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