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