17e4d5620SIcenowy Zheng /*
27e4d5620SIcenowy Zheng * Copyright (C) 2018 Marvell International Ltd.
37e4d5620SIcenowy Zheng * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
47e4d5620SIcenowy Zheng *
57e4d5620SIcenowy Zheng * SPDX-License-Identifier: BSD-3-Clause
67e4d5620SIcenowy Zheng * https://spdx.org/licenses
77e4d5620SIcenowy Zheng */
87e4d5620SIcenowy Zheng
97e4d5620SIcenowy Zheng /*
107e4d5620SIcenowy Zheng * This driver is for Mentor Graphics Inventra MI2CV IP core, which is used
117e4d5620SIcenowy Zheng * for Marvell and Allwinner SoCs in ATF.
127e4d5620SIcenowy Zheng */
137e4d5620SIcenowy Zheng
147e4d5620SIcenowy Zheng #include <errno.h>
1509d40e0eSAntonio Nino Diaz
1609d40e0eSAntonio Nino Diaz #include <common/debug.h>
1709d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
1809d40e0eSAntonio Nino Diaz #include <drivers/mentor/mi2cv.h>
1909d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
2009d40e0eSAntonio Nino Diaz
21dfc0fb27SAndre Przywara #include <mentor_i2c_plat.h>
227e4d5620SIcenowy Zheng
237e4d5620SIcenowy Zheng #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
247e4d5620SIcenowy Zheng #define DEBUG_I2C
257e4d5620SIcenowy Zheng #endif
267e4d5620SIcenowy Zheng
277e4d5620SIcenowy Zheng #define I2C_TIMEOUT_VALUE 0x500
287e4d5620SIcenowy Zheng #define I2C_MAX_RETRY_CNT 1000
297e4d5620SIcenowy Zheng #define I2C_CMD_WRITE 0x0
307e4d5620SIcenowy Zheng #define I2C_CMD_READ 0x1
317e4d5620SIcenowy Zheng
327e4d5620SIcenowy Zheng #define I2C_DATA_ADDR_7BIT_OFFS 0x1
337e4d5620SIcenowy Zheng #define I2C_DATA_ADDR_7BIT_MASK (0xFF << I2C_DATA_ADDR_7BIT_OFFS)
347e4d5620SIcenowy Zheng
357e4d5620SIcenowy Zheng #define I2C_CONTROL_ACK 0x00000004
367e4d5620SIcenowy Zheng #define I2C_CONTROL_IFLG 0x00000008
377e4d5620SIcenowy Zheng #define I2C_CONTROL_STOP 0x00000010
387e4d5620SIcenowy Zheng #define I2C_CONTROL_START 0x00000020
397e4d5620SIcenowy Zheng #define I2C_CONTROL_TWSIEN 0x00000040
407e4d5620SIcenowy Zheng #define I2C_CONTROL_INTEN 0x00000080
417e4d5620SIcenowy Zheng
427e4d5620SIcenowy Zheng #define I2C_STATUS_START 0x08
437e4d5620SIcenowy Zheng #define I2C_STATUS_REPEATED_START 0x10
447e4d5620SIcenowy Zheng #define I2C_STATUS_ADDR_W_ACK 0x18
457e4d5620SIcenowy Zheng #define I2C_STATUS_DATA_W_ACK 0x28
467e4d5620SIcenowy Zheng #define I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER 0x38
477e4d5620SIcenowy Zheng #define I2C_STATUS_ADDR_R_ACK 0x40
487e4d5620SIcenowy Zheng #define I2C_STATUS_DATA_R_ACK 0x50
497e4d5620SIcenowy Zheng #define I2C_STATUS_DATA_R_NAK 0x58
507e4d5620SIcenowy Zheng #define I2C_STATUS_LOST_ARB_GENERAL_CALL 0x78
517e4d5620SIcenowy Zheng #define I2C_STATUS_IDLE 0xF8
527e4d5620SIcenowy Zheng
537e4d5620SIcenowy Zheng #define I2C_UNSTUCK_TRIGGER 0x1
547e4d5620SIcenowy Zheng #define I2C_UNSTUCK_ONGOING 0x2
557e4d5620SIcenowy Zheng #define I2C_UNSTUCK_ERROR 0x4
567e4d5620SIcenowy Zheng
577e4d5620SIcenowy Zheng static struct mentor_i2c_regs *base;
587e4d5620SIcenowy Zheng
mentor_i2c_lost_arbitration(uint32_t * status)597e4d5620SIcenowy Zheng static int mentor_i2c_lost_arbitration(uint32_t *status)
607e4d5620SIcenowy Zheng {
617e4d5620SIcenowy Zheng *status = mmio_read_32((uintptr_t)&base->status);
627e4d5620SIcenowy Zheng if ((*status == I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER) ||
637e4d5620SIcenowy Zheng (*status == I2C_STATUS_LOST_ARB_GENERAL_CALL))
647e4d5620SIcenowy Zheng return -EAGAIN;
657e4d5620SIcenowy Zheng
667e4d5620SIcenowy Zheng return 0;
677e4d5620SIcenowy Zheng }
687e4d5620SIcenowy Zheng
mentor_i2c_interrupt_clear(void)697e4d5620SIcenowy Zheng static void mentor_i2c_interrupt_clear(void)
707e4d5620SIcenowy Zheng {
717e4d5620SIcenowy Zheng uint32_t reg;
727e4d5620SIcenowy Zheng
737e4d5620SIcenowy Zheng reg = mmio_read_32((uintptr_t)&base->control);
7420719914SIcenowy Zheng #ifndef I2C_INTERRUPT_CLEAR_INVERTED
757e4d5620SIcenowy Zheng reg &= ~(I2C_CONTROL_IFLG);
7620719914SIcenowy Zheng #else
7720719914SIcenowy Zheng reg |= I2C_CONTROL_IFLG;
7820719914SIcenowy Zheng #endif
797e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->control, reg);
807e4d5620SIcenowy Zheng /* Wait for 1 us for the clear to take effect */
817e4d5620SIcenowy Zheng udelay(1);
827e4d5620SIcenowy Zheng }
837e4d5620SIcenowy Zheng
mentor_i2c_interrupt_get(void)84*d7b4cd41SJustin Chadwell static bool mentor_i2c_interrupt_get(void)
857e4d5620SIcenowy Zheng {
867e4d5620SIcenowy Zheng uint32_t reg;
877e4d5620SIcenowy Zheng
887e4d5620SIcenowy Zheng /* get the interrupt flag bit */
897e4d5620SIcenowy Zheng reg = mmio_read_32((uintptr_t)&base->control);
907e4d5620SIcenowy Zheng reg &= I2C_CONTROL_IFLG;
91*d7b4cd41SJustin Chadwell return (reg != 0U);
927e4d5620SIcenowy Zheng }
937e4d5620SIcenowy Zheng
mentor_i2c_wait_interrupt(void)947e4d5620SIcenowy Zheng static int mentor_i2c_wait_interrupt(void)
957e4d5620SIcenowy Zheng {
967e4d5620SIcenowy Zheng uint32_t timeout = 0;
977e4d5620SIcenowy Zheng
987e4d5620SIcenowy Zheng while (!mentor_i2c_interrupt_get() && (timeout++ < I2C_TIMEOUT_VALUE))
997e4d5620SIcenowy Zheng ;
1007e4d5620SIcenowy Zheng if (timeout >= I2C_TIMEOUT_VALUE)
1017e4d5620SIcenowy Zheng return -ETIMEDOUT;
1027e4d5620SIcenowy Zheng
1037e4d5620SIcenowy Zheng return 0;
1047e4d5620SIcenowy Zheng }
1057e4d5620SIcenowy Zheng
mentor_i2c_start_bit_set(void)1067e4d5620SIcenowy Zheng static int mentor_i2c_start_bit_set(void)
1077e4d5620SIcenowy Zheng {
1087e4d5620SIcenowy Zheng int is_int_flag = 0;
1097e4d5620SIcenowy Zheng uint32_t status;
1107e4d5620SIcenowy Zheng
1117e4d5620SIcenowy Zheng if (mentor_i2c_interrupt_get())
1127e4d5620SIcenowy Zheng is_int_flag = 1;
1137e4d5620SIcenowy Zheng
1147e4d5620SIcenowy Zheng /* set start bit */
1157e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->control,
1167e4d5620SIcenowy Zheng mmio_read_32((uintptr_t)&base->control) |
1177e4d5620SIcenowy Zheng I2C_CONTROL_START);
1187e4d5620SIcenowy Zheng
1197e4d5620SIcenowy Zheng /* in case that the int flag was set before i.e. repeated start bit */
1207e4d5620SIcenowy Zheng if (is_int_flag) {
1217e4d5620SIcenowy Zheng VERBOSE("%s: repeated start Bit\n", __func__);
1227e4d5620SIcenowy Zheng mentor_i2c_interrupt_clear();
1237e4d5620SIcenowy Zheng }
1247e4d5620SIcenowy Zheng
1257e4d5620SIcenowy Zheng if (mentor_i2c_wait_interrupt()) {
1267e4d5620SIcenowy Zheng ERROR("Start clear bit timeout\n");
1277e4d5620SIcenowy Zheng return -ETIMEDOUT;
1287e4d5620SIcenowy Zheng }
1297e4d5620SIcenowy Zheng
1307e4d5620SIcenowy Zheng /* check that start bit went down */
1317e4d5620SIcenowy Zheng if ((mmio_read_32((uintptr_t)&base->control) &
1327e4d5620SIcenowy Zheng I2C_CONTROL_START) != 0) {
1337e4d5620SIcenowy Zheng ERROR("Start bit didn't went down\n");
1347e4d5620SIcenowy Zheng return -EPERM;
1357e4d5620SIcenowy Zheng }
1367e4d5620SIcenowy Zheng
1377e4d5620SIcenowy Zheng /* check the status */
1387e4d5620SIcenowy Zheng if (mentor_i2c_lost_arbitration(&status)) {
1397e4d5620SIcenowy Zheng ERROR("%s - %d: Lost arbitration, got status %x\n",
1407e4d5620SIcenowy Zheng __func__, __LINE__, status);
1417e4d5620SIcenowy Zheng return -EAGAIN;
1427e4d5620SIcenowy Zheng }
1437e4d5620SIcenowy Zheng if ((status != I2C_STATUS_START) &&
1447e4d5620SIcenowy Zheng (status != I2C_STATUS_REPEATED_START)) {
1457e4d5620SIcenowy Zheng ERROR("Got status %x after enable start bit.\n", status);
1467e4d5620SIcenowy Zheng return -EPERM;
1477e4d5620SIcenowy Zheng }
1487e4d5620SIcenowy Zheng
1497e4d5620SIcenowy Zheng return 0;
1507e4d5620SIcenowy Zheng }
1517e4d5620SIcenowy Zheng
mentor_i2c_stop_bit_set(void)1527e4d5620SIcenowy Zheng static int mentor_i2c_stop_bit_set(void)
1537e4d5620SIcenowy Zheng {
1547e4d5620SIcenowy Zheng int timeout;
1557e4d5620SIcenowy Zheng uint32_t status;
1567e4d5620SIcenowy Zheng
1577e4d5620SIcenowy Zheng /* Generate stop bit */
1587e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->control,
1597e4d5620SIcenowy Zheng mmio_read_32((uintptr_t)&base->control) |
1607e4d5620SIcenowy Zheng I2C_CONTROL_STOP);
1617e4d5620SIcenowy Zheng mentor_i2c_interrupt_clear();
1627e4d5620SIcenowy Zheng
1637e4d5620SIcenowy Zheng timeout = 0;
1647e4d5620SIcenowy Zheng /* Read control register, check the control stop bit */
1657e4d5620SIcenowy Zheng while ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) &&
1667e4d5620SIcenowy Zheng (timeout++ < I2C_TIMEOUT_VALUE))
1677e4d5620SIcenowy Zheng ;
1687e4d5620SIcenowy Zheng if (timeout >= I2C_TIMEOUT_VALUE) {
1697e4d5620SIcenowy Zheng ERROR("Stop bit didn't went down\n");
1707e4d5620SIcenowy Zheng return -ETIMEDOUT;
1717e4d5620SIcenowy Zheng }
1727e4d5620SIcenowy Zheng
1737e4d5620SIcenowy Zheng /* check that stop bit went down */
1747e4d5620SIcenowy Zheng if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) != 0) {
1757e4d5620SIcenowy Zheng ERROR("Stop bit didn't went down\n");
1767e4d5620SIcenowy Zheng return -EPERM;
1777e4d5620SIcenowy Zheng }
1787e4d5620SIcenowy Zheng
1797e4d5620SIcenowy Zheng /* check the status */
1807e4d5620SIcenowy Zheng if (mentor_i2c_lost_arbitration(&status)) {
1817e4d5620SIcenowy Zheng ERROR("%s - %d: Lost arbitration, got status %x\n",
1827e4d5620SIcenowy Zheng __func__, __LINE__, status);
1837e4d5620SIcenowy Zheng return -EAGAIN;
1847e4d5620SIcenowy Zheng }
1857e4d5620SIcenowy Zheng if (status != I2C_STATUS_IDLE) {
1867e4d5620SIcenowy Zheng ERROR("Got status %x after enable stop bit.\n", status);
1877e4d5620SIcenowy Zheng return -EPERM;
1887e4d5620SIcenowy Zheng }
1897e4d5620SIcenowy Zheng
1907e4d5620SIcenowy Zheng return 0;
1917e4d5620SIcenowy Zheng }
1927e4d5620SIcenowy Zheng
mentor_i2c_address_set(uint8_t chain,int command)1937e4d5620SIcenowy Zheng static int mentor_i2c_address_set(uint8_t chain, int command)
1947e4d5620SIcenowy Zheng {
1957e4d5620SIcenowy Zheng uint32_t reg, status;
1967e4d5620SIcenowy Zheng
1977e4d5620SIcenowy Zheng reg = (chain << I2C_DATA_ADDR_7BIT_OFFS) & I2C_DATA_ADDR_7BIT_MASK;
1987e4d5620SIcenowy Zheng reg |= command;
1997e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->data, reg);
2007e4d5620SIcenowy Zheng udelay(1);
2017e4d5620SIcenowy Zheng
2027e4d5620SIcenowy Zheng mentor_i2c_interrupt_clear();
2037e4d5620SIcenowy Zheng
2047e4d5620SIcenowy Zheng if (mentor_i2c_wait_interrupt()) {
2057e4d5620SIcenowy Zheng ERROR("Start clear bit timeout\n");
2067e4d5620SIcenowy Zheng return -ETIMEDOUT;
2077e4d5620SIcenowy Zheng }
2087e4d5620SIcenowy Zheng
2097e4d5620SIcenowy Zheng /* check the status */
2107e4d5620SIcenowy Zheng if (mentor_i2c_lost_arbitration(&status)) {
2117e4d5620SIcenowy Zheng ERROR("%s - %d: Lost arbitration, got status %x\n",
2127e4d5620SIcenowy Zheng __func__, __LINE__, status);
2137e4d5620SIcenowy Zheng return -EAGAIN;
2147e4d5620SIcenowy Zheng }
2157e4d5620SIcenowy Zheng if (((status != I2C_STATUS_ADDR_R_ACK) && (command == I2C_CMD_READ)) ||
2167e4d5620SIcenowy Zheng ((status != I2C_STATUS_ADDR_W_ACK) && (command == I2C_CMD_WRITE))) {
2177e4d5620SIcenowy Zheng /* only in debug, since in boot we try to read the SPD
2187e4d5620SIcenowy Zheng * of both DRAM, and we don't want error messages in cas
2197e4d5620SIcenowy Zheng * DIMM doesn't exist.
2207e4d5620SIcenowy Zheng */
2217e4d5620SIcenowy Zheng INFO("%s: ERROR - status %x addr in %s mode.\n", __func__,
2227e4d5620SIcenowy Zheng status, (command == I2C_CMD_WRITE) ? "Write" : "Read");
2237e4d5620SIcenowy Zheng return -EPERM;
2247e4d5620SIcenowy Zheng }
2257e4d5620SIcenowy Zheng
2267e4d5620SIcenowy Zheng return 0;
2277e4d5620SIcenowy Zheng }
2287e4d5620SIcenowy Zheng
2297e4d5620SIcenowy Zheng /*
2307e4d5620SIcenowy Zheng * The I2C module contains a clock divider to generate the SCL clock.
2317e4d5620SIcenowy Zheng * This function calculates and sets the <N> and <M> fields in the I2C Baud
2327e4d5620SIcenowy Zheng * Rate Register (t=01) to obtain given 'requested_speed'.
2337e4d5620SIcenowy Zheng * The requested_speed will be equal to:
2347e4d5620SIcenowy Zheng * CONFIG_SYS_TCLK / (10 * (M + 1) * (2 << N))
2357e4d5620SIcenowy Zheng * Where M is the value represented by bits[6:3] and N is the value represented
2367e4d5620SIcenowy Zheng * by bits[2:0] of "I2C Baud Rate Register".
2377e4d5620SIcenowy Zheng * Therefore max M which can be set is 16 (2^4) and max N is 8 (2^3). So the
2387e4d5620SIcenowy Zheng * lowest possible baudrate is:
2397e4d5620SIcenowy Zheng * CONFIG_SYS_TCLK/(10 * (16 +1) * (2 << 8), which equals to:
2407e4d5620SIcenowy Zheng * CONFIG_SYS_TCLK/87040. Assuming that CONFIG_SYS_TCLK=250MHz, the lowest
2417e4d5620SIcenowy Zheng * possible frequency is ~2,872KHz.
2427e4d5620SIcenowy Zheng */
mentor_i2c_bus_speed_set(unsigned int requested_speed)2437e4d5620SIcenowy Zheng static unsigned int mentor_i2c_bus_speed_set(unsigned int requested_speed)
2447e4d5620SIcenowy Zheng {
2457e4d5620SIcenowy Zheng unsigned int n, m, freq, margin, min_margin = 0xffffffff;
2467e4d5620SIcenowy Zheng unsigned int actual_n = 0, actual_m = 0;
2477e4d5620SIcenowy Zheng int val;
2487e4d5620SIcenowy Zheng
2497e4d5620SIcenowy Zheng /* Calculate N and M for the TWSI clock baud rate */
2507e4d5620SIcenowy Zheng for (n = 0; n < 8; n++) {
2517e4d5620SIcenowy Zheng for (m = 0; m < 16; m++) {
2527e4d5620SIcenowy Zheng freq = CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
2537e4d5620SIcenowy Zheng val = requested_speed - freq;
2547e4d5620SIcenowy Zheng margin = (val > 0) ? val : -val;
2557e4d5620SIcenowy Zheng
2567e4d5620SIcenowy Zheng if ((freq <= requested_speed) &&
2577e4d5620SIcenowy Zheng (margin < min_margin)) {
2587e4d5620SIcenowy Zheng min_margin = margin;
2597e4d5620SIcenowy Zheng actual_n = n;
2607e4d5620SIcenowy Zheng actual_m = m;
2617e4d5620SIcenowy Zheng }
2627e4d5620SIcenowy Zheng }
2637e4d5620SIcenowy Zheng }
2647e4d5620SIcenowy Zheng VERBOSE("%s: actual_n = %u, actual_m = %u\n",
2657e4d5620SIcenowy Zheng __func__, actual_n, actual_m);
2667e4d5620SIcenowy Zheng /* Set the baud rate */
2677e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->baudrate, (actual_m << 3) | actual_n);
2687e4d5620SIcenowy Zheng
2697e4d5620SIcenowy Zheng return 0;
2707e4d5620SIcenowy Zheng }
2717e4d5620SIcenowy Zheng
2727e4d5620SIcenowy Zheng #ifdef DEBUG_I2C
mentor_i2c_probe(uint8_t chip)2737e4d5620SIcenowy Zheng static int mentor_i2c_probe(uint8_t chip)
2747e4d5620SIcenowy Zheng {
2757e4d5620SIcenowy Zheng int ret = 0;
2767e4d5620SIcenowy Zheng
2777e4d5620SIcenowy Zheng ret = mentor_i2c_start_bit_set();
2787e4d5620SIcenowy Zheng if (ret != 0) {
2797e4d5620SIcenowy Zheng mentor_i2c_stop_bit_set();
2807e4d5620SIcenowy Zheng ERROR("%s - %d: %s", __func__, __LINE__,
2817e4d5620SIcenowy Zheng "mentor_i2c_start_bit_set failed\n");
2827e4d5620SIcenowy Zheng return -EPERM;
2837e4d5620SIcenowy Zheng }
2847e4d5620SIcenowy Zheng
2857e4d5620SIcenowy Zheng ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
2867e4d5620SIcenowy Zheng if (ret != 0) {
2877e4d5620SIcenowy Zheng mentor_i2c_stop_bit_set();
2887e4d5620SIcenowy Zheng ERROR("%s - %d: %s", __func__, __LINE__,
2897e4d5620SIcenowy Zheng "mentor_i2c_address_set failed\n");
2907e4d5620SIcenowy Zheng return -EPERM;
2917e4d5620SIcenowy Zheng }
2927e4d5620SIcenowy Zheng
2937e4d5620SIcenowy Zheng mentor_i2c_stop_bit_set();
2947e4d5620SIcenowy Zheng
2957e4d5620SIcenowy Zheng VERBOSE("%s: successful I2C probe\n", __func__);
2967e4d5620SIcenowy Zheng
2977e4d5620SIcenowy Zheng return ret;
2987e4d5620SIcenowy Zheng }
2997e4d5620SIcenowy Zheng #endif
3007e4d5620SIcenowy Zheng
3017e4d5620SIcenowy Zheng /* regular i2c transaction */
mentor_i2c_data_receive(uint8_t * p_block,uint32_t block_size)3027e4d5620SIcenowy Zheng static int mentor_i2c_data_receive(uint8_t *p_block, uint32_t block_size)
3037e4d5620SIcenowy Zheng {
3047e4d5620SIcenowy Zheng uint32_t reg, status, block_size_read = block_size;
3057e4d5620SIcenowy Zheng
3067e4d5620SIcenowy Zheng /* Wait for cause interrupt */
3077e4d5620SIcenowy Zheng if (mentor_i2c_wait_interrupt()) {
3087e4d5620SIcenowy Zheng ERROR("Start clear bit timeout\n");
3097e4d5620SIcenowy Zheng return -ETIMEDOUT;
3107e4d5620SIcenowy Zheng }
3117e4d5620SIcenowy Zheng while (block_size_read) {
3127e4d5620SIcenowy Zheng if (block_size_read == 1) {
3137e4d5620SIcenowy Zheng reg = mmio_read_32((uintptr_t)&base->control);
3147e4d5620SIcenowy Zheng reg &= ~(I2C_CONTROL_ACK);
3157e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->control, reg);
3167e4d5620SIcenowy Zheng }
3177e4d5620SIcenowy Zheng mentor_i2c_interrupt_clear();
3187e4d5620SIcenowy Zheng
3197e4d5620SIcenowy Zheng if (mentor_i2c_wait_interrupt()) {
3207e4d5620SIcenowy Zheng ERROR("Start clear bit timeout\n");
3217e4d5620SIcenowy Zheng return -ETIMEDOUT;
3227e4d5620SIcenowy Zheng }
3237e4d5620SIcenowy Zheng /* check the status */
3247e4d5620SIcenowy Zheng if (mentor_i2c_lost_arbitration(&status)) {
3257e4d5620SIcenowy Zheng ERROR("%s - %d: Lost arbitration, got status %x\n",
3267e4d5620SIcenowy Zheng __func__, __LINE__, status);
3277e4d5620SIcenowy Zheng return -EAGAIN;
3287e4d5620SIcenowy Zheng }
3297e4d5620SIcenowy Zheng if ((status != I2C_STATUS_DATA_R_ACK) &&
3307e4d5620SIcenowy Zheng (block_size_read != 1)) {
3317e4d5620SIcenowy Zheng ERROR("Status %x in read transaction\n", status);
3327e4d5620SIcenowy Zheng return -EPERM;
3337e4d5620SIcenowy Zheng }
3347e4d5620SIcenowy Zheng if ((status != I2C_STATUS_DATA_R_NAK) &&
3357e4d5620SIcenowy Zheng (block_size_read == 1)) {
3367e4d5620SIcenowy Zheng ERROR("Status %x in Rd Terminate\n", status);
3377e4d5620SIcenowy Zheng return -EPERM;
3387e4d5620SIcenowy Zheng }
3397e4d5620SIcenowy Zheng
3407e4d5620SIcenowy Zheng /* read the data */
3417e4d5620SIcenowy Zheng *p_block = (uint8_t) mmio_read_32((uintptr_t)&base->data);
3427e4d5620SIcenowy Zheng VERBOSE("%s: place %d read %x\n", __func__,
3437e4d5620SIcenowy Zheng block_size - block_size_read, *p_block);
3447e4d5620SIcenowy Zheng p_block++;
3457e4d5620SIcenowy Zheng block_size_read--;
3467e4d5620SIcenowy Zheng }
3477e4d5620SIcenowy Zheng
3487e4d5620SIcenowy Zheng return 0;
3497e4d5620SIcenowy Zheng }
3507e4d5620SIcenowy Zheng
mentor_i2c_data_transmit(uint8_t * p_block,uint32_t block_size)3517e4d5620SIcenowy Zheng static int mentor_i2c_data_transmit(uint8_t *p_block, uint32_t block_size)
3527e4d5620SIcenowy Zheng {
3537e4d5620SIcenowy Zheng uint32_t status, block_size_write = block_size;
3547e4d5620SIcenowy Zheng
3557e4d5620SIcenowy Zheng if (mentor_i2c_wait_interrupt()) {
3567e4d5620SIcenowy Zheng ERROR("Start clear bit timeout\n");
3577e4d5620SIcenowy Zheng return -ETIMEDOUT;
3587e4d5620SIcenowy Zheng }
3597e4d5620SIcenowy Zheng
3607e4d5620SIcenowy Zheng while (block_size_write) {
3617e4d5620SIcenowy Zheng /* write the data */
3627e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->data, (uint32_t) *p_block);
3637e4d5620SIcenowy Zheng VERBOSE("%s: index = %d, data = %x\n", __func__,
3647e4d5620SIcenowy Zheng block_size - block_size_write, *p_block);
3657e4d5620SIcenowy Zheng p_block++;
3667e4d5620SIcenowy Zheng block_size_write--;
3677e4d5620SIcenowy Zheng
3687e4d5620SIcenowy Zheng mentor_i2c_interrupt_clear();
3697e4d5620SIcenowy Zheng
3707e4d5620SIcenowy Zheng if (mentor_i2c_wait_interrupt()) {
3717e4d5620SIcenowy Zheng ERROR("Start clear bit timeout\n");
3727e4d5620SIcenowy Zheng return -ETIMEDOUT;
3737e4d5620SIcenowy Zheng }
3747e4d5620SIcenowy Zheng
3757e4d5620SIcenowy Zheng /* check the status */
3767e4d5620SIcenowy Zheng if (mentor_i2c_lost_arbitration(&status)) {
3777e4d5620SIcenowy Zheng ERROR("%s - %d: Lost arbitration, got status %x\n",
3787e4d5620SIcenowy Zheng __func__, __LINE__, status);
3797e4d5620SIcenowy Zheng return -EAGAIN;
3807e4d5620SIcenowy Zheng }
3817e4d5620SIcenowy Zheng if (status != I2C_STATUS_DATA_W_ACK) {
3827e4d5620SIcenowy Zheng ERROR("Status %x in write transaction\n", status);
3837e4d5620SIcenowy Zheng return -EPERM;
3847e4d5620SIcenowy Zheng }
3857e4d5620SIcenowy Zheng }
3867e4d5620SIcenowy Zheng
3877e4d5620SIcenowy Zheng return 0;
3887e4d5620SIcenowy Zheng }
3897e4d5620SIcenowy Zheng
mentor_i2c_target_offset_set(uint8_t chip,uint32_t addr,int alen)3907e4d5620SIcenowy Zheng static int mentor_i2c_target_offset_set(uint8_t chip, uint32_t addr, int alen)
3917e4d5620SIcenowy Zheng {
3927e4d5620SIcenowy Zheng uint8_t off_block[2];
3937e4d5620SIcenowy Zheng uint32_t off_size;
3947e4d5620SIcenowy Zheng
3957e4d5620SIcenowy Zheng if (alen == 2) { /* 2-byte addresses support */
3967e4d5620SIcenowy Zheng off_block[0] = (addr >> 8) & 0xff;
3977e4d5620SIcenowy Zheng off_block[1] = addr & 0xff;
3987e4d5620SIcenowy Zheng off_size = 2;
3997e4d5620SIcenowy Zheng } else { /* 1-byte addresses support */
4007e4d5620SIcenowy Zheng off_block[0] = addr & 0xff;
4017e4d5620SIcenowy Zheng off_size = 1;
4027e4d5620SIcenowy Zheng }
4037e4d5620SIcenowy Zheng VERBOSE("%s: off_size = %x addr1 = %x addr2 = %x\n", __func__,
4047e4d5620SIcenowy Zheng off_size, off_block[0], off_block[1]);
4057e4d5620SIcenowy Zheng return mentor_i2c_data_transmit(off_block, off_size);
4067e4d5620SIcenowy Zheng }
4077e4d5620SIcenowy Zheng
4087e4d5620SIcenowy Zheng #ifdef I2C_CAN_UNSTUCK
mentor_i2c_unstuck(int ret)4097e4d5620SIcenowy Zheng static int mentor_i2c_unstuck(int ret)
4107e4d5620SIcenowy Zheng {
4117e4d5620SIcenowy Zheng uint32_t v;
4127e4d5620SIcenowy Zheng
4137e4d5620SIcenowy Zheng if (ret != -ETIMEDOUT)
4147e4d5620SIcenowy Zheng return ret;
4157e4d5620SIcenowy Zheng VERBOSE("Trying to \"unstuck i2c\"... ");
4167e4d5620SIcenowy Zheng i2c_init(base);
4177e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->unstuck, I2C_UNSTUCK_TRIGGER);
4187e4d5620SIcenowy Zheng do {
4197e4d5620SIcenowy Zheng v = mmio_read_32((uintptr_t)&base->unstuck);
4207e4d5620SIcenowy Zheng } while (v & I2C_UNSTUCK_ONGOING);
4217e4d5620SIcenowy Zheng
4227e4d5620SIcenowy Zheng if (v & I2C_UNSTUCK_ERROR) {
4237e4d5620SIcenowy Zheng VERBOSE("failed - soft reset i2c\n");
4247e4d5620SIcenowy Zheng ret = -EPERM;
4257e4d5620SIcenowy Zheng } else {
4267e4d5620SIcenowy Zheng VERBOSE("ok\n");
4277e4d5620SIcenowy Zheng i2c_init(base);
4287e4d5620SIcenowy Zheng ret = -EAGAIN;
4297e4d5620SIcenowy Zheng }
4307e4d5620SIcenowy Zheng return ret;
4317e4d5620SIcenowy Zheng }
4327e4d5620SIcenowy Zheng #else
mentor_i2c_unstuck(int ret)4337e4d5620SIcenowy Zheng static int mentor_i2c_unstuck(int ret)
4347e4d5620SIcenowy Zheng {
4357e4d5620SIcenowy Zheng VERBOSE("Cannot \"unstuck i2c\" - soft reset i2c\n");
4367e4d5620SIcenowy Zheng return -EPERM;
4377e4d5620SIcenowy Zheng }
4387e4d5620SIcenowy Zheng #endif
4397e4d5620SIcenowy Zheng
4407e4d5620SIcenowy Zheng /*
4417e4d5620SIcenowy Zheng * API Functions
4427e4d5620SIcenowy Zheng */
i2c_init(void * i2c_base)4437e4d5620SIcenowy Zheng void i2c_init(void *i2c_base)
4447e4d5620SIcenowy Zheng {
4457e4d5620SIcenowy Zheng /* For I2C speed and slave address, now we do not set them since
4467e4d5620SIcenowy Zheng * we just provide the working speed and slave address otherwhere
4477e4d5620SIcenowy Zheng * for i2c_init
4487e4d5620SIcenowy Zheng */
4497e4d5620SIcenowy Zheng base = (struct mentor_i2c_regs *)i2c_base;
4507e4d5620SIcenowy Zheng
4517e4d5620SIcenowy Zheng /* Reset the I2C logic */
4527e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->soft_reset, 0);
4537e4d5620SIcenowy Zheng
4547e4d5620SIcenowy Zheng udelay(200);
4557e4d5620SIcenowy Zheng
4567e4d5620SIcenowy Zheng mentor_i2c_bus_speed_set(CONFIG_SYS_I2C_SPEED);
4577e4d5620SIcenowy Zheng
4587e4d5620SIcenowy Zheng /* Enable the I2C and slave */
4597e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->control,
4607e4d5620SIcenowy Zheng I2C_CONTROL_TWSIEN | I2C_CONTROL_ACK);
4617e4d5620SIcenowy Zheng
4627e4d5620SIcenowy Zheng /* set the I2C slave address */
4637e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->xtnd_slave_addr, 0);
4647e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->slave_address, CONFIG_SYS_I2C_SLAVE);
4657e4d5620SIcenowy Zheng
4667e4d5620SIcenowy Zheng /* unmask I2C interrupt */
4677e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->control,
4687e4d5620SIcenowy Zheng mmio_read_32((uintptr_t)&base->control) |
4697e4d5620SIcenowy Zheng I2C_CONTROL_INTEN);
4707e4d5620SIcenowy Zheng
4717e4d5620SIcenowy Zheng udelay(10);
4727e4d5620SIcenowy Zheng }
4737e4d5620SIcenowy Zheng
4747e4d5620SIcenowy Zheng /*
4757e4d5620SIcenowy Zheng * i2c_read: - Read multiple bytes from an i2c device
4767e4d5620SIcenowy Zheng *
4777e4d5620SIcenowy Zheng * The higher level routines take into account that this function is only
4787e4d5620SIcenowy Zheng * called with len < page length of the device (see configuration file)
4797e4d5620SIcenowy Zheng *
4807e4d5620SIcenowy Zheng * @chip: address of the chip which is to be read
4817e4d5620SIcenowy Zheng * @addr: i2c data address within the chip
4827e4d5620SIcenowy Zheng * @alen: length of the i2c data address (1..2 bytes)
4837e4d5620SIcenowy Zheng * @buffer: where to write the data
4847e4d5620SIcenowy Zheng * @len: how much byte do we want to read
4857e4d5620SIcenowy Zheng * @return: 0 in case of success
4867e4d5620SIcenowy Zheng */
i2c_read(uint8_t chip,uint32_t addr,int alen,uint8_t * buffer,int len)4877e4d5620SIcenowy Zheng int i2c_read(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
4887e4d5620SIcenowy Zheng {
4897e4d5620SIcenowy Zheng int ret = 0;
4907e4d5620SIcenowy Zheng uint32_t counter = 0;
4917e4d5620SIcenowy Zheng
4927e4d5620SIcenowy Zheng #ifdef DEBUG_I2C
4937e4d5620SIcenowy Zheng mentor_i2c_probe(chip);
4947e4d5620SIcenowy Zheng #endif
4957e4d5620SIcenowy Zheng
4967e4d5620SIcenowy Zheng do {
4977e4d5620SIcenowy Zheng if (ret != -EAGAIN && ret) {
4987e4d5620SIcenowy Zheng ERROR("i2c transaction failed, after %d retries\n",
4997e4d5620SIcenowy Zheng counter);
5007e4d5620SIcenowy Zheng mentor_i2c_stop_bit_set();
5017e4d5620SIcenowy Zheng return ret;
5027e4d5620SIcenowy Zheng }
5037e4d5620SIcenowy Zheng
5047e4d5620SIcenowy Zheng /* wait for 1 us for the interrupt clear to take effect */
5057e4d5620SIcenowy Zheng if (counter > 0)
5067e4d5620SIcenowy Zheng udelay(1);
5077e4d5620SIcenowy Zheng counter++;
5087e4d5620SIcenowy Zheng
5097e4d5620SIcenowy Zheng ret = mentor_i2c_start_bit_set();
5107e4d5620SIcenowy Zheng if (ret) {
5117e4d5620SIcenowy Zheng ret = mentor_i2c_unstuck(ret);
5127e4d5620SIcenowy Zheng continue;
5137e4d5620SIcenowy Zheng }
5147e4d5620SIcenowy Zheng
5157e4d5620SIcenowy Zheng /* if EEPROM device */
5167e4d5620SIcenowy Zheng if (alen != 0) {
5177e4d5620SIcenowy Zheng ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
5187e4d5620SIcenowy Zheng if (ret)
5197e4d5620SIcenowy Zheng continue;
5207e4d5620SIcenowy Zheng
5217e4d5620SIcenowy Zheng ret = mentor_i2c_target_offset_set(chip, addr, alen);
5227e4d5620SIcenowy Zheng if (ret)
5237e4d5620SIcenowy Zheng continue;
5247e4d5620SIcenowy Zheng ret = mentor_i2c_start_bit_set();
5257e4d5620SIcenowy Zheng if (ret)
5267e4d5620SIcenowy Zheng continue;
5277e4d5620SIcenowy Zheng }
5287e4d5620SIcenowy Zheng
5297e4d5620SIcenowy Zheng ret = mentor_i2c_address_set(chip, I2C_CMD_READ);
5307e4d5620SIcenowy Zheng if (ret)
5317e4d5620SIcenowy Zheng continue;
5327e4d5620SIcenowy Zheng
5337e4d5620SIcenowy Zheng ret = mentor_i2c_data_receive(buffer, len);
5347e4d5620SIcenowy Zheng if (ret)
5357e4d5620SIcenowy Zheng continue;
5367e4d5620SIcenowy Zheng
5377e4d5620SIcenowy Zheng ret = mentor_i2c_stop_bit_set();
5387e4d5620SIcenowy Zheng } while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
5397e4d5620SIcenowy Zheng
5407e4d5620SIcenowy Zheng if (counter == I2C_MAX_RETRY_CNT) {
5417e4d5620SIcenowy Zheng ERROR("I2C transactions failed, got EAGAIN %d times\n",
5427e4d5620SIcenowy Zheng I2C_MAX_RETRY_CNT);
5437e4d5620SIcenowy Zheng ret = -EPERM;
5447e4d5620SIcenowy Zheng }
5457e4d5620SIcenowy Zheng mmio_write_32((uintptr_t)&base->control,
5467e4d5620SIcenowy Zheng mmio_read_32((uintptr_t)&base->control) |
5477e4d5620SIcenowy Zheng I2C_CONTROL_ACK);
5487e4d5620SIcenowy Zheng
5497e4d5620SIcenowy Zheng udelay(1);
5507e4d5620SIcenowy Zheng return ret;
5517e4d5620SIcenowy Zheng }
5527e4d5620SIcenowy Zheng
5537e4d5620SIcenowy Zheng /*
5547e4d5620SIcenowy Zheng * i2c_write: - Write multiple bytes to an i2c device
5557e4d5620SIcenowy Zheng *
5567e4d5620SIcenowy Zheng * The higher level routines take into account that this function is only
5577e4d5620SIcenowy Zheng * called with len < page length of the device (see configuration file)
5587e4d5620SIcenowy Zheng *
5597e4d5620SIcenowy Zheng * @chip: address of the chip which is to be written
5607e4d5620SIcenowy Zheng * @addr: i2c data address within the chip
5617e4d5620SIcenowy Zheng * @alen: length of the i2c data address (1..2 bytes)
5627e4d5620SIcenowy Zheng * @buffer: where to find the data to be written
5637e4d5620SIcenowy Zheng * @len: how much byte do we want to read
5647e4d5620SIcenowy Zheng * @return: 0 in case of success
5657e4d5620SIcenowy Zheng */
i2c_write(uint8_t chip,uint32_t addr,int alen,uint8_t * buffer,int len)5667e4d5620SIcenowy Zheng int i2c_write(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
5677e4d5620SIcenowy Zheng {
5687e4d5620SIcenowy Zheng int ret = 0;
5697e4d5620SIcenowy Zheng uint32_t counter = 0;
5707e4d5620SIcenowy Zheng
5717e4d5620SIcenowy Zheng do {
5727e4d5620SIcenowy Zheng if (ret != -EAGAIN && ret) {
5737e4d5620SIcenowy Zheng ERROR("i2c transaction failed\n");
5747e4d5620SIcenowy Zheng mentor_i2c_stop_bit_set();
5757e4d5620SIcenowy Zheng return ret;
5767e4d5620SIcenowy Zheng }
5777e4d5620SIcenowy Zheng /* wait for 1 us for the interrupt clear to take effect */
5787e4d5620SIcenowy Zheng if (counter > 0)
5797e4d5620SIcenowy Zheng udelay(1);
5807e4d5620SIcenowy Zheng counter++;
5817e4d5620SIcenowy Zheng
5827e4d5620SIcenowy Zheng ret = mentor_i2c_start_bit_set();
5837e4d5620SIcenowy Zheng if (ret) {
5847e4d5620SIcenowy Zheng ret = mentor_i2c_unstuck(ret);
5857e4d5620SIcenowy Zheng continue;
5867e4d5620SIcenowy Zheng }
5877e4d5620SIcenowy Zheng
5887e4d5620SIcenowy Zheng ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
5897e4d5620SIcenowy Zheng if (ret)
5907e4d5620SIcenowy Zheng continue;
5917e4d5620SIcenowy Zheng
5927e4d5620SIcenowy Zheng /* if EEPROM device */
5937e4d5620SIcenowy Zheng if (alen != 0) {
5947e4d5620SIcenowy Zheng ret = mentor_i2c_target_offset_set(chip, addr, alen);
5957e4d5620SIcenowy Zheng if (ret)
5967e4d5620SIcenowy Zheng continue;
5977e4d5620SIcenowy Zheng }
5987e4d5620SIcenowy Zheng
5997e4d5620SIcenowy Zheng ret = mentor_i2c_data_transmit(buffer, len);
6007e4d5620SIcenowy Zheng if (ret)
6017e4d5620SIcenowy Zheng continue;
6027e4d5620SIcenowy Zheng
6037e4d5620SIcenowy Zheng ret = mentor_i2c_stop_bit_set();
6047e4d5620SIcenowy Zheng } while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
6057e4d5620SIcenowy Zheng
6067e4d5620SIcenowy Zheng if (counter == I2C_MAX_RETRY_CNT) {
6077e4d5620SIcenowy Zheng ERROR("I2C transactions failed, got EAGAIN %d times\n",
6087e4d5620SIcenowy Zheng I2C_MAX_RETRY_CNT);
6097e4d5620SIcenowy Zheng ret = -EPERM;
6107e4d5620SIcenowy Zheng }
6117e4d5620SIcenowy Zheng
6127e4d5620SIcenowy Zheng udelay(1);
6137e4d5620SIcenowy Zheng return ret;
6147e4d5620SIcenowy Zheng }
615