record bus/ganged type in tsv spec files
[pinmux.git] / src / spec / interfaces.py
1 #!/usr/bin/env python
2
3 from spec.pinfunctions import pinspec
4 from copy import deepcopy
5
6
7 def namesuffix(name, suffix, namelist):
8 names = []
9 for n in namelist:
10 if n:
11 names.append("%s%s_%s" % (name, suffix, n))
12 else:
13 names.append("%s_%s" % (name, suffix))
14 return names
15
16
17 class PinGen(object):
18 """ a meta-helper which creates pins from the pinspec
19 and adds them to the pinouts.
20
21 __call__ is used to effectively create a lambda function, which
22 in combination with setattr (below) gives the function a name
23 in the Pinouts class, according to the pinspec.
24
25 arguments to __call__ (which ends up as Pinouts.i2s, Pinouts.sdmmc
26 and so on, according to spec.pinfunctions.pinspec) are:
27
28 suffix: e.g. GPIO or SD or SPI
29 offs : a tuple of (Bank, Bank offset) as a string, integer
30 mux : which column in the multiplexer
31 start : the start of a subset of pins to be inserted
32 limit : the end of the subset (or the number if start also given)
33 spec : *EXTRA* pins to be inserted.
34
35 spec is slightly complicated, basically there's extra
36 functions that we want to be on the same pin (but a different mux)
37 because their use is mutually-exclusive. without this spec
38 argument the extra pins would need to be MANUALLY moved about
39 during the development of the pinmux, if the "main" pins
40 were also moved about. this would be a pain.
41
42 so instead, extra pins are given of the form:
43 { 'EXTRA1' : ('PREEXISTING_NAME', MUX_COLUMN),
44 ...
45 }
46
47 where the function EXTRA1 will always be placed on the SAME ROW
48 as PREEXISTING_NAME, just in MUX_COLUMN. this may be done
49 several times i.e. multiple new EXTRA functions can be added
50 on the same row as PRE_EXISTING_NAME, just with different
51 MUX_COLUMN values.
52
53 Note: spec must implicitly be in the same Bank.
54 """
55
56 def __init__(self, pinouts, fname, pinfn, bankspec):
57 self.pinouts = pinouts
58 self.bankspec = bankspec
59 self.pinfn = pinfn
60 self.fname = fname
61
62 def __call__(self, suffix, offs, mux,
63 start=None, limit=None, spec=None, origsuffix=None):
64 bank = offs[0]
65 pingroup, gangedgroup = self.pinfn(suffix, bank)
66 if isinstance(pingroup, tuple):
67 prefix, pingroup = pingroup
68 else:
69 prefix = self.fname
70 if start and limit: # limit turns into an offset from start
71 limit = start + limit
72 pingroup = pingroup[start:limit] # see comment in spec.pinfunctions
73 pins = Pins(prefix, pingroup, self.bankspec,
74 suffix, offs, bank, mux,
75 spec, origsuffix=suffix, gangedgrp=gangedgroup)
76 fname = self.pinouts.pinmerge(pins)
77 self.pinouts.setganged(fname, gangedgroup)
78
79 # pinouts class
80
81
82 class Pinouts(object):
83 def __init__(self, bankspec):
84 self.bankspec = bankspec
85 self.pins = {}
86 self.fnspec = {}
87 self.ganged = {}
88 for fname, pinfn in pinspec:
89 if isinstance(pinfn, tuple):
90 name, pinfn = pinfn
91 else:
92 name = pinfn.__name__
93 setattr(self, name, PinGen(self, fname, pinfn, self.bankspec))
94
95 def setganged(self, fname, grp):
96 self.ganged[fname] = map(lambda x: x[:-1], grp)
97
98 def __contains__(self, k):
99 return k in self.pins
100
101 def has_key(self, k):
102 return k in self.pins
103
104 def add_spec(self, k, v):
105 self.fnspec[k] = v
106
107 def update(self, pinidx, v):
108 if pinidx not in self.pins:
109 self.pins[pinidx] = v
110 else:
111 for k in v:
112 assert k not in self.pins[pinidx], \
113 "pin %d position %d already taken\n%s\n%s" % \
114 (pinidx, k, str(v), self.pins[pinidx])
115 self.pins[pinidx].update(v)
116
117 def keys(self):
118 return self.pins.keys()
119
120 def items(self):
121 return self.pins.items()
122
123 def get(self, k):
124 return self.pins[k]
125
126 def __len__(self):
127 return len(self.pins)
128
129 def __delitem__(self, k):
130 del self.pins[k]
131
132 def __getitem__(self, k):
133 return self.pins[k]
134
135 def pinmerge(self, fn):
136 # hack, store the function specs in the pins dict
137 fname = fn.fname
138 suffix = fn.origsuffix
139 bank = fn.bank
140
141 if not hasattr(self, 'fnspec'):
142 self.fnspec = pins
143 if fname == 'GPIO':
144 fname = fname + bank
145 assert 'EINT' not in self
146 if fname not in self.fnspec:
147 self.add_spec(fname, {})
148 if suffix or fname == 'EINT' or fname == 'PWM':
149 specname = fname + suffix
150 else:
151 specname = fname
152 # print "fname bank specname suffix ", fname, bank, specname, repr(
153 # suffix)
154 if specname in self.fnspec[fname]:
155 # ok so some declarations may bring in different
156 # names at different stages (EINT, PWM, flexbus1/2)
157 # so we have to merge the names in. main thing is
158 # the pingroup
159 tomerge = self.fnspec[fname][specname]
160 for p in fn.pingroup:
161 if p not in tomerge.pingroup:
162 tomerge.pingroup.append(p)
163 tomerge.pins.update(fn.pins)
164 tomerge.fntype.update(fn.fntype)
165 else:
166 self.fnspec[fname][specname] = deepcopy(fn)
167
168 # merge actual pins
169 for (pinidx, v) in fn.pins.items():
170 self.update(pinidx, v)
171
172 return fname
173
174
175 class Pins(object):
176
177 def __init__(self, fname, pingroup, bankspec, suffix, offs, bank, mux,
178 spec=None, limit=None, origsuffix=None, gangedgrp=None):
179
180 # function type can be in, out or inout, represented by - + *
181 # strip function type out of each pin name
182 self.fntype = {}
183 for i in range(len(pingroup)):
184 pname = pingroup[i]
185 if not pname:
186 continue
187 fntype = pname[-1]
188 if fntype not in '+-*':
189 continue
190 pname = pname[:-1]
191 fntype = {'-': 'in', '+': 'out', '*': 'inout'}[fntype]
192 self.fntype[pname] = fntype
193 pingroup[i] = pname
194
195 self.fname = fname
196 self.pingroup = pingroup
197 self.gangedgroup = gangedgrp
198 self.bankspec = bankspec
199 self.suffix = suffix
200 self.origsuffix = origsuffix or suffix
201 self.bank = bank
202 self.mux = mux
203
204 # create consistent name suffixes
205 pingroup = namesuffix(fname, suffix, pingroup)
206 suffix = '' # hack
207
208 res = {}
209 names = {}
210 idx = 0
211 for name in pingroup[:limit]:
212 if suffix and name:
213 name_ = "%s_%s" % (name, suffix)
214 else:
215 name_ = name
216 if spec and name in spec:
217 continue
218 pin = {mux: (name_, bank)}
219 offs_bank, offs_ = offs
220 idx_ = offs_ + idx
221 idx += 1
222 idx_ += bankspec[bank]
223 res[idx_] = pin
224 names[name] = idx_
225 for name in pingroup:
226 if suffix and name:
227 name_ = "%s_%s" % (name, suffix)
228 else:
229 name_ = name
230 if not spec:
231 continue
232 if name not in spec:
233 continue
234 idx_, mux_ = spec[name]
235 idx_ = names[idx_]
236 pin = {mux_: (name_, bank)}
237 if idx_ in res:
238 res[idx_].update(pin)
239 else:
240 res[idx_] = pin
241
242 self.pins = res