From 9d2a173b15ff2f9c546d95261fd171cf6da51328 Mon Sep 17 00:00:00 2001 From: Alex Solomatnikov Date: Tue, 24 Jan 2017 14:58:01 -0800 Subject: [PATCH] Initial (compilable) version of I2C (no actual logic yet) --- src/main/scala/devices/i2c/I2C.scala | 58 +++++++++++++++++++ src/main/scala/devices/i2c/I2CCtrlRegs.scala | 13 +++++ src/main/scala/devices/i2c/I2CPeriphery.scala | 34 +++++++++++ src/main/scala/devices/i2c/I2CPins.scala | 27 +++++++++ 4 files changed, 132 insertions(+) create mode 100644 src/main/scala/devices/i2c/I2C.scala create mode 100644 src/main/scala/devices/i2c/I2CCtrlRegs.scala create mode 100644 src/main/scala/devices/i2c/I2CPeriphery.scala create mode 100644 src/main/scala/devices/i2c/I2CPins.scala diff --git a/src/main/scala/devices/i2c/I2C.scala b/src/main/scala/devices/i2c/I2C.scala new file mode 100644 index 0000000..e5959c5 --- /dev/null +++ b/src/main/scala/devices/i2c/I2C.scala @@ -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 index 0000000..1a69783 --- /dev/null +++ b/src/main/scala/devices/i2c/I2CCtrlRegs.scala @@ -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 index 0000000..8eb7418 --- /dev/null +++ b/src/main/scala/devices/i2c/I2CPeriphery.scala @@ -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 index 0000000..d7017bc --- /dev/null +++ b/src/main/scala/devices/i2c/I2CPins.scala @@ -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)) +} -- 2.30.2