Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/nvidia Support transfers > 4-bytes long by read...



details:   https://anonhg.NetBSD.org/src/rev/fc48176705f3
branches:  trunk
changeset: 808409:fc48176705f3
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat May 16 21:31:39 2015 +0000

description:
Support transfers > 4-bytes long by reading and writing using the
controller's packet-based interface instead of non-packet ("normal") mode.

diffstat:

 sys/arch/arm/nvidia/tegra_i2c.c    |  185 +++++++++++++++++++++++-------------
 sys/arch/arm/nvidia/tegra_i2creg.h |   62 +++++++++++-
 2 files changed, 177 insertions(+), 70 deletions(-)

diffs (truncated from 362 to 300 lines):

diff -r d58d55ebdd4d -r fc48176705f3 sys/arch/arm/nvidia/tegra_i2c.c
--- a/sys/arch/arm/nvidia/tegra_i2c.c   Sat May 16 20:23:38 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_i2c.c   Sat May 16 21:31:39 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_i2c.c,v 1.1 2015/05/10 23:50:21 jmcneill Exp $ */
+/* $NetBSD: tegra_i2c.c,v 1.2 2015/05/16 21:31:39 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
 #include "locators.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_i2c.c,v 1.1 2015/05/10 23:50:21 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_i2c.c,v 1.2 2015/05/16 21:31:39 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -52,6 +52,7 @@
        bus_space_tag_t         sc_bst;
        bus_space_handle_t      sc_bsh;
        void *                  sc_ih;
+       u_int                   sc_port;
 
        struct i2c_controller   sc_ic;
        kmutex_t                sc_lock;
@@ -107,6 +108,7 @@
        sc->sc_bst = tio->tio_bst;
        bus_space_subregion(tio->tio_bst, tio->tio_bsh,
            loc->loc_offset, loc->loc_size, &sc->sc_bsh);
+       sc->sc_port = loc->loc_port;
        mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
        cv_init(&sc->sc_cv, device_xname(self));
 
@@ -144,7 +146,8 @@
            __SHIFTIN(0x1, I2C_CLK_DIVISOR_HSMODE));
 
        I2C_WRITE(sc, I2C_INTERRUPT_MASK_REG, 0);
-       I2C_WRITE(sc, I2C_CNFG_REG, I2C_CNFG_NEW_MASTER_FSM);
+       I2C_WRITE(sc, I2C_CNFG_REG,
+           I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN);
        I2C_SET_CLEAR(sc, I2C_SL_CNFG_REG, I2C_SL_CNFG_NEWSL, 0);
 }
 
@@ -242,43 +245,42 @@
 static int
 tegra_i2c_wait(struct tegra_i2c_softc *sc, int flags)
 {
-       const struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
-       struct timeval tnow, tend;
-       uint32_t stat;
-       int error;
+       int error, retry;
+       uint32_t stat = 0;
 
-       getmicrotime(&tnow);
-       timeradd(&tnow, &timeout, &tend);
+       retry = (flags & I2C_F_POLL) ? 100000 : 100;
 
-       for (;;) {
-               getmicrotime(&tnow);
-               if (timercmp(&tnow, &tend, >=)) {
-                       return ETIMEDOUT;
-               }
+       while (--retry > 0) {
                if ((flags & I2C_F_POLL) == 0) {
-                       struct timeval trem;
-                       timersub(&tend, &tnow, &trem);
-                       const u_int ms = (trem.tv_sec * 1000) +
-                           (trem.tv_usec / 1000);
-                       KASSERT(ms > 0);
                        error = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock,
-                           max(mstohz(ms), 1));
+                           max(mstohz(10), 1));
                        if (error) {
                                return error;
                        }
                }
-               stat = I2C_READ(sc, I2C_STATUS_REG);
-               if ((stat & I2C_STATUS_BUSY) == 0) {
+               stat = I2C_READ(sc, I2C_INTERRUPT_STATUS_REG);
+               if (stat & I2C_INTERRUPT_STATUS_PACKET_XFER_COMPLETE) {
                        break;
                }
                if (flags & I2C_F_POLL) {
-                       delay(1);
+                       delay(10);
                }
        }
+       if (retry == 0) {
+               stat = I2C_READ(sc, I2C_INTERRUPT_STATUS_REG);
+               device_printf(sc->sc_dev, "timed out, status = %#x\n", stat);
+               return ETIMEDOUT;
+       }
 
+       const uint32_t err_mask =
+           I2C_INTERRUPT_STATUS_NOACK |
+           I2C_INTERRUPT_STATUS_ARB_LOST |
+           I2C_INTERRUPT_MASK_TIMEOUT;
 
-       if (__SHIFTOUT(stat, I2C_STATUS_CMD1_STAT) != 0)
+       if (stat & err_mask) {
+               device_printf(sc->sc_dev, "error, status = %#x\n", stat);
                return EIO;
+       }
 
        return 0;
 }
@@ -287,33 +289,55 @@
 tegra_i2c_write(struct tegra_i2c_softc *sc, i2c_addr_t addr, const uint8_t *buf,
     size_t buflen, int flags)
 {
-       uint32_t data, cnfg;
-       size_t n;
-
-       if (buflen > 4)
-               return EINVAL;
+       const uint8_t *p = buf;
+       size_t n, resid = buflen;
+       uint32_t data;
+       int retry;
 
-       I2C_WRITE(sc, I2C_CMD_ADDR0_REG, addr << 1);
-       for (n = 0, data = 0; n < buflen; n++) {
-               data |= (uint32_t)buf[n] << (n * 8);
-       }
-       I2C_WRITE(sc, I2C_CMD_DATA1_REG, data);
+       const uint32_t istatus = I2C_READ(sc, I2C_INTERRUPT_STATUS_REG);
+       I2C_WRITE(sc, I2C_INTERRUPT_STATUS_REG, istatus);
 
-       cnfg = I2C_READ(sc, I2C_CNFG_REG);
-       cnfg &= ~I2C_CNFG_DEBOUNCE_CNT;
-       cnfg |= __SHIFTIN(2, I2C_CNFG_DEBOUNCE_CNT);
-       cnfg &= ~I2C_CNFG_LENGTH;
-       cnfg |= __SHIFTIN(buflen - 1, I2C_CNFG_LENGTH);
-       cnfg &= ~I2C_CNFG_SLV2;
-       cnfg &= ~I2C_CNFG_CMD1;
-       cnfg &= ~I2C_CNFG_NOACK;
-       cnfg &= ~I2C_CNFG_A_MOD;
-       I2C_WRITE(sc, I2C_CNFG_REG, cnfg);
+       /* Generic Header 0 */
+       I2C_WRITE(sc, I2C_TX_PACKET_FIFO_REG,
+           __SHIFTIN(I2C_IOPACKET_WORD0_PROTHDRSZ_REQ,
+                     I2C_IOPACKET_WORD0_PROTHDRSZ) |
+           __SHIFTIN(sc->sc_port, I2C_IOPACKET_WORD0_CONTROLLERID) |
+           __SHIFTIN(1, I2C_IOPACKET_WORD0_PKTID) |
+           __SHIFTIN(I2C_IOPACKET_WORD0_PROTOCOL_I2C,
+                     I2C_IOPACKET_WORD0_PROTOCOL) |
+           __SHIFTIN(I2C_IOPACKET_WORD0_PKTTYPE_REQ,
+                     I2C_IOPACKET_WORD0_PKTTYPE));
+       /* Generic Header 1 */
+       I2C_WRITE(sc, I2C_TX_PACKET_FIFO_REG,
+           __SHIFTIN(buflen - 1, I2C_IOPACKET_WORD1_PAYLOADSIZE));
+       /* I2C Master Transmit Packet Header */
+       I2C_WRITE(sc, I2C_TX_PACKET_FIFO_REG,
+           I2C_IOPACKET_XMITHDR_IE |
+           __SHIFTIN((addr << 1), I2C_IOPACKET_XMITHDR_SLAVE_ADDR));
 
