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