// SPDX-License-Identifier: GPL-2.0 /* * I3C master driver for the AMD I3C controller. * * Copyright (C) 2026, Advanced Micro Devices, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define XI3C_VERSION_OFFSET 0x00 /* Version Register */ #define XI3C_RESET_OFFSET 0x04 /* Soft Reset Register */ #define XI3C_CR_OFFSET 0x08 /* Control Register */ #define XI3C_ADDRESS_OFFSET 0x0C /* Target Address Register */ #define XI3C_SR_OFFSET 0x10 /* Status Register */ #define XI3C_CMD_FIFO_OFFSET 0x20 /* I3C Command FIFO Register */ #define XI3C_WR_FIFO_OFFSET 0x24 /* I3C Write Data FIFO Register */ #define XI3C_RD_FIFO_OFFSET 0x28 /* I3C Read Data FIFO Register */ #define XI3C_RESP_STATUS_FIFO_OFFSET 0x2C /* I3C Response status FIFO Register */ #define XI3C_FIFO_LVL_STATUS_OFFSET 0x30 /* CMD slots free | WR-FIFO free (words) */ #define XI3C_FIFO_LVL_STATUS_1_OFFSET 0x34 /* RESP fill | RD-FIFO fill level (words) */ #define XI3C_SCL_HIGH_TIME_OFFSET 0x38 /* I3C SCL HIGH Register */ #define XI3C_SCL_LOW_TIME_OFFSET 0x3C /* I3C SCL LOW Register */ #define XI3C_SDA_HOLD_TIME_OFFSET 0x40 /* I3C SDA HOLD Register */ #define XI3C_TSU_START_OFFSET 0x48 /* I3C START SETUP Register */ #define XI3C_THD_START_OFFSET 0x4C /* I3C START HOLD Register */ #define XI3C_TSU_STOP_OFFSET 0x50 /* I3C STOP Setup Register */ #define XI3C_OD_SCL_HIGH_TIME_OFFSET 0x54 /* I3C OD SCL HIGH Register */ #define XI3C_OD_SCL_LOW_TIME_OFFSET 0x58 /* I3C OD SCL LOW Register */ #define XI3C_PID0_OFFSET 0x6C /* LSB 4 bytes of the PID */ #define XI3C_PID1_BCR_DCR 0x70 /* MSB 2 bytes of the PID, BCR and DCR */ #define XI3C_CR_EN_MASK BIT(0) /* Core Enable */ #define XI3C_CR_RESUME_MASK BIT(2) /* Core Resume */ #define XI3C_SR_RESP_NOT_EMPTY_MASK BIT(4) /* Resp Fifo not empty status mask */ #define XI3C_RD_FIFO_NOT_EMPTY_MASK BIT(15) /* Read Fifo not empty status mask */ #define XI3C_BCR_MASK GENMASK(23, 16) #define XI3C_DCR_MASK GENMASK(31, 24) #define XI3C_PID_MASK GENMASK_ULL(63, 16) #define XI3C_TIMING_MASK GENMASK(17, 0) #define XI3C_REV_NUM_MASK GENMASK(15, 8) #define XI3C_PID1_MASK GENMASK(15, 0) #define XI3C_FIFO_LEVEL_MASK GENMASK(15, 0) #define XI3C_RESP_CODE_MASK GENMASK(8, 5) /* Controller response codes; PG439 page 34, Table 46 */ #define XI3C_RESP_CODE_SUCCESS 0 /* Transfer completed OK */ #define XI3C_RESP_CODE_NO_TARGET 2 /* 7E NACK: no target on bus */ #define XI3C_RESP_CODE_NACK 3 /* Target NACK / DAA end */ #define XI3C_RESP_CODE_READ_EARLY_TERM 5 /* Target ended read early (T-bit), short read */ /* xi3c_get_response() private return: read ended early with valid data; resume needed */ #define XI3C_XFER_SHORT_READ 1 #define XI3C_RESP_BYTES_MASK GENMASK(20, 9) /* NUM_BYTES processed */ #define XI3C_ADDR_MASK GENMASK(6, 0) #define XI3C_FIFOS_RST_MASK GENMASK(4, 1) /* Command FIFO word layout (bit ranges encoded in the GENMASK/BIT args) */ #define XI3C_CMD_TYPE GENMASK(3, 0) /* command type */ #define XI3C_CMD_TERMINATE BIT(4) /* terminate (last cmd of xfer) */ #define XI3C_CMD_ADDR GENMASK(15, 8) /* target address << 1 | RnW */ #define XI3C_CMD_LEN GENMASK(27, 16) /* payload length in bytes */ #define XI3C_CMD_TID GENMASK(31, 28) /* transfer ID */ /* tLOW_OD open-drain SCL low; MIPI I3C v1.1.1 Table 74 min 200 ns, 500 ns chosen conservatively */ #define XI3C_OD_TLOW_NS 500 /* Open-drain SCL high (tHIGH) max; MIPI I3C v1.1.1 Table 74 (41 ns) */ #define XI3C_OD_THIGH_NS 41 /* * tSU_STA/tHD_STA/tSU_STO min, 400 kHz/Fm; MIPI I3C v1.1.1 Table 73 * (mixed bus with legacy I2C device) */ #define XI3C_I2C_TCASMIN_NS 600 /* tSU_STA/tHD_STA/tSU_STO min, 1 MHz/Fm+; MIPI I3C v1.1.1 Table 73 (pure I3C bus) */ #define XI3C_TCASMIN_NS 260 /* Max payload per transfer: 12-bit CMD length field (XI3C_CMD_LEN); PG439 page 32, Table 42 */ #define XI3C_MAXDATA_LENGTH 4095 /* Max enumerated devices; PG439 page 27, AXI_I3C_IBI_TARGET_ADDR register detail */ #define XI3C_MAX_DEVS 128 /* DAA target response = 48-bit PID + BCR + DCR = 8 bytes; PG439 page 28 */ #define XI3C_DAA_SLAVEINFO_READ_BYTECOUNT 8 /* * Min SDA hold cycles, rev 0 IP. Revision-specific value, PG439 page 24, * AXI_I3C_SDA_HOLD_TIME register detail */ #define XI3C_THOLD_MIN_REV0 5 /* * Min SDA hold cycles, rev >= 1 IP. Revision-specific value, PG439 page 24, * AXI_I3C_SDA_HOLD_TIME register detail */ #define XI3C_THOLD_MIN_REV1 6 /* * SCL/SDA pre-bias to account for the HW pipeline. PG439 page 24, * AXI_I3C_SDA_HOLD_TIME register detail */ #define XI3C_CYCLE_ADJUST 2 /* Short settling delay so the FIFO reset assert/de-assert takes effect before the FIFOs are used */ #define XI3C_FIFO_RESET_DELAY_US 10 /* * Poll/sleep slice for FIFO and response waits: small enough to stay * responsive, avoids busy-waiting */ #define XI3C_POLL_INTERVAL_US 10 #define XI3C_I2C_MODE 0 #define XI3C_I2C_TID 0 #define XI3C_SDR_MODE 1 #define XI3C_SDR_TID 1 #define XI3C_WORD_LEN 4 /* Software guard: 500 ms (us, for readl_poll_timeout) to bail out if no response word arrives */ #define XI3C_RESP_TIMEOUT_US 500000 /* Software guard: 1 s (ms, for msecs_to_jiffies) to bail out if a transfer never completes */ #define XI3C_XFER_TIMEOUT_MS 1000 struct xi3c_cmd { const void *tx_buf; void *rx_buf; u16 tx_len; u16 rx_len; u16 rx_actual; u8 addr; u8 type; u8 tid; bool rnw; bool is_daa; bool continued; enum i3c_error_code err; }; struct xi3c_xfer { unsigned int ncmds; unsigned int nissued; struct xi3c_cmd cmds[] __counted_by(ncmds); }; /** * struct xi3c_master - I3C master controller state. * @base: I3C master controller embedded by the framework. * @dev: Pointer to the backing device structure. * @membase: Memory base of the HW registers. * @pclk: Input clock driving the controller. * @lock: Serializes transfers and CCC submission. * @daa: ENTDAA enumeration state. * @daa.addrs: Dynamic addresses assigned in enumeration order. * @daa.index: Number of responders enumerated so far. */ struct xi3c_master { struct i3c_master_controller base; struct device *dev; void __iomem *membase; struct clk *pclk; struct mutex lock; /* serializes transfers and CCC submission */ struct { u8 addrs[XI3C_MAX_DEVS]; u8 index; } daa; }; static inline struct xi3c_master * to_xi3c_master(struct i3c_master_controller *master) { return container_of(master, struct xi3c_master, base); } static inline u8 xi3c_get_revision_number(struct xi3c_master *master) { return FIELD_GET(XI3C_REV_NUM_MASK, ioread32(master->membase + XI3C_VERSION_OFFSET)); } static inline u16 xi3c_wr_fifo_level(struct xi3c_master *master) { return ioread32(master->membase + XI3C_FIFO_LVL_STATUS_OFFSET) & XI3C_FIFO_LEVEL_MASK; } static inline u16 xi3c_rd_fifo_level(struct xi3c_master *master) { return ioread32(master->membase + XI3C_FIFO_LVL_STATUS_1_OFFSET) & XI3C_FIFO_LEVEL_MASK; } static inline bool xi3c_is_resp_available(struct xi3c_master *master) { return FIELD_GET(XI3C_SR_RESP_NOT_EMPTY_MASK, ioread32(master->membase + XI3C_SR_OFFSET)); } static int xi3c_get_response(struct xi3c_master *master, struct xi3c_cmd *cmd) { u32 response_data; u32 resp_reg; u8 code; int ret; ret = readl_poll_timeout(master->membase + XI3C_SR_OFFSET, resp_reg, resp_reg & XI3C_SR_RESP_NOT_EMPTY_MASK, XI3C_POLL_INTERVAL_US, XI3C_RESP_TIMEOUT_US); if (ret) { dev_err(master->dev, "XI3C response timeout\n"); return ret; } response_data = ioread32(master->membase + XI3C_RESP_STATUS_FIFO_OFFSET); code = FIELD_GET(XI3C_RESP_CODE_MASK, response_data); switch (code) { case XI3C_RESP_CODE_SUCCESS: cmd->err = I3C_ERROR_UNKNOWN; cmd->rx_actual = FIELD_GET(XI3C_RESP_BYTES_MASK, response_data); return 0; case XI3C_RESP_CODE_READ_EARLY_TERM: /* Short read: valid data, but controller parked in STOP and must be resumed */ cmd->err = I3C_ERROR_UNKNOWN; cmd->rx_actual = FIELD_GET(XI3C_RESP_BYTES_MASK, response_data); return XI3C_XFER_SHORT_READ; case XI3C_RESP_CODE_NO_TARGET: case XI3C_RESP_CODE_NACK: cmd->err = I3C_ERROR_M2; return cmd->is_daa ? -ENODEV : -EIO; default: cmd->err = I3C_ERROR_M0; dev_err(master->dev, "XI3C transfer error, response code %u\n", code); return -EIO; } } static inline void xi3c_writesl_be(void __iomem *addr, const void *buffer, unsigned int count) { const u32 *buf = buffer; while (count--) iowrite32be(get_unaligned(buf++), addr); } static inline void xi3c_readsl_be(const void __iomem *addr, void *buffer, unsigned int count) { u32 *buf = buffer; while (count--) put_unaligned(ioread32be(addr), buf++); } static inline void xi3c_writel_fifo(void __iomem *addr, const void *buf, int nbytes) { xi3c_writesl_be(addr, buf, nbytes / 4); if (nbytes & 3) { u32 tmp = 0; memcpy(&tmp, (const u8 *)buf + (nbytes & ~3), nbytes & 3); xi3c_writesl_be(addr, &tmp, 1); } } static inline void xi3c_readl_fifo(const void __iomem *addr, void *buf, int nbytes) { xi3c_readsl_be(addr, buf, nbytes / 4); if (nbytes & 3) { u32 tmp; xi3c_readsl_be(addr, &tmp, 1); memcpy((u8 *)buf + (nbytes & ~3), &tmp, nbytes & 3); } } static void xi3c_master_write_to_cmdfifo(struct xi3c_master *master, struct xi3c_cmd *cmd, u16 len) { u32 transfer_cmd; u8 addr; addr = ((cmd->addr & XI3C_ADDR_MASK) << 1) | (u8)cmd->rnw; transfer_cmd = FIELD_PREP(XI3C_CMD_TYPE, cmd->type); transfer_cmd |= FIELD_PREP(XI3C_CMD_TERMINATE, !cmd->continued); transfer_cmd |= FIELD_PREP(XI3C_CMD_ADDR, addr); transfer_cmd |= FIELD_PREP(XI3C_CMD_TID, cmd->tid); /* * For dynamic addressing, an additional 1-byte length must be added * to the command FIFO to account for the address present in the TX FIFO */ if (cmd->is_daa) { xi3c_writel_fifo(master->membase + XI3C_WR_FIFO_OFFSET, cmd->tx_buf, cmd->tx_len); len++; } transfer_cmd |= FIELD_PREP(XI3C_CMD_LEN, len); iowrite32(transfer_cmd, master->membase + XI3C_CMD_FIFO_OFFSET); } static inline void xi3c_master_enable(struct xi3c_master *master) { iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) | XI3C_CR_EN_MASK, master->membase + XI3C_CR_OFFSET); } static inline void xi3c_master_disable(struct xi3c_master *master) { iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) & ~XI3C_CR_EN_MASK, master->membase + XI3C_CR_OFFSET); } static inline void xi3c_master_resume(struct xi3c_master *master) { iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) | XI3C_CR_RESUME_MASK, master->membase + XI3C_CR_OFFSET); } static void xi3c_master_reset_fifos(struct xi3c_master *master) { u32 data; /* Assert FIFO reset. */ data = ioread32(master->membase + XI3C_RESET_OFFSET); data |= XI3C_FIFOS_RST_MASK; iowrite32(data, master->membase + XI3C_RESET_OFFSET); /* Read-back flushes the posted write before the settling delay below. */ ioread32(master->membase + XI3C_RESET_OFFSET); fsleep(XI3C_FIFO_RESET_DELAY_US); /* De-assert FIFO reset, then wait for the FIFOs to come back up. */ data &= ~XI3C_FIFOS_RST_MASK; iowrite32(data, master->membase + XI3C_RESET_OFFSET); ioread32(master->membase + XI3C_RESET_OFFSET); fsleep(XI3C_FIFO_RESET_DELAY_US); } static inline void xi3c_master_init(struct xi3c_master *master) { /* Reset fifos */ xi3c_master_reset_fifos(master); /* Enable controller */ xi3c_master_enable(master); } static inline void xi3c_master_reinit(struct xi3c_master *master) { /* Reset fifos */ xi3c_master_reset_fifos(master); /* Resume controller */ xi3c_master_resume(master); } static struct xi3c_xfer *xi3c_master_alloc_xfer(unsigned int ncmds) { struct xi3c_xfer *xfer; xfer = kzalloc_flex(*xfer, cmds, ncmds, GFP_KERNEL); if (!xfer) return NULL; xfer->ncmds = ncmds; return xfer; } static void xi3c_master_rd_from_rx_fifo(struct xi3c_master *master, struct xi3c_cmd *cmd) { u16 rx_data_available; u16 copy_len; u16 len; rx_data_available = xi3c_rd_fifo_level(master); len = rx_data_available * XI3C_WORD_LEN; if (!len) return; copy_len = min(len, cmd->rx_len); xi3c_readl_fifo(master->membase + XI3C_RD_FIFO_OFFSET, (u8 *)cmd->rx_buf, copy_len); cmd->rx_buf = (u8 *)cmd->rx_buf + copy_len; cmd->rx_len -= copy_len; } static int xi3c_master_read(struct xi3c_master *master, struct xi3c_cmd *cmd) { unsigned long timeout; u32 status_reg; int ret; if (cmd->rx_len > XI3C_MAXDATA_LENGTH) return -EINVAL; /* * Zero-length probes (e.g. i2cdetect) legitimately pass a NULL * buffer; only a non-zero length requires one. */ if (cmd->rx_len && !cmd->rx_buf) return -EINVAL; /* Fill command fifo */ xi3c_master_write_to_cmdfifo(master, cmd, cmd->rx_len); if (!cmd->rx_len) return 0; ret = readl_poll_timeout(master->membase + XI3C_SR_OFFSET, status_reg, status_reg & (XI3C_RD_FIFO_NOT_EMPTY_MASK | XI3C_SR_RESP_NOT_EMPTY_MASK), XI3C_POLL_INTERVAL_US, XI3C_RESP_TIMEOUT_US); if (ret) { dev_err(master->dev, "XI3C read timeout\n"); return ret; } if (!(status_reg & XI3C_RD_FIFO_NOT_EMPTY_MASK)) return 0; timeout = jiffies + msecs_to_jiffies(XI3C_XFER_TIMEOUT_MS); /* Read data from rx fifo */ while (cmd->rx_len > 0 && !xi3c_is_resp_available(master)) { if (time_after(jiffies, timeout)) { dev_err(master->dev, "XI3C read timeout\n"); return -EIO; } xi3c_master_rd_from_rx_fifo(master, cmd); usleep_range(XI3C_POLL_INTERVAL_US, 2 * XI3C_POLL_INTERVAL_US); } /* Read remaining data */ xi3c_master_rd_from_rx_fifo(master, cmd); return 0; } static void xi3c_master_wr_to_tx_fifo(struct xi3c_master *master, struct xi3c_cmd *cmd) { u16 wrfifo_space; u16 len; wrfifo_space = xi3c_wr_fifo_level(master); if (cmd->tx_len > wrfifo_space * XI3C_WORD_LEN) len = wrfifo_space * XI3C_WORD_LEN; else len = cmd->tx_len; if (len) { xi3c_writel_fifo(master->membase + XI3C_WR_FIFO_OFFSET, cmd->tx_buf, len); cmd->tx_buf = (const u8 *)cmd->tx_buf + len; cmd->tx_len -= len; } } static int xi3c_master_write(struct xi3c_master *master, struct xi3c_cmd *cmd) { unsigned long timeout; u16 cmd_len; if (cmd->tx_len > XI3C_MAXDATA_LENGTH) return -EINVAL; /* * Zero-length probes (e.g. i2cdetect) legitimately pass a NULL * buffer; only a non-zero length requires one. */ if (cmd->tx_len && !cmd->tx_buf) return -EINVAL; cmd_len = cmd->tx_len; /* Fill Tx fifo */ xi3c_master_wr_to_tx_fifo(master, cmd); /* Write to command fifo */ xi3c_master_write_to_cmdfifo(master, cmd, cmd_len); timeout = jiffies + msecs_to_jiffies(XI3C_XFER_TIMEOUT_MS); /* Fill if any remaining data to tx fifo */ while (cmd->tx_len > 0 && !xi3c_is_resp_available(master)) { if (time_after(jiffies, timeout)) { dev_err(master->dev, "XI3C write timeout\n"); return -EIO; } xi3c_master_wr_to_tx_fifo(master, cmd); usleep_range(XI3C_POLL_INTERVAL_US, 2 * XI3C_POLL_INTERVAL_US); } return 0; } static int xi3c_master_xfer(struct xi3c_master *master, struct xi3c_cmd *cmd) { int ret; if (cmd->rnw) ret = xi3c_master_read(master, cmd); else ret = xi3c_master_write(master, cmd); if (ret) goto err_xfer_out; ret = xi3c_get_response(master, cmd); if (ret < 0) goto err_xfer_out; /* Short read leaves the controller parked in STOP; resume it for the next command */ if (ret == XI3C_XFER_SHORT_READ) xi3c_master_resume(master); return 0; err_xfer_out: xi3c_master_reinit(master); return ret; } static int xi3c_master_common_xfer(struct xi3c_master *master, struct xi3c_xfer *xfer) { unsigned int i; int ret; guard(mutex)(&master->lock); for (i = 0; i < xfer->ncmds; i++) { ret = xi3c_master_xfer(master, &xfer->cmds[i]); if (ret) { /* Count commands sent on the bus; the rest never ran */ xfer->nissued = i + 1; return ret; } } xfer->nissued = xfer->ncmds; return 0; } static int xi3c_master_do_daa(struct i3c_master_controller *m) { u8 (*pid_bufs)[XI3C_DAA_SLAVEINFO_READ_BYTECOUNT]; struct xi3c_master *master = to_xi3c_master(m); struct xi3c_cmd *daa_cmd; struct xi3c_xfer *xfer; int addr, ret, i; u8 last_addr = 0; u8 *pid_buf; u8 ccc_id; xfer = xi3c_master_alloc_xfer(1); if (!xfer) return -ENOMEM; pid_bufs = kcalloc(XI3C_MAX_DEVS, XI3C_DAA_SLAVEINFO_READ_BYTECOUNT, GFP_KERNEL); if (!pid_bufs) { ret = -ENOMEM; goto out; } /* Fill ENTDAA CCC */ ccc_id = I3C_CCC_ENTDAA; daa_cmd = &xfer->cmds[0]; daa_cmd->addr = I3C_BROADCAST_ADDR; daa_cmd->rnw = false; daa_cmd->tx_buf = &ccc_id; daa_cmd->tx_len = 1; daa_cmd->type = XI3C_SDR_MODE; daa_cmd->tid = XI3C_SDR_TID; daa_cmd->continued = true; ret = xi3c_master_common_xfer(master, xfer); if (ret) { /* NACK on ENTDAA broadcast means no devices to enumerate */ if (daa_cmd->err == I3C_ERROR_M2) ret = 0; goto err_daa; } master->daa.index = 0; while (true) { struct xi3c_cmd *cmd = &xfer->cmds[0]; u8 daa_byte; /* Out of device slots; stop and keep what was enumerated */ if (master->daa.index >= XI3C_MAX_DEVS) { dev_warn(master->dev, "DAA: reached %d devices, stopping enumeration\n", XI3C_MAX_DEVS); xi3c_master_reinit(master); break; } addr = i3c_master_get_free_addr(m, last_addr + 1); if (addr < 0) { dev_warn(master->dev, "DAA: no free dynamic address, stopping enumeration\n"); xi3c_master_reinit(master); break; } pid_buf = pid_bufs[master->daa.index]; daa_byte = (addr << 1) | (parity8(addr) ^ 1); cmd->tx_buf = &daa_byte; cmd->tx_len = 1; cmd->addr = I3C_BROADCAST_ADDR; cmd->rnw = true; cmd->rx_buf = pid_buf; cmd->rx_len = XI3C_DAA_SLAVEINFO_READ_BYTECOUNT; cmd->is_daa = true; cmd->type = XI3C_SDR_MODE; cmd->tid = XI3C_SDR_TID; cmd->continued = true; ret = xi3c_master_common_xfer(master, xfer); /* -ENODEV: no more responders, enumeration complete */ if (ret == -ENODEV) { ret = 0; break; } if (ret) goto err_daa; master->daa.addrs[master->daa.index] = addr; last_addr = addr; master->daa.index++; } for (i = 0; i < master->daa.index; i++) { u64 pid; /* Ignore per-device add errors so one failure doesn't abort the rest */ i3c_master_add_i3c_dev_locked(m, master->daa.addrs[i]); pid = FIELD_GET(XI3C_PID_MASK, get_unaligned_be64(pid_bufs[i])); dev_dbg(master->dev, "Client %d: PID: 0x%llx\n", i, pid); } ret = 0; goto out; err_daa: xi3c_master_reinit(master); out: kfree(pid_bufs); kfree(xfer); return ret; } static bool xi3c_master_supports_ccc_cmd(struct i3c_master_controller *master, const struct i3c_ccc_cmd *cmd) { if (cmd->ndests > 1) return false; switch (cmd->id) { case I3C_CCC_ENEC(true): case I3C_CCC_ENEC(false): case I3C_CCC_DISEC(true): case I3C_CCC_DISEC(false): case I3C_CCC_ENTAS(0, true): case I3C_CCC_ENTAS(0, false): case I3C_CCC_RSTDAA(true): case I3C_CCC_RSTDAA(false): case I3C_CCC_ENTDAA: case I3C_CCC_SETMWL(true): case I3C_CCC_SETMWL(false): case I3C_CCC_SETMRL(true): case I3C_CCC_SETMRL(false): case I3C_CCC_SETDASA: case I3C_CCC_SETNEWDA: case I3C_CCC_GETMWL: case I3C_CCC_GETMRL: case I3C_CCC_GETPID: case I3C_CCC_GETBCR: case I3C_CCC_GETDCR: case I3C_CCC_GETSTATUS: case I3C_CCC_GETMXDS: return true; default: return false; } } static int xi3c_master_send_bdcast_ccc_cmd(struct xi3c_master *master, struct i3c_ccc_cmd *ccc) { struct xi3c_xfer *xfer __free(kfree) = NULL; u8 *buf __free(kfree) = NULL; struct xi3c_cmd *cmd; u16 xfer_len; int ret; if (ccc->dests[0].payload.len >= XI3C_MAXDATA_LENGTH) return -EINVAL; xfer_len = ccc->dests[0].payload.len + 1; xfer = xi3c_master_alloc_xfer(1); if (!xfer) return -ENOMEM; buf = kmalloc_objs(*buf, xfer_len, GFP_KERNEL); if (!buf) return -ENOMEM; buf[0] = ccc->id; memcpy(&buf[1], ccc->dests[0].payload.data, ccc->dests[0].payload.len); cmd = &xfer->cmds[0]; cmd->addr = ccc->dests[0].addr; cmd->rnw = ccc->rnw; cmd->tx_buf = buf; cmd->tx_len = xfer_len; cmd->type = XI3C_SDR_MODE; cmd->tid = XI3C_SDR_TID; cmd->continued = false; ret = xi3c_master_common_xfer(master, xfer); ccc->err = cmd->err; return ret; } static int xi3c_master_send_direct_ccc_cmd(struct xi3c_master *master, struct i3c_ccc_cmd *ccc) { struct xi3c_xfer *xfer __free(kfree) = NULL; struct xi3c_cmd *cmd; int ret; if (ccc->dests[0].payload.len > XI3C_MAXDATA_LENGTH) return -EINVAL; xfer = xi3c_master_alloc_xfer(2); if (!xfer) return -ENOMEM; /* Broadcasted message */ cmd = &xfer->cmds[0]; cmd->addr = I3C_BROADCAST_ADDR; cmd->rnw = false; cmd->tx_buf = &ccc->id; cmd->tx_len = 1; cmd->type = XI3C_SDR_MODE; cmd->tid = XI3C_SDR_TID; cmd->continued = true; /* Directed message */ cmd = &xfer->cmds[1]; cmd->addr = ccc->dests[0].addr; cmd->rnw = ccc->rnw; if (cmd->rnw) { cmd->rx_buf = ccc->dests[0].payload.data; cmd->rx_len = ccc->dests[0].payload.len; } else { cmd->tx_buf = ccc->dests[0].payload.data; cmd->tx_len = ccc->dests[0].payload.len; } cmd->type = XI3C_SDR_MODE; cmd->tid = XI3C_SDR_TID; cmd->continued = false; ret = xi3c_master_common_xfer(master, xfer); /* * Report broadcast error if any, else the directed one, so either * NACK reaches the caller */ ccc->err = xfer->cmds[0].err ? xfer->cmds[0].err : xfer->cmds[1].err; /* Report actual byte count so the core sees the right length on short reads */ if (!ret && ccc->rnw) ccc->dests[0].payload.len = min(xfer->cmds[1].rx_actual, ccc->dests[0].payload.len); return ret; } static int xi3c_master_send_ccc_cmd(struct i3c_master_controller *m, struct i3c_ccc_cmd *cmd) { struct xi3c_master *master = to_xi3c_master(m); if (cmd->id & I3C_CCC_DIRECT) return xi3c_master_send_direct_ccc_cmd(master, cmd); return xi3c_master_send_bdcast_ccc_cmd(master, cmd); } static int xi3c_master_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *xfers, int nxfers, enum i3c_xfer_mode mode) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct xi3c_master *master = to_xi3c_master(m); struct xi3c_xfer *xfer __free(kfree) = NULL; int i, ret; if (!nxfers) return 0; if (mode != I3C_SDR) return -EOPNOTSUPP; for (i = 0; i < nxfers; i++) if (xfers[i].len > XI3C_MAXDATA_LENGTH) return -EINVAL; xfer = xi3c_master_alloc_xfer(nxfers); if (!xfer) return -ENOMEM; for (i = 0; i < nxfers; i++) { struct xi3c_cmd *cmd = &xfer->cmds[i]; cmd->addr = dev->info.dyn_addr; cmd->rnw = xfers[i].rnw; if (cmd->rnw) { cmd->rx_buf = xfers[i].data.in; cmd->rx_len = xfers[i].len; } else { cmd->tx_buf = xfers[i].data.out; cmd->tx_len = xfers[i].len; } cmd->type = XI3C_SDR_MODE; cmd->tid = XI3C_SDR_TID; cmd->continued = (i + 1) < nxfers; } ret = xi3c_master_common_xfer(master, xfer); for (i = 0; i < xfer->nissued; i++) { xfers[i].err = xfer->cmds[i].err; if (xfers[i].rnw) xfers[i].actual_len = min(xfer->cmds[i].rx_actual, xfers[i].len); } return ret; } static int xi3c_master_i2c_xfers(struct i2c_dev_desc *dev, struct i2c_msg *xfers, int nxfers) { struct i3c_master_controller *m = i2c_dev_get_master(dev); struct xi3c_master *master = to_xi3c_master(m); struct xi3c_xfer *xfer __free(kfree) = NULL; int i; if (!nxfers) return 0; for (i = 0; i < nxfers; i++) if (xfers[i].len > XI3C_MAXDATA_LENGTH) return -EINVAL; xfer = xi3c_master_alloc_xfer(nxfers); if (!xfer) return -ENOMEM; for (i = 0; i < nxfers; i++) { struct xi3c_cmd *cmd = &xfer->cmds[i]; cmd->addr = xfers[i].addr & XI3C_ADDR_MASK; cmd->rnw = !!(xfers[i].flags & I2C_M_RD); if (cmd->rnw) { cmd->rx_buf = xfers[i].buf; cmd->rx_len = xfers[i].len; } else { cmd->tx_buf = xfers[i].buf; cmd->tx_len = xfers[i].len; } cmd->type = XI3C_I2C_MODE; cmd->tid = XI3C_I2C_TID; cmd->continued = (i + 1) < nxfers; } return xi3c_master_common_xfer(master, xfer); } static int xi3c_clk_cfg(struct xi3c_master *master, unsigned long sclhz, u8 mode) { unsigned long core_rate, core_periodns; u32 tcasmin, tsustart, tsustop, thdstart; u32 thigh, tlow, thold; u32 odthigh, odtlow; core_rate = clk_get_rate(master->pclk); if (!core_rate) return -EINVAL; if (!sclhz) return -EINVAL; core_periodns = DIV_ROUND_UP(NSEC_PER_SEC, core_rate); thigh = DIV_ROUND_UP(core_rate, sclhz) >> 1; tlow = thigh; /* Reject rates whose timing exceeds the 18-bit registers (would wrap) */ if (thigh <= XI3C_CYCLE_ADJUST || (thigh - XI3C_CYCLE_ADJUST) > XI3C_TIMING_MASK) return -EINVAL; /* Hold time : 40% of tlow time */ thold = (tlow * 4) / 10; if (xi3c_get_revision_number(master) == 0) thold = max_t(u32, thold, XI3C_THOLD_MIN_REV0); else thold = max_t(u32, thold, XI3C_THOLD_MIN_REV1); iowrite32((thigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_SCL_HIGH_TIME_OFFSET); iowrite32((tlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_SCL_LOW_TIME_OFFSET); iowrite32((thold - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_SDA_HOLD_TIME_OFFSET); if (mode == XI3C_I2C_MODE) { iowrite32((thigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_OD_SCL_HIGH_TIME_OFFSET); iowrite32((tlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_OD_SCL_LOW_TIME_OFFSET); tcasmin = DIV_ROUND_UP(XI3C_I2C_TCASMIN_NS, core_periodns); } else { odtlow = DIV_ROUND_UP(XI3C_OD_TLOW_NS, core_periodns); odthigh = DIV_ROUND_UP(XI3C_OD_THIGH_NS, core_periodns); odtlow = max(tlow, odtlow); odthigh = min(thigh, odthigh); if (odthigh <= XI3C_CYCLE_ADJUST) return -EINVAL; iowrite32((odthigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_OD_SCL_HIGH_TIME_OFFSET); iowrite32((odtlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_OD_SCL_LOW_TIME_OFFSET); tcasmin = DIV_ROUND_UP(XI3C_TCASMIN_NS, core_periodns); } thdstart = max(thigh, tcasmin); tsustart = max(tlow, tcasmin); tsustop = max(tlow, tcasmin); iowrite32((tsustart - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_TSU_START_OFFSET); iowrite32((thdstart - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_THD_START_OFFSET); iowrite32((tsustop - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK, master->membase + XI3C_TSU_STOP_OFFSET); return 0; } static int xi3c_master_bus_init(struct i3c_master_controller *m) { struct xi3c_master *master = to_xi3c_master(m); struct i3c_bus *bus = i3c_master_get_bus(m); struct i3c_device_info info = {}; unsigned long sclhz; u32 pid1_bcr_dcr; u8 mode; int ret; switch (bus->mode) { case I3C_BUS_MODE_MIXED_FAST: case I3C_BUS_MODE_MIXED_LIMITED: case I3C_BUS_MODE_MIXED_SLOW: mode = XI3C_I2C_MODE; sclhz = bus->scl_rate.i2c; break; case I3C_BUS_MODE_PURE: mode = XI3C_SDR_MODE; sclhz = bus->scl_rate.i3c; break; default: return -EINVAL; } ret = xi3c_clk_cfg(master, sclhz, mode); if (ret) return ret; xi3c_master_init(master); /* Get an address for the master. */ ret = i3c_master_get_free_addr(m, 0); if (ret < 0) return ret; info.dyn_addr = ret; /* Write the dynamic address value to the address register. */ iowrite32(info.dyn_addr, master->membase + XI3C_ADDRESS_OFFSET); /* Read PID, BCR and DCR values, and assign to i3c device info. */ pid1_bcr_dcr = ioread32(master->membase + XI3C_PID1_BCR_DCR); info.pid = ((u64)FIELD_GET(XI3C_PID1_MASK, pid1_bcr_dcr) << 32) | ioread32(master->membase + XI3C_PID0_OFFSET); info.bcr = FIELD_GET(XI3C_BCR_MASK, pid1_bcr_dcr); info.dcr = FIELD_GET(XI3C_DCR_MASK, pid1_bcr_dcr); return i3c_master_set_info(&master->base, &info); } static void xi3c_master_bus_cleanup(struct i3c_master_controller *m) { struct xi3c_master *master = to_xi3c_master(m); xi3c_master_disable(master); } static const struct i3c_master_controller_ops xi3c_master_ops = { .bus_init = xi3c_master_bus_init, .bus_cleanup = xi3c_master_bus_cleanup, .do_daa = xi3c_master_do_daa, .supports_ccc_cmd = xi3c_master_supports_ccc_cmd, .send_ccc_cmd = xi3c_master_send_ccc_cmd, .i3c_xfers = xi3c_master_i3c_xfers, .i2c_xfers = xi3c_master_i2c_xfers, }; static int xi3c_master_probe(struct platform_device *pdev) { struct xi3c_master *master; int ret; master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); if (!master) return -ENOMEM; master->dev = &pdev->dev; master->membase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(master->membase)) return dev_err_probe(master->dev, PTR_ERR(master->membase), "Failed to map registers\n"); master->pclk = devm_clk_get_enabled(master->dev, NULL); if (IS_ERR(master->pclk)) return dev_err_probe(master->dev, PTR_ERR(master->pclk), "Failed to get and enable clock\n"); ret = devm_mutex_init(master->dev, &master->lock); if (ret) return ret; platform_set_drvdata(pdev, master); return i3c_master_register(&master->base, master->dev, &xi3c_master_ops, false); } static void xi3c_master_remove(struct platform_device *pdev) { struct xi3c_master *master = platform_get_drvdata(pdev); i3c_master_unregister(&master->base); } static const struct of_device_id xi3c_master_of_ids[] = { { .compatible = "xlnx,axi-i3c-1.0" }, { }, }; MODULE_DEVICE_TABLE(of, xi3c_master_of_ids); static struct platform_driver xi3c_master_driver = { .probe = xi3c_master_probe, .remove = xi3c_master_remove, .driver = { .name = "axi-i3c-master", .of_match_table = xi3c_master_of_ids, }, }; module_platform_driver(xi3c_master_driver); MODULE_AUTHOR("Manikanta Guntupalli "); MODULE_DESCRIPTION("AMD AXI I3C master driver"); MODULE_LICENSE("GPL");