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 24d782188cSJeremy Kerr #include "dw-i3c-master.h" 25d782188cSJeremy Kerr 261dd728f5SVitor Soares #define DEVICE_CTRL 0x0 271dd728f5SVitor Soares #define DEV_CTRL_ENABLE BIT(31) 281dd728f5SVitor Soares #define DEV_CTRL_RESUME BIT(30) 291dd728f5SVitor Soares #define DEV_CTRL_HOT_JOIN_NACK BIT(8) 301dd728f5SVitor Soares #define DEV_CTRL_I2C_SLAVE_PRESENT BIT(7) 311dd728f5SVitor Soares 321dd728f5SVitor Soares #define DEVICE_ADDR 0x4 331dd728f5SVitor Soares #define DEV_ADDR_DYNAMIC_ADDR_VALID BIT(31) 341dd728f5SVitor Soares #define DEV_ADDR_DYNAMIC(x) (((x) << 16) & GENMASK(22, 16)) 351dd728f5SVitor Soares 361dd728f5SVitor Soares #define HW_CAPABILITY 0x8 371dd728f5SVitor Soares #define COMMAND_QUEUE_PORT 0xc 381dd728f5SVitor Soares #define COMMAND_PORT_TOC BIT(30) 391dd728f5SVitor Soares #define COMMAND_PORT_READ_TRANSFER BIT(28) 401dd728f5SVitor Soares #define COMMAND_PORT_SDAP BIT(27) 411dd728f5SVitor Soares #define COMMAND_PORT_ROC BIT(26) 421dd728f5SVitor Soares #define COMMAND_PORT_SPEED(x) (((x) << 21) & GENMASK(23, 21)) 431dd728f5SVitor Soares #define COMMAND_PORT_DEV_INDEX(x) (((x) << 16) & GENMASK(20, 16)) 441dd728f5SVitor Soares #define COMMAND_PORT_CP BIT(15) 451dd728f5SVitor Soares #define COMMAND_PORT_CMD(x) (((x) << 7) & GENMASK(14, 7)) 461dd728f5SVitor Soares #define COMMAND_PORT_TID(x) (((x) << 3) & GENMASK(6, 3)) 471dd728f5SVitor Soares 481dd728f5SVitor Soares #define COMMAND_PORT_ARG_DATA_LEN(x) (((x) << 16) & GENMASK(31, 16)) 491dd728f5SVitor Soares #define COMMAND_PORT_ARG_DATA_LEN_MAX 65536 501dd728f5SVitor Soares #define COMMAND_PORT_TRANSFER_ARG 0x01 511dd728f5SVitor Soares 521dd728f5SVitor Soares #define COMMAND_PORT_SDA_DATA_BYTE_3(x) (((x) << 24) & GENMASK(31, 24)) 531dd728f5SVitor Soares #define COMMAND_PORT_SDA_DATA_BYTE_2(x) (((x) << 16) & GENMASK(23, 16)) 541dd728f5SVitor Soares #define COMMAND_PORT_SDA_DATA_BYTE_1(x) (((x) << 8) & GENMASK(15, 8)) 551dd728f5SVitor Soares #define COMMAND_PORT_SDA_BYTE_STRB_3 BIT(5) 561dd728f5SVitor Soares #define COMMAND_PORT_SDA_BYTE_STRB_2 BIT(4) 571dd728f5SVitor Soares #define COMMAND_PORT_SDA_BYTE_STRB_1 BIT(3) 581dd728f5SVitor Soares #define COMMAND_PORT_SHORT_DATA_ARG 0x02 591dd728f5SVitor Soares 601dd728f5SVitor Soares #define COMMAND_PORT_DEV_COUNT(x) (((x) << 21) & GENMASK(25, 21)) 611dd728f5SVitor Soares #define COMMAND_PORT_ADDR_ASSGN_CMD 0x03 621dd728f5SVitor Soares 631dd728f5SVitor Soares #define RESPONSE_QUEUE_PORT 0x10 641dd728f5SVitor Soares #define RESPONSE_PORT_ERR_STATUS(x) (((x) & GENMASK(31, 28)) >> 28) 651dd728f5SVitor Soares #define RESPONSE_NO_ERROR 0 661dd728f5SVitor Soares #define RESPONSE_ERROR_CRC 1 671dd728f5SVitor Soares #define RESPONSE_ERROR_PARITY 2 681dd728f5SVitor Soares #define RESPONSE_ERROR_FRAME 3 691dd728f5SVitor Soares #define RESPONSE_ERROR_IBA_NACK 4 701dd728f5SVitor Soares #define RESPONSE_ERROR_ADDRESS_NACK 5 711dd728f5SVitor Soares #define RESPONSE_ERROR_OVER_UNDER_FLOW 6 721dd728f5SVitor Soares #define RESPONSE_ERROR_TRANSF_ABORT 8 731dd728f5SVitor Soares #define RESPONSE_ERROR_I2C_W_NACK_ERR 9 741dd728f5SVitor Soares #define RESPONSE_PORT_TID(x) (((x) & GENMASK(27, 24)) >> 24) 751dd728f5SVitor Soares #define RESPONSE_PORT_DATA_LEN(x) ((x) & GENMASK(15, 0)) 761dd728f5SVitor Soares 771dd728f5SVitor Soares #define RX_TX_DATA_PORT 0x14 781dd728f5SVitor Soares #define IBI_QUEUE_STATUS 0x18 79*e389b1d7SJeremy Kerr #define IBI_QUEUE_STATUS_IBI_ID(x) (((x) & GENMASK(15, 8)) >> 8) 80*e389b1d7SJeremy Kerr #define IBI_QUEUE_STATUS_DATA_LEN(x) ((x) & GENMASK(7, 0)) 81*e389b1d7SJeremy Kerr #define IBI_QUEUE_IBI_ADDR(x) (IBI_QUEUE_STATUS_IBI_ID(x) >> 1) 82*e389b1d7SJeremy Kerr #define IBI_QUEUE_IBI_RNW(x) (IBI_QUEUE_STATUS_IBI_ID(x) & BIT(0)) 83*e389b1d7SJeremy Kerr #define IBI_TYPE_MR(x) \ 84*e389b1d7SJeremy Kerr ((IBI_QUEUE_IBI_ADDR(x) != I3C_HOT_JOIN_ADDR) && !IBI_QUEUE_IBI_RNW(x)) 85*e389b1d7SJeremy Kerr #define IBI_TYPE_HJ(x) \ 86*e389b1d7SJeremy Kerr ((IBI_QUEUE_IBI_ADDR(x) == I3C_HOT_JOIN_ADDR) && !IBI_QUEUE_IBI_RNW(x)) 87*e389b1d7SJeremy Kerr #define IBI_TYPE_SIRQ(x) \ 88*e389b1d7SJeremy Kerr ((IBI_QUEUE_IBI_ADDR(x) != I3C_HOT_JOIN_ADDR) && IBI_QUEUE_IBI_RNW(x)) 89*e389b1d7SJeremy Kerr 901dd728f5SVitor Soares #define QUEUE_THLD_CTRL 0x1c 91*e389b1d7SJeremy Kerr #define QUEUE_THLD_CTRL_IBI_STAT_MASK GENMASK(31, 24) 92*e389b1d7SJeremy Kerr #define QUEUE_THLD_CTRL_IBI_STAT(x) (((x) - 1) << 24) 93*e389b1d7SJeremy Kerr #define QUEUE_THLD_CTRL_IBI_DATA_MASK GENMASK(20, 16) 94*e389b1d7SJeremy Kerr #define QUEUE_THLD_CTRL_IBI_DATA(x) ((x) << 16) 951dd728f5SVitor Soares #define QUEUE_THLD_CTRL_RESP_BUF_MASK GENMASK(15, 8) 961dd728f5SVitor Soares #define QUEUE_THLD_CTRL_RESP_BUF(x) (((x) - 1) << 8) 971dd728f5SVitor Soares 981dd728f5SVitor Soares #define DATA_BUFFER_THLD_CTRL 0x20 991dd728f5SVitor Soares #define DATA_BUFFER_THLD_CTRL_RX_BUF GENMASK(11, 8) 1001dd728f5SVitor Soares 1011dd728f5SVitor Soares #define IBI_QUEUE_CTRL 0x24 1021dd728f5SVitor Soares #define IBI_MR_REQ_REJECT 0x2C 1031dd728f5SVitor Soares #define IBI_SIR_REQ_REJECT 0x30 1041dd728f5SVitor Soares #define IBI_REQ_REJECT_ALL GENMASK(31, 0) 1051dd728f5SVitor Soares 1061dd728f5SVitor Soares #define RESET_CTRL 0x34 1071dd728f5SVitor Soares #define RESET_CTRL_IBI_QUEUE BIT(5) 1081dd728f5SVitor Soares #define RESET_CTRL_RX_FIFO BIT(4) 1091dd728f5SVitor Soares #define RESET_CTRL_TX_FIFO BIT(3) 1101dd728f5SVitor Soares #define RESET_CTRL_RESP_QUEUE BIT(2) 1111dd728f5SVitor Soares #define RESET_CTRL_CMD_QUEUE BIT(1) 1121dd728f5SVitor Soares #define RESET_CTRL_SOFT BIT(0) 1131dd728f5SVitor Soares 1141dd728f5SVitor Soares #define SLV_EVENT_CTRL 0x38 1151dd728f5SVitor Soares #define INTR_STATUS 0x3c 1161dd728f5SVitor Soares #define INTR_STATUS_EN 0x40 1171dd728f5SVitor Soares #define INTR_SIGNAL_EN 0x44 1181dd728f5SVitor Soares #define INTR_FORCE 0x48 1191dd728f5SVitor Soares #define INTR_BUSOWNER_UPDATE_STAT BIT(13) 1201dd728f5SVitor Soares #define INTR_IBI_UPDATED_STAT BIT(12) 1211dd728f5SVitor Soares #define INTR_READ_REQ_RECV_STAT BIT(11) 1221dd728f5SVitor Soares #define INTR_DEFSLV_STAT BIT(10) 1231dd728f5SVitor Soares #define INTR_TRANSFER_ERR_STAT BIT(9) 1241dd728f5SVitor Soares #define INTR_DYN_ADDR_ASSGN_STAT BIT(8) 1251dd728f5SVitor Soares #define INTR_CCC_UPDATED_STAT BIT(6) 1261dd728f5SVitor Soares #define INTR_TRANSFER_ABORT_STAT BIT(5) 1271dd728f5SVitor Soares #define INTR_RESP_READY_STAT BIT(4) 1281dd728f5SVitor Soares #define INTR_CMD_QUEUE_READY_STAT BIT(3) 1291dd728f5SVitor Soares #define INTR_IBI_THLD_STAT BIT(2) 1301dd728f5SVitor Soares #define INTR_RX_THLD_STAT BIT(1) 1311dd728f5SVitor Soares #define INTR_TX_THLD_STAT BIT(0) 1321dd728f5SVitor Soares #define INTR_ALL (INTR_BUSOWNER_UPDATE_STAT | \ 1331dd728f5SVitor Soares INTR_IBI_UPDATED_STAT | \ 1341dd728f5SVitor Soares INTR_READ_REQ_RECV_STAT | \ 1351dd728f5SVitor Soares INTR_DEFSLV_STAT | \ 1361dd728f5SVitor Soares INTR_TRANSFER_ERR_STAT | \ 1371dd728f5SVitor Soares INTR_DYN_ADDR_ASSGN_STAT | \ 1381dd728f5SVitor Soares INTR_CCC_UPDATED_STAT | \ 1391dd728f5SVitor Soares INTR_TRANSFER_ABORT_STAT | \ 1401dd728f5SVitor Soares INTR_RESP_READY_STAT | \ 1411dd728f5SVitor Soares INTR_CMD_QUEUE_READY_STAT | \ 1421dd728f5SVitor Soares INTR_IBI_THLD_STAT | \ 1431dd728f5SVitor Soares INTR_TX_THLD_STAT | \ 1441dd728f5SVitor Soares INTR_RX_THLD_STAT) 1451dd728f5SVitor Soares 1461dd728f5SVitor Soares #define INTR_MASTER_MASK (INTR_TRANSFER_ERR_STAT | \ 1471dd728f5SVitor Soares INTR_RESP_READY_STAT) 1481dd728f5SVitor Soares 1491dd728f5SVitor Soares #define QUEUE_STATUS_LEVEL 0x4c 1501dd728f5SVitor Soares #define QUEUE_STATUS_IBI_STATUS_CNT(x) (((x) & GENMASK(28, 24)) >> 24) 1511dd728f5SVitor Soares #define QUEUE_STATUS_IBI_BUF_BLR(x) (((x) & GENMASK(23, 16)) >> 16) 1521dd728f5SVitor Soares #define QUEUE_STATUS_LEVEL_RESP(x) (((x) & GENMASK(15, 8)) >> 8) 1531dd728f5SVitor Soares #define QUEUE_STATUS_LEVEL_CMD(x) ((x) & GENMASK(7, 0)) 1541dd728f5SVitor Soares 1551dd728f5SVitor Soares #define DATA_BUFFER_STATUS_LEVEL 0x50 1561dd728f5SVitor Soares #define DATA_BUFFER_STATUS_LEVEL_TX(x) ((x) & GENMASK(7, 0)) 1571dd728f5SVitor Soares 1581dd728f5SVitor Soares #define PRESENT_STATE 0x54 1591dd728f5SVitor Soares #define CCC_DEVICE_STATUS 0x58 1601dd728f5SVitor Soares #define DEVICE_ADDR_TABLE_POINTER 0x5c 1611dd728f5SVitor Soares #define DEVICE_ADDR_TABLE_DEPTH(x) (((x) & GENMASK(31, 16)) >> 16) 1621dd728f5SVitor Soares #define DEVICE_ADDR_TABLE_ADDR(x) ((x) & GENMASK(7, 0)) 1631dd728f5SVitor Soares 1641dd728f5SVitor Soares #define DEV_CHAR_TABLE_POINTER 0x60 1651dd728f5SVitor Soares #define VENDOR_SPECIFIC_REG_POINTER 0x6c 1661dd728f5SVitor Soares #define SLV_PID_VALUE 0x74 1671dd728f5SVitor Soares #define SLV_CHAR_CTRL 0x78 1681dd728f5SVitor Soares #define SLV_MAX_LEN 0x7c 1691dd728f5SVitor Soares #define MAX_READ_TURNAROUND 0x80 1701dd728f5SVitor Soares #define MAX_DATA_SPEED 0x84 1711dd728f5SVitor Soares #define SLV_DEBUG_STATUS 0x88 1721dd728f5SVitor Soares #define SLV_INTR_REQ 0x8c 1731dd728f5SVitor Soares #define DEVICE_CTRL_EXTENDED 0xb0 1741dd728f5SVitor Soares #define SCL_I3C_OD_TIMING 0xb4 1751dd728f5SVitor Soares #define SCL_I3C_PP_TIMING 0xb8 1761dd728f5SVitor Soares #define SCL_I3C_TIMING_HCNT(x) (((x) << 16) & GENMASK(23, 16)) 1771dd728f5SVitor Soares #define SCL_I3C_TIMING_LCNT(x) ((x) & GENMASK(7, 0)) 1781dd728f5SVitor Soares #define SCL_I3C_TIMING_CNT_MIN 5 1791dd728f5SVitor Soares 1801dd728f5SVitor Soares #define SCL_I2C_FM_TIMING 0xbc 1811dd728f5SVitor Soares #define SCL_I2C_FM_TIMING_HCNT(x) (((x) << 16) & GENMASK(31, 16)) 1821dd728f5SVitor Soares #define SCL_I2C_FM_TIMING_LCNT(x) ((x) & GENMASK(15, 0)) 1831dd728f5SVitor Soares 1841dd728f5SVitor Soares #define SCL_I2C_FMP_TIMING 0xc0 1851dd728f5SVitor Soares #define SCL_I2C_FMP_TIMING_HCNT(x) (((x) << 16) & GENMASK(23, 16)) 1861dd728f5SVitor Soares #define SCL_I2C_FMP_TIMING_LCNT(x) ((x) & GENMASK(15, 0)) 1871dd728f5SVitor Soares 1881dd728f5SVitor Soares #define SCL_EXT_LCNT_TIMING 0xc8 1891dd728f5SVitor Soares #define SCL_EXT_LCNT_4(x) (((x) << 24) & GENMASK(31, 24)) 1901dd728f5SVitor Soares #define SCL_EXT_LCNT_3(x) (((x) << 16) & GENMASK(23, 16)) 1911dd728f5SVitor Soares #define SCL_EXT_LCNT_2(x) (((x) << 8) & GENMASK(15, 8)) 1921dd728f5SVitor Soares #define SCL_EXT_LCNT_1(x) ((x) & GENMASK(7, 0)) 1931dd728f5SVitor Soares 1941dd728f5SVitor Soares #define SCL_EXT_TERMN_LCNT_TIMING 0xcc 1951dd728f5SVitor Soares #define BUS_FREE_TIMING 0xd4 1961dd728f5SVitor Soares #define BUS_I3C_MST_FREE(x) ((x) & GENMASK(15, 0)) 1971dd728f5SVitor Soares 1981dd728f5SVitor Soares #define BUS_IDLE_TIMING 0xd8 1991dd728f5SVitor Soares #define I3C_VER_ID 0xe0 2001dd728f5SVitor Soares #define I3C_VER_TYPE 0xe4 2011dd728f5SVitor Soares #define EXTENDED_CAPABILITY 0xe8 2021dd728f5SVitor Soares #define SLAVE_CONFIG 0xec 2031dd728f5SVitor Soares 204*e389b1d7SJeremy Kerr #define DEV_ADDR_TABLE_IBI_MDB BIT(12) 205*e389b1d7SJeremy Kerr #define DEV_ADDR_TABLE_SIR_REJECT BIT(13) 2061dd728f5SVitor Soares #define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31) 2071dd728f5SVitor Soares #define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) (((x) << 16) & GENMASK(23, 16)) 2081dd728f5SVitor Soares #define DEV_ADDR_TABLE_STATIC_ADDR(x) ((x) & GENMASK(6, 0)) 2091dd728f5SVitor Soares #define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2)) 2101dd728f5SVitor Soares 2111dd728f5SVitor Soares #define I3C_BUS_SDR1_SCL_RATE 8000000 2121dd728f5SVitor Soares #define I3C_BUS_SDR2_SCL_RATE 6000000 2131dd728f5SVitor Soares #define I3C_BUS_SDR3_SCL_RATE 4000000 2141dd728f5SVitor Soares #define I3C_BUS_SDR4_SCL_RATE 2000000 2151dd728f5SVitor Soares #define I3C_BUS_I2C_FM_TLOW_MIN_NS 1300 2161dd728f5SVitor Soares #define I3C_BUS_I2C_FMP_TLOW_MIN_NS 500 2171dd728f5SVitor Soares #define I3C_BUS_THIGH_MAX_NS 41 2181dd728f5SVitor Soares 2191dd728f5SVitor Soares #define XFER_TIMEOUT (msecs_to_jiffies(1000)) 2201dd728f5SVitor Soares 2211dd728f5SVitor Soares struct dw_i3c_cmd { 2221dd728f5SVitor Soares u32 cmd_lo; 2231dd728f5SVitor Soares u32 cmd_hi; 2241dd728f5SVitor Soares u16 tx_len; 2251dd728f5SVitor Soares const void *tx_buf; 2261dd728f5SVitor Soares u16 rx_len; 2271dd728f5SVitor Soares void *rx_buf; 2281dd728f5SVitor Soares u8 error; 2291dd728f5SVitor Soares }; 2301dd728f5SVitor Soares 2311dd728f5SVitor Soares struct dw_i3c_xfer { 2321dd728f5SVitor Soares struct list_head node; 2331dd728f5SVitor Soares struct completion comp; 2341dd728f5SVitor Soares int ret; 2351dd728f5SVitor Soares unsigned int ncmds; 236cd851485SGustavo A. R. Silva struct dw_i3c_cmd cmds[]; 2371dd728f5SVitor Soares }; 2381dd728f5SVitor Soares 2391dd728f5SVitor Soares struct dw_i3c_i2c_dev_data { 2401dd728f5SVitor Soares u8 index; 241*e389b1d7SJeremy Kerr struct i3c_generic_ibi_pool *ibi_pool; 2421dd728f5SVitor Soares }; 2431dd728f5SVitor Soares 2441dd728f5SVitor Soares static u8 even_parity(u8 p) 2451dd728f5SVitor Soares { 2461dd728f5SVitor Soares p ^= p >> 4; 2471dd728f5SVitor Soares p &= 0xf; 2481dd728f5SVitor Soares 2491dd728f5SVitor Soares return (0x9669 >> p) & 1; 2501dd728f5SVitor Soares } 2511dd728f5SVitor Soares 2521dd728f5SVitor Soares static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m, 2531dd728f5SVitor Soares const struct i3c_ccc_cmd *cmd) 2541dd728f5SVitor Soares { 2551dd728f5SVitor Soares if (cmd->ndests > 1) 2561dd728f5SVitor Soares return false; 2571dd728f5SVitor Soares 2581dd728f5SVitor Soares switch (cmd->id) { 2591dd728f5SVitor Soares case I3C_CCC_ENEC(true): 2601dd728f5SVitor Soares case I3C_CCC_ENEC(false): 2611dd728f5SVitor Soares case I3C_CCC_DISEC(true): 2621dd728f5SVitor Soares case I3C_CCC_DISEC(false): 2631dd728f5SVitor Soares case I3C_CCC_ENTAS(0, true): 2641dd728f5SVitor Soares case I3C_CCC_ENTAS(0, false): 2651dd728f5SVitor Soares case I3C_CCC_RSTDAA(true): 2661dd728f5SVitor Soares case I3C_CCC_RSTDAA(false): 2671dd728f5SVitor Soares case I3C_CCC_ENTDAA: 2681dd728f5SVitor Soares case I3C_CCC_SETMWL(true): 2691dd728f5SVitor Soares case I3C_CCC_SETMWL(false): 2701dd728f5SVitor Soares case I3C_CCC_SETMRL(true): 2711dd728f5SVitor Soares case I3C_CCC_SETMRL(false): 2721dd728f5SVitor Soares case I3C_CCC_ENTHDR(0): 2731dd728f5SVitor Soares case I3C_CCC_SETDASA: 2741dd728f5SVitor Soares case I3C_CCC_SETNEWDA: 2751dd728f5SVitor Soares case I3C_CCC_GETMWL: 2761dd728f5SVitor Soares case I3C_CCC_GETMRL: 2771dd728f5SVitor Soares case I3C_CCC_GETPID: 2781dd728f5SVitor Soares case I3C_CCC_GETBCR: 2791dd728f5SVitor Soares case I3C_CCC_GETDCR: 2801dd728f5SVitor Soares case I3C_CCC_GETSTATUS: 2811dd728f5SVitor Soares case I3C_CCC_GETMXDS: 2821dd728f5SVitor Soares case I3C_CCC_GETHDRCAP: 2831dd728f5SVitor Soares return true; 2841dd728f5SVitor Soares default: 2851dd728f5SVitor Soares return false; 2861dd728f5SVitor Soares } 2871dd728f5SVitor Soares } 2881dd728f5SVitor Soares 2891dd728f5SVitor Soares static inline struct dw_i3c_master * 2901dd728f5SVitor Soares to_dw_i3c_master(struct i3c_master_controller *master) 2911dd728f5SVitor Soares { 2921dd728f5SVitor Soares return container_of(master, struct dw_i3c_master, base); 2931dd728f5SVitor Soares } 2941dd728f5SVitor Soares 2951dd728f5SVitor Soares static void dw_i3c_master_disable(struct dw_i3c_master *master) 2961dd728f5SVitor Soares { 297907621e9SVitor Soares writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_ENABLE, 2981dd728f5SVitor Soares master->regs + DEVICE_CTRL); 2991dd728f5SVitor Soares } 3001dd728f5SVitor Soares 3011dd728f5SVitor Soares static void dw_i3c_master_enable(struct dw_i3c_master *master) 3021dd728f5SVitor Soares { 3031dd728f5SVitor Soares writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_ENABLE, 3041dd728f5SVitor Soares master->regs + DEVICE_CTRL); 3051dd728f5SVitor Soares } 3061dd728f5SVitor Soares 3071dd728f5SVitor Soares static int dw_i3c_master_get_addr_pos(struct dw_i3c_master *master, u8 addr) 3081dd728f5SVitor Soares { 3091dd728f5SVitor Soares int pos; 3101dd728f5SVitor Soares 3111dd728f5SVitor Soares for (pos = 0; pos < master->maxdevs; pos++) { 312e2d43101SJeremy Kerr if (addr == master->devs[pos].addr) 3131dd728f5SVitor Soares return pos; 3141dd728f5SVitor Soares } 3151dd728f5SVitor Soares 3161dd728f5SVitor Soares return -EINVAL; 3171dd728f5SVitor Soares } 3181dd728f5SVitor Soares 3191dd728f5SVitor Soares static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master) 3201dd728f5SVitor Soares { 3211dd728f5SVitor Soares if (!(master->free_pos & GENMASK(master->maxdevs - 1, 0))) 3221dd728f5SVitor Soares return -ENOSPC; 3231dd728f5SVitor Soares 3241dd728f5SVitor Soares return ffs(master->free_pos) - 1; 3251dd728f5SVitor Soares } 3261dd728f5SVitor Soares 3271dd728f5SVitor Soares static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master, 3281dd728f5SVitor Soares const u8 *bytes, int nbytes) 3291dd728f5SVitor Soares { 3301dd728f5SVitor Soares writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4); 3311dd728f5SVitor Soares if (nbytes & 3) { 3321dd728f5SVitor Soares u32 tmp = 0; 3331dd728f5SVitor Soares 3341dd728f5SVitor Soares memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3); 3351dd728f5SVitor Soares writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1); 3361dd728f5SVitor Soares } 3371dd728f5SVitor Soares } 3381dd728f5SVitor Soares 33979f42b31SJeremy Kerr static void dw_i3c_master_read_fifo(struct dw_i3c_master *master, 34079f42b31SJeremy Kerr int reg, u8 *bytes, int nbytes) 3411dd728f5SVitor Soares { 34279f42b31SJeremy Kerr readsl(master->regs + reg, bytes, nbytes / 4); 3431dd728f5SVitor Soares if (nbytes & 3) { 3441dd728f5SVitor Soares u32 tmp; 3451dd728f5SVitor Soares 34679f42b31SJeremy Kerr readsl(master->regs + reg, &tmp, 1); 3471dd728f5SVitor Soares memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3); 3481dd728f5SVitor Soares } 3491dd728f5SVitor Soares } 3501dd728f5SVitor Soares 35179f42b31SJeremy Kerr static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master, 35279f42b31SJeremy Kerr u8 *bytes, int nbytes) 35379f42b31SJeremy Kerr { 35479f42b31SJeremy Kerr return dw_i3c_master_read_fifo(master, RX_TX_DATA_PORT, bytes, nbytes); 35579f42b31SJeremy Kerr } 35679f42b31SJeremy Kerr 357*e389b1d7SJeremy Kerr static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master, 358*e389b1d7SJeremy Kerr u8 *bytes, int nbytes) 359*e389b1d7SJeremy Kerr { 360*e389b1d7SJeremy Kerr return dw_i3c_master_read_fifo(master, IBI_QUEUE_STATUS, bytes, nbytes); 361*e389b1d7SJeremy Kerr } 362*e389b1d7SJeremy Kerr 3631dd728f5SVitor Soares static struct dw_i3c_xfer * 3641dd728f5SVitor Soares dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds) 3651dd728f5SVitor Soares { 3661dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 3671dd728f5SVitor Soares 3681dd728f5SVitor Soares xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL); 3691dd728f5SVitor Soares if (!xfer) 3701dd728f5SVitor Soares return NULL; 3711dd728f5SVitor Soares 3721dd728f5SVitor Soares INIT_LIST_HEAD(&xfer->node); 3731dd728f5SVitor Soares xfer->ncmds = ncmds; 3741dd728f5SVitor Soares xfer->ret = -ETIMEDOUT; 3751dd728f5SVitor Soares 3761dd728f5SVitor Soares return xfer; 3771dd728f5SVitor Soares } 3781dd728f5SVitor Soares 3791dd728f5SVitor Soares static void dw_i3c_master_free_xfer(struct dw_i3c_xfer *xfer) 3801dd728f5SVitor Soares { 3811dd728f5SVitor Soares kfree(xfer); 3821dd728f5SVitor Soares } 3831dd728f5SVitor Soares 3841dd728f5SVitor Soares static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master) 3851dd728f5SVitor Soares { 3861dd728f5SVitor Soares struct dw_i3c_xfer *xfer = master->xferqueue.cur; 3871dd728f5SVitor Soares unsigned int i; 3881dd728f5SVitor Soares u32 thld_ctrl; 3891dd728f5SVitor Soares 3901dd728f5SVitor Soares if (!xfer) 3911dd728f5SVitor Soares return; 3921dd728f5SVitor Soares 3931dd728f5SVitor Soares for (i = 0; i < xfer->ncmds; i++) { 3941dd728f5SVitor Soares struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 3951dd728f5SVitor Soares 3961dd728f5SVitor Soares dw_i3c_master_wr_tx_fifo(master, cmd->tx_buf, cmd->tx_len); 3971dd728f5SVitor Soares } 3981dd728f5SVitor Soares 3991dd728f5SVitor Soares thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL); 4001dd728f5SVitor Soares thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK; 4011dd728f5SVitor Soares thld_ctrl |= QUEUE_THLD_CTRL_RESP_BUF(xfer->ncmds); 4021dd728f5SVitor Soares writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL); 4031dd728f5SVitor Soares 4041dd728f5SVitor Soares for (i = 0; i < xfer->ncmds; i++) { 4051dd728f5SVitor Soares struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 4061dd728f5SVitor Soares 4071dd728f5SVitor Soares writel(cmd->cmd_hi, master->regs + COMMAND_QUEUE_PORT); 4081dd728f5SVitor Soares writel(cmd->cmd_lo, master->regs + COMMAND_QUEUE_PORT); 4091dd728f5SVitor Soares } 4101dd728f5SVitor Soares } 4111dd728f5SVitor Soares 4121dd728f5SVitor Soares static void dw_i3c_master_enqueue_xfer(struct dw_i3c_master *master, 4131dd728f5SVitor Soares struct dw_i3c_xfer *xfer) 4141dd728f5SVitor Soares { 4151dd728f5SVitor Soares unsigned long flags; 4161dd728f5SVitor Soares 4171dd728f5SVitor Soares init_completion(&xfer->comp); 4181dd728f5SVitor Soares spin_lock_irqsave(&master->xferqueue.lock, flags); 4191dd728f5SVitor Soares if (master->xferqueue.cur) { 4201dd728f5SVitor Soares list_add_tail(&xfer->node, &master->xferqueue.list); 4211dd728f5SVitor Soares } else { 4221dd728f5SVitor Soares master->xferqueue.cur = xfer; 4231dd728f5SVitor Soares dw_i3c_master_start_xfer_locked(master); 4241dd728f5SVitor Soares } 4251dd728f5SVitor Soares spin_unlock_irqrestore(&master->xferqueue.lock, flags); 4261dd728f5SVitor Soares } 4271dd728f5SVitor Soares 428f36c1f9aSJisheng Zhang static void dw_i3c_master_dequeue_xfer_locked(struct dw_i3c_master *master, 4291dd728f5SVitor Soares struct dw_i3c_xfer *xfer) 4301dd728f5SVitor Soares { 4311dd728f5SVitor Soares if (master->xferqueue.cur == xfer) { 4321dd728f5SVitor Soares u32 status; 4331dd728f5SVitor Soares 4341dd728f5SVitor Soares master->xferqueue.cur = NULL; 4351dd728f5SVitor Soares 4361dd728f5SVitor Soares writel(RESET_CTRL_RX_FIFO | RESET_CTRL_TX_FIFO | 4371dd728f5SVitor Soares RESET_CTRL_RESP_QUEUE | RESET_CTRL_CMD_QUEUE, 4381dd728f5SVitor Soares master->regs + RESET_CTRL); 4391dd728f5SVitor Soares 4401dd728f5SVitor Soares readl_poll_timeout_atomic(master->regs + RESET_CTRL, status, 4411dd728f5SVitor Soares !status, 10, 1000000); 4421dd728f5SVitor Soares } else { 4431dd728f5SVitor Soares list_del_init(&xfer->node); 4441dd728f5SVitor Soares } 445f36c1f9aSJisheng Zhang } 446f36c1f9aSJisheng Zhang 447f36c1f9aSJisheng Zhang static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, 448f36c1f9aSJisheng Zhang struct dw_i3c_xfer *xfer) 449f36c1f9aSJisheng Zhang { 450f36c1f9aSJisheng Zhang unsigned long flags; 451f36c1f9aSJisheng Zhang 452f36c1f9aSJisheng Zhang spin_lock_irqsave(&master->xferqueue.lock, flags); 453f36c1f9aSJisheng Zhang dw_i3c_master_dequeue_xfer_locked(master, xfer); 4541dd728f5SVitor Soares spin_unlock_irqrestore(&master->xferqueue.lock, flags); 4551dd728f5SVitor Soares } 4561dd728f5SVitor Soares 4571dd728f5SVitor Soares static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr) 4581dd728f5SVitor Soares { 4591dd728f5SVitor Soares struct dw_i3c_xfer *xfer = master->xferqueue.cur; 4601dd728f5SVitor Soares int i, ret = 0; 4611dd728f5SVitor Soares u32 nresp; 4621dd728f5SVitor Soares 4631dd728f5SVitor Soares if (!xfer) 4641dd728f5SVitor Soares return; 4651dd728f5SVitor Soares 4661dd728f5SVitor Soares nresp = readl(master->regs + QUEUE_STATUS_LEVEL); 4671dd728f5SVitor Soares nresp = QUEUE_STATUS_LEVEL_RESP(nresp); 4681dd728f5SVitor Soares 4691dd728f5SVitor Soares for (i = 0; i < nresp; i++) { 4701dd728f5SVitor Soares struct dw_i3c_cmd *cmd; 4711dd728f5SVitor Soares u32 resp; 4721dd728f5SVitor Soares 4731dd728f5SVitor Soares resp = readl(master->regs + RESPONSE_QUEUE_PORT); 4741dd728f5SVitor Soares 4751dd728f5SVitor Soares cmd = &xfer->cmds[RESPONSE_PORT_TID(resp)]; 4761dd728f5SVitor Soares cmd->rx_len = RESPONSE_PORT_DATA_LEN(resp); 4771dd728f5SVitor Soares cmd->error = RESPONSE_PORT_ERR_STATUS(resp); 4781dd728f5SVitor Soares if (cmd->rx_len && !cmd->error) 4791dd728f5SVitor Soares dw_i3c_master_read_rx_fifo(master, cmd->rx_buf, 4801dd728f5SVitor Soares cmd->rx_len); 4811dd728f5SVitor Soares } 4821dd728f5SVitor Soares 4831dd728f5SVitor Soares for (i = 0; i < nresp; i++) { 4841dd728f5SVitor Soares switch (xfer->cmds[i].error) { 4851dd728f5SVitor Soares case RESPONSE_NO_ERROR: 4861dd728f5SVitor Soares break; 4871dd728f5SVitor Soares case RESPONSE_ERROR_PARITY: 4881dd728f5SVitor Soares case RESPONSE_ERROR_IBA_NACK: 4891dd728f5SVitor Soares case RESPONSE_ERROR_TRANSF_ABORT: 4901dd728f5SVitor Soares case RESPONSE_ERROR_CRC: 4911dd728f5SVitor Soares case RESPONSE_ERROR_FRAME: 4921dd728f5SVitor Soares ret = -EIO; 4931dd728f5SVitor Soares break; 4941dd728f5SVitor Soares case RESPONSE_ERROR_OVER_UNDER_FLOW: 4951dd728f5SVitor Soares ret = -ENOSPC; 4961dd728f5SVitor Soares break; 4971dd728f5SVitor Soares case RESPONSE_ERROR_I2C_W_NACK_ERR: 4981dd728f5SVitor Soares case RESPONSE_ERROR_ADDRESS_NACK: 4991dd728f5SVitor Soares default: 5001dd728f5SVitor Soares ret = -EINVAL; 5011dd728f5SVitor Soares break; 5021dd728f5SVitor Soares } 5031dd728f5SVitor Soares } 5041dd728f5SVitor Soares 5051dd728f5SVitor Soares xfer->ret = ret; 5061dd728f5SVitor Soares complete(&xfer->comp); 5071dd728f5SVitor Soares 5081dd728f5SVitor Soares if (ret < 0) { 509f36c1f9aSJisheng Zhang dw_i3c_master_dequeue_xfer_locked(master, xfer); 5101dd728f5SVitor Soares writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME, 5111dd728f5SVitor Soares master->regs + DEVICE_CTRL); 5121dd728f5SVitor Soares } 5131dd728f5SVitor Soares 5141dd728f5SVitor Soares xfer = list_first_entry_or_null(&master->xferqueue.list, 5151dd728f5SVitor Soares struct dw_i3c_xfer, 5161dd728f5SVitor Soares node); 5171dd728f5SVitor Soares if (xfer) 5181dd728f5SVitor Soares list_del_init(&xfer->node); 5191dd728f5SVitor Soares 5201dd728f5SVitor Soares master->xferqueue.cur = xfer; 5211dd728f5SVitor Soares dw_i3c_master_start_xfer_locked(master); 5221dd728f5SVitor Soares } 5231dd728f5SVitor Soares 5241dd728f5SVitor Soares static int dw_i3c_clk_cfg(struct dw_i3c_master *master) 5251dd728f5SVitor Soares { 5261dd728f5SVitor Soares unsigned long core_rate, core_period; 5271dd728f5SVitor Soares u32 scl_timing; 5281dd728f5SVitor Soares u8 hcnt, lcnt; 5291dd728f5SVitor Soares 5301dd728f5SVitor Soares core_rate = clk_get_rate(master->core_clk); 5311dd728f5SVitor Soares if (!core_rate) 5321dd728f5SVitor Soares return -EINVAL; 5331dd728f5SVitor Soares 5341dd728f5SVitor Soares core_period = DIV_ROUND_UP(1000000000, core_rate); 5351dd728f5SVitor Soares 5361dd728f5SVitor Soares hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period) - 1; 5371dd728f5SVitor Soares if (hcnt < SCL_I3C_TIMING_CNT_MIN) 5381dd728f5SVitor Soares hcnt = SCL_I3C_TIMING_CNT_MIN; 5391dd728f5SVitor Soares 540510d2358SJack Chen lcnt = DIV_ROUND_UP(core_rate, master->base.bus.scl_rate.i3c) - hcnt; 5411dd728f5SVitor Soares if (lcnt < SCL_I3C_TIMING_CNT_MIN) 5421dd728f5SVitor Soares lcnt = SCL_I3C_TIMING_CNT_MIN; 5431dd728f5SVitor Soares 5441dd728f5SVitor Soares scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt); 5451dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_I3C_PP_TIMING); 5461dd728f5SVitor Soares 54766b32e3dSJeremy Kerr /* 54866b32e3dSJeremy Kerr * In pure i3c mode, MST_FREE represents tCAS. In shared mode, this 54966b32e3dSJeremy Kerr * will be set up by dw_i2c_clk_cfg as tLOW. 55066b32e3dSJeremy Kerr */ 55166b32e3dSJeremy Kerr if (master->base.bus.mode == I3C_BUS_MODE_PURE) 5521dd728f5SVitor Soares writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING); 5531dd728f5SVitor Soares 554510d2358SJack Chen lcnt = max_t(u8, 555510d2358SJack Chen DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period), lcnt); 5561dd728f5SVitor Soares scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt); 5571dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_I3C_OD_TIMING); 5581dd728f5SVitor Soares 5591dd728f5SVitor Soares lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt; 5601dd728f5SVitor Soares scl_timing = SCL_EXT_LCNT_1(lcnt); 5611dd728f5SVitor Soares lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt; 5621dd728f5SVitor Soares scl_timing |= SCL_EXT_LCNT_2(lcnt); 5631dd728f5SVitor Soares lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt; 5641dd728f5SVitor Soares scl_timing |= SCL_EXT_LCNT_3(lcnt); 5651dd728f5SVitor Soares lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt; 5661dd728f5SVitor Soares scl_timing |= SCL_EXT_LCNT_4(lcnt); 5671dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_EXT_LCNT_TIMING); 5681dd728f5SVitor Soares 5691dd728f5SVitor Soares return 0; 5701dd728f5SVitor Soares } 5711dd728f5SVitor Soares 5721dd728f5SVitor Soares static int dw_i2c_clk_cfg(struct dw_i3c_master *master) 5731dd728f5SVitor Soares { 5741dd728f5SVitor Soares unsigned long core_rate, core_period; 5751dd728f5SVitor Soares u16 hcnt, lcnt; 5761dd728f5SVitor Soares u32 scl_timing; 5771dd728f5SVitor Soares 5781dd728f5SVitor Soares core_rate = clk_get_rate(master->core_clk); 5791dd728f5SVitor Soares if (!core_rate) 5801dd728f5SVitor Soares return -EINVAL; 5811dd728f5SVitor Soares 5821dd728f5SVitor Soares core_period = DIV_ROUND_UP(1000000000, core_rate); 5831dd728f5SVitor Soares 5841dd728f5SVitor Soares lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS, core_period); 5851dd728f5SVitor Soares hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt; 5861dd728f5SVitor Soares scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) | 5871dd728f5SVitor Soares SCL_I2C_FMP_TIMING_LCNT(lcnt); 5881dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING); 5891dd728f5SVitor Soares 5901dd728f5SVitor Soares lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS, core_period); 5911dd728f5SVitor Soares hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt; 5921dd728f5SVitor Soares scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) | 5931dd728f5SVitor Soares SCL_I2C_FM_TIMING_LCNT(lcnt); 5941dd728f5SVitor Soares writel(scl_timing, master->regs + SCL_I2C_FM_TIMING); 5951dd728f5SVitor Soares 5961dd728f5SVitor Soares writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING); 5971dd728f5SVitor Soares writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_I2C_SLAVE_PRESENT, 5981dd728f5SVitor Soares master->regs + DEVICE_CTRL); 5991dd728f5SVitor Soares 6001dd728f5SVitor Soares return 0; 6011dd728f5SVitor Soares } 6021dd728f5SVitor Soares 6031dd728f5SVitor Soares static int dw_i3c_master_bus_init(struct i3c_master_controller *m) 6041dd728f5SVitor Soares { 6051dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 6061dd728f5SVitor Soares struct i3c_bus *bus = i3c_master_get_bus(m); 6071dd728f5SVitor Soares struct i3c_device_info info = { }; 6081dd728f5SVitor Soares u32 thld_ctrl; 6091dd728f5SVitor Soares int ret; 6101dd728f5SVitor Soares 611d782188cSJeremy Kerr ret = master->platform_ops->init(master); 612d782188cSJeremy Kerr if (ret) 613d782188cSJeremy Kerr return ret; 614d782188cSJeremy Kerr 6151dd728f5SVitor Soares switch (bus->mode) { 6161dd728f5SVitor Soares case I3C_BUS_MODE_MIXED_FAST: 617f467907cSVitor Soares case I3C_BUS_MODE_MIXED_LIMITED: 6181dd728f5SVitor Soares ret = dw_i2c_clk_cfg(master); 6191dd728f5SVitor Soares if (ret) 6201dd728f5SVitor Soares return ret; 621df561f66SGustavo A. R. Silva fallthrough; 6221dd728f5SVitor Soares case I3C_BUS_MODE_PURE: 6231dd728f5SVitor Soares ret = dw_i3c_clk_cfg(master); 6241dd728f5SVitor Soares if (ret) 6251dd728f5SVitor Soares return ret; 6261dd728f5SVitor Soares break; 6271dd728f5SVitor Soares default: 6281dd728f5SVitor Soares return -EINVAL; 6291dd728f5SVitor Soares } 6301dd728f5SVitor Soares 6311dd728f5SVitor Soares thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL); 632*e389b1d7SJeremy Kerr thld_ctrl &= ~(QUEUE_THLD_CTRL_RESP_BUF_MASK | 633*e389b1d7SJeremy Kerr QUEUE_THLD_CTRL_IBI_STAT_MASK | 634*e389b1d7SJeremy Kerr QUEUE_THLD_CTRL_IBI_STAT_MASK); 635*e389b1d7SJeremy Kerr thld_ctrl |= QUEUE_THLD_CTRL_IBI_STAT(1) | 636*e389b1d7SJeremy Kerr QUEUE_THLD_CTRL_IBI_DATA(31); 6371dd728f5SVitor Soares writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL); 6381dd728f5SVitor Soares 6391dd728f5SVitor Soares thld_ctrl = readl(master->regs + DATA_BUFFER_THLD_CTRL); 6401dd728f5SVitor Soares thld_ctrl &= ~DATA_BUFFER_THLD_CTRL_RX_BUF; 6411dd728f5SVitor Soares writel(thld_ctrl, master->regs + DATA_BUFFER_THLD_CTRL); 6421dd728f5SVitor Soares 6431dd728f5SVitor Soares writel(INTR_ALL, master->regs + INTR_STATUS); 6441dd728f5SVitor Soares writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN); 6451dd728f5SVitor Soares writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN); 6461dd728f5SVitor Soares 6471dd728f5SVitor Soares ret = i3c_master_get_free_addr(m, 0); 6481dd728f5SVitor Soares if (ret < 0) 6491dd728f5SVitor Soares return ret; 6501dd728f5SVitor Soares 6511dd728f5SVitor Soares writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret), 6521dd728f5SVitor Soares master->regs + DEVICE_ADDR); 6531dd728f5SVitor Soares 6541dd728f5SVitor Soares memset(&info, 0, sizeof(info)); 6551dd728f5SVitor Soares info.dyn_addr = ret; 6561dd728f5SVitor Soares 6571dd728f5SVitor Soares ret = i3c_master_set_info(&master->base, &info); 6581dd728f5SVitor Soares if (ret) 6591dd728f5SVitor Soares return ret; 6601dd728f5SVitor Soares 6611dd728f5SVitor Soares writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT); 6621dd728f5SVitor Soares writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT); 6631dd728f5SVitor Soares 6641dd728f5SVitor Soares /* For now don't support Hot-Join */ 6651dd728f5SVitor Soares writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK, 6661dd728f5SVitor Soares master->regs + DEVICE_CTRL); 6671dd728f5SVitor Soares 6681dd728f5SVitor Soares dw_i3c_master_enable(master); 6691dd728f5SVitor Soares 6701dd728f5SVitor Soares return 0; 6711dd728f5SVitor Soares } 6721dd728f5SVitor Soares 6731dd728f5SVitor Soares static void dw_i3c_master_bus_cleanup(struct i3c_master_controller *m) 6741dd728f5SVitor Soares { 6751dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 6761dd728f5SVitor Soares 6771dd728f5SVitor Soares dw_i3c_master_disable(master); 6781dd728f5SVitor Soares } 6791dd728f5SVitor Soares 6801dd728f5SVitor Soares static int dw_i3c_ccc_set(struct dw_i3c_master *master, 6811dd728f5SVitor Soares struct i3c_ccc_cmd *ccc) 6821dd728f5SVitor Soares { 6831dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 6841dd728f5SVitor Soares struct dw_i3c_cmd *cmd; 6851dd728f5SVitor Soares int ret, pos = 0; 6861dd728f5SVitor Soares 6871dd728f5SVitor Soares if (ccc->id & I3C_CCC_DIRECT) { 6881dd728f5SVitor Soares pos = dw_i3c_master_get_addr_pos(master, ccc->dests[0].addr); 6891dd728f5SVitor Soares if (pos < 0) 6901dd728f5SVitor Soares return pos; 6911dd728f5SVitor Soares } 6921dd728f5SVitor Soares 6931dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, 1); 6941dd728f5SVitor Soares if (!xfer) 6951dd728f5SVitor Soares return -ENOMEM; 6961dd728f5SVitor Soares 6971dd728f5SVitor Soares cmd = xfer->cmds; 6981dd728f5SVitor Soares cmd->tx_buf = ccc->dests[0].payload.data; 6991dd728f5SVitor Soares cmd->tx_len = ccc->dests[0].payload.len; 7001dd728f5SVitor Soares 7011dd728f5SVitor Soares cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) | 7021dd728f5SVitor Soares COMMAND_PORT_TRANSFER_ARG; 7031dd728f5SVitor Soares 7041dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_CP | 7051dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(pos) | 7061dd728f5SVitor Soares COMMAND_PORT_CMD(ccc->id) | 7071dd728f5SVitor Soares COMMAND_PORT_TOC | 7081dd728f5SVitor Soares COMMAND_PORT_ROC; 7091dd728f5SVitor Soares 7101dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 7111dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 7121dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 7131dd728f5SVitor Soares 7141dd728f5SVitor Soares ret = xfer->ret; 7151dd728f5SVitor Soares if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK) 7161dd728f5SVitor Soares ccc->err = I3C_ERROR_M2; 7171dd728f5SVitor Soares 7181dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 7191dd728f5SVitor Soares 7201dd728f5SVitor Soares return ret; 7211dd728f5SVitor Soares } 7221dd728f5SVitor Soares 7231dd728f5SVitor Soares static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc) 7241dd728f5SVitor Soares { 7251dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 7261dd728f5SVitor Soares struct dw_i3c_cmd *cmd; 7271dd728f5SVitor Soares int ret, pos; 7281dd728f5SVitor Soares 7291dd728f5SVitor Soares pos = dw_i3c_master_get_addr_pos(master, ccc->dests[0].addr); 7301dd728f5SVitor Soares if (pos < 0) 7311dd728f5SVitor Soares return pos; 7321dd728f5SVitor Soares 7331dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, 1); 7341dd728f5SVitor Soares if (!xfer) 7351dd728f5SVitor Soares return -ENOMEM; 7361dd728f5SVitor Soares 7371dd728f5SVitor Soares cmd = xfer->cmds; 7381dd728f5SVitor Soares cmd->rx_buf = ccc->dests[0].payload.data; 7391dd728f5SVitor Soares cmd->rx_len = ccc->dests[0].payload.len; 7401dd728f5SVitor Soares 7411dd728f5SVitor Soares cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) | 7421dd728f5SVitor Soares COMMAND_PORT_TRANSFER_ARG; 7431dd728f5SVitor Soares 7441dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER | 7451dd728f5SVitor Soares COMMAND_PORT_CP | 7461dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(pos) | 7471dd728f5SVitor Soares COMMAND_PORT_CMD(ccc->id) | 7481dd728f5SVitor Soares COMMAND_PORT_TOC | 7491dd728f5SVitor Soares COMMAND_PORT_ROC; 7501dd728f5SVitor Soares 7511dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 7521dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 7531dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 7541dd728f5SVitor Soares 7551dd728f5SVitor Soares ret = xfer->ret; 7561dd728f5SVitor Soares if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK) 7571dd728f5SVitor Soares ccc->err = I3C_ERROR_M2; 7581dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 7591dd728f5SVitor Soares 7601dd728f5SVitor Soares return ret; 7611dd728f5SVitor Soares } 7621dd728f5SVitor Soares 7631dd728f5SVitor Soares static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, 7641dd728f5SVitor Soares struct i3c_ccc_cmd *ccc) 7651dd728f5SVitor Soares { 7661dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 7671dd728f5SVitor Soares int ret = 0; 7681dd728f5SVitor Soares 7691dd728f5SVitor Soares if (ccc->id == I3C_CCC_ENTDAA) 7701dd728f5SVitor Soares return -EINVAL; 7711dd728f5SVitor Soares 7721dd728f5SVitor Soares if (ccc->rnw) 7731dd728f5SVitor Soares ret = dw_i3c_ccc_get(master, ccc); 7741dd728f5SVitor Soares else 7751dd728f5SVitor Soares ret = dw_i3c_ccc_set(master, ccc); 7761dd728f5SVitor Soares 7771dd728f5SVitor Soares return ret; 7781dd728f5SVitor Soares } 7791dd728f5SVitor Soares 7801dd728f5SVitor Soares static int dw_i3c_master_daa(struct i3c_master_controller *m) 7811dd728f5SVitor Soares { 7821dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 7831dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 7841dd728f5SVitor Soares struct dw_i3c_cmd *cmd; 7851dd728f5SVitor Soares u32 olddevs, newdevs; 7861dd728f5SVitor Soares u8 p, last_addr = 0; 7871dd728f5SVitor Soares int ret, pos; 7881dd728f5SVitor Soares 7891dd728f5SVitor Soares olddevs = ~(master->free_pos); 7901dd728f5SVitor Soares 7911dd728f5SVitor Soares /* Prepare DAT before launching DAA. */ 7921dd728f5SVitor Soares for (pos = 0; pos < master->maxdevs; pos++) { 7931dd728f5SVitor Soares if (olddevs & BIT(pos)) 7941dd728f5SVitor Soares continue; 7951dd728f5SVitor Soares 7961dd728f5SVitor Soares ret = i3c_master_get_free_addr(m, last_addr + 1); 7971dd728f5SVitor Soares if (ret < 0) 7981dd728f5SVitor Soares return -ENOSPC; 7991dd728f5SVitor Soares 800e2d43101SJeremy Kerr master->devs[pos].addr = ret; 8011dd728f5SVitor Soares p = even_parity(ret); 8021dd728f5SVitor Soares last_addr = ret; 8031dd728f5SVitor Soares ret |= (p << 7); 8041dd728f5SVitor Soares 8051dd728f5SVitor Soares writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(ret), 8061dd728f5SVitor Soares master->regs + 8071dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, pos)); 8081dd728f5SVitor Soares } 8091dd728f5SVitor Soares 8101dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, 1); 8111dd728f5SVitor Soares if (!xfer) 8121dd728f5SVitor Soares return -ENOMEM; 8131dd728f5SVitor Soares 8141dd728f5SVitor Soares pos = dw_i3c_master_get_free_pos(master); 81513462ba1STom Rix if (pos < 0) { 81613462ba1STom Rix dw_i3c_master_free_xfer(xfer); 81713462ba1STom Rix return pos; 81813462ba1STom Rix } 8191dd728f5SVitor Soares cmd = &xfer->cmds[0]; 8201dd728f5SVitor Soares cmd->cmd_hi = 0x1; 8211dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_DEV_COUNT(master->maxdevs - pos) | 8221dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(pos) | 8231dd728f5SVitor Soares COMMAND_PORT_CMD(I3C_CCC_ENTDAA) | 8241dd728f5SVitor Soares COMMAND_PORT_ADDR_ASSGN_CMD | 8251dd728f5SVitor Soares COMMAND_PORT_TOC | 8261dd728f5SVitor Soares COMMAND_PORT_ROC; 8271dd728f5SVitor Soares 8281dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 8291dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 8301dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 8311dd728f5SVitor Soares 8321dd728f5SVitor Soares newdevs = GENMASK(master->maxdevs - cmd->rx_len - 1, 0); 8331dd728f5SVitor Soares newdevs &= ~olddevs; 8341dd728f5SVitor Soares 8351dd728f5SVitor Soares for (pos = 0; pos < master->maxdevs; pos++) { 8361dd728f5SVitor Soares if (newdevs & BIT(pos)) 837e2d43101SJeremy Kerr i3c_master_add_i3c_dev_locked(m, master->devs[pos].addr); 8381dd728f5SVitor Soares } 8391dd728f5SVitor Soares 8401dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 8411dd728f5SVitor Soares 8421dd728f5SVitor Soares return 0; 8431dd728f5SVitor Soares } 8441dd728f5SVitor Soares 8451dd728f5SVitor Soares static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, 8461dd728f5SVitor Soares struct i3c_priv_xfer *i3c_xfers, 8471dd728f5SVitor Soares int i3c_nxfers) 8481dd728f5SVitor Soares { 8491dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 8501dd728f5SVitor Soares struct i3c_master_controller *m = i3c_dev_get_master(dev); 8511dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 8521dd728f5SVitor Soares unsigned int nrxwords = 0, ntxwords = 0; 8531dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 8541dd728f5SVitor Soares int i, ret = 0; 8551dd728f5SVitor Soares 8561dd728f5SVitor Soares if (!i3c_nxfers) 8571dd728f5SVitor Soares return 0; 8581dd728f5SVitor Soares 8591dd728f5SVitor Soares if (i3c_nxfers > master->caps.cmdfifodepth) 8601dd728f5SVitor Soares return -ENOTSUPP; 8611dd728f5SVitor Soares 8621dd728f5SVitor Soares for (i = 0; i < i3c_nxfers; i++) { 8631dd728f5SVitor Soares if (i3c_xfers[i].rnw) 8641dd728f5SVitor Soares nrxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4); 8651dd728f5SVitor Soares else 8661dd728f5SVitor Soares ntxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4); 8671dd728f5SVitor Soares } 8681dd728f5SVitor Soares 8691dd728f5SVitor Soares if (ntxwords > master->caps.datafifodepth || 8701dd728f5SVitor Soares nrxwords > master->caps.datafifodepth) 8711dd728f5SVitor Soares return -ENOTSUPP; 8721dd728f5SVitor Soares 8731dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers); 8741dd728f5SVitor Soares if (!xfer) 8751dd728f5SVitor Soares return -ENOMEM; 8761dd728f5SVitor Soares 8771dd728f5SVitor Soares for (i = 0; i < i3c_nxfers; i++) { 8781dd728f5SVitor Soares struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 8791dd728f5SVitor Soares 8801dd728f5SVitor Soares cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i3c_xfers[i].len) | 8811dd728f5SVitor Soares COMMAND_PORT_TRANSFER_ARG; 8821dd728f5SVitor Soares 8831dd728f5SVitor Soares if (i3c_xfers[i].rnw) { 8841dd728f5SVitor Soares cmd->rx_buf = i3c_xfers[i].data.in; 8851dd728f5SVitor Soares cmd->rx_len = i3c_xfers[i].len; 8861dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER | 8871dd728f5SVitor Soares COMMAND_PORT_SPEED(dev->info.max_read_ds); 8881dd728f5SVitor Soares 8891dd728f5SVitor Soares } else { 8901dd728f5SVitor Soares cmd->tx_buf = i3c_xfers[i].data.out; 8911dd728f5SVitor Soares cmd->tx_len = i3c_xfers[i].len; 8921dd728f5SVitor Soares cmd->cmd_lo = 8931dd728f5SVitor Soares COMMAND_PORT_SPEED(dev->info.max_write_ds); 8941dd728f5SVitor Soares } 8951dd728f5SVitor Soares 8961dd728f5SVitor Soares cmd->cmd_lo |= COMMAND_PORT_TID(i) | 8971dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(data->index) | 8981dd728f5SVitor Soares COMMAND_PORT_ROC; 8991dd728f5SVitor Soares 9001dd728f5SVitor Soares if (i == (i3c_nxfers - 1)) 9011dd728f5SVitor Soares cmd->cmd_lo |= COMMAND_PORT_TOC; 9021dd728f5SVitor Soares } 9031dd728f5SVitor Soares 9041dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 9051dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 9061dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 9071dd728f5SVitor Soares 90867df5ce9SMatt Johnston for (i = 0; i < i3c_nxfers; i++) { 90967df5ce9SMatt Johnston struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 91067df5ce9SMatt Johnston 91167df5ce9SMatt Johnston if (i3c_xfers[i].rnw) 91267df5ce9SMatt Johnston i3c_xfers[i].len = cmd->rx_len; 91367df5ce9SMatt Johnston } 91467df5ce9SMatt Johnston 9151dd728f5SVitor Soares ret = xfer->ret; 9161dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 9171dd728f5SVitor Soares 9181dd728f5SVitor Soares return ret; 9191dd728f5SVitor Soares } 9201dd728f5SVitor Soares 9211dd728f5SVitor Soares static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, 9221dd728f5SVitor Soares u8 old_dyn_addr) 9231dd728f5SVitor Soares { 9241dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 9251dd728f5SVitor Soares struct i3c_master_controller *m = i3c_dev_get_master(dev); 9261dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 9273952cf8fSVitor Soares int pos; 9283952cf8fSVitor Soares 9293952cf8fSVitor Soares pos = dw_i3c_master_get_free_pos(master); 9303952cf8fSVitor Soares 9313952cf8fSVitor Soares if (data->index > pos && pos > 0) { 9323952cf8fSVitor Soares writel(0, 9333952cf8fSVitor Soares master->regs + 9343952cf8fSVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 9353952cf8fSVitor Soares 936e2d43101SJeremy Kerr master->devs[data->index].addr = 0; 9373952cf8fSVitor Soares master->free_pos |= BIT(data->index); 9383952cf8fSVitor Soares 9393952cf8fSVitor Soares data->index = pos; 940e2d43101SJeremy Kerr master->devs[pos].addr = dev->info.dyn_addr; 9413952cf8fSVitor Soares master->free_pos &= ~BIT(pos); 9423952cf8fSVitor Soares } 9431dd728f5SVitor Soares 9441dd728f5SVitor Soares writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr), 9451dd728f5SVitor Soares master->regs + 9461dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 9471dd728f5SVitor Soares 948e2d43101SJeremy Kerr master->devs[data->index].addr = dev->info.dyn_addr; 9491dd728f5SVitor Soares 9501dd728f5SVitor Soares return 0; 9511dd728f5SVitor Soares } 9521dd728f5SVitor Soares 9531dd728f5SVitor Soares static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev) 9541dd728f5SVitor Soares { 9551dd728f5SVitor Soares struct i3c_master_controller *m = i3c_dev_get_master(dev); 9561dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 9571dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data; 9581dd728f5SVitor Soares int pos; 9591dd728f5SVitor Soares 9601dd728f5SVitor Soares pos = dw_i3c_master_get_free_pos(master); 9611dd728f5SVitor Soares if (pos < 0) 9621dd728f5SVitor Soares return pos; 9631dd728f5SVitor Soares 9641dd728f5SVitor Soares data = kzalloc(sizeof(*data), GFP_KERNEL); 9651dd728f5SVitor Soares if (!data) 9661dd728f5SVitor Soares return -ENOMEM; 9671dd728f5SVitor Soares 9681dd728f5SVitor Soares data->index = pos; 969e2d43101SJeremy Kerr master->devs[pos].addr = dev->info.dyn_addr ? : dev->info.static_addr; 9701dd728f5SVitor Soares master->free_pos &= ~BIT(pos); 9711dd728f5SVitor Soares i3c_dev_set_master_data(dev, data); 9721dd728f5SVitor Soares 973e2d43101SJeremy Kerr writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr), 9741dd728f5SVitor Soares master->regs + 9751dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 9761dd728f5SVitor Soares 9771dd728f5SVitor Soares return 0; 9781dd728f5SVitor Soares } 9791dd728f5SVitor Soares 9801dd728f5SVitor Soares static void dw_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev) 9811dd728f5SVitor Soares { 9821dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 9831dd728f5SVitor Soares struct i3c_master_controller *m = i3c_dev_get_master(dev); 9841dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 9851dd728f5SVitor Soares 9861dd728f5SVitor Soares writel(0, 9871dd728f5SVitor Soares master->regs + 9881dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 9891dd728f5SVitor Soares 9901dd728f5SVitor Soares i3c_dev_set_master_data(dev, NULL); 991e2d43101SJeremy Kerr master->devs[data->index].addr = 0; 9921dd728f5SVitor Soares master->free_pos |= BIT(data->index); 9931dd728f5SVitor Soares kfree(data); 9941dd728f5SVitor Soares } 9951dd728f5SVitor Soares 9961dd728f5SVitor Soares static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, 9971dd728f5SVitor Soares const struct i2c_msg *i2c_xfers, 9981dd728f5SVitor Soares int i2c_nxfers) 9991dd728f5SVitor Soares { 10001dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); 10011dd728f5SVitor Soares struct i3c_master_controller *m = i2c_dev_get_master(dev); 10021dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 10031dd728f5SVitor Soares unsigned int nrxwords = 0, ntxwords = 0; 10041dd728f5SVitor Soares struct dw_i3c_xfer *xfer; 10051dd728f5SVitor Soares int i, ret = 0; 10061dd728f5SVitor Soares 10071dd728f5SVitor Soares if (!i2c_nxfers) 10081dd728f5SVitor Soares return 0; 10091dd728f5SVitor Soares 10101dd728f5SVitor Soares if (i2c_nxfers > master->caps.cmdfifodepth) 10111dd728f5SVitor Soares return -ENOTSUPP; 10121dd728f5SVitor Soares 10131dd728f5SVitor Soares for (i = 0; i < i2c_nxfers; i++) { 10141dd728f5SVitor Soares if (i2c_xfers[i].flags & I2C_M_RD) 10151dd728f5SVitor Soares nrxwords += DIV_ROUND_UP(i2c_xfers[i].len, 4); 10161dd728f5SVitor Soares else 10171dd728f5SVitor Soares ntxwords += DIV_ROUND_UP(i2c_xfers[i].len, 4); 10181dd728f5SVitor Soares } 10191dd728f5SVitor Soares 10201dd728f5SVitor Soares if (ntxwords > master->caps.datafifodepth || 10211dd728f5SVitor Soares nrxwords > master->caps.datafifodepth) 10221dd728f5SVitor Soares return -ENOTSUPP; 10231dd728f5SVitor Soares 10241dd728f5SVitor Soares xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers); 10251dd728f5SVitor Soares if (!xfer) 10261dd728f5SVitor Soares return -ENOMEM; 10271dd728f5SVitor Soares 10281dd728f5SVitor Soares for (i = 0; i < i2c_nxfers; i++) { 10291dd728f5SVitor Soares struct dw_i3c_cmd *cmd = &xfer->cmds[i]; 10301dd728f5SVitor Soares 10311dd728f5SVitor Soares cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i2c_xfers[i].len) | 10321dd728f5SVitor Soares COMMAND_PORT_TRANSFER_ARG; 10331dd728f5SVitor Soares 10341dd728f5SVitor Soares cmd->cmd_lo = COMMAND_PORT_TID(i) | 10351dd728f5SVitor Soares COMMAND_PORT_DEV_INDEX(data->index) | 10361dd728f5SVitor Soares COMMAND_PORT_ROC; 10371dd728f5SVitor Soares 10381dd728f5SVitor Soares if (i2c_xfers[i].flags & I2C_M_RD) { 10391dd728f5SVitor Soares cmd->cmd_lo |= COMMAND_PORT_READ_TRANSFER; 10401dd728f5SVitor Soares cmd->rx_buf = i2c_xfers[i].buf; 10411dd728f5SVitor Soares cmd->rx_len = i2c_xfers[i].len; 10421dd728f5SVitor Soares } else { 10431dd728f5SVitor Soares cmd->tx_buf = i2c_xfers[i].buf; 10441dd728f5SVitor Soares cmd->tx_len = i2c_xfers[i].len; 10451dd728f5SVitor Soares } 10461dd728f5SVitor Soares 10471dd728f5SVitor Soares if (i == (i2c_nxfers - 1)) 10481dd728f5SVitor Soares cmd->cmd_lo |= COMMAND_PORT_TOC; 10491dd728f5SVitor Soares } 10501dd728f5SVitor Soares 10511dd728f5SVitor Soares dw_i3c_master_enqueue_xfer(master, xfer); 10521dd728f5SVitor Soares if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 10531dd728f5SVitor Soares dw_i3c_master_dequeue_xfer(master, xfer); 10541dd728f5SVitor Soares 10551dd728f5SVitor Soares ret = xfer->ret; 10561dd728f5SVitor Soares dw_i3c_master_free_xfer(xfer); 10571dd728f5SVitor Soares 10581dd728f5SVitor Soares return ret; 10591dd728f5SVitor Soares } 10601dd728f5SVitor Soares 10611dd728f5SVitor Soares static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) 10621dd728f5SVitor Soares { 10631dd728f5SVitor Soares struct i3c_master_controller *m = i2c_dev_get_master(dev); 10641dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 10651dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data; 10661dd728f5SVitor Soares int pos; 10671dd728f5SVitor Soares 10681dd728f5SVitor Soares pos = dw_i3c_master_get_free_pos(master); 10691dd728f5SVitor Soares if (pos < 0) 10701dd728f5SVitor Soares return pos; 10711dd728f5SVitor Soares 10721dd728f5SVitor Soares data = kzalloc(sizeof(*data), GFP_KERNEL); 10731dd728f5SVitor Soares if (!data) 10741dd728f5SVitor Soares return -ENOMEM; 10751dd728f5SVitor Soares 10761dd728f5SVitor Soares data->index = pos; 1077e2d43101SJeremy Kerr master->devs[pos].addr = dev->addr; 10781dd728f5SVitor Soares master->free_pos &= ~BIT(pos); 10791dd728f5SVitor Soares i2c_dev_set_master_data(dev, data); 10801dd728f5SVitor Soares 10811dd728f5SVitor Soares writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV | 1082b1ac3a4bSPrzemyslaw Gaj DEV_ADDR_TABLE_STATIC_ADDR(dev->addr), 10831dd728f5SVitor Soares master->regs + 10841dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 10851dd728f5SVitor Soares 10861dd728f5SVitor Soares return 0; 10871dd728f5SVitor Soares } 10881dd728f5SVitor Soares 10891dd728f5SVitor Soares static void dw_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) 10901dd728f5SVitor Soares { 10911dd728f5SVitor Soares struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); 10921dd728f5SVitor Soares struct i3c_master_controller *m = i2c_dev_get_master(dev); 10931dd728f5SVitor Soares struct dw_i3c_master *master = to_dw_i3c_master(m); 10941dd728f5SVitor Soares 10951dd728f5SVitor Soares writel(0, 10961dd728f5SVitor Soares master->regs + 10971dd728f5SVitor Soares DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); 10981dd728f5SVitor Soares 10991dd728f5SVitor Soares i2c_dev_set_master_data(dev, NULL); 1100e2d43101SJeremy Kerr master->devs[data->index].addr = 0; 11011dd728f5SVitor Soares master->free_pos |= BIT(data->index); 11021dd728f5SVitor Soares kfree(data); 11031dd728f5SVitor Soares } 11041dd728f5SVitor Soares 1105*e389b1d7SJeremy Kerr static int dw_i3c_master_request_ibi(struct i3c_dev_desc *dev, 1106*e389b1d7SJeremy Kerr const struct i3c_ibi_setup *req) 1107*e389b1d7SJeremy Kerr { 1108*e389b1d7SJeremy Kerr struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 1109*e389b1d7SJeremy Kerr struct i3c_master_controller *m = i3c_dev_get_master(dev); 1110*e389b1d7SJeremy Kerr struct dw_i3c_master *master = to_dw_i3c_master(m); 1111*e389b1d7SJeremy Kerr unsigned long flags; 1112*e389b1d7SJeremy Kerr 1113*e389b1d7SJeremy Kerr data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req); 1114*e389b1d7SJeremy Kerr if (IS_ERR(data->ibi_pool)) 1115*e389b1d7SJeremy Kerr return PTR_ERR(data->ibi_pool); 1116*e389b1d7SJeremy Kerr 1117*e389b1d7SJeremy Kerr spin_lock_irqsave(&master->devs_lock, flags); 1118*e389b1d7SJeremy Kerr master->devs[data->index].ibi_dev = dev; 1119*e389b1d7SJeremy Kerr spin_unlock_irqrestore(&master->devs_lock, flags); 1120*e389b1d7SJeremy Kerr 1121*e389b1d7SJeremy Kerr return 0; 1122*e389b1d7SJeremy Kerr } 1123*e389b1d7SJeremy Kerr 1124*e389b1d7SJeremy Kerr static void dw_i3c_master_free_ibi(struct i3c_dev_desc *dev) 1125*e389b1d7SJeremy Kerr { 1126*e389b1d7SJeremy Kerr struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 1127*e389b1d7SJeremy Kerr struct i3c_master_controller *m = i3c_dev_get_master(dev); 1128*e389b1d7SJeremy Kerr struct dw_i3c_master *master = to_dw_i3c_master(m); 1129*e389b1d7SJeremy Kerr unsigned long flags; 1130*e389b1d7SJeremy Kerr 1131*e389b1d7SJeremy Kerr spin_lock_irqsave(&master->devs_lock, flags); 1132*e389b1d7SJeremy Kerr master->devs[data->index].ibi_dev = NULL; 1133*e389b1d7SJeremy Kerr spin_unlock_irqrestore(&master->devs_lock, flags); 1134*e389b1d7SJeremy Kerr 1135*e389b1d7SJeremy Kerr i3c_generic_ibi_free_pool(data->ibi_pool); 1136*e389b1d7SJeremy Kerr data->ibi_pool = NULL; 1137*e389b1d7SJeremy Kerr } 1138*e389b1d7SJeremy Kerr 1139*e389b1d7SJeremy Kerr static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master, 1140*e389b1d7SJeremy Kerr struct i3c_dev_desc *dev, 1141*e389b1d7SJeremy Kerr u8 idx, bool enable) 1142*e389b1d7SJeremy Kerr { 1143*e389b1d7SJeremy Kerr unsigned long flags; 1144*e389b1d7SJeremy Kerr u32 dat_entry, reg; 1145*e389b1d7SJeremy Kerr bool global; 1146*e389b1d7SJeremy Kerr 1147*e389b1d7SJeremy Kerr dat_entry = DEV_ADDR_TABLE_LOC(master->datstartaddr, idx); 1148*e389b1d7SJeremy Kerr 1149*e389b1d7SJeremy Kerr spin_lock_irqsave(&master->devs_lock, flags); 1150*e389b1d7SJeremy Kerr reg = readl(master->regs + dat_entry); 1151*e389b1d7SJeremy Kerr if (enable) { 1152*e389b1d7SJeremy Kerr reg &= ~DEV_ADDR_TABLE_SIR_REJECT; 1153*e389b1d7SJeremy Kerr if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) 1154*e389b1d7SJeremy Kerr reg |= DEV_ADDR_TABLE_IBI_MDB; 1155*e389b1d7SJeremy Kerr } else { 1156*e389b1d7SJeremy Kerr reg |= DEV_ADDR_TABLE_SIR_REJECT; 1157*e389b1d7SJeremy Kerr } 1158*e389b1d7SJeremy Kerr writel(reg, master->regs + dat_entry); 1159*e389b1d7SJeremy Kerr 1160*e389b1d7SJeremy Kerr reg = readl(master->regs + IBI_SIR_REQ_REJECT); 1161*e389b1d7SJeremy Kerr if (enable) { 1162*e389b1d7SJeremy Kerr global = reg == 0xffffffff; 1163*e389b1d7SJeremy Kerr reg &= ~BIT(idx); 1164*e389b1d7SJeremy Kerr } else { 1165*e389b1d7SJeremy Kerr global = reg == 0; 1166*e389b1d7SJeremy Kerr reg |= BIT(idx); 1167*e389b1d7SJeremy Kerr } 1168*e389b1d7SJeremy Kerr writel(reg, master->regs + IBI_SIR_REQ_REJECT); 1169*e389b1d7SJeremy Kerr 1170*e389b1d7SJeremy Kerr if (global) { 1171*e389b1d7SJeremy Kerr reg = readl(master->regs + INTR_STATUS_EN); 1172*e389b1d7SJeremy Kerr reg &= ~INTR_IBI_THLD_STAT; 1173*e389b1d7SJeremy Kerr if (enable) 1174*e389b1d7SJeremy Kerr reg |= INTR_IBI_THLD_STAT; 1175*e389b1d7SJeremy Kerr writel(reg, master->regs + INTR_STATUS_EN); 1176*e389b1d7SJeremy Kerr 1177*e389b1d7SJeremy Kerr reg = readl(master->regs + INTR_SIGNAL_EN); 1178*e389b1d7SJeremy Kerr reg &= ~INTR_IBI_THLD_STAT; 1179*e389b1d7SJeremy Kerr if (enable) 1180*e389b1d7SJeremy Kerr reg |= INTR_IBI_THLD_STAT; 1181*e389b1d7SJeremy Kerr writel(reg, master->regs + INTR_SIGNAL_EN); 1182*e389b1d7SJeremy Kerr } 1183*e389b1d7SJeremy Kerr 1184*e389b1d7SJeremy Kerr spin_unlock_irqrestore(&master->devs_lock, flags); 1185*e389b1d7SJeremy Kerr } 1186*e389b1d7SJeremy Kerr 1187*e389b1d7SJeremy Kerr static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev) 1188*e389b1d7SJeremy Kerr { 1189*e389b1d7SJeremy Kerr struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 1190*e389b1d7SJeremy Kerr struct i3c_master_controller *m = i3c_dev_get_master(dev); 1191*e389b1d7SJeremy Kerr struct dw_i3c_master *master = to_dw_i3c_master(m); 1192*e389b1d7SJeremy Kerr int rc; 1193*e389b1d7SJeremy Kerr 1194*e389b1d7SJeremy Kerr dw_i3c_master_set_sir_enabled(master, dev, data->index, true); 1195*e389b1d7SJeremy Kerr 1196*e389b1d7SJeremy Kerr rc = i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); 1197*e389b1d7SJeremy Kerr 1198*e389b1d7SJeremy Kerr if (rc) 1199*e389b1d7SJeremy Kerr dw_i3c_master_set_sir_enabled(master, dev, data->index, false); 1200*e389b1d7SJeremy Kerr 1201*e389b1d7SJeremy Kerr return rc; 1202*e389b1d7SJeremy Kerr } 1203*e389b1d7SJeremy Kerr 1204*e389b1d7SJeremy Kerr static int dw_i3c_master_disable_ibi(struct i3c_dev_desc *dev) 1205*e389b1d7SJeremy Kerr { 1206*e389b1d7SJeremy Kerr struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 1207*e389b1d7SJeremy Kerr struct i3c_master_controller *m = i3c_dev_get_master(dev); 1208*e389b1d7SJeremy Kerr struct dw_i3c_master *master = to_dw_i3c_master(m); 1209*e389b1d7SJeremy Kerr int rc; 1210*e389b1d7SJeremy Kerr 1211*e389b1d7SJeremy Kerr rc = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); 1212*e389b1d7SJeremy Kerr if (rc) 1213*e389b1d7SJeremy Kerr return rc; 1214*e389b1d7SJeremy Kerr 1215*e389b1d7SJeremy Kerr dw_i3c_master_set_sir_enabled(master, dev, data->index, false); 1216*e389b1d7SJeremy Kerr 1217*e389b1d7SJeremy Kerr return 0; 1218*e389b1d7SJeremy Kerr } 1219*e389b1d7SJeremy Kerr 1220*e389b1d7SJeremy Kerr static void dw_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev, 1221*e389b1d7SJeremy Kerr struct i3c_ibi_slot *slot) 1222*e389b1d7SJeremy Kerr { 1223*e389b1d7SJeremy Kerr struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 1224*e389b1d7SJeremy Kerr 1225*e389b1d7SJeremy Kerr i3c_generic_ibi_recycle_slot(data->ibi_pool, slot); 1226*e389b1d7SJeremy Kerr } 1227*e389b1d7SJeremy Kerr 1228*e389b1d7SJeremy Kerr static void dw_i3c_master_drain_ibi_queue(struct dw_i3c_master *master, 1229*e389b1d7SJeremy Kerr int len) 1230*e389b1d7SJeremy Kerr { 1231*e389b1d7SJeremy Kerr int i; 1232*e389b1d7SJeremy Kerr 1233*e389b1d7SJeremy Kerr for (i = 0; i < DIV_ROUND_UP(len, 4); i++) 1234*e389b1d7SJeremy Kerr readl(master->regs + IBI_QUEUE_STATUS); 1235*e389b1d7SJeremy Kerr } 1236*e389b1d7SJeremy Kerr 1237*e389b1d7SJeremy Kerr static void dw_i3c_master_handle_ibi_sir(struct dw_i3c_master *master, 1238*e389b1d7SJeremy Kerr u32 status) 1239*e389b1d7SJeremy Kerr { 1240*e389b1d7SJeremy Kerr struct dw_i3c_i2c_dev_data *data; 1241*e389b1d7SJeremy Kerr struct i3c_ibi_slot *slot; 1242*e389b1d7SJeremy Kerr struct i3c_dev_desc *dev; 1243*e389b1d7SJeremy Kerr unsigned long flags; 1244*e389b1d7SJeremy Kerr u8 addr, len; 1245*e389b1d7SJeremy Kerr int idx; 1246*e389b1d7SJeremy Kerr 1247*e389b1d7SJeremy Kerr addr = IBI_QUEUE_IBI_ADDR(status); 1248*e389b1d7SJeremy Kerr len = IBI_QUEUE_STATUS_DATA_LEN(status); 1249*e389b1d7SJeremy Kerr 1250*e389b1d7SJeremy Kerr spin_lock_irqsave(&master->devs_lock, flags); 1251*e389b1d7SJeremy Kerr idx = dw_i3c_master_get_addr_pos(master, addr); 1252*e389b1d7SJeremy Kerr if (idx < 0) { 1253*e389b1d7SJeremy Kerr dev_dbg_ratelimited(&master->base.dev, 1254*e389b1d7SJeremy Kerr "IBI from unknown addr 0x%x\n", addr); 1255*e389b1d7SJeremy Kerr goto err_drain; 1256*e389b1d7SJeremy Kerr } 1257*e389b1d7SJeremy Kerr 1258*e389b1d7SJeremy Kerr dev = master->devs[idx].ibi_dev; 1259*e389b1d7SJeremy Kerr if (!dev || !dev->ibi) { 1260*e389b1d7SJeremy Kerr dev_dbg_ratelimited(&master->base.dev, 1261*e389b1d7SJeremy Kerr "IBI from non-requested dev idx %d\n", idx); 1262*e389b1d7SJeremy Kerr goto err_drain; 1263*e389b1d7SJeremy Kerr } 1264*e389b1d7SJeremy Kerr 1265*e389b1d7SJeremy Kerr data = i3c_dev_get_master_data(dev); 1266*e389b1d7SJeremy Kerr slot = i3c_generic_ibi_get_free_slot(data->ibi_pool); 1267*e389b1d7SJeremy Kerr if (!slot) { 1268*e389b1d7SJeremy Kerr dev_dbg_ratelimited(&master->base.dev, 1269*e389b1d7SJeremy Kerr "No IBI slots available\n"); 1270*e389b1d7SJeremy Kerr goto err_drain; 1271*e389b1d7SJeremy Kerr } 1272*e389b1d7SJeremy Kerr 1273*e389b1d7SJeremy Kerr if (dev->ibi->max_payload_len < len) { 1274*e389b1d7SJeremy Kerr dev_dbg_ratelimited(&master->base.dev, 1275*e389b1d7SJeremy Kerr "IBI payload len %d greater than max %d\n", 1276*e389b1d7SJeremy Kerr len, dev->ibi->max_payload_len); 1277*e389b1d7SJeremy Kerr goto err_drain; 1278*e389b1d7SJeremy Kerr } 1279*e389b1d7SJeremy Kerr 1280*e389b1d7SJeremy Kerr if (len) { 1281*e389b1d7SJeremy Kerr dw_i3c_master_read_ibi_fifo(master, slot->data, len); 1282*e389b1d7SJeremy Kerr slot->len = len; 1283*e389b1d7SJeremy Kerr } 1284*e389b1d7SJeremy Kerr i3c_master_queue_ibi(dev, slot); 1285*e389b1d7SJeremy Kerr 1286*e389b1d7SJeremy Kerr spin_unlock_irqrestore(&master->devs_lock, flags); 1287*e389b1d7SJeremy Kerr 1288*e389b1d7SJeremy Kerr return; 1289*e389b1d7SJeremy Kerr 1290*e389b1d7SJeremy Kerr err_drain: 1291*e389b1d7SJeremy Kerr dw_i3c_master_drain_ibi_queue(master, len); 1292*e389b1d7SJeremy Kerr 1293*e389b1d7SJeremy Kerr spin_unlock_irqrestore(&master->devs_lock, flags); 1294*e389b1d7SJeremy Kerr } 1295*e389b1d7SJeremy Kerr 1296*e389b1d7SJeremy Kerr /* "ibis": referring to In-Band Interrupts, and not 1297*e389b1d7SJeremy Kerr * https://en.wikipedia.org/wiki/Australian_white_ibis. The latter should 1298*e389b1d7SJeremy Kerr * not be handled. 1299*e389b1d7SJeremy Kerr */ 1300*e389b1d7SJeremy Kerr static void dw_i3c_master_irq_handle_ibis(struct dw_i3c_master *master) 1301*e389b1d7SJeremy Kerr { 1302*e389b1d7SJeremy Kerr unsigned int i, len, n_ibis; 1303*e389b1d7SJeremy Kerr u32 reg; 1304*e389b1d7SJeremy Kerr 1305*e389b1d7SJeremy Kerr reg = readl(master->regs + QUEUE_STATUS_LEVEL); 1306*e389b1d7SJeremy Kerr n_ibis = QUEUE_STATUS_IBI_STATUS_CNT(reg); 1307*e389b1d7SJeremy Kerr if (!n_ibis) 1308*e389b1d7SJeremy Kerr return; 1309*e389b1d7SJeremy Kerr 1310*e389b1d7SJeremy Kerr for (i = 0; i < n_ibis; i++) { 1311*e389b1d7SJeremy Kerr reg = readl(master->regs + IBI_QUEUE_STATUS); 1312*e389b1d7SJeremy Kerr 1313*e389b1d7SJeremy Kerr if (IBI_TYPE_SIRQ(reg)) { 1314*e389b1d7SJeremy Kerr dw_i3c_master_handle_ibi_sir(master, reg); 1315*e389b1d7SJeremy Kerr } else { 1316*e389b1d7SJeremy Kerr len = IBI_QUEUE_STATUS_DATA_LEN(reg); 1317*e389b1d7SJeremy Kerr dev_info(&master->base.dev, 1318*e389b1d7SJeremy Kerr "unsupported IBI type 0x%lx len %d\n", 1319*e389b1d7SJeremy Kerr IBI_QUEUE_STATUS_IBI_ID(reg), len); 1320*e389b1d7SJeremy Kerr dw_i3c_master_drain_ibi_queue(master, len); 1321*e389b1d7SJeremy Kerr } 1322*e389b1d7SJeremy Kerr } 1323*e389b1d7SJeremy Kerr } 1324*e389b1d7SJeremy Kerr 13251dd728f5SVitor Soares static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id) 13261dd728f5SVitor Soares { 13271dd728f5SVitor Soares struct dw_i3c_master *master = dev_id; 13281dd728f5SVitor Soares u32 status; 13291dd728f5SVitor Soares 13301dd728f5SVitor Soares status = readl(master->regs + INTR_STATUS); 13311dd728f5SVitor Soares 13321dd728f5SVitor Soares if (!(status & readl(master->regs + INTR_STATUS_EN))) { 13331dd728f5SVitor Soares writel(INTR_ALL, master->regs + INTR_STATUS); 13341dd728f5SVitor Soares return IRQ_NONE; 13351dd728f5SVitor Soares } 13361dd728f5SVitor Soares 13371dd728f5SVitor Soares spin_lock(&master->xferqueue.lock); 13381dd728f5SVitor Soares dw_i3c_master_end_xfer_locked(master, status); 13392b2b283cSColin Ian King if (status & INTR_TRANSFER_ERR_STAT) 13401dd728f5SVitor Soares writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS); 13411dd728f5SVitor Soares spin_unlock(&master->xferqueue.lock); 13421dd728f5SVitor Soares 1343*e389b1d7SJeremy Kerr if (status & INTR_IBI_THLD_STAT) 1344*e389b1d7SJeremy Kerr dw_i3c_master_irq_handle_ibis(master); 1345*e389b1d7SJeremy Kerr 13461dd728f5SVitor Soares return IRQ_HANDLED; 13471dd728f5SVitor Soares } 13481dd728f5SVitor Soares 13491dd728f5SVitor Soares static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { 13501dd728f5SVitor Soares .bus_init = dw_i3c_master_bus_init, 13511dd728f5SVitor Soares .bus_cleanup = dw_i3c_master_bus_cleanup, 13521dd728f5SVitor Soares .attach_i3c_dev = dw_i3c_master_attach_i3c_dev, 13531dd728f5SVitor Soares .reattach_i3c_dev = dw_i3c_master_reattach_i3c_dev, 13541dd728f5SVitor Soares .detach_i3c_dev = dw_i3c_master_detach_i3c_dev, 13551dd728f5SVitor Soares .do_daa = dw_i3c_master_daa, 13561dd728f5SVitor Soares .supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd, 13571dd728f5SVitor Soares .send_ccc_cmd = dw_i3c_master_send_ccc_cmd, 13581dd728f5SVitor Soares .priv_xfers = dw_i3c_master_priv_xfers, 13591dd728f5SVitor Soares .attach_i2c_dev = dw_i3c_master_attach_i2c_dev, 13601dd728f5SVitor Soares .detach_i2c_dev = dw_i3c_master_detach_i2c_dev, 13611dd728f5SVitor Soares .i2c_xfers = dw_i3c_master_i2c_xfers, 13621dd728f5SVitor Soares }; 13631dd728f5SVitor Soares 1364*e389b1d7SJeremy Kerr static const struct i3c_master_controller_ops dw_mipi_i3c_ibi_ops = { 1365*e389b1d7SJeremy Kerr .bus_init = dw_i3c_master_bus_init, 1366*e389b1d7SJeremy Kerr .bus_cleanup = dw_i3c_master_bus_cleanup, 1367*e389b1d7SJeremy Kerr .attach_i3c_dev = dw_i3c_master_attach_i3c_dev, 1368*e389b1d7SJeremy Kerr .reattach_i3c_dev = dw_i3c_master_reattach_i3c_dev, 1369*e389b1d7SJeremy Kerr .detach_i3c_dev = dw_i3c_master_detach_i3c_dev, 1370*e389b1d7SJeremy Kerr .do_daa = dw_i3c_master_daa, 1371*e389b1d7SJeremy Kerr .supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd, 1372*e389b1d7SJeremy Kerr .send_ccc_cmd = dw_i3c_master_send_ccc_cmd, 1373*e389b1d7SJeremy Kerr .priv_xfers = dw_i3c_master_priv_xfers, 1374*e389b1d7SJeremy Kerr .attach_i2c_dev = dw_i3c_master_attach_i2c_dev, 1375*e389b1d7SJeremy Kerr .detach_i2c_dev = dw_i3c_master_detach_i2c_dev, 1376*e389b1d7SJeremy Kerr .i2c_xfers = dw_i3c_master_i2c_xfers, 1377*e389b1d7SJeremy Kerr .request_ibi = dw_i3c_master_request_ibi, 1378*e389b1d7SJeremy Kerr .free_ibi = dw_i3c_master_free_ibi, 1379*e389b1d7SJeremy Kerr .enable_ibi = dw_i3c_master_enable_ibi, 1380*e389b1d7SJeremy Kerr .disable_ibi = dw_i3c_master_disable_ibi, 1381*e389b1d7SJeremy Kerr .recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot, 1382*e389b1d7SJeremy Kerr }; 1383*e389b1d7SJeremy Kerr 1384d782188cSJeremy Kerr /* default platform ops implementations */ 1385d782188cSJeremy Kerr static int dw_i3c_platform_init_nop(struct dw_i3c_master *i3c) 13861dd728f5SVitor Soares { 1387d782188cSJeremy Kerr return 0; 1388d782188cSJeremy Kerr } 1389d782188cSJeremy Kerr 1390d782188cSJeremy Kerr static const struct dw_i3c_platform_ops dw_i3c_platform_ops_default = { 1391d782188cSJeremy Kerr .init = dw_i3c_platform_init_nop, 1392d782188cSJeremy Kerr }; 1393d782188cSJeremy Kerr 1394d782188cSJeremy Kerr int dw_i3c_common_probe(struct dw_i3c_master *master, 1395d782188cSJeremy Kerr struct platform_device *pdev) 1396d782188cSJeremy Kerr { 1397*e389b1d7SJeremy Kerr const struct i3c_master_controller_ops *ops; 13981dd728f5SVitor Soares int ret, irq; 13991dd728f5SVitor Soares 1400d782188cSJeremy Kerr if (!master->platform_ops) 1401d782188cSJeremy Kerr master->platform_ops = &dw_i3c_platform_ops_default; 14021dd728f5SVitor Soares 1403fae04237SYangtao Li master->regs = devm_platform_ioremap_resource(pdev, 0); 14041dd728f5SVitor Soares if (IS_ERR(master->regs)) 14051dd728f5SVitor Soares return PTR_ERR(master->regs); 14061dd728f5SVitor Soares 14071dd728f5SVitor Soares master->core_clk = devm_clk_get(&pdev->dev, NULL); 14081dd728f5SVitor Soares if (IS_ERR(master->core_clk)) 14091dd728f5SVitor Soares return PTR_ERR(master->core_clk); 14101dd728f5SVitor Soares 14111dd728f5SVitor Soares master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, 14121dd728f5SVitor Soares "core_rst"); 14131dd728f5SVitor Soares if (IS_ERR(master->core_rst)) 14141dd728f5SVitor Soares return PTR_ERR(master->core_rst); 14151dd728f5SVitor Soares 14161dd728f5SVitor Soares ret = clk_prepare_enable(master->core_clk); 14171dd728f5SVitor Soares if (ret) 14181dd728f5SVitor Soares goto err_disable_core_clk; 14191dd728f5SVitor Soares 14201dd728f5SVitor Soares reset_control_deassert(master->core_rst); 14211dd728f5SVitor Soares 14221dd728f5SVitor Soares spin_lock_init(&master->xferqueue.lock); 14231dd728f5SVitor Soares INIT_LIST_HEAD(&master->xferqueue.list); 14241dd728f5SVitor Soares 14251dd728f5SVitor Soares writel(INTR_ALL, master->regs + INTR_STATUS); 14261dd728f5SVitor Soares irq = platform_get_irq(pdev, 0); 14271dd728f5SVitor Soares ret = devm_request_irq(&pdev->dev, irq, 14281dd728f5SVitor Soares dw_i3c_master_irq_handler, 0, 14291dd728f5SVitor Soares dev_name(&pdev->dev), master); 14301dd728f5SVitor Soares if (ret) 14311dd728f5SVitor Soares goto err_assert_rst; 14321dd728f5SVitor Soares 14331dd728f5SVitor Soares platform_set_drvdata(pdev, master); 14341dd728f5SVitor Soares 14351dd728f5SVitor Soares /* Information regarding the FIFOs/QUEUEs depth */ 14361dd728f5SVitor Soares ret = readl(master->regs + QUEUE_STATUS_LEVEL); 14371dd728f5SVitor Soares master->caps.cmdfifodepth = QUEUE_STATUS_LEVEL_CMD(ret); 14381dd728f5SVitor Soares 14391dd728f5SVitor Soares ret = readl(master->regs + DATA_BUFFER_STATUS_LEVEL); 14401dd728f5SVitor Soares master->caps.datafifodepth = DATA_BUFFER_STATUS_LEVEL_TX(ret); 14411dd728f5SVitor Soares 14421dd728f5SVitor Soares ret = readl(master->regs + DEVICE_ADDR_TABLE_POINTER); 14431dd728f5SVitor Soares master->datstartaddr = ret; 14441dd728f5SVitor Soares master->maxdevs = ret >> 16; 14451dd728f5SVitor Soares master->free_pos = GENMASK(master->maxdevs - 1, 0); 14461dd728f5SVitor Soares 1447*e389b1d7SJeremy Kerr ops = &dw_mipi_i3c_ops; 1448*e389b1d7SJeremy Kerr if (master->ibi_capable) 1449*e389b1d7SJeremy Kerr ops = &dw_mipi_i3c_ibi_ops; 1450*e389b1d7SJeremy Kerr 1451*e389b1d7SJeremy Kerr ret = i3c_master_register(&master->base, &pdev->dev, ops, false); 14521dd728f5SVitor Soares if (ret) 14531dd728f5SVitor Soares goto err_assert_rst; 14541dd728f5SVitor Soares 14551dd728f5SVitor Soares return 0; 14561dd728f5SVitor Soares 14571dd728f5SVitor Soares err_assert_rst: 14581dd728f5SVitor Soares reset_control_assert(master->core_rst); 14591dd728f5SVitor Soares 14601dd728f5SVitor Soares err_disable_core_clk: 14611dd728f5SVitor Soares clk_disable_unprepare(master->core_clk); 14621dd728f5SVitor Soares 14631dd728f5SVitor Soares return ret; 14641dd728f5SVitor Soares } 1465d782188cSJeremy Kerr EXPORT_SYMBOL_GPL(dw_i3c_common_probe); 14661dd728f5SVitor Soares 1467d782188cSJeremy Kerr void dw_i3c_common_remove(struct dw_i3c_master *master) 14681dd728f5SVitor Soares { 14690f74f8b6SUwe Kleine-König i3c_master_unregister(&master->base); 14701dd728f5SVitor Soares 14711dd728f5SVitor Soares reset_control_assert(master->core_rst); 14721dd728f5SVitor Soares 14731dd728f5SVitor Soares clk_disable_unprepare(master->core_clk); 14741dd728f5SVitor Soares } 1475d782188cSJeremy Kerr EXPORT_SYMBOL_GPL(dw_i3c_common_remove); 1476d782188cSJeremy Kerr 1477d782188cSJeremy Kerr /* base platform implementation */ 1478d782188cSJeremy Kerr 1479d782188cSJeremy Kerr static int dw_i3c_probe(struct platform_device *pdev) 1480d782188cSJeremy Kerr { 1481d782188cSJeremy Kerr struct dw_i3c_master *master; 1482d782188cSJeremy Kerr 1483d782188cSJeremy Kerr master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); 1484d782188cSJeremy Kerr if (!master) 1485d782188cSJeremy Kerr return -ENOMEM; 1486d782188cSJeremy Kerr 1487d782188cSJeremy Kerr return dw_i3c_common_probe(master, pdev); 1488d782188cSJeremy Kerr } 1489d782188cSJeremy Kerr 1490d782188cSJeremy Kerr static void dw_i3c_remove(struct platform_device *pdev) 1491d782188cSJeremy Kerr { 1492d782188cSJeremy Kerr struct dw_i3c_master *master = platform_get_drvdata(pdev); 1493d782188cSJeremy Kerr 1494d782188cSJeremy Kerr dw_i3c_common_remove(master); 1495d782188cSJeremy Kerr } 14961dd728f5SVitor Soares 14971dd728f5SVitor Soares static const struct of_device_id dw_i3c_master_of_match[] = { 14981dd728f5SVitor Soares { .compatible = "snps,dw-i3c-master-1.00a", }, 14991dd728f5SVitor Soares {}, 15001dd728f5SVitor Soares }; 15011dd728f5SVitor Soares MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match); 15021dd728f5SVitor Soares 15031dd728f5SVitor Soares static struct platform_driver dw_i3c_driver = { 15041dd728f5SVitor Soares .probe = dw_i3c_probe, 150504b5f1beSUwe Kleine-König .remove_new = dw_i3c_remove, 15061dd728f5SVitor Soares .driver = { 15071dd728f5SVitor Soares .name = "dw-i3c-master", 15081dae3f1dSKrzysztof Kozlowski .of_match_table = dw_i3c_master_of_match, 15091dd728f5SVitor Soares }, 15101dd728f5SVitor Soares }; 15111dd728f5SVitor Soares module_platform_driver(dw_i3c_driver); 15121dd728f5SVitor Soares 15131dd728f5SVitor Soares MODULE_AUTHOR("Vitor Soares <vitor.soares@synopsys.com>"); 15141dd728f5SVitor Soares MODULE_DESCRIPTION("DesignWare MIPI I3C driver"); 15151dd728f5SVitor Soares MODULE_LICENSE("GPL v2"); 1516