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