Initial (compilable) version of I2C (no actual logic yet)
authorAlex Solomatnikov <sols@gamma06.internal.sifive.com>
Tue, 24 Jan 2017 22:58:01 +0000 (14:58 -0800)
committerAlex Solomatnikov <sols@gamma06.internal.sifive.com>
Tue, 24 Jan 2017 22:58:01 +0000 (14:58 -0800)
src/main/scala/devices/i2c/I2C.scala [new file with mode: 0644]
src/main/scala/devices/i2c/I2CCtrlRegs.scala [new file with mode: 0644]
src/main/scala/devices/i2c/I2CPeriphery.scala [new file with mode: 0644]
src/main/scala/devices/i2c/I2CPins.scala [new file with mode: 0644]

diff --git a/src/main/scala/devices/i2c/I2C.scala b/src/main/scala/devices/i2c/I2C.scala
new file mode 100644 (file)
index 0000000..e5959c5
--- /dev/null
@@ -0,0 +1,58 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.i2c
+
+import Chisel._
+import config._
+import regmapper._
+import uncore.tilelink2._
+import rocketchip.PeripheryBusConfig
+import util.AsyncResetRegVec
+import sifive.blocks.devices.gpio.{GPIOPinCtrl}
+
+case class I2CConfig(address: BigInt)
+
+trait HasI2CParameters {
+  implicit val p: Parameters
+  val params: I2CConfig
+  val c = params
+}
+
+class I2CPin extends Bundle {
+  val in  = Bool(INPUT)
+  val out = Bool(OUTPUT)
+  val oe  = Bool(OUTPUT)
+}
+
+class I2CPort extends Bundle {
+  val scl = new I2CPin
+  val sda = new I2CPin
+}
+
+trait I2CBundle extends Bundle with HasI2CParameters {
+  val port = new I2CPort
+}
+
+trait I2CModule extends Module with HasI2CParameters with HasRegMap {
+  val io: I2CBundle
+
+  val prescaler_lo = Reg(UInt(8.W))  // low byte clock prescaler register
+  val prescaler_hi = Reg(UInt(8.W))  // high byte clock prescaler register
+  val control      = Reg(UInt(8.W))  // control register
+  val data         = Reg(UInt(8.W))  // write: transmit byte, read: receive byte
+  val cmd_status   = Reg(UInt(8.W))  // write: command, read: status
+
+  // Note that these are out of order.
+  regmap(
+    I2CCtrlRegs.prescaler_lo -> Seq(RegField(8, prescaler_lo)),
+    I2CCtrlRegs.prescaler_hi -> Seq(RegField(8, prescaler_hi)),
+    I2CCtrlRegs.control      -> Seq(RegField(8, control)),
+    I2CCtrlRegs.data         -> Seq(RegField(8, data)),
+    I2CCtrlRegs.cmd_status   -> Seq(RegField(8, cmd_status))
+  )
+}
+
+// Magic TL2 Incantation to create a TL2 Slave
+class TLI2C(c: I2CConfig)(implicit p: Parameters)
+  extends TLRegisterRouter(c.address, interrupts = 1, beatBytes = p(PeripheryBusConfig).beatBytes)(
+  new TLRegBundle(c, _)    with I2CBundle)(
+  new TLRegModule(c, _, _) with I2CModule)
diff --git a/src/main/scala/devices/i2c/I2CCtrlRegs.scala b/src/main/scala/devices/i2c/I2CCtrlRegs.scala
new file mode 100644 (file)
index 0000000..1a69783
--- /dev/null
@@ -0,0 +1,13 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.i2c
+
+// matching Open Cores I2C to re-use Linux driver
+// http://lxr.free-electrons.com/source/drivers/i2c/busses/i2c-ocores.c?v=4.6
+
+object I2CCtrlRegs {
+  val prescaler_lo = 0x00  // low byte clock prescaler register
+  val prescaler_hi = 0x01  // high byte clock prescaler register
+  val control      = 0x02  // control register
+  val data         = 0x03  // write: transmit byte, read: receive byte
+  val cmd_status   = 0x04  // write: command, read: status
+}
diff --git a/src/main/scala/devices/i2c/I2CPeriphery.scala b/src/main/scala/devices/i2c/I2CPeriphery.scala
new file mode 100644 (file)
index 0000000..8eb7418
--- /dev/null
@@ -0,0 +1,34 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.i2c
+
+import Chisel._
+import diplomacy.LazyModule
+import rocketchip.{TopNetwork,TopNetworkModule}
+import uncore.tilelink2.TLFragmenter
+
+trait PeripheryI2C {
+  this: TopNetwork { val i2cConfigs: Seq[I2CConfig] } =>
+  val i2cDevices = i2cConfigs.zipWithIndex.map { case (c, i) =>
+    val i2c = LazyModule(new TLI2C(c))
+    i2c.suggestName(s"i2c$i")
+    i2c.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
+    intBus.intnode := i2c.intnode
+    i2c
+  }
+}
+
+trait PeripheryI2CBundle {
+  this: { val i2cConfigs: Seq[I2CConfig] } =>
+  val i2cs = Vec(i2cConfigs.size, new I2CPort)
+}
+
+trait PeripheryI2CModule {
+  this: TopNetworkModule {
+    val i2cConfigs: Seq[I2CConfig]
+    val outer: PeripheryI2C
+    val io: PeripheryI2CBundle
+  } =>
+  (io.i2cs zip outer.i2cDevices).foreach { case (io, device) =>
+    io <> device.module.io.port
+  }
+}
diff --git a/src/main/scala/devices/i2c/I2CPins.scala b/src/main/scala/devices/i2c/I2CPins.scala
new file mode 100644 (file)
index 0000000..d7017bc
--- /dev/null
@@ -0,0 +1,27 @@
+// See LICENSE for license details.
+package sifive.blocks.devices.i2c
+
+import Chisel._
+import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl}
+import sifive.blocks.util.ShiftRegisterInit
+
+
+class I2CPinsIO extends Bundle {
+  val scl = new GPIOPin
+  val sda = new GPIOPin
+}
+
+class I2CGPIOPort(syncStages: Int = 0) extends Module {
+  val io = new Bundle{
+    val i2c = new I2CPort().flip()
+    val pins = new I2CPinsIO
+  }
+
+  GPIOOutputPinCtrl(io.pins.scl, io.i2c.scl.out, pue=true.B, ie = true.B)
+  io.pins.scl.o.oe := io.i2c.scl.oe
+  io.i2c.scl.in := ShiftRegisterInit(io.pins.scl.i.ival, syncStages, Bool(true))
+
+  GPIOOutputPinCtrl(io.pins.sda, io.i2c.sda.out, pue=true.B, ie = true.B)
+  io.pins.sda.o.oe := io.i2c.sda.oe
+  io.i2c.sda.in := ShiftRegisterInit(io.pins.sda.i.ival, syncStages, Bool(true))
+}