Initial commit.
[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 config._
6 import regmapper._
7 import uncore.tilelink2._
8 import rocketchip.PeripheryBusConfig
9 import util.AsyncResetRegVec
10
11 case class GPIOConfig(address: BigInt, width: Int)
12
13 trait HasGPIOParameters {
14 val params: Tuple2[Parameters, GPIOConfig]
15 implicit val p = params._1
16 val c = params._2
17 }
18
19 // YAGNI: Make the PUE, DS, and
20 // these also optionally HW controllable.
21 // This is the base class of things you "always"
22 // want to control from a HW block.
23 class GPIOCtrl extends Bundle {
24 val oval = Bool()
25 val oe = Bool()
26 val ie = Bool()
27 }
28
29 // This is the actual IOF interface.
30 // Add a valid bit to indicate whether
31 // there is something actually connected
32 // to this.
33 class GPIOPinIOFCtrl extends GPIOCtrl {
34 val valid = Bool()
35 }
36
37 // By default,
38 object GPIOPinIOFCtrl {
39 def apply(): GPIOPinIOFCtrl = {
40 val iof = Wire(new GPIOPinIOFCtrl())
41 iof.valid := Bool(false)
42 iof.oval := Bool(false)
43 iof.oe := Bool(false)
44 iof.ie := Bool(false)
45 iof
46 }
47 }
48
49 // This is the control for a physical
50 // Pad.
51
52 class GPIOPinCtrl extends GPIOCtrl {
53 val pue = Bool() // Pull-up Enable
54 val ds = Bool() // Drive Strength
55 }
56
57 object GPIOPinCtrl {
58 def apply(): GPIOPinCtrl = {
59 val pin = Wire(new GPIOPinCtrl())
60 pin.oval := Bool(false)
61 pin.oe := Bool(false)
62 pin.pue := Bool(false)
63 pin.ds := Bool(false)
64 pin.ie := Bool(false)
65 pin
66 }
67 }
68
69 // Package up the inputs and outputs
70 // for the IOF
71 class GPIOPinIOF extends Bundle {
72 val i = new Bundle {
73 val ival = Bool(INPUT)
74 }
75 val o = new GPIOPinIOFCtrl().asOutput
76 }
77
78 // Connect both the i and o side of the pin,
79 // and drive the valid signal for the IOF.
80 object GPIOPinToIOF {
81
82 def apply (pin: GPIOPin, iof: GPIOPinIOF): Unit = {
83 iof <> pin
84 iof.o.valid := Bool(true)
85 }
86
87 }
88
89 // Package up the inputs and outputs
90 // for the Pin
91 class GPIOPin extends Bundle {
92 val i = new Bundle {
93 val ival = Bool(INPUT)
94 }
95 val o = new GPIOPinCtrl().asOutput
96 }
97
98 // This is sort of weird because
99 // the IOF end up at the RocketChipTop
100 // level, and we have to do the pinmux
101 // outside of RocketChipTop.
102
103 class GPIOPortIO(c: GPIOConfig) extends Bundle {
104 val pins = Vec(c.width, new GPIOPin)
105 val iof_0 = Vec(c.width, new GPIOPinIOF).flip
106 val iof_1 = Vec(c.width, new GPIOPinIOF).flip
107 }
108
109 // It would be better if the IOF were here and
110 // we could do the pinmux inside.
111 trait GPIOBundle extends Bundle with HasGPIOParameters {
112 val port = new GPIOPortIO(c)
113 }
114
115 trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
116 val io: GPIOBundle
117
118 //--------------------------------------------------
119 // CSR Declarations
120 // -------------------------------------------------
121
122 // SW Control only.
123 val portReg = Reg(init = UInt(0, c.width))
124
125 val oeReg = Module(new AsyncResetRegVec(c.width, 0))
126 val pueReg = Module(new AsyncResetRegVec(c.width, 0))
127 val dsReg = Reg(init = UInt(0, c.width))
128 val ieReg = Module(new AsyncResetRegVec(c.width, 0))
129
130 // Synchronize Input to get valueReg
131 val inVal = Wire(UInt(0, width=c.width))
132 inVal := Vec(io.port.pins.map(_.i.ival)).asUInt
133 val inSyncReg = ShiftRegister(inVal, 3)
134 val valueReg = Reg(init = UInt(0, c.width), next = inSyncReg)
135
136 // Interrupt Configuration
137 val highIeReg = Reg(init = UInt(0, c.width))
138 val lowIeReg = Reg(init = UInt(0, c.width))
139 val riseIeReg = Reg(init = UInt(0, c.width))
140 val fallIeReg = Reg(init = UInt(0, c.width))
141 val highIpReg = Reg(init = UInt(0, c.width))
142 val lowIpReg = Reg(init = UInt(0, c.width))
143 val riseIpReg = Reg(init = UInt(0, c.width))
144 val fallIpReg = Reg(init = UInt(0, c.width))
145
146 // HW IO Function
147 val iofEnReg = Module(new AsyncResetRegVec(c.width, 0))
148 val iofSelReg = Reg(init = UInt(0, c.width))
149
150 // Invert Output
151 val xorReg = Reg(init = UInt(0, c.width))
152
153 //--------------------------------------------------
154 // CSR Access Logic (most of this section is boilerplate)
155 // -------------------------------------------------
156
157 val rise = ~valueReg & inSyncReg;
158 val fall = valueReg & ~inSyncReg;
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 -> Seq(RegField.rwReg(c.width, iofEnReg.io)),
175 GPIOCtrlRegs.iof_sel -> Seq(RegField(c.width, iofSelReg)),
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 // Allow SW Override for invalid inputs.
206 iof0Ctrl(pin) <> swPinCtrl(pin)
207 when (io.port.iof_0(pin).o.valid) {
208 iof0Ctrl(pin) <> io.port.iof_0(pin).o
209 }
210
211 iof1Ctrl(pin) <> swPinCtrl(pin)
212 when (io.port.iof_1(pin).o.valid) {
213 iof1Ctrl(pin) <> io.port.iof_1(pin).o
214 }
215
216 // Select IOF 0 vs. IOF 1.
217 iofCtrl(pin) <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin))
218
219 // Allow SW Override for things IOF doesn't control.
220 iofPlusSwPinCtrl(pin) <> swPinCtrl(pin)
221 iofPlusSwPinCtrl(pin) <> iofCtrl(pin)
222
223 // Final XOR & Pin Control
224 val pre_xor: GPIOPinCtrl = Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
225 io.port.pins(pin).o := pre_xor
226 io.port.pins(pin).o.oval := pre_xor.oval ^ xorReg(pin)
227
228 // Generate Interrupts
229 interrupts(pin) := (riseIpReg(pin) & riseIeReg(pin)) |
230 (fallIpReg(pin) & fallIeReg(pin)) |
231 (highIpReg(pin) & highIeReg(pin)) |
232 (lowIpReg(pin) & lowIeReg(pin))
233
234 // Send Value to all consumers
235 io.port.iof_0(pin).i.ival := inSyncReg(pin)
236 io.port.iof_1(pin).i.ival := inSyncReg(pin)
237 }
238 }
239
240 object GPIOOutputPinCtrl {
241
242 def apply( pin: GPIOPin, signal: Bool,
243 pue: Bool = Bool(false),
244 ds: Bool = Bool(false),
245 ie: Bool = Bool(false)
246 ): Unit = {
247 pin.o.oval := signal
248 pin.o.oe := Bool(true)
249 pin.o.pue := pue
250 pin.o.ds := ds
251 pin.o.ie := ie
252 }
253
254 def apply(pins: Vec[GPIOPin], signals: Bits,
255 pue: Bool, ds: Bool, ie: Bool
256 ): Unit = {
257 for ((signal, pin) <- (signals.toBools zip pins)) {
258 apply(pin, signal, pue, ds, ie)
259 }
260 }
261
262 def apply(pins: Vec[GPIOPin], signals: Bits): Unit = apply(pins, signals,
263 Bool(false), Bool(false), Bool(false))
264
265 }
266
267 object GPIOInputPinCtrl {
268
269 def apply (pin: GPIOPin, pue: Bool = Bool(false)): Bool = {
270 pin.o.oval := Bool(false)
271 pin.o.oe := Bool(false)
272 pin.o.pue := pue
273 pin.o.ds := Bool(false)
274 pin.o.ie := Bool(true)
275
276 pin.i.ival
277 }
278
279 def apply (pins: Vec[GPIOPin], pue: Bool): Vec[Bool] = {
280 val signals = Wire(Vec.fill(pins.size)(Bool(false)))
281 for ((signal, pin) <- (signals zip pins)) {
282 signal := GPIOInputPinCtrl(pin, pue)
283 }
284 signals
285 }
286
287 def apply (pins: Vec[GPIOPin]): Vec[Bool] = apply(pins, Bool(false))
288
289 }
290
291 // Magic TL2 Incantation to create a TL2 Slave
292 class TLGPIO(p: Parameters, c: GPIOConfig)
293 extends TLRegisterRouter(c.address, interrupts = c.width, beatBytes = p(PeripheryBusConfig).beatBytes)(
294 new TLRegBundle(Tuple2(p, c), _) with GPIOBundle)(
295 new TLRegModule(Tuple2(p, c), _, _) with GPIOModule)