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