allow bundle content params to be specified via a def (#29)
[sifive-blocks.git] / src / main / scala / devices / gpio / GPIO.scala
index 4a0b3fcaf8e728dfe5b40bfb1a9d5fe3faab8edf..2bb04fe2a53a3760ebd047ef24495ef07956298d 100644 (file)
@@ -2,42 +2,26 @@
 package sifive.blocks.devices.gpio
 
 import Chisel._
-import config._
-import regmapper._
-import uncore.tilelink2._
-import rocketchip.PeripheryBusConfig
-import util.AsyncResetRegVec
+import sifive.blocks.devices.pinctrl.{PinCtrl, Pin, BasePin, EnhancedPin, EnhancedPinCtrl}
+import freechips.rocketchip.config.Parameters
+import freechips.rocketchip.regmapper._
+import freechips.rocketchip.tilelink._
+import freechips.rocketchip.util.{AsyncResetRegVec, GenericParameterizedBundle}
 
-case class GPIOConfig(address: BigInt, width: Int)
+case class GPIOParams(address: BigInt, width: Int, includeIOF: Boolean = false)
 
-trait HasGPIOParameters {
-  implicit val p: Parameters
-  val params: GPIOConfig
-  val c = params
-}
-
-// YAGNI: Make the PUE, DS, and
-// these also optionally HW controllable.
-// This is the base class of things you "always"
-// want to control from a HW block.
-class GPIOCtrl extends Bundle {
-  val oval = Bool()
-  val oe   = Bool()
-  val ie   = Bool()
-}
-
-// This is the actual IOF interface.
+// This is the actual IOF interface.pa
 // Add a valid bit to indicate whether
 // there is something actually connected
 // to this.
-class GPIOPinIOFCtrl extends GPIOCtrl {
+class IOFCtrl extends PinCtrl {
   val valid = Bool()
 }
 
 // By default,
-object GPIOPinIOFCtrl {
-  def apply(): GPIOPinIOFCtrl = {
-    val iof = Wire(new GPIOPinIOFCtrl())
+object IOFCtrl {
+  def apply(): IOFCtrl = {
+    val iof = Wire(new IOFCtrl())
     iof.valid := Bool(false)
     iof.oval  := Bool(false)
     iof.oe    := Bool(false)
@@ -46,53 +30,42 @@ object GPIOPinIOFCtrl {
   }
 }
 
-// This is the control for a physical
-// Pad.
-
-class GPIOPinCtrl extends GPIOCtrl {
-  val pue  = Bool() // Pull-up Enable
-  val ds   = Bool() // Drive Strength
-}
-
-object GPIOPinCtrl {
-  def apply(): GPIOPinCtrl = {
-    val pin = Wire(new GPIOPinCtrl())
-    pin.oval := Bool(false)
-    pin.oe   := Bool(false)
-    pin.pue  := Bool(false)
-    pin.ds   := Bool(false)
-    pin.ie   := Bool(false)
-    pin
-  }
-}
-
 // Package up the inputs and outputs
 // for the IOF
-class GPIOPinIOF extends Bundle {
-  val i = new Bundle {
-    val ival = Bool(INPUT)
+class IOFPin extends Pin {
+  val o  = new IOFCtrl().asOutput
+
+  def default(): Unit = {
+    this.o.oval  := Bool(false)
+    this.o.oe    := Bool(false)
+    this.o.ie    := Bool(false)
+    this.o.valid := Bool(false)
+  }
+
+  def inputPin(pue: Bool = Bool(false) /*ignored*/): Bool = {
+    this.o.oval := Bool(false)
+    this.o.oe   := Bool(false)
+    this.o.ie   := Bool(true)
+    this.i.ival
+  }
+  def outputPin(signal: Bool,
+    pue: Bool = Bool(false), /*ignored*/
+    ds: Bool = Bool(false), /*ignored*/
+    ie: Bool = Bool(false)
+  ): Unit = {
+    this.o.oval := signal
+    this.o.oe   := Bool(true)
+    this.o.ie   := ie
   }
-  val o = new GPIOPinIOFCtrl().asOutput
 }
 
 // Connect both the i and o side of the pin,
 // and drive the valid signal for the IOF.
-object GPIOPinToIOF {
-
-  def apply (pin: GPIOPin, iof: GPIOPinIOF): Unit = {
+object BasePinToIOF {
+  def apply(pin: BasePin, iof: IOFPin): Unit = {
     iof <> pin
     iof.o.valid := Bool(true)
   }
-
-}
-
-// Package up the inputs and outputs
-// for the Pin
-class GPIOPin extends Bundle {
-  val i = new Bundle {
-    val ival = Bool(INPUT)
-  }
-  val o = new GPIOPinCtrl().asOutput
 }
 
 // This is sort of weird because
@@ -100,20 +73,23 @@ class GPIOPin extends Bundle {
 // level, and we have to do the pinmux
 // outside of RocketChipTop.
 
-class GPIOPortIO(c: GPIOConfig) extends Bundle {
-  val pins = Vec(c.width, new GPIOPin)
-  val iof_0 = Vec(c.width, new GPIOPinIOF).flip
-  val iof_1 = Vec(c.width, new GPIOPinIOF).flip
+class GPIOPortIO(c: GPIOParams) extends GenericParameterizedBundle(c) {
+  val pins = Vec(c.width, new EnhancedPin())
+  val iof_0 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None
+  val iof_1 = if (c.includeIOF) Some(Vec(c.width, new IOFPin).flip) else None
 }
 
 // It would be better if the IOF were here and
 // we could do the pinmux inside.
-trait GPIOBundle extends Bundle with HasGPIOParameters {
-  val port = new GPIOPortIO(c)
+trait HasGPIOBundleContents extends Bundle {
+  def params: GPIOParams
+  val port = new GPIOPortIO(params)
 }
 
-trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
-  val io: GPIOBundle
+trait HasGPIOModuleContents extends Module with HasRegMap {
+  val io: HasGPIOBundleContents
+  val params: GPIOParams
+  val c = params
 
   //--------------------------------------------------
   // CSR Declarations
@@ -146,7 +122,7 @@ trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
   // HW IO Function
   val iofEnReg  = Module(new AsyncResetRegVec(c.width, 0))
   val iofSelReg = Reg(init = UInt(0, c.width))
-
+  
   // Invert Output
   val xorReg    = Reg(init = UInt(0, c.width))
 
@@ -157,6 +133,10 @@ trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
   val rise = ~valueReg & inSyncReg;
   val fall = valueReg & ~inSyncReg;
 
+  val iofEnFields =  if (c.includeIOF) (Seq(RegField.rwReg(c.width, iofEnReg.io))) else (Seq(RegField(c.width)))
+  val iofSelFields = if (c.includeIOF) (Seq(RegField(c.width, iofSelReg))) else (Seq(RegField(c.width)))
+
+
   // Note that these are out of order.
   regmap(
     GPIOCtrlRegs.value     -> Seq(RegField.r(c.width, valueReg)),
@@ -171,8 +151,8 @@ trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
     GPIOCtrlRegs.low_ip    -> Seq(RegField.w1ToClear(c.width,lowIpReg, ~valueReg)),
     GPIOCtrlRegs.port      -> Seq(RegField(c.width, portReg)),
     GPIOCtrlRegs.pullup_en -> Seq(RegField.rwReg(c.width, pueReg.io)),
-    GPIOCtrlRegs.iof_en    -> Seq(RegField.rwReg(c.width, iofEnReg.io)),
-    GPIOCtrlRegs.iof_sel   -> Seq(RegField(c.width, iofSelReg)),
+    GPIOCtrlRegs.iof_en    -> iofEnFields,
+    GPIOCtrlRegs.iof_sel   -> iofSelFields,
     GPIOCtrlRegs.drive     -> Seq(RegField(c.width, dsReg)),
     GPIOCtrlRegs.input_en  -> Seq(RegField.rwReg(c.width, ieReg.io)),
     GPIOCtrlRegs.out_xor   -> Seq(RegField(c.width, xorReg))
@@ -183,15 +163,14 @@ trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
   // Actual Pinmux
   // -------------------------------------------------
 
-  val swPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
+  val swPinCtrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
 
   // This strips off the valid.
-  val iof0Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
-  val iof1Ctrl = Wire(Vec(c.width, new GPIOCtrl()))
-
-  val iofCtrl = Wire(Vec(c.width, new GPIOCtrl()))
-  val iofPlusSwPinCtrl = Wire(Vec(c.width, new GPIOPinCtrl()))
+  val iof0Ctrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
+  val iof1Ctrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
 
+  val iofCtrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
+  val iofPlusSwPinCtrl = Wire(Vec(c.width, new EnhancedPinCtrl()))
 
   for (pin <- 0 until c.width) {
 
@@ -202,26 +181,33 @@ trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
     swPinCtrl(pin).ds     := dsReg(pin)
     swPinCtrl(pin).ie     := ieReg.io.q(pin)
 
-    // Allow SW Override for invalid inputs.
-    iof0Ctrl(pin)      <> swPinCtrl(pin)
-    when (io.port.iof_0(pin).o.valid) {
-      iof0Ctrl(pin)    <> io.port.iof_0(pin).o
-    }
-
-    iof1Ctrl(pin)      <> swPinCtrl(pin)
-    when (io.port.iof_1(pin).o.valid) {
-      iof1Ctrl(pin)    <> io.port.iof_1(pin).o
+    val pre_xor = Wire(new EnhancedPinCtrl())
+
+    if (c.includeIOF) {
+      // Allow SW Override for invalid inputs.
+      iof0Ctrl(pin)      <> swPinCtrl(pin)
+      when (io.port.iof_0.get(pin).o.valid) {
+        iof0Ctrl(pin)    <> io.port.iof_0.get(pin).o
+      }
+
+      iof1Ctrl(pin)      <> swPinCtrl(pin)
+      when (io.port.iof_1.get(pin).o.valid) {
+        iof1Ctrl(pin)    <> io.port.iof_1.get(pin).o
+      }
+
+      // Select IOF 0 vs. IOF 1.
+      iofCtrl(pin)       <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin))
+
+      // Allow SW Override for things IOF doesn't control.
+      iofPlusSwPinCtrl(pin) <> swPinCtrl(pin)
+      iofPlusSwPinCtrl(pin) <> iofCtrl(pin)
+   
+      // Final XOR & Pin Control
+      pre_xor  := Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
+    } else {
+      pre_xor := swPinCtrl(pin)
     }
 
-    // Select IOF 0 vs. IOF 1.
-    iofCtrl(pin)       <> Mux(iofSelReg(pin), iof1Ctrl(pin), iof0Ctrl(pin))
-
-    // Allow SW Override for things IOF doesn't control.
-    iofPlusSwPinCtrl(pin) <> swPinCtrl(pin)
-    iofPlusSwPinCtrl(pin) <> iofCtrl(pin)
-
-    // Final XOR & Pin Control
-    val pre_xor: GPIOPinCtrl = Mux(iofEnReg.io.q(pin), iofPlusSwPinCtrl(pin), swPinCtrl(pin))
     io.port.pins(pin).o      := pre_xor
     io.port.pins(pin).o.oval := pre_xor.oval ^ xorReg(pin)
 
@@ -231,65 +217,16 @@ trait GPIOModule extends Module with HasGPIOParameters with HasRegMap {
                          (highIpReg(pin) & highIeReg(pin)) |
                          (lowIpReg(pin) & lowIeReg(pin))
 
-    // Send Value to all consumers
-    io.port.iof_0(pin).i.ival := inSyncReg(pin)
-    io.port.iof_1(pin).i.ival := inSyncReg(pin)
-  }
-}
-
-object GPIOOutputPinCtrl {
-
-  def apply( pin: GPIOPin, signal: Bool,
-    pue: Bool = Bool(false),
-    ds:  Bool = Bool(false),
-    ie:  Bool = Bool(false)
-  ): Unit = {
-    pin.o.oval := signal
-    pin.o.oe   := Bool(true)
-    pin.o.pue  := pue
-    pin.o.ds   := ds
-    pin.o.ie   := ie
-  }
-
-  def apply(pins: Vec[GPIOPin], signals: Bits,
-    pue: Bool, ds:  Bool, ie:  Bool
-  ): Unit = {
-    for ((signal, pin) <- (signals.toBools zip pins)) {
-      apply(pin, signal, pue, ds, ie)
+    if (c.includeIOF) {
+      // Send Value to all consumers
+      io.port.iof_0.get(pin).i.ival := inSyncReg(pin)
+      io.port.iof_1.get(pin).i.ival := inSyncReg(pin)
     }
   }
-
-  def apply(pins: Vec[GPIOPin], signals: Bits): Unit = apply(pins, signals,
-    Bool(false), Bool(false), Bool(false))
-
-}
-
-object GPIOInputPinCtrl {
-
-  def apply (pin: GPIOPin, pue: Bool = Bool(false)): Bool = {
-    pin.o.oval := Bool(false)
-    pin.o.oe   := Bool(false)
-    pin.o.pue  := pue
-    pin.o.ds   := Bool(false)
-    pin.o.ie   := Bool(true)
-
-    pin.i.ival
-  }
-
-  def apply (pins: Vec[GPIOPin], pue: Bool): Vec[Bool] = {
-    val signals = Wire(Vec.fill(pins.size)(Bool(false)))
-    for ((signal, pin) <- (signals zip pins)) {
-      signal := GPIOInputPinCtrl(pin, pue)
-    }
-    signals
-  }
-
-  def apply (pins: Vec[GPIOPin]): Vec[Bool] = apply(pins, Bool(false))
-
 }
 
 // Magic TL2 Incantation to create a TL2 Slave
-class TLGPIO(c: GPIOConfig)(implicit p: Parameters)
-  extends TLRegisterRouter(c.address, interrupts = c.width, beatBytes = p(PeripheryBusConfig).beatBytes)(
-  new TLRegBundle(c, _)    with GPIOBundle)(
-  new TLRegModule(c, _, _) with GPIOModule)
+class TLGPIO(w: Int, c: GPIOParams)(implicit p: Parameters)
+  extends TLRegisterRouter(c.address, "gpio", Seq("sifive,gpio0"), interrupts = c.width, beatBytes = w)(
+  new TLRegBundle(c, _)    with HasGPIOBundleContents)(
+  new TLRegModule(c, _, _) with HasGPIOModuleContents)