In-progress, re-arranging peripherals
[pinmux.git] / src / spec / ngi_router.py
1 #!/usr/bin/env python
2 # see https://bugs.libre-soc.org/show_bug.cgi?id=739
3
4 from spec.base import PinSpec
5 from parse import Parse
6 import json
7
8 from pprint import pprint
9 from spec.ifaceprint import display, display_fns, check_functions
10 from spec.ifaceprint import display_fixed
11 from collections import OrderedDict
12
13 def pinspec():
14 # TODO - Turn the number of pins per side into a variable?
15 pinbanks = OrderedDict((
16 ('N', (64, 2)),
17 ('E', (64, 2)),
18 ('S', (64, 2)),
19 ('W', (64, 2)),
20 ))
21 fixedpins = {
22 'CTRL_SYS': [
23 'TEST',
24 'JTAG_SEL',
25 'UBOOT_SEL',
26 'NMI#',
27 'RESET#',
28 'CLK24M_IN',
29 'CLK24M_OUT',
30 'PLLTEST',
31 'PLLREGIO',
32 'PLLVP25',
33 'PLLDV',
34 'PLLVREG',
35 'PLLGND',
36 ],
37 'POWER_GPIO': [
38 'VDD_GPIOB',
39 'GND_GPIOB',
40 ]}
41 fixedpins = {}
42 function_names = {
43 # Essential
44 'RG0': 'Gigabit Ethernet 0',
45 'RG1': 'Gigabit Ethernet 1',
46 'RG2': 'Gigabit Ethernet 2',
47 'RG3': 'Gigabit Ethernet 3',
48 'RG4': 'Gigabit Ethernet 4',
49 'ULPI0': 'USB ULPI0 PHY',
50 'ULPI1': 'USB ULPI1 PHY',
51 'SDR': 'SDRAM',
52 'UART0': 'UART (TX/RX)',
53 'JTAG': 'JTAG',
54 'VDD': '1.8V Core Power',
55 'VSS': '1.8V Core GND',
56 'VDD': '3.3V I/O Power',
57 'VSS': '3.3V I/O GND',
58 'SYS': 'System Control',
59 'MSPI0': 'SPI Master 0 (general)',
60 # Non-Essential
61 'GPIO': 'GPIO',
62 'EINT': 'External Interrupt',
63 'MTWI': 'I2C Master',
64 'QSPI': 'QSPI Master',
65 'SD0': 'SD/MMC',
66 }
67
68 ps = PinSpec(pinbanks, fixedpins, function_names)
69
70 ps.sdram1("", ('W', 0), 0, 15, 6, rev=True) # AD4-9, turned round
71 ps.vdd("E", ('W', 6), 0, 0, 1)
72 ps.vss("E", ('W', 7), 0, 0, 1)
73 ps.vdd("I", ('W', 8), 0, 0, 1)
74 ps.vss("I", ('W', 9), 0, 0, 1)
75 ps.sdram1("", ('W', 10), 0, 0, 15, rev=True) # SDRAM DAM0, D0-7, AD0-3
76 ps.mi2c("", ('W', 26), 0, 0, 2)
77 ps.vss("I", ('W', 28), 0, 1, 1)
78 ps.vdd("I", ('W', 29), 0, 1, 1)
79 ps.vss("E", ('W', 30), 0, 1, 1)
80 ps.vdd("E", ('W', 31), 0, 1, 1)
81
82 ps.sdram2("", ('S', 0), 0, 0, 4) # 1st 4, AD10-12,DQM1
83 ps.vdd("E", ('S', 4), 0, 2, 1)
84 ps.vss("E", ('S', 5), 0, 2, 1)
85 ps.vdd("I", ('S', 6), 0, 2, 1)
86 ps.vss("I", ('S', 7), 0, 2, 1)
87 ps.sdram2("", ('S', 8), 0, 4, 8) # D8-15
88 ps.sdram1("", ('S', 16), 0, 21, 9) # clk etc.
89 ps.vss("I", ('S', 22), 0, 3, 1)
90 ps.vdd("I", ('S', 23), 0, 3, 1)
91 ps.vss("E", ('S', 24), 0, 3, 1)
92 ps.vdd("E", ('S', 25), 0, 3, 1)
93 ps.uart("0", ('S', 26), 0)
94 ps.mspi("0", ('S', 28), 0)
95
96 ps.gpio("", ('E', 0), 0, 0, 6) # GPIO 0-5
97 ps.vss("E", ('E', 6), 0, 4, 1)
98 ps.vdd("E", ('E', 7), 0, 4, 1)
99 ps.vdd("I", ('E', 8), 0, 4, 1)
100 ps.vss("I", ('E', 9), 0, 4, 1)
101 ps.gpio("", ('E', 10), 0, 6, 3) # GPIO 6-8
102 ps.jtag("", ('E', 13), 0, 0, 4)
103 ps.gpio("", ('E', 17), 0, 9, 5) # GPIO 9-13
104 #ps.vss("I", ('E', 22), 0, 5, 1)
105 #ps.vdd("I", ('E', 23), 0, 5, 1)
106 #ps.vss("E", ('E', 24), 0, 5, 1)
107 #ps.vdd("E", ('E', 25), 0, 5, 1)
108 #ps.gpio("", ('E', 26), 0, 14, 2) # GPIO 14-15
109 #ps.eint("", ('E', 28), 0, 0, 3)
110 ps.sys("", ('E', 63), 0, 5, 1) # analog VCO out in right top
111
112 ps.vss("E", ('N', 6), 0, 6, 1)
113 ps.vdd("E", ('N', 7), 0, 6, 1)
114 ps.vdd("I", ('N', 8), 0, 6, 1)
115 ps.vss("I", ('N', 9), 0, 6, 1)
116
117 #ps.pwm("", ('N', 2), 0, 0, 2) comment out (litex problem 25mar2021)
118 #ps.mspi("1", ('N', 7), 0) comment out (litex problem 25mar2021)
119 #ps.sdmmc("0", ('N', 11), 0) # comment out (litex problem 25mar2021)
120 ps.sys("", ('N', 59), 0, 0, 5) # all but analog out in top right
121 ps.vss("I", ('N', 54), 0, 7, 1)
122 ps.vdd("I", ('N', 55), 0, 7, 1)
123 ps.vss("E", ('N', 56), 0, 7, 1)
124 ps.vdd("E", ('N', 57), 0, 7, 1)
125
126 ps.rgmii("0", ('E', 42), 0, 0, 18)
127 ps.rgmii("1", ('E', 22), 0, 0, 18)
128 ps.rgmii("2", ('N', 31), 0, 0, 18)
129 #ps.mquadspi("1", ('S', 0), 0)
130
131 print ("ps clocks", ps.clocks)
132
133 # Scenarios below can be spec'd out as either "find first interface"
134 # by name/number e.g. SPI1, or as "find in bank/mux" which must be
135 # spec'd as "BM:Name" where B is bank (A-F), M is Mux (0-3)
136 # EINT and PWM are grouped together, specially, but may still be spec'd
137 # using "BM:Name". Pins are removed in-order as listed from
138 # lists (interfaces, EINTs, PWMs) from available pins.
139
140 ngi_router = [
141 # 'SD0', litex problem 25mar2021
142 'UART0', 'GPIOS', 'GPIOE', 'JTAG', 'PWM', 'EINT',
143 'VDD', 'VSS', 'SYS',
144 'MTWI', 'MSPI0',
145 'RG0', 'RG1', 'RG2', 'RG3', 'RG4',
146 # 'MSPI1', litex problem 25mar2021
147 'SDR']
148 ngi_router_eint = []
149 ngi_router_pwm = []#['B0:PWM_0']
150 descriptions = {
151 'SD0': 'user-facing: internal (on Card), multiplexed with JTAG\n'
152 'and UART2, for debug purposes',
153 'MTWI': 'I2C.\n',
154 'E2:SD1': '',
155 'MSPI1': '',
156 'UART0': '',
157 'LPC1': '',
158 'SYS': '',
159 'LPC2': '',
160 'SDR': '',
161 'B1:LCD/22': '18-bit RGB/TTL LCD',
162 'ULPI0/8': 'user-facing: internal (on Card), USB-OTG ULPI PHY',
163 'ULPI1': 'dual USB2 Host ULPI PHY'
164 }
165
166 ps.add_scenario("NGI ROUTER Libre-SOC 180nm", ngi_router, ngi_router_eint, ngi_router_pwm,
167 descriptions)
168
169 return ps
170
171
172 # map pins to litex name conventions, primarily for use in coriolis2
173 # yes this is a mess. it'll do the job though. improvements later
174 def pinparse(psp, pinspec):
175 p = Parse(pinspec, verify=False)
176 pinmap = {}
177 litexmap = {}
178
179 print (p.muxed_cells)
180 print (p.muxed_cells_bank)
181
182 # TODO - Turn the number of pins per side into a variable?
183 ps = [''] * 64
184 pn = [''] * 64
185 pe = [''] * 64
186 pw = [''] * 64
187 pads = {'N': pn, 'S': ps, 'E': pe, 'W': pw}
188
189 iopads = []
190 domains = {}
191 clocks = {}
192
193 n_intpower = 0
194 n_extpower = 0
195 for (padnum, name, x), bank in zip(p.muxed_cells, p.muxed_cells_bank):
196 orig_name = name
197 litex_name = None
198 domain = None # TODO, get this from the PinSpec. sigh
199 padnum = int(padnum)
200 start = p.bankstart[bank]
201 banknum = padnum - start
202 print ("bank", bank, banknum, "padname", name, padnum, x)
203 padbank = pads[bank]
204 pad = None
205 # VSS
206 if name.startswith('vss'):
207 name = 'p_%s_' % name[:-2] + name[-1]
208 if 'i' in name:
209 name = 'ground_' + name[-1]
210 name2 = 'vss'
211 else:
212 name = 'ioground_' + name[-1]
213 name2 = 'iovss'
214 pad = [name, name2]
215 # VDD
216 elif name.startswith('vdd'):
217 if 'i' in name:
218 n_intpower += 1
219 name = 'power_' + name[-1]
220 name2 = 'vdd'
221 else:
222 n_extpower += 1
223 name = 'iopower_' + name[-1]
224 name2 = 'iovdd'
225 pad = [name, name2]
226 # SYS
227 elif name.startswith('sys'):
228 domain = 'SYS'
229 if name == 'sys_pllclk':
230 pad = ["p_"+name, name, name]
231 elif name == 'sys_rst':
232 #name = 'p_sys_rst_1'
233 pad = [name, name, name]
234 padbank[banknum] = name
235 print ("sys_rst add", bank, banknum, name)
236 name = None
237 elif name == 'sys_pllclk':
238 name = None # ignore
239 elif name == 'sys_pllvcout':
240 name = 'sys_pll_vco_o'
241 pad = ['p_' + name, name, name, "A"] # A for Analog
242 elif name == 'sys_plltestout':
243 name = 'sys_pll_testout_o'
244 pad = ['p_' + name, name, name]
245 elif name.startswith('sys_pllsel'):
246 i = name[-1]
247 name2 = 'sys_clksel_i(%s)' % i
248 name = 'p_sys_clksel_' + i
249 pad = [name, name2, name2]
250 #if name:
251 # iopads.append([pname, name, name])
252 print ("sys pad", name)
253 # SPI Card
254 elif name.startswith('mspi0') or name.startswith('mspi1'):
255 domain = 'MSPI'
256 suffix = name[6:]
257 if suffix == 'ck':
258 suffix = 'clk'
259 elif suffix == 'nss':
260 suffix = 'cs_n'
261 if name.startswith('mspi0'):
262 prefix = 'spimaster_'
263 else:
264 prefix = 'spisdcard_'
265 litex_name = name[:6] + suffix
266 name = prefix + suffix
267 pad = ['p_' + name, name, name]
268 # SD/MMC
269 elif name.startswith('sd0'):
270 domain = 'SD'
271 if name.startswith('sd0_d'):
272 i = name[5:]
273 name = 'sdcard_data' + i
274 name2 = 'sdcard_data_%%s(%s)' % i
275 pad = ['p_'+name, name, name2 % 'o', name2 % 'i', name2 % 'oe']
276 elif name.startswith('sd0_cmd'):
277 name = 'sdcard_cmd'
278 name2 = 'sdcard_cmd_%s'
279 pad = ['p_'+name, name, name2 % 'o', name2 % 'i', name2 % 'oe']
280 else:
281 name = 'sdcard_' + name[4:]
282 pad = ['p_' + name, name, name]
283 litex_name = orig_name[:4] + "_".join(name.split("_")[1:])
284 # SDRAM
285 elif name.startswith('sdr'):
286 domain = 'SDR'
287 if name == 'sdr_clk':
288 name = 'sdram_clock'
289 pad = ['p_' + name, name, name]
290 elif name.startswith('sdr_ad'):
291 i = name[6:]
292 name = 'sdram_a_' + i
293 name2 = 'sdram_a(%s)' % i
294 pad = ['p_' + name, name2, name2]
295 elif name.startswith('sdr_ba'):
296 i = name[-1]
297 name = 'sdram_ba_' + i
298 name2 = 'sdram_ba(%s)' % i
299 pad = ['p_' + name, name2, name2]
300 elif name.startswith('sdr_dqm'):
301 i = name[-1]
302 name = 'sdram_dm_' + i
303 name2 = 'sdram_dm(%s)' % i
304 pad = ['p_' + name, name2, name2]
305 elif name.startswith('sdr_d'):
306 i = name[5:]
307 name = 'sdram_dq_' + i
308 name2 = 'sdram_dq_%%s(%s)' % i
309 pad = ['p_'+name, name, name2 % 'o', name2 % 'i', name2 % 'oe']
310 elif name == 'sdr_csn0':
311 name = 'sdram_cs_n'
312 pad = ['p_' + name, name, name]
313 elif name[-1] == 'n':
314 name = 'sdram_' + name[4:-1] + '_n'
315 pad = ['p_' + name, name, name]
316 else:
317 name = 'sdram_' + name[4:]
318 pad = ['p_' + name, name, name]
319 litex_name = orig_name[:4] + "_".join(name.split("_")[1:])
320 # UART
321 elif name.startswith('uart'):
322 domain = 'UART'
323 name = 'uart_' + name[6:]
324 pad = ['p_' + name, name, name]
325 # GPIO
326 elif name.startswith('gpio'):
327 gbank = name[4]
328 domain = 'GPIO'
329 i = name[7:]
330 name = 'gpio_' + i
331 name2 = 'gpio_%%s(%s)' % i
332 pad = ['p_' + name, name, name2 % 'o', name2 % 'i', name2 % 'oe']
333 print ("GPIO pad", name, pad)
334 litex_name = "gpio_%s" % gbank + "_".join(name.split("_")[1:])
335 # I2C master-only
336 elif name.startswith('mtwi'):
337 domain = 'MTWI'
338 suffix = name[4:]
339 litex_name = 'mtwi' + suffix
340 name = 'i2c' + suffix
341 if name.startswith('i2c_sda'):
342 name2 = 'i2c_sda_%s'
343 pad = ['p_'+name, name, name2 % 'o', name2 % 'i', name2 % 'oe']
344 print ("I2C pad", name, pad)
345 else:
346 pad = ['p_' + name, name, name]
347 # I2C bi-directional
348 elif name.startswith('twi'):
349 domain = 'TWI'
350 name = 'i2c' + name[3:]
351 name2 = name + '_%s'
352 pad = ['p_'+name, name, name2 % 'o', name2 % 'i', name2 % 'oe']
353 print ("I2C pad", name, pad)
354 # EINT
355 elif name.startswith('eint'):
356 domain = 'EINT'
357 i = name[-1]
358 name = 'eint_%s' % i
359 name2 = 'eint_%s' % i
360 pad = ['p_' + name, name2, name2]
361 # PWM
362 elif name.startswith('pwm'):
363 domain = 'PWM'
364 name = name[:-4]
365 i = name[3:]
366 name2 = 'pwm(%s)' % i
367 pad = ['p_' + name, name2, name2]
368 else:
369 pad = ['p_' + name, name, name]
370 print ("GPIO pad", name, pad)
371
372 if litex_name is None:
373 litex_name = name
374
375 # JTAG domain
376 if name and name.startswith('jtag'):
377 domain = 'JTAG'
378
379 if name and not name.startswith('p_'):
380 if 'power' not in name and 'ground' not in name:
381 name = 'p_' + name
382 if name is not None:
383 padbank[banknum] = name
384 # create domains
385 if domain is not None:
386 if domain not in domains:
387 domains[domain] = []
388 domains[domain].append(name)
389 dl = domain.lower()
390 if domain in psp.clocks and orig_name.startswith(dl):
391 clk = psp.clocks[domain]
392 if clk.lower() in orig_name: # TODO, might over-match
393 clocks[domain] = name
394 # record remap
395 pinmap[orig_name] = name
396 litexmap[litex_name] = name
397
398 # add pad to iopads
399 if domain and pad is not None:
400 # append direction from spec/domain. damn awkward processing
401 # to find it.
402 fn, name = orig_name.split("_")
403 if domain == 'PWM':
404 name = fn[3:]
405 print (psp.byspec)
406 spec = None
407 for k in psp.byspec.keys():
408 if k.startswith(domain):
409 spec = psp.byspec[k]
410 print ("spec found", domain, spec)
411 assert spec is not None
412 found = None
413 for pname in spec:
414 if pname.lower().startswith(name):
415 found = pname
416 print ("found spec", found)
417 assert found is not None
418 # whewwww. add the direction onto the pad spec list
419 dirn = found[-1]
420 if pad[-1] == 'A':
421 pad[-1] += dirn
422 else:
423 pad.append(dirn)
424 iopads.append(pad)
425 elif pad is not None:
426 iopads.append(pad)
427
428 # not connected
429 nc_idx = 0
430 for pl in [pe, pw, pn, ps]:
431 for i in range(len(pl)):
432 if pl[i] == '':
433 name = 'nc_%d' % nc_idx
434 name2 = 'nc(%d)' % nc_idx
435 pl[i] = name
436 pinmap[name] = name
437 iopads.append([name, name2, name2, "-"])
438 nc_idx += 1
439
440 print (p.bankstart)
441 pprint(psp.clocks)
442
443 print
444 print ("N pads", pn)
445 print ("S pads", ps)
446 print ("E pads", pe)
447 print ("W pads", pw)
448
449 # do not want these
450 del clocks['SYS']
451 del domains['SYS']
452
453 print ("chip domains (excluding sys-default)")
454 pprint(domains)
455 print ("chip clocks (excluding sys-default)")
456 pprint(clocks)
457 print ("pin spec")
458 pprint(psp.byspec)
459
460 chip = {
461 'pads.south' : ps,
462 'pads.east' : pe,
463 'pads.north' : pn,
464 'pads.west' : pw,
465 'pads.instances' : iopads,
466 'pins.specs' : psp.byspec,
467 'pins.map' : pinmap,
468 'litex.map' : litexmap,
469 'chip.domains' : domains,
470 'chip.clocks' : clocks,
471 'chip.n_intpower': n_intpower,
472 'chip.n_extpower': n_extpower,
473 }
474
475 return pinmap, chip