11dd728f5SVitor Soares // SPDX-License-Identifier: GPL-2.0 21dd728f5SVitor Soares /* 31dd728f5SVitor Soares * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. 41dd728f5SVitor Soares * 51dd728f5SVitor Soares * Author: Vitor Soares <vitor.soares@synopsys.com> 61dd728f5SVitor Soares */ 71dd728f5SVitor Soares 81dd728f5SVitor Soares #include <linux/bitops.h> 91dd728f5SVitor Soares #include <linux/clk.h> 101dd728f5SVitor Soares #include <linux/completion.h> 111dd728f5SVitor Soares #include <linux/err.h> 121dd728f5SVitor Soares #include <linux/errno.h> 131dd728f5SVitor Soares #include <linux/i3c/master.h> 141dd728f5SVitor Soares #include <linux/interrupt.h> 151dd728f5SVitor Soares #include <linux/ioport.h> 161dd728f5SVitor Soares #include <linux/iopoll.h> 171dd728f5SVitor Soares #include <linux/list.h> 181dd728f5SVitor Soares #include <linux/module.h> 191dd728f5SVitor Soares #include <linux/of.h> 201dd728f5SVitor Soares #include <linux/platform_device.h> 211dd728f5SVitor Soares #include <linux/reset.h> 221dd728f5SVitor Soares #include <linux/slab.h> 231dd728f5SVitor Soares 241dd728f5SVitor Soares #define DEVICE_CTRL 0x0 251dd728f5SVitor Soares #define DEV_CTRL_ENABLE BIT(31) 261dd728f5SVitor Soares #define DEV_CTRL_RESUME BIT(30) 271dd728f5SVitor Soares #define DEV_CTRL_HOT_JOIN_NACK BIT(8) 281dd728f5SVitor Soares #define DEV_CTRL_I2C_SLAVE_PRESENT BIT(7) 291dd728f5SVitor Soares 301dd728f5SVitor Soares #define DEVICE_ADDR 0x4 311dd728f5SVitor Soares #define DEV_ADDR_DYNAMIC_ADDR_VALID BIT(31) 321dd728f5SVitor Soares #define DEV_ADDR_DYNAMIC(x) (((x) << 16) & GENMASK(22, 16)) 331dd728f5SVitor Soares 341dd728f5SVitor Soares #define HW_CAPABILITY 0x8 351dd728f5SVitor Soares #define COMMAND_QUEUE_PORT 0xc 361dd728f5SVitor Soares #define COMMAND_PORT_TOC BIT(30) 371dd728f5SVitor Soares #define COMMAND_PORT_READ_TRANSFER BIT(28) 381dd728f5SVitor Soares #define COMMAND_PORT_SDAP BIT(27) 391dd728f5SVitor Soares #define COMMAND_PORT_ROC BIT(26) 401dd728f5SVitor Soares #define COMMAND_PORT_SPEED(x) (((x) << 21) & GENMASK(23, 21)) 411dd728f5SVitor Soares #define COMMAND_PORT_DEV_INDEX(x) (((x) << 16) & GENMASK(20, 16)) 421dd728f5SVitor Soares #define COMMAND_PORT_CP BIT(15) 431dd728f5SVitor Soares #define COMMAND_PORT_CMD(x) (((x) << 7) & GENMASK(14, 7)) 441dd728f5SVitor Soares #define COMMAND_PORT_TID(x) (((x) << 3) & GENMASK(6, 3)) 451dd728f5SVitor Soares 461dd728f5SVitor Soares #define COMMAND_PORT_ARG_DATA_LEN(x) (((x) << 16) & GENMASK(31, 16)) 471dd728f5SVitor Soares #define COMMAND_PORT_ARG_DATA_LEN_MAX 65536 481dd728f5SVitor Soares #define COMMAND_PORT_TRANSFER_ARG 0x01 491dd728f5SVitor Soares 501dd728f5SVitor Soares #define COMMAND_PORT_SDA_DATA_BYTE_3(x) (((x) << 24) & GENMASK(31, 24)) 511dd728f5SVitor Soares #define COMMAND_PORT_SDA_DATA_BYTE_2(x) (((x) << 16) & GENMASK(23, 16)) 521dd728f5SVitor Soares #define COMMAND_PORT_SDA_DATA_BYTE_1(x) (((x) << 8) & GENMASK(15, 8)) 531dd728f5SVitor Soares #define COMMAND_PORT_SDA_BYTE_STRB_3 BIT(5) 541dd728f5SVitor Soares #define COMMAND_PORT_SDA_BYTE_STRB_2 BIT(4) 551dd728f5SVitor Soares #define COMMAND_PORT_SDA_BYTE_STRB_1 BIT(3) 561dd728f5SVitor Soares #define COMMAND_PORT_SHORT_DATA_ARG 0x02 571dd728f5SVitor Soares 581dd728f5SVitor Soares #define COMMAND_PORT_DEV_COUNT(x) (((x) << 21) & GENMASK(25, 21)) 591dd728f5SVitor Soares #define COMMAND_PORT_ADDR_ASSGN_CMD 0x03 601dd728f5SVitor Soares 611dd728f5SVitor Soares #define RESPONSE_QUEUE_PORT 0x10 621dd728f5SVitor Soares #define RESPONSE_PORT_ERR_STATUS(x) (((x) & GENMASK(31, 28)) >> 28) 631dd728f5SVitor Soares #define RESPONSE_NO_ERROR 0 641dd728f5SVitor Soares #define RESPONSE_ERROR_CRC 1 651dd728f5SVitor Soares #define RESPONSE_ERROR_PARITY 2 661dd728f5SVitor Soares #define RESPONSE_ERROR_FRAME 3 671dd728f5SVitor Soares #define RESPONSE_ERROR_IBA_NACK 4 681dd728f5SVitor Soares #define RESPONSE_ERROR_ADDRESS_NACK 5 691dd728f5SVitor Soares #define RESPONSE_ERROR_OVER_UNDER_FLOW 6 701dd728f5SVitor Soares #define RESPONSE_ERROR_TRANSF_ABORT 8 711dd728f5SVitor Soares #define RESPONSE_ERROR_I2C_W_NACK_ERR 9 721dd728f5SVitor Soares #define RESPONSE_PORT_TID(x) (((x) & GENMASK(27, 24)) >> 24) 731dd728f5SVitor Soares #define RESPONSE_PORT_DATA_LEN(x) ((x) & GENMASK(15, 0)) 741dd728f5SVitor Soares 751dd728f5SVitor Soares #define RX_TX_DATA_PORT 0x14 761dd728f5SVitor Soares #define IBI_QUEUE_STATUS 0x18 771dd728f5SVitor Soares #define QUEUE_THLD_CTRL 0x1c 781dd728f5SVitor Soares #define QUEUE_THLD_CTRL_RESP_BUF_MASK GENMASK(15, 8) 791dd728f5SVitor Soares #define QUEUE_THLD_CTRL_RESP_BUF(x) (((x) - 1) << 8) 801dd728f5SVitor Soares 811dd728f5SVitor Soares #define DATA_BUFFER_THLD_CTRL 0x20 821dd728f5SVitor Soares #define DATA_BUFFER_THLD_CTRL_RX_BUF GENMASK(11, 8) 831dd728f5SVitor Soares 841dd728f5SVitor Soares #define IBI_QUEUE_CTRL 0x24 851dd728f5SVitor Soares #define IBI_MR_REQ_REJECT 0x2C 861dd728f5SVitor Soares #define IBI_SIR_REQ_REJECT 0x30 871dd728f5SVitor Soares #define IBI_REQ_REJECT_ALL GENMASK(31, 0) 881dd728f5SVitor Soares 891dd728f5SVitor Soares #define RESET_CTRL 0x34 901dd728f5SVitor Soares #define RESET_CTRL_IBI_QUEUE BIT(5) 911dd728f5SVitor Soares #define RESET_CTRL_RX_FIFO BIT(4) 921dd728f5SVitor Soares #define RESET_CTRL_TX_FIFO BIT(3) 931dd728f5SVitor Soares #define RESET_CTRL_RESP_QUEUE BIT(2) 941dd728f5SVitor Soares #define RESET_CTRL_CMD_QUEUE BIT(1) 951dd728f5SVitor Soares #define RESET_CTRL_SOFT BIT(0) 961dd728f5SVitor Soares 971dd728f5SVitor Soares #define SLV_EVENT_CTRL 0x38 981dd728f5SVitor Soares #define INTR_STATUS 0x3c 991dd728f5SVitor Soares #define INTR_STATUS_EN 0x40 1001dd728f5SVitor Soares #define INTR_SIGNAL_EN 0x44 1011dd728f5SVitor Soares #define INTR_FORCE 0x48 1021dd728f5SVitor Soares #define INTR_BUSOWNER_UPDATE_STAT BIT(13) 1031dd728f5SVitor Soares #define INTR_IBI_UPDATED_STAT BIT(12) 1041dd728f5SVitor Soares #define INTR_READ_REQ_RECV_STAT BIT(11) 1051dd728f5SVitor Soares #define INTR_DEFSLV_STAT BIT(10) 1061dd728f5SVitor Soares #define INTR_TRANSFER_ERR_STAT BIT(9) 1071dd728f5SVitor Soares #define INTR_DYN_ADDR_ASSGN_STAT BIT(8) 1081dd728f5SVitor Soares #define INTR_CCC_UPDATED_STAT BIT(6) 1091dd728f5SVitor Soares #define INTR_TRANSFER_ABORT_STAT BIT(5) 1101dd728f5SVitor Soares #define INTR_RESP_READY_STAT BIT(4) 1111dd728f5SVitor Soares #define INTR_CMD_QUEUE_READY_STAT BIT(3) 1121dd728f5SVitor Soares #define INTR_IBI_THLD_STAT BIT(2) 1131dd728f5SVitor Soares #define INTR_RX_THLD_STAT BIT(1) 1141dd728f5SVitor Soares #define INTR_TX_THLD_STAT BIT(0) 1151dd728f5SVitor Soares #define INTR_ALL (INTR_BUSOWNER_UPDATE_STAT | \ 1161dd728f5SVitor Soares INTR_IBI_UPDATED_STAT | \ 1171dd728f5SVitor Soares INTR_READ_REQ_RECV_STAT | \ 1181dd728f5SVitor Soares INTR_DEFSLV_STAT | \ 1191dd728f5SVitor Soares INTR_TRANSFER_ERR_STAT | \ 1201dd728f5SVitor Soares INTR_DYN_ADDR_ASSGN_STAT | \ 1211dd728f5SVitor Soares INTR_CCC_UPDATED_STAT | \ 1221dd728f5SVitor Soares INTR_TRANSFER_ABORT_STAT | \ 1231dd728f5SVitor Soares INTR_RESP_READY_STAT | \ 1241dd728f5SVitor Soares INTR_CMD_QUEUE_READY_STAT | \ 1251dd728f5SVitor Soares INTR_IBI_THLD_STAT | \ 1261dd728f5SVitor Soares INTR_TX_THLD_STAT | \ 1271dd728f5SVitor Soares INTR_RX_THLD_STAT) 1281dd728f5SVitor Soares 1291dd728f5SVitor Soares #define INTR_MASTER_MASK (INTR_TRANSFER_ERR_STAT | \ 1301dd728f5SVitor Soares INTR_RESP_READY_STAT) 1311dd728f5SVitor Soares 1321dd728f5SVitor Soares #define QUEUE_STATUS_LEVEL 0x4c 1331dd728f5SVitor Soares #define QUEUE_STATUS_IBI_STATUS_CNT(x) (((x) & GENMASK(28, 24)) >> 24) 1341dd728f5SVitor Soares #define QUEUE_STATUS_IBI_BUF_BLR(x) (((x) & GENMASK(23, 16)) >> 16) 1351dd728f5SVitor Soares #define QUEUE_STATUS_LEVEL_RESP(x) (((x) & GENMASK(15, 8)) >> 8) 1361dd728f5SVitor Soares #define QUEUE_STATUS_LEVEL_CMD(x) ((x) & GENMASK(7, 0)) 1371dd728f5SVitor Soares 1381dd728f5SVitor Soares #define DATA_BUFFER_STATUS_LEVEL 0x50 1391dd728f5SVitor Soares #define DATA_BUFFER_STATUS_LEVEL_TX(x) ((x) & GENMASK(7, 0)) 1401dd728f5SVitor Soares 1411dd728f5SVitor Soares #define PRESENT_STATE 0x54 1421dd728f5SVitor Soares #define CCC_DEVICE_STATUS 0x58 1431dd728f5SVitor Soares #define DEVICE_ADDR_TABLE_POINTER 0x5c 1441dd728f5SVitor Soares #define DEVICE_ADDR_TABLE_DEPTH(x) (((x) & GENMASK(31, 16)) >> 16) 1451dd728f5SVitor Soares #define DEVICE_ADDR_TABLE_ADDR(x) ((x) & GENMASK(7, 0)) 1461dd728f5SVitor Soares 1471dd728f5SVitor Soares #define DEV_CHAR_TABLE_POINTER 0x60 1481dd728f5SVitor Soares #define VENDOR_SPECIFIC_REG_POINTER 0x6c 1491dd728f5SVitor Soares #define SLV_PID_VALUE 0x74 1501dd728f5SVitor Soares #define SLV_CHAR_CTRL 0x78 1511dd728f5SVitor Soares #define SLV_MAX_LEN 0x7c 1521dd728f5SVitor Soares #define MAX_READ_TURNAROUND 0x80 1531dd728f5SVitor Soares #define MAX_DATA_SPEED 0x84 1541dd728f5SVitor Soares #define SLV_DEBUG_STATUS 0x88 1551dd728f5SVitor Soares #define SLV_INTR_REQ 0x8c 1561dd728f5SVitor Soares #define DEVICE_CTRL_EXTENDED 0xb0 1571dd728f5SVitor Soares #define SCL_I3C_OD_TIMING 0xb4 1581dd728f5SVitor Soares #define SCL_I3C_PP_TIMING 0xb8 1591dd728f5SVitor Soares #define SCL_I3C_TIMING_HCNT(x) (((x) << 16) & GENMASK(23, 16)) 1601dd728f5SVitor Soares #define SCL_I3C_TIMING_LCNT(x) ((x) & GENMASK(7, 0)) 1611dd728f5SVitor Soares #define SCL_I3C_TIMING_CNT_MIN 5 1621dd728f5SVitor Soares 1631dd728f5SVitor Soares #define SCL_I2C_FM_TIMING 0xbc 1641dd728f5SVitor Soares #define SCL_I2C_FM_TIMING_HCNT(x) (((x) << 16) & GENMASK(31, 16)) 1651dd728f5SVitor Soares #define SCL_I2C_FM_TIMING_LCNT(x) ((x) & GENMASK(15, 0)) 1661dd728f5SVitor Soares 1671dd728f5SVitor Soares #define SCL_I2C_FMP_TIMING 0xc0 1681dd728f5SVitor Soares #define SCL_I2C_FMP_TIMING_HCNT(x) (((x) << 16) & GENMASK(23, 16)) 1691dd728f5SVitor Soares #define SCL_I2C_FMP_TIMING_LCNT(x) ((x) & GENMASK(15, 0)) 1701dd728f5SVitor Soares 1711dd728f5SVitor Soares #define SCL_EXT_LCNT_TIMING 0xc8 1721dd728f5SVitor Soares #define SCL_EXT_LCNT_4(x) (((x) << 24) & GENMASK(31, 24)) 1731dd728f5SVitor Soares #define SCL_EXT_LCNT_3(x) (((x) << 16) & GENMASK(23, 16)) 1741dd728f5SVitor Soares #define SCL_EXT_LCNT_2(x) (((x) << 8) & GENMASK(15, 8)) 1751dd728f5SVitor Soares #define SCL_EXT_LCNT_1(x) ((x) & GENMASK(7, 0)) 1761dd728f5SVitor Soares 1771dd728f5SVitor Soares #define SCL_EXT_TERMN_LCNT_TIMING 0xcc 1781dd728f5SVitor Soares #define BUS_FREE_TIMING 0xd4 1791dd728f5SVitor Soares #define BUS_I3C_MST_FREE(x) ((x) & GENMASK(15, 0)) 1801dd728f5SVitor Soares 1811dd728f5SVitor Soares #define BUS_IDLE_TIMING 0xd8 1821dd728f5SVitor Soares #define I3C_VER_ID 0xe0 1831dd728f5SVitor Soares #define I3C_VER_TYPE 0xe4 1841dd728f5SVitor Soares #define EXTENDED_CAPABILITY 0xe8 1851dd728f5SVitor Soares #define SLAVE_CONFIG 0xec 1861dd728f5SVitor Soares 1871dd728f5SVitor Soares #define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31) 1881dd728f5SVitor Soares #define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) (((x) << 16) & GENMASK(23, 16)) 1891dd728f5SVitor Soares #define DEV_ADDR_TABLE_STATIC_ADDR(x) ((x) & GENMASK(6, 0)) 1901dd728f5SVitor Soares #define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2)) 1911dd728f5SVitor Soares 1921dd728f5SVitor Soares #define MAX_DEVS 32 1931dd728f5SVitor Soares 1941dd728f5SVitor Soares #define I3C_BUS_SDR1_SCL_RATE 8000000 1951dd728f5SVitor Soares #define I3C_BUS_SDR2_SCL_RATE 6000000 1961dd728f5SVitor Soares #define I3C_BUS_SDR3_SCL_RATE 4000000 1971dd728f5SVitor Soares #define I3C_BUS_SDR4_SCL_RATE 2000000 1981dd728f5SVitor Soares #define I3C_BUS_I2C_FM_TLOW_MIN_NS 1300 1991dd728f5SVitor Soares #define I3C_BUS_I2C_FMP_TLOW_MIN_NS 500 2001dd728f5SVitor Soares #define I3C_BUS_THIGH_MAX_NS 41 2011dd728f5SVitor Soares 2021dd728f5SVitor Soares #define XFER_TIMEOUT (msecs_to_jiffies(1000)) 2031dd728f5SVitor Soares 2041dd728f5SVitor Soares struct dw_i3c_master_caps { 2051dd728f5SVitor Soares u8 cmdfifodepth; 2061dd728f5SVitor Soares u8 datafifodepth; 2071dd728f5SVitor Soares }; 2081dd728f5SVitor Soares 2091dd728f5SVitor Soares struct dw_i3c_cmd { 2101dd728f5SVitor Soares u32 cmd_lo; 2111dd728f5SVitor Soares u32 cmd_hi; 2121dd728f5SVitor Soares u16 tx_len; 2131dd728f5SVitor Soares const void *tx_buf; 2141dd728f5SVitor Soares u16 rx_len; 2151dd728f5SVitor Soares void *rx_buf; 2161dd728f5SVitor Soares u8 error; 2171dd728f5SVitor Soares }; 2181dd728f5SVitor Soares 2191dd728f5SVitor Soares struct dw_i3c_xfer { 2201dd728f5SVitor Soares struct list_head node; 2211dd728f5SVitor Soares struct completion comp; 2221dd728f5SVitor Soares int ret; 2231dd728f5SVitor Soares unsigned int ncmds; 224cd851485SGustavo A. R. Silva struct dw_i3c_cmd cmds[]; 2251dd728f5SVitor Soares }; 2261dd728f5SVitor Soares 2271dd728f5SVitor Soares struct dw_i3c_master { 2281dd728f5SVitor Soares struct i3c_master_controller base; 2291dd728f5SVitor Soares u16 maxdevs; 2301dd728f5SVitor Soares u16 datstartaddr; 2311dd728f5SVitor Soares u32 free_pos; 2321dd728f5SVitor Soares struct { 2331dd728f5SVitor Soares struct list_head list; 2341dd728f5SVitor Soares struct dw_i3c_xfer *cur; 2351dd728f5SVitor Soares spinlock_t lock; 2361dd728f5SVitor Soares } xferqueue; 2371dd728f5SVitor Soares struct dw_i3c_master_caps caps; 2381dd728f5SVitor Soares void __iomem *regs; 2391dd728f5SVitor Soares struct reset_control *core_rst; 2401dd728f5SVitor Soares struct clk *core_clk; 2411dd728f5SVitor Soares char version[5]; 2421dd728f5SVitor Soares char type[5]; 2431dd728f5SVitor Soares u8 addrs[MAX_DEVS]; 2441dd728f5SVitor Soares }; 2451dd728f5SVitor Soares 2461dd728f5SVitor Soares struct dw_i3c_i2c_dev_data { 2471dd728f5SVitor Soares u8 index; 2481dd728f5SVitor Soares }; 2491dd728f5SVitor Soares 2501dd728f5SVitor Soares static u8 even_parity(u8 p) 2511dd728f5SVitor Soares { 2521dd728f5SVitor Soares p ^= p >> 4; 2531dd728f5SVitor Soares p &= 0xf; 2541dd728f5SVitor Soares 2551dd728f5SVitor Soares return (0x9669 >> p) & 1; 2561dd728f5SVitor Soares } 2571dd728f5SVitor Soares 2581dd728f5SVitor Soares static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m, 2591dd728f5SVitor Soares const struct i3c_ccc_cmd *cmd) 2601dd728f5SVitor Soares { 2611dd728f5SVitor Soares if (cmd->ndests > 1) 2621dd728f5SVitor Soares return false; 2631dd728f5SVitor Soares 2641dd728f5SVitor Soares switch (cmd->id) { 2651dd728f5SVitor Soares case I3C_CCC_ENEC(true): 2661dd728f5SVitor Soares case I3C_CCC_ENEC(false): 2671dd728f5SVitor Soares case I3C_CCC_DISEC(true): 2681dd728f5SVitor Soares case I3C_CCC_DISEC(false): 2691dd728f5SVitor Soares case I3C_CCC_ENTAS(0, true): 2701dd728f5SVitor Soares case I3C_CCC_ENTAS(0, false): 2711dd728f5SVitor Soares case I3C_CCC_RSTDAA(true): 2721dd728f5SVitor Soares case I3C_CCC_RSTDAA(false): 2731dd728f5SVitor Soares case I3C_CCC_ENTDAA: 2741dd728f5SVitor Soares case I3C_CCC_SETMWL(true): 2751dd728f5SVitor Soares case I3C_CCC_SETMWL(false): 2761dd728f5SVitor Soares case I3C_CCC_SETMRL(true): 2771dd728f5SVitor Soares case I3C_CCC_SETMRL(false): 2781dd728f5SVitor Soares case I3C_CCC_ENTHDR(0): 2791dd728f5SVitor Soares case I3C_CCC_SETDASA: 2801dd728f5SVitor Soares case I3C_CCC_SETNEWDA: 2811dd728f5SVitor Soares case I3C_CCC_GETMWL: 2821dd728f5SVitor Soares case I3C_CCC_GETMRL: 2831dd728f5SVitor Soares case I3C_CCC_GETPID: 2841dd728f5SVitor Soares case I3C_CCC_GETBCR: 2851dd728f5SVitor Soares case I3C_CCC_GETDCR: 2861dd728f5SVitor Soares case I3C_CCC_GETSTATUS: 2871dd728f5SVitor Soares case I3C_CCC_GETMXDS: 2881dd728f5SVitor Soares case I3C_CCC_GETHDRCAP: 2891dd728f5SVitor Soares return true; 2901dd728f5SVitor Soares default: 2911dd728f5SVitor Soares return false; 2921dd728f5SVitor Soares } 2931dd728f5SVitor Soares } 2941dd728f5SVitor Soares 2951dd728f5SVitor Soares static inline struct dw_i3c_master * 2961dd728f5SVitor Soares to_dw_i3c_master(struct i3c_master_controller *master) 2971dd728f5SVitor Soares { 2981dd728f5SVitor Soares return container_of(master, struct dw_i3c_master, base); 2991dd728f5SVitor Soares } 3001dd728f5SVitor Soares 3011dd728f5SVitor Soares static void dw_i3c_master_disable(struct dw_i3c_master *master) 3021dd728f5SVitor Soares { 303907621e9SVitor Soares writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_ENABLE, 3041dd728f5SVitor Soares master->regs + DEVICE_CTRL); 3051dd728f5SVitor Soares } 3061dd728f5SVitor Soares 3071dd728f5SVitor Soares static void dw_i3c_master_enable(struct dw_i3c_master *master) 3081dd728f5SVitor Soares { 3091dd728f5SVitor Soares writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_ENABLE, 3101dd728f5SVitor Soares master->regs + DEVICE_CTRL); 3111dd728f5SVitor Soares } 3121dd728f5SVitor Soares 3131dd728f5SVitor Soares static int dw_i3c_master_get_addr_pos(struct dw_i3c_master *master, u8 addr) 3141dd728f5SVitor Soares { 3151dd728f5SVitor Soares int pos; 3161dd728f5SVitor Soares 3171dd728f5SVitor Soares for (pos = 0; pos < master->maxdevs; pos++) { 3181dd728f5SVitor Soares if (addr == master->addrs[pos]) 3191dd728f5SVitor Soares return pos; 3201dd728f5SVitor Soares } 3211dd728f5SVitor Soares 3221dd728f5SVitor Soares return -EINVAL; 3231dd728f5SVitor Soares } 3241dd728f5SVitor Soares 3251dd728f5SVitor Soares static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master) 3261dd728f5SVitor Soares { 3271dd728f5SVitor Soares if (!(master->free_pos & GENMASK(master->maxdevs - 1, 0))) 3281dd728f5SVitor Soares return -ENOSPC; 3291dd728f5SVitor Soares 3301dd728f5SVitor Soares return ffs(master->free_pos) - 1; 3311dd728f5SVitor Soares } 3321dd728f5SVitor Soares 3331dd728f5SVitor Soares static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master, 3341dd728f5SVitor Soares const u8 *bytes, int nbytes) 3351dd728f5SVitor Soares { 3361dd728f5SVitor Soares writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4); 3371dd728f5SVitor Soares if (nbytes & 3) { 3381dd728f5SVitor Soares u32 tmp = 0; 3391dd728f5SVitor Soares 3401dd728f5SVitor Soares memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3); 3411dd728f5SVitor Soares writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1); 3421dd728f5SVitor Soares } 3431dd728f5SVitor Soares } 3441dd728f5SVitor Soares 3451dd728f5SVitor Soares static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master, 3461dd728f5SVitor Soares u8 *bytes, int nbytes) 3471dd728f5SVitor Soares { 3481dd728f5SVitor Soares readsl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4); 3491dd728f5SVitor Soares if (nbytes & 3) { 3501dd728f5SVitor Soares u32 tmp; 3511dd728f5SVitor Soares 3521dd728f5SVitor Soares readsl(master->regs + RX_TX_DATA_PORT, &tmp, 1); 3531dd728f5SVitor Soares memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3); 3541dd728f5SVitor Soares } 3551dd728f5SVitor Soares } 3561dd728f5SVitor Soares 3571dd728f5SVitor Soares static struct dw_i3c_xfer * 3581dd728f5SVitor Soares dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds) 3591dd728f5SVitor Soares { 3601dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 3611dd728f5SVitor Soares 3621dd728f5SVitor Soares xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL); 3631dd728f5SVitor Soares if (!xfer) 3641dd728f5SVitor Soares return NULL; 3651dd728f5SVitor Soares 3661dd728f5SVitor Soares INIT_LIST_HEAD(&xfer->node); 3671dd728f5SVitor Soares xfer->ncmds = ncmds; 3681dd728f5SVitor Soares xfer->ret = -ETIMEDOUT; 3691dd728f5SVitor Soares 3701dd728f5SVitor Soares return xfer; 3711dd728f5SVitor Soares } 3721dd728f5SVitor Soares 3731dd728f5SVitor Soares static void dw_i3c_master_free_xfer(struct dw_i3c_xfer *xfer) 3741dd728f5SVitor Soares { 3751dd728f5SVitor Soares kfree(xfer); 3761dd728f5SVitor Soares } 3771dd728f5SVitor Soares 3781dd728f5SVitor Soares static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master) 3791dd728f5SVitor Soares { 3801dd728f5SVitor Soares struct dw_i3c_xfer *xfer = master->xferqueue.cur; 3811dd728f5SVitor Soares unsigned int i; 3821dd728f5SVitor Soares u32 thld_ctrl; 3831dd728f5SVitor Soares 3841dd728f5SVitor Soares if (!xfer) 3851dd728f5SVitor Soares return; 3861dd728f5SVitor Soares 3871dd728f5SVitor Soares for (i = 0; i < xfer->ncmds; i++) { 3881dd728f5SVitor Soares struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 3891dd728f5SVitor Soares 3901dd728f5SVitor Soares dw_i3c_master_wr_tx_fifo(master, cmd->tx_buf, cmd->tx_len); 3911dd728f5SVitor Soares } 3921dd728f5SVitor Soares 3931dd728f5SVitor Soares thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL); 3941dd728f5SVitor Soares thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK; 3951dd728f5SVitor Soares thld_ctrl |= QUEUE_THLD_CTRL_RESP_BUF(xfer->ncmds); 3961dd728f5SVitor Soares writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL); 3971dd728f5SVitor Soares 3981dd728f5SVitor Soares for (i = 0; i < xfer->ncmds; i++) { 3991dd728f5SVitor Soares struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 4001dd728f5SVitor Soares 4011dd728f5SVitor Soares writel(cmd->cmd_hi, master->regs + COMMAND_QUEUE_PORT); 4021dd728f5SVitor Soares writel(cmd->cmd_lo, master->regs + COMMAND_QUEUE_PORT); 4031dd728f5SVitor Soares } 4041dd728f5SVitor Soares } 4051dd728f5SVitor Soares 4061dd728f5SVitor Soares static void dw_i3c_master_enqueue_xfer(struct dw_i3c_master *master, 4071dd728f5SVitor Soares struct dw_i3c_xfer *xfer) 4081dd728f5SVitor Soares { 4091dd728f5SVitor Soares unsigned long flags; 4101dd728f5SVitor Soares 4111dd728f5SVitor Soares init_completion(&xfer->comp); 4121dd728f5SVitor Soares spin_lock_irqsave(&master->xferqueue.lock, flags); 4131dd728f5SVitor Soares if (master->xferqueue.cur) { 4141dd728f5SVitor Soares list_add_tail(&xfer->node, &master->xferqueue.list); 4151dd728f5SVitor Soares } else { 4161dd728f5SVitor Soares master->xferqueue.cur = xfer; 4171dd728f5SVitor Soares dw_i3c_master_start_xfer_locked(master); 4181dd728f5SVitor Soares } 4191dd728f5SVitor Soares spin_unlock_irqrestore(&master->xferqueue.lock, flags); 4201dd728f5SVitor Soares } 4211dd728f5SVitor Soares 422f36c1f9aSJisheng Zhang static void dw_i3c_master_dequeue_xfer_locked(struct dw_i3c_master *master, 4231dd728f5SVitor Soares struct dw_i3c_xfer *xfer) 4241dd728f5SVitor Soares { 4251dd728f5SVitor Soares if (master->xferqueue.cur == xfer) { 4261dd728f5SVitor Soares u32 status; 4271dd728f5SVitor Soares 4281dd728f5SVitor Soares master->xferqueue.cur = NULL; 4291dd728f5SVitor Soares 4301dd728f5SVitor Soares writel(RESET_CTRL_RX_FIFO | RESET_CTRL_TX_FIFO | 4311dd728f5SVitor Soares RESET_CTRL_RESP_QUEUE | RESET_CTRL_CMD_QUEUE, 4321dd728f5SVitor Soares master->regs + RESET_CTRL); 4331dd728f5SVitor Soares 4341dd728f5SVitor Soares readl_poll_timeout_atomic(master->regs + RESET_CTRL, status, 4351dd728f5SVitor Soares !status, 10, 1000000); 4361dd728f5SVitor Soares } else { 4371dd728f5SVitor Soares list_del_init(&xfer->node); 4381dd728f5SVitor Soares } 439f36c1f9aSJisheng Zhang } 440f36c1f9aSJisheng Zhang 441f36c1f9aSJisheng Zhang static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, 442f36c1f9aSJisheng Zhang struct dw_i3c_xfer *xfer) 443f36c1f9aSJisheng Zhang { 444f36c1f9aSJisheng Zhang unsigned long flags; 445f36c1f9aSJisheng Zhang 446f36c1f9aSJisheng Zhang spin_lock_irqsave(&master->xferqueue.lock, flags); 447f36c1f9aSJisheng Zhang dw_i3c_master_dequeue_xfer_locked(master, xfer); 4481dd728f5SVitor Soares spin_unlock_irqrestore(&master->xferqueue.lock, flags); 4491dd728f5SVitor Soares } 4501dd728f5SVitor Soares 4511dd728f5SVitor Soares static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr) 4521dd728f5SVitor Soares { 4531dd728f5SVitor Soares struct dw_i3c_xfer *xfer = master->xferqueue.cur; 4541dd728f5SVitor Soares int i, ret = 0; 4551dd728f5SVitor Soares u32 nresp; 4561dd728f5SVitor Soares 4571dd728f5SVitor Soares if (!xfer) 4581dd728f5SVitor Soares return; 4591dd728f5SVitor Soares 4601dd728f5SVitor Soares nresp = readl(master->regs + QUEUE_STATUS_LEVEL); 4611dd728f5SVitor Soares nresp = QUEUE_STATUS_LEVEL_RESP(nresp); 4621dd728f5SVitor Soares 4631dd728f5SVitor Soares for (i = 0; i < nresp; i++) { 4641dd728f5SVitor Soares struct dw_i3c_cmd *cmd; 4651dd728f5SVitor Soares u32 resp; 4661dd728f5SVitor Soares 4671dd728f5SVitor Soares resp = readl(master->regs + RESPONSE_QUEUE_PORT); 4681dd728f5SVitor Soares 4691dd728f5SVitor Soares cmd = &xfer->cmds[RESPONSE_PORT_TID(resp)]; 4701dd728f5SVitor Soares cmd->rx_len = RESPONSE_PORT_DATA_LEN(resp); 4711dd728f5SVitor Soares cmd->error = RESPONSE_PORT_ERR_STATUS(resp); 4721dd728f5SVitor Soares if (cmd->rx_len && !cmd->error) 4731dd728f5SVitor Soares dw_i3c_master_read_rx_fifo(master, cmd->rx_buf, 4741dd728f5SVitor Soares cmd->rx_len); 4751dd728f5SVitor Soares } 4761dd728f5SVitor Soares 4771dd728f5SVitor Soares for (i = 0; i < nresp; i++) { 4781dd728f5SVitor Soares switch (xfer->cmds[i].error) { 4791dd728f5SVitor Soares case RESPONSE_NO_ERROR: 4801dd728f5SVitor Soares break; 4811dd728f5SVitor Soares case RESPONSE_ERROR_PARITY: 4821dd728f5SVitor Soares case RESPONSE_ERROR_IBA_NACK: 4831dd728f5SVitor Soares case RESPONSE_ERROR_TRANSF_ABORT: 4841dd728f5SVitor Soares case RESPONSE_ERROR_CRC: 4851dd728f5SVitor Soares case RESPONSE_ERROR_FRAME: 4861dd728f5SVitor Soares ret = -EIO; 4871dd728f5SVitor Soares break; 4881dd728f5SVitor Soares case RESPONSE_ERROR_OVER_UNDER_FLOW: 4891dd728f5SVitor Soares ret = -ENOSPC; 4901dd728f5SVitor Soares break; 4911dd728f5SVitor Soares case RESPONSE_ERROR_I2C_W_NACK_ERR: 4921dd728f5SVitor Soares case RESPONSE_ERROR_ADDRESS_NACK: 4931dd728f5SVitor Soares default: 4941dd728f5SVitor Soares ret = -EINVAL; 4951dd728f5SVitor Soares break; 4961dd728f5SVitor Soares } 4971dd728f5SVitor Soares } 4981dd728f5SVitor Soares 4991dd728f5SVitor Soares xfer->ret = ret; 5001dd728f5SVitor Soares complete(&xfer->comp); 5011dd728f5SVitor Soares 5021dd728f5SVitor Soares if (ret < 0) { 503f36c1f9aSJisheng Zhang dw_i3c_master_dequeue_xfer_locked(master, xfer); 5041dd728f5SVitor Soares writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME, 5051dd728f5SVitor Soares master->regs + DEVICE_CTRL); 5061dd728f5SVitor Soares } 5071dd728f5SVitor Soares 5081dd728f5SVitor Soares xfer = list_first_entry_or_null(&master->xferqueue.list, 5091dd728f5SVitor Soares struct dw_i3c_xfer, 5101dd728f5SVitor Soares node); 5111dd728f5SVitor Soares if (xfer) 5121dd728f5SVitor Soares list_del_init(&xfer->node); 5131dd728f5SVitor Soares 5141dd728f5SVitor Soares master->xferqueue.cur = xfer; 5151dd728f5SVitor Soares dw_i3c_master_start_xfer_locked(master); 5161dd728f5SVitor Soares } 5171dd728f5SVitor Soares 5181dd728f5SVitor Soares static int dw_i3c_clk_cfg(struct dw_i3c_master *master) 5191dd728f5SVitor Soares { 5201dd728f5SVitor Soares unsigned long core_rate, core_period; 5211dd728f5SVitor Soares u32 scl_timing; 5221dd728f5SVitor Soares u8 hcnt, lcnt; 5231dd728f5SVitor Soares 5241dd728f5SVitor Soares core_rate = clk_get_rate(master->core_clk); 5251dd728f5SVitor Soares if (!core_rate) 5261dd728f5SVitor Soares return -EINVAL; 5271dd728f5SVitor Soares 5281dd728f5SVitor Soares core_period = DIV_ROUND_UP(1000000000, core_rate); 5291dd728f5SVitor Soares 5301dd728f5SVitor Soares hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period) - 1; 5311dd728f5SVitor Soares if (hcnt < SCL_I3C_TIMING_CNT_MIN) 5321dd728f5SVitor Soares hcnt = SCL_I3C_TIMING_CNT_MIN; 5331dd728f5SVitor Soares 534510d2358SJack Chen lcnt = DIV_ROUND_UP(core_rate, master->base.bus.scl_rate.i3c) - hcnt; 5351dd728f5SVitor Soares if (lcnt < SCL_I3C_TIMING_CNT_MIN) 5361dd728f5SVitor Soares lcnt = SCL_I3C_TIMING_CNT_MIN; 5371dd728f5SVitor Soares 5381dd728f5SVitor Soares scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt); 5391dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_I3C_PP_TIMING); 5401dd728f5SVitor Soares 5411dd728f5SVitor Soares if (!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_I2C_SLAVE_PRESENT)) 5421dd728f5SVitor Soares writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING); 5431dd728f5SVitor Soares 544510d2358SJack Chen lcnt = max_t(u8, 545510d2358SJack Chen DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period), lcnt); 5461dd728f5SVitor Soares scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt); 5471dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_I3C_OD_TIMING); 5481dd728f5SVitor Soares 5491dd728f5SVitor Soares lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt; 5501dd728f5SVitor Soares scl_timing = SCL_EXT_LCNT_1(lcnt); 5511dd728f5SVitor Soares lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt; 5521dd728f5SVitor Soares scl_timing |= SCL_EXT_LCNT_2(lcnt); 5531dd728f5SVitor Soares lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt; 5541dd728f5SVitor Soares scl_timing |= SCL_EXT_LCNT_3(lcnt); 5551dd728f5SVitor Soares lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt; 5561dd728f5SVitor Soares scl_timing |= SCL_EXT_LCNT_4(lcnt); 5571dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_EXT_LCNT_TIMING); 5581dd728f5SVitor Soares 5591dd728f5SVitor Soares return 0; 5601dd728f5SVitor Soares } 5611dd728f5SVitor Soares 5621dd728f5SVitor Soares static int dw_i2c_clk_cfg(struct dw_i3c_master *master) 5631dd728f5SVitor Soares { 5641dd728f5SVitor Soares unsigned long core_rate, core_period; 5651dd728f5SVitor Soares u16 hcnt, lcnt; 5661dd728f5SVitor Soares u32 scl_timing; 5671dd728f5SVitor Soares 5681dd728f5SVitor Soares core_rate = clk_get_rate(master->core_clk); 5691dd728f5SVitor Soares if (!core_rate) 5701dd728f5SVitor Soares return -EINVAL; 5711dd728f5SVitor Soares 5721dd728f5SVitor Soares core_period = DIV_ROUND_UP(1000000000, core_rate); 5731dd728f5SVitor Soares 5741dd728f5SVitor Soares lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS, core_period); 5751dd728f5SVitor Soares hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt; 5761dd728f5SVitor Soares scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) | 5771dd728f5SVitor Soares SCL_I2C_FMP_TIMING_LCNT(lcnt); 5781dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING); 5791dd728f5SVitor Soares 5801dd728f5SVitor Soares lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS, core_period); 5811dd728f5SVitor Soares hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt; 5821dd728f5SVitor Soares scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) | 5831dd728f5SVitor Soares SCL_I2C_FM_TIMING_LCNT(lcnt); 5841dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_I2C_FM_TIMING); 5851dd728f5SVitor Soares 5861dd728f5SVitor Soares writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING); 5871dd728f5SVitor Soares writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_I2C_SLAVE_PRESENT, 5881dd728f5SVitor Soares master->regs + DEVICE_CTRL); 5891dd728f5SVitor Soares 5901dd728f5SVitor Soares return 0; 5911dd728f5SVitor Soares } 5921dd728f5SVitor Soares 5931dd728f5SVitor Soares static int dw_i3c_master_bus_init(struct i3c_master_controller *m) 5941dd728f5SVitor Soares { 5951dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 5961dd728f5SVitor Soares struct i3c_bus *bus = i3c_master_get_bus(m); 5971dd728f5SVitor Soares struct i3c_device_info info = { }; 5981dd728f5SVitor Soares u32 thld_ctrl; 5991dd728f5SVitor Soares int ret; 6001dd728f5SVitor Soares 6011dd728f5SVitor Soares switch (bus->mode) { 6021dd728f5SVitor Soares case I3C_BUS_MODE_MIXED_FAST: 603f467907cSVitor Soares case I3C_BUS_MODE_MIXED_LIMITED: 6041dd728f5SVitor Soares ret = dw_i2c_clk_cfg(master); 6051dd728f5SVitor Soares if (ret) 6061dd728f5SVitor Soares return ret; 607df561f66SGustavo A. R. Silva fallthrough; 6081dd728f5SVitor Soares case I3C_BUS_MODE_PURE: 6091dd728f5SVitor Soares ret = dw_i3c_clk_cfg(master); 6101dd728f5SVitor Soares if (ret) 6111dd728f5SVitor Soares return ret; 6121dd728f5SVitor Soares break; 6131dd728f5SVitor Soares default: 6141dd728f5SVitor Soares return -EINVAL; 6151dd728f5SVitor Soares } 6161dd728f5SVitor Soares 6171dd728f5SVitor Soares thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL); 6181dd728f5SVitor Soares thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK; 6191dd728f5SVitor Soares writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL); 6201dd728f5SVitor Soares 6211dd728f5SVitor Soares thld_ctrl = readl(master->regs + DATA_BUFFER_THLD_CTRL); 6221dd728f5SVitor Soares thld_ctrl &= ~DATA_BUFFER_THLD_CTRL_RX_BUF; 6231dd728f5SVitor Soares writel(thld_ctrl, master->regs + DATA_BUFFER_THLD_CTRL); 6241dd728f5SVitor Soares 6251dd728f5SVitor Soares writel(INTR_ALL, master->regs + INTR_STATUS); 6261dd728f5SVitor Soares writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN); 6271dd728f5SVitor Soares writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN); 6281dd728f5SVitor Soares 6291dd728f5SVitor Soares ret = i3c_master_get_free_addr(m, 0); 6301dd728f5SVitor Soares if (ret < 0) 6311dd728f5SVitor Soares return ret; 6321dd728f5SVitor Soares 6331dd728f5SVitor Soares writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret), 6341dd728f5SVitor Soares master->regs + DEVICE_ADDR); 6351dd728f5SVitor Soares 6361dd728f5SVitor Soares memset(&info, 0, sizeof(info)); 6371dd728f5SVitor Soares info.dyn_addr = ret; 6381dd728f5SVitor Soares 6391dd728f5SVitor Soares ret = i3c_master_set_info(&master->base, &info); 6401dd728f5SVitor Soares if (ret) 6411dd728f5SVitor Soares return ret; 6421dd728f5SVitor Soares 6431dd728f5SVitor Soares writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT); 6441dd728f5SVitor Soares writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT); 6451dd728f5SVitor Soares 6461dd728f5SVitor Soares /* For now don't support Hot-Join */ 6471dd728f5SVitor Soares writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK, 6481dd728f5SVitor Soares master->regs + DEVICE_CTRL); 6491dd728f5SVitor Soares 6501dd728f5SVitor Soares dw_i3c_master_enable(master); 6511dd728f5SVitor Soares 6521dd728f5SVitor Soares return 0; 6531dd728f5SVitor Soares } 6541dd728f5SVitor Soares 6551dd728f5SVitor Soares static void dw_i3c_master_bus_cleanup(struct i3c_master_controller *m) 6561dd728f5SVitor Soares { 6571dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 6581dd728f5SVitor Soares 6591dd728f5SVitor Soares dw_i3c_master_disable(master); 6601dd728f5SVitor Soares } 6611dd728f5SVitor Soares 6621dd728f5SVitor Soares static int dw_i3c_ccc_set(struct dw_i3c_master *master, 6631dd728f5SVitor Soares struct i3c_ccc_cmd *ccc) 6641dd728f5SVitor Soares { 6651dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 6661dd728f5SVitor Soares struct dw_i3c_cmd *cmd; 6671dd728f5SVitor Soares int ret, pos = 0; 6681dd728f5SVitor Soares 6691dd728f5SVitor Soares if (ccc->id & I3C_CCC_DIRECT) { 6701dd728f5SVitor Soares pos = dw_i3c_master_get_addr_pos(master, ccc->dests[0].addr); 6711dd728f5SVitor Soares if (pos < 0) 6721dd728f5SVitor Soares return pos; 6731dd728f5SVitor Soares } 6741dd728f5SVitor Soares 6751dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, 1); 6761dd728f5SVitor Soares if (!xfer) 6771dd728f5SVitor Soares return -ENOMEM; 6781dd728f5SVitor Soares 6791dd728f5SVitor Soares cmd = xfer->cmds; 6801dd728f5SVitor Soares cmd->tx_buf = ccc->dests[0].payload.data; 6811dd728f5SVitor Soares cmd->tx_len = ccc->dests[0].payload.len; 6821dd728f5SVitor Soares 6831dd728f5SVitor Soares cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) | 6841dd728f5SVitor Soares COMMAND_PORT_TRANSFER_ARG; 6851dd728f5SVitor Soares 6861dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_CP | 6871dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(pos) | 6881dd728f5SVitor Soares COMMAND_PORT_CMD(ccc->id) | 6891dd728f5SVitor Soares COMMAND_PORT_TOC | 6901dd728f5SVitor Soares COMMAND_PORT_ROC; 6911dd728f5SVitor Soares 6921dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 6931dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 6941dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 6951dd728f5SVitor Soares 6961dd728f5SVitor Soares ret = xfer->ret; 6971dd728f5SVitor Soares if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK) 6981dd728f5SVitor Soares ccc->err = I3C_ERROR_M2; 6991dd728f5SVitor Soares 7001dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 7011dd728f5SVitor Soares 7021dd728f5SVitor Soares return ret; 7031dd728f5SVitor Soares } 7041dd728f5SVitor Soares 7051dd728f5SVitor Soares static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc) 7061dd728f5SVitor Soares { 7071dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 7081dd728f5SVitor Soares struct dw_i3c_cmd *cmd; 7091dd728f5SVitor Soares int ret, pos; 7101dd728f5SVitor Soares 7111dd728f5SVitor Soares pos = dw_i3c_master_get_addr_pos(master, ccc->dests[0].addr); 7121dd728f5SVitor Soares if (pos < 0) 7131dd728f5SVitor Soares return pos; 7141dd728f5SVitor Soares 7151dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, 1); 7161dd728f5SVitor Soares if (!xfer) 7171dd728f5SVitor Soares return -ENOMEM; 7181dd728f5SVitor Soares 7191dd728f5SVitor Soares cmd = xfer->cmds; 7201dd728f5SVitor Soares cmd->rx_buf = ccc->dests[0].payload.data; 7211dd728f5SVitor Soares cmd->rx_len = ccc->dests[0].payload.len; 7221dd728f5SVitor Soares 7231dd728f5SVitor Soares cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) | 7241dd728f5SVitor Soares COMMAND_PORT_TRANSFER_ARG; 7251dd728f5SVitor Soares 7261dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER | 7271dd728f5SVitor Soares COMMAND_PORT_CP | 7281dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(pos) | 7291dd728f5SVitor Soares COMMAND_PORT_CMD(ccc->id) | 7301dd728f5SVitor Soares COMMAND_PORT_TOC | 7311dd728f5SVitor Soares COMMAND_PORT_ROC; 7321dd728f5SVitor Soares 7331dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 7341dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 7351dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 7361dd728f5SVitor Soares 7371dd728f5SVitor Soares ret = xfer->ret; 7381dd728f5SVitor Soares if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK) 7391dd728f5SVitor Soares ccc->err = I3C_ERROR_M2; 7401dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 7411dd728f5SVitor Soares 7421dd728f5SVitor Soares return ret; 7431dd728f5SVitor Soares } 7441dd728f5SVitor Soares 7451dd728f5SVitor Soares static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, 7461dd728f5SVitor Soares struct i3c_ccc_cmd *ccc) 7471dd728f5SVitor Soares { 7481dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 7491dd728f5SVitor Soares int ret = 0; 7501dd728f5SVitor Soares 7511dd728f5SVitor Soares if (ccc->id == I3C_CCC_ENTDAA) 7521dd728f5SVitor Soares return -EINVAL; 7531dd728f5SVitor Soares 7541dd728f5SVitor Soares if (ccc->rnw) 7551dd728f5SVitor Soares ret = dw_i3c_ccc_get(master, ccc); 7561dd728f5SVitor Soares else 7571dd728f5SVitor Soares ret = dw_i3c_ccc_set(master, ccc); 7581dd728f5SVitor Soares 7591dd728f5SVitor Soares return ret; 7601dd728f5SVitor Soares } 7611dd728f5SVitor Soares 7621dd728f5SVitor Soares static int dw_i3c_master_daa(struct i3c_master_controller *m) 7631dd728f5SVitor Soares { 7641dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 7651dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 7661dd728f5SVitor Soares struct dw_i3c_cmd *cmd; 7671dd728f5SVitor Soares u32 olddevs, newdevs; 7681dd728f5SVitor Soares u8 p, last_addr = 0; 7691dd728f5SVitor Soares int ret, pos; 7701dd728f5SVitor Soares 7711dd728f5SVitor Soares olddevs = ~(master->free_pos); 7721dd728f5SVitor Soares 7731dd728f5SVitor Soares /* Prepare DAT before launching DAA. */ 7741dd728f5SVitor Soares for (pos = 0; pos < master->maxdevs; pos++) { 7751dd728f5SVitor Soares if (olddevs & BIT(pos)) 7761dd728f5SVitor Soares continue; 7771dd728f5SVitor Soares 7781dd728f5SVitor Soares ret = i3c_master_get_free_addr(m, last_addr + 1); 7791dd728f5SVitor Soares if (ret < 0) 7801dd728f5SVitor Soares return -ENOSPC; 7811dd728f5SVitor Soares 7821dd728f5SVitor Soares master->addrs[pos] = ret; 7831dd728f5SVitor Soares p = even_parity(ret); 7841dd728f5SVitor Soares last_addr = ret; 7851dd728f5SVitor Soares ret |= (p << 7); 7861dd728f5SVitor Soares 7871dd728f5SVitor Soares writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(ret), 7881dd728f5SVitor Soares master->regs + 7891dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, pos)); 7901dd728f5SVitor Soares } 7911dd728f5SVitor Soares 7921dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, 1); 7931dd728f5SVitor Soares if (!xfer) 7941dd728f5SVitor Soares return -ENOMEM; 7951dd728f5SVitor Soares 7961dd728f5SVitor Soares pos = dw_i3c_master_get_free_pos(master); 79713462ba1STom Rix if (pos < 0) { 79813462ba1STom Rix dw_i3c_master_free_xfer(xfer); 79913462ba1STom Rix return pos; 80013462ba1STom Rix } 8011dd728f5SVitor Soares cmd = &xfer->cmds[0]; 8021dd728f5SVitor Soares cmd->cmd_hi = 0x1; 8031dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_DEV_COUNT(master->maxdevs - pos) | 8041dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(pos) | 8051dd728f5SVitor Soares COMMAND_PORT_CMD(I3C_CCC_ENTDAA) | 8061dd728f5SVitor Soares COMMAND_PORT_ADDR_ASSGN_CMD | 8071dd728f5SVitor Soares COMMAND_PORT_TOC | 8081dd728f5SVitor Soares COMMAND_PORT_ROC; 8091dd728f5SVitor Soares 8101dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 8111dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 8121dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 8131dd728f5SVitor Soares 8141dd728f5SVitor Soares newdevs = GENMASK(master->maxdevs - cmd->rx_len - 1, 0); 8151dd728f5SVitor Soares newdevs &= ~olddevs; 8161dd728f5SVitor Soares 8171dd728f5SVitor Soares for (pos = 0; pos < master->maxdevs; pos++) { 8181dd728f5SVitor Soares if (newdevs & BIT(pos)) 8191dd728f5SVitor Soares i3c_master_add_i3c_dev_locked(m, master->addrs[pos]); 8201dd728f5SVitor Soares } 8211dd728f5SVitor Soares 8221dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 8231dd728f5SVitor Soares 8241dd728f5SVitor Soares return 0; 8251dd728f5SVitor Soares } 8261dd728f5SVitor Soares 8271dd728f5SVitor Soares static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, 8281dd728f5SVitor Soares struct i3c_priv_xfer *i3c_xfers, 8291dd728f5SVitor Soares int i3c_nxfers) 8301dd728f5SVitor Soares { 8311dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 8321dd728f5SVitor Soares struct i3c_master_controller *m = i3c_dev_get_master(dev); 8331dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 8341dd728f5SVitor Soares unsigned int nrxwords = 0, ntxwords = 0; 8351dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 8361dd728f5SVitor Soares int i, ret = 0; 8371dd728f5SVitor Soares 8381dd728f5SVitor Soares if (!i3c_nxfers) 8391dd728f5SVitor Soares return 0; 8401dd728f5SVitor Soares 8411dd728f5SVitor Soares if (i3c_nxfers > master->caps.cmdfifodepth) 8421dd728f5SVitor Soares return -ENOTSUPP; 8431dd728f5SVitor Soares 8441dd728f5SVitor Soares for (i = 0; i < i3c_nxfers; i++) { 8451dd728f5SVitor Soares if (i3c_xfers[i].rnw) 8461dd728f5SVitor Soares nrxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4); 8471dd728f5SVitor Soares else 8481dd728f5SVitor Soares ntxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4); 8491dd728f5SVitor Soares } 8501dd728f5SVitor Soares 8511dd728f5SVitor Soares if (ntxwords > master->caps.datafifodepth || 8521dd728f5SVitor Soares nrxwords > master->caps.datafifodepth) 8531dd728f5SVitor Soares return -ENOTSUPP; 8541dd728f5SVitor Soares 8551dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers); 8561dd728f5SVitor Soares if (!xfer) 8571dd728f5SVitor Soares return -ENOMEM; 8581dd728f5SVitor Soares 8591dd728f5SVitor Soares for (i = 0; i < i3c_nxfers; i++) { 8601dd728f5SVitor Soares struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 8611dd728f5SVitor Soares 8621dd728f5SVitor Soares cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i3c_xfers[i].len) | 8631dd728f5SVitor Soares COMMAND_PORT_TRANSFER_ARG; 8641dd728f5SVitor Soares 8651dd728f5SVitor Soares if (i3c_xfers[i].rnw) { 8661dd728f5SVitor Soares cmd->rx_buf = i3c_xfers[i].data.in; 8671dd728f5SVitor Soares cmd->rx_len = i3c_xfers[i].len; 8681dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER | 8691dd728f5SVitor Soares COMMAND_PORT_SPEED(dev->info.max_read_ds); 8701dd728f5SVitor Soares 8711dd728f5SVitor Soares } else { 8721dd728f5SVitor Soares cmd->tx_buf = i3c_xfers[i].data.out; 8731dd728f5SVitor Soares cmd->tx_len = i3c_xfers[i].len; 8741dd728f5SVitor Soares cmd->cmd_lo = 8751dd728f5SVitor Soares COMMAND_PORT_SPEED(dev->info.max_write_ds); 8761dd728f5SVitor Soares } 8771dd728f5SVitor Soares 8781dd728f5SVitor Soares cmd->cmd_lo |= COMMAND_PORT_TID(i) | 8791dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(data->index) | 8801dd728f5SVitor Soares COMMAND_PORT_ROC; 8811dd728f5SVitor Soares 8821dd728f5SVitor Soares if (i == (i3c_nxfers - 1)) 8831dd728f5SVitor Soares cmd->cmd_lo |= COMMAND_PORT_TOC; 8841dd728f5SVitor Soares } 8851dd728f5SVitor Soares 8861dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 8871dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 8881dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 8891dd728f5SVitor Soares 8901dd728f5SVitor Soares ret = xfer->ret; 8911dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 8921dd728f5SVitor Soares 8931dd728f5SVitor Soares return ret; 8941dd728f5SVitor Soares } 8951dd728f5SVitor Soares 8961dd728f5SVitor Soares static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, 8971dd728f5SVitor Soares u8 old_dyn_addr) 8981dd728f5SVitor Soares { 8991dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 9001dd728f5SVitor Soares struct i3c_master_controller *m = i3c_dev_get_master(dev); 9011dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 9023952cf8fSVitor Soares int pos; 9033952cf8fSVitor Soares 9043952cf8fSVitor Soares pos = dw_i3c_master_get_free_pos(master); 9053952cf8fSVitor Soares 9063952cf8fSVitor Soares if (data->index > pos && pos > 0) { 9073952cf8fSVitor Soares writel(0, 9083952cf8fSVitor Soares master->regs + 9093952cf8fSVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 9103952cf8fSVitor Soares 9113952cf8fSVitor Soares master->addrs[data->index] = 0; 9123952cf8fSVitor Soares master->free_pos |= BIT(data->index); 9133952cf8fSVitor Soares 9143952cf8fSVitor Soares data->index = pos; 9153952cf8fSVitor Soares master->addrs[pos] = dev->info.dyn_addr; 9163952cf8fSVitor Soares master->free_pos &= ~BIT(pos); 9173952cf8fSVitor Soares } 9181dd728f5SVitor Soares 9191dd728f5SVitor Soares writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr), 9201dd728f5SVitor Soares master->regs + 9211dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 9221dd728f5SVitor Soares 9231dd728f5SVitor Soares master->addrs[data->index] = dev->info.dyn_addr; 9241dd728f5SVitor Soares 9251dd728f5SVitor Soares return 0; 9261dd728f5SVitor Soares } 9271dd728f5SVitor Soares 9281dd728f5SVitor Soares static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev) 9291dd728f5SVitor Soares { 9301dd728f5SVitor Soares struct i3c_master_controller *m = i3c_dev_get_master(dev); 9311dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 9321dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data; 9331dd728f5SVitor Soares int pos; 9341dd728f5SVitor Soares 9351dd728f5SVitor Soares pos = dw_i3c_master_get_free_pos(master); 9361dd728f5SVitor Soares if (pos < 0) 9371dd728f5SVitor Soares return pos; 9381dd728f5SVitor Soares 9391dd728f5SVitor Soares data = kzalloc(sizeof(*data), GFP_KERNEL); 9401dd728f5SVitor Soares if (!data) 9411dd728f5SVitor Soares return -ENOMEM; 9421dd728f5SVitor Soares 9431dd728f5SVitor Soares data->index = pos; 944f29fd331SVitor Soares master->addrs[pos] = dev->info.dyn_addr ? : dev->info.static_addr; 9451dd728f5SVitor Soares master->free_pos &= ~BIT(pos); 9461dd728f5SVitor Soares i3c_dev_set_master_data(dev, data); 9471dd728f5SVitor Soares 948f29fd331SVitor Soares writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->addrs[pos]), 9491dd728f5SVitor Soares master->regs + 9501dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 9511dd728f5SVitor Soares 9521dd728f5SVitor Soares return 0; 9531dd728f5SVitor Soares } 9541dd728f5SVitor Soares 9551dd728f5SVitor Soares static void dw_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev) 9561dd728f5SVitor Soares { 9571dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 9581dd728f5SVitor Soares struct i3c_master_controller *m = i3c_dev_get_master(dev); 9591dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 9601dd728f5SVitor Soares 9611dd728f5SVitor Soares writel(0, 9621dd728f5SVitor Soares master->regs + 9631dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 9641dd728f5SVitor Soares 9651dd728f5SVitor Soares i3c_dev_set_master_data(dev, NULL); 9661dd728f5SVitor Soares master->addrs[data->index] = 0; 9671dd728f5SVitor Soares master->free_pos |= BIT(data->index); 9681dd728f5SVitor Soares kfree(data); 9691dd728f5SVitor Soares } 9701dd728f5SVitor Soares 9711dd728f5SVitor Soares static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, 9721dd728f5SVitor Soares const struct i2c_msg *i2c_xfers, 9731dd728f5SVitor Soares int i2c_nxfers) 9741dd728f5SVitor Soares { 9751dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); 9761dd728f5SVitor Soares struct i3c_master_controller *m = i2c_dev_get_master(dev); 9771dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 9781dd728f5SVitor Soares unsigned int nrxwords = 0, ntxwords = 0; 9791dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 9801dd728f5SVitor Soares int i, ret = 0; 9811dd728f5SVitor Soares 9821dd728f5SVitor Soares if (!i2c_nxfers) 9831dd728f5SVitor Soares return 0; 9841dd728f5SVitor Soares 9851dd728f5SVitor Soares if (i2c_nxfers > master->caps.cmdfifodepth) 9861dd728f5SVitor Soares return -ENOTSUPP; 9871dd728f5SVitor Soares 9881dd728f5SVitor Soares for (i = 0; i < i2c_nxfers; i++) { 9891dd728f5SVitor Soares if (i2c_xfers[i].flags & I2C_M_RD) 9901dd728f5SVitor Soares nrxwords += DIV_ROUND_UP(i2c_xfers[i].len, 4); 9911dd728f5SVitor Soares else 9921dd728f5SVitor Soares ntxwords += DIV_ROUND_UP(i2c_xfers[i].len, 4); 9931dd728f5SVitor Soares } 9941dd728f5SVitor Soares 9951dd728f5SVitor Soares if (ntxwords > master->caps.datafifodepth || 9961dd728f5SVitor Soares nrxwords > master->caps.datafifodepth) 9971dd728f5SVitor Soares return -ENOTSUPP; 9981dd728f5SVitor Soares 9991dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers); 10001dd728f5SVitor Soares if (!xfer) 10011dd728f5SVitor Soares return -ENOMEM; 10021dd728f5SVitor Soares 10031dd728f5SVitor Soares for (i = 0; i < i2c_nxfers; i++) { 10041dd728f5SVitor Soares struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 10051dd728f5SVitor Soares 10061dd728f5SVitor Soares cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i2c_xfers[i].len) | 10071dd728f5SVitor Soares COMMAND_PORT_TRANSFER_ARG; 10081dd728f5SVitor Soares 10091dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_TID(i) | 10101dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(data->index) | 10111dd728f5SVitor Soares COMMAND_PORT_ROC; 10121dd728f5SVitor Soares 10131dd728f5SVitor Soares if (i2c_xfers[i].flags & I2C_M_RD) { 10141dd728f5SVitor Soares cmd->cmd_lo |= COMMAND_PORT_READ_TRANSFER; 10151dd728f5SVitor Soares cmd->rx_buf = i2c_xfers[i].buf; 10161dd728f5SVitor Soares cmd->rx_len = i2c_xfers[i].len; 10171dd728f5SVitor Soares } else { 10181dd728f5SVitor Soares cmd->tx_buf = i2c_xfers[i].buf; 10191dd728f5SVitor Soares cmd->tx_len = i2c_xfers[i].len; 10201dd728f5SVitor Soares } 10211dd728f5SVitor Soares 10221dd728f5SVitor Soares if (i == (i2c_nxfers - 1)) 10231dd728f5SVitor Soares cmd->cmd_lo |= COMMAND_PORT_TOC; 10241dd728f5SVitor Soares } 10251dd728f5SVitor Soares 10261dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 10271dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 10281dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 10291dd728f5SVitor Soares 10301dd728f5SVitor Soares ret = xfer->ret; 10311dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 10321dd728f5SVitor Soares 10331dd728f5SVitor Soares return ret; 10341dd728f5SVitor Soares } 10351dd728f5SVitor Soares 10361dd728f5SVitor Soares static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) 10371dd728f5SVitor Soares { 10381dd728f5SVitor Soares struct i3c_master_controller *m = i2c_dev_get_master(dev); 10391dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 10401dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data; 10411dd728f5SVitor Soares int pos; 10421dd728f5SVitor Soares 10431dd728f5SVitor Soares pos = dw_i3c_master_get_free_pos(master); 10441dd728f5SVitor Soares if (pos < 0) 10451dd728f5SVitor Soares return pos; 10461dd728f5SVitor Soares 10471dd728f5SVitor Soares data = kzalloc(sizeof(*data), GFP_KERNEL); 10481dd728f5SVitor Soares if (!data) 10491dd728f5SVitor Soares return -ENOMEM; 10501dd728f5SVitor Soares 10511dd728f5SVitor Soares data->index = pos; 1052b1ac3a4bSPrzemyslaw Gaj master->addrs[pos] = dev->addr; 10531dd728f5SVitor Soares master->free_pos &= ~BIT(pos); 10541dd728f5SVitor Soares i2c_dev_set_master_data(dev, data); 10551dd728f5SVitor Soares 10561dd728f5SVitor Soares writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV | 1057b1ac3a4bSPrzemyslaw Gaj DEV_ADDR_TABLE_STATIC_ADDR(dev->addr), 10581dd728f5SVitor Soares master->regs + 10591dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 10601dd728f5SVitor Soares 10611dd728f5SVitor Soares return 0; 10621dd728f5SVitor Soares } 10631dd728f5SVitor Soares 10641dd728f5SVitor Soares static void dw_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) 10651dd728f5SVitor Soares { 10661dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); 10671dd728f5SVitor Soares struct i3c_master_controller *m = i2c_dev_get_master(dev); 10681dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 10691dd728f5SVitor Soares 10701dd728f5SVitor Soares writel(0, 10711dd728f5SVitor Soares master->regs + 10721dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 10731dd728f5SVitor Soares 10741dd728f5SVitor Soares i2c_dev_set_master_data(dev, NULL); 10751dd728f5SVitor Soares master->addrs[data->index] = 0; 10761dd728f5SVitor Soares master->free_pos |= BIT(data->index); 10771dd728f5SVitor Soares kfree(data); 10781dd728f5SVitor Soares } 10791dd728f5SVitor Soares 10801dd728f5SVitor Soares static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id) 10811dd728f5SVitor Soares { 10821dd728f5SVitor Soares struct dw_i3c_master *master = dev_id; 10831dd728f5SVitor Soares u32 status; 10841dd728f5SVitor Soares 10851dd728f5SVitor Soares status = readl(master->regs + INTR_STATUS); 10861dd728f5SVitor Soares 10871dd728f5SVitor Soares if (!(status & readl(master->regs + INTR_STATUS_EN))) { 10881dd728f5SVitor Soares writel(INTR_ALL, master->regs + INTR_STATUS); 10891dd728f5SVitor Soares return IRQ_NONE; 10901dd728f5SVitor Soares } 10911dd728f5SVitor Soares 10921dd728f5SVitor Soares spin_lock(&master->xferqueue.lock); 10931dd728f5SVitor Soares dw_i3c_master_end_xfer_locked(master, status); 10942b2b283cSColin Ian King if (status & INTR_TRANSFER_ERR_STAT) 10951dd728f5SVitor Soares writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS); 10961dd728f5SVitor Soares spin_unlock(&master->xferqueue.lock); 10971dd728f5SVitor Soares 10981dd728f5SVitor Soares return IRQ_HANDLED; 10991dd728f5SVitor Soares } 11001dd728f5SVitor Soares 11011dd728f5SVitor Soares static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { 11021dd728f5SVitor Soares .bus_init = dw_i3c_master_bus_init, 11031dd728f5SVitor Soares .bus_cleanup = dw_i3c_master_bus_cleanup, 11041dd728f5SVitor Soares .attach_i3c_dev = dw_i3c_master_attach_i3c_dev, 11051dd728f5SVitor Soares .reattach_i3c_dev = dw_i3c_master_reattach_i3c_dev, 11061dd728f5SVitor Soares .detach_i3c_dev = dw_i3c_master_detach_i3c_dev, 11071dd728f5SVitor Soares .do_daa = dw_i3c_master_daa, 11081dd728f5SVitor Soares .supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd, 11091dd728f5SVitor Soares .send_ccc_cmd = dw_i3c_master_send_ccc_cmd, 11101dd728f5SVitor Soares .priv_xfers = dw_i3c_master_priv_xfers, 11111dd728f5SVitor Soares .attach_i2c_dev = dw_i3c_master_attach_i2c_dev, 11121dd728f5SVitor Soares .detach_i2c_dev = dw_i3c_master_detach_i2c_dev, 11131dd728f5SVitor Soares .i2c_xfers = dw_i3c_master_i2c_xfers, 11141dd728f5SVitor Soares }; 11151dd728f5SVitor Soares 11161dd728f5SVitor Soares static int dw_i3c_probe(struct platform_device *pdev) 11171dd728f5SVitor Soares { 11181dd728f5SVitor Soares struct dw_i3c_master *master; 11191dd728f5SVitor Soares int ret, irq; 11201dd728f5SVitor Soares 11211dd728f5SVitor Soares master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); 11221dd728f5SVitor Soares if (!master) 11231dd728f5SVitor Soares return -ENOMEM; 11241dd728f5SVitor Soares 1125fae04237SYangtao Li master->regs = devm_platform_ioremap_resource(pdev, 0); 11261dd728f5SVitor Soares if (IS_ERR(master->regs)) 11271dd728f5SVitor Soares return PTR_ERR(master->regs); 11281dd728f5SVitor Soares 11291dd728f5SVitor Soares master->core_clk = devm_clk_get(&pdev->dev, NULL); 11301dd728f5SVitor Soares if (IS_ERR(master->core_clk)) 11311dd728f5SVitor Soares return PTR_ERR(master->core_clk); 11321dd728f5SVitor Soares 11331dd728f5SVitor Soares master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, 11341dd728f5SVitor Soares "core_rst"); 11351dd728f5SVitor Soares if (IS_ERR(master->core_rst)) 11361dd728f5SVitor Soares return PTR_ERR(master->core_rst); 11371dd728f5SVitor Soares 11381dd728f5SVitor Soares ret = clk_prepare_enable(master->core_clk); 11391dd728f5SVitor Soares if (ret) 11401dd728f5SVitor Soares goto err_disable_core_clk; 11411dd728f5SVitor Soares 11421dd728f5SVitor Soares reset_control_deassert(master->core_rst); 11431dd728f5SVitor Soares 11441dd728f5SVitor Soares spin_lock_init(&master->xferqueue.lock); 11451dd728f5SVitor Soares INIT_LIST_HEAD(&master->xferqueue.list); 11461dd728f5SVitor Soares 11471dd728f5SVitor Soares writel(INTR_ALL, master->regs + INTR_STATUS); 11481dd728f5SVitor Soares irq = platform_get_irq(pdev, 0); 11491dd728f5SVitor Soares ret = devm_request_irq(&pdev->dev, irq, 11501dd728f5SVitor Soares dw_i3c_master_irq_handler, 0, 11511dd728f5SVitor Soares dev_name(&pdev->dev), master); 11521dd728f5SVitor Soares if (ret) 11531dd728f5SVitor Soares goto err_assert_rst; 11541dd728f5SVitor Soares 11551dd728f5SVitor Soares platform_set_drvdata(pdev, master); 11561dd728f5SVitor Soares 11571dd728f5SVitor Soares /* Information regarding the FIFOs/QUEUEs depth */ 11581dd728f5SVitor Soares ret = readl(master->regs + QUEUE_STATUS_LEVEL); 11591dd728f5SVitor Soares master->caps.cmdfifodepth = QUEUE_STATUS_LEVEL_CMD(ret); 11601dd728f5SVitor Soares 11611dd728f5SVitor Soares ret = readl(master->regs + DATA_BUFFER_STATUS_LEVEL); 11621dd728f5SVitor Soares master->caps.datafifodepth = DATA_BUFFER_STATUS_LEVEL_TX(ret); 11631dd728f5SVitor Soares 11641dd728f5SVitor Soares ret = readl(master->regs + DEVICE_ADDR_TABLE_POINTER); 11651dd728f5SVitor Soares master->datstartaddr = ret; 11661dd728f5SVitor Soares master->maxdevs = ret >> 16; 11671dd728f5SVitor Soares master->free_pos = GENMASK(master->maxdevs - 1, 0); 11681dd728f5SVitor Soares 11691dd728f5SVitor Soares ret = i3c_master_register(&master->base, &pdev->dev, 11701dd728f5SVitor Soares &dw_mipi_i3c_ops, false); 11711dd728f5SVitor Soares if (ret) 11721dd728f5SVitor Soares goto err_assert_rst; 11731dd728f5SVitor Soares 11741dd728f5SVitor Soares return 0; 11751dd728f5SVitor Soares 11761dd728f5SVitor Soares err_assert_rst: 11771dd728f5SVitor Soares reset_control_assert(master->core_rst); 11781dd728f5SVitor Soares 11791dd728f5SVitor Soares err_disable_core_clk: 11801dd728f5SVitor Soares clk_disable_unprepare(master->core_clk); 11811dd728f5SVitor Soares 11821dd728f5SVitor Soares return ret; 11831dd728f5SVitor Soares } 11841dd728f5SVitor Soares 1185*04b5f1beSUwe Kleine-König static void dw_i3c_remove(struct platform_device *pdev) 11861dd728f5SVitor Soares { 11871dd728f5SVitor Soares struct dw_i3c_master *master = platform_get_drvdata(pdev); 11881dd728f5SVitor Soares 11890f74f8b6SUwe Kleine-König i3c_master_unregister(&master->base); 11901dd728f5SVitor Soares 11911dd728f5SVitor Soares reset_control_assert(master->core_rst); 11921dd728f5SVitor Soares 11931dd728f5SVitor Soares clk_disable_unprepare(master->core_clk); 11941dd728f5SVitor Soares } 11951dd728f5SVitor Soares 11961dd728f5SVitor Soares static const struct of_device_id dw_i3c_master_of_match[] = { 11971dd728f5SVitor Soares { .compatible = "snps,dw-i3c-master-1.00a", }, 11981dd728f5SVitor Soares {}, 11991dd728f5SVitor Soares }; 12001dd728f5SVitor Soares MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match); 12011dd728f5SVitor Soares 12021dd728f5SVitor Soares static struct platform_driver dw_i3c_driver = { 12031dd728f5SVitor Soares .probe = dw_i3c_probe, 1204*04b5f1beSUwe Kleine-König .remove_new = dw_i3c_remove, 12051dd728f5SVitor Soares .driver = { 12061dd728f5SVitor Soares .name = "dw-i3c-master", 12071dae3f1dSKrzysztof Kozlowski .of_match_table = dw_i3c_master_of_match, 12081dd728f5SVitor Soares }, 12091dd728f5SVitor Soares }; 12101dd728f5SVitor Soares module_platform_driver(dw_i3c_driver); 12111dd728f5SVitor Soares 12121dd728f5SVitor Soares MODULE_AUTHOR("Vitor Soares <vitor.soares@synopsys.com>"); 12131dd728f5SVitor Soares MODULE_DESCRIPTION("DesignWare MIPI I3C driver"); 12141dd728f5SVitor Soares MODULE_LICENSE("GPL v2"); 1215