dpdk/drivers/net/axgbe/axgbe_i2c.c
<<
>>
Prefs
   1/*   SPDX-License-Identifier: BSD-3-Clause
   2 *   Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
   3 *   Copyright(c) 2018 Synopsys, Inc. All rights reserved.
   4 */
   5
   6#include "axgbe_ethdev.h"
   7#include "axgbe_common.h"
   8
   9#define AXGBE_ABORT_COUNT       500
  10#define AXGBE_DISABLE_COUNT     1000
  11
  12#define AXGBE_STD_SPEED         1
  13
  14#define AXGBE_INTR_RX_FULL      BIT(IC_RAW_INTR_STAT_RX_FULL_INDEX)
  15#define AXGBE_INTR_TX_EMPTY     BIT(IC_RAW_INTR_STAT_TX_EMPTY_INDEX)
  16#define AXGBE_INTR_TX_ABRT      BIT(IC_RAW_INTR_STAT_TX_ABRT_INDEX)
  17#define AXGBE_INTR_STOP_DET     BIT(IC_RAW_INTR_STAT_STOP_DET_INDEX)
  18#define AXGBE_DEFAULT_INT_MASK  (AXGBE_INTR_RX_FULL  |  \
  19                                 AXGBE_INTR_TX_EMPTY |  \
  20                                 AXGBE_INTR_TX_ABRT  |  \
  21                                 AXGBE_INTR_STOP_DET)
  22
  23#define AXGBE_I2C_READ          BIT(8)
  24#define AXGBE_I2C_STOP          BIT(9)
  25
  26static int axgbe_i2c_abort(struct axgbe_port *pdata)
  27{
  28        unsigned int wait = AXGBE_ABORT_COUNT;
  29
  30        /* Must be enabled to recognize the abort request */
  31        XI2C_IOWRITE_BITS(pdata, IC_ENABLE, EN, 1);
  32
  33        /* Issue the abort */
  34        XI2C_IOWRITE_BITS(pdata, IC_ENABLE, ABORT, 1);
  35
  36        while (wait--) {
  37                if (!XI2C_IOREAD_BITS(pdata, IC_ENABLE, ABORT))
  38                        return 0;
  39                rte_delay_us(500);
  40        }
  41
  42        return -EBUSY;
  43}
  44
  45static int axgbe_i2c_set_enable(struct axgbe_port *pdata, bool enable)
  46{
  47        unsigned int wait = AXGBE_DISABLE_COUNT;
  48        unsigned int mode = enable ? 1 : 0;
  49
  50        while (wait--) {
  51                XI2C_IOWRITE_BITS(pdata, IC_ENABLE, EN, mode);
  52                if (XI2C_IOREAD_BITS(pdata, IC_ENABLE_STATUS, EN) == mode)
  53                        return 0;
  54
  55                rte_delay_us(100);
  56        }
  57
  58        return -EBUSY;
  59}
  60
  61static int axgbe_i2c_disable(struct axgbe_port *pdata)
  62{
  63        unsigned int ret;
  64
  65        ret = axgbe_i2c_set_enable(pdata, false);
  66        if (ret) {
  67                /* Disable failed, try an abort */
  68                ret = axgbe_i2c_abort(pdata);
  69                if (ret)
  70                        return ret;
  71
  72                /* Abort succeeded, try to disable again */
  73                ret = axgbe_i2c_set_enable(pdata, false);
  74        }
  75
  76        return ret;
  77}
  78
  79static int axgbe_i2c_enable(struct axgbe_port *pdata)
  80{
  81        return axgbe_i2c_set_enable(pdata, true);
  82}
  83
  84static void axgbe_i2c_clear_all_interrupts(struct axgbe_port *pdata)
  85{
  86        XI2C_IOREAD(pdata, IC_CLR_INTR);
  87}
  88
  89static void axgbe_i2c_disable_interrupts(struct axgbe_port *pdata)
  90{
  91        XI2C_IOWRITE(pdata, IC_INTR_MASK, 0);
  92}
  93
  94static void axgbe_i2c_enable_interrupts(struct axgbe_port *pdata)
  95{
  96        XI2C_IOWRITE(pdata, IC_INTR_MASK, AXGBE_DEFAULT_INT_MASK);
  97}
  98
  99static void axgbe_i2c_write(struct axgbe_port *pdata)
 100{
 101        struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
 102        unsigned int tx_slots;
 103        unsigned int cmd;
 104
 105        /* Configured to never receive Rx overflows, so fill up Tx fifo */
 106        tx_slots = pdata->i2c.tx_fifo_size - XI2C_IOREAD(pdata, IC_TXFLR);
 107        while (tx_slots && state->tx_len) {
 108                if (state->op->cmd == AXGBE_I2C_CMD_READ)
 109                        cmd = AXGBE_I2C_READ;
 110                else
 111                        cmd = *state->tx_buf++;
 112
 113                if (state->tx_len == 1)
 114                        XI2C_SET_BITS(cmd, IC_DATA_CMD, STOP, 1);
 115
 116                XI2C_IOWRITE(pdata, IC_DATA_CMD, cmd);
 117
 118                tx_slots--;
 119                state->tx_len--;
 120        }
 121
 122        /* No more Tx operations, so ignore TX_EMPTY and return */
 123        if (!state->tx_len)
 124                XI2C_IOWRITE_BITS(pdata, IC_INTR_MASK, TX_EMPTY, 0);
 125}
 126
 127static void axgbe_i2c_read(struct axgbe_port *pdata)
 128{
 129        struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
 130        unsigned int rx_slots;
 131
 132        /* Anything to be read? */
 133        if (state->op->cmd != AXGBE_I2C_CMD_READ)
 134                return;
 135
 136        rx_slots = XI2C_IOREAD(pdata, IC_RXFLR);
 137        while (rx_slots && state->rx_len) {
 138                *state->rx_buf++ = XI2C_IOREAD(pdata, IC_DATA_CMD);
 139                state->rx_len--;
 140                rx_slots--;
 141        }
 142}
 143
 144static void axgbe_i2c_clear_isr_interrupts(struct axgbe_port *pdata,
 145                                          unsigned int isr)
 146{
 147        struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
 148
 149        if (isr & AXGBE_INTR_TX_ABRT) {
 150                state->tx_abort_source = XI2C_IOREAD(pdata, IC_TX_ABRT_SOURCE);
 151                XI2C_IOREAD(pdata, IC_CLR_TX_ABRT);
 152        }
 153
 154        if (isr & AXGBE_INTR_STOP_DET)
 155                XI2C_IOREAD(pdata, IC_CLR_STOP_DET);
 156}
 157
 158static int axgbe_i2c_isr(struct axgbe_port *pdata)
 159{
 160        struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
 161        unsigned int isr;
 162
 163        isr = XI2C_IOREAD(pdata, IC_RAW_INTR_STAT);
 164
 165        PMD_DRV_LOG(DEBUG, "I2C interrupt received: status=%#010x\n", isr);
 166
 167        axgbe_i2c_clear_isr_interrupts(pdata, isr);
 168
 169        if (isr & AXGBE_INTR_TX_ABRT) {
 170                PMD_DRV_LOG(DEBUG,
 171                            "I2C TX_ABRT received (%#010x) for target %#04x\n",
 172                            state->tx_abort_source, state->op->target);
 173
 174                axgbe_i2c_disable_interrupts(pdata);
 175
 176                state->ret = -EIO;
 177                goto out;
 178        }
 179
 180        /* Check for data in the Rx fifo */
 181        axgbe_i2c_read(pdata);
 182
 183        /* Fill up the Tx fifo next */
 184        axgbe_i2c_write(pdata);
 185
 186out:
 187        /* Complete on an error or STOP condition */
 188        if (state->ret || XI2C_GET_BITS(isr, IC_RAW_INTR_STAT, STOP_DET))
 189                return 1;
 190
 191        return 0;
 192}
 193
 194static void axgbe_i2c_set_mode(struct axgbe_port *pdata)
 195{
 196        unsigned int reg;
 197
 198        reg = XI2C_IOREAD(pdata, IC_CON);
 199        XI2C_SET_BITS(reg, IC_CON, MASTER_MODE, 1);
 200        XI2C_SET_BITS(reg, IC_CON, SLAVE_DISABLE, 1);
 201        XI2C_SET_BITS(reg, IC_CON, RESTART_EN, 1);
 202        XI2C_SET_BITS(reg, IC_CON, SPEED, AXGBE_STD_SPEED);
 203        XI2C_SET_BITS(reg, IC_CON, RX_FIFO_FULL_HOLD, 1);
 204        XI2C_IOWRITE(pdata, IC_CON, reg);
 205}
 206
 207static void axgbe_i2c_get_features(struct axgbe_port *pdata)
 208{
 209        struct axgbe_i2c *i2c = &pdata->i2c;
 210        unsigned int reg;
 211
 212        reg = XI2C_IOREAD(pdata, IC_COMP_PARAM_1);
 213        i2c->max_speed_mode = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
 214                                            MAX_SPEED_MODE);
 215        i2c->rx_fifo_size = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
 216                                          RX_BUFFER_DEPTH);
 217        i2c->tx_fifo_size = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
 218                                          TX_BUFFER_DEPTH);
 219}
 220
 221static void axgbe_i2c_set_target(struct axgbe_port *pdata, unsigned int addr)
 222{
 223        XI2C_IOWRITE(pdata, IC_TAR, addr);
 224}
 225
 226static int axgbe_i2c_xfer(struct axgbe_port *pdata, struct axgbe_i2c_op *op)
 227{
 228        struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
 229        int ret;
 230        uint64_t timeout;
 231
 232        pthread_mutex_lock(&pdata->i2c_mutex);
 233        ret = axgbe_i2c_disable(pdata);
 234        if (ret) {
 235                PMD_DRV_LOG(ERR, "failed to disable i2c master\n");
 236                return ret;
 237        }
 238
 239        axgbe_i2c_set_target(pdata, op->target);
 240
 241        memset(state, 0, sizeof(*state));
 242        state->op = op;
 243        state->tx_len = op->len;
 244        state->tx_buf = (unsigned char *)op->buf;
 245        state->rx_len = op->len;
 246        state->rx_buf = (unsigned char *)op->buf;
 247
 248        axgbe_i2c_clear_all_interrupts(pdata);
 249        ret = axgbe_i2c_enable(pdata);
 250        if (ret) {
 251                PMD_DRV_LOG(ERR, "failed to enable i2c master\n");
 252                return ret;
 253        }
 254
 255        /* Enabling the interrupts will cause the TX FIFO empty interrupt to
 256         * fire and begin to process the command via the ISR.
 257         */
 258        axgbe_i2c_enable_interrupts(pdata);
 259        timeout = rte_get_timer_cycles() + rte_get_timer_hz();
 260
 261        while (time_before(rte_get_timer_cycles(), timeout)) {
 262                rte_delay_us(100);
 263                if (XI2C_IOREAD(pdata, IC_RAW_INTR_STAT)) {
 264                        if (axgbe_i2c_isr(pdata))
 265                                goto success;
 266                }
 267        }
 268
 269        PMD_DRV_LOG(ERR, "i2c operation timed out\n");
 270        axgbe_i2c_disable_interrupts(pdata);
 271        axgbe_i2c_disable(pdata);
 272        ret = -ETIMEDOUT;
 273        goto unlock;
 274
 275success:
 276        ret = state->ret;
 277        if (ret) {
 278                if (state->tx_abort_source & IC_TX_ABRT_7B_ADDR_NOACK)
 279                        ret = -ENOTCONN;
 280                else if (state->tx_abort_source & IC_TX_ABRT_ARB_LOST)
 281                        ret = -EAGAIN;
 282        }
 283
 284unlock:
 285        pthread_mutex_unlock(&pdata->i2c_mutex);
 286        return ret;
 287}
 288
 289static void axgbe_i2c_stop(struct axgbe_port *pdata)
 290{
 291        if (!pdata->i2c.started)
 292                return;
 293
 294        PMD_DRV_LOG(DEBUG, "stopping I2C\n");
 295
 296        pdata->i2c.started = 0;
 297        axgbe_i2c_disable_interrupts(pdata);
 298        axgbe_i2c_disable(pdata);
 299        axgbe_i2c_clear_all_interrupts(pdata);
 300}
 301
 302static int axgbe_i2c_start(struct axgbe_port *pdata)
 303{
 304        if (pdata->i2c.started)
 305                return 0;
 306
 307        PMD_DRV_LOG(DEBUG, "starting I2C\n");
 308
 309        pdata->i2c.started = 1;
 310
 311        return 0;
 312}
 313
 314static int axgbe_i2c_init(struct axgbe_port *pdata)
 315{
 316        int ret;
 317
 318        axgbe_i2c_disable_interrupts(pdata);
 319
 320        ret = axgbe_i2c_disable(pdata);
 321        if (ret) {
 322                PMD_DRV_LOG(ERR, "failed to disable i2c master\n");
 323                return ret;
 324        }
 325
 326        axgbe_i2c_get_features(pdata);
 327
 328        axgbe_i2c_set_mode(pdata);
 329
 330        axgbe_i2c_clear_all_interrupts(pdata);
 331
 332        return 0;
 333}
 334
 335void axgbe_init_function_ptrs_i2c(struct axgbe_i2c_if *i2c_if)
 336{
 337        i2c_if->i2c_init                = axgbe_i2c_init;
 338        i2c_if->i2c_start               = axgbe_i2c_start;
 339        i2c_if->i2c_stop                = axgbe_i2c_stop;
 340        i2c_if->i2c_xfer                = axgbe_i2c_xfer;
 341}
 342