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