X-Git-Url: https://git.libre-soc.org/?p=sifive-blocks.git;a=blobdiff_plain;f=src%2Fmain%2Fscala%2Fdevices%2Fi2c%2FI2C.scala;h=b3e2db5f7cb0d88556bcf027ed7f1aee5034b0ee;hp=363d37b6eec33553f3e1f000cc535e19d90bfc96;hb=3dee15277598e45d7ac9d435f0365989c6d00f7e;hpb=baccd5ada2ab54381d9f4c75a3e3e72f39b2bcef diff --git a/src/main/scala/devices/i2c/I2C.scala b/src/main/scala/devices/i2c/I2C.scala index 363d37b..b3e2db5 100644 --- a/src/main/scala/devices/i2c/I2C.scala +++ b/src/main/scala/devices/i2c/I2C.scala @@ -42,11 +42,11 @@ package sifive.blocks.devices.i2c import Chisel._ -import config._ -import regmapper._ -import uncore.tilelink2._ -import util.{AsyncResetRegVec, Majority} -import sifive.blocks.devices.gpio.{GPIOPinCtrl} +import chisel3.experimental.MultiIOModule +import freechips.rocketchip.config._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util.{AsyncResetRegVec, Majority} case class I2CParams(address: BigInt) @@ -65,7 +65,7 @@ trait HasI2CBundleContents extends Bundle { val port = new I2CPort } -trait HasI2CModuleContents extends Module with HasRegMap { +trait HasI2CModuleContents extends MultiIOModule with HasRegMap { val io: HasI2CBundleContents val params: I2CParams @@ -202,7 +202,7 @@ trait HasI2CModuleContents extends Module with HasRegMap { s_bit_wr_a :: s_bit_wr_b :: s_bit_wr_c :: s_bit_wr_d :: Nil) = Enum(UInt(), 18) val bitState = Reg(init = s_bit_idle) - val arbLost = Reg(init = false.B, next = (sdaChk && !sSDA && sdaOen) | ((bitState === s_bit_idle) && stopCond && !bitCmdStop)) + val arbLost = Reg(init = false.B, next = (sdaChk && !sSDA && sdaOen) | ((bitState =/= s_bit_idle) && stopCond && !bitCmdStop)) // bit FSM when (arbLost) { @@ -488,16 +488,16 @@ trait HasI2CModuleContents extends Module with HasRegMap { // hack: b/c the same register offset is used to write cmd and read status val nextCmd = Wire(UInt(8.W)) - nextCmd := cmd.asUInt cmd := (new CommandBundle).fromBits(nextCmd) + nextCmd := cmd.asUInt & 0xFE.U // clear IRQ_ACK bit (essentially 1 cycle pulse b/c it is overwritten by regmap below) + // Note: This wins over the regmap update of nextCmd (even if something tries to write them to 1, these values take priority). when (cmdAck || arbLost) { cmd.start := false.B // clear command bits when done cmd.stop := false.B // or when aribitration lost cmd.read := false.B cmd.write := false.B } - cmd.irqAck := false.B // clear IRQ_ACK bit (essentially 1 cycle pulse b/c it is overwritten by regmap below) status.receivedAck := receivedAck when (stopCond) { @@ -514,15 +514,34 @@ trait HasI2CModuleContents extends Module with HasRegMap { status.arbLost := false.B } status.transferInProgress := cmd.read || cmd.write - status.irqFlag := (cmdAck || arbLost || status.irqFlag) && !cmd.irqAck + status.irqFlag := (cmdAck || arbLost || status.irqFlag) && !cmd.irqAck // interrupt request flag is always generated + val statusReadReady = Reg(init = true.B) + when (cmdAck || arbLost) { // => cmd.read or cmd.write deassert 1 cycle later => transferInProgress deassert 2 cycles later + statusReadReady := false.B // do not allow status read if status.transferInProgress is going to change + } + .elsewhen (!statusReadReady) { + statusReadReady := true.B + } + + // statusReadReady, regmap( I2CCtrlRegs.prescaler_lo -> Seq(RegField(8, prescaler.lo)), I2CCtrlRegs.prescaler_hi -> Seq(RegField(8, prescaler.hi)), I2CCtrlRegs.control -> control.elements.map{ case(name, e) => RegField(e.getWidth, e.asInstanceOf[UInt]) }.toSeq, I2CCtrlRegs.data -> Seq(RegField(8, r = RegReadFn(receivedData), w = RegWriteFn(transmitData))), - I2CCtrlRegs.cmd_status -> Seq(RegField(8, r = RegReadFn(status.asUInt), w = RegWriteFn(nextCmd))) + I2CCtrlRegs.cmd_status -> Seq(RegField(8, r = RegReadFn{ ready => + (statusReadReady, status.asUInt) + }, + w = RegWriteFn((valid, data) => { + when (valid) { + statusReadReady := false.B + nextCmd := data + } + true.B + } + ))) ) // tie off unused bits @@ -535,6 +554,6 @@ trait HasI2CModuleContents extends Module with HasRegMap { // Magic TL2 Incantation to create a TL2 Slave class TLI2C(w: Int, c: I2CParams)(implicit p: Parameters) - extends TLRegisterRouter(c.address, interrupts = 1, beatBytes = w)( + extends TLRegisterRouter(c.address, "i2c", Seq("sifive,i2c0"), interrupts = 1, beatBytes = w)( new TLRegBundle(c, _) with HasI2CBundleContents)( new TLRegModule(c, _, _) with HasI2CModuleContents)