162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2018 Cadence Design Systems Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@bootlin.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bitops.h>
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <linux/i3c/master.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/iopoll.h>
1662306a36Sopenharmony_ci#include <linux/ioport.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/list.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/of.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/spinlock.h>
2462306a36Sopenharmony_ci#include <linux/workqueue.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define DEV_ID				0x0
2762306a36Sopenharmony_ci#define DEV_ID_I3C_MASTER		0x5034
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define CONF_STATUS0			0x4
3062306a36Sopenharmony_ci#define CONF_STATUS0_CMDR_DEPTH(x)	(4 << (((x) & GENMASK(31, 29)) >> 29))
3162306a36Sopenharmony_ci#define CONF_STATUS0_ECC_CHK		BIT(28)
3262306a36Sopenharmony_ci#define CONF_STATUS0_INTEG_CHK		BIT(27)
3362306a36Sopenharmony_ci#define CONF_STATUS0_CSR_DAP_CHK	BIT(26)
3462306a36Sopenharmony_ci#define CONF_STATUS0_TRANS_TOUT_CHK	BIT(25)
3562306a36Sopenharmony_ci#define CONF_STATUS0_PROT_FAULTS_CHK	BIT(24)
3662306a36Sopenharmony_ci#define CONF_STATUS0_GPO_NUM(x)		(((x) & GENMASK(23, 16)) >> 16)
3762306a36Sopenharmony_ci#define CONF_STATUS0_GPI_NUM(x)		(((x) & GENMASK(15, 8)) >> 8)
3862306a36Sopenharmony_ci#define CONF_STATUS0_IBIR_DEPTH(x)	(4 << (((x) & GENMASK(7, 6)) >> 7))
3962306a36Sopenharmony_ci#define CONF_STATUS0_SUPPORTS_DDR	BIT(5)
4062306a36Sopenharmony_ci#define CONF_STATUS0_SEC_MASTER		BIT(4)
4162306a36Sopenharmony_ci#define CONF_STATUS0_DEVS_NUM(x)	((x) & GENMASK(3, 0))
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define CONF_STATUS1			0x8
4462306a36Sopenharmony_ci#define CONF_STATUS1_IBI_HW_RES(x)	((((x) & GENMASK(31, 28)) >> 28) + 1)
4562306a36Sopenharmony_ci#define CONF_STATUS1_CMD_DEPTH(x)	(4 << (((x) & GENMASK(27, 26)) >> 26))
4662306a36Sopenharmony_ci#define CONF_STATUS1_SLVDDR_RX_DEPTH(x)	(8 << (((x) & GENMASK(25, 21)) >> 21))
4762306a36Sopenharmony_ci#define CONF_STATUS1_SLVDDR_TX_DEPTH(x)	(8 << (((x) & GENMASK(20, 16)) >> 16))
4862306a36Sopenharmony_ci#define CONF_STATUS1_IBI_DEPTH(x)	(2 << (((x) & GENMASK(12, 10)) >> 10))
4962306a36Sopenharmony_ci#define CONF_STATUS1_RX_DEPTH(x)	(8 << (((x) & GENMASK(9, 5)) >> 5))
5062306a36Sopenharmony_ci#define CONF_STATUS1_TX_DEPTH(x)	(8 << ((x) & GENMASK(4, 0)))
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define REV_ID				0xc
5362306a36Sopenharmony_ci#define REV_ID_VID(id)			(((id) & GENMASK(31, 20)) >> 20)
5462306a36Sopenharmony_ci#define REV_ID_PID(id)			(((id) & GENMASK(19, 8)) >> 8)
5562306a36Sopenharmony_ci#define REV_ID_REV_MAJOR(id)		(((id) & GENMASK(7, 4)) >> 4)
5662306a36Sopenharmony_ci#define REV_ID_REV_MINOR(id)		((id) & GENMASK(3, 0))
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define CTRL				0x10
5962306a36Sopenharmony_ci#define CTRL_DEV_EN			BIT(31)
6062306a36Sopenharmony_ci#define CTRL_HALT_EN			BIT(30)
6162306a36Sopenharmony_ci#define CTRL_MCS			BIT(29)
6262306a36Sopenharmony_ci#define CTRL_MCS_EN			BIT(28)
6362306a36Sopenharmony_ci#define CTRL_THD_DELAY(x)		(((x) << 24) & GENMASK(25, 24))
6462306a36Sopenharmony_ci#define CTRL_HJ_DISEC			BIT(8)
6562306a36Sopenharmony_ci#define CTRL_MST_ACK			BIT(7)
6662306a36Sopenharmony_ci#define CTRL_HJ_ACK			BIT(6)
6762306a36Sopenharmony_ci#define CTRL_HJ_INIT			BIT(5)
6862306a36Sopenharmony_ci#define CTRL_MST_INIT			BIT(4)
6962306a36Sopenharmony_ci#define CTRL_AHDR_OPT			BIT(3)
7062306a36Sopenharmony_ci#define CTRL_PURE_BUS_MODE		0
7162306a36Sopenharmony_ci#define CTRL_MIXED_FAST_BUS_MODE	2
7262306a36Sopenharmony_ci#define CTRL_MIXED_SLOW_BUS_MODE	3
7362306a36Sopenharmony_ci#define CTRL_BUS_MODE_MASK		GENMASK(1, 0)
7462306a36Sopenharmony_ci#define THD_DELAY_MAX			3
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define PRESCL_CTRL0			0x14
7762306a36Sopenharmony_ci#define PRESCL_CTRL0_I2C(x)		((x) << 16)
7862306a36Sopenharmony_ci#define PRESCL_CTRL0_I3C(x)		(x)
7962306a36Sopenharmony_ci#define PRESCL_CTRL0_I3C_MAX		GENMASK(9, 0)
8062306a36Sopenharmony_ci#define PRESCL_CTRL0_I2C_MAX		GENMASK(15, 0)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define PRESCL_CTRL1			0x18
8362306a36Sopenharmony_ci#define PRESCL_CTRL1_PP_LOW_MASK	GENMASK(15, 8)
8462306a36Sopenharmony_ci#define PRESCL_CTRL1_PP_LOW(x)		((x) << 8)
8562306a36Sopenharmony_ci#define PRESCL_CTRL1_OD_LOW_MASK	GENMASK(7, 0)
8662306a36Sopenharmony_ci#define PRESCL_CTRL1_OD_LOW(x)		(x)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define MST_IER				0x20
8962306a36Sopenharmony_ci#define MST_IDR				0x24
9062306a36Sopenharmony_ci#define MST_IMR				0x28
9162306a36Sopenharmony_ci#define MST_ICR				0x2c
9262306a36Sopenharmony_ci#define MST_ISR				0x30
9362306a36Sopenharmony_ci#define MST_INT_HALTED			BIT(18)
9462306a36Sopenharmony_ci#define MST_INT_MR_DONE			BIT(17)
9562306a36Sopenharmony_ci#define MST_INT_IMM_COMP		BIT(16)
9662306a36Sopenharmony_ci#define MST_INT_TX_THR			BIT(15)
9762306a36Sopenharmony_ci#define MST_INT_TX_OVF			BIT(14)
9862306a36Sopenharmony_ci#define MST_INT_IBID_THR		BIT(12)
9962306a36Sopenharmony_ci#define MST_INT_IBID_UNF		BIT(11)
10062306a36Sopenharmony_ci#define MST_INT_IBIR_THR		BIT(10)
10162306a36Sopenharmony_ci#define MST_INT_IBIR_UNF		BIT(9)
10262306a36Sopenharmony_ci#define MST_INT_IBIR_OVF		BIT(8)
10362306a36Sopenharmony_ci#define MST_INT_RX_THR			BIT(7)
10462306a36Sopenharmony_ci#define MST_INT_RX_UNF			BIT(6)
10562306a36Sopenharmony_ci#define MST_INT_CMDD_EMP		BIT(5)
10662306a36Sopenharmony_ci#define MST_INT_CMDD_THR		BIT(4)
10762306a36Sopenharmony_ci#define MST_INT_CMDD_OVF		BIT(3)
10862306a36Sopenharmony_ci#define MST_INT_CMDR_THR		BIT(2)
10962306a36Sopenharmony_ci#define MST_INT_CMDR_UNF		BIT(1)
11062306a36Sopenharmony_ci#define MST_INT_CMDR_OVF		BIT(0)
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define MST_STATUS0			0x34
11362306a36Sopenharmony_ci#define MST_STATUS0_IDLE		BIT(18)
11462306a36Sopenharmony_ci#define MST_STATUS0_HALTED		BIT(17)
11562306a36Sopenharmony_ci#define MST_STATUS0_MASTER_MODE		BIT(16)
11662306a36Sopenharmony_ci#define MST_STATUS0_TX_FULL		BIT(13)
11762306a36Sopenharmony_ci#define MST_STATUS0_IBID_FULL		BIT(12)
11862306a36Sopenharmony_ci#define MST_STATUS0_IBIR_FULL		BIT(11)
11962306a36Sopenharmony_ci#define MST_STATUS0_RX_FULL		BIT(10)
12062306a36Sopenharmony_ci#define MST_STATUS0_CMDD_FULL		BIT(9)
12162306a36Sopenharmony_ci#define MST_STATUS0_CMDR_FULL		BIT(8)
12262306a36Sopenharmony_ci#define MST_STATUS0_TX_EMP		BIT(5)
12362306a36Sopenharmony_ci#define MST_STATUS0_IBID_EMP		BIT(4)
12462306a36Sopenharmony_ci#define MST_STATUS0_IBIR_EMP		BIT(3)
12562306a36Sopenharmony_ci#define MST_STATUS0_RX_EMP		BIT(2)
12662306a36Sopenharmony_ci#define MST_STATUS0_CMDD_EMP		BIT(1)
12762306a36Sopenharmony_ci#define MST_STATUS0_CMDR_EMP		BIT(0)
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define CMDR				0x38
13062306a36Sopenharmony_ci#define CMDR_NO_ERROR			0
13162306a36Sopenharmony_ci#define CMDR_DDR_PREAMBLE_ERROR		1
13262306a36Sopenharmony_ci#define CMDR_DDR_PARITY_ERROR		2
13362306a36Sopenharmony_ci#define CMDR_DDR_RX_FIFO_OVF		3
13462306a36Sopenharmony_ci#define CMDR_DDR_TX_FIFO_UNF		4
13562306a36Sopenharmony_ci#define CMDR_M0_ERROR			5
13662306a36Sopenharmony_ci#define CMDR_M1_ERROR			6
13762306a36Sopenharmony_ci#define CMDR_M2_ERROR			7
13862306a36Sopenharmony_ci#define CMDR_MST_ABORT			8
13962306a36Sopenharmony_ci#define CMDR_NACK_RESP			9
14062306a36Sopenharmony_ci#define CMDR_INVALID_DA			10
14162306a36Sopenharmony_ci#define CMDR_DDR_DROPPED		11
14262306a36Sopenharmony_ci#define CMDR_ERROR(x)			(((x) & GENMASK(27, 24)) >> 24)
14362306a36Sopenharmony_ci#define CMDR_XFER_BYTES(x)		(((x) & GENMASK(19, 8)) >> 8)
14462306a36Sopenharmony_ci#define CMDR_CMDID_HJACK_DISEC		0xfe
14562306a36Sopenharmony_ci#define CMDR_CMDID_HJACK_ENTDAA		0xff
14662306a36Sopenharmony_ci#define CMDR_CMDID(x)			((x) & GENMASK(7, 0))
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci#define IBIR				0x3c
14962306a36Sopenharmony_ci#define IBIR_ACKED			BIT(12)
15062306a36Sopenharmony_ci#define IBIR_SLVID(x)			(((x) & GENMASK(11, 8)) >> 8)
15162306a36Sopenharmony_ci#define IBIR_ERROR			BIT(7)
15262306a36Sopenharmony_ci#define IBIR_XFER_BYTES(x)		(((x) & GENMASK(6, 2)) >> 2)
15362306a36Sopenharmony_ci#define IBIR_TYPE_IBI			0
15462306a36Sopenharmony_ci#define IBIR_TYPE_HJ			1
15562306a36Sopenharmony_ci#define IBIR_TYPE_MR			2
15662306a36Sopenharmony_ci#define IBIR_TYPE(x)			((x) & GENMASK(1, 0))
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci#define SLV_IER				0x40
15962306a36Sopenharmony_ci#define SLV_IDR				0x44
16062306a36Sopenharmony_ci#define SLV_IMR				0x48
16162306a36Sopenharmony_ci#define SLV_ICR				0x4c
16262306a36Sopenharmony_ci#define SLV_ISR				0x50
16362306a36Sopenharmony_ci#define SLV_INT_TM			BIT(20)
16462306a36Sopenharmony_ci#define SLV_INT_ERROR			BIT(19)
16562306a36Sopenharmony_ci#define SLV_INT_EVENT_UP		BIT(18)
16662306a36Sopenharmony_ci#define SLV_INT_HJ_DONE			BIT(17)
16762306a36Sopenharmony_ci#define SLV_INT_MR_DONE			BIT(16)
16862306a36Sopenharmony_ci#define SLV_INT_DA_UPD			BIT(15)
16962306a36Sopenharmony_ci#define SLV_INT_SDR_FAIL		BIT(14)
17062306a36Sopenharmony_ci#define SLV_INT_DDR_FAIL		BIT(13)
17162306a36Sopenharmony_ci#define SLV_INT_M_RD_ABORT		BIT(12)
17262306a36Sopenharmony_ci#define SLV_INT_DDR_RX_THR		BIT(11)
17362306a36Sopenharmony_ci#define SLV_INT_DDR_TX_THR		BIT(10)
17462306a36Sopenharmony_ci#define SLV_INT_SDR_RX_THR		BIT(9)
17562306a36Sopenharmony_ci#define SLV_INT_SDR_TX_THR		BIT(8)
17662306a36Sopenharmony_ci#define SLV_INT_DDR_RX_UNF		BIT(7)
17762306a36Sopenharmony_ci#define SLV_INT_DDR_TX_OVF		BIT(6)
17862306a36Sopenharmony_ci#define SLV_INT_SDR_RX_UNF		BIT(5)
17962306a36Sopenharmony_ci#define SLV_INT_SDR_TX_OVF		BIT(4)
18062306a36Sopenharmony_ci#define SLV_INT_DDR_RD_COMP		BIT(3)
18162306a36Sopenharmony_ci#define SLV_INT_DDR_WR_COMP		BIT(2)
18262306a36Sopenharmony_ci#define SLV_INT_SDR_RD_COMP		BIT(1)
18362306a36Sopenharmony_ci#define SLV_INT_SDR_WR_COMP		BIT(0)
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#define SLV_STATUS0			0x54
18662306a36Sopenharmony_ci#define SLV_STATUS0_REG_ADDR(s)		(((s) & GENMASK(23, 16)) >> 16)
18762306a36Sopenharmony_ci#define SLV_STATUS0_XFRD_BYTES(s)	((s) & GENMASK(15, 0))
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci#define SLV_STATUS1			0x58
19062306a36Sopenharmony_ci#define SLV_STATUS1_AS(s)		(((s) & GENMASK(21, 20)) >> 20)
19162306a36Sopenharmony_ci#define SLV_STATUS1_VEN_TM		BIT(19)
19262306a36Sopenharmony_ci#define SLV_STATUS1_HJ_DIS		BIT(18)
19362306a36Sopenharmony_ci#define SLV_STATUS1_MR_DIS		BIT(17)
19462306a36Sopenharmony_ci#define SLV_STATUS1_PROT_ERR		BIT(16)
19562306a36Sopenharmony_ci#define SLV_STATUS1_DA(s)		(((s) & GENMASK(15, 9)) >> 9)
19662306a36Sopenharmony_ci#define SLV_STATUS1_HAS_DA		BIT(8)
19762306a36Sopenharmony_ci#define SLV_STATUS1_DDR_RX_FULL		BIT(7)
19862306a36Sopenharmony_ci#define SLV_STATUS1_DDR_TX_FULL		BIT(6)
19962306a36Sopenharmony_ci#define SLV_STATUS1_DDR_RX_EMPTY	BIT(5)
20062306a36Sopenharmony_ci#define SLV_STATUS1_DDR_TX_EMPTY	BIT(4)
20162306a36Sopenharmony_ci#define SLV_STATUS1_SDR_RX_FULL		BIT(3)
20262306a36Sopenharmony_ci#define SLV_STATUS1_SDR_TX_FULL		BIT(2)
20362306a36Sopenharmony_ci#define SLV_STATUS1_SDR_RX_EMPTY	BIT(1)
20462306a36Sopenharmony_ci#define SLV_STATUS1_SDR_TX_EMPTY	BIT(0)
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#define CMD0_FIFO			0x60
20762306a36Sopenharmony_ci#define CMD0_FIFO_IS_DDR		BIT(31)
20862306a36Sopenharmony_ci#define CMD0_FIFO_IS_CCC		BIT(30)
20962306a36Sopenharmony_ci#define CMD0_FIFO_BCH			BIT(29)
21062306a36Sopenharmony_ci#define XMIT_BURST_STATIC_SUBADDR	0
21162306a36Sopenharmony_ci#define XMIT_SINGLE_INC_SUBADDR		1
21262306a36Sopenharmony_ci#define XMIT_SINGLE_STATIC_SUBADDR	2
21362306a36Sopenharmony_ci#define XMIT_BURST_WITHOUT_SUBADDR	3
21462306a36Sopenharmony_ci#define CMD0_FIFO_PRIV_XMIT_MODE(m)	((m) << 27)
21562306a36Sopenharmony_ci#define CMD0_FIFO_SBCA			BIT(26)
21662306a36Sopenharmony_ci#define CMD0_FIFO_RSBC			BIT(25)
21762306a36Sopenharmony_ci#define CMD0_FIFO_IS_10B		BIT(24)
21862306a36Sopenharmony_ci#define CMD0_FIFO_PL_LEN(l)		((l) << 12)
21962306a36Sopenharmony_ci#define CMD0_FIFO_PL_LEN_MAX		4095
22062306a36Sopenharmony_ci#define CMD0_FIFO_DEV_ADDR(a)		((a) << 1)
22162306a36Sopenharmony_ci#define CMD0_FIFO_RNW			BIT(0)
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci#define CMD1_FIFO			0x64
22462306a36Sopenharmony_ci#define CMD1_FIFO_CMDID(id)		((id) << 24)
22562306a36Sopenharmony_ci#define CMD1_FIFO_CSRADDR(a)		(a)
22662306a36Sopenharmony_ci#define CMD1_FIFO_CCC(id)		(id)
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#define TX_FIFO				0x68
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci#define IMD_CMD0			0x70
23162306a36Sopenharmony_ci#define IMD_CMD0_PL_LEN(l)		((l) << 12)
23262306a36Sopenharmony_ci#define IMD_CMD0_DEV_ADDR(a)		((a) << 1)
23362306a36Sopenharmony_ci#define IMD_CMD0_RNW			BIT(0)
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci#define IMD_CMD1			0x74
23662306a36Sopenharmony_ci#define IMD_CMD1_CCC(id)		(id)
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#define IMD_DATA			0x78
23962306a36Sopenharmony_ci#define RX_FIFO				0x80
24062306a36Sopenharmony_ci#define IBI_DATA_FIFO			0x84
24162306a36Sopenharmony_ci#define SLV_DDR_TX_FIFO			0x88
24262306a36Sopenharmony_ci#define SLV_DDR_RX_FIFO			0x8c
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci#define CMD_IBI_THR_CTRL		0x90
24562306a36Sopenharmony_ci#define IBIR_THR(t)			((t) << 24)
24662306a36Sopenharmony_ci#define CMDR_THR(t)			((t) << 16)
24762306a36Sopenharmony_ci#define IBI_THR(t)			((t) << 8)
24862306a36Sopenharmony_ci#define CMD_THR(t)			(t)
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci#define TX_RX_THR_CTRL			0x94
25162306a36Sopenharmony_ci#define RX_THR(t)			((t) << 16)
25262306a36Sopenharmony_ci#define TX_THR(t)			(t)
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci#define SLV_DDR_TX_RX_THR_CTRL		0x98
25562306a36Sopenharmony_ci#define SLV_DDR_RX_THR(t)		((t) << 16)
25662306a36Sopenharmony_ci#define SLV_DDR_TX_THR(t)		(t)
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci#define FLUSH_CTRL			0x9c
25962306a36Sopenharmony_ci#define FLUSH_IBI_RESP			BIT(23)
26062306a36Sopenharmony_ci#define FLUSH_CMD_RESP			BIT(22)
26162306a36Sopenharmony_ci#define FLUSH_SLV_DDR_RX_FIFO		BIT(22)
26262306a36Sopenharmony_ci#define FLUSH_SLV_DDR_TX_FIFO		BIT(21)
26362306a36Sopenharmony_ci#define FLUSH_IMM_FIFO			BIT(20)
26462306a36Sopenharmony_ci#define FLUSH_IBI_FIFO			BIT(19)
26562306a36Sopenharmony_ci#define FLUSH_RX_FIFO			BIT(18)
26662306a36Sopenharmony_ci#define FLUSH_TX_FIFO			BIT(17)
26762306a36Sopenharmony_ci#define FLUSH_CMD_FIFO			BIT(16)
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#define TTO_PRESCL_CTRL0		0xb0
27062306a36Sopenharmony_ci#define TTO_PRESCL_CTRL0_DIVB(x)	((x) << 16)
27162306a36Sopenharmony_ci#define TTO_PRESCL_CTRL0_DIVA(x)	(x)
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci#define TTO_PRESCL_CTRL1		0xb4
27462306a36Sopenharmony_ci#define TTO_PRESCL_CTRL1_DIVB(x)	((x) << 16)
27562306a36Sopenharmony_ci#define TTO_PRESCL_CTRL1_DIVA(x)	(x)
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci#define DEVS_CTRL			0xb8
27862306a36Sopenharmony_ci#define DEVS_CTRL_DEV_CLR_SHIFT		16
27962306a36Sopenharmony_ci#define DEVS_CTRL_DEV_CLR_ALL		GENMASK(31, 16)
28062306a36Sopenharmony_ci#define DEVS_CTRL_DEV_CLR(dev)		BIT(16 + (dev))
28162306a36Sopenharmony_ci#define DEVS_CTRL_DEV_ACTIVE(dev)	BIT(dev)
28262306a36Sopenharmony_ci#define DEVS_CTRL_DEVS_ACTIVE_MASK	GENMASK(15, 0)
28362306a36Sopenharmony_ci#define MAX_DEVS			16
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci#define DEV_ID_RR0(d)			(0xc0 + ((d) * 0x10))
28662306a36Sopenharmony_ci#define DEV_ID_RR0_LVR_EXT_ADDR		BIT(11)
28762306a36Sopenharmony_ci#define DEV_ID_RR0_HDR_CAP		BIT(10)
28862306a36Sopenharmony_ci#define DEV_ID_RR0_IS_I3C		BIT(9)
28962306a36Sopenharmony_ci#define DEV_ID_RR0_DEV_ADDR_MASK	(GENMASK(6, 0) | GENMASK(15, 13))
29062306a36Sopenharmony_ci#define DEV_ID_RR0_SET_DEV_ADDR(a)	(((a) & GENMASK(6, 0)) |	\
29162306a36Sopenharmony_ci					 (((a) & GENMASK(9, 7)) << 6))
29262306a36Sopenharmony_ci#define DEV_ID_RR0_GET_DEV_ADDR(x)	((((x) >> 1) & GENMASK(6, 0)) |	\
29362306a36Sopenharmony_ci					 (((x) >> 6) & GENMASK(9, 7)))
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci#define DEV_ID_RR1(d)			(0xc4 + ((d) * 0x10))
29662306a36Sopenharmony_ci#define DEV_ID_RR1_PID_MSB(pid)		(pid)
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci#define DEV_ID_RR2(d)			(0xc8 + ((d) * 0x10))
29962306a36Sopenharmony_ci#define DEV_ID_RR2_PID_LSB(pid)		((pid) << 16)
30062306a36Sopenharmony_ci#define DEV_ID_RR2_BCR(bcr)		((bcr) << 8)
30162306a36Sopenharmony_ci#define DEV_ID_RR2_DCR(dcr)		(dcr)
30262306a36Sopenharmony_ci#define DEV_ID_RR2_LVR(lvr)		(lvr)
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci#define SIR_MAP(x)			(0x180 + ((x) * 4))
30562306a36Sopenharmony_ci#define SIR_MAP_DEV_REG(d)		SIR_MAP((d) / 2)
30662306a36Sopenharmony_ci#define SIR_MAP_DEV_SHIFT(d, fs)	((fs) + (((d) % 2) ? 16 : 0))
30762306a36Sopenharmony_ci#define SIR_MAP_DEV_CONF_MASK(d)	(GENMASK(15, 0) << (((d) % 2) ? 16 : 0))
30862306a36Sopenharmony_ci#define SIR_MAP_DEV_CONF(d, c)		((c) << (((d) % 2) ? 16 : 0))
30962306a36Sopenharmony_ci#define DEV_ROLE_SLAVE			0
31062306a36Sopenharmony_ci#define DEV_ROLE_MASTER			1
31162306a36Sopenharmony_ci#define SIR_MAP_DEV_ROLE(role)		((role) << 14)
31262306a36Sopenharmony_ci#define SIR_MAP_DEV_SLOW		BIT(13)
31362306a36Sopenharmony_ci#define SIR_MAP_DEV_PL(l)		((l) << 8)
31462306a36Sopenharmony_ci#define SIR_MAP_PL_MAX			GENMASK(4, 0)
31562306a36Sopenharmony_ci#define SIR_MAP_DEV_DA(a)		((a) << 1)
31662306a36Sopenharmony_ci#define SIR_MAP_DEV_ACK			BIT(0)
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci#define GPIR_WORD(x)			(0x200 + ((x) * 4))
31962306a36Sopenharmony_ci#define GPI_REG(val, id)		\
32062306a36Sopenharmony_ci	(((val) >> (((id) % 4) * 8)) & GENMASK(7, 0))
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci#define GPOR_WORD(x)			(0x220 + ((x) * 4))
32362306a36Sopenharmony_ci#define GPO_REG(val, id)		\
32462306a36Sopenharmony_ci	(((val) >> (((id) % 4) * 8)) & GENMASK(7, 0))
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci#define ASF_INT_STATUS			0x300
32762306a36Sopenharmony_ci#define ASF_INT_RAW_STATUS		0x304
32862306a36Sopenharmony_ci#define ASF_INT_MASK			0x308
32962306a36Sopenharmony_ci#define ASF_INT_TEST			0x30c
33062306a36Sopenharmony_ci#define ASF_INT_FATAL_SELECT		0x310
33162306a36Sopenharmony_ci#define ASF_INTEGRITY_ERR		BIT(6)
33262306a36Sopenharmony_ci#define ASF_PROTOCOL_ERR		BIT(5)
33362306a36Sopenharmony_ci#define ASF_TRANS_TIMEOUT_ERR		BIT(4)
33462306a36Sopenharmony_ci#define ASF_CSR_ERR			BIT(3)
33562306a36Sopenharmony_ci#define ASF_DAP_ERR			BIT(2)
33662306a36Sopenharmony_ci#define ASF_SRAM_UNCORR_ERR		BIT(1)
33762306a36Sopenharmony_ci#define ASF_SRAM_CORR_ERR		BIT(0)
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci#define ASF_SRAM_CORR_FAULT_STATUS	0x320
34062306a36Sopenharmony_ci#define ASF_SRAM_UNCORR_FAULT_STATUS	0x324
34162306a36Sopenharmony_ci#define ASF_SRAM_CORR_FAULT_INSTANCE(x)	((x) >> 24)
34262306a36Sopenharmony_ci#define ASF_SRAM_CORR_FAULT_ADDR(x)	((x) & GENMASK(23, 0))
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci#define ASF_SRAM_FAULT_STATS		0x328
34562306a36Sopenharmony_ci#define ASF_SRAM_FAULT_UNCORR_STATS(x)	((x) >> 16)
34662306a36Sopenharmony_ci#define ASF_SRAM_FAULT_CORR_STATS(x)	((x) & GENMASK(15, 0))
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci#define ASF_TRANS_TOUT_CTRL		0x330
34962306a36Sopenharmony_ci#define ASF_TRANS_TOUT_EN		BIT(31)
35062306a36Sopenharmony_ci#define ASF_TRANS_TOUT_VAL(x)	(x)
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_MASK	0x334
35362306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_STATUS	0x338
35462306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_APB	BIT(3)
35562306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_SCL_LOW	BIT(2)
35662306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_SCL_HIGH	BIT(1)
35762306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_FSCL_HIGH	BIT(0)
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci#define ASF_PROTO_FAULT_MASK		0x340
36062306a36Sopenharmony_ci#define ASF_PROTO_FAULT_STATUS		0x344
36162306a36Sopenharmony_ci#define ASF_PROTO_FAULT_SLVSDR_RD_ABORT	BIT(31)
36262306a36Sopenharmony_ci#define ASF_PROTO_FAULT_SLVDDR_FAIL	BIT(30)
36362306a36Sopenharmony_ci#define ASF_PROTO_FAULT_S(x)		BIT(16 + (x))
36462306a36Sopenharmony_ci#define ASF_PROTO_FAULT_MSTSDR_RD_ABORT	BIT(15)
36562306a36Sopenharmony_ci#define ASF_PROTO_FAULT_MSTDDR_FAIL	BIT(14)
36662306a36Sopenharmony_ci#define ASF_PROTO_FAULT_M(x)		BIT(x)
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistruct cdns_i3c_master_caps {
36962306a36Sopenharmony_ci	u32 cmdfifodepth;
37062306a36Sopenharmony_ci	u32 cmdrfifodepth;
37162306a36Sopenharmony_ci	u32 txfifodepth;
37262306a36Sopenharmony_ci	u32 rxfifodepth;
37362306a36Sopenharmony_ci	u32 ibirfifodepth;
37462306a36Sopenharmony_ci};
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistruct cdns_i3c_cmd {
37762306a36Sopenharmony_ci	u32 cmd0;
37862306a36Sopenharmony_ci	u32 cmd1;
37962306a36Sopenharmony_ci	u32 tx_len;
38062306a36Sopenharmony_ci	const void *tx_buf;
38162306a36Sopenharmony_ci	u32 rx_len;
38262306a36Sopenharmony_ci	void *rx_buf;
38362306a36Sopenharmony_ci	u32 error;
38462306a36Sopenharmony_ci};
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistruct cdns_i3c_xfer {
38762306a36Sopenharmony_ci	struct list_head node;
38862306a36Sopenharmony_ci	struct completion comp;
38962306a36Sopenharmony_ci	int ret;
39062306a36Sopenharmony_ci	unsigned int ncmds;
39162306a36Sopenharmony_ci	struct cdns_i3c_cmd cmds[];
39262306a36Sopenharmony_ci};
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistruct cdns_i3c_data {
39562306a36Sopenharmony_ci	u8 thd_delay_ns;
39662306a36Sopenharmony_ci};
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistruct cdns_i3c_master {
39962306a36Sopenharmony_ci	struct work_struct hj_work;
40062306a36Sopenharmony_ci	struct i3c_master_controller base;
40162306a36Sopenharmony_ci	u32 free_rr_slots;
40262306a36Sopenharmony_ci	unsigned int maxdevs;
40362306a36Sopenharmony_ci	struct {
40462306a36Sopenharmony_ci		unsigned int num_slots;
40562306a36Sopenharmony_ci		struct i3c_dev_desc **slots;
40662306a36Sopenharmony_ci		spinlock_t lock;
40762306a36Sopenharmony_ci	} ibi;
40862306a36Sopenharmony_ci	struct {
40962306a36Sopenharmony_ci		struct list_head list;
41062306a36Sopenharmony_ci		struct cdns_i3c_xfer *cur;
41162306a36Sopenharmony_ci		spinlock_t lock;
41262306a36Sopenharmony_ci	} xferqueue;
41362306a36Sopenharmony_ci	void __iomem *regs;
41462306a36Sopenharmony_ci	struct clk *sysclk;
41562306a36Sopenharmony_ci	struct clk *pclk;
41662306a36Sopenharmony_ci	struct cdns_i3c_master_caps caps;
41762306a36Sopenharmony_ci	unsigned long i3c_scl_lim;
41862306a36Sopenharmony_ci	const struct cdns_i3c_data *devdata;
41962306a36Sopenharmony_ci};
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic inline struct cdns_i3c_master *
42262306a36Sopenharmony_cito_cdns_i3c_master(struct i3c_master_controller *master)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	return container_of(master, struct cdns_i3c_master, base);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master,
42862306a36Sopenharmony_ci					  const u8 *bytes, int nbytes)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	writesl(master->regs + TX_FIFO, bytes, nbytes / 4);
43162306a36Sopenharmony_ci	if (nbytes & 3) {
43262306a36Sopenharmony_ci		u32 tmp = 0;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
43562306a36Sopenharmony_ci		writesl(master->regs + TX_FIFO, &tmp, 1);
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master,
44062306a36Sopenharmony_ci					    u8 *bytes, int nbytes)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	readsl(master->regs + RX_FIFO, bytes, nbytes / 4);
44362306a36Sopenharmony_ci	if (nbytes & 3) {
44462306a36Sopenharmony_ci		u32 tmp;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		readsl(master->regs + RX_FIFO, &tmp, 1);
44762306a36Sopenharmony_ci		memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
45262306a36Sopenharmony_ci					     const struct i3c_ccc_cmd *cmd)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	if (cmd->ndests > 1)
45562306a36Sopenharmony_ci		return false;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	switch (cmd->id) {
45862306a36Sopenharmony_ci	case I3C_CCC_ENEC(true):
45962306a36Sopenharmony_ci	case I3C_CCC_ENEC(false):
46062306a36Sopenharmony_ci	case I3C_CCC_DISEC(true):
46162306a36Sopenharmony_ci	case I3C_CCC_DISEC(false):
46262306a36Sopenharmony_ci	case I3C_CCC_ENTAS(0, true):
46362306a36Sopenharmony_ci	case I3C_CCC_ENTAS(0, false):
46462306a36Sopenharmony_ci	case I3C_CCC_RSTDAA(true):
46562306a36Sopenharmony_ci	case I3C_CCC_RSTDAA(false):
46662306a36Sopenharmony_ci	case I3C_CCC_ENTDAA:
46762306a36Sopenharmony_ci	case I3C_CCC_SETMWL(true):
46862306a36Sopenharmony_ci	case I3C_CCC_SETMWL(false):
46962306a36Sopenharmony_ci	case I3C_CCC_SETMRL(true):
47062306a36Sopenharmony_ci	case I3C_CCC_SETMRL(false):
47162306a36Sopenharmony_ci	case I3C_CCC_DEFSLVS:
47262306a36Sopenharmony_ci	case I3C_CCC_ENTHDR(0):
47362306a36Sopenharmony_ci	case I3C_CCC_SETDASA:
47462306a36Sopenharmony_ci	case I3C_CCC_SETNEWDA:
47562306a36Sopenharmony_ci	case I3C_CCC_GETMWL:
47662306a36Sopenharmony_ci	case I3C_CCC_GETMRL:
47762306a36Sopenharmony_ci	case I3C_CCC_GETPID:
47862306a36Sopenharmony_ci	case I3C_CCC_GETBCR:
47962306a36Sopenharmony_ci	case I3C_CCC_GETDCR:
48062306a36Sopenharmony_ci	case I3C_CCC_GETSTATUS:
48162306a36Sopenharmony_ci	case I3C_CCC_GETACCMST:
48262306a36Sopenharmony_ci	case I3C_CCC_GETMXDS:
48362306a36Sopenharmony_ci	case I3C_CCC_GETHDRCAP:
48462306a36Sopenharmony_ci		return true;
48562306a36Sopenharmony_ci	default:
48662306a36Sopenharmony_ci		break;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	return false;
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic int cdns_i3c_master_disable(struct cdns_i3c_master *master)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	u32 status;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	writel(readl(master->regs + CTRL) & ~CTRL_DEV_EN, master->regs + CTRL);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return readl_poll_timeout(master->regs + MST_STATUS0, status,
49962306a36Sopenharmony_ci				  status & MST_STATUS0_IDLE, 10, 1000000);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic void cdns_i3c_master_enable(struct cdns_i3c_master *master)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	writel(readl(master->regs + CTRL) | CTRL_DEV_EN, master->regs + CTRL);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic struct cdns_i3c_xfer *
50862306a36Sopenharmony_cicdns_i3c_master_alloc_xfer(struct cdns_i3c_master *master, unsigned int ncmds)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct cdns_i3c_xfer *xfer;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
51362306a36Sopenharmony_ci	if (!xfer)
51462306a36Sopenharmony_ci		return NULL;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	INIT_LIST_HEAD(&xfer->node);
51762306a36Sopenharmony_ci	xfer->ncmds = ncmds;
51862306a36Sopenharmony_ci	xfer->ret = -ETIMEDOUT;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	return xfer;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic void cdns_i3c_master_free_xfer(struct cdns_i3c_xfer *xfer)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	kfree(xfer);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic void cdns_i3c_master_start_xfer_locked(struct cdns_i3c_master *master)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct cdns_i3c_xfer *xfer = master->xferqueue.cur;
53162306a36Sopenharmony_ci	unsigned int i;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (!xfer)
53462306a36Sopenharmony_ci		return;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	writel(MST_INT_CMDD_EMP, master->regs + MST_ICR);
53762306a36Sopenharmony_ci	for (i = 0; i < xfer->ncmds; i++) {
53862306a36Sopenharmony_ci		struct cdns_i3c_cmd *cmd = &xfer->cmds[i];
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		cdns_i3c_master_wr_to_tx_fifo(master, cmd->tx_buf,
54162306a36Sopenharmony_ci					      cmd->tx_len);
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	for (i = 0; i < xfer->ncmds; i++) {
54562306a36Sopenharmony_ci		struct cdns_i3c_cmd *cmd = &xfer->cmds[i];
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		writel(cmd->cmd1 | CMD1_FIFO_CMDID(i),
54862306a36Sopenharmony_ci		       master->regs + CMD1_FIFO);
54962306a36Sopenharmony_ci		writel(cmd->cmd0, master->regs + CMD0_FIFO);
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	writel(readl(master->regs + CTRL) | CTRL_MCS,
55362306a36Sopenharmony_ci	       master->regs + CTRL);
55462306a36Sopenharmony_ci	writel(MST_INT_CMDD_EMP, master->regs + MST_IER);
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic void cdns_i3c_master_end_xfer_locked(struct cdns_i3c_master *master,
55862306a36Sopenharmony_ci					    u32 isr)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct cdns_i3c_xfer *xfer = master->xferqueue.cur;
56162306a36Sopenharmony_ci	int i, ret = 0;
56262306a36Sopenharmony_ci	u32 status0;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (!xfer)
56562306a36Sopenharmony_ci		return;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (!(isr & MST_INT_CMDD_EMP))
56862306a36Sopenharmony_ci		return;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	writel(MST_INT_CMDD_EMP, master->regs + MST_IDR);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	for (status0 = readl(master->regs + MST_STATUS0);
57362306a36Sopenharmony_ci	     !(status0 & MST_STATUS0_CMDR_EMP);
57462306a36Sopenharmony_ci	     status0 = readl(master->regs + MST_STATUS0)) {
57562306a36Sopenharmony_ci		struct cdns_i3c_cmd *cmd;
57662306a36Sopenharmony_ci		u32 cmdr, rx_len, id;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		cmdr = readl(master->regs + CMDR);
57962306a36Sopenharmony_ci		id = CMDR_CMDID(cmdr);
58062306a36Sopenharmony_ci		if (id == CMDR_CMDID_HJACK_DISEC ||
58162306a36Sopenharmony_ci		    id == CMDR_CMDID_HJACK_ENTDAA ||
58262306a36Sopenharmony_ci		    WARN_ON(id >= xfer->ncmds))
58362306a36Sopenharmony_ci			continue;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci		cmd = &xfer->cmds[CMDR_CMDID(cmdr)];
58662306a36Sopenharmony_ci		rx_len = min_t(u32, CMDR_XFER_BYTES(cmdr), cmd->rx_len);
58762306a36Sopenharmony_ci		cdns_i3c_master_rd_from_rx_fifo(master, cmd->rx_buf, rx_len);
58862306a36Sopenharmony_ci		cmd->error = CMDR_ERROR(cmdr);
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	for (i = 0; i < xfer->ncmds; i++) {
59262306a36Sopenharmony_ci		switch (xfer->cmds[i].error) {
59362306a36Sopenharmony_ci		case CMDR_NO_ERROR:
59462306a36Sopenharmony_ci			break;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		case CMDR_DDR_PREAMBLE_ERROR:
59762306a36Sopenharmony_ci		case CMDR_DDR_PARITY_ERROR:
59862306a36Sopenharmony_ci		case CMDR_M0_ERROR:
59962306a36Sopenharmony_ci		case CMDR_M1_ERROR:
60062306a36Sopenharmony_ci		case CMDR_M2_ERROR:
60162306a36Sopenharmony_ci		case CMDR_MST_ABORT:
60262306a36Sopenharmony_ci		case CMDR_NACK_RESP:
60362306a36Sopenharmony_ci		case CMDR_DDR_DROPPED:
60462306a36Sopenharmony_ci			ret = -EIO;
60562306a36Sopenharmony_ci			break;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci		case CMDR_DDR_RX_FIFO_OVF:
60862306a36Sopenharmony_ci		case CMDR_DDR_TX_FIFO_UNF:
60962306a36Sopenharmony_ci			ret = -ENOSPC;
61062306a36Sopenharmony_ci			break;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci		case CMDR_INVALID_DA:
61362306a36Sopenharmony_ci		default:
61462306a36Sopenharmony_ci			ret = -EINVAL;
61562306a36Sopenharmony_ci			break;
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	xfer->ret = ret;
62062306a36Sopenharmony_ci	complete(&xfer->comp);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	xfer = list_first_entry_or_null(&master->xferqueue.list,
62362306a36Sopenharmony_ci					struct cdns_i3c_xfer, node);
62462306a36Sopenharmony_ci	if (xfer)
62562306a36Sopenharmony_ci		list_del_init(&xfer->node);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	master->xferqueue.cur = xfer;
62862306a36Sopenharmony_ci	cdns_i3c_master_start_xfer_locked(master);
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic void cdns_i3c_master_queue_xfer(struct cdns_i3c_master *master,
63262306a36Sopenharmony_ci				       struct cdns_i3c_xfer *xfer)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	unsigned long flags;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	init_completion(&xfer->comp);
63762306a36Sopenharmony_ci	spin_lock_irqsave(&master->xferqueue.lock, flags);
63862306a36Sopenharmony_ci	if (master->xferqueue.cur) {
63962306a36Sopenharmony_ci		list_add_tail(&xfer->node, &master->xferqueue.list);
64062306a36Sopenharmony_ci	} else {
64162306a36Sopenharmony_ci		master->xferqueue.cur = xfer;
64262306a36Sopenharmony_ci		cdns_i3c_master_start_xfer_locked(master);
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci	spin_unlock_irqrestore(&master->xferqueue.lock, flags);
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic void cdns_i3c_master_unqueue_xfer(struct cdns_i3c_master *master,
64862306a36Sopenharmony_ci					 struct cdns_i3c_xfer *xfer)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	unsigned long flags;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	spin_lock_irqsave(&master->xferqueue.lock, flags);
65362306a36Sopenharmony_ci	if (master->xferqueue.cur == xfer) {
65462306a36Sopenharmony_ci		u32 status;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci		writel(readl(master->regs + CTRL) & ~CTRL_DEV_EN,
65762306a36Sopenharmony_ci		       master->regs + CTRL);
65862306a36Sopenharmony_ci		readl_poll_timeout_atomic(master->regs + MST_STATUS0, status,
65962306a36Sopenharmony_ci					  status & MST_STATUS0_IDLE, 10,
66062306a36Sopenharmony_ci					  1000000);
66162306a36Sopenharmony_ci		master->xferqueue.cur = NULL;
66262306a36Sopenharmony_ci		writel(FLUSH_RX_FIFO | FLUSH_TX_FIFO | FLUSH_CMD_FIFO |
66362306a36Sopenharmony_ci		       FLUSH_CMD_RESP,
66462306a36Sopenharmony_ci		       master->regs + FLUSH_CTRL);
66562306a36Sopenharmony_ci		writel(MST_INT_CMDD_EMP, master->regs + MST_IDR);
66662306a36Sopenharmony_ci		writel(readl(master->regs + CTRL) | CTRL_DEV_EN,
66762306a36Sopenharmony_ci		       master->regs + CTRL);
66862306a36Sopenharmony_ci	} else {
66962306a36Sopenharmony_ci		list_del_init(&xfer->node);
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci	spin_unlock_irqrestore(&master->xferqueue.lock, flags);
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic enum i3c_error_code cdns_i3c_cmd_get_err(struct cdns_i3c_cmd *cmd)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	switch (cmd->error) {
67762306a36Sopenharmony_ci	case CMDR_M0_ERROR:
67862306a36Sopenharmony_ci		return I3C_ERROR_M0;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	case CMDR_M1_ERROR:
68162306a36Sopenharmony_ci		return I3C_ERROR_M1;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	case CMDR_M2_ERROR:
68462306a36Sopenharmony_ci	case CMDR_NACK_RESP:
68562306a36Sopenharmony_ci		return I3C_ERROR_M2;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	default:
68862306a36Sopenharmony_ci		break;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	return I3C_ERROR_UNKNOWN;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic int cdns_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
69562306a36Sopenharmony_ci					struct i3c_ccc_cmd *cmd)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
69862306a36Sopenharmony_ci	struct cdns_i3c_xfer *xfer;
69962306a36Sopenharmony_ci	struct cdns_i3c_cmd *ccmd;
70062306a36Sopenharmony_ci	int ret;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	xfer = cdns_i3c_master_alloc_xfer(master, 1);
70362306a36Sopenharmony_ci	if (!xfer)
70462306a36Sopenharmony_ci		return -ENOMEM;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	ccmd = xfer->cmds;
70762306a36Sopenharmony_ci	ccmd->cmd1 = CMD1_FIFO_CCC(cmd->id);
70862306a36Sopenharmony_ci	ccmd->cmd0 = CMD0_FIFO_IS_CCC |
70962306a36Sopenharmony_ci		     CMD0_FIFO_PL_LEN(cmd->dests[0].payload.len);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (cmd->id & I3C_CCC_DIRECT)
71262306a36Sopenharmony_ci		ccmd->cmd0 |= CMD0_FIFO_DEV_ADDR(cmd->dests[0].addr);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (cmd->rnw) {
71562306a36Sopenharmony_ci		ccmd->cmd0 |= CMD0_FIFO_RNW;
71662306a36Sopenharmony_ci		ccmd->rx_buf = cmd->dests[0].payload.data;
71762306a36Sopenharmony_ci		ccmd->rx_len = cmd->dests[0].payload.len;
71862306a36Sopenharmony_ci	} else {
71962306a36Sopenharmony_ci		ccmd->tx_buf = cmd->dests[0].payload.data;
72062306a36Sopenharmony_ci		ccmd->tx_len = cmd->dests[0].payload.len;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	cdns_i3c_master_queue_xfer(master, xfer);
72462306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
72562306a36Sopenharmony_ci		cdns_i3c_master_unqueue_xfer(master, xfer);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	ret = xfer->ret;
72862306a36Sopenharmony_ci	cmd->err = cdns_i3c_cmd_get_err(&xfer->cmds[0]);
72962306a36Sopenharmony_ci	cdns_i3c_master_free_xfer(xfer);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return ret;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
73562306a36Sopenharmony_ci				      struct i3c_priv_xfer *xfers,
73662306a36Sopenharmony_ci				      int nxfers)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	struct i3c_master_controller *m = i3c_dev_get_master(dev);
73962306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
74062306a36Sopenharmony_ci	int txslots = 0, rxslots = 0, i, ret;
74162306a36Sopenharmony_ci	struct cdns_i3c_xfer *cdns_xfer;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	for (i = 0; i < nxfers; i++) {
74462306a36Sopenharmony_ci		if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
74562306a36Sopenharmony_ci			return -ENOTSUPP;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (!nxfers)
74962306a36Sopenharmony_ci		return 0;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (nxfers > master->caps.cmdfifodepth ||
75262306a36Sopenharmony_ci	    nxfers > master->caps.cmdrfifodepth)
75362306a36Sopenharmony_ci		return -ENOTSUPP;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/*
75662306a36Sopenharmony_ci	 * First make sure that all transactions (block of transfers separated
75762306a36Sopenharmony_ci	 * by a STOP marker) fit in the FIFOs.
75862306a36Sopenharmony_ci	 */
75962306a36Sopenharmony_ci	for (i = 0; i < nxfers; i++) {
76062306a36Sopenharmony_ci		if (xfers[i].rnw)
76162306a36Sopenharmony_ci			rxslots += DIV_ROUND_UP(xfers[i].len, 4);
76262306a36Sopenharmony_ci		else
76362306a36Sopenharmony_ci			txslots += DIV_ROUND_UP(xfers[i].len, 4);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	if (rxslots > master->caps.rxfifodepth ||
76762306a36Sopenharmony_ci	    txslots > master->caps.txfifodepth)
76862306a36Sopenharmony_ci		return -ENOTSUPP;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	cdns_xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
77162306a36Sopenharmony_ci	if (!cdns_xfer)
77262306a36Sopenharmony_ci		return -ENOMEM;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	for (i = 0; i < nxfers; i++) {
77562306a36Sopenharmony_ci		struct cdns_i3c_cmd *ccmd = &cdns_xfer->cmds[i];
77662306a36Sopenharmony_ci		u32 pl_len = xfers[i].len;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci		ccmd->cmd0 = CMD0_FIFO_DEV_ADDR(dev->info.dyn_addr) |
77962306a36Sopenharmony_ci			CMD0_FIFO_PRIV_XMIT_MODE(XMIT_BURST_WITHOUT_SUBADDR);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci		if (xfers[i].rnw) {
78262306a36Sopenharmony_ci			ccmd->cmd0 |= CMD0_FIFO_RNW;
78362306a36Sopenharmony_ci			ccmd->rx_buf = xfers[i].data.in;
78462306a36Sopenharmony_ci			ccmd->rx_len = xfers[i].len;
78562306a36Sopenharmony_ci			pl_len++;
78662306a36Sopenharmony_ci		} else {
78762306a36Sopenharmony_ci			ccmd->tx_buf = xfers[i].data.out;
78862306a36Sopenharmony_ci			ccmd->tx_len = xfers[i].len;
78962306a36Sopenharmony_ci		}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci		ccmd->cmd0 |= CMD0_FIFO_PL_LEN(pl_len);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		if (i < nxfers - 1)
79462306a36Sopenharmony_ci			ccmd->cmd0 |= CMD0_FIFO_RSBC;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		if (!i)
79762306a36Sopenharmony_ci			ccmd->cmd0 |= CMD0_FIFO_BCH;
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	cdns_i3c_master_queue_xfer(master, cdns_xfer);
80162306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&cdns_xfer->comp,
80262306a36Sopenharmony_ci					 msecs_to_jiffies(1000)))
80362306a36Sopenharmony_ci		cdns_i3c_master_unqueue_xfer(master, cdns_xfer);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	ret = cdns_xfer->ret;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	for (i = 0; i < nxfers; i++)
80862306a36Sopenharmony_ci		xfers[i].err = cdns_i3c_cmd_get_err(&cdns_xfer->cmds[i]);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	cdns_i3c_master_free_xfer(cdns_xfer);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	return ret;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
81662306a36Sopenharmony_ci				     const struct i2c_msg *xfers, int nxfers)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	struct i3c_master_controller *m = i2c_dev_get_master(dev);
81962306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
82062306a36Sopenharmony_ci	unsigned int nrxwords = 0, ntxwords = 0;
82162306a36Sopenharmony_ci	struct cdns_i3c_xfer *xfer;
82262306a36Sopenharmony_ci	int i, ret = 0;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if (nxfers > master->caps.cmdfifodepth)
82562306a36Sopenharmony_ci		return -ENOTSUPP;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	for (i = 0; i < nxfers; i++) {
82862306a36Sopenharmony_ci		if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
82962306a36Sopenharmony_ci			return -ENOTSUPP;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		if (xfers[i].flags & I2C_M_RD)
83262306a36Sopenharmony_ci			nrxwords += DIV_ROUND_UP(xfers[i].len, 4);
83362306a36Sopenharmony_ci		else
83462306a36Sopenharmony_ci			ntxwords += DIV_ROUND_UP(xfers[i].len, 4);
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	if (ntxwords > master->caps.txfifodepth ||
83862306a36Sopenharmony_ci	    nrxwords > master->caps.rxfifodepth)
83962306a36Sopenharmony_ci		return -ENOTSUPP;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
84262306a36Sopenharmony_ci	if (!xfer)
84362306a36Sopenharmony_ci		return -ENOMEM;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	for (i = 0; i < nxfers; i++) {
84662306a36Sopenharmony_ci		struct cdns_i3c_cmd *ccmd = &xfer->cmds[i];
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci		ccmd->cmd0 = CMD0_FIFO_DEV_ADDR(xfers[i].addr) |
84962306a36Sopenharmony_ci			CMD0_FIFO_PL_LEN(xfers[i].len) |
85062306a36Sopenharmony_ci			CMD0_FIFO_PRIV_XMIT_MODE(XMIT_BURST_WITHOUT_SUBADDR);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci		if (xfers[i].flags & I2C_M_TEN)
85362306a36Sopenharmony_ci			ccmd->cmd0 |= CMD0_FIFO_IS_10B;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci		if (xfers[i].flags & I2C_M_RD) {
85662306a36Sopenharmony_ci			ccmd->cmd0 |= CMD0_FIFO_RNW;
85762306a36Sopenharmony_ci			ccmd->rx_buf = xfers[i].buf;
85862306a36Sopenharmony_ci			ccmd->rx_len = xfers[i].len;
85962306a36Sopenharmony_ci		} else {
86062306a36Sopenharmony_ci			ccmd->tx_buf = xfers[i].buf;
86162306a36Sopenharmony_ci			ccmd->tx_len = xfers[i].len;
86262306a36Sopenharmony_ci		}
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	cdns_i3c_master_queue_xfer(master, xfer);
86662306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
86762306a36Sopenharmony_ci		cdns_i3c_master_unqueue_xfer(master, xfer);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	ret = xfer->ret;
87062306a36Sopenharmony_ci	cdns_i3c_master_free_xfer(xfer);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	return ret;
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistruct cdns_i3c_i2c_dev_data {
87662306a36Sopenharmony_ci	u16 id;
87762306a36Sopenharmony_ci	s16 ibi;
87862306a36Sopenharmony_ci	struct i3c_generic_ibi_pool *ibi_pool;
87962306a36Sopenharmony_ci};
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_cistatic u32 prepare_rr0_dev_address(u32 addr)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	u32 ret = (addr << 1) & 0xff;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	/* RR0[7:1] = addr[6:0] */
88662306a36Sopenharmony_ci	ret |= (addr & GENMASK(6, 0)) << 1;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/* RR0[15:13] = addr[9:7] */
88962306a36Sopenharmony_ci	ret |= (addr & GENMASK(9, 7)) << 6;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	/* RR0[0] = ~XOR(addr[6:0]) */
89262306a36Sopenharmony_ci	if (!(hweight8(addr & 0x7f) & 1))
89362306a36Sopenharmony_ci		ret |= 1;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	return ret;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic void cdns_i3c_master_upd_i3c_addr(struct i3c_dev_desc *dev)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	struct i3c_master_controller *m = i3c_dev_get_master(dev);
90162306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
90262306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
90362306a36Sopenharmony_ci	u32 rr;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	rr = prepare_rr0_dev_address(dev->info.dyn_addr ?
90662306a36Sopenharmony_ci				     dev->info.dyn_addr :
90762306a36Sopenharmony_ci				     dev->info.static_addr);
90862306a36Sopenharmony_ci	writel(DEV_ID_RR0_IS_I3C | rr, master->regs + DEV_ID_RR0(data->id));
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master,
91262306a36Sopenharmony_ci				       u8 dyn_addr)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	unsigned long activedevs;
91562306a36Sopenharmony_ci	u32 rr;
91662306a36Sopenharmony_ci	int i;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (!dyn_addr) {
91962306a36Sopenharmony_ci		if (!master->free_rr_slots)
92062306a36Sopenharmony_ci			return -ENOSPC;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci		return ffs(master->free_rr_slots) - 1;
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	activedevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
92662306a36Sopenharmony_ci	activedevs &= ~BIT(0);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	for_each_set_bit(i, &activedevs, master->maxdevs + 1) {
92962306a36Sopenharmony_ci		rr = readl(master->regs + DEV_ID_RR0(i));
93062306a36Sopenharmony_ci		if (!(rr & DEV_ID_RR0_IS_I3C) ||
93162306a36Sopenharmony_ci		    DEV_ID_RR0_GET_DEV_ADDR(rr) != dyn_addr)
93262306a36Sopenharmony_ci			continue;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci		return i;
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	return -EINVAL;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic int cdns_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
94162306a36Sopenharmony_ci					    u8 old_dyn_addr)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	cdns_i3c_master_upd_i3c_addr(dev);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	return 0;
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cistatic int cdns_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct i3c_master_controller *m = i3c_dev_get_master(dev);
95162306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
95262306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data;
95362306a36Sopenharmony_ci	int slot;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	data = kzalloc(sizeof(*data), GFP_KERNEL);
95662306a36Sopenharmony_ci	if (!data)
95762306a36Sopenharmony_ci		return -ENOMEM;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	slot = cdns_i3c_master_get_rr_slot(master, dev->info.dyn_addr);
96062306a36Sopenharmony_ci	if (slot < 0) {
96162306a36Sopenharmony_ci		kfree(data);
96262306a36Sopenharmony_ci		return slot;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	data->ibi = -1;
96662306a36Sopenharmony_ci	data->id = slot;
96762306a36Sopenharmony_ci	i3c_dev_set_master_data(dev, data);
96862306a36Sopenharmony_ci	master->free_rr_slots &= ~BIT(slot);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	if (!dev->info.dyn_addr) {
97162306a36Sopenharmony_ci		cdns_i3c_master_upd_i3c_addr(dev);
97262306a36Sopenharmony_ci		writel(readl(master->regs + DEVS_CTRL) |
97362306a36Sopenharmony_ci		       DEVS_CTRL_DEV_ACTIVE(data->id),
97462306a36Sopenharmony_ci		       master->regs + DEVS_CTRL);
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	return 0;
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cistatic void cdns_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	struct i3c_master_controller *m = i3c_dev_get_master(dev);
98362306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
98462306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	writel(readl(master->regs + DEVS_CTRL) |
98762306a36Sopenharmony_ci	       DEVS_CTRL_DEV_CLR(data->id),
98862306a36Sopenharmony_ci	       master->regs + DEVS_CTRL);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	i3c_dev_set_master_data(dev, NULL);
99162306a36Sopenharmony_ci	master->free_rr_slots |= BIT(data->id);
99262306a36Sopenharmony_ci	kfree(data);
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_cistatic int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct i3c_master_controller *m = i2c_dev_get_master(dev);
99862306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
99962306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data;
100062306a36Sopenharmony_ci	int slot;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	slot = cdns_i3c_master_get_rr_slot(master, 0);
100362306a36Sopenharmony_ci	if (slot < 0)
100462306a36Sopenharmony_ci		return slot;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	data = kzalloc(sizeof(*data), GFP_KERNEL);
100762306a36Sopenharmony_ci	if (!data)
100862306a36Sopenharmony_ci		return -ENOMEM;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	data->id = slot;
101162306a36Sopenharmony_ci	master->free_rr_slots &= ~BIT(slot);
101262306a36Sopenharmony_ci	i2c_dev_set_master_data(dev, data);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	writel(prepare_rr0_dev_address(dev->addr),
101562306a36Sopenharmony_ci	       master->regs + DEV_ID_RR0(data->id));
101662306a36Sopenharmony_ci	writel(dev->lvr, master->regs + DEV_ID_RR2(data->id));
101762306a36Sopenharmony_ci	writel(readl(master->regs + DEVS_CTRL) |
101862306a36Sopenharmony_ci	       DEVS_CTRL_DEV_ACTIVE(data->id),
101962306a36Sopenharmony_ci	       master->regs + DEVS_CTRL);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	return 0;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic void cdns_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	struct i3c_master_controller *m = i2c_dev_get_master(dev);
102762306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
102862306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	writel(readl(master->regs + DEVS_CTRL) |
103162306a36Sopenharmony_ci	       DEVS_CTRL_DEV_CLR(data->id),
103262306a36Sopenharmony_ci	       master->regs + DEVS_CTRL);
103362306a36Sopenharmony_ci	master->free_rr_slots |= BIT(data->id);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	i2c_dev_set_master_data(dev, NULL);
103662306a36Sopenharmony_ci	kfree(data);
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic void cdns_i3c_master_bus_cleanup(struct i3c_master_controller *m)
104062306a36Sopenharmony_ci{
104162306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	cdns_i3c_master_disable(master);
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic void cdns_i3c_master_dev_rr_to_info(struct cdns_i3c_master *master,
104762306a36Sopenharmony_ci					   unsigned int slot,
104862306a36Sopenharmony_ci					   struct i3c_device_info *info)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	u32 rr;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	memset(info, 0, sizeof(*info));
105362306a36Sopenharmony_ci	rr = readl(master->regs + DEV_ID_RR0(slot));
105462306a36Sopenharmony_ci	info->dyn_addr = DEV_ID_RR0_GET_DEV_ADDR(rr);
105562306a36Sopenharmony_ci	rr = readl(master->regs + DEV_ID_RR2(slot));
105662306a36Sopenharmony_ci	info->dcr = rr;
105762306a36Sopenharmony_ci	info->bcr = rr >> 8;
105862306a36Sopenharmony_ci	info->pid = rr >> 16;
105962306a36Sopenharmony_ci	info->pid |= (u64)readl(master->regs + DEV_ID_RR1(slot)) << 16;
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct i3c_master_controller *m = &master->base;
106562306a36Sopenharmony_ci	unsigned long i3c_lim_period, pres_step, ncycles;
106662306a36Sopenharmony_ci	struct i3c_bus *bus = i3c_master_get_bus(m);
106762306a36Sopenharmony_ci	unsigned long new_i3c_scl_lim = 0;
106862306a36Sopenharmony_ci	struct i3c_dev_desc *dev;
106962306a36Sopenharmony_ci	u32 prescl1, ctrl;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	i3c_bus_for_each_i3cdev(bus, dev) {
107262306a36Sopenharmony_ci		unsigned long max_fscl;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci		max_fscl = max(I3C_CCC_MAX_SDR_FSCL(dev->info.max_read_ds),
107562306a36Sopenharmony_ci			       I3C_CCC_MAX_SDR_FSCL(dev->info.max_write_ds));
107662306a36Sopenharmony_ci		switch (max_fscl) {
107762306a36Sopenharmony_ci		case I3C_SDR1_FSCL_8MHZ:
107862306a36Sopenharmony_ci			max_fscl = 8000000;
107962306a36Sopenharmony_ci			break;
108062306a36Sopenharmony_ci		case I3C_SDR2_FSCL_6MHZ:
108162306a36Sopenharmony_ci			max_fscl = 6000000;
108262306a36Sopenharmony_ci			break;
108362306a36Sopenharmony_ci		case I3C_SDR3_FSCL_4MHZ:
108462306a36Sopenharmony_ci			max_fscl = 4000000;
108562306a36Sopenharmony_ci			break;
108662306a36Sopenharmony_ci		case I3C_SDR4_FSCL_2MHZ:
108762306a36Sopenharmony_ci			max_fscl = 2000000;
108862306a36Sopenharmony_ci			break;
108962306a36Sopenharmony_ci		case I3C_SDR0_FSCL_MAX:
109062306a36Sopenharmony_ci		default:
109162306a36Sopenharmony_ci			max_fscl = 0;
109262306a36Sopenharmony_ci			break;
109362306a36Sopenharmony_ci		}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci		if (max_fscl &&
109662306a36Sopenharmony_ci		    (new_i3c_scl_lim > max_fscl || !new_i3c_scl_lim))
109762306a36Sopenharmony_ci			new_i3c_scl_lim = max_fscl;
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/* Only update PRESCL_CTRL1 if the I3C SCL limitation has changed. */
110162306a36Sopenharmony_ci	if (new_i3c_scl_lim == master->i3c_scl_lim)
110262306a36Sopenharmony_ci		return;
110362306a36Sopenharmony_ci	master->i3c_scl_lim = new_i3c_scl_lim;
110462306a36Sopenharmony_ci	if (!new_i3c_scl_lim)
110562306a36Sopenharmony_ci		return;
110662306a36Sopenharmony_ci	pres_step = 1000000000UL / (bus->scl_rate.i3c * 4);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/* Configure PP_LOW to meet I3C slave limitations. */
110962306a36Sopenharmony_ci	prescl1 = readl(master->regs + PRESCL_CTRL1) &
111062306a36Sopenharmony_ci		  ~PRESCL_CTRL1_PP_LOW_MASK;
111162306a36Sopenharmony_ci	ctrl = readl(master->regs + CTRL);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	i3c_lim_period = DIV_ROUND_UP(1000000000, master->i3c_scl_lim);
111462306a36Sopenharmony_ci	ncycles = DIV_ROUND_UP(i3c_lim_period, pres_step);
111562306a36Sopenharmony_ci	if (ncycles < 4)
111662306a36Sopenharmony_ci		ncycles = 0;
111762306a36Sopenharmony_ci	else
111862306a36Sopenharmony_ci		ncycles -= 4;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	prescl1 |= PRESCL_CTRL1_PP_LOW(ncycles);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	/* Disable I3C master before updating PRESCL_CTRL1. */
112362306a36Sopenharmony_ci	if (ctrl & CTRL_DEV_EN)
112462306a36Sopenharmony_ci		cdns_i3c_master_disable(master);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	writel(prescl1, master->regs + PRESCL_CTRL1);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (ctrl & CTRL_DEV_EN)
112962306a36Sopenharmony_ci		cdns_i3c_master_enable(master);
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
113562306a36Sopenharmony_ci	unsigned long olddevs, newdevs;
113662306a36Sopenharmony_ci	int ret, slot;
113762306a36Sopenharmony_ci	u8 addrs[MAX_DEVS] = { };
113862306a36Sopenharmony_ci	u8 last_addr = 0;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
114162306a36Sopenharmony_ci	olddevs |= BIT(0);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	/* Prepare RR slots before launching DAA. */
114462306a36Sopenharmony_ci	for_each_clear_bit(slot, &olddevs, master->maxdevs + 1) {
114562306a36Sopenharmony_ci		ret = i3c_master_get_free_addr(m, last_addr + 1);
114662306a36Sopenharmony_ci		if (ret < 0)
114762306a36Sopenharmony_ci			return -ENOSPC;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci		last_addr = ret;
115062306a36Sopenharmony_ci		addrs[slot] = last_addr;
115162306a36Sopenharmony_ci		writel(prepare_rr0_dev_address(last_addr) | DEV_ID_RR0_IS_I3C,
115262306a36Sopenharmony_ci		       master->regs + DEV_ID_RR0(slot));
115362306a36Sopenharmony_ci		writel(0, master->regs + DEV_ID_RR1(slot));
115462306a36Sopenharmony_ci		writel(0, master->regs + DEV_ID_RR2(slot));
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	ret = i3c_master_entdaa_locked(&master->base);
115862306a36Sopenharmony_ci	if (ret && ret != I3C_ERROR_M2)
115962306a36Sopenharmony_ci		return ret;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	newdevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
116262306a36Sopenharmony_ci	newdevs &= ~olddevs;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	/*
116562306a36Sopenharmony_ci	 * Clear all retaining registers filled during DAA. We already
116662306a36Sopenharmony_ci	 * have the addressed assigned to them in the addrs array.
116762306a36Sopenharmony_ci	 */
116862306a36Sopenharmony_ci	for_each_set_bit(slot, &newdevs, master->maxdevs + 1)
116962306a36Sopenharmony_ci		i3c_master_add_i3c_dev_locked(m, addrs[slot]);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	/*
117262306a36Sopenharmony_ci	 * Clear slots that ended up not being used. Can be caused by I3C
117362306a36Sopenharmony_ci	 * device creation failure or when the I3C device was already known
117462306a36Sopenharmony_ci	 * by the system but with a different address (in this case the device
117562306a36Sopenharmony_ci	 * already has a slot and does not need a new one).
117662306a36Sopenharmony_ci	 */
117762306a36Sopenharmony_ci	writel(readl(master->regs + DEVS_CTRL) |
117862306a36Sopenharmony_ci	       master->free_rr_slots << DEVS_CTRL_DEV_CLR_SHIFT,
117962306a36Sopenharmony_ci	       master->regs + DEVS_CTRL);
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	i3c_master_defslvs_locked(&master->base);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	cdns_i3c_master_upd_i3c_scl_lim(master);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	/* Unmask Hot-Join and Mastership request interrupts. */
118662306a36Sopenharmony_ci	i3c_master_enec_locked(m, I3C_BROADCAST_ADDR,
118762306a36Sopenharmony_ci			       I3C_CCC_EVENT_HJ | I3C_CCC_EVENT_MR);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	return 0;
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic u8 cdns_i3c_master_calculate_thd_delay(struct cdns_i3c_master *master)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	unsigned long sysclk_rate = clk_get_rate(master->sysclk);
119562306a36Sopenharmony_ci	u8 thd_delay = DIV_ROUND_UP(master->devdata->thd_delay_ns,
119662306a36Sopenharmony_ci				    (NSEC_PER_SEC / sysclk_rate));
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	/* Every value greater than 3 is not valid. */
119962306a36Sopenharmony_ci	if (thd_delay > THD_DELAY_MAX)
120062306a36Sopenharmony_ci		thd_delay = THD_DELAY_MAX;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/* CTLR_THD_DEL value is encoded. */
120362306a36Sopenharmony_ci	return (THD_DELAY_MAX - thd_delay);
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
120962306a36Sopenharmony_ci	unsigned long pres_step, sysclk_rate, max_i2cfreq;
121062306a36Sopenharmony_ci	struct i3c_bus *bus = i3c_master_get_bus(m);
121162306a36Sopenharmony_ci	u32 ctrl, prescl0, prescl1, pres, low;
121262306a36Sopenharmony_ci	struct i3c_device_info info = { };
121362306a36Sopenharmony_ci	int ret, ncycles;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	switch (bus->mode) {
121662306a36Sopenharmony_ci	case I3C_BUS_MODE_PURE:
121762306a36Sopenharmony_ci		ctrl = CTRL_PURE_BUS_MODE;
121862306a36Sopenharmony_ci		break;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	case I3C_BUS_MODE_MIXED_FAST:
122162306a36Sopenharmony_ci		ctrl = CTRL_MIXED_FAST_BUS_MODE;
122262306a36Sopenharmony_ci		break;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	case I3C_BUS_MODE_MIXED_SLOW:
122562306a36Sopenharmony_ci		ctrl = CTRL_MIXED_SLOW_BUS_MODE;
122662306a36Sopenharmony_ci		break;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	default:
122962306a36Sopenharmony_ci		return -EINVAL;
123062306a36Sopenharmony_ci	}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	sysclk_rate = clk_get_rate(master->sysclk);
123362306a36Sopenharmony_ci	if (!sysclk_rate)
123462306a36Sopenharmony_ci		return -EINVAL;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1;
123762306a36Sopenharmony_ci	if (pres > PRESCL_CTRL0_I3C_MAX)
123862306a36Sopenharmony_ci		return -ERANGE;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	bus->scl_rate.i3c = sysclk_rate / ((pres + 1) * 4);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	prescl0 = PRESCL_CTRL0_I3C(pres);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	low = ((I3C_BUS_TLOW_OD_MIN_NS * sysclk_rate) / (pres + 1)) - 2;
124562306a36Sopenharmony_ci	prescl1 = PRESCL_CTRL1_OD_LOW(low);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	max_i2cfreq = bus->scl_rate.i2c;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	pres = (sysclk_rate / (max_i2cfreq * 5)) - 1;
125062306a36Sopenharmony_ci	if (pres > PRESCL_CTRL0_I2C_MAX)
125162306a36Sopenharmony_ci		return -ERANGE;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	prescl0 |= PRESCL_CTRL0_I2C(pres);
125662306a36Sopenharmony_ci	writel(prescl0, master->regs + PRESCL_CTRL0);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	/* Calculate OD and PP low. */
125962306a36Sopenharmony_ci	pres_step = 1000000000 / (bus->scl_rate.i3c * 4);
126062306a36Sopenharmony_ci	ncycles = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, pres_step) - 2;
126162306a36Sopenharmony_ci	if (ncycles < 0)
126262306a36Sopenharmony_ci		ncycles = 0;
126362306a36Sopenharmony_ci	prescl1 = PRESCL_CTRL1_OD_LOW(ncycles);
126462306a36Sopenharmony_ci	writel(prescl1, master->regs + PRESCL_CTRL1);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	/* Get an address for the master. */
126762306a36Sopenharmony_ci	ret = i3c_master_get_free_addr(m, 0);
126862306a36Sopenharmony_ci	if (ret < 0)
126962306a36Sopenharmony_ci		return ret;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C,
127262306a36Sopenharmony_ci	       master->regs + DEV_ID_RR0(0));
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	cdns_i3c_master_dev_rr_to_info(master, 0, &info);
127562306a36Sopenharmony_ci	if (info.bcr & I3C_BCR_HDR_CAP)
127662306a36Sopenharmony_ci		info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	ret = i3c_master_set_info(&master->base, &info);
127962306a36Sopenharmony_ci	if (ret)
128062306a36Sopenharmony_ci		return ret;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	/*
128362306a36Sopenharmony_ci	 * Enable Hot-Join, and, when a Hot-Join request happens, disable all
128462306a36Sopenharmony_ci	 * events coming from this device.
128562306a36Sopenharmony_ci	 *
128662306a36Sopenharmony_ci	 * We will issue ENTDAA afterwards from the threaded IRQ handler.
128762306a36Sopenharmony_ci	 */
128862306a36Sopenharmony_ci	ctrl |= CTRL_HJ_ACK | CTRL_HJ_DISEC | CTRL_HALT_EN | CTRL_MCS_EN;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/*
129162306a36Sopenharmony_ci	 * Configure data hold delay based on device-specific data.
129262306a36Sopenharmony_ci	 *
129362306a36Sopenharmony_ci	 * MIPI I3C Specification 1.0 defines non-zero minimal tHD_PP timing on
129462306a36Sopenharmony_ci	 * master output. This setting allows to meet this timing on master's
129562306a36Sopenharmony_ci	 * SoC outputs, regardless of PCB balancing.
129662306a36Sopenharmony_ci	 */
129762306a36Sopenharmony_ci	ctrl |= CTRL_THD_DELAY(cdns_i3c_master_calculate_thd_delay(master));
129862306a36Sopenharmony_ci	writel(ctrl, master->regs + CTRL);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	cdns_i3c_master_enable(master);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	return 0;
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
130662306a36Sopenharmony_ci				       u32 ibir)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data;
130962306a36Sopenharmony_ci	bool data_consumed = false;
131062306a36Sopenharmony_ci	struct i3c_ibi_slot *slot;
131162306a36Sopenharmony_ci	u32 id = IBIR_SLVID(ibir);
131262306a36Sopenharmony_ci	struct i3c_dev_desc *dev;
131362306a36Sopenharmony_ci	size_t nbytes;
131462306a36Sopenharmony_ci	u8 *buf;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	/*
131762306a36Sopenharmony_ci	 * FIXME: maybe we should report the FIFO OVF errors to the upper
131862306a36Sopenharmony_ci	 * layer.
131962306a36Sopenharmony_ci	 */
132062306a36Sopenharmony_ci	if (id >= master->ibi.num_slots || (ibir & IBIR_ERROR))
132162306a36Sopenharmony_ci		goto out;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	dev = master->ibi.slots[id];
132462306a36Sopenharmony_ci	spin_lock(&master->ibi.lock);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	data = i3c_dev_get_master_data(dev);
132762306a36Sopenharmony_ci	slot = i3c_generic_ibi_get_free_slot(data->ibi_pool);
132862306a36Sopenharmony_ci	if (!slot)
132962306a36Sopenharmony_ci		goto out_unlock;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	buf = slot->data;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	nbytes = IBIR_XFER_BYTES(ibir);
133462306a36Sopenharmony_ci	readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4);
133562306a36Sopenharmony_ci	if (nbytes % 3) {
133662306a36Sopenharmony_ci		u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci		memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir),
134262306a36Sopenharmony_ci			  dev->ibi->max_payload_len);
134362306a36Sopenharmony_ci	i3c_master_queue_ibi(dev, slot);
134462306a36Sopenharmony_ci	data_consumed = true;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ciout_unlock:
134762306a36Sopenharmony_ci	spin_unlock(&master->ibi.lock);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ciout:
135062306a36Sopenharmony_ci	/* Consume data from the FIFO if it's not been done already. */
135162306a36Sopenharmony_ci	if (!data_consumed) {
135262306a36Sopenharmony_ci		int i;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci		for (i = 0; i < IBIR_XFER_BYTES(ibir); i += 4)
135562306a36Sopenharmony_ci			readl(master->regs + IBI_DATA_FIFO);
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic void cnds_i3c_master_demux_ibis(struct cdns_i3c_master *master)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	u32 status0;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	writel(MST_INT_IBIR_THR, master->regs + MST_ICR);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	for (status0 = readl(master->regs + MST_STATUS0);
136662306a36Sopenharmony_ci	     !(status0 & MST_STATUS0_IBIR_EMP);
136762306a36Sopenharmony_ci	     status0 = readl(master->regs + MST_STATUS0)) {
136862306a36Sopenharmony_ci		u32 ibir = readl(master->regs + IBIR);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci		switch (IBIR_TYPE(ibir)) {
137162306a36Sopenharmony_ci		case IBIR_TYPE_IBI:
137262306a36Sopenharmony_ci			cdns_i3c_master_handle_ibi(master, ibir);
137362306a36Sopenharmony_ci			break;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci		case IBIR_TYPE_HJ:
137662306a36Sopenharmony_ci			WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR));
137762306a36Sopenharmony_ci			queue_work(master->base.wq, &master->hj_work);
137862306a36Sopenharmony_ci			break;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci		case IBIR_TYPE_MR:
138162306a36Sopenharmony_ci			WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR));
138262306a36Sopenharmony_ci			break;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci		default:
138562306a36Sopenharmony_ci			break;
138662306a36Sopenharmony_ci		}
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic irqreturn_t cdns_i3c_master_interrupt(int irq, void *data)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	struct cdns_i3c_master *master = data;
139362306a36Sopenharmony_ci	u32 status;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	status = readl(master->regs + MST_ISR);
139662306a36Sopenharmony_ci	if (!(status & readl(master->regs + MST_IMR)))
139762306a36Sopenharmony_ci		return IRQ_NONE;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	spin_lock(&master->xferqueue.lock);
140062306a36Sopenharmony_ci	cdns_i3c_master_end_xfer_locked(master, status);
140162306a36Sopenharmony_ci	spin_unlock(&master->xferqueue.lock);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	if (status & MST_INT_IBIR_THR)
140462306a36Sopenharmony_ci		cnds_i3c_master_demux_ibis(master);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	return IRQ_HANDLED;
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic int cdns_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
141062306a36Sopenharmony_ci{
141162306a36Sopenharmony_ci	struct i3c_master_controller *m = i3c_dev_get_master(dev);
141262306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
141362306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
141462306a36Sopenharmony_ci	unsigned long flags;
141562306a36Sopenharmony_ci	u32 sirmap;
141662306a36Sopenharmony_ci	int ret;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	ret = i3c_master_disec_locked(m, dev->info.dyn_addr,
141962306a36Sopenharmony_ci				      I3C_CCC_EVENT_SIR);
142062306a36Sopenharmony_ci	if (ret)
142162306a36Sopenharmony_ci		return ret;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	spin_lock_irqsave(&master->ibi.lock, flags);
142462306a36Sopenharmony_ci	sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
142562306a36Sopenharmony_ci	sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
142662306a36Sopenharmony_ci	sirmap |= SIR_MAP_DEV_CONF(data->ibi,
142762306a36Sopenharmony_ci				   SIR_MAP_DEV_DA(I3C_BROADCAST_ADDR));
142862306a36Sopenharmony_ci	writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
142962306a36Sopenharmony_ci	spin_unlock_irqrestore(&master->ibi.lock, flags);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	return ret;
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_cistatic int cdns_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
143562306a36Sopenharmony_ci{
143662306a36Sopenharmony_ci	struct i3c_master_controller *m = i3c_dev_get_master(dev);
143762306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
143862306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
143962306a36Sopenharmony_ci	unsigned long flags;
144062306a36Sopenharmony_ci	u32 sircfg, sirmap;
144162306a36Sopenharmony_ci	int ret;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	spin_lock_irqsave(&master->ibi.lock, flags);
144462306a36Sopenharmony_ci	sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
144562306a36Sopenharmony_ci	sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
144662306a36Sopenharmony_ci	sircfg = SIR_MAP_DEV_ROLE(dev->info.bcr >> 6) |
144762306a36Sopenharmony_ci		 SIR_MAP_DEV_DA(dev->info.dyn_addr) |
144862306a36Sopenharmony_ci		 SIR_MAP_DEV_PL(dev->info.max_ibi_len) |
144962306a36Sopenharmony_ci		 SIR_MAP_DEV_ACK;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	if (dev->info.bcr & I3C_BCR_MAX_DATA_SPEED_LIM)
145262306a36Sopenharmony_ci		sircfg |= SIR_MAP_DEV_SLOW;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	sirmap |= SIR_MAP_DEV_CONF(data->ibi, sircfg);
145562306a36Sopenharmony_ci	writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
145662306a36Sopenharmony_ci	spin_unlock_irqrestore(&master->ibi.lock, flags);
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	ret = i3c_master_enec_locked(m, dev->info.dyn_addr,
145962306a36Sopenharmony_ci				     I3C_CCC_EVENT_SIR);
146062306a36Sopenharmony_ci	if (ret) {
146162306a36Sopenharmony_ci		spin_lock_irqsave(&master->ibi.lock, flags);
146262306a36Sopenharmony_ci		sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi));
146362306a36Sopenharmony_ci		sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi);
146462306a36Sopenharmony_ci		sirmap |= SIR_MAP_DEV_CONF(data->ibi,
146562306a36Sopenharmony_ci					   SIR_MAP_DEV_DA(I3C_BROADCAST_ADDR));
146662306a36Sopenharmony_ci		writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi));
146762306a36Sopenharmony_ci		spin_unlock_irqrestore(&master->ibi.lock, flags);
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	return ret;
147162306a36Sopenharmony_ci}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_cistatic int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev,
147462306a36Sopenharmony_ci				       const struct i3c_ibi_setup *req)
147562306a36Sopenharmony_ci{
147662306a36Sopenharmony_ci	struct i3c_master_controller *m = i3c_dev_get_master(dev);
147762306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
147862306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
147962306a36Sopenharmony_ci	unsigned long flags;
148062306a36Sopenharmony_ci	unsigned int i;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
148362306a36Sopenharmony_ci	if (IS_ERR(data->ibi_pool))
148462306a36Sopenharmony_ci		return PTR_ERR(data->ibi_pool);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	spin_lock_irqsave(&master->ibi.lock, flags);
148762306a36Sopenharmony_ci	for (i = 0; i < master->ibi.num_slots; i++) {
148862306a36Sopenharmony_ci		if (!master->ibi.slots[i]) {
148962306a36Sopenharmony_ci			data->ibi = i;
149062306a36Sopenharmony_ci			master->ibi.slots[i] = dev;
149162306a36Sopenharmony_ci			break;
149262306a36Sopenharmony_ci		}
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci	spin_unlock_irqrestore(&master->ibi.lock, flags);
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	if (i < master->ibi.num_slots)
149762306a36Sopenharmony_ci		return 0;
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	i3c_generic_ibi_free_pool(data->ibi_pool);
150062306a36Sopenharmony_ci	data->ibi_pool = NULL;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	return -ENOSPC;
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_cistatic void cdns_i3c_master_free_ibi(struct i3c_dev_desc *dev)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	struct i3c_master_controller *m = i3c_dev_get_master(dev);
150862306a36Sopenharmony_ci	struct cdns_i3c_master *master = to_cdns_i3c_master(m);
150962306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
151062306a36Sopenharmony_ci	unsigned long flags;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	spin_lock_irqsave(&master->ibi.lock, flags);
151362306a36Sopenharmony_ci	master->ibi.slots[data->ibi] = NULL;
151462306a36Sopenharmony_ci	data->ibi = -1;
151562306a36Sopenharmony_ci	spin_unlock_irqrestore(&master->ibi.lock, flags);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	i3c_generic_ibi_free_pool(data->ibi_pool);
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_cistatic void cdns_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
152162306a36Sopenharmony_ci					     struct i3c_ibi_slot *slot)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	i3c_generic_ibi_recycle_slot(data->ibi_pool, slot);
152662306a36Sopenharmony_ci}
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_cistatic const struct i3c_master_controller_ops cdns_i3c_master_ops = {
152962306a36Sopenharmony_ci	.bus_init = cdns_i3c_master_bus_init,
153062306a36Sopenharmony_ci	.bus_cleanup = cdns_i3c_master_bus_cleanup,
153162306a36Sopenharmony_ci	.do_daa = cdns_i3c_master_do_daa,
153262306a36Sopenharmony_ci	.attach_i3c_dev = cdns_i3c_master_attach_i3c_dev,
153362306a36Sopenharmony_ci	.reattach_i3c_dev = cdns_i3c_master_reattach_i3c_dev,
153462306a36Sopenharmony_ci	.detach_i3c_dev = cdns_i3c_master_detach_i3c_dev,
153562306a36Sopenharmony_ci	.attach_i2c_dev = cdns_i3c_master_attach_i2c_dev,
153662306a36Sopenharmony_ci	.detach_i2c_dev = cdns_i3c_master_detach_i2c_dev,
153762306a36Sopenharmony_ci	.supports_ccc_cmd = cdns_i3c_master_supports_ccc_cmd,
153862306a36Sopenharmony_ci	.send_ccc_cmd = cdns_i3c_master_send_ccc_cmd,
153962306a36Sopenharmony_ci	.priv_xfers = cdns_i3c_master_priv_xfers,
154062306a36Sopenharmony_ci	.i2c_xfers = cdns_i3c_master_i2c_xfers,
154162306a36Sopenharmony_ci	.enable_ibi = cdns_i3c_master_enable_ibi,
154262306a36Sopenharmony_ci	.disable_ibi = cdns_i3c_master_disable_ibi,
154362306a36Sopenharmony_ci	.request_ibi = cdns_i3c_master_request_ibi,
154462306a36Sopenharmony_ci	.free_ibi = cdns_i3c_master_free_ibi,
154562306a36Sopenharmony_ci	.recycle_ibi_slot = cdns_i3c_master_recycle_ibi_slot,
154662306a36Sopenharmony_ci};
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_cistatic void cdns_i3c_master_hj(struct work_struct *work)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	struct cdns_i3c_master *master = container_of(work,
155162306a36Sopenharmony_ci						      struct cdns_i3c_master,
155262306a36Sopenharmony_ci						      hj_work);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	i3c_master_do_daa(&master->base);
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_cistatic struct cdns_i3c_data cdns_i3c_devdata = {
155862306a36Sopenharmony_ci	.thd_delay_ns = 10,
155962306a36Sopenharmony_ci};
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_cistatic const struct of_device_id cdns_i3c_master_of_ids[] = {
156262306a36Sopenharmony_ci	{ .compatible = "cdns,i3c-master", .data = &cdns_i3c_devdata },
156362306a36Sopenharmony_ci	{ /* sentinel */ },
156462306a36Sopenharmony_ci};
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_cistatic int cdns_i3c_master_probe(struct platform_device *pdev)
156762306a36Sopenharmony_ci{
156862306a36Sopenharmony_ci	struct cdns_i3c_master *master;
156962306a36Sopenharmony_ci	int ret, irq;
157062306a36Sopenharmony_ci	u32 val;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
157362306a36Sopenharmony_ci	if (!master)
157462306a36Sopenharmony_ci		return -ENOMEM;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	master->devdata = of_device_get_match_data(&pdev->dev);
157762306a36Sopenharmony_ci	if (!master->devdata)
157862306a36Sopenharmony_ci		return -EINVAL;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	master->regs = devm_platform_ioremap_resource(pdev, 0);
158162306a36Sopenharmony_ci	if (IS_ERR(master->regs))
158262306a36Sopenharmony_ci		return PTR_ERR(master->regs);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	master->pclk = devm_clk_get(&pdev->dev, "pclk");
158562306a36Sopenharmony_ci	if (IS_ERR(master->pclk))
158662306a36Sopenharmony_ci		return PTR_ERR(master->pclk);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	master->sysclk = devm_clk_get(&pdev->dev, "sysclk");
158962306a36Sopenharmony_ci	if (IS_ERR(master->sysclk))
159062306a36Sopenharmony_ci		return PTR_ERR(master->sysclk);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
159362306a36Sopenharmony_ci	if (irq < 0)
159462306a36Sopenharmony_ci		return irq;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	ret = clk_prepare_enable(master->pclk);
159762306a36Sopenharmony_ci	if (ret)
159862306a36Sopenharmony_ci		return ret;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	ret = clk_prepare_enable(master->sysclk);
160162306a36Sopenharmony_ci	if (ret)
160262306a36Sopenharmony_ci		goto err_disable_pclk;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) {
160562306a36Sopenharmony_ci		ret = -EINVAL;
160662306a36Sopenharmony_ci		goto err_disable_sysclk;
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	spin_lock_init(&master->xferqueue.lock);
161062306a36Sopenharmony_ci	INIT_LIST_HEAD(&master->xferqueue.list);
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	INIT_WORK(&master->hj_work, cdns_i3c_master_hj);
161362306a36Sopenharmony_ci	writel(0xffffffff, master->regs + MST_IDR);
161462306a36Sopenharmony_ci	writel(0xffffffff, master->regs + SLV_IDR);
161562306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0,
161662306a36Sopenharmony_ci			       dev_name(&pdev->dev), master);
161762306a36Sopenharmony_ci	if (ret)
161862306a36Sopenharmony_ci		goto err_disable_sysclk;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	platform_set_drvdata(pdev, master);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	val = readl(master->regs + CONF_STATUS0);
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	/* Device ID0 is reserved to describe this master. */
162562306a36Sopenharmony_ci	master->maxdevs = CONF_STATUS0_DEVS_NUM(val);
162662306a36Sopenharmony_ci	master->free_rr_slots = GENMASK(master->maxdevs, 1);
162762306a36Sopenharmony_ci	master->caps.ibirfifodepth = CONF_STATUS0_IBIR_DEPTH(val);
162862306a36Sopenharmony_ci	master->caps.cmdrfifodepth = CONF_STATUS0_CMDR_DEPTH(val);
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	val = readl(master->regs + CONF_STATUS1);
163162306a36Sopenharmony_ci	master->caps.cmdfifodepth = CONF_STATUS1_CMD_DEPTH(val);
163262306a36Sopenharmony_ci	master->caps.rxfifodepth = CONF_STATUS1_RX_DEPTH(val);
163362306a36Sopenharmony_ci	master->caps.txfifodepth = CONF_STATUS1_TX_DEPTH(val);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	spin_lock_init(&master->ibi.lock);
163662306a36Sopenharmony_ci	master->ibi.num_slots = CONF_STATUS1_IBI_HW_RES(val);
163762306a36Sopenharmony_ci	master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
163862306a36Sopenharmony_ci					 sizeof(*master->ibi.slots),
163962306a36Sopenharmony_ci					 GFP_KERNEL);
164062306a36Sopenharmony_ci	if (!master->ibi.slots) {
164162306a36Sopenharmony_ci		ret = -ENOMEM;
164262306a36Sopenharmony_ci		goto err_disable_sysclk;
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
164662306a36Sopenharmony_ci	writel(MST_INT_IBIR_THR, master->regs + MST_IER);
164762306a36Sopenharmony_ci	writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	ret = i3c_master_register(&master->base, &pdev->dev,
165062306a36Sopenharmony_ci				  &cdns_i3c_master_ops, false);
165162306a36Sopenharmony_ci	if (ret)
165262306a36Sopenharmony_ci		goto err_disable_sysclk;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	return 0;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_cierr_disable_sysclk:
165762306a36Sopenharmony_ci	clk_disable_unprepare(master->sysclk);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_cierr_disable_pclk:
166062306a36Sopenharmony_ci	clk_disable_unprepare(master->pclk);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	return ret;
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_cistatic void cdns_i3c_master_remove(struct platform_device *pdev)
166662306a36Sopenharmony_ci{
166762306a36Sopenharmony_ci	struct cdns_i3c_master *master = platform_get_drvdata(pdev);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	i3c_master_unregister(&master->base);
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	clk_disable_unprepare(master->sysclk);
167262306a36Sopenharmony_ci	clk_disable_unprepare(master->pclk);
167362306a36Sopenharmony_ci}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_cistatic struct platform_driver cdns_i3c_master = {
167662306a36Sopenharmony_ci	.probe = cdns_i3c_master_probe,
167762306a36Sopenharmony_ci	.remove_new = cdns_i3c_master_remove,
167862306a36Sopenharmony_ci	.driver = {
167962306a36Sopenharmony_ci		.name = "cdns-i3c-master",
168062306a36Sopenharmony_ci		.of_match_table = cdns_i3c_master_of_ids,
168162306a36Sopenharmony_ci	},
168262306a36Sopenharmony_ci};
168362306a36Sopenharmony_cimodule_platform_driver(cdns_i3c_master);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ciMODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>");
168662306a36Sopenharmony_ciMODULE_DESCRIPTION("Cadence I3C master driver");
168762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
168862306a36Sopenharmony_ciMODULE_ALIAS("platform:cdns-i3c-master");
1689