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
47 import uncore.tilelink2._
48 import util.{AsyncResetRegVec, Majority}
49 import sifive.blocks.devices.gpio.{GPIOPinCtrl}
51 case class I2CParams(address: BigInt)
53 class I2CPin extends Bundle {
55 val out = Bool(OUTPUT)
59 class I2CPort extends Bundle {
64 trait HasI2CBundleContents extends Bundle {
65 val port = new I2CPort
68 trait HasI2CModuleContents extends Module with HasRegMap {
69 val io: HasI2CBundleContents
72 val I2C_CMD_NOP = UInt(0x00)
73 val I2C_CMD_START = UInt(0x01)
74 val I2C_CMD_STOP = UInt(0x02)
75 val I2C_CMD_WRITE = UInt(0x04)
76 val I2C_CMD_READ = UInt(0x08)
78 class PrescalerBundle extends Bundle{
83 class ControlBundle extends Bundle{
86 val reserved = UInt(6.W)
89 class CommandBundle extends Bundle{
95 val reserved = UInt(2.W)
99 class StatusBundle extends Bundle{
100 val receivedAck = Bool() // received aknowledge from slave
103 val reserved = UInt(3.W)
104 val transferInProgress = Bool()
108 // control state visible to SW/driver
109 val prescaler = Reg(init = (new PrescalerBundle).fromBits(0xFFFF.U))
110 val control = Reg(init = (new ControlBundle).fromBits(0.U))
111 val transmitData = Reg(init = UInt(0, 8.W))
112 val receivedData = Reg(init = UInt(0, 8.W))
113 val cmd = Reg(init = (new CommandBundle).fromBits(0.U))
114 val status = Reg(init = (new StatusBundle).fromBits(0.U))
117 //////// Bit level ////////
119 io.port.scl.out := false.B // i2c clock line output
120 io.port.sda.out := false.B // i2c data line output
122 // filter SCL and SDA signals; (attempt to) remove glitches
123 val filterCnt = Reg(init = UInt(0, 14.W))
124 when ( !control.coreEn ) {
126 } .elsewhen (!(filterCnt.orR)) {
127 filterCnt := Cat(prescaler.hi, prescaler.lo) >> 2 //16x I2C bus frequency
129 filterCnt := filterCnt - 1.U
132 val fSCL = Reg(init = UInt(0x7, 3.W))
133 val fSDA = Reg(init = UInt(0x7, 3.W))
134 when (!(filterCnt.orR)) {
135 fSCL := Cat(fSCL, io.port.scl.in)
136 fSDA := Cat(fSDA, io.port.sda.in)
139 val sSCL = Reg(init = true.B, next = Majority(fSCL))
140 val sSDA = Reg(init = true.B, next = Majority(fSDA))
142 val dSCL = Reg(init = true.B, next = sSCL)
143 val dSDA = Reg(init = true.B, next = sSDA)
145 val dSCLOen = Reg(next = io.port.scl.oe) // delayed scl_oen
147 // detect start condition => detect falling edge on SDA while SCL is high
148 // detect stop condition => detect rising edge on SDA while SCL is high
149 val startCond = Reg(init = false.B, next = !sSDA && dSDA && sSCL)
150 val stopCond = Reg(init = false.B, next = sSDA && !dSDA && sSCL)
152 // master drives SCL high, but another master pulls it low
153 // master start counting down its low cycle now (clock synchronization)
154 val sclSync = dSCL && !sSCL && io.port.scl.oe
156 // slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low
157 // slave_wait remains asserted until the slave releases SCL
158 val slaveWait = Reg(init = false.B)
159 slaveWait := (io.port.scl.oe && !dSCLOen && !sSCL) || (slaveWait && !sSCL)
161 val clkEn = Reg(init = true.B) // clock generation signals
162 val cnt = Reg(init = UInt(0, 16.W)) // clock divider counter (synthesis)
164 // generate clk enable signal
165 when (!(cnt.orR) || !control.coreEn || sclSync ) {
166 cnt := Cat(prescaler.hi, prescaler.lo)
169 .elsewhen (slaveWait) {
177 val sclOen = Reg(init = true.B)
178 io.port.scl.oe := !sclOen
180 val sdaOen = Reg(init = true.B)
181 io.port.sda.oe := !sdaOen
183 val sdaChk = Reg(init = false.B) // check SDA output (Multi-master arbitration)
185 val transmitBit = Reg(init = false.B)
186 val receivedBit = Reg(Bool())
187 when (sSCL && !dSCL) {
191 val bitCmd = Reg(init = UInt(0, 4.W)) // command (from byte controller)
192 val bitCmdStop = Reg(init = false.B)
194 bitCmdStop := bitCmd === I2C_CMD_STOP
196 val bitCmdAck = Reg(init = false.B)
199 s_bit_start_a :: s_bit_start_b :: s_bit_start_c :: s_bit_start_d :: s_bit_start_e ::
200 s_bit_stop_a :: s_bit_stop_b :: s_bit_stop_c :: s_bit_stop_d ::
201 s_bit_rd_a :: s_bit_rd_b :: s_bit_rd_c :: s_bit_rd_d ::
202 s_bit_wr_a :: s_bit_wr_b :: s_bit_wr_c :: s_bit_wr_d :: Nil) = Enum(UInt(), 18)
203 val bitState = Reg(init = s_bit_idle)
205 val arbLost = Reg(init = false.B, next = (sdaChk && !sSDA && sdaOen) | ((bitState === s_bit_idle) && stopCond && !bitCmdStop))
209 bitState := s_bit_idle
222 is (I2C_CMD_START) { bitState := s_bit_start_a }
223 is (I2C_CMD_STOP) { bitState := s_bit_stop_a }
224 is (I2C_CMD_WRITE) { bitState := s_bit_wr_a }
225 is (I2C_CMD_READ) { bitState := s_bit_rd_a }
231 bitState := s_bit_start_b
237 bitState := s_bit_start_c
243 bitState := s_bit_start_d
249 bitState := s_bit_start_e
255 bitState := s_bit_idle
263 bitState := s_bit_stop_b
269 bitState := s_bit_stop_c
275 bitState := s_bit_stop_d
281 bitState := s_bit_idle
289 bitState := s_bit_rd_b
295 bitState := s_bit_rd_c
301 bitState := s_bit_rd_d
307 bitState := s_bit_idle
315 bitState := s_bit_wr_b
317 sdaOen := transmitBit
321 bitState := s_bit_wr_c
323 sdaOen := transmitBit
327 bitState := s_bit_wr_d
329 sdaOen := transmitBit
333 bitState := s_bit_idle
336 sdaOen := transmitBit
344 //////// Byte level ///////
345 val load = Reg(init = false.B) // load shift register
346 val shift = Reg(init = false.B) // shift shift register
347 val cmdAck = Reg(init = false.B) // also done
348 val receivedAck = Reg(init = false.B) // from I2C slave
349 val go = (cmd.read | cmd.write | cmd.stop) & !cmdAck
351 val bitCnt = Reg(init = UInt(0, 3.W))
356 bitCnt := bitCnt - 1.U
358 val bitCntDone = !(bitCnt.orR)
360 // receivedData is used as shift register directly
362 receivedData := transmitData
365 receivedData := Cat(receivedData, receivedBit)
368 val (s_byte_idle :: s_byte_start :: s_byte_read :: s_byte_write :: s_byte_ack :: s_byte_stop :: Nil) = Enum(UInt(), 6)
369 val byteState = Reg(init = s_byte_idle)
372 bitCmd := I2C_CMD_NOP
373 transmitBit := false.B
377 byteState := s_byte_idle
378 receivedAck := false.B
381 transmitBit := receivedData(7)
390 byteState := s_byte_start
391 bitCmd := I2C_CMD_START
393 .elsewhen (cmd.read) {
394 byteState := s_byte_read
395 bitCmd := I2C_CMD_READ
397 .elsewhen (cmd.write) {
398 byteState := s_byte_write
399 bitCmd := I2C_CMD_WRITE
402 byteState := s_byte_stop
403 bitCmd := I2C_CMD_STOP
412 byteState := s_byte_read
413 bitCmd := I2C_CMD_READ
416 byteState := s_byte_write
417 bitCmd := I2C_CMD_WRITE
426 byteState := s_byte_ack
427 bitCmd := I2C_CMD_READ
430 byteState := s_byte_write
431 bitCmd := I2C_CMD_WRITE
439 byteState := s_byte_ack
440 bitCmd := I2C_CMD_WRITE
443 byteState := s_byte_read
444 bitCmd := I2C_CMD_READ
448 transmitBit := cmd.ack
454 byteState := s_byte_stop
455 bitCmd := I2C_CMD_STOP
458 byteState := s_byte_idle
459 bitCmd := I2C_CMD_NOP
461 // generate command acknowledge signal
465 // assign ack_out output to bit_controller_rxd (contains last received bit)
466 receivedAck := receivedBit
468 transmitBit := true.B
471 transmitBit := cmd.ack
476 byteState := s_byte_idle
477 bitCmd := I2C_CMD_NOP
479 // assign ack_out output to bit_controller_rxd (contains last received bit)
487 //////// Top level ////////
489 // hack: b/c the same register offset is used to write cmd and read status
490 val nextCmd = Wire(UInt(8.W))
491 nextCmd := cmd.asUInt
492 cmd := (new CommandBundle).fromBits(nextCmd)
494 when (cmdAck || arbLost) {
495 cmd.start := false.B // clear command bits when done
496 cmd.stop := false.B // or when aribitration lost
500 cmd.irqAck := false.B // clear IRQ_ACK bit (essentially 1 cycle pulse b/c it is overwritten by regmap below)
502 status.receivedAck := receivedAck
504 status.busy := false.B
506 .elsewhen (startCond) {
507 status.busy := true.B
511 status.arbLost := true.B
513 .elsewhen (cmd.start) {
514 status.arbLost := false.B
516 status.transferInProgress := cmd.read || cmd.write
517 status.irqFlag := (cmdAck || arbLost || status.irqFlag) && !cmd.irqAck
521 I2CCtrlRegs.prescaler_lo -> Seq(RegField(8, prescaler.lo)),
522 I2CCtrlRegs.prescaler_hi -> Seq(RegField(8, prescaler.hi)),
523 I2CCtrlRegs.control -> control.elements.map{ case(name, e) => RegField(e.getWidth, e.asInstanceOf[UInt]) }.toSeq,
524 I2CCtrlRegs.data -> Seq(RegField(8, r = RegReadFn(receivedData), w = RegWriteFn(transmitData))),
525 I2CCtrlRegs.cmd_status -> Seq(RegField(8, r = RegReadFn(status.asUInt), w = RegWriteFn(nextCmd)))
528 // tie off unused bits
529 control.reserved := 0.U
531 status.reserved := 0.U
533 interrupts(0) := status.irqFlag & control.intEn
536 // Magic TL2 Incantation to create a TL2 Slave
537 class TLI2C(w: Int, c: I2CParams)(implicit p: Parameters)
538 extends TLRegisterRouter(c.address, "i2c", Seq("sifive,i2c0"), interrupts = 1, beatBytes = w)(
539 new TLRegBundle(c, _) with HasI2CBundleContents)(
540 new TLRegModule(c, _, _) with HasI2CModuleContents)