9dd8d87ba58ef8d6da8da59263fa5fd771641a14
[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.Parameters
6 import regmapper._
7 import uncore.tilelink2._
8 import util.AsyncResetRegVec
9
10 case class GPIOParams(address: BigInt, width: Int)
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 Bundle {
97 val pins = Vec(c.width, new GPIOPin)
98 val iof_0 = Vec(c.width, new GPIOPinIOF).flip
99 val iof_1 = Vec(c.width, new GPIOPinIOF).flip
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 // Note that these are out of order.
157 regmap(
158 GPIOCtrlRegs.value -> Seq(RegField.r(c.width, valueReg)),
159 GPIOCtrlRegs.output_en -> Seq(RegField.rwReg(c.width, oeReg.io)),
160 GPIOCtrlRegs.rise_ie -> Seq(RegField(c.width, riseIeReg)),
161 GPIOCtrlRegs.rise_ip -> Seq(RegField.w1ToClear(c.width, riseIpReg, rise)),
162 GPIOCtrlRegs.fall_ie -> Seq(RegField(c.width, fallIeReg)),
163 GPIOCtrlRegs.fall_ip -> Seq(RegField.w1ToClear(c.width, fallIpReg, fall)),
164 GPIOCtrlRegs.high_ie -> Seq(RegField(c.width, highIeReg)),
165 GPIOCtrlRegs.high_ip -> Seq(RegField.w1ToClear(c.width, highIpReg, valueReg)),
166 GPIOCtrlRegs.low_ie -> Seq(RegField(c.width, lowIeReg)),
167 GPIOCtrlRegs.low_ip -> Seq(RegField.w1ToClear(c.width,lowIpReg, ~valueReg)),
168 GPIOCtrlRegs.port -> Seq(RegField(c.width, portReg)),
169 GPIOCtrlRegs.pullup_en -> Seq(RegField.rwReg(c.width, pueReg.io)),
170 GPIOCtrlRegs.iof_en -> Seq(RegField.rwReg(c.width, iofEnReg.io)),
171 GPIOCtrlRegs.iof_sel -> Seq(RegField(c.width, iofSelReg)),
172 GPIOCtrlRegs.drive -> Seq(RegField(c.width, dsReg)),
173 GPIOCtrlRegs.input_en -> Seq(RegField.rwReg(c.width, ieReg.io)),
174 GPIOCtrlRegs.out_xor -> Seq(RegField(c.width, xorReg))
175
176 )
177
178 //--------------------------------------------------
179 // Actual Pinmux
180 // -------------------------------------------------
181
182 val swPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
183
184 // This strips off the valid.
185 val iof0Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
186 val iof1Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
187
188 val iofCtrl = Wire(Vec(c.width, new GPIOCtrl()))
189 val iofPlusSwPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
190
191
192 for (pin <- 0 until c.width) {
193
194 // Software Pin Control
195 swPinCtrl(pin).pue := pueReg.io.q(pin)
196 swPinCtrl(pin).oval := portReg(pin)
197 swPinCtrl(pin).oe := oeReg.io.q(pin)
198 swPinCtrl(pin).ds := dsReg(pin)
199 swPinCtrl(pin).ie := ieReg.io.q(pin)
200
201 // Allow SW Override for invalid inputs.
202 iof0Ctrl(pin) <> swPinCtrl(pin)
203 when (io.port.iof_0(pin).o.valid) {
204 iof0Ctrl(pin) <> io.port.iof_0(pin).o
205 }
206
207 iof1Ctrl(pin) <> swPinCtrl(pin)
208 when (io.port.iof_1(pin).o.valid) {
209 iof1Ctrl(pin) <> io.port.iof_1(pin).o
210 }
211
212 // Select IOF 0 vs. IOF 1.
213 iofCtrl(pin) <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin))
214
215 // Allow SW Override for things IOF doesn't control.
216 iofPlusSwPinCtrl(pin) <> swPinCtrl(pin)
217 iofPlusSwPinCtrl(pin) <> iofCtrl(pin)
218
219 // Final XOR & Pin Control
220 val pre_xor: GPIOPinCtrl = Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
221 io.port.pins(pin).o := pre_xor
222 io.port.pins(pin).o.oval := pre_xor.oval ^ xorReg(pin)
223
224 // Generate Interrupts
225 interrupts(pin) := (riseIpReg(pin) & riseIeReg(pin)) |
226 (fallIpReg(pin) & fallIeReg(pin)) |
227 (highIpReg(pin) & highIeReg(pin)) |
228 (lowIpReg(pin) & lowIeReg(pin))
229
230 // Send Value to all consumers
231 io.port.iof_0(pin).i.ival := inSyncReg(pin)
232 io.port.iof_1(pin).i.ival := inSyncReg(pin)
233 }
234 }
235
236 object GPIOOutputPinCtrl {
237
238 def apply( pin: GPIOPin, signal: Bool,
239 pue: Bool = Bool(false),
240 ds: Bool = Bool(false),
241 ie: Bool = Bool(false)
242 ): Unit = {
243 pin.o.oval := signal
244 pin.o.oe := Bool(true)
245 pin.o.pue := pue
246 pin.o.ds := ds
247 pin.o.ie := ie
248 }
249
250 def apply(pins: Vec[GPIOPin], signals: Bits,
251 pue: Bool, ds: Bool, ie: Bool
252 ): Unit = {
253 for ((signal, pin) <- (signals.toBools zip pins)) {
254 apply(pin, signal, pue, ds, ie)
255 }
256 }
257
258 def apply(pins: Vec[GPIOPin], signals: Bits): Unit = apply(pins, signals,
259 Bool(false), Bool(false), Bool(false))
260
261 }
262
263 object GPIOInputPinCtrl {
264
265 def apply (pin: GPIOPin, pue: Bool = Bool(false)): Bool = {
266 pin.o.oval := Bool(false)
267 pin.o.oe := Bool(false)
268 pin.o.pue := pue
269 pin.o.ds := Bool(false)
270 pin.o.ie := Bool(true)
271
272 pin.i.ival
273 }
274
275 def apply (pins: Vec[GPIOPin], pue: Bool): Vec[Bool] = {
276 val signals = Wire(Vec.fill(pins.size)(Bool(false)))
277 for ((signal, pin) <- (signals zip pins)) {
278 signal := GPIOInputPinCtrl(pin, pue)
279 }
280 signals
281 }
282
283 def apply (pins: Vec[GPIOPin]): Vec[Bool] = apply(pins, Bool(false))
284
285 }
286
287 // Magic TL2 Incantation to create a TL2 Slave
288 class TLGPIO(w: Int, c: GPIOParams)(implicit p: Parameters)
289 extends TLRegisterRouter(c.address, "gpio", Seq("sifive,gpio0"), interrupts = c.width, beatBytes = w)(
290 new TLRegBundle(c, _) with HasGPIOBundleContents)(
291 new TLRegModule(c, _, _) with HasGPIOModuleContents)