-       I2C_SET_CLEAR(sc, I2C_BUS_CONFIG_LOAD_REG,
-           I2C_BUS_CONFIG_LOAD_MSTR_CONFIG_LOAD, 0);
+       /* Transmit data */
+       while (resid > 0) {
+               retry = 10000;
+               while (--retry > 0) {
+                       const uint32_t fs = I2C_READ(sc, I2C_FIFO_STATUS_REG);
+                       const u_int cnt =
+                           __SHIFTOUT(fs, I2C_FIFO_STATUS_TX_FIFO_EMPTY_CNT);
+                       if (cnt > 0)
+                               break;
+                       delay(10);
+               }
+               if (retry == 0) {
+                       device_printf(sc->sc_dev, "TX FIFO timeout\n");
+                       return ETIMEDOUT;
+               }
 
-       I2C_SET_CLEAR(sc, I2C_CNFG_REG, I2C_CNFG_SEND, 0);
+               for (n = 0, data = 0; n < min(resid, 4); n++) {
+                       data |= (uint32_t)p[n] << (n * 8);
+               }
+               I2C_WRITE(sc, I2C_TX_PACKET_FIFO_REG, data);
+               resid -= min(resid, 4);
+               p += min(resid, 4);
+       }
 
        return tegra_i2c_wait(sc, flags);
 }
