178b3ea9cSJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause 278b3ea9cSJorge Ramirez-Ortiz /* 378b3ea9cSJorge Ramirez-Ortiz * (c) 2020 Jorge Ramirez <jorge@foundries.io>, Foundries Ltd. 478b3ea9cSJorge Ramirez-Ortiz */ 578b3ea9cSJorge Ramirez-Ortiz #include <arm.h> 678b3ea9cSJorge Ramirez-Ortiz #include <drivers/imx_i2c.h> 778b3ea9cSJorge Ramirez-Ortiz #include <initcall.h> 878b3ea9cSJorge Ramirez-Ortiz #include <io.h> 978b3ea9cSJorge Ramirez-Ortiz #include <kernel/delay.h> 1078b3ea9cSJorge Ramirez-Ortiz #include <mm/core_memprot.h> 1178b3ea9cSJorge Ramirez-Ortiz #include <mm/core_mmu.h> 1278b3ea9cSJorge Ramirez-Ortiz #include <platform_config.h> 1378b3ea9cSJorge Ramirez-Ortiz #include <stdlib.h> 1478b3ea9cSJorge Ramirez-Ortiz #include <trace.h> 1578b3ea9cSJorge Ramirez-Ortiz #include <util.h> 1678b3ea9cSJorge Ramirez-Ortiz 1778b3ea9cSJorge Ramirez-Ortiz #define I2C_CLK_RATE 24000000 /* Bits per second */ 1878b3ea9cSJorge Ramirez-Ortiz 1978b3ea9cSJorge Ramirez-Ortiz static struct io_pa_va i2c_bus[] = { 2078b3ea9cSJorge Ramirez-Ortiz { .pa = I2C1_BASE, }, 2178b3ea9cSJorge Ramirez-Ortiz { .pa = I2C2_BASE, }, 2278b3ea9cSJorge Ramirez-Ortiz { .pa = I2C3_BASE, }, 2378b3ea9cSJorge Ramirez-Ortiz }; 2478b3ea9cSJorge Ramirez-Ortiz 2578b3ea9cSJorge Ramirez-Ortiz static struct imx_i2c_clk { 2678b3ea9cSJorge Ramirez-Ortiz struct io_pa_va base; 2778b3ea9cSJorge Ramirez-Ortiz uint32_t i2c[ARRAY_SIZE(i2c_bus)]; 2878b3ea9cSJorge Ramirez-Ortiz } i2c_clk = { 2978b3ea9cSJorge Ramirez-Ortiz .base.pa = CCM_BASE, 3078b3ea9cSJorge Ramirez-Ortiz .i2c = { I2C_CLK_CGR(1), I2C_CLK_CGR(2), I2C_CLK_CGR(3), }, 3178b3ea9cSJorge Ramirez-Ortiz }; 3278b3ea9cSJorge Ramirez-Ortiz 3378b3ea9cSJorge Ramirez-Ortiz static struct imx_i2c_mux { 3478b3ea9cSJorge Ramirez-Ortiz struct io_pa_va base; 3578b3ea9cSJorge Ramirez-Ortiz struct imx_i2c_mux_regs { 3678b3ea9cSJorge Ramirez-Ortiz uint32_t scl_mux; 3778b3ea9cSJorge Ramirez-Ortiz uint32_t scl_cfg; 3878b3ea9cSJorge Ramirez-Ortiz uint32_t sda_mux; 3978b3ea9cSJorge Ramirez-Ortiz uint32_t sda_cfg; 4078b3ea9cSJorge Ramirez-Ortiz } i2c[ARRAY_SIZE(i2c_bus)]; 4178b3ea9cSJorge Ramirez-Ortiz } i2c_mux = { 4278b3ea9cSJorge Ramirez-Ortiz .base.pa = IOMUXC_BASE, 4378b3ea9cSJorge Ramirez-Ortiz .i2c = {{ .scl_mux = I2C_MUX_SCL(1), .scl_cfg = I2C_CFG_SCL(1), 4478b3ea9cSJorge Ramirez-Ortiz .sda_mux = I2C_MUX_SDA(1), .sda_cfg = I2C_CFG_SDA(1), }, 4578b3ea9cSJorge Ramirez-Ortiz { .scl_mux = I2C_MUX_SCL(2), .scl_cfg = I2C_CFG_SCL(2), 4678b3ea9cSJorge Ramirez-Ortiz .sda_mux = I2C_MUX_SDA(2), .sda_cfg = I2C_CFG_SDA(2), }, 4778b3ea9cSJorge Ramirez-Ortiz { .scl_mux = I2C_MUX_SCL(3), .scl_cfg = I2C_CFG_SCL(3), 4878b3ea9cSJorge Ramirez-Ortiz .sda_mux = I2C_MUX_SDA(3), .sda_cfg = I2C_CFG_SDA(3), },}, 4978b3ea9cSJorge Ramirez-Ortiz }; 5078b3ea9cSJorge Ramirez-Ortiz 5178b3ea9cSJorge Ramirez-Ortiz #define I2DR 0x10 5278b3ea9cSJorge Ramirez-Ortiz #define I2SR 0x0C 5378b3ea9cSJorge Ramirez-Ortiz #define I2CR 0x08 5478b3ea9cSJorge Ramirez-Ortiz #define IFDR 0x04 5578b3ea9cSJorge Ramirez-Ortiz 5678b3ea9cSJorge Ramirez-Ortiz #define I2CR_IEN BIT(7) 5778b3ea9cSJorge Ramirez-Ortiz #define I2CR_IIEN BIT(6) 5878b3ea9cSJorge Ramirez-Ortiz #define I2CR_MSTA BIT(5) 5978b3ea9cSJorge Ramirez-Ortiz #define I2CR_MTX BIT(4) 6078b3ea9cSJorge Ramirez-Ortiz #define I2CR_TX_NO_AK BIT(3) 6178b3ea9cSJorge Ramirez-Ortiz #define I2CR_RSTA BIT(2) 6278b3ea9cSJorge Ramirez-Ortiz 6378b3ea9cSJorge Ramirez-Ortiz #define I2SR_ICF BIT(7) 6478b3ea9cSJorge Ramirez-Ortiz #define I2SR_IBB BIT(5) 6578b3ea9cSJorge Ramirez-Ortiz #define I2SR_IAL BIT(4) 6678b3ea9cSJorge Ramirez-Ortiz #define I2SR_IIF BIT(1) 6778b3ea9cSJorge Ramirez-Ortiz #define I2SR_RX_NO_AK BIT(0) 6878b3ea9cSJorge Ramirez-Ortiz 6978b3ea9cSJorge Ramirez-Ortiz static uint8_t i2c_io_read8(uint8_t bid, uint32_t address) 7078b3ea9cSJorge Ramirez-Ortiz { 7178b3ea9cSJorge Ramirez-Ortiz return io_read8(i2c_bus[bid].va + address); 7278b3ea9cSJorge Ramirez-Ortiz } 7378b3ea9cSJorge Ramirez-Ortiz 7478b3ea9cSJorge Ramirez-Ortiz static void i2c_io_write8(uint8_t bid, uint32_t address, uint8_t data) 7578b3ea9cSJorge Ramirez-Ortiz { 7678b3ea9cSJorge Ramirez-Ortiz return io_write8(i2c_bus[bid].va + address, data); 7778b3ea9cSJorge Ramirez-Ortiz } 7878b3ea9cSJorge Ramirez-Ortiz 7978b3ea9cSJorge Ramirez-Ortiz static bool bus_is_idle(uint32_t sr) 8078b3ea9cSJorge Ramirez-Ortiz { 8178b3ea9cSJorge Ramirez-Ortiz return (sr & I2SR_IBB) == 0; 8278b3ea9cSJorge Ramirez-Ortiz } 8378b3ea9cSJorge Ramirez-Ortiz 8478b3ea9cSJorge Ramirez-Ortiz static bool bus_is_busy(uint32_t sr) 8578b3ea9cSJorge Ramirez-Ortiz { 8678b3ea9cSJorge Ramirez-Ortiz return !bus_is_idle(sr); 8778b3ea9cSJorge Ramirez-Ortiz } 8878b3ea9cSJorge Ramirez-Ortiz 8978b3ea9cSJorge Ramirez-Ortiz static bool isr_active(uint32_t sr) 9078b3ea9cSJorge Ramirez-Ortiz { 9178b3ea9cSJorge Ramirez-Ortiz return (sr & I2SR_IIF) == I2SR_IIF; 9278b3ea9cSJorge Ramirez-Ortiz } 9378b3ea9cSJorge Ramirez-Ortiz 9478b3ea9cSJorge Ramirez-Ortiz static struct ifdr_pair { 9578b3ea9cSJorge Ramirez-Ortiz uint32_t divider; 9678b3ea9cSJorge Ramirez-Ortiz uint8_t prescaler; 9778b3ea9cSJorge Ramirez-Ortiz } ifdr_table[] = { 9878b3ea9cSJorge Ramirez-Ortiz { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, 9978b3ea9cSJorge Ramirez-Ortiz { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, 10078b3ea9cSJorge Ramirez-Ortiz { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, 10178b3ea9cSJorge Ramirez-Ortiz { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B }, 10278b3ea9cSJorge Ramirez-Ortiz { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A }, 10378b3ea9cSJorge Ramirez-Ortiz { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 }, 10478b3ea9cSJorge Ramirez-Ortiz { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 }, 10578b3ea9cSJorge Ramirez-Ortiz { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 }, 10678b3ea9cSJorge Ramirez-Ortiz { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 }, 10778b3ea9cSJorge Ramirez-Ortiz { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B }, 10878b3ea9cSJorge Ramirez-Ortiz { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E }, 10978b3ea9cSJorge Ramirez-Ortiz { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, 11078b3ea9cSJorge Ramirez-Ortiz { 3072, 0x1E }, { 3840, 0x1F } 11178b3ea9cSJorge Ramirez-Ortiz }; 11278b3ea9cSJorge Ramirez-Ortiz 11378b3ea9cSJorge Ramirez-Ortiz static void i2c_set_prescaler(uint8_t bid, uint32_t bps) 11478b3ea9cSJorge Ramirez-Ortiz { 11578b3ea9cSJorge Ramirez-Ortiz struct ifdr_pair *p = ifdr_table; 11678b3ea9cSJorge Ramirez-Ortiz struct ifdr_pair *q = p + ARRAY_SIZE(ifdr_table) - 1; 11778b3ea9cSJorge Ramirez-Ortiz uint32_t div = (I2C_CLK_RATE + bps - 1) / bps; 11878b3ea9cSJorge Ramirez-Ortiz 11978b3ea9cSJorge Ramirez-Ortiz if (div < p->divider) 12078b3ea9cSJorge Ramirez-Ortiz q = p; 12178b3ea9cSJorge Ramirez-Ortiz else if (div > q->divider) 12278b3ea9cSJorge Ramirez-Ortiz p = q; 12378b3ea9cSJorge Ramirez-Ortiz 12478b3ea9cSJorge Ramirez-Ortiz while (p != q) { 12578b3ea9cSJorge Ramirez-Ortiz if (div <= p->divider) 12678b3ea9cSJorge Ramirez-Ortiz break; 12778b3ea9cSJorge Ramirez-Ortiz p++; 12878b3ea9cSJorge Ramirez-Ortiz } 12978b3ea9cSJorge Ramirez-Ortiz 13078b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, IFDR, p->prescaler); 13178b3ea9cSJorge Ramirez-Ortiz } 13278b3ea9cSJorge Ramirez-Ortiz 13378b3ea9cSJorge Ramirez-Ortiz static void i2c_set_bus_speed(uint8_t bid, int bps) 13478b3ea9cSJorge Ramirez-Ortiz { 13578b3ea9cSJorge Ramirez-Ortiz /* Enable the clock */ 13678b3ea9cSJorge Ramirez-Ortiz io_write32(i2c_clk.base.va + CCM_CCGRx_SET(i2c_clk.i2c[bid]), 13778b3ea9cSJorge Ramirez-Ortiz CCM_CCGRx_ALWAYS_ON(0)); 13878b3ea9cSJorge Ramirez-Ortiz 13978b3ea9cSJorge Ramirez-Ortiz i2c_set_prescaler(bid, bps); 14078b3ea9cSJorge Ramirez-Ortiz } 14178b3ea9cSJorge Ramirez-Ortiz 14278b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_sync_bus(uint8_t bid, bool (*match)(uint32_t), 14378b3ea9cSJorge Ramirez-Ortiz uint32_t *status) 14478b3ea9cSJorge Ramirez-Ortiz { 14578b3ea9cSJorge Ramirez-Ortiz uint64_t tref = timeout_init_us(100000); 14678b3ea9cSJorge Ramirez-Ortiz uint32_t sr = 0; 14778b3ea9cSJorge Ramirez-Ortiz 14878b3ea9cSJorge Ramirez-Ortiz while (!timeout_elapsed(tref)) { 14978b3ea9cSJorge Ramirez-Ortiz sr = i2c_io_read8(bid, I2SR); 15078b3ea9cSJorge Ramirez-Ortiz if (sr & I2SR_IAL) { 15178b3ea9cSJorge Ramirez-Ortiz EMSG("bus arbitration lost"); 15278b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2SR, sr & ~I2SR_IAL); 15378b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_COMMUNICATION; 15478b3ea9cSJorge Ramirez-Ortiz } 15578b3ea9cSJorge Ramirez-Ortiz if ((*match)(sr)) { 15678b3ea9cSJorge Ramirez-Ortiz if (status) 15778b3ea9cSJorge Ramirez-Ortiz *status = sr; 15878b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 15978b3ea9cSJorge Ramirez-Ortiz } 16078b3ea9cSJorge Ramirez-Ortiz } 16178b3ea9cSJorge Ramirez-Ortiz 16278b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BUSY; 16378b3ea9cSJorge Ramirez-Ortiz } 16478b3ea9cSJorge Ramirez-Ortiz 16578b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_idle_bus(uint8_t bid) 16678b3ea9cSJorge Ramirez-Ortiz { 16778b3ea9cSJorge Ramirez-Ortiz uint8_t tmp = i2c_io_read8(bid, I2CR) & ~I2CR_MSTA; 16878b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 16978b3ea9cSJorge Ramirez-Ortiz 17078b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 17178b3ea9cSJorge Ramirez-Ortiz ret = i2c_sync_bus(bid, &bus_is_idle, NULL); 17278b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2SR, 0); 17378b3ea9cSJorge Ramirez-Ortiz 17478b3ea9cSJorge Ramirez-Ortiz return ret; 17578b3ea9cSJorge Ramirez-Ortiz } 17678b3ea9cSJorge Ramirez-Ortiz 17778b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_write_byte(uint8_t bid, uint8_t byte) 17878b3ea9cSJorge Ramirez-Ortiz { 17978b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 18078b3ea9cSJorge Ramirez-Ortiz uint32_t status = 0; 18178b3ea9cSJorge Ramirez-Ortiz 18278b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2DR, byte); 18378b3ea9cSJorge Ramirez-Ortiz ret = i2c_sync_bus(bid, &isr_active, &status); 18478b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2SR, 0); 18578b3ea9cSJorge Ramirez-Ortiz 186*14371509SJorge Ramirez-Ortiz if (!ret && (status & I2SR_RX_NO_AK)) 18778b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_STATE; 18878b3ea9cSJorge Ramirez-Ortiz 18978b3ea9cSJorge Ramirez-Ortiz return ret; 19078b3ea9cSJorge Ramirez-Ortiz } 19178b3ea9cSJorge Ramirez-Ortiz 19278b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_read_byte(uint8_t bid, uint8_t *p) 19378b3ea9cSJorge Ramirez-Ortiz { 19478b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 19578b3ea9cSJorge Ramirez-Ortiz 19678b3ea9cSJorge Ramirez-Ortiz *p = i2c_io_read8(bid, I2DR); 19778b3ea9cSJorge Ramirez-Ortiz ret = i2c_sync_bus(bid, &isr_active, NULL); 19878b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2SR, 0); 19978b3ea9cSJorge Ramirez-Ortiz 20078b3ea9cSJorge Ramirez-Ortiz return ret; 20178b3ea9cSJorge Ramirez-Ortiz } 20278b3ea9cSJorge Ramirez-Ortiz 20378b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_write_data(uint8_t bid, const uint8_t *buf, int len) 20478b3ea9cSJorge Ramirez-Ortiz { 20578b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 20678b3ea9cSJorge Ramirez-Ortiz uint32_t tmp = 0; 20778b3ea9cSJorge Ramirez-Ortiz 20878b3ea9cSJorge Ramirez-Ortiz if (!len) 20978b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 21078b3ea9cSJorge Ramirez-Ortiz 21178b3ea9cSJorge Ramirez-Ortiz tmp = i2c_io_read8(bid, I2CR) | I2CR_MTX | I2CR_TX_NO_AK; 21278b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 21378b3ea9cSJorge Ramirez-Ortiz 21478b3ea9cSJorge Ramirez-Ortiz while (len--) { 21578b3ea9cSJorge Ramirez-Ortiz ret = i2c_write_byte(bid, *buf++); 216*14371509SJorge Ramirez-Ortiz if (ret) 21778b3ea9cSJorge Ramirez-Ortiz return ret; 21878b3ea9cSJorge Ramirez-Ortiz } 21978b3ea9cSJorge Ramirez-Ortiz 22078b3ea9cSJorge Ramirez-Ortiz return ret; 22178b3ea9cSJorge Ramirez-Ortiz } 22278b3ea9cSJorge Ramirez-Ortiz 22378b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_read_data(uint8_t bid, uint8_t *buf, int len) 22478b3ea9cSJorge Ramirez-Ortiz { 22578b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 22678b3ea9cSJorge Ramirez-Ortiz uint8_t dummy = 0; 22778b3ea9cSJorge Ramirez-Ortiz uint32_t tmp = 0; 22878b3ea9cSJorge Ramirez-Ortiz 22978b3ea9cSJorge Ramirez-Ortiz if (!len) 23078b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 23178b3ea9cSJorge Ramirez-Ortiz 23278b3ea9cSJorge Ramirez-Ortiz tmp = i2c_io_read8(bid, I2CR) & ~I2CR_MTX; 23378b3ea9cSJorge Ramirez-Ortiz tmp = (len == 1) ? tmp | I2CR_TX_NO_AK : tmp & ~I2CR_TX_NO_AK; 23478b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 23578b3ea9cSJorge Ramirez-Ortiz i2c_io_read8(bid, I2DR); 23678b3ea9cSJorge Ramirez-Ortiz 23778b3ea9cSJorge Ramirez-Ortiz ret = i2c_read_byte(bid, &dummy); 238*14371509SJorge Ramirez-Ortiz if (ret) 23978b3ea9cSJorge Ramirez-Ortiz return ret; 24078b3ea9cSJorge Ramirez-Ortiz 24178b3ea9cSJorge Ramirez-Ortiz /* 24278b3ea9cSJorge Ramirez-Ortiz * A data transfer ends when the master signals a stop; for a master 24378b3ea9cSJorge Ramirez-Ortiz * receiver to terminate a transfer it must inform the slave transmiter 24478b3ea9cSJorge Ramirez-Ortiz * by not acknowledging the last data byte. This is done by setting the 24578b3ea9cSJorge Ramirez-Ortiz * transmit acknowledge bit before reading the next-to-last byte. 24678b3ea9cSJorge Ramirez-Ortiz */ 24778b3ea9cSJorge Ramirez-Ortiz do { 24878b3ea9cSJorge Ramirez-Ortiz if (len == 2) { 24978b3ea9cSJorge Ramirez-Ortiz tmp = i2c_io_read8(bid, I2CR) | I2CR_TX_NO_AK; 25078b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 25178b3ea9cSJorge Ramirez-Ortiz } 25278b3ea9cSJorge Ramirez-Ortiz 25378b3ea9cSJorge Ramirez-Ortiz ret = i2c_read_byte(bid, buf++); 254*14371509SJorge Ramirez-Ortiz if (ret) 25578b3ea9cSJorge Ramirez-Ortiz return ret; 25678b3ea9cSJorge Ramirez-Ortiz } while (len--); 25778b3ea9cSJorge Ramirez-Ortiz 25878b3ea9cSJorge Ramirez-Ortiz return ret; 25978b3ea9cSJorge Ramirez-Ortiz } 26078b3ea9cSJorge Ramirez-Ortiz 26178b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_init_transfer(uint8_t bid, uint8_t chip) 26278b3ea9cSJorge Ramirez-Ortiz { 26378b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 26478b3ea9cSJorge Ramirez-Ortiz uint32_t tmp = 0; 26578b3ea9cSJorge Ramirez-Ortiz 26678b3ea9cSJorge Ramirez-Ortiz ret = i2c_idle_bus(bid); 267*14371509SJorge Ramirez-Ortiz if (ret) 26878b3ea9cSJorge Ramirez-Ortiz return ret; 26978b3ea9cSJorge Ramirez-Ortiz 27078b3ea9cSJorge Ramirez-Ortiz /* Enable the interface */ 27178b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, I2CR_IEN); 27278b3ea9cSJorge Ramirez-Ortiz 27378b3ea9cSJorge Ramirez-Ortiz tmp = i2c_io_read8(bid, I2CR) | I2CR_MSTA; 27478b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 27578b3ea9cSJorge Ramirez-Ortiz 27678b3ea9cSJorge Ramirez-Ortiz /* Wait until the bus is active */ 27778b3ea9cSJorge Ramirez-Ortiz ret = i2c_sync_bus(bid, &bus_is_busy, NULL); 278*14371509SJorge Ramirez-Ortiz if (ret) 27978b3ea9cSJorge Ramirez-Ortiz return ret; 28078b3ea9cSJorge Ramirez-Ortiz 28178b3ea9cSJorge Ramirez-Ortiz /* Slave address on the bus */ 28278b3ea9cSJorge Ramirez-Ortiz return i2c_write_data(bid, &chip, 1); 28378b3ea9cSJorge Ramirez-Ortiz } 28478b3ea9cSJorge Ramirez-Ortiz 28578b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_read(uint8_t bid, uint8_t chip, uint8_t *buf, int len) 28678b3ea9cSJorge Ramirez-Ortiz { 28778b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 28878b3ea9cSJorge Ramirez-Ortiz 28978b3ea9cSJorge Ramirez-Ortiz if (bid >= ARRAY_SIZE(i2c_bus)) 29078b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 29178b3ea9cSJorge Ramirez-Ortiz 29278b3ea9cSJorge Ramirez-Ortiz if ((len && !buf) || chip > 0x7F) 29378b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 29478b3ea9cSJorge Ramirez-Ortiz 29578b3ea9cSJorge Ramirez-Ortiz ret = i2c_init_transfer(bid, chip << 1 | BIT(0)); 296*14371509SJorge Ramirez-Ortiz if (!ret) 29778b3ea9cSJorge Ramirez-Ortiz ret = i2c_read_data(bid, buf, len); 29878b3ea9cSJorge Ramirez-Ortiz 299*14371509SJorge Ramirez-Ortiz if (i2c_idle_bus(bid)) 30078b3ea9cSJorge Ramirez-Ortiz IMSG("bus not idle"); 30178b3ea9cSJorge Ramirez-Ortiz 30278b3ea9cSJorge Ramirez-Ortiz return ret; 30378b3ea9cSJorge Ramirez-Ortiz } 30478b3ea9cSJorge Ramirez-Ortiz 30578b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_write(uint8_t bid, uint8_t chip, const uint8_t *buf, int len) 30678b3ea9cSJorge Ramirez-Ortiz { 30778b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 30878b3ea9cSJorge Ramirez-Ortiz 30978b3ea9cSJorge Ramirez-Ortiz if (bid >= ARRAY_SIZE(i2c_bus)) 31078b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 31178b3ea9cSJorge Ramirez-Ortiz 31278b3ea9cSJorge Ramirez-Ortiz if ((len && !buf) || chip > 0x7F) 31378b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 31478b3ea9cSJorge Ramirez-Ortiz 31578b3ea9cSJorge Ramirez-Ortiz ret = i2c_init_transfer(bid, chip << 1); 316*14371509SJorge Ramirez-Ortiz if (!ret) 31778b3ea9cSJorge Ramirez-Ortiz ret = i2c_write_data(bid, buf, len); 31878b3ea9cSJorge Ramirez-Ortiz 319*14371509SJorge Ramirez-Ortiz if (i2c_idle_bus(bid)) 32078b3ea9cSJorge Ramirez-Ortiz IMSG("bus not idle"); 32178b3ea9cSJorge Ramirez-Ortiz 32278b3ea9cSJorge Ramirez-Ortiz return ret; 32378b3ea9cSJorge Ramirez-Ortiz } 32478b3ea9cSJorge Ramirez-Ortiz 32578b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_probe(uint8_t bid, uint8_t chip) 32678b3ea9cSJorge Ramirez-Ortiz { 32778b3ea9cSJorge Ramirez-Ortiz if (bid >= ARRAY_SIZE(i2c_bus)) 32878b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 32978b3ea9cSJorge Ramirez-Ortiz 33078b3ea9cSJorge Ramirez-Ortiz if (chip > 0x7F) 33178b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 33278b3ea9cSJorge Ramirez-Ortiz 33378b3ea9cSJorge Ramirez-Ortiz return imx_i2c_write(bid, chip, NULL, 0); 33478b3ea9cSJorge Ramirez-Ortiz } 33578b3ea9cSJorge Ramirez-Ortiz 33678b3ea9cSJorge Ramirez-Ortiz /* 33778b3ea9cSJorge Ramirez-Ortiz * I2C bus initialization: configure the IOMUX and enable the clock. 33878b3ea9cSJorge Ramirez-Ortiz * @bid: Bus ID: (0=I2C1), (1=I2C2), (2=I2C3). 33978b3ea9cSJorge Ramirez-Ortiz * @bps: Bus baud rate, in bits per second. 34078b3ea9cSJorge Ramirez-Ortiz */ 34178b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_init(uint8_t bid, int bps) 34278b3ea9cSJorge Ramirez-Ortiz { 34378b3ea9cSJorge Ramirez-Ortiz struct imx_i2c_mux *mux = &i2c_mux; 34478b3ea9cSJorge Ramirez-Ortiz 34578b3ea9cSJorge Ramirez-Ortiz if (bid >= ARRAY_SIZE(i2c_bus)) 34678b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 34778b3ea9cSJorge Ramirez-Ortiz 34878b3ea9cSJorge Ramirez-Ortiz if (!bps) 34978b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 35078b3ea9cSJorge Ramirez-Ortiz 35178b3ea9cSJorge Ramirez-Ortiz io_write32(mux->base.va + mux->i2c[bid].scl_mux, I2C_MUX_VAL(bid)); 35278b3ea9cSJorge Ramirez-Ortiz io_write32(mux->base.va + mux->i2c[bid].scl_cfg, I2C_CFG_VAL(bid)); 35378b3ea9cSJorge Ramirez-Ortiz io_write32(mux->base.va + mux->i2c[bid].sda_mux, I2C_MUX_VAL(bid)); 35478b3ea9cSJorge Ramirez-Ortiz io_write32(mux->base.va + mux->i2c[bid].sda_cfg, I2C_CFG_VAL(bid)); 35578b3ea9cSJorge Ramirez-Ortiz 35678b3ea9cSJorge Ramirez-Ortiz /* Baud rate in bits per second */ 35778b3ea9cSJorge Ramirez-Ortiz i2c_set_bus_speed(bid, bps); 35878b3ea9cSJorge Ramirez-Ortiz 35978b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 36078b3ea9cSJorge Ramirez-Ortiz } 36178b3ea9cSJorge Ramirez-Ortiz 36278b3ea9cSJorge Ramirez-Ortiz static TEE_Result get_va(paddr_t pa, vaddr_t *va) 36378b3ea9cSJorge Ramirez-Ortiz { 36478b3ea9cSJorge Ramirez-Ortiz if (!core_mmu_add_mapping(MEM_AREA_IO_SEC, pa, 0x10000)) 36578b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 36678b3ea9cSJorge Ramirez-Ortiz 36778b3ea9cSJorge Ramirez-Ortiz *va = (vaddr_t)phys_to_virt(pa, MEM_AREA_IO_SEC); 36878b3ea9cSJorge Ramirez-Ortiz if (*va) 36978b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 37078b3ea9cSJorge Ramirez-Ortiz 37178b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 37278b3ea9cSJorge Ramirez-Ortiz } 37378b3ea9cSJorge Ramirez-Ortiz 37478b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_init(void) 37578b3ea9cSJorge Ramirez-Ortiz { 37678b3ea9cSJorge Ramirez-Ortiz size_t n = 0; 37778b3ea9cSJorge Ramirez-Ortiz 378*14371509SJorge Ramirez-Ortiz if (get_va(i2c_clk.base.pa, &i2c_clk.base.va)) 37978b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 38078b3ea9cSJorge Ramirez-Ortiz 381*14371509SJorge Ramirez-Ortiz if (get_va(i2c_mux.base.pa, &i2c_mux.base.va)) 38278b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 38378b3ea9cSJorge Ramirez-Ortiz 38478b3ea9cSJorge Ramirez-Ortiz for (n = 0; n < ARRAY_SIZE(i2c_bus); n++) { 385*14371509SJorge Ramirez-Ortiz if (get_va(i2c_bus[n].pa, &i2c_bus[n].va)) 38678b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 38778b3ea9cSJorge Ramirez-Ortiz } 38878b3ea9cSJorge Ramirez-Ortiz 38978b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 39078b3ea9cSJorge Ramirez-Ortiz } 39178b3ea9cSJorge Ramirez-Ortiz 392db0683faSJorge Ramirez-Ortiz early_init(i2c_init); 393