// SPDX-License-Identifier: GPL-2.0
/*
* I3C master driver for the AMD I3C controller.
*
* Copyright (C) 2026, Advanced Micro Devices, Inc.
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i3c/master.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/unaligned.h>
#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 <manikanta.guntupalli@amd.com>");
MODULE_DESCRIPTION("AMD AXI I3C master driver");
MODULE_LICENSE("GPL");