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