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