@@ -322,30 +346,57 @@
 tegra_i2c_read(struct tegra_i2c_softc *sc, i2c_addr_t addr, uint8_t *buf,
     size_t buflen, int flags)
 {
-       uint32_t data, cnfg;
-       int error;
-       size_t n;
+       uint8_t *p = buf;
+       size_t n, resid = buflen;
+       uint32_t data;
+       int error, retry;
+
+       const uint32_t istatus = I2C_READ(sc, I2C_INTERRUPT_STATUS_REG);
+       I2C_WRITE(sc, I2C_INTERRUPT_STATUS_REG, istatus);
 
-       if (buflen > 4)
-               return EINVAL;
+       /* Generic Header 0 */
+       I2C_WRITE(sc, I2C_TX_PACKET_FIFO_REG,
+           __SHIFTIN(I2C_IOPACKET_WORD0_PROTHDRSZ_REQ,
+                     I2C_IOPACKET_WORD0_PROTHDRSZ) |
+           __SHIFTIN(sc->sc_port, I2C_IOPACKET_WORD0_CONTROLLERID) |
+           __SHIFTIN(1, I2C_IOPACKET_WORD0_PKTID) |
+           __SHIFTIN(I2C_IOPACKET_WORD0_PROTOCOL_I2C,
+                     I2C_IOPACKET_WORD0_PROTOCOL) |
+           __SHIFTIN(I2C_IOPACKET_WORD0_PKTTYPE_REQ,
+                     I2C_IOPACKET_WORD0_PKTTYPE));
+       /* Generic Header 1 */
+       I2C_WRITE(sc, I2C_TX_PACKET_FIFO_REG,
+           __SHIFTIN(buflen - 1, I2C_IOPACKET_WORD1_PAYLOADSIZE));
+       /* I2C Master Transmit Packet Header */
+       I2C_WRITE(sc, I2C_TX_PACKET_FIFO_REG,
+           I2C_IOPACKET_XMITHDR_IE | I2C_IOPACKET_XMITHDR_READ |
+           __SHIFTIN((addr << 1) | 1, I2C_IOPACKET_XMITHDR_SLAVE_ADDR));
 
-       I2C_WRITE(sc, I2C_CMD_ADDR0_REG, (addr << 1) | 1);
-       cnfg = I2C_READ(sc, I2C_CNFG_REG);
-       cnfg &= ~I2C_CNFG_SLV2;
-       cnfg |= I2C_CNFG_CMD1;
-       cnfg &= ~I2C_CNFG_LENGTH;
-       cnfg |= __SHIFTIN(buflen - 1, I2C_CNFG_LENGTH);
-       I2C_WRITE(sc, I2C_CNFG_REG, cnfg);
+       if ((error = tegra_i2c_wait(sc, flags)) != 0) {
+               return error;
+       }
 
-       I2C_SET_CLEAR(sc, I2C_CNFG_REG, I2C_CNFG_SEND, 0);
+       while (resid > 0) {
+               retry = 10000;
+               while (--retry > 0) {
+                       const uint32_t fs = I2C_READ(sc, I2C_FIFO_STATUS_REG);
+                       const u_int cnt =
+                           __SHIFTOUT(fs, I2C_FIFO_STATUS_RX_FIFO_FULL_CNT);
+                       if (cnt > 0)
+                               break;
+                       delay(10);
+               }
+               if (retry == 0) {
+                       device_printf(sc->sc_dev, "RX FIFO timeout\n");
+                       return ETIMEDOUT;
+               }
 
-       error = tegra_i2c_wait(sc, flags);
-       if (error)
-               return error;
-
-       data = I2C_READ(sc, I2C_CMD_DATA1_REG);
-       for (n = 0; n < buflen; n++) {
-               buf[n] = (data >> (n * 8)) & 0xff;
+               data = I2C_READ(sc, I2C_RX_FIFO_REG);
+               for (n = 0; n < min(resid, 4); n++) {
+                       p[n] = (data >> (n * 8)) & 0xff;
+               }
+               resid -= min(resid, 4);
+               p += min(resid, 4);
        }
 
        return 0;
diff -r d58d55ebdd4d -r fc48176705f3 sys/arch/arm/nvidia/tegra_i2creg.h
--- a/sys/arch/arm/nvidia/tegra_i2creg.h        Sat May 16 20:23:38 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_i2creg.h        Sat May 16 21:31:39 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_i2creg.h,v 1.1 2015/05/10 23:50:21 jmcneill Exp $ */
+/* $NetBSD: tegra_i2creg.h,v 1.2 2015/05/16 21:31:39 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -76,7 +76,15 @@
 #define I2C_SL_INT_SET_REG             0x48
 #define I2C_TX_PACKET_FIFO_REG         0x50
 #define I2C_RX_FIFO_REG                        0x54
+
 #define I2C_PACKET_TRANSFER_STATUS_REG 0x58
+#define I2C_PACKET_TRANSFER_STATUS_TRANSFER_COMPLETE __BIT(24)
+#define I2C_PACKET_TRANSFER_STATUS_TRANSFER_PKT_ID __BITS(23,16)
+#define I2C_PACKET_TRANSFER_STATUS_TRANSFER_BYTENUM __BITS(15,4)
+#define I2C_PACKET_TRANSFER_STATUS_NOACK_FOR_ADDR __BIT(3)
+#define I2C_PACKET_TRANSFER_STATUS_NOACK_FOR_DATA __BIT(2)
+#define I2C_PACKET_TRANSFER_STATUS_ARB_LOST    __BIT(1)
+#define I2C_PACKET_TRANSFER_STATUS_CONTROLLER_BUSY __BIT(0)
 
 #define I2C_FIFO_CONTROL_REG           0x5c
 #define I2C_FIFO_CONTROL_SLV_TX_FIFO_TRIG      __BITS(15,13)
@@ -91,9 +99,9 @@
 #define I2C_FIFO_STATUS_REG            0x60
 #define I2C_FIFO_STATUS_SLV_XFER_ERR_REASON    __BIT(25)
 #define I2C_FIFO_STATUS_SLV_TX_FIFO_EMPTY_CNT  __BITS(23,20)
-#define I2C_FIFO_STATUS_SLV_RX_FIFO_EMPTY_CNT  __BITS(19,16)
+#define I2C_FIFO_STATUS_SLV_RX_FIFO_FULL_CNT   __BITS(19,16)
 #define I2C_FIFO_STATUS_TX_FIFO_EMPTY_CNT      __BITS(7,4)
-#define I2C_FIFO_STATUS_RX_FIFO_EMPTY_CNT      __BITS(3,0)
+#define I2C_FIFO_STATUS_RX_FIFO_FULL_CNT       __BITS(3,0)
 



Home | Main Index | Thread Index | Old Index