1629a6dddSManikanta Guntupalli // SPDX-License-Identifier: GPL-2.0
2629a6dddSManikanta Guntupalli /*
3629a6dddSManikanta Guntupalli * I3C master driver for the AMD I3C controller.
4629a6dddSManikanta Guntupalli *
5629a6dddSManikanta Guntupalli * Copyright (C) 2026, Advanced Micro Devices, Inc.
6629a6dddSManikanta Guntupalli */
7629a6dddSManikanta Guntupalli
8629a6dddSManikanta Guntupalli #include <linux/bitfield.h>
9629a6dddSManikanta Guntupalli #include <linux/bitops.h>
10629a6dddSManikanta Guntupalli #include <linux/cleanup.h>
11629a6dddSManikanta Guntupalli #include <linux/clk.h>
12629a6dddSManikanta Guntupalli #include <linux/delay.h>
13629a6dddSManikanta Guntupalli #include <linux/err.h>
14629a6dddSManikanta Guntupalli #include <linux/i3c/master.h>
15629a6dddSManikanta Guntupalli #include <linux/io.h>
16629a6dddSManikanta Guntupalli #include <linux/iopoll.h>
17629a6dddSManikanta Guntupalli #include <linux/kernel.h>
18629a6dddSManikanta Guntupalli #include <linux/module.h>
19629a6dddSManikanta Guntupalli #include <linux/mutex.h>
20629a6dddSManikanta Guntupalli #include <linux/of.h>
21629a6dddSManikanta Guntupalli #include <linux/platform_device.h>
22629a6dddSManikanta Guntupalli #include <linux/slab.h>
23629a6dddSManikanta Guntupalli #include <linux/time.h>
24629a6dddSManikanta Guntupalli #include <linux/unaligned.h>
25629a6dddSManikanta Guntupalli
26629a6dddSManikanta Guntupalli #define XI3C_VERSION_OFFSET 0x00 /* Version Register */
27629a6dddSManikanta Guntupalli #define XI3C_RESET_OFFSET 0x04 /* Soft Reset Register */
28629a6dddSManikanta Guntupalli #define XI3C_CR_OFFSET 0x08 /* Control Register */
29629a6dddSManikanta Guntupalli #define XI3C_ADDRESS_OFFSET 0x0C /* Target Address Register */
30629a6dddSManikanta Guntupalli #define XI3C_SR_OFFSET 0x10 /* Status Register */
31629a6dddSManikanta Guntupalli #define XI3C_CMD_FIFO_OFFSET 0x20 /* I3C Command FIFO Register */
32629a6dddSManikanta Guntupalli #define XI3C_WR_FIFO_OFFSET 0x24 /* I3C Write Data FIFO Register */
33629a6dddSManikanta Guntupalli #define XI3C_RD_FIFO_OFFSET 0x28 /* I3C Read Data FIFO Register */
34629a6dddSManikanta Guntupalli #define XI3C_RESP_STATUS_FIFO_OFFSET 0x2C /* I3C Response status FIFO Register */
35629a6dddSManikanta Guntupalli #define XI3C_FIFO_LVL_STATUS_OFFSET 0x30 /* CMD slots free | WR-FIFO free (words) */
36629a6dddSManikanta Guntupalli #define XI3C_FIFO_LVL_STATUS_1_OFFSET 0x34 /* RESP fill | RD-FIFO fill level (words) */
37629a6dddSManikanta Guntupalli #define XI3C_SCL_HIGH_TIME_OFFSET 0x38 /* I3C SCL HIGH Register */
38629a6dddSManikanta Guntupalli #define XI3C_SCL_LOW_TIME_OFFSET 0x3C /* I3C SCL LOW Register */
39629a6dddSManikanta Guntupalli #define XI3C_SDA_HOLD_TIME_OFFSET 0x40 /* I3C SDA HOLD Register */
40629a6dddSManikanta Guntupalli #define XI3C_TSU_START_OFFSET 0x48 /* I3C START SETUP Register */
41629a6dddSManikanta Guntupalli #define XI3C_THD_START_OFFSET 0x4C /* I3C START HOLD Register */
42629a6dddSManikanta Guntupalli #define XI3C_TSU_STOP_OFFSET 0x50 /* I3C STOP Setup Register */
43629a6dddSManikanta Guntupalli #define XI3C_OD_SCL_HIGH_TIME_OFFSET 0x54 /* I3C OD SCL HIGH Register */
44629a6dddSManikanta Guntupalli #define XI3C_OD_SCL_LOW_TIME_OFFSET 0x58 /* I3C OD SCL LOW Register */
45629a6dddSManikanta Guntupalli #define XI3C_PID0_OFFSET 0x6C /* LSB 4 bytes of the PID */
46629a6dddSManikanta Guntupalli #define XI3C_PID1_BCR_DCR 0x70 /* MSB 2 bytes of the PID, BCR and DCR */
47629a6dddSManikanta Guntupalli
48629a6dddSManikanta Guntupalli #define XI3C_CR_EN_MASK BIT(0) /* Core Enable */
49629a6dddSManikanta Guntupalli #define XI3C_CR_RESUME_MASK BIT(2) /* Core Resume */
50629a6dddSManikanta Guntupalli #define XI3C_SR_RESP_NOT_EMPTY_MASK BIT(4) /* Resp Fifo not empty status mask */
51629a6dddSManikanta Guntupalli #define XI3C_RD_FIFO_NOT_EMPTY_MASK BIT(15) /* Read Fifo not empty status mask */
52629a6dddSManikanta Guntupalli
53629a6dddSManikanta Guntupalli #define XI3C_BCR_MASK GENMASK(23, 16)
54629a6dddSManikanta Guntupalli #define XI3C_DCR_MASK GENMASK(31, 24)
55629a6dddSManikanta Guntupalli #define XI3C_PID_MASK GENMASK_ULL(63, 16)
56629a6dddSManikanta Guntupalli #define XI3C_TIMING_MASK GENMASK(17, 0)
57629a6dddSManikanta Guntupalli #define XI3C_REV_NUM_MASK GENMASK(15, 8)
58629a6dddSManikanta Guntupalli #define XI3C_PID1_MASK GENMASK(15, 0)
59629a6dddSManikanta Guntupalli #define XI3C_FIFO_LEVEL_MASK GENMASK(15, 0)
60629a6dddSManikanta Guntupalli #define XI3C_RESP_CODE_MASK GENMASK(8, 5)
61629a6dddSManikanta Guntupalli
62629a6dddSManikanta Guntupalli /* Controller response codes; PG439 page 34, Table 46 */
63629a6dddSManikanta Guntupalli #define XI3C_RESP_CODE_SUCCESS 0 /* Transfer completed OK */
64629a6dddSManikanta Guntupalli #define XI3C_RESP_CODE_NO_TARGET 2 /* 7E NACK: no target on bus */
65629a6dddSManikanta Guntupalli #define XI3C_RESP_CODE_NACK 3 /* Target NACK / DAA end */
66629a6dddSManikanta Guntupalli #define XI3C_RESP_CODE_READ_EARLY_TERM 5 /* Target ended read early (T-bit), short read */
67629a6dddSManikanta Guntupalli
68629a6dddSManikanta Guntupalli /* xi3c_get_response() private return: read ended early with valid data; resume needed */
69629a6dddSManikanta Guntupalli #define XI3C_XFER_SHORT_READ 1
70629a6dddSManikanta Guntupalli
71629a6dddSManikanta Guntupalli #define XI3C_RESP_BYTES_MASK GENMASK(20, 9) /* NUM_BYTES processed */
72629a6dddSManikanta Guntupalli #define XI3C_ADDR_MASK GENMASK(6, 0)
73629a6dddSManikanta Guntupalli #define XI3C_FIFOS_RST_MASK GENMASK(4, 1)
74629a6dddSManikanta Guntupalli
75629a6dddSManikanta Guntupalli /* Command FIFO word layout (bit ranges encoded in the GENMASK/BIT args) */
76629a6dddSManikanta Guntupalli #define XI3C_CMD_TYPE GENMASK(3, 0) /* command type */
77629a6dddSManikanta Guntupalli #define XI3C_CMD_TERMINATE BIT(4) /* terminate (last cmd of xfer) */
78629a6dddSManikanta Guntupalli #define XI3C_CMD_ADDR GENMASK(15, 8) /* target address << 1 | RnW */
79629a6dddSManikanta Guntupalli #define XI3C_CMD_LEN GENMASK(27, 16) /* payload length in bytes */
80629a6dddSManikanta Guntupalli #define XI3C_CMD_TID GENMASK(31, 28) /* transfer ID */
81629a6dddSManikanta Guntupalli
82629a6dddSManikanta Guntupalli /* tLOW_OD open-drain SCL low; MIPI I3C v1.1.1 Table 74 min 200 ns, 500 ns chosen conservatively */
83629a6dddSManikanta Guntupalli #define XI3C_OD_TLOW_NS 500
84629a6dddSManikanta Guntupalli /* Open-drain SCL high (tHIGH) max; MIPI I3C v1.1.1 Table 74 (41 ns) */
85629a6dddSManikanta Guntupalli #define XI3C_OD_THIGH_NS 41
86629a6dddSManikanta Guntupalli /*
87629a6dddSManikanta Guntupalli * tSU_STA/tHD_STA/tSU_STO min, 400 kHz/Fm; MIPI I3C v1.1.1 Table 73
88629a6dddSManikanta Guntupalli * (mixed bus with legacy I2C device)
89629a6dddSManikanta Guntupalli */
90629a6dddSManikanta Guntupalli #define XI3C_I2C_TCASMIN_NS 600
91629a6dddSManikanta Guntupalli /* tSU_STA/tHD_STA/tSU_STO min, 1 MHz/Fm+; MIPI I3C v1.1.1 Table 73 (pure I3C bus) */
92629a6dddSManikanta Guntupalli #define XI3C_TCASMIN_NS 260
93629a6dddSManikanta Guntupalli /* Max payload per transfer: 12-bit CMD length field (XI3C_CMD_LEN); PG439 page 32, Table 42 */
94629a6dddSManikanta Guntupalli #define XI3C_MAXDATA_LENGTH 4095
95629a6dddSManikanta Guntupalli /* Max enumerated devices; PG439 page 27, AXI_I3C_IBI_TARGET_ADDR register detail */
96629a6dddSManikanta Guntupalli #define XI3C_MAX_DEVS 128
97629a6dddSManikanta Guntupalli /* DAA target response = 48-bit PID + BCR + DCR = 8 bytes; PG439 page 28 */
98629a6dddSManikanta Guntupalli #define XI3C_DAA_SLAVEINFO_READ_BYTECOUNT 8
99629a6dddSManikanta Guntupalli
100629a6dddSManikanta Guntupalli /*
101629a6dddSManikanta Guntupalli * Min SDA hold cycles, rev 0 IP. Revision-specific value, PG439 page 24,
102629a6dddSManikanta Guntupalli * AXI_I3C_SDA_HOLD_TIME register detail
103629a6dddSManikanta Guntupalli */
104629a6dddSManikanta Guntupalli #define XI3C_THOLD_MIN_REV0 5
105629a6dddSManikanta Guntupalli /*
106629a6dddSManikanta Guntupalli * Min SDA hold cycles, rev >= 1 IP. Revision-specific value, PG439 page 24,
107629a6dddSManikanta Guntupalli * AXI_I3C_SDA_HOLD_TIME register detail
108629a6dddSManikanta Guntupalli */
109629a6dddSManikanta Guntupalli #define XI3C_THOLD_MIN_REV1 6
110629a6dddSManikanta Guntupalli /*
111629a6dddSManikanta Guntupalli * SCL/SDA pre-bias to account for the HW pipeline. PG439 page 24,
112629a6dddSManikanta Guntupalli * AXI_I3C_SDA_HOLD_TIME register detail
113629a6dddSManikanta Guntupalli */
114629a6dddSManikanta Guntupalli #define XI3C_CYCLE_ADJUST 2
115629a6dddSManikanta Guntupalli /* Short settling delay so the FIFO reset assert/de-assert takes effect before the FIFOs are used */
116629a6dddSManikanta Guntupalli #define XI3C_FIFO_RESET_DELAY_US 10
117629a6dddSManikanta Guntupalli /*
118629a6dddSManikanta Guntupalli * Poll/sleep slice for FIFO and response waits: small enough to stay
119629a6dddSManikanta Guntupalli * responsive, avoids busy-waiting
120629a6dddSManikanta Guntupalli */
121629a6dddSManikanta Guntupalli #define XI3C_POLL_INTERVAL_US 10
122629a6dddSManikanta Guntupalli
123629a6dddSManikanta Guntupalli #define XI3C_I2C_MODE 0
124629a6dddSManikanta Guntupalli #define XI3C_I2C_TID 0
125629a6dddSManikanta Guntupalli #define XI3C_SDR_MODE 1
126629a6dddSManikanta Guntupalli #define XI3C_SDR_TID 1
127629a6dddSManikanta Guntupalli
128629a6dddSManikanta Guntupalli #define XI3C_WORD_LEN 4
129629a6dddSManikanta Guntupalli
130629a6dddSManikanta Guntupalli /* Software guard: 500 ms (us, for readl_poll_timeout) to bail out if no response word arrives */
131629a6dddSManikanta Guntupalli #define XI3C_RESP_TIMEOUT_US 500000
132629a6dddSManikanta Guntupalli /* Software guard: 1 s (ms, for msecs_to_jiffies) to bail out if a transfer never completes */
133629a6dddSManikanta Guntupalli #define XI3C_XFER_TIMEOUT_MS 1000
134629a6dddSManikanta Guntupalli
135629a6dddSManikanta Guntupalli struct xi3c_cmd {
136629a6dddSManikanta Guntupalli const void *tx_buf;
137629a6dddSManikanta Guntupalli void *rx_buf;
138629a6dddSManikanta Guntupalli u16 tx_len;
139629a6dddSManikanta Guntupalli u16 rx_len;
140629a6dddSManikanta Guntupalli u16 rx_actual;
141629a6dddSManikanta Guntupalli u8 addr;
142629a6dddSManikanta Guntupalli u8 type;
143629a6dddSManikanta Guntupalli u8 tid;
144629a6dddSManikanta Guntupalli bool rnw;
145629a6dddSManikanta Guntupalli bool is_daa;
146629a6dddSManikanta Guntupalli bool continued;
147629a6dddSManikanta Guntupalli enum i3c_error_code err;
148629a6dddSManikanta Guntupalli };
149629a6dddSManikanta Guntupalli
150629a6dddSManikanta Guntupalli struct xi3c_xfer {
151629a6dddSManikanta Guntupalli unsigned int ncmds;
152629a6dddSManikanta Guntupalli unsigned int nissued;
153629a6dddSManikanta Guntupalli struct xi3c_cmd cmds[] __counted_by(ncmds);
154629a6dddSManikanta Guntupalli };
155629a6dddSManikanta Guntupalli
156629a6dddSManikanta Guntupalli /**
157629a6dddSManikanta Guntupalli * struct xi3c_master - I3C master controller state.
158629a6dddSManikanta Guntupalli * @base: I3C master controller embedded by the framework.
159629a6dddSManikanta Guntupalli * @dev: Pointer to the backing device structure.
160629a6dddSManikanta Guntupalli * @membase: Memory base of the HW registers.
161629a6dddSManikanta Guntupalli * @pclk: Input clock driving the controller.
162629a6dddSManikanta Guntupalli * @lock: Serializes transfers and CCC submission.
163629a6dddSManikanta Guntupalli * @daa: ENTDAA enumeration state.
164629a6dddSManikanta Guntupalli * @daa.addrs: Dynamic addresses assigned in enumeration order.
165629a6dddSManikanta Guntupalli * @daa.index: Number of responders enumerated so far.
166629a6dddSManikanta Guntupalli */
167629a6dddSManikanta Guntupalli struct xi3c_master {
168629a6dddSManikanta Guntupalli struct i3c_master_controller base;
169629a6dddSManikanta Guntupalli struct device *dev;
170629a6dddSManikanta Guntupalli void __iomem *membase;
171629a6dddSManikanta Guntupalli struct clk *pclk;
172629a6dddSManikanta Guntupalli struct mutex lock; /* serializes transfers and CCC submission */
173629a6dddSManikanta Guntupalli struct {
174629a6dddSManikanta Guntupalli u8 addrs[XI3C_MAX_DEVS];
175629a6dddSManikanta Guntupalli u8 index;
176629a6dddSManikanta Guntupalli } daa;
177629a6dddSManikanta Guntupalli };
178629a6dddSManikanta Guntupalli
179629a6dddSManikanta Guntupalli static inline struct xi3c_master *
to_xi3c_master(struct i3c_master_controller * master)180629a6dddSManikanta Guntupalli to_xi3c_master(struct i3c_master_controller *master)
181629a6dddSManikanta Guntupalli {
182629a6dddSManikanta Guntupalli return container_of(master, struct xi3c_master, base);
183629a6dddSManikanta Guntupalli }
184629a6dddSManikanta Guntupalli
xi3c_get_revision_number(struct xi3c_master * master)185629a6dddSManikanta Guntupalli static inline u8 xi3c_get_revision_number(struct xi3c_master *master)
186629a6dddSManikanta Guntupalli {
187629a6dddSManikanta Guntupalli return FIELD_GET(XI3C_REV_NUM_MASK,
188629a6dddSManikanta Guntupalli ioread32(master->membase + XI3C_VERSION_OFFSET));
189629a6dddSManikanta Guntupalli }
190629a6dddSManikanta Guntupalli
xi3c_wr_fifo_level(struct xi3c_master * master)191629a6dddSManikanta Guntupalli static inline u16 xi3c_wr_fifo_level(struct xi3c_master *master)
192629a6dddSManikanta Guntupalli {
193629a6dddSManikanta Guntupalli return ioread32(master->membase + XI3C_FIFO_LVL_STATUS_OFFSET) &
194629a6dddSManikanta Guntupalli XI3C_FIFO_LEVEL_MASK;
195629a6dddSManikanta Guntupalli }
196629a6dddSManikanta Guntupalli
xi3c_rd_fifo_level(struct xi3c_master * master)197629a6dddSManikanta Guntupalli static inline u16 xi3c_rd_fifo_level(struct xi3c_master *master)
198629a6dddSManikanta Guntupalli {
199629a6dddSManikanta Guntupalli return ioread32(master->membase + XI3C_FIFO_LVL_STATUS_1_OFFSET) &
200629a6dddSManikanta Guntupalli XI3C_FIFO_LEVEL_MASK;
201629a6dddSManikanta Guntupalli }
202629a6dddSManikanta Guntupalli
xi3c_is_resp_available(struct xi3c_master * master)203629a6dddSManikanta Guntupalli static inline bool xi3c_is_resp_available(struct xi3c_master *master)
204629a6dddSManikanta Guntupalli {
205629a6dddSManikanta Guntupalli return FIELD_GET(XI3C_SR_RESP_NOT_EMPTY_MASK,
206629a6dddSManikanta Guntupalli ioread32(master->membase + XI3C_SR_OFFSET));
207629a6dddSManikanta Guntupalli }
208629a6dddSManikanta Guntupalli
xi3c_get_response(struct xi3c_master * master,struct xi3c_cmd * cmd)209629a6dddSManikanta Guntupalli static int xi3c_get_response(struct xi3c_master *master, struct xi3c_cmd *cmd)
210629a6dddSManikanta Guntupalli {
211629a6dddSManikanta Guntupalli u32 response_data;
212629a6dddSManikanta Guntupalli u32 resp_reg;
213629a6dddSManikanta Guntupalli u8 code;
214629a6dddSManikanta Guntupalli int ret;
215629a6dddSManikanta Guntupalli
216629a6dddSManikanta Guntupalli ret = readl_poll_timeout(master->membase + XI3C_SR_OFFSET,
217629a6dddSManikanta Guntupalli resp_reg,
218629a6dddSManikanta Guntupalli resp_reg & XI3C_SR_RESP_NOT_EMPTY_MASK,
219629a6dddSManikanta Guntupalli XI3C_POLL_INTERVAL_US, XI3C_RESP_TIMEOUT_US);
220629a6dddSManikanta Guntupalli if (ret) {
221629a6dddSManikanta Guntupalli dev_err(master->dev, "XI3C response timeout\n");
222629a6dddSManikanta Guntupalli return ret;
223629a6dddSManikanta Guntupalli }
224629a6dddSManikanta Guntupalli
225629a6dddSManikanta Guntupalli response_data = ioread32(master->membase + XI3C_RESP_STATUS_FIFO_OFFSET);
226629a6dddSManikanta Guntupalli code = FIELD_GET(XI3C_RESP_CODE_MASK, response_data);
227629a6dddSManikanta Guntupalli
228629a6dddSManikanta Guntupalli switch (code) {
229629a6dddSManikanta Guntupalli case XI3C_RESP_CODE_SUCCESS:
230629a6dddSManikanta Guntupalli cmd->err = I3C_ERROR_UNKNOWN;
231629a6dddSManikanta Guntupalli cmd->rx_actual = FIELD_GET(XI3C_RESP_BYTES_MASK, response_data);
232629a6dddSManikanta Guntupalli return 0;
233629a6dddSManikanta Guntupalli case XI3C_RESP_CODE_READ_EARLY_TERM:
234629a6dddSManikanta Guntupalli /* Short read: valid data, but controller parked in STOP and must be resumed */
235629a6dddSManikanta Guntupalli cmd->err = I3C_ERROR_UNKNOWN;
236629a6dddSManikanta Guntupalli cmd->rx_actual = FIELD_GET(XI3C_RESP_BYTES_MASK, response_data);
237629a6dddSManikanta Guntupalli return XI3C_XFER_SHORT_READ;
238629a6dddSManikanta Guntupalli case XI3C_RESP_CODE_NO_TARGET:
239629a6dddSManikanta Guntupalli case XI3C_RESP_CODE_NACK:
240629a6dddSManikanta Guntupalli cmd->err = I3C_ERROR_M2;
241629a6dddSManikanta Guntupalli return cmd->is_daa ? -ENODEV : -EIO;
242629a6dddSManikanta Guntupalli default:
243629a6dddSManikanta Guntupalli cmd->err = I3C_ERROR_M0;
244629a6dddSManikanta Guntupalli dev_err(master->dev, "XI3C transfer error, response code %u\n",
245629a6dddSManikanta Guntupalli code);
246629a6dddSManikanta Guntupalli return -EIO;
247629a6dddSManikanta Guntupalli }
248629a6dddSManikanta Guntupalli }
249629a6dddSManikanta Guntupalli
xi3c_writesl_be(void __iomem * addr,const void * buffer,unsigned int count)250629a6dddSManikanta Guntupalli static inline void xi3c_writesl_be(void __iomem *addr, const void *buffer,
251629a6dddSManikanta Guntupalli unsigned int count)
252629a6dddSManikanta Guntupalli {
253629a6dddSManikanta Guntupalli const u32 *buf = buffer;
254629a6dddSManikanta Guntupalli
255629a6dddSManikanta Guntupalli while (count--)
256629a6dddSManikanta Guntupalli iowrite32be(get_unaligned(buf++), addr);
257629a6dddSManikanta Guntupalli }
258629a6dddSManikanta Guntupalli
xi3c_readsl_be(const void __iomem * addr,void * buffer,unsigned int count)259629a6dddSManikanta Guntupalli static inline void xi3c_readsl_be(const void __iomem *addr, void *buffer,
260629a6dddSManikanta Guntupalli unsigned int count)
261629a6dddSManikanta Guntupalli {
262629a6dddSManikanta Guntupalli u32 *buf = buffer;
263629a6dddSManikanta Guntupalli
264629a6dddSManikanta Guntupalli while (count--)
265629a6dddSManikanta Guntupalli put_unaligned(ioread32be(addr), buf++);
266629a6dddSManikanta Guntupalli }
267629a6dddSManikanta Guntupalli
xi3c_writel_fifo(void __iomem * addr,const void * buf,int nbytes)268629a6dddSManikanta Guntupalli static inline void xi3c_writel_fifo(void __iomem *addr, const void *buf,
269629a6dddSManikanta Guntupalli int nbytes)
270629a6dddSManikanta Guntupalli {
271629a6dddSManikanta Guntupalli xi3c_writesl_be(addr, buf, nbytes / 4);
272629a6dddSManikanta Guntupalli if (nbytes & 3) {
273629a6dddSManikanta Guntupalli u32 tmp = 0;
274629a6dddSManikanta Guntupalli
275629a6dddSManikanta Guntupalli memcpy(&tmp, (const u8 *)buf + (nbytes & ~3), nbytes & 3);
276629a6dddSManikanta Guntupalli xi3c_writesl_be(addr, &tmp, 1);
277629a6dddSManikanta Guntupalli }
278629a6dddSManikanta Guntupalli }
279629a6dddSManikanta Guntupalli
xi3c_readl_fifo(const void __iomem * addr,void * buf,int nbytes)280629a6dddSManikanta Guntupalli static inline void xi3c_readl_fifo(const void __iomem *addr, void *buf,
281629a6dddSManikanta Guntupalli int nbytes)
282629a6dddSManikanta Guntupalli {
283629a6dddSManikanta Guntupalli xi3c_readsl_be(addr, buf, nbytes / 4);
284629a6dddSManikanta Guntupalli if (nbytes & 3) {
285629a6dddSManikanta Guntupalli u32 tmp;
286629a6dddSManikanta Guntupalli
287629a6dddSManikanta Guntupalli xi3c_readsl_be(addr, &tmp, 1);
288629a6dddSManikanta Guntupalli memcpy((u8 *)buf + (nbytes & ~3), &tmp, nbytes & 3);
289629a6dddSManikanta Guntupalli }
290629a6dddSManikanta Guntupalli }
291629a6dddSManikanta Guntupalli
xi3c_master_write_to_cmdfifo(struct xi3c_master * master,struct xi3c_cmd * cmd,u16 len)292629a6dddSManikanta Guntupalli static void xi3c_master_write_to_cmdfifo(struct xi3c_master *master,
293629a6dddSManikanta Guntupalli struct xi3c_cmd *cmd, u16 len)
294629a6dddSManikanta Guntupalli {
295629a6dddSManikanta Guntupalli u32 transfer_cmd;
296629a6dddSManikanta Guntupalli u8 addr;
297629a6dddSManikanta Guntupalli
298629a6dddSManikanta Guntupalli addr = ((cmd->addr & XI3C_ADDR_MASK) << 1) | (u8)cmd->rnw;
299629a6dddSManikanta Guntupalli
300629a6dddSManikanta Guntupalli transfer_cmd = FIELD_PREP(XI3C_CMD_TYPE, cmd->type);
301629a6dddSManikanta Guntupalli transfer_cmd |= FIELD_PREP(XI3C_CMD_TERMINATE, !cmd->continued);
302629a6dddSManikanta Guntupalli transfer_cmd |= FIELD_PREP(XI3C_CMD_ADDR, addr);
303629a6dddSManikanta Guntupalli transfer_cmd |= FIELD_PREP(XI3C_CMD_TID, cmd->tid);
304629a6dddSManikanta Guntupalli
305629a6dddSManikanta Guntupalli /*
306629a6dddSManikanta Guntupalli * For dynamic addressing, an additional 1-byte length must be added
307629a6dddSManikanta Guntupalli * to the command FIFO to account for the address present in the TX FIFO
308629a6dddSManikanta Guntupalli */
309629a6dddSManikanta Guntupalli if (cmd->is_daa) {
310629a6dddSManikanta Guntupalli xi3c_writel_fifo(master->membase + XI3C_WR_FIFO_OFFSET,
311629a6dddSManikanta Guntupalli cmd->tx_buf, cmd->tx_len);
312629a6dddSManikanta Guntupalli
313629a6dddSManikanta Guntupalli len++;
314629a6dddSManikanta Guntupalli }
315629a6dddSManikanta Guntupalli
316629a6dddSManikanta Guntupalli transfer_cmd |= FIELD_PREP(XI3C_CMD_LEN, len);
317629a6dddSManikanta Guntupalli iowrite32(transfer_cmd, master->membase + XI3C_CMD_FIFO_OFFSET);
318629a6dddSManikanta Guntupalli }
319629a6dddSManikanta Guntupalli
xi3c_master_enable(struct xi3c_master * master)320629a6dddSManikanta Guntupalli static inline void xi3c_master_enable(struct xi3c_master *master)
321629a6dddSManikanta Guntupalli {
322629a6dddSManikanta Guntupalli iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) | XI3C_CR_EN_MASK,
323629a6dddSManikanta Guntupalli master->membase + XI3C_CR_OFFSET);
324629a6dddSManikanta Guntupalli }
325629a6dddSManikanta Guntupalli
xi3c_master_disable(struct xi3c_master * master)326629a6dddSManikanta Guntupalli static inline void xi3c_master_disable(struct xi3c_master *master)
327629a6dddSManikanta Guntupalli {
328629a6dddSManikanta Guntupalli iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) & ~XI3C_CR_EN_MASK,
329629a6dddSManikanta Guntupalli master->membase + XI3C_CR_OFFSET);
330629a6dddSManikanta Guntupalli }
331629a6dddSManikanta Guntupalli
xi3c_master_resume(struct xi3c_master * master)332629a6dddSManikanta Guntupalli static inline void xi3c_master_resume(struct xi3c_master *master)
333629a6dddSManikanta Guntupalli {
334629a6dddSManikanta Guntupalli iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) |
335629a6dddSManikanta Guntupalli XI3C_CR_RESUME_MASK, master->membase + XI3C_CR_OFFSET);
336629a6dddSManikanta Guntupalli }
337629a6dddSManikanta Guntupalli
xi3c_master_reset_fifos(struct xi3c_master * master)338629a6dddSManikanta Guntupalli static void xi3c_master_reset_fifos(struct xi3c_master *master)
339629a6dddSManikanta Guntupalli {
340629a6dddSManikanta Guntupalli u32 data;
341629a6dddSManikanta Guntupalli
342629a6dddSManikanta Guntupalli /* Assert FIFO reset. */
343629a6dddSManikanta Guntupalli data = ioread32(master->membase + XI3C_RESET_OFFSET);
344629a6dddSManikanta Guntupalli data |= XI3C_FIFOS_RST_MASK;
345629a6dddSManikanta Guntupalli iowrite32(data, master->membase + XI3C_RESET_OFFSET);
346629a6dddSManikanta Guntupalli /* Read-back flushes the posted write before the settling delay below. */
347629a6dddSManikanta Guntupalli ioread32(master->membase + XI3C_RESET_OFFSET);
348629a6dddSManikanta Guntupalli fsleep(XI3C_FIFO_RESET_DELAY_US);
349629a6dddSManikanta Guntupalli
350629a6dddSManikanta Guntupalli /* De-assert FIFO reset, then wait for the FIFOs to come back up. */
351629a6dddSManikanta Guntupalli data &= ~XI3C_FIFOS_RST_MASK;
352629a6dddSManikanta Guntupalli iowrite32(data, master->membase + XI3C_RESET_OFFSET);
353629a6dddSManikanta Guntupalli ioread32(master->membase + XI3C_RESET_OFFSET);
354629a6dddSManikanta Guntupalli fsleep(XI3C_FIFO_RESET_DELAY_US);
355629a6dddSManikanta Guntupalli }
356629a6dddSManikanta Guntupalli
xi3c_master_init(struct xi3c_master * master)357629a6dddSManikanta Guntupalli static inline void xi3c_master_init(struct xi3c_master *master)
358629a6dddSManikanta Guntupalli {
359629a6dddSManikanta Guntupalli /* Reset fifos */
360629a6dddSManikanta Guntupalli xi3c_master_reset_fifos(master);
361629a6dddSManikanta Guntupalli
362629a6dddSManikanta Guntupalli /* Enable controller */
363629a6dddSManikanta Guntupalli xi3c_master_enable(master);
364629a6dddSManikanta Guntupalli }
365629a6dddSManikanta Guntupalli
xi3c_master_reinit(struct xi3c_master * master)366629a6dddSManikanta Guntupalli static inline void xi3c_master_reinit(struct xi3c_master *master)
367629a6dddSManikanta Guntupalli {
368629a6dddSManikanta Guntupalli /* Reset fifos */
369629a6dddSManikanta Guntupalli xi3c_master_reset_fifos(master);
370629a6dddSManikanta Guntupalli
371629a6dddSManikanta Guntupalli /* Resume controller */
372629a6dddSManikanta Guntupalli xi3c_master_resume(master);
373629a6dddSManikanta Guntupalli }
374629a6dddSManikanta Guntupalli
xi3c_master_alloc_xfer(unsigned int ncmds)375629a6dddSManikanta Guntupalli static struct xi3c_xfer *xi3c_master_alloc_xfer(unsigned int ncmds)
376629a6dddSManikanta Guntupalli {
377629a6dddSManikanta Guntupalli struct xi3c_xfer *xfer;
378629a6dddSManikanta Guntupalli
379*3a2c4d55SKees Cook xfer = kzalloc_flex(*xfer, cmds, ncmds);
380629a6dddSManikanta Guntupalli if (!xfer)
381629a6dddSManikanta Guntupalli return NULL;
382629a6dddSManikanta Guntupalli
383629a6dddSManikanta Guntupalli xfer->ncmds = ncmds;
384629a6dddSManikanta Guntupalli
385629a6dddSManikanta Guntupalli return xfer;
386629a6dddSManikanta Guntupalli }
387629a6dddSManikanta Guntupalli
xi3c_master_rd_from_rx_fifo(struct xi3c_master * master,struct xi3c_cmd * cmd)388629a6dddSManikanta Guntupalli static void xi3c_master_rd_from_rx_fifo(struct xi3c_master *master,
389629a6dddSManikanta Guntupalli struct xi3c_cmd *cmd)
390629a6dddSManikanta Guntupalli {
391629a6dddSManikanta Guntupalli u16 rx_data_available;
392629a6dddSManikanta Guntupalli u16 copy_len;
393629a6dddSManikanta Guntupalli u16 len;
394629a6dddSManikanta Guntupalli
395629a6dddSManikanta Guntupalli rx_data_available = xi3c_rd_fifo_level(master);
396629a6dddSManikanta Guntupalli len = rx_data_available * XI3C_WORD_LEN;
397629a6dddSManikanta Guntupalli
398629a6dddSManikanta Guntupalli if (!len)
399629a6dddSManikanta Guntupalli return;
400629a6dddSManikanta Guntupalli
401629a6dddSManikanta Guntupalli copy_len = min(len, cmd->rx_len);
402629a6dddSManikanta Guntupalli xi3c_readl_fifo(master->membase + XI3C_RD_FIFO_OFFSET,
403629a6dddSManikanta Guntupalli (u8 *)cmd->rx_buf, copy_len);
404629a6dddSManikanta Guntupalli
405629a6dddSManikanta Guntupalli cmd->rx_buf = (u8 *)cmd->rx_buf + copy_len;
406629a6dddSManikanta Guntupalli cmd->rx_len -= copy_len;
407629a6dddSManikanta Guntupalli }
408629a6dddSManikanta Guntupalli
xi3c_master_read(struct xi3c_master * master,struct xi3c_cmd * cmd)409629a6dddSManikanta Guntupalli static int xi3c_master_read(struct xi3c_master *master, struct xi3c_cmd *cmd)
410629a6dddSManikanta Guntupalli {
411629a6dddSManikanta Guntupalli unsigned long timeout;
412629a6dddSManikanta Guntupalli u32 status_reg;
413629a6dddSManikanta Guntupalli int ret;
414629a6dddSManikanta Guntupalli
415629a6dddSManikanta Guntupalli if (cmd->rx_len > XI3C_MAXDATA_LENGTH)
416629a6dddSManikanta Guntupalli return -EINVAL;
417629a6dddSManikanta Guntupalli /*
418629a6dddSManikanta Guntupalli * Zero-length probes (e.g. i2cdetect) legitimately pass a NULL
419629a6dddSManikanta Guntupalli * buffer; only a non-zero length requires one.
420629a6dddSManikanta Guntupalli */
421629a6dddSManikanta Guntupalli if (cmd->rx_len && !cmd->rx_buf)
422629a6dddSManikanta Guntupalli return -EINVAL;
423629a6dddSManikanta Guntupalli
424629a6dddSManikanta Guntupalli /* Fill command fifo */
425629a6dddSManikanta Guntupalli xi3c_master_write_to_cmdfifo(master, cmd, cmd->rx_len);
426629a6dddSManikanta Guntupalli
427629a6dddSManikanta Guntupalli if (!cmd->rx_len)
428629a6dddSManikanta Guntupalli return 0;
429629a6dddSManikanta Guntupalli
430629a6dddSManikanta Guntupalli ret = readl_poll_timeout(master->membase + XI3C_SR_OFFSET,
431629a6dddSManikanta Guntupalli status_reg,
432629a6dddSManikanta Guntupalli status_reg & (XI3C_RD_FIFO_NOT_EMPTY_MASK |
433629a6dddSManikanta Guntupalli XI3C_SR_RESP_NOT_EMPTY_MASK),
434629a6dddSManikanta Guntupalli XI3C_POLL_INTERVAL_US, XI3C_RESP_TIMEOUT_US);
435629a6dddSManikanta Guntupalli if (ret) {
436629a6dddSManikanta Guntupalli dev_err(master->dev, "XI3C read timeout\n");
437629a6dddSManikanta Guntupalli return ret;
438629a6dddSManikanta Guntupalli }
439629a6dddSManikanta Guntupalli
440629a6dddSManikanta Guntupalli if (!(status_reg & XI3C_RD_FIFO_NOT_EMPTY_MASK))
441629a6dddSManikanta Guntupalli return 0;
442629a6dddSManikanta Guntupalli
443629a6dddSManikanta Guntupalli timeout = jiffies + msecs_to_jiffies(XI3C_XFER_TIMEOUT_MS);
444629a6dddSManikanta Guntupalli
445629a6dddSManikanta Guntupalli /* Read data from rx fifo */
446629a6dddSManikanta Guntupalli while (cmd->rx_len > 0 && !xi3c_is_resp_available(master)) {
447629a6dddSManikanta Guntupalli if (time_after(jiffies, timeout)) {
448629a6dddSManikanta Guntupalli dev_err(master->dev, "XI3C read timeout\n");
449629a6dddSManikanta Guntupalli return -EIO;
450629a6dddSManikanta Guntupalli }
451629a6dddSManikanta Guntupalli xi3c_master_rd_from_rx_fifo(master, cmd);
452629a6dddSManikanta Guntupalli usleep_range(XI3C_POLL_INTERVAL_US, 2 * XI3C_POLL_INTERVAL_US);
453629a6dddSManikanta Guntupalli }
454629a6dddSManikanta Guntupalli
455629a6dddSManikanta Guntupalli /* Read remaining data */
456629a6dddSManikanta Guntupalli xi3c_master_rd_from_rx_fifo(master, cmd);
457629a6dddSManikanta Guntupalli
458629a6dddSManikanta Guntupalli return 0;
459629a6dddSManikanta Guntupalli }
460629a6dddSManikanta Guntupalli
xi3c_master_wr_to_tx_fifo(struct xi3c_master * master,struct xi3c_cmd * cmd)461629a6dddSManikanta Guntupalli static void xi3c_master_wr_to_tx_fifo(struct xi3c_master *master,
462629a6dddSManikanta Guntupalli struct xi3c_cmd *cmd)
463629a6dddSManikanta Guntupalli {
464629a6dddSManikanta Guntupalli u16 wrfifo_space;
465629a6dddSManikanta Guntupalli u16 len;
466629a6dddSManikanta Guntupalli
467629a6dddSManikanta Guntupalli wrfifo_space = xi3c_wr_fifo_level(master);
468629a6dddSManikanta Guntupalli if (cmd->tx_len > wrfifo_space * XI3C_WORD_LEN)
469629a6dddSManikanta Guntupalli len = wrfifo_space * XI3C_WORD_LEN;
470629a6dddSManikanta Guntupalli else
471629a6dddSManikanta Guntupalli len = cmd->tx_len;
472629a6dddSManikanta Guntupalli
473629a6dddSManikanta Guntupalli if (len) {
474629a6dddSManikanta Guntupalli xi3c_writel_fifo(master->membase + XI3C_WR_FIFO_OFFSET, cmd->tx_buf,
475629a6dddSManikanta Guntupalli len);
476629a6dddSManikanta Guntupalli
477629a6dddSManikanta Guntupalli cmd->tx_buf = (const u8 *)cmd->tx_buf + len;
478629a6dddSManikanta Guntupalli cmd->tx_len -= len;
479629a6dddSManikanta Guntupalli }
480629a6dddSManikanta Guntupalli }
481629a6dddSManikanta Guntupalli
xi3c_master_write(struct xi3c_master * master,struct xi3c_cmd * cmd)482629a6dddSManikanta Guntupalli static int xi3c_master_write(struct xi3c_master *master, struct xi3c_cmd *cmd)
483629a6dddSManikanta Guntupalli {
484629a6dddSManikanta Guntupalli unsigned long timeout;
485629a6dddSManikanta Guntupalli u16 cmd_len;
486629a6dddSManikanta Guntupalli
487629a6dddSManikanta Guntupalli if (cmd->tx_len > XI3C_MAXDATA_LENGTH)
488629a6dddSManikanta Guntupalli return -EINVAL;
489629a6dddSManikanta Guntupalli /*
490629a6dddSManikanta Guntupalli * Zero-length probes (e.g. i2cdetect) legitimately pass a NULL
491629a6dddSManikanta Guntupalli * buffer; only a non-zero length requires one.
492629a6dddSManikanta Guntupalli */
493629a6dddSManikanta Guntupalli if (cmd->tx_len && !cmd->tx_buf)
494629a6dddSManikanta Guntupalli return -EINVAL;
495629a6dddSManikanta Guntupalli
496629a6dddSManikanta Guntupalli cmd_len = cmd->tx_len;
497629a6dddSManikanta Guntupalli
498629a6dddSManikanta Guntupalli /* Fill Tx fifo */
499629a6dddSManikanta Guntupalli xi3c_master_wr_to_tx_fifo(master, cmd);
500629a6dddSManikanta Guntupalli
501629a6dddSManikanta Guntupalli /* Write to command fifo */
502629a6dddSManikanta Guntupalli xi3c_master_write_to_cmdfifo(master, cmd, cmd_len);
503629a6dddSManikanta Guntupalli
504629a6dddSManikanta Guntupalli timeout = jiffies + msecs_to_jiffies(XI3C_XFER_TIMEOUT_MS);
505629a6dddSManikanta Guntupalli /* Fill if any remaining data to tx fifo */
506629a6dddSManikanta Guntupalli while (cmd->tx_len > 0 && !xi3c_is_resp_available(master)) {
507629a6dddSManikanta Guntupalli if (time_after(jiffies, timeout)) {
508629a6dddSManikanta Guntupalli dev_err(master->dev, "XI3C write timeout\n");
509629a6dddSManikanta Guntupalli return -EIO;
510629a6dddSManikanta Guntupalli }
511629a6dddSManikanta Guntupalli
512629a6dddSManikanta Guntupalli xi3c_master_wr_to_tx_fifo(master, cmd);
513629a6dddSManikanta Guntupalli usleep_range(XI3C_POLL_INTERVAL_US, 2 * XI3C_POLL_INTERVAL_US);
514629a6dddSManikanta Guntupalli }
515629a6dddSManikanta Guntupalli
516629a6dddSManikanta Guntupalli return 0;
517629a6dddSManikanta Guntupalli }
518629a6dddSManikanta Guntupalli
xi3c_master_xfer(struct xi3c_master * master,struct xi3c_cmd * cmd)519629a6dddSManikanta Guntupalli static int xi3c_master_xfer(struct xi3c_master *master, struct xi3c_cmd *cmd)
520629a6dddSManikanta Guntupalli {
521629a6dddSManikanta Guntupalli int ret;
522629a6dddSManikanta Guntupalli
523629a6dddSManikanta Guntupalli if (cmd->rnw)
524629a6dddSManikanta Guntupalli ret = xi3c_master_read(master, cmd);
525629a6dddSManikanta Guntupalli else
526629a6dddSManikanta Guntupalli ret = xi3c_master_write(master, cmd);
527629a6dddSManikanta Guntupalli
528629a6dddSManikanta Guntupalli if (ret)
529629a6dddSManikanta Guntupalli goto err_xfer_out;
530629a6dddSManikanta Guntupalli
531629a6dddSManikanta Guntupalli ret = xi3c_get_response(master, cmd);
532629a6dddSManikanta Guntupalli if (ret < 0)
533629a6dddSManikanta Guntupalli goto err_xfer_out;
534629a6dddSManikanta Guntupalli
535629a6dddSManikanta Guntupalli /* Short read leaves the controller parked in STOP; resume it for the next command */
536629a6dddSManikanta Guntupalli if (ret == XI3C_XFER_SHORT_READ)
537629a6dddSManikanta Guntupalli xi3c_master_resume(master);
538629a6dddSManikanta Guntupalli
539629a6dddSManikanta Guntupalli return 0;
540629a6dddSManikanta Guntupalli
541629a6dddSManikanta Guntupalli err_xfer_out:
542629a6dddSManikanta Guntupalli xi3c_master_reinit(master);
543629a6dddSManikanta Guntupalli return ret;
544629a6dddSManikanta Guntupalli }
545629a6dddSManikanta Guntupalli
xi3c_master_common_xfer(struct xi3c_master * master,struct xi3c_xfer * xfer)546629a6dddSManikanta Guntupalli static int xi3c_master_common_xfer(struct xi3c_master *master,
547629a6dddSManikanta Guntupalli struct xi3c_xfer *xfer)
548629a6dddSManikanta Guntupalli {
549629a6dddSManikanta Guntupalli unsigned int i;
550629a6dddSManikanta Guntupalli int ret;
551629a6dddSManikanta Guntupalli
552629a6dddSManikanta Guntupalli guard(mutex)(&master->lock);
553629a6dddSManikanta Guntupalli
554629a6dddSManikanta Guntupalli for (i = 0; i < xfer->ncmds; i++) {
555629a6dddSManikanta Guntupalli ret = xi3c_master_xfer(master, &xfer->cmds[i]);
556629a6dddSManikanta Guntupalli if (ret) {
557629a6dddSManikanta Guntupalli /* Count commands sent on the bus; the rest never ran */
558629a6dddSManikanta Guntupalli xfer->nissued = i + 1;
559629a6dddSManikanta Guntupalli return ret;
560629a6dddSManikanta Guntupalli }
561629a6dddSManikanta Guntupalli }
562629a6dddSManikanta Guntupalli
563629a6dddSManikanta Guntupalli xfer->nissued = xfer->ncmds;
564629a6dddSManikanta Guntupalli
565629a6dddSManikanta Guntupalli return 0;
566629a6dddSManikanta Guntupalli }
567629a6dddSManikanta Guntupalli
xi3c_master_do_daa(struct i3c_master_controller * m)568629a6dddSManikanta Guntupalli static int xi3c_master_do_daa(struct i3c_master_controller *m)
569629a6dddSManikanta Guntupalli {
570629a6dddSManikanta Guntupalli u8 (*pid_bufs)[XI3C_DAA_SLAVEINFO_READ_BYTECOUNT];
571629a6dddSManikanta Guntupalli struct xi3c_master *master = to_xi3c_master(m);
572629a6dddSManikanta Guntupalli struct xi3c_cmd *daa_cmd;
573629a6dddSManikanta Guntupalli struct xi3c_xfer *xfer;
574629a6dddSManikanta Guntupalli int addr, ret, i;
575629a6dddSManikanta Guntupalli u8 last_addr = 0;
576629a6dddSManikanta Guntupalli u8 *pid_buf;
577629a6dddSManikanta Guntupalli u8 ccc_id;
578629a6dddSManikanta Guntupalli
579629a6dddSManikanta Guntupalli xfer = xi3c_master_alloc_xfer(1);
580629a6dddSManikanta Guntupalli if (!xfer)
581629a6dddSManikanta Guntupalli return -ENOMEM;
582629a6dddSManikanta Guntupalli
583629a6dddSManikanta Guntupalli pid_bufs = kcalloc(XI3C_MAX_DEVS, XI3C_DAA_SLAVEINFO_READ_BYTECOUNT,
584629a6dddSManikanta Guntupalli GFP_KERNEL);
585629a6dddSManikanta Guntupalli if (!pid_bufs) {
586629a6dddSManikanta Guntupalli ret = -ENOMEM;
587629a6dddSManikanta Guntupalli goto out;
588629a6dddSManikanta Guntupalli }
589629a6dddSManikanta Guntupalli
590629a6dddSManikanta Guntupalli /* Fill ENTDAA CCC */
591629a6dddSManikanta Guntupalli ccc_id = I3C_CCC_ENTDAA;
592629a6dddSManikanta Guntupalli daa_cmd = &xfer->cmds[0];
593629a6dddSManikanta Guntupalli daa_cmd->addr = I3C_BROADCAST_ADDR;
594629a6dddSManikanta Guntupalli daa_cmd->rnw = false;
595629a6dddSManikanta Guntupalli daa_cmd->tx_buf = &ccc_id;
596629a6dddSManikanta Guntupalli daa_cmd->tx_len = 1;
597629a6dddSManikanta Guntupalli daa_cmd->type = XI3C_SDR_MODE;
598629a6dddSManikanta Guntupalli daa_cmd->tid = XI3C_SDR_TID;
599629a6dddSManikanta Guntupalli daa_cmd->continued = true;
600629a6dddSManikanta Guntupalli
601629a6dddSManikanta Guntupalli ret = xi3c_master_common_xfer(master, xfer);
602629a6dddSManikanta Guntupalli if (ret) {
603629a6dddSManikanta Guntupalli /* NACK on ENTDAA broadcast means no devices to enumerate */
604629a6dddSManikanta Guntupalli if (daa_cmd->err == I3C_ERROR_M2)
605629a6dddSManikanta Guntupalli ret = 0;
606629a6dddSManikanta Guntupalli goto err_daa;
607629a6dddSManikanta Guntupalli }
608629a6dddSManikanta Guntupalli
609629a6dddSManikanta Guntupalli master->daa.index = 0;
610629a6dddSManikanta Guntupalli
611629a6dddSManikanta Guntupalli while (true) {
612629a6dddSManikanta Guntupalli struct xi3c_cmd *cmd = &xfer->cmds[0];
613629a6dddSManikanta Guntupalli u8 daa_byte;
614629a6dddSManikanta Guntupalli
615629a6dddSManikanta Guntupalli /* Out of device slots; stop and keep what was enumerated */
616629a6dddSManikanta Guntupalli if (master->daa.index >= XI3C_MAX_DEVS) {
617629a6dddSManikanta Guntupalli dev_warn(master->dev,
618629a6dddSManikanta Guntupalli "DAA: reached %d devices, stopping enumeration\n",
619629a6dddSManikanta Guntupalli XI3C_MAX_DEVS);
620629a6dddSManikanta Guntupalli xi3c_master_reinit(master);
621629a6dddSManikanta Guntupalli break;
622629a6dddSManikanta Guntupalli }
623629a6dddSManikanta Guntupalli
624629a6dddSManikanta Guntupalli addr = i3c_master_get_free_addr(m, last_addr + 1);
625629a6dddSManikanta Guntupalli if (addr < 0) {
626629a6dddSManikanta Guntupalli dev_warn(master->dev,
627629a6dddSManikanta Guntupalli "DAA: no free dynamic address, stopping enumeration\n");
628629a6dddSManikanta Guntupalli xi3c_master_reinit(master);
629629a6dddSManikanta Guntupalli break;
630629a6dddSManikanta Guntupalli }
631629a6dddSManikanta Guntupalli
632629a6dddSManikanta Guntupalli pid_buf = pid_bufs[master->daa.index];
633629a6dddSManikanta Guntupalli
634629a6dddSManikanta Guntupalli daa_byte = (addr << 1) | (parity8(addr) ^ 1);
635629a6dddSManikanta Guntupalli
636629a6dddSManikanta Guntupalli cmd->tx_buf = &daa_byte;
637629a6dddSManikanta Guntupalli cmd->tx_len = 1;
638629a6dddSManikanta Guntupalli cmd->addr = I3C_BROADCAST_ADDR;
639629a6dddSManikanta Guntupalli cmd->rnw = true;
640629a6dddSManikanta Guntupalli cmd->rx_buf = pid_buf;
641629a6dddSManikanta Guntupalli cmd->rx_len = XI3C_DAA_SLAVEINFO_READ_BYTECOUNT;
642629a6dddSManikanta Guntupalli cmd->is_daa = true;
643629a6dddSManikanta Guntupalli cmd->type = XI3C_SDR_MODE;
644629a6dddSManikanta Guntupalli cmd->tid = XI3C_SDR_TID;
645629a6dddSManikanta Guntupalli cmd->continued = true;
646629a6dddSManikanta Guntupalli
647629a6dddSManikanta Guntupalli ret = xi3c_master_common_xfer(master, xfer);
648629a6dddSManikanta Guntupalli
649629a6dddSManikanta Guntupalli /* -ENODEV: no more responders, enumeration complete */
650629a6dddSManikanta Guntupalli if (ret == -ENODEV) {
651629a6dddSManikanta Guntupalli ret = 0;
652629a6dddSManikanta Guntupalli break;
653629a6dddSManikanta Guntupalli }
654629a6dddSManikanta Guntupalli if (ret)
655629a6dddSManikanta Guntupalli goto err_daa;
656629a6dddSManikanta Guntupalli
657629a6dddSManikanta Guntupalli master->daa.addrs[master->daa.index] = addr;
658629a6dddSManikanta Guntupalli last_addr = addr;
659629a6dddSManikanta Guntupalli master->daa.index++;
660629a6dddSManikanta Guntupalli }
661629a6dddSManikanta Guntupalli
662629a6dddSManikanta Guntupalli for (i = 0; i < master->daa.index; i++) {
663629a6dddSManikanta Guntupalli u64 pid;
664629a6dddSManikanta Guntupalli
665629a6dddSManikanta Guntupalli /* Ignore per-device add errors so one failure doesn't abort the rest */
666629a6dddSManikanta Guntupalli i3c_master_add_i3c_dev_locked(m, master->daa.addrs[i]);
667629a6dddSManikanta Guntupalli
668629a6dddSManikanta Guntupalli pid = FIELD_GET(XI3C_PID_MASK,
669629a6dddSManikanta Guntupalli get_unaligned_be64(pid_bufs[i]));
670629a6dddSManikanta Guntupalli dev_dbg(master->dev, "Client %d: PID: 0x%llx\n", i, pid);
671629a6dddSManikanta Guntupalli }
672629a6dddSManikanta Guntupalli
673629a6dddSManikanta Guntupalli ret = 0;
674629a6dddSManikanta Guntupalli goto out;
675629a6dddSManikanta Guntupalli
676629a6dddSManikanta Guntupalli err_daa:
677629a6dddSManikanta Guntupalli xi3c_master_reinit(master);
678629a6dddSManikanta Guntupalli out:
679629a6dddSManikanta Guntupalli kfree(pid_bufs);
680629a6dddSManikanta Guntupalli kfree(xfer);
681629a6dddSManikanta Guntupalli return ret;
682629a6dddSManikanta Guntupalli }
683629a6dddSManikanta Guntupalli
684629a6dddSManikanta Guntupalli static bool
xi3c_master_supports_ccc_cmd(struct i3c_master_controller * master,const struct i3c_ccc_cmd * cmd)685629a6dddSManikanta Guntupalli xi3c_master_supports_ccc_cmd(struct i3c_master_controller *master,
686629a6dddSManikanta Guntupalli const struct i3c_ccc_cmd *cmd)
687629a6dddSManikanta Guntupalli {
688629a6dddSManikanta Guntupalli if (cmd->ndests > 1)
689629a6dddSManikanta Guntupalli return false;
690629a6dddSManikanta Guntupalli
691629a6dddSManikanta Guntupalli switch (cmd->id) {
692629a6dddSManikanta Guntupalli case I3C_CCC_ENEC(true):
693629a6dddSManikanta Guntupalli case I3C_CCC_ENEC(false):
694629a6dddSManikanta Guntupalli case I3C_CCC_DISEC(true):
695629a6dddSManikanta Guntupalli case I3C_CCC_DISEC(false):
696629a6dddSManikanta Guntupalli case I3C_CCC_ENTAS(0, true):
697629a6dddSManikanta Guntupalli case I3C_CCC_ENTAS(0, false):
698629a6dddSManikanta Guntupalli case I3C_CCC_RSTDAA(true):
699629a6dddSManikanta Guntupalli case I3C_CCC_RSTDAA(false):
700629a6dddSManikanta Guntupalli case I3C_CCC_ENTDAA:
701629a6dddSManikanta Guntupalli case I3C_CCC_SETMWL(true):
702629a6dddSManikanta Guntupalli case I3C_CCC_SETMWL(false):
703629a6dddSManikanta Guntupalli case I3C_CCC_SETMRL(true):
704629a6dddSManikanta Guntupalli case I3C_CCC_SETMRL(false):
705629a6dddSManikanta Guntupalli case I3C_CCC_SETDASA:
706629a6dddSManikanta Guntupalli case I3C_CCC_SETNEWDA:
707629a6dddSManikanta Guntupalli case I3C_CCC_GETMWL:
708629a6dddSManikanta Guntupalli case I3C_CCC_GETMRL:
709629a6dddSManikanta Guntupalli case I3C_CCC_GETPID:
710629a6dddSManikanta Guntupalli case I3C_CCC_GETBCR:
711629a6dddSManikanta Guntupalli case I3C_CCC_GETDCR:
712629a6dddSManikanta Guntupalli case I3C_CCC_GETSTATUS:
713629a6dddSManikanta Guntupalli case I3C_CCC_GETMXDS:
714629a6dddSManikanta Guntupalli return true;
715629a6dddSManikanta Guntupalli default:
716629a6dddSManikanta Guntupalli return false;
717629a6dddSManikanta Guntupalli }
718629a6dddSManikanta Guntupalli }
719629a6dddSManikanta Guntupalli
xi3c_master_send_bdcast_ccc_cmd(struct xi3c_master * master,struct i3c_ccc_cmd * ccc)720629a6dddSManikanta Guntupalli static int xi3c_master_send_bdcast_ccc_cmd(struct xi3c_master *master,
721629a6dddSManikanta Guntupalli struct i3c_ccc_cmd *ccc)
722629a6dddSManikanta Guntupalli {
723629a6dddSManikanta Guntupalli struct xi3c_xfer *xfer __free(kfree) = NULL;
724629a6dddSManikanta Guntupalli u8 *buf __free(kfree) = NULL;
725629a6dddSManikanta Guntupalli struct xi3c_cmd *cmd;
726629a6dddSManikanta Guntupalli u16 xfer_len;
727629a6dddSManikanta Guntupalli int ret;
728629a6dddSManikanta Guntupalli
729629a6dddSManikanta Guntupalli if (ccc->dests[0].payload.len >= XI3C_MAXDATA_LENGTH)
730629a6dddSManikanta Guntupalli return -EINVAL;
731629a6dddSManikanta Guntupalli
732629a6dddSManikanta Guntupalli xfer_len = ccc->dests[0].payload.len + 1;
733629a6dddSManikanta Guntupalli
734629a6dddSManikanta Guntupalli xfer = xi3c_master_alloc_xfer(1);
735629a6dddSManikanta Guntupalli if (!xfer)
736629a6dddSManikanta Guntupalli return -ENOMEM;
737629a6dddSManikanta Guntupalli
738*3a2c4d55SKees Cook buf = kmalloc_objs(*buf, xfer_len);
739629a6dddSManikanta Guntupalli if (!buf)
740629a6dddSManikanta Guntupalli return -ENOMEM;
741629a6dddSManikanta Guntupalli
742629a6dddSManikanta Guntupalli buf[0] = ccc->id;
743629a6dddSManikanta Guntupalli memcpy(&buf[1], ccc->dests[0].payload.data, ccc->dests[0].payload.len);
744629a6dddSManikanta Guntupalli
745629a6dddSManikanta Guntupalli cmd = &xfer->cmds[0];
746629a6dddSManikanta Guntupalli cmd->addr = ccc->dests[0].addr;
747629a6dddSManikanta Guntupalli cmd->rnw = ccc->rnw;
748629a6dddSManikanta Guntupalli cmd->tx_buf = buf;
749629a6dddSManikanta Guntupalli cmd->tx_len = xfer_len;
750629a6dddSManikanta Guntupalli cmd->type = XI3C_SDR_MODE;
751629a6dddSManikanta Guntupalli cmd->tid = XI3C_SDR_TID;
752629a6dddSManikanta Guntupalli cmd->continued = false;
753629a6dddSManikanta Guntupalli
754629a6dddSManikanta Guntupalli ret = xi3c_master_common_xfer(master, xfer);
755629a6dddSManikanta Guntupalli ccc->err = cmd->err;
756629a6dddSManikanta Guntupalli
757629a6dddSManikanta Guntupalli return ret;
758629a6dddSManikanta Guntupalli }
759629a6dddSManikanta Guntupalli
xi3c_master_send_direct_ccc_cmd(struct xi3c_master * master,struct i3c_ccc_cmd * ccc)760629a6dddSManikanta Guntupalli static int xi3c_master_send_direct_ccc_cmd(struct xi3c_master *master,
761629a6dddSManikanta Guntupalli struct i3c_ccc_cmd *ccc)
762629a6dddSManikanta Guntupalli {
763629a6dddSManikanta Guntupalli struct xi3c_xfer *xfer __free(kfree) = NULL;
764629a6dddSManikanta Guntupalli struct xi3c_cmd *cmd;
765629a6dddSManikanta Guntupalli int ret;
766629a6dddSManikanta Guntupalli
767629a6dddSManikanta Guntupalli if (ccc->dests[0].payload.len > XI3C_MAXDATA_LENGTH)
768629a6dddSManikanta Guntupalli return -EINVAL;
769629a6dddSManikanta Guntupalli
770629a6dddSManikanta Guntupalli xfer = xi3c_master_alloc_xfer(2);
771629a6dddSManikanta Guntupalli if (!xfer)
772629a6dddSManikanta Guntupalli return -ENOMEM;
773629a6dddSManikanta Guntupalli
774629a6dddSManikanta Guntupalli /* Broadcasted message */
775629a6dddSManikanta Guntupalli cmd = &xfer->cmds[0];
776629a6dddSManikanta Guntupalli cmd->addr = I3C_BROADCAST_ADDR;
777629a6dddSManikanta Guntupalli cmd->rnw = false;
778629a6dddSManikanta Guntupalli cmd->tx_buf = &ccc->id;
779629a6dddSManikanta Guntupalli cmd->tx_len = 1;
780629a6dddSManikanta Guntupalli cmd->type = XI3C_SDR_MODE;
781629a6dddSManikanta Guntupalli cmd->tid = XI3C_SDR_TID;
782629a6dddSManikanta Guntupalli cmd->continued = true;
783629a6dddSManikanta Guntupalli
784629a6dddSManikanta Guntupalli /* Directed message */
785629a6dddSManikanta Guntupalli cmd = &xfer->cmds[1];
786629a6dddSManikanta Guntupalli cmd->addr = ccc->dests[0].addr;
787629a6dddSManikanta Guntupalli cmd->rnw = ccc->rnw;
788629a6dddSManikanta Guntupalli if (cmd->rnw) {
789629a6dddSManikanta Guntupalli cmd->rx_buf = ccc->dests[0].payload.data;
790629a6dddSManikanta Guntupalli cmd->rx_len = ccc->dests[0].payload.len;
791629a6dddSManikanta Guntupalli } else {
792629a6dddSManikanta Guntupalli cmd->tx_buf = ccc->dests[0].payload.data;
793629a6dddSManikanta Guntupalli cmd->tx_len = ccc->dests[0].payload.len;
794629a6dddSManikanta Guntupalli }
795629a6dddSManikanta Guntupalli cmd->type = XI3C_SDR_MODE;
796629a6dddSManikanta Guntupalli cmd->tid = XI3C_SDR_TID;
797629a6dddSManikanta Guntupalli cmd->continued = false;
798629a6dddSManikanta Guntupalli
799629a6dddSManikanta Guntupalli ret = xi3c_master_common_xfer(master, xfer);
800629a6dddSManikanta Guntupalli
801629a6dddSManikanta Guntupalli /*
802629a6dddSManikanta Guntupalli * Report broadcast error if any, else the directed one, so either
803629a6dddSManikanta Guntupalli * NACK reaches the caller
804629a6dddSManikanta Guntupalli */
805629a6dddSManikanta Guntupalli ccc->err = xfer->cmds[0].err ? xfer->cmds[0].err : xfer->cmds[1].err;
806629a6dddSManikanta Guntupalli
807629a6dddSManikanta Guntupalli /* Report actual byte count so the core sees the right length on short reads */
808629a6dddSManikanta Guntupalli if (!ret && ccc->rnw)
809629a6dddSManikanta Guntupalli ccc->dests[0].payload.len = min(xfer->cmds[1].rx_actual,
810629a6dddSManikanta Guntupalli ccc->dests[0].payload.len);
811629a6dddSManikanta Guntupalli
812629a6dddSManikanta Guntupalli return ret;
813629a6dddSManikanta Guntupalli }
814629a6dddSManikanta Guntupalli
xi3c_master_send_ccc_cmd(struct i3c_master_controller * m,struct i3c_ccc_cmd * cmd)815629a6dddSManikanta Guntupalli static int xi3c_master_send_ccc_cmd(struct i3c_master_controller *m,
816629a6dddSManikanta Guntupalli struct i3c_ccc_cmd *cmd)
817629a6dddSManikanta Guntupalli {
818629a6dddSManikanta Guntupalli struct xi3c_master *master = to_xi3c_master(m);
819629a6dddSManikanta Guntupalli
820629a6dddSManikanta Guntupalli if (cmd->id & I3C_CCC_DIRECT)
821629a6dddSManikanta Guntupalli return xi3c_master_send_direct_ccc_cmd(master, cmd);
822629a6dddSManikanta Guntupalli
823629a6dddSManikanta Guntupalli return xi3c_master_send_bdcast_ccc_cmd(master, cmd);
824629a6dddSManikanta Guntupalli }
825629a6dddSManikanta Guntupalli
xi3c_master_i3c_xfers(struct i3c_dev_desc * dev,struct i3c_xfer * xfers,int nxfers,enum i3c_xfer_mode mode)826629a6dddSManikanta Guntupalli static int xi3c_master_i3c_xfers(struct i3c_dev_desc *dev,
827629a6dddSManikanta Guntupalli struct i3c_xfer *xfers,
828629a6dddSManikanta Guntupalli int nxfers, enum i3c_xfer_mode mode)
829629a6dddSManikanta Guntupalli {
830629a6dddSManikanta Guntupalli struct i3c_master_controller *m = i3c_dev_get_master(dev);
831629a6dddSManikanta Guntupalli struct xi3c_master *master = to_xi3c_master(m);
832629a6dddSManikanta Guntupalli struct xi3c_xfer *xfer __free(kfree) = NULL;
833629a6dddSManikanta Guntupalli int i, ret;
834629a6dddSManikanta Guntupalli
835629a6dddSManikanta Guntupalli if (!nxfers)
836629a6dddSManikanta Guntupalli return 0;
837629a6dddSManikanta Guntupalli
838629a6dddSManikanta Guntupalli if (mode != I3C_SDR)
839629a6dddSManikanta Guntupalli return -EOPNOTSUPP;
840629a6dddSManikanta Guntupalli
841629a6dddSManikanta Guntupalli for (i = 0; i < nxfers; i++)
842629a6dddSManikanta Guntupalli if (xfers[i].len > XI3C_MAXDATA_LENGTH)
843629a6dddSManikanta Guntupalli return -EINVAL;
844629a6dddSManikanta Guntupalli
845629a6dddSManikanta Guntupalli xfer = xi3c_master_alloc_xfer(nxfers);
846629a6dddSManikanta Guntupalli if (!xfer)
847629a6dddSManikanta Guntupalli return -ENOMEM;
848629a6dddSManikanta Guntupalli
849629a6dddSManikanta Guntupalli for (i = 0; i < nxfers; i++) {
850629a6dddSManikanta Guntupalli struct xi3c_cmd *cmd = &xfer->cmds[i];
851629a6dddSManikanta Guntupalli
852629a6dddSManikanta Guntupalli cmd->addr = dev->info.dyn_addr;
853629a6dddSManikanta Guntupalli cmd->rnw = xfers[i].rnw;
854629a6dddSManikanta Guntupalli
855629a6dddSManikanta Guntupalli if (cmd->rnw) {
856629a6dddSManikanta Guntupalli cmd->rx_buf = xfers[i].data.in;
857629a6dddSManikanta Guntupalli cmd->rx_len = xfers[i].len;
858629a6dddSManikanta Guntupalli } else {
859629a6dddSManikanta Guntupalli cmd->tx_buf = xfers[i].data.out;
860629a6dddSManikanta Guntupalli cmd->tx_len = xfers[i].len;
861629a6dddSManikanta Guntupalli }
862629a6dddSManikanta Guntupalli
863629a6dddSManikanta Guntupalli cmd->type = XI3C_SDR_MODE;
864629a6dddSManikanta Guntupalli cmd->tid = XI3C_SDR_TID;
865629a6dddSManikanta Guntupalli cmd->continued = (i + 1) < nxfers;
866629a6dddSManikanta Guntupalli }
867629a6dddSManikanta Guntupalli
868629a6dddSManikanta Guntupalli ret = xi3c_master_common_xfer(master, xfer);
869629a6dddSManikanta Guntupalli
870629a6dddSManikanta Guntupalli for (i = 0; i < xfer->nissued; i++) {
871629a6dddSManikanta Guntupalli xfers[i].err = xfer->cmds[i].err;
872629a6dddSManikanta Guntupalli if (xfers[i].rnw)
873629a6dddSManikanta Guntupalli xfers[i].actual_len = min(xfer->cmds[i].rx_actual,
874629a6dddSManikanta Guntupalli xfers[i].len);
875629a6dddSManikanta Guntupalli }
876629a6dddSManikanta Guntupalli
877629a6dddSManikanta Guntupalli return ret;
878629a6dddSManikanta Guntupalli }
879629a6dddSManikanta Guntupalli
xi3c_master_i2c_xfers(struct i2c_dev_desc * dev,struct i2c_msg * xfers,int nxfers)880629a6dddSManikanta Guntupalli static int xi3c_master_i2c_xfers(struct i2c_dev_desc *dev,
881629a6dddSManikanta Guntupalli struct i2c_msg *xfers,
882629a6dddSManikanta Guntupalli int nxfers)
883629a6dddSManikanta Guntupalli {
884629a6dddSManikanta Guntupalli struct i3c_master_controller *m = i2c_dev_get_master(dev);
885629a6dddSManikanta Guntupalli struct xi3c_master *master = to_xi3c_master(m);
886629a6dddSManikanta Guntupalli struct xi3c_xfer *xfer __free(kfree) = NULL;
887629a6dddSManikanta Guntupalli int i;
888629a6dddSManikanta Guntupalli
889629a6dddSManikanta Guntupalli if (!nxfers)
890629a6dddSManikanta Guntupalli return 0;
891629a6dddSManikanta Guntupalli
892629a6dddSManikanta Guntupalli for (i = 0; i < nxfers; i++)
893629a6dddSManikanta Guntupalli if (xfers[i].len > XI3C_MAXDATA_LENGTH)
894629a6dddSManikanta Guntupalli return -EINVAL;
895629a6dddSManikanta Guntupalli
896629a6dddSManikanta Guntupalli xfer = xi3c_master_alloc_xfer(nxfers);
897629a6dddSManikanta Guntupalli if (!xfer)
898629a6dddSManikanta Guntupalli return -ENOMEM;
899629a6dddSManikanta Guntupalli
900629a6dddSManikanta Guntupalli for (i = 0; i < nxfers; i++) {
901629a6dddSManikanta Guntupalli struct xi3c_cmd *cmd = &xfer->cmds[i];
902629a6dddSManikanta Guntupalli
903629a6dddSManikanta Guntupalli cmd->addr = xfers[i].addr & XI3C_ADDR_MASK;
904629a6dddSManikanta Guntupalli cmd->rnw = !!(xfers[i].flags & I2C_M_RD);
905629a6dddSManikanta Guntupalli
906629a6dddSManikanta Guntupalli if (cmd->rnw) {
907629a6dddSManikanta Guntupalli cmd->rx_buf = xfers[i].buf;
908629a6dddSManikanta Guntupalli cmd->rx_len = xfers[i].len;
909629a6dddSManikanta Guntupalli } else {
910629a6dddSManikanta Guntupalli cmd->tx_buf = xfers[i].buf;
911629a6dddSManikanta Guntupalli cmd->tx_len = xfers[i].len;
912629a6dddSManikanta Guntupalli }
913629a6dddSManikanta Guntupalli
914629a6dddSManikanta Guntupalli cmd->type = XI3C_I2C_MODE;
915629a6dddSManikanta Guntupalli cmd->tid = XI3C_I2C_TID;
916629a6dddSManikanta Guntupalli cmd->continued = (i + 1) < nxfers;
917629a6dddSManikanta Guntupalli }
918629a6dddSManikanta Guntupalli
919629a6dddSManikanta Guntupalli return xi3c_master_common_xfer(master, xfer);
920629a6dddSManikanta Guntupalli }
921629a6dddSManikanta Guntupalli
xi3c_clk_cfg(struct xi3c_master * master,unsigned long sclhz,u8 mode)922629a6dddSManikanta Guntupalli static int xi3c_clk_cfg(struct xi3c_master *master, unsigned long sclhz, u8 mode)
923629a6dddSManikanta Guntupalli {
924629a6dddSManikanta Guntupalli unsigned long core_rate, core_periodns;
925629a6dddSManikanta Guntupalli u32 tcasmin, tsustart, tsustop, thdstart;
926629a6dddSManikanta Guntupalli u32 thigh, tlow, thold;
927629a6dddSManikanta Guntupalli u32 odthigh, odtlow;
928629a6dddSManikanta Guntupalli
929629a6dddSManikanta Guntupalli core_rate = clk_get_rate(master->pclk);
930629a6dddSManikanta Guntupalli if (!core_rate)
931629a6dddSManikanta Guntupalli return -EINVAL;
932629a6dddSManikanta Guntupalli
933629a6dddSManikanta Guntupalli if (!sclhz)
934629a6dddSManikanta Guntupalli return -EINVAL;
935629a6dddSManikanta Guntupalli
936629a6dddSManikanta Guntupalli core_periodns = DIV_ROUND_UP(NSEC_PER_SEC, core_rate);
937629a6dddSManikanta Guntupalli
938629a6dddSManikanta Guntupalli thigh = DIV_ROUND_UP(core_rate, sclhz) >> 1;
939629a6dddSManikanta Guntupalli tlow = thigh;
940629a6dddSManikanta Guntupalli
941629a6dddSManikanta Guntupalli /* Reject rates whose timing exceeds the 18-bit registers (would wrap) */
942629a6dddSManikanta Guntupalli if (thigh <= XI3C_CYCLE_ADJUST ||
943629a6dddSManikanta Guntupalli (thigh - XI3C_CYCLE_ADJUST) > XI3C_TIMING_MASK)
944629a6dddSManikanta Guntupalli return -EINVAL;
945629a6dddSManikanta Guntupalli
946629a6dddSManikanta Guntupalli /* Hold time : 40% of tlow time */
947629a6dddSManikanta Guntupalli thold = (tlow * 4) / 10;
948629a6dddSManikanta Guntupalli
949629a6dddSManikanta Guntupalli if (xi3c_get_revision_number(master) == 0)
950629a6dddSManikanta Guntupalli thold = max_t(u32, thold, XI3C_THOLD_MIN_REV0);
951629a6dddSManikanta Guntupalli else
952629a6dddSManikanta Guntupalli thold = max_t(u32, thold, XI3C_THOLD_MIN_REV1);
953629a6dddSManikanta Guntupalli
954629a6dddSManikanta Guntupalli iowrite32((thigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
955629a6dddSManikanta Guntupalli master->membase + XI3C_SCL_HIGH_TIME_OFFSET);
956629a6dddSManikanta Guntupalli iowrite32((tlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
957629a6dddSManikanta Guntupalli master->membase + XI3C_SCL_LOW_TIME_OFFSET);
958629a6dddSManikanta Guntupalli iowrite32((thold - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
959629a6dddSManikanta Guntupalli master->membase + XI3C_SDA_HOLD_TIME_OFFSET);
960629a6dddSManikanta Guntupalli
961629a6dddSManikanta Guntupalli if (mode == XI3C_I2C_MODE) {
962629a6dddSManikanta Guntupalli iowrite32((thigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
963629a6dddSManikanta Guntupalli master->membase + XI3C_OD_SCL_HIGH_TIME_OFFSET);
964629a6dddSManikanta Guntupalli iowrite32((tlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
965629a6dddSManikanta Guntupalli master->membase + XI3C_OD_SCL_LOW_TIME_OFFSET);
966629a6dddSManikanta Guntupalli
967629a6dddSManikanta Guntupalli tcasmin = DIV_ROUND_UP(XI3C_I2C_TCASMIN_NS, core_periodns);
968629a6dddSManikanta Guntupalli } else {
969629a6dddSManikanta Guntupalli odtlow = DIV_ROUND_UP(XI3C_OD_TLOW_NS, core_periodns);
970629a6dddSManikanta Guntupalli odthigh = DIV_ROUND_UP(XI3C_OD_THIGH_NS, core_periodns);
971629a6dddSManikanta Guntupalli
972629a6dddSManikanta Guntupalli odtlow = max(tlow, odtlow);
973629a6dddSManikanta Guntupalli odthigh = min(thigh, odthigh);
974629a6dddSManikanta Guntupalli
975629a6dddSManikanta Guntupalli if (odthigh <= XI3C_CYCLE_ADJUST)
976629a6dddSManikanta Guntupalli return -EINVAL;
977629a6dddSManikanta Guntupalli
978629a6dddSManikanta Guntupalli iowrite32((odthigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
979629a6dddSManikanta Guntupalli master->membase + XI3C_OD_SCL_HIGH_TIME_OFFSET);
980629a6dddSManikanta Guntupalli iowrite32((odtlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
981629a6dddSManikanta Guntupalli master->membase + XI3C_OD_SCL_LOW_TIME_OFFSET);
982629a6dddSManikanta Guntupalli
983629a6dddSManikanta Guntupalli tcasmin = DIV_ROUND_UP(XI3C_TCASMIN_NS, core_periodns);
984629a6dddSManikanta Guntupalli }
985629a6dddSManikanta Guntupalli
986629a6dddSManikanta Guntupalli thdstart = max(thigh, tcasmin);
987629a6dddSManikanta Guntupalli tsustart = max(tlow, tcasmin);
988629a6dddSManikanta Guntupalli tsustop = max(tlow, tcasmin);
989629a6dddSManikanta Guntupalli
990629a6dddSManikanta Guntupalli iowrite32((tsustart - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
991629a6dddSManikanta Guntupalli master->membase + XI3C_TSU_START_OFFSET);
992629a6dddSManikanta Guntupalli iowrite32((thdstart - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
993629a6dddSManikanta Guntupalli master->membase + XI3C_THD_START_OFFSET);
994629a6dddSManikanta Guntupalli iowrite32((tsustop - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
995629a6dddSManikanta Guntupalli master->membase + XI3C_TSU_STOP_OFFSET);
996629a6dddSManikanta Guntupalli
997629a6dddSManikanta Guntupalli return 0;
998629a6dddSManikanta Guntupalli }
999629a6dddSManikanta Guntupalli
xi3c_master_bus_init(struct i3c_master_controller * m)1000629a6dddSManikanta Guntupalli static int xi3c_master_bus_init(struct i3c_master_controller *m)
1001629a6dddSManikanta Guntupalli {
1002629a6dddSManikanta Guntupalli struct xi3c_master *master = to_xi3c_master(m);
1003629a6dddSManikanta Guntupalli struct i3c_bus *bus = i3c_master_get_bus(m);
1004629a6dddSManikanta Guntupalli struct i3c_device_info info = {};
1005629a6dddSManikanta Guntupalli unsigned long sclhz;
1006629a6dddSManikanta Guntupalli u32 pid1_bcr_dcr;
1007629a6dddSManikanta Guntupalli u8 mode;
1008629a6dddSManikanta Guntupalli int ret;
1009629a6dddSManikanta Guntupalli
1010629a6dddSManikanta Guntupalli switch (bus->mode) {
1011629a6dddSManikanta Guntupalli case I3C_BUS_MODE_MIXED_FAST:
1012629a6dddSManikanta Guntupalli case I3C_BUS_MODE_MIXED_LIMITED:
1013629a6dddSManikanta Guntupalli case I3C_BUS_MODE_MIXED_SLOW:
1014629a6dddSManikanta Guntupalli mode = XI3C_I2C_MODE;
1015629a6dddSManikanta Guntupalli sclhz = bus->scl_rate.i2c;
1016629a6dddSManikanta Guntupalli break;
1017629a6dddSManikanta Guntupalli case I3C_BUS_MODE_PURE:
1018629a6dddSManikanta Guntupalli mode = XI3C_SDR_MODE;
1019629a6dddSManikanta Guntupalli sclhz = bus->scl_rate.i3c;
1020629a6dddSManikanta Guntupalli break;
1021629a6dddSManikanta Guntupalli default:
1022629a6dddSManikanta Guntupalli return -EINVAL;
1023629a6dddSManikanta Guntupalli }
1024629a6dddSManikanta Guntupalli
1025629a6dddSManikanta Guntupalli ret = xi3c_clk_cfg(master, sclhz, mode);
1026629a6dddSManikanta Guntupalli if (ret)
1027629a6dddSManikanta Guntupalli return ret;
1028629a6dddSManikanta Guntupalli
1029629a6dddSManikanta Guntupalli xi3c_master_init(master);
1030629a6dddSManikanta Guntupalli
1031629a6dddSManikanta Guntupalli /* Get an address for the master. */
1032629a6dddSManikanta Guntupalli ret = i3c_master_get_free_addr(m, 0);
1033629a6dddSManikanta Guntupalli if (ret < 0)
1034629a6dddSManikanta Guntupalli return ret;
1035629a6dddSManikanta Guntupalli
1036629a6dddSManikanta Guntupalli info.dyn_addr = ret;
1037629a6dddSManikanta Guntupalli
1038629a6dddSManikanta Guntupalli /* Write the dynamic address value to the address register. */
1039629a6dddSManikanta Guntupalli iowrite32(info.dyn_addr, master->membase + XI3C_ADDRESS_OFFSET);
1040629a6dddSManikanta Guntupalli
1041629a6dddSManikanta Guntupalli /* Read PID, BCR and DCR values, and assign to i3c device info. */
1042629a6dddSManikanta Guntupalli pid1_bcr_dcr = ioread32(master->membase + XI3C_PID1_BCR_DCR);
1043629a6dddSManikanta Guntupalli info.pid = ((u64)FIELD_GET(XI3C_PID1_MASK, pid1_bcr_dcr) << 32) |
1044629a6dddSManikanta Guntupalli ioread32(master->membase + XI3C_PID0_OFFSET);
1045629a6dddSManikanta Guntupalli info.bcr = FIELD_GET(XI3C_BCR_MASK, pid1_bcr_dcr);
1046629a6dddSManikanta Guntupalli info.dcr = FIELD_GET(XI3C_DCR_MASK, pid1_bcr_dcr);
1047629a6dddSManikanta Guntupalli
1048629a6dddSManikanta Guntupalli return i3c_master_set_info(&master->base, &info);
1049629a6dddSManikanta Guntupalli }
1050629a6dddSManikanta Guntupalli
xi3c_master_bus_cleanup(struct i3c_master_controller * m)1051629a6dddSManikanta Guntupalli static void xi3c_master_bus_cleanup(struct i3c_master_controller *m)
1052629a6dddSManikanta Guntupalli {
1053629a6dddSManikanta Guntupalli struct xi3c_master *master = to_xi3c_master(m);
1054629a6dddSManikanta Guntupalli
1055629a6dddSManikanta Guntupalli xi3c_master_disable(master);
1056629a6dddSManikanta Guntupalli }
1057629a6dddSManikanta Guntupalli
1058629a6dddSManikanta Guntupalli static const struct i3c_master_controller_ops xi3c_master_ops = {
1059629a6dddSManikanta Guntupalli .bus_init = xi3c_master_bus_init,
1060629a6dddSManikanta Guntupalli .bus_cleanup = xi3c_master_bus_cleanup,
1061629a6dddSManikanta Guntupalli .do_daa = xi3c_master_do_daa,
1062629a6dddSManikanta Guntupalli .supports_ccc_cmd = xi3c_master_supports_ccc_cmd,
1063629a6dddSManikanta Guntupalli .send_ccc_cmd = xi3c_master_send_ccc_cmd,
1064629a6dddSManikanta Guntupalli .i3c_xfers = xi3c_master_i3c_xfers,
1065629a6dddSManikanta Guntupalli .i2c_xfers = xi3c_master_i2c_xfers,
1066629a6dddSManikanta Guntupalli };
1067629a6dddSManikanta Guntupalli
xi3c_master_probe(struct platform_device * pdev)1068629a6dddSManikanta Guntupalli static int xi3c_master_probe(struct platform_device *pdev)
1069629a6dddSManikanta Guntupalli {
1070629a6dddSManikanta Guntupalli struct xi3c_master *master;
1071629a6dddSManikanta Guntupalli int ret;
1072629a6dddSManikanta Guntupalli
1073629a6dddSManikanta Guntupalli master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
1074629a6dddSManikanta Guntupalli if (!master)
1075629a6dddSManikanta Guntupalli return -ENOMEM;
1076629a6dddSManikanta Guntupalli
1077629a6dddSManikanta Guntupalli master->dev = &pdev->dev;
1078629a6dddSManikanta Guntupalli
1079629a6dddSManikanta Guntupalli master->membase = devm_platform_ioremap_resource(pdev, 0);
1080629a6dddSManikanta Guntupalli if (IS_ERR(master->membase))
1081629a6dddSManikanta Guntupalli return dev_err_probe(master->dev, PTR_ERR(master->membase),
1082629a6dddSManikanta Guntupalli "Failed to map registers\n");
1083629a6dddSManikanta Guntupalli
1084629a6dddSManikanta Guntupalli master->pclk = devm_clk_get_enabled(master->dev, NULL);
1085629a6dddSManikanta Guntupalli if (IS_ERR(master->pclk))
1086629a6dddSManikanta Guntupalli return dev_err_probe(master->dev, PTR_ERR(master->pclk),
1087629a6dddSManikanta Guntupalli "Failed to get and enable clock\n");
1088629a6dddSManikanta Guntupalli
1089629a6dddSManikanta Guntupalli ret = devm_mutex_init(master->dev, &master->lock);
1090629a6dddSManikanta Guntupalli if (ret)
1091629a6dddSManikanta Guntupalli return ret;
1092629a6dddSManikanta Guntupalli
1093629a6dddSManikanta Guntupalli platform_set_drvdata(pdev, master);
1094629a6dddSManikanta Guntupalli
1095629a6dddSManikanta Guntupalli return i3c_master_register(&master->base, master->dev,
1096629a6dddSManikanta Guntupalli &xi3c_master_ops, false);
1097629a6dddSManikanta Guntupalli }
1098629a6dddSManikanta Guntupalli
xi3c_master_remove(struct platform_device * pdev)1099629a6dddSManikanta Guntupalli static void xi3c_master_remove(struct platform_device *pdev)
1100629a6dddSManikanta Guntupalli {
1101629a6dddSManikanta Guntupalli struct xi3c_master *master = platform_get_drvdata(pdev);
1102629a6dddSManikanta Guntupalli
1103629a6dddSManikanta Guntupalli i3c_master_unregister(&master->base);
1104629a6dddSManikanta Guntupalli }
1105629a6dddSManikanta Guntupalli
1106629a6dddSManikanta Guntupalli static const struct of_device_id xi3c_master_of_ids[] = {
1107629a6dddSManikanta Guntupalli { .compatible = "xlnx,axi-i3c-1.0" },
1108629a6dddSManikanta Guntupalli { },
1109629a6dddSManikanta Guntupalli };
1110629a6dddSManikanta Guntupalli MODULE_DEVICE_TABLE(of, xi3c_master_of_ids);
1111629a6dddSManikanta Guntupalli
1112629a6dddSManikanta Guntupalli static struct platform_driver xi3c_master_driver = {
1113629a6dddSManikanta Guntupalli .probe = xi3c_master_probe,
1114629a6dddSManikanta Guntupalli .remove = xi3c_master_remove,
1115629a6dddSManikanta Guntupalli .driver = {
1116629a6dddSManikanta Guntupalli .name = "axi-i3c-master",
1117629a6dddSManikanta Guntupalli .of_match_table = xi3c_master_of_ids,
1118629a6dddSManikanta Guntupalli },
1119629a6dddSManikanta Guntupalli };
1120629a6dddSManikanta Guntupalli module_platform_driver(xi3c_master_driver);
1121629a6dddSManikanta Guntupalli
1122629a6dddSManikanta Guntupalli MODULE_AUTHOR("Manikanta Guntupalli <manikanta.guntupalli@amd.com>");
1123629a6dddSManikanta Guntupalli MODULE_DESCRIPTION("AMD AXI I3C master driver");
1124629a6dddSManikanta Guntupalli MODULE_LICENSE("GPL");
1125