1 /////////////////////////////////////////////////////////////////////
3 //// WISHBONE revB.2 compliant I2C Master controller Top-level ////
6 //// Author: Richard Herveille ////
7 //// richard@asics.ws ////
10 //// Downloaded from: http://www.opencores.org/projects/i2c/ ////
12 /////////////////////////////////////////////////////////////////////
14 //// Copyright (C) 2001 Richard Herveille ////
15 //// richard@asics.ws ////
17 //// This source file may be used and distributed without ////
18 //// restriction provided that this copyright statement is not ////
19 //// removed from the file and that any derivative work contains ////
20 //// the original copyright notice and the associated disclaimer.////
22 //// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
23 //// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
24 //// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
25 //// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
26 //// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
27 //// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
28 //// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
29 //// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
30 //// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
31 //// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
32 //// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
33 //// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
34 //// POSSIBILITY OF SUCH DAMAGE. ////
36 /////////////////////////////////////////////////////////////////////
38 // This code was re-written in Chisel by SiFive, Inc.
39 // See LICENSE for license details.
40 // WISHBONE interface replaced by Tilelink2
42 package sifive.blocks.devices.i2c
45 import freechips.rocketchip.config._
46 import freechips.rocketchip.regmapper._
47 import freechips.rocketchip.tilelink._
48 import freechips.rocketchip.util.{AsyncResetRegVec, Majority}
50 case class I2CParams(address: BigInt)
52 class I2CPin extends Bundle {
54 val out = Bool(OUTPUT)
58 class I2CPort extends Bundle {
63 trait HasI2CBundleContents extends Bundle {
64 val port = new I2CPort
67 trait HasI2CModuleContents extends Module with HasRegMap {
68 val io: HasI2CBundleContents
71 val I2C_CMD_NOP = UInt(0x00)
72 val I2C_CMD_START = UInt(0x01)
73 val I2C_CMD_STOP = UInt(0x02)
74 val I2C_CMD_WRITE = UInt(0x04)
75 val I2C_CMD_READ = UInt(0x08)
77 class PrescalerBundle extends Bundle{
82 class ControlBundle extends Bundle{
85 val reserved = UInt(6.W)
88 class CommandBundle extends Bundle{
94 val reserved = UInt(2.W)
98 class StatusBundle extends Bundle{
99 val receivedAck = Bool() // received aknowledge from slave
102 val reserved = UInt(3.W)
103 val transferInProgress = Bool()
107 // control state visible to SW/driver
108 val prescaler = Reg(init = (new PrescalerBundle).fromBits(0xFFFF.U))
109 val control = Reg(init = (new ControlBundle).fromBits(0.U))
110 val transmitData = Reg(init = UInt(0, 8.W))
111 val receivedData = Reg(init = UInt(0, 8.W))
112 val cmd = Reg(init = (new CommandBundle).fromBits(0.U))
113 val status = Reg(init = (new StatusBundle).fromBits(0.U))
116 //////// Bit level ////////
118 io.port.scl.out := false.B // i2c clock line output
119 io.port.sda.out := false.B // i2c data line output
121 // filter SCL and SDA signals; (attempt to) remove glitches
122 val filterCnt = Reg(init = UInt(0, 14.W))
123 when ( !control.coreEn ) {
125 } .elsewhen (!(filterCnt.orR)) {
126 filterCnt := Cat(prescaler.hi, prescaler.lo) >> 2 //16x I2C bus frequency
128 filterCnt := filterCnt - 1.U
131 val fSCL = Reg(init = UInt(0x7, 3.W))
132 val fSDA = Reg(init = UInt(0x7, 3.W))
133 when (!(filterCnt.orR)) {
134 fSCL := Cat(fSCL, io.port.scl.in)
135 fSDA := Cat(fSDA, io.port.sda.in)
138 val sSCL = Reg(init = true.B, next = Majority(fSCL))
139 val sSDA = Reg(init = true.B, next = Majority(fSDA))
141 val dSCL = Reg(init = true.B, next = sSCL)
142 val dSDA = Reg(init = true.B, next = sSDA)
144 val dSCLOen = Reg(next = io.port.scl.oe) // delayed scl_oen
146 // detect start condition => detect falling edge on SDA while SCL is high
147 // detect stop condition => detect rising edge on SDA while SCL is high
148 val startCond = Reg(init = false.B, next = !sSDA && dSDA && sSCL)
149 val stopCond = Reg(init = false.B, next = sSDA && !dSDA && sSCL)
151 // master drives SCL high, but another master pulls it low
152 // master start counting down its low cycle now (clock synchronization)
153 val sclSync = dSCL && !sSCL && io.port.scl.oe
155 // slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low
156 // slave_wait remains asserted until the slave releases SCL
157 val slaveWait = Reg(init = false.B)
158 slaveWait := (io.port.scl.oe && !dSCLOen && !sSCL) || (slaveWait && !sSCL)
160 val clkEn = Reg(init = true.B) // clock generation signals
161 val cnt = Reg(init = UInt(0, 16.W)) // clock divider counter (synthesis)
163 // generate clk enable signal
164 when (!(cnt.orR) || !control.coreEn || sclSync ) {
165 cnt := Cat(prescaler.hi, prescaler.lo)
168 .elsewhen (slaveWait) {
176 val sclOen = Reg(init = true.B)
177 io.port.scl.oe := !sclOen
179 val sdaOen = Reg(init = true.B)
180 io.port.sda.oe := !sdaOen
182 val sdaChk = Reg(init = false.B) // check SDA output (Multi-master arbitration)
184 val transmitBit = Reg(init = false.B)
185 val receivedBit = Reg(Bool())
186 when (sSCL && !dSCL) {
190 val bitCmd = Reg(init = UInt(0, 4.W)) // command (from byte controller)
191 val bitCmdStop = Reg(init = false.B)
193 bitCmdStop := bitCmd === I2C_CMD_STOP
195 val bitCmdAck = Reg(init = false.B)
198 s_bit_start_a :: s_bit_start_b :: s_bit_start_c :: s_bit_start_d :: s_bit_start_e ::
199 s_bit_stop_a :: s_bit_stop_b :: s_bit_stop_c :: s_bit_stop_d ::
200 s_bit_rd_a :: s_bit_rd_b :: s_bit_rd_c :: s_bit_rd_d ::
201 s_bit_wr_a :: s_bit_wr_b :: s_bit_wr_c :: s_bit_wr_d :: Nil) = Enum(UInt(), 18)
202 val bitState = Reg(init = s_bit_idle)
204 val arbLost = Reg(init = false.B, next = (sdaChk && !sSDA && sdaOen) | ((bitState === s_bit_idle) && stopCond && !bitCmdStop))
208 bitState := s_bit_idle
221 is (I2C_CMD_START) { bitState := s_bit_start_a }
222 is (I2C_CMD_STOP) { bitState := s_bit_stop_a }
223 is (I2C_CMD_WRITE) { bitState := s_bit_wr_a }
224 is (I2C_CMD_READ) { bitState := s_bit_rd_a }
230 bitState := s_bit_start_b
236 bitState := s_bit_start_c
242 bitState := s_bit_start_d
248 bitState := s_bit_start_e
254 bitState := s_bit_idle
262 bitState := s_bit_stop_b
268 bitState := s_bit_stop_c
274 bitState := s_bit_stop_d
280 bitState := s_bit_idle
288 bitState := s_bit_rd_b
294 bitState := s_bit_rd_c
300 bitState := s_bit_rd_d
306 bitState := s_bit_idle
314 bitState := s_bit_wr_b
316 sdaOen := transmitBit
320 bitState := s_bit_wr_c
322 sdaOen := transmitBit
326 bitState := s_bit_wr_d
328 sdaOen := transmitBit
332 bitState := s_bit_idle
335 sdaOen := transmitBit
343 //////// Byte level ///////
344 val load = Reg(init = false.B) // load shift register
345 val shift = Reg(init = false.B) // shift shift register
346 val cmdAck = Reg(init = false.B) // also done
347 val receivedAck = Reg(init = false.B) // from I2C slave
348 val go = (cmd.read | cmd.write | cmd.stop) & !cmdAck
350 val bitCnt = Reg(init = UInt(0, 3.W))
355 bitCnt := bitCnt - 1.U
357 val bitCntDone = !(bitCnt.orR)
359 // receivedData is used as shift register directly
361 receivedData := transmitData
364 receivedData := Cat(receivedData, receivedBit)
367 val (s_byte_idle :: s_byte_start :: s_byte_read :: s_byte_write :: s_byte_ack :: s_byte_stop :: Nil) = Enum(UInt(), 6)
368 val byteState = Reg(init = s_byte_idle)
371 bitCmd := I2C_CMD_NOP
372 transmitBit := false.B
376 byteState := s_byte_idle
377 receivedAck := false.B
380 transmitBit := receivedData(7)
389 byteState := s_byte_start
390 bitCmd := I2C_CMD_START
392 .elsewhen (cmd.read) {
393 byteState := s_byte_read
394 bitCmd := I2C_CMD_READ
396 .elsewhen (cmd.write) {
397 byteState := s_byte_write
398 bitCmd := I2C_CMD_WRITE
401 byteState := s_byte_stop
402 bitCmd := I2C_CMD_STOP
411 byteState := s_byte_read
412 bitCmd := I2C_CMD_READ
415 byteState := s_byte_write
416 bitCmd := I2C_CMD_WRITE
425 byteState := s_byte_ack
426 bitCmd := I2C_CMD_READ
429 byteState := s_byte_write
430 bitCmd := I2C_CMD_WRITE
438 byteState := s_byte_ack
439 bitCmd := I2C_CMD_WRITE
442 byteState := s_byte_read
443 bitCmd := I2C_CMD_READ
447 transmitBit := cmd.ack
453 byteState := s_byte_stop
454 bitCmd := I2C_CMD_STOP
457 byteState := s_byte_idle
458 bitCmd := I2C_CMD_NOP
460 // generate command acknowledge signal
464 // assign ack_out output to bit_controller_rxd (contains last received bit)
465 receivedAck := receivedBit
467 transmitBit := true.B
470 transmitBit := cmd.ack
475 byteState := s_byte_idle
476 bitCmd := I2C_CMD_NOP
478 // assign ack_out output to bit_controller_rxd (contains last received bit)
486 //////// Top level ////////
488 // hack: b/c the same register offset is used to write cmd and read status
489 val nextCmd = Wire(UInt(8.W))
490 nextCmd := cmd.asUInt
491 cmd := (new CommandBundle).fromBits(nextCmd)
493 when (cmdAck || arbLost) {
494 cmd.start := false.B // clear command bits when done
495 cmd.stop := false.B // or when aribitration lost
499 cmd.irqAck := false.B // clear IRQ_ACK bit (essentially 1 cycle pulse b/c it is overwritten by regmap below)
501 status.receivedAck := receivedAck
503 status.busy := false.B
505 .elsewhen (startCond) {
506 status.busy := true.B
510 status.arbLost := true.B
512 .elsewhen (cmd.start) {
513 status.arbLost := false.B
515 status.transferInProgress := cmd.read || cmd.write
516 status.irqFlag := (cmdAck || arbLost || status.irqFlag) && !cmd.irqAck
519 val statusReadReady = Reg(init = true.B)
520 when (!statusReadReady) {
521 statusReadReady := true.B
526 I2CCtrlRegs.prescaler_lo -> Seq(RegField(8, prescaler.lo)),
527 I2CCtrlRegs.prescaler_hi -> Seq(RegField(8, prescaler.hi)),
528 I2CCtrlRegs.control -> control.elements.map{ case(name, e) => RegField(e.getWidth, e.asInstanceOf[UInt]) }.toSeq,
529 I2CCtrlRegs.data -> Seq(RegField(8, r = RegReadFn(receivedData), w = RegWriteFn(transmitData))),
530 I2CCtrlRegs.cmd_status -> Seq(RegField(8, r = RegReadFn{ ready =>
531 (statusReadReady, status.asUInt)
533 w = RegWriteFn((valid, data) => {
535 statusReadReady := false.B
543 // tie off unused bits
544 control.reserved := 0.U
546 status.reserved := 0.U
548 interrupts(0) := status.irqFlag & control.intEn
551 // Magic TL2 Incantation to create a TL2 Slave
552 class TLI2C(w: Int, c: I2CParams)(implicit p: Parameters)
553 extends TLRegisterRouter(c.address, "i2c", Seq("sifive,i2c0"), interrupts = 1, beatBytes = w)(
554 new TLRegBundle(c, _) with HasI2CBundleContents)(
555 new TLRegModule(c, _, _) with HasI2CModuleContents)