add IOF 2 and 3
[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 chisel3.experimental.MultiIOModule
6 import sifive.blocks.devices.pinctrl.{PinCtrl, Pin, BasePin, EnhancedPin, EnhancedPinCtrl}
7 import freechips.rocketchip.config.Parameters
8 import freechips.rocketchip.util.SynchronizerShiftReg
9 import freechips.rocketchip.regmapper._
10 import freechips.rocketchip.tilelink._
11 import freechips.rocketchip.util.AsyncResetRegVec
12
13 case class GPIOParams(address: BigInt, width: Int, includeIOF: Boolean = false)
14
15 // This is the actual IOF interface.pa
16 // Add a valid bit to indicate whether
17 // there is something actually connected
18 // to this.
19 class IOFCtrl extends PinCtrl {
20 val valid = Bool()
21 }
22
23 // By default,
24 object IOFCtrl {
25 def apply(): IOFCtrl = {
26 val iof = Wire(new IOFCtrl())
27 iof.valid := Bool(false)
28 iof.oval := Bool(false)
29 iof.oe := Bool(false)
30 iof.ie := Bool(false)
31 iof
32 }
33 }
34
35 // Package up the inputs and outputs
36 // for the IOF
37 class IOFPin extends Pin {
38 val o = new IOFCtrl().asOutput
39
40 def default(): Unit = {
41 this.o.oval := Bool(false)
42 this.o.oe := Bool(false)
43 this.o.ie := Bool(false)
44 this.o.valid := Bool(false)
45 }
46
47 def inputPin(pue: Bool = Bool(false) /*ignored*/): Bool = {
48 this.o.oval := Bool(false)
49 this.o.oe := Bool(false)
50 this.o.ie := Bool(true)
51 this.i.ival
52 }
53 def outputPin(signal: Bool,
54 pue: Bool = Bool(false), /*ignored*/
55 ds: Bool = Bool(false), /*ignored*/
56 ie: Bool = Bool(false)
57 ): Unit = {
58 this.o.oval := signal
59 this.o.oe := Bool(true)
60 this.o.ie := ie
61 }
62 }
63
64 // Connect both the i and o side of the pin,
65 // and drive the valid signal for the IOF.
66 object BasePinToIOF {
67 def apply(pin: BasePin, iof: IOFPin): Unit = {
68 iof <> pin
69 iof.o.valid := Bool(true)
70 }
71 }
72
73 // This is sort of weird because
74 // the IOF end up at the RocketChipTop
75 // level, and we have to do the pinmux
76 // outside of RocketChipTop.
77
78 class GPIOPortIO(private val c: GPIOParams) extends Bundle {
79 val pins = Vec(c.width, new EnhancedPin())
80 val iof_0 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None
81 val iof_1 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None
82 val iof_2 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None
83 val iof_3 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None
84 }
85
86 // It would be better if the IOF were here and
87 // we could do the pinmux inside.
88 trait HasGPIOBundleContents extends Bundle {
89 def params: GPIOParams
90 val port = new GPIOPortIO(params)
91 }
92
93 trait HasGPIOModuleContents extends MultiIOModule with HasRegMap {
94 val io: HasGPIOBundleContents
95 val params: GPIOParams
96 val c = params
97
98 //--------------------------------------------------
99 // CSR Declarations
100 // -------------------------------------------------
101
102 // SW Control only.
103 val portReg = Reg(init = UInt(0, c.width))
104
105 val oeReg = Module(new AsyncResetRegVec(c.width, 0))
106 val pueReg = Module(new AsyncResetRegVec(c.width, 0))
107 val dsReg = Reg(init = UInt(0, c.width))
108 val ieReg = Module(new AsyncResetRegVec(c.width, 0))
109
110 // Synchronize Input to get valueReg
111 val inVal = Wire(UInt(0, width=c.width))
112 inVal := Vec(io.port.pins.map(_.i.ival)).asUInt
113 val inSyncReg = SynchronizerShiftReg(inVal, 3, Some("inSyncReg"))
114 val valueReg = Reg(init = UInt(0, c.width), next = inSyncReg)
115
116 // Interrupt Configuration
117 val highIeReg = Reg(init = UInt(0, c.width))
118 val lowIeReg = Reg(init = UInt(0, c.width))
119 val riseIeReg = Reg(init = UInt(0, c.width))
120 val fallIeReg = Reg(init = UInt(0, c.width))
121 val highIpReg = Reg(init = UInt(0, c.width))
122 val lowIpReg = Reg(init = UInt(0, c.width))
123 val riseIpReg = Reg(init = UInt(0, c.width))
124 val fallIpReg = Reg(init = UInt(0, c.width))
125
126 // HW IO Function
127 val iofEnReg = Module(new AsyncResetRegVec(c.width, 0))
128 val iofSelReg = Reg(init = UInt(0, c.width))
129
130 // Invert Output
131 val xorReg = Reg(init = UInt(0, c.width))
132
133 //--------------------------------------------------
134 // CSR Access Logic (most of this section is boilerplate)
135 // -------------------------------------------------
136
137 val rise = ~valueReg & inSyncReg;
138 val fall = valueReg & ~inSyncReg;
139
140 val iofEnFields = if (c.includeIOF) (Seq(RegField.rwReg(c.width, iofEnReg.io))) else (Seq(RegField(c.width)))
141 val iofSelFields = if (c.includeIOF) (Seq(RegField(c.width, iofSelReg))) else (Seq(RegField(c.width)))
142
143
144 // Note that these are out of order.
145 regmap(
146 GPIOCtrlRegs.value -> Seq(RegField.r(c.width, valueReg)),
147 GPIOCtrlRegs.output_en -> Seq(RegField.rwReg(c.width, oeReg.io)),
148 GPIOCtrlRegs.rise_ie -> Seq(RegField(c.width, riseIeReg)),
149 GPIOCtrlRegs.rise_ip -> Seq(RegField.w1ToClear(c.width, riseIpReg, rise)),
150 GPIOCtrlRegs.fall_ie -> Seq(RegField(c.width, fallIeReg)),
151 GPIOCtrlRegs.fall_ip -> Seq(RegField.w1ToClear(c.width, fallIpReg, fall)),
152 GPIOCtrlRegs.high_ie -> Seq(RegField(c.width, highIeReg)),
153 GPIOCtrlRegs.high_ip -> Seq(RegField.w1ToClear(c.width, highIpReg, valueReg)),
154 GPIOCtrlRegs.low_ie -> Seq(RegField(c.width, lowIeReg)),
155 GPIOCtrlRegs.low_ip -> Seq(RegField.w1ToClear(c.width,lowIpReg, ~valueReg)),
156 GPIOCtrlRegs.port -> Seq(RegField(c.width, portReg)),
157 GPIOCtrlRegs.pullup_en -> Seq(RegField.rwReg(c.width, pueReg.io)),
158 GPIOCtrlRegs.iof_en -> iofEnFields,
159 GPIOCtrlRegs.iof_sel -> iofSelFields,
160 GPIOCtrlRegs.drive -> Seq(RegField(c.width, dsReg)),
161 GPIOCtrlRegs.input_en -> Seq(RegField.rwReg(c.width, ieReg.io)),
162 GPIOCtrlRegs.out_xor -> Seq(RegField(c.width, xorReg))
163
164 )
165
166 //--------------------------------------------------
167 // Actual Pinmux
168 // -------------------------------------------------
169
170 val swPinCtrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
171
172 // This strips off the valid.
173 val iof0Ctrl = Wire(Vec(c.width, new IOFCtrl()))
174 val iof1Ctrl = Wire(Vec(c.width, new IOFCtrl()))
175
176 val iofCtrl = Wire(Vec(c.width, new IOFCtrl()))
177 val iofPlusSwPinCtrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
178
179 for (pin <- 0 until c.width) {
180
181 // Software Pin Control
182 swPinCtrl(pin).pue := pueReg.io.q(pin)
183 swPinCtrl(pin).oval := portReg(pin)
184 swPinCtrl(pin).oe := oeReg.io.q(pin)
185 swPinCtrl(pin).ds := dsReg(pin)
186 swPinCtrl(pin).ie := ieReg.io.q(pin)
187
188 val pre_xor = Wire(new EnhancedPinCtrl())
189
190 if (c.includeIOF) {
191 // Allow SW Override for invalid inputs.
192 iof0Ctrl(pin) <> swPinCtrl(pin)
193 when (io.port.iof_0.get(pin).o.valid) {
194 iof0Ctrl(pin) <> io.port.iof_0.get(pin).o
195 }
196
197 iof1Ctrl(pin) <> swPinCtrl(pin)
198 when (io.port.iof_1.get(pin).o.valid) {
199 iof1Ctrl(pin) <> io.port.iof_1.get(pin).o
200 }
201
202 iof2Ctrl(pin) <> swPinCtrl(pin)
203 when (io.port.iof_2.get(pin).o.valid) {
204 iof1Ctrl(pin) <> io.port.iof_2.get(pin).o
205 }
206
207 iof2Ctrl(pin) <> swPinCtrl(pin)
208 when (io.port.iof_3.get(pin).o.valid) {
209 iof1Ctrl(pin) <> io.port.iof_3.get(pin).o
210 }
211
212 // Select IOF 0 vs. IOF 1 vs. IOF 2 vs. IOF 3.
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 pre_xor := Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
221 } else {
222 pre_xor := swPinCtrl(pin)
223 }
224
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 if (c.includeIOF) {
235 // Send Value to all consumers
236 io.port.iof_0.get(pin).i.ival := inSyncReg(pin)
237 io.port.iof_1.get(pin).i.ival := inSyncReg(pin)
238 io.port.iof_2.get(pin).i.ival := inSyncReg(pin)
239 io.port.iof_3.get(pin).i.ival := inSyncReg(pin)
240 }
241 }
242 }
243
244 // Magic TL2 Incantation to create a TL2 Slave
245 class TLGPIO(w: Int, c: GPIOParams)(implicit p: Parameters)
246 extends TLRegisterRouter(c.address, "gpio", Seq("sifive,gpio0"), interrupts = c.width, beatBytes = w)(
247 new TLRegBundle(c, _) with HasGPIOBundleContents)(
248 new TLRegModule(c, _, _) with HasGPIOModuleContents)