Refactor package hierarchy. (#25)
[sifive-blocks.git] / src / main / scala / devices / gpio / GPIO.scala
1 // See LICENSE for license details.
2 package sifive.blocks.devices.gpio
3
4 import Chisel._
5 import freechips.rocketchip.config.Parameters
6 import freechips.rocketchip.regmapper._
7 import freechips.rocketchip.tilelink._
8 import freechips.rocketchip.util.{AsyncResetRegVec, GenericParameterizedBundle}
9
10 case class GPIOParams(address: BigInt, width: Int, includeIOF: Boolean = false)
11
12 // YAGNI: Make the PUE, DS, and
13 // these also optionally HW controllable.
14 // This is the base class of things you "always"
15 // want to control from a HW block.
16 class GPIOCtrl extends Bundle {
17 val oval = Bool()
18 val oe = Bool()
19 val ie = Bool()
20 }
21
22 // This is the actual IOF interface.
23 // Add a valid bit to indicate whether
24 // there is something actually connected
25 // to this.
26 class GPIOPinIOFCtrl extends GPIOCtrl {
27 val valid = Bool()
28 }
29
30 // By default,
31 object GPIOPinIOFCtrl {
32 def apply(): GPIOPinIOFCtrl = {
33 val iof = Wire(new GPIOPinIOFCtrl())
34 iof.valid := Bool(false)
35 iof.oval := Bool(false)
36 iof.oe := Bool(false)
37 iof.ie := Bool(false)
38 iof
39 }
40 }
41
42 // This is the control for a physical
43 // Pad.
44
45 class GPIOPinCtrl extends GPIOCtrl {
46 val pue = Bool() // Pull-up Enable
47 val ds = Bool() // Drive Strength
48 }
49
50 object GPIOPinCtrl {
51 def apply(): GPIOPinCtrl = {
52 val pin = Wire(new GPIOPinCtrl())
53 pin.oval := Bool(false)
54 pin.oe := Bool(false)
55 pin.pue := Bool(false)
56 pin.ds := Bool(false)
57 pin.ie := Bool(false)
58 pin
59 }
60 }
61
62 // Package up the inputs and outputs
63 // for the IOF
64 class GPIOPinIOF extends Bundle {
65 val i = new Bundle {
66 val ival = Bool(INPUT)
67 }
68 val o = new GPIOPinIOFCtrl().asOutput
69 }
70
71 // Connect both the i and o side of the pin,
72 // and drive the valid signal for the IOF.
73 object GPIOPinToIOF {
74
75 def apply (pin: GPIOPin, iof: GPIOPinIOF): Unit = {
76 iof <> pin
77 iof.o.valid := Bool(true)
78 }
79
80 }
81
82 // Package up the inputs and outputs
83 // for the Pin
84 class GPIOPin extends Bundle {
85 val i = new Bundle {
86 val ival = Bool(INPUT)
87 }
88 val o = new GPIOPinCtrl().asOutput
89 }
90
91 // This is sort of weird because
92 // the IOF end up at the RocketChipTop
93 // level, and we have to do the pinmux
94 // outside of RocketChipTop.
95
96 class GPIOPortIO(c: GPIOParams) extends GenericParameterizedBundle(c) {
97 val pins = Vec(c.width, new GPIOPin)
98 val iof_0 = if (c.includeIOF) Some(Vec(c.width, new GPIOPinIOF).flip) else None
99 val iof_1 = if (c.includeIOF) Some(Vec(c.width, new GPIOPinIOF).flip) else None
100 }
101
102 // It would be better if the IOF were here and
103 // we could do the pinmux inside.
104 trait HasGPIOBundleContents extends Bundle {
105 val params: GPIOParams
106 val port = new GPIOPortIO(params)
107 }
108
109 trait HasGPIOModuleContents extends Module with HasRegMap {
110 val io: HasGPIOBundleContents
111 val params: GPIOParams
112 val c = params
113
114 //--------------------------------------------------
115 // CSR Declarations
116 // -------------------------------------------------
117
118 // SW Control only.
119 val portReg = Reg(init = UInt(0, c.width))
120
121 val oeReg = Module(new AsyncResetRegVec(c.width, 0))
122 val pueReg = Module(new AsyncResetRegVec(c.width, 0))
123 val dsReg = Reg(init = UInt(0, c.width))
124 val ieReg = Module(new AsyncResetRegVec(c.width, 0))
125
126 // Synchronize Input to get valueReg
127 val inVal = Wire(UInt(0, width=c.width))
128 inVal := Vec(io.port.pins.map(_.i.ival)).asUInt
129 val inSyncReg = ShiftRegister(inVal, 3)
130 val valueReg = Reg(init = UInt(0, c.width), next = inSyncReg)
131
132 // Interrupt Configuration
133 val highIeReg = Reg(init = UInt(0, c.width))
134 val lowIeReg = Reg(init = UInt(0, c.width))
135 val riseIeReg = Reg(init = UInt(0, c.width))
136 val fallIeReg = Reg(init = UInt(0, c.width))
137 val highIpReg = Reg(init = UInt(0, c.width))
138 val lowIpReg = Reg(init = UInt(0, c.width))
139 val riseIpReg = Reg(init = UInt(0, c.width))
140 val fallIpReg = Reg(init = UInt(0, c.width))
141
142 // HW IO Function
143 val iofEnReg = Module(new AsyncResetRegVec(c.width, 0))
144 val iofSelReg = Reg(init = UInt(0, c.width))
145
146 // Invert Output
147 val xorReg = Reg(init = UInt(0, c.width))
148
149 //--------------------------------------------------
150 // CSR Access Logic (most of this section is boilerplate)
151 // -------------------------------------------------
152
153 val rise = ~valueReg & inSyncReg;
154 val fall = valueReg & ~inSyncReg;
155
156 val iofEnFields = if (c.includeIOF) (Seq(RegField.rwReg(c.width, iofEnReg.io))) else (Seq(RegField(c.width)))
157 val iofSelFields = if (c.includeIOF) (Seq(RegField(c.width, iofSelReg))) else (Seq(RegField(c.width)))
158
159
160 // Note that these are out of order.
161 regmap(
162 GPIOCtrlRegs.value -> Seq(RegField.r(c.width, valueReg)),
163 GPIOCtrlRegs.output_en -> Seq(RegField.rwReg(c.width, oeReg.io)),
164 GPIOCtrlRegs.rise_ie -> Seq(RegField(c.width, riseIeReg)),
165 GPIOCtrlRegs.rise_ip -> Seq(RegField.w1ToClear(c.width, riseIpReg, rise)),
166 GPIOCtrlRegs.fall_ie -> Seq(RegField(c.width, fallIeReg)),
167 GPIOCtrlRegs.fall_ip -> Seq(RegField.w1ToClear(c.width, fallIpReg, fall)),
168 GPIOCtrlRegs.high_ie -> Seq(RegField(c.width, highIeReg)),
169 GPIOCtrlRegs.high_ip -> Seq(RegField.w1ToClear(c.width, highIpReg, valueReg)),
170 GPIOCtrlRegs.low_ie -> Seq(RegField(c.width, lowIeReg)),
171 GPIOCtrlRegs.low_ip -> Seq(RegField.w1ToClear(c.width,lowIpReg, ~valueReg)),
172 GPIOCtrlRegs.port -> Seq(RegField(c.width, portReg)),
173 GPIOCtrlRegs.pullup_en -> Seq(RegField.rwReg(c.width, pueReg.io)),
174 GPIOCtrlRegs.iof_en -> iofEnFields,
175 GPIOCtrlRegs.iof_sel -> iofSelFields,
176 GPIOCtrlRegs.drive -> Seq(RegField(c.width, dsReg)),
177 GPIOCtrlRegs.input_en -> Seq(RegField.rwReg(c.width, ieReg.io)),
178 GPIOCtrlRegs.out_xor -> Seq(RegField(c.width, xorReg))
179
180 )
181
182 //--------------------------------------------------
183 // Actual Pinmux
184 // -------------------------------------------------
185
186 val swPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
187
188 // This strips off the valid.
189 val iof0Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
190 val iof1Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
191
192 val iofCtrl = Wire(Vec(c.width, new GPIOCtrl()))
193 val iofPlusSwPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
194
195
196 for (pin <- 0 until c.width) {
197
198 // Software Pin Control
199 swPinCtrl(pin).pue := pueReg.io.q(pin)
200 swPinCtrl(pin).oval := portReg(pin)
201 swPinCtrl(pin).oe := oeReg.io.q(pin)
202 swPinCtrl(pin).ds := dsReg(pin)
203 swPinCtrl(pin).ie := ieReg.io.q(pin)
204
205 val pre_xor = Wire(new GPIOPinCtrl())
206
207 if (c.includeIOF) {
208 // Allow SW Override for invalid inputs.
209 iof0Ctrl(pin) <> swPinCtrl(pin)
210 when (io.port.iof_0.get(pin).o.valid) {
211 iof0Ctrl(pin) <> io.port.iof_0.get(pin).o
212 }
213
214 iof1Ctrl(pin) <> swPinCtrl(pin)
215 when (io.port.iof_1.get(pin).o.valid) {
216 iof1Ctrl(pin) <> io.port.iof_1.get(pin).o
217 }
218
219 // Select IOF 0 vs. IOF 1.
220 iofCtrl(pin) <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin))
221
222 // Allow SW Override for things IOF doesn't control.
223 iofPlusSwPinCtrl(pin) <> swPinCtrl(pin)
224 iofPlusSwPinCtrl(pin) <> iofCtrl(pin)
225
226 // Final XOR & Pin Control
227 pre_xor := Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
228 } else {
229 pre_xor := swPinCtrl(pin)
230 }
231
232 io.port.pins(pin).o := pre_xor
233 io.port.pins(pin).o.oval := pre_xor.oval ^ xorReg(pin)
234
235 // Generate Interrupts
236 interrupts(pin) := (riseIpReg(pin) & riseIeReg(pin)) |
237 (fallIpReg(pin) & fallIeReg(pin)) |
238 (highIpReg(pin) & highIeReg(pin)) |
239 (lowIpReg(pin) & lowIeReg(pin))
240
241 if (c.includeIOF) {
242 // Send Value to all consumers
243 io.port.iof_0.get(pin).i.ival := inSyncReg(pin)
244 io.port.iof_1.get(pin).i.ival := inSyncReg(pin)
245 }
246 }
247 }
248
249 object GPIOOutputPinCtrl {
250
251 def apply( pin: GPIOPin, signal: Bool,
252 pue: Bool = Bool(false),
253 ds: Bool = Bool(false),
254 ie: Bool = Bool(false)
255 ): Unit = {
256 pin.o.oval := signal
257 pin.o.oe := Bool(true)
258 pin.o.pue := pue
259 pin.o.ds := ds
260 pin.o.ie := ie
261 }
262
263 def apply(pins: Vec[GPIOPin], signals: Bits,
264 pue: Bool, ds: Bool, ie: Bool
265 ): Unit = {
266 for ((signal, pin) <- (signals.toBools zip pins)) {
267 apply(pin, signal, pue, ds, ie)
268 }
269 }
270
271 def apply(pins: Vec[GPIOPin], signals: Bits): Unit = apply(pins, signals,
272 Bool(false), Bool(false), Bool(false))
273
274 }
275
276 object GPIOInputPinCtrl {
277
278 def apply (pin: GPIOPin, pue: Bool = Bool(false)): Bool = {
279 pin.o.oval := Bool(false)
280 pin.o.oe := Bool(false)
281 pin.o.pue := pue
282 pin.o.ds := Bool(false)
283 pin.o.ie := Bool(true)
284
285 pin.i.ival
286 }
287
288 def apply (pins: Vec[GPIOPin], pue: Bool): Vec[Bool] = {
289 val signals = Wire(Vec.fill(pins.size)(Bool(false)))
290 for ((signal, pin) <- (signals zip pins)) {
291 signal := GPIOInputPinCtrl(pin, pue)
292 }
293 signals
294 }
295
296 def apply (pins: Vec[GPIOPin]): Vec[Bool] = apply(pins, Bool(false))
297
298 }
299
300 // Magic TL2 Incantation to create a TL2 Slave
301 class TLGPIO(w: Int, c: GPIOParams)(implicit p: Parameters)
302 extends TLRegisterRouter(c.address, "gpio", Seq("sifive,gpio0"), interrupts = c.width, beatBytes = w)(
303 new TLRegBundle(c, _) with HasGPIOBundleContents)(
304 new TLRegModule(c, _, _) with HasGPIOModuleContents)