// 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);
	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);
	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");
