Dockerfile: Update to latest "focal" tag
[platform/kernel/u-boot.git] / tools / rkmux.py
1 #!/usr/bin/env python3
2
3 # Script to create enums from datasheet register tables
4 #
5 # Usage:
6 #
7 # First, create a text file from the datasheet:
8 #    pdftotext -layout /path/to/rockchip-3288-trm.pdf /tmp/asc
9 #
10 # Then use this script to output the #defines for a particular register:
11 #    ./tools/rkmux.py GRF_GPIO4C_IOMUX
12 #
13 # It will create output suitable for putting in a header file, with SHIFT and
14 # MASK values for each bitfield in the register.
15 #
16 # Note: this tool is not perfect and you may need to edit the resulting code.
17 # But it should speed up the process.
18
19 import csv
20 import re
21 import sys
22
23 tab_to_col = 3
24
25 class RegField:
26     def __init__(self, cols=None):
27         if cols:
28             self.bits, self.attr, self.reset_val, self.desc = (
29                 [x.strip() for x in cols])
30             self.desc = [self.desc]
31         else:
32             self.bits = ''
33             self.attr = ''
34             self.reset_val = ''
35             self.desc = []
36
37     def Setup(self, cols):
38         self.bits, self.attr, self.reset_val = cols[0:3]
39         if len(cols) > 3:
40             self.desc.append(cols[3])
41
42     def AddDesc(self, desc):
43         self.desc.append(desc)
44
45     def Show(self):
46         print(self)
47         print()
48         self.__init__()
49
50     def __str__(self):
51         return '%s,%s,%s,%s' % (self.bits, self.attr, self.reset_val,
52                                 '\n'.join(self.desc))
53
54 class Printer:
55     def __init__(self, name):
56         self.first = True
57         self.name = name
58         self.re_sel = re.compile("[1-9]'b([01]+): (.*)")
59
60     def __enter__(self):
61         return self
62
63     def __exit__(self, type, value, traceback):
64         if not self.first:
65             self.output_footer()
66
67     def output_header(self):
68         print('/* %s */' % self.name)
69         print('enum {')
70
71     def output_footer(self):
72         print('};');
73
74     def output_regfield(self, regfield):
75         lines = regfield.desc
76         field = lines[0]
77         #print 'field:', field
78         if field in ['reserved', 'reserve', 'write_enable', 'write_mask']:
79             return
80         if field.endswith('_sel') or field.endswith('_con'):
81             field = field[:-4]
82         elif field.endswith(' iomux'):
83             field = field[:-6]
84         elif field.endswith('_mode') or field.endswith('_mask'):
85             field = field[:-5]
86         #else:
87             #print 'bad field %s' % field
88             #return
89         field = field.upper()
90         if ':' in regfield.bits:
91             bit_high, bit_low = [int(x) for x in regfield.bits.split(':')]
92         else:
93             bit_high = bit_low = int(regfield.bits)
94         bit_width = bit_high - bit_low + 1
95         mask = (1 << bit_width) - 1
96         if self.first:
97             self.first = False
98             self.output_header()
99         else:
100             print()
101         out_enum(field, 'shift', bit_low)
102         out_enum(field, 'mask', mask)
103         next_val = -1
104         #print 'lines: %s', lines
105         for line in lines:
106             m = self.re_sel.match(line)
107             if m:
108                 val, enum = int(m.group(1), 2), m.group(2)
109                 if enum not in ['reserved', 'reserve']:
110                     out_enum(field, enum, val, val == next_val)
111                     next_val = val + 1
112
113
114 def process_file(name, fd):
115     field = RegField()
116     reg = ''
117
118     fields = []
119
120     def add_it(field):
121         if field.bits:
122             if reg == name:
123                 fields.append(field)
124             field = RegField()
125         return field
126
127     def is_field_start(line):
128        if '=' in line or '+' in line:
129            return False
130        if (line.startswith('gpio') or line.startswith('peri_') or
131                 line.endswith('_sel') or line.endswith('_con')):
132            return True
133        if not ' ' in line: # and '_' in line:
134            return True
135        return False
136
137     for line in fd:
138         line = line.rstrip()
139         if line[:4] in ['GRF_', 'PMU_', 'CRU_']:
140             field = add_it(field)
141             reg = line
142             do_this = name == reg
143         elif not line or not line.startswith(' '):
144             continue
145         line = line.replace('\xe2\x80\x99', "'")
146         leading = len(line) - len(line.lstrip())
147         line = line.lstrip()
148         cols = re.split(' *', line, 3)
149         if leading > 15 or (len(cols) > 3 and is_field_start(cols[3])):
150             if is_field_start(line):
151                 field = add_it(field)
152             field.AddDesc(line)
153         else:
154             if cols[0] == 'Bit' or len(cols) < 3:
155                 continue
156             #print
157             #print field
158             field = add_it(field)
159             field.Setup(cols)
160     field = add_it(field)
161
162     with Printer(name) as printer:
163         for field in fields:
164             #print field
165             printer.output_regfield(field)
166             #print
167
168 def out_enum(field, suffix, value, skip_val=False):
169     str = '%s_%s' % (field.upper(), suffix.upper())
170     if not skip_val:
171         tabs = tab_to_col - len(str) / 8
172         if value > 9:
173             val_str = '%#x' % value
174         else:
175             val_str = '%d' % value
176
177         str += '%s= %s' % ('\t' * tabs, val_str)
178     print('\t%s,' % str)
179
180 # Process a CSV file, e.g. from tabula
181 def process_csv(name, fd):
182     reader = csv.reader(fd)
183
184     rows = []
185
186     field = RegField()
187     for row in reader:
188         #print field.desc
189         if not row[0]:
190             field.desc.append(row[3])
191             continue
192         if field.bits:
193             if field.bits != 'Bit':
194                 rows.append(field)
195         #print row
196         field = RegField(row)
197
198     with Printer(name) as printer:
199         for row in rows:
200             #print field
201             printer.output_regfield(row)
202             #print
203
204 fname = sys.argv[1]
205 name = sys.argv[2]
206
207 # Read output from pdftotext -layout
208 if 1:
209     with open(fname, 'r') as fd:
210         process_file(name, fd)
211
212 # Use tabula
213 # It seems to be better at outputting text for an entire cell in one cell.
214 # But it does not always work. E.g. GRF_GPIO7CH_IOMUX.
215 # So there is no point in using it.
216 if 0:
217     with open(fname, 'r') as fd:
218         process_csv(name, fd)