1*9ad9a52cSNicolas Pitre // SPDX-License-Identifier: BSD-3-Clause
2*9ad9a52cSNicolas Pitre /*
3*9ad9a52cSNicolas Pitre  * Copyright (c) 2020, MIPI Alliance, Inc.
4*9ad9a52cSNicolas Pitre  *
5*9ad9a52cSNicolas Pitre  * Author: Nicolas Pitre <npitre@baylibre.com>
6*9ad9a52cSNicolas Pitre  */
7*9ad9a52cSNicolas Pitre 
8*9ad9a52cSNicolas Pitre #include <linux/bitfield.h>
9*9ad9a52cSNicolas Pitre #include <linux/device.h>
10*9ad9a52cSNicolas Pitre #include <linux/errno.h>
11*9ad9a52cSNicolas Pitre #include <linux/i3c/master.h>
12*9ad9a52cSNicolas Pitre #include <linux/io.h>
13*9ad9a52cSNicolas Pitre 
14*9ad9a52cSNicolas Pitre #include "hci.h"
15*9ad9a52cSNicolas Pitre #include "cmd.h"
16*9ad9a52cSNicolas Pitre #include "ibi.h"
17*9ad9a52cSNicolas Pitre 
18*9ad9a52cSNicolas Pitre 
19*9ad9a52cSNicolas Pitre /*
20*9ad9a52cSNicolas Pitre  * PIO Access Area
21*9ad9a52cSNicolas Pitre  */
22*9ad9a52cSNicolas Pitre 
23*9ad9a52cSNicolas Pitre #define pio_reg_read(r)		readl(hci->PIO_regs + (PIO_##r))
24*9ad9a52cSNicolas Pitre #define pio_reg_write(r, v)	writel(v, hci->PIO_regs + (PIO_##r))
25*9ad9a52cSNicolas Pitre 
26*9ad9a52cSNicolas Pitre #define PIO_COMMAND_QUEUE_PORT		0x00
27*9ad9a52cSNicolas Pitre #define PIO_RESPONSE_QUEUE_PORT		0x04
28*9ad9a52cSNicolas Pitre #define PIO_XFER_DATA_PORT		0x08
29*9ad9a52cSNicolas Pitre #define PIO_IBI_PORT			0x0c
30*9ad9a52cSNicolas Pitre 
31*9ad9a52cSNicolas Pitre #define PIO_QUEUE_THLD_CTRL		0x10
32*9ad9a52cSNicolas Pitre #define QUEUE_IBI_STATUS_THLD		GENMASK(31, 24)
33*9ad9a52cSNicolas Pitre #define QUEUE_IBI_DATA_THLD		GENMASK(23, 16)
34*9ad9a52cSNicolas Pitre #define QUEUE_RESP_BUF_THLD		GENMASK(15, 8)
35*9ad9a52cSNicolas Pitre #define QUEUE_CMD_EMPTY_BUF_THLD	GENMASK(7, 0)
36*9ad9a52cSNicolas Pitre 
37*9ad9a52cSNicolas Pitre #define PIO_DATA_BUFFER_THLD_CTRL	0x14
38*9ad9a52cSNicolas Pitre #define DATA_RX_START_THLD		GENMASK(26, 24)
39*9ad9a52cSNicolas Pitre #define DATA_TX_START_THLD		GENMASK(18, 16)
40*9ad9a52cSNicolas Pitre #define DATA_RX_BUF_THLD		GENMASK(10, 8)
41*9ad9a52cSNicolas Pitre #define DATA_TX_BUF_THLD		GENMASK(2, 0)
42*9ad9a52cSNicolas Pitre 
43*9ad9a52cSNicolas Pitre #define PIO_QUEUE_SIZE			0x18
44*9ad9a52cSNicolas Pitre #define TX_DATA_BUFFER_SIZE		GENMASK(31, 24)
45*9ad9a52cSNicolas Pitre #define RX_DATA_BUFFER_SIZE		GENMASK(23, 16)
46*9ad9a52cSNicolas Pitre #define IBI_STATUS_SIZE			GENMASK(15, 8)
47*9ad9a52cSNicolas Pitre #define CR_QUEUE_SIZE			GENMASK(7, 0)
48*9ad9a52cSNicolas Pitre 
49*9ad9a52cSNicolas Pitre #define PIO_INTR_STATUS			0x20
50*9ad9a52cSNicolas Pitre #define PIO_INTR_STATUS_ENABLE		0x24
51*9ad9a52cSNicolas Pitre #define PIO_INTR_SIGNAL_ENABLE		0x28
52*9ad9a52cSNicolas Pitre #define PIO_INTR_FORCE			0x2c
53*9ad9a52cSNicolas Pitre #define STAT_TRANSFER_BLOCKED		BIT(25)
54*9ad9a52cSNicolas Pitre #define STAT_PERR_RESP_UFLOW		BIT(24)
55*9ad9a52cSNicolas Pitre #define STAT_PERR_CMD_OFLOW		BIT(23)
56*9ad9a52cSNicolas Pitre #define STAT_PERR_IBI_UFLOW		BIT(22)
57*9ad9a52cSNicolas Pitre #define STAT_PERR_RX_UFLOW		BIT(21)
58*9ad9a52cSNicolas Pitre #define STAT_PERR_TX_OFLOW		BIT(20)
59*9ad9a52cSNicolas Pitre #define STAT_ERR_RESP_QUEUE_FULL	BIT(19)
60*9ad9a52cSNicolas Pitre #define STAT_WARN_RESP_QUEUE_FULL	BIT(18)
61*9ad9a52cSNicolas Pitre #define STAT_ERR_IBI_QUEUE_FULL		BIT(17)
62*9ad9a52cSNicolas Pitre #define STAT_WARN_IBI_QUEUE_FULL	BIT(16)
63*9ad9a52cSNicolas Pitre #define STAT_ERR_RX_DATA_FULL		BIT(15)
64*9ad9a52cSNicolas Pitre #define STAT_WARN_RX_DATA_FULL		BIT(14)
65*9ad9a52cSNicolas Pitre #define STAT_ERR_TX_DATA_EMPTY		BIT(13)
66*9ad9a52cSNicolas Pitre #define STAT_WARN_TX_DATA_EMPTY		BIT(12)
67*9ad9a52cSNicolas Pitre #define STAT_TRANSFER_ERR		BIT(9)
68*9ad9a52cSNicolas Pitre #define STAT_WARN_INS_STOP_MODE		BIT(7)
69*9ad9a52cSNicolas Pitre #define STAT_TRANSFER_ABORT		BIT(5)
70*9ad9a52cSNicolas Pitre #define STAT_RESP_READY			BIT(4)
71*9ad9a52cSNicolas Pitre #define STAT_CMD_QUEUE_READY		BIT(3)
72*9ad9a52cSNicolas Pitre #define STAT_IBI_STATUS_THLD		BIT(2)
73*9ad9a52cSNicolas Pitre #define STAT_RX_THLD			BIT(1)
74*9ad9a52cSNicolas Pitre #define STAT_TX_THLD			BIT(0)
75*9ad9a52cSNicolas Pitre 
76*9ad9a52cSNicolas Pitre #define PIO_QUEUE_CUR_STATUS		0x38
77*9ad9a52cSNicolas Pitre #define CUR_IBI_Q_LEVEL			GENMASK(28, 20)
78*9ad9a52cSNicolas Pitre #define CUR_RESP_Q_LEVEL		GENMASK(18, 10)
79*9ad9a52cSNicolas Pitre #define CUR_CMD_Q_EMPTY_LEVEL		GENMASK(8, 0)
80*9ad9a52cSNicolas Pitre 
81*9ad9a52cSNicolas Pitre #define PIO_DATA_BUFFER_CUR_STATUS	0x3c
82*9ad9a52cSNicolas Pitre #define CUR_RX_BUF_LVL			GENMASK(26, 16)
83*9ad9a52cSNicolas Pitre #define CUR_TX_BUF_LVL			GENMASK(10, 0)
84*9ad9a52cSNicolas Pitre 
85*9ad9a52cSNicolas Pitre /*
86*9ad9a52cSNicolas Pitre  * Handy status bit combinations
87*9ad9a52cSNicolas Pitre  */
88*9ad9a52cSNicolas Pitre 
89*9ad9a52cSNicolas Pitre #define STAT_LATENCY_WARNINGS		(STAT_WARN_RESP_QUEUE_FULL | \
90*9ad9a52cSNicolas Pitre 					 STAT_WARN_IBI_QUEUE_FULL | \
91*9ad9a52cSNicolas Pitre 					 STAT_WARN_RX_DATA_FULL | \
92*9ad9a52cSNicolas Pitre 					 STAT_WARN_TX_DATA_EMPTY | \
93*9ad9a52cSNicolas Pitre 					 STAT_WARN_INS_STOP_MODE)
94*9ad9a52cSNicolas Pitre 
95*9ad9a52cSNicolas Pitre #define STAT_LATENCY_ERRORS		(STAT_ERR_RESP_QUEUE_FULL | \
96*9ad9a52cSNicolas Pitre 					 STAT_ERR_IBI_QUEUE_FULL | \
97*9ad9a52cSNicolas Pitre 					 STAT_ERR_RX_DATA_FULL | \
98*9ad9a52cSNicolas Pitre 					 STAT_ERR_TX_DATA_EMPTY)
99*9ad9a52cSNicolas Pitre 
100*9ad9a52cSNicolas Pitre #define STAT_PROG_ERRORS		(STAT_TRANSFER_BLOCKED | \
101*9ad9a52cSNicolas Pitre 					 STAT_PERR_RESP_UFLOW | \
102*9ad9a52cSNicolas Pitre 					 STAT_PERR_CMD_OFLOW | \
103*9ad9a52cSNicolas Pitre 					 STAT_PERR_IBI_UFLOW | \
104*9ad9a52cSNicolas Pitre 					 STAT_PERR_RX_UFLOW | \
105*9ad9a52cSNicolas Pitre 					 STAT_PERR_TX_OFLOW)
106*9ad9a52cSNicolas Pitre 
107*9ad9a52cSNicolas Pitre #define STAT_ALL_ERRORS			(STAT_TRANSFER_ABORT | \
108*9ad9a52cSNicolas Pitre 					 STAT_TRANSFER_ERR | \
109*9ad9a52cSNicolas Pitre 					 STAT_LATENCY_ERRORS | \
110*9ad9a52cSNicolas Pitre 					 STAT_PROG_ERRORS)
111*9ad9a52cSNicolas Pitre 
112*9ad9a52cSNicolas Pitre struct hci_pio_dev_ibi_data {
113*9ad9a52cSNicolas Pitre 	struct i3c_generic_ibi_pool *pool;
114*9ad9a52cSNicolas Pitre 	unsigned int max_len;
115*9ad9a52cSNicolas Pitre };
116*9ad9a52cSNicolas Pitre 
117*9ad9a52cSNicolas Pitre struct hci_pio_ibi_data {
118*9ad9a52cSNicolas Pitre 	struct i3c_ibi_slot *slot;
119*9ad9a52cSNicolas Pitre 	void *data_ptr;
120*9ad9a52cSNicolas Pitre 	unsigned int addr;
121*9ad9a52cSNicolas Pitre 	unsigned int seg_len, seg_cnt;
122*9ad9a52cSNicolas Pitre 	unsigned int max_len;
123*9ad9a52cSNicolas Pitre 	bool last_seg;
124*9ad9a52cSNicolas Pitre };
125*9ad9a52cSNicolas Pitre 
126*9ad9a52cSNicolas Pitre struct hci_pio_data {
127*9ad9a52cSNicolas Pitre 	spinlock_t lock;
128*9ad9a52cSNicolas Pitre 	struct hci_xfer *curr_xfer, *xfer_queue;
129*9ad9a52cSNicolas Pitre 	struct hci_xfer *curr_rx, *rx_queue;
130*9ad9a52cSNicolas Pitre 	struct hci_xfer *curr_tx, *tx_queue;
131*9ad9a52cSNicolas Pitre 	struct hci_xfer *curr_resp, *resp_queue;
132*9ad9a52cSNicolas Pitre 	struct hci_pio_ibi_data ibi;
133*9ad9a52cSNicolas Pitre 	unsigned int rx_thresh_size, tx_thresh_size;
134*9ad9a52cSNicolas Pitre 	unsigned int max_ibi_thresh;
135*9ad9a52cSNicolas Pitre 	u32 reg_queue_thresh;
136*9ad9a52cSNicolas Pitre 	u32 enabled_irqs;
137*9ad9a52cSNicolas Pitre };
138*9ad9a52cSNicolas Pitre 
hci_pio_init(struct i3c_hci * hci)139*9ad9a52cSNicolas Pitre static int hci_pio_init(struct i3c_hci *hci)
140*9ad9a52cSNicolas Pitre {
141*9ad9a52cSNicolas Pitre 	struct hci_pio_data *pio;
142*9ad9a52cSNicolas Pitre 	u32 val, size_val, rx_thresh, tx_thresh, ibi_val;
143*9ad9a52cSNicolas Pitre 
144*9ad9a52cSNicolas Pitre 	pio = kzalloc(sizeof(*pio), GFP_KERNEL);
145*9ad9a52cSNicolas Pitre 	if (!pio)
146*9ad9a52cSNicolas Pitre 		return -ENOMEM;
147*9ad9a52cSNicolas Pitre 
148*9ad9a52cSNicolas Pitre 	hci->io_data = pio;
149*9ad9a52cSNicolas Pitre 	spin_lock_init(&pio->lock);
150*9ad9a52cSNicolas Pitre 
151*9ad9a52cSNicolas Pitre 	size_val = pio_reg_read(QUEUE_SIZE);
152*9ad9a52cSNicolas Pitre 	dev_info(&hci->master.dev, "CMD/RESP FIFO = %ld entries\n",
153*9ad9a52cSNicolas Pitre 		 FIELD_GET(CR_QUEUE_SIZE, size_val));
154*9ad9a52cSNicolas Pitre 	dev_info(&hci->master.dev, "IBI FIFO = %ld bytes\n",
155*9ad9a52cSNicolas Pitre 		 4 * FIELD_GET(IBI_STATUS_SIZE, size_val));
156*9ad9a52cSNicolas Pitre 	dev_info(&hci->master.dev, "RX data FIFO = %d bytes\n",
157*9ad9a52cSNicolas Pitre 		 4 * (2 << FIELD_GET(RX_DATA_BUFFER_SIZE, size_val)));
158*9ad9a52cSNicolas Pitre 	dev_info(&hci->master.dev, "TX data FIFO = %d bytes\n",
159*9ad9a52cSNicolas Pitre 		 4 * (2 << FIELD_GET(TX_DATA_BUFFER_SIZE, size_val)));
160*9ad9a52cSNicolas Pitre 
161*9ad9a52cSNicolas Pitre 	/*
162*9ad9a52cSNicolas Pitre 	 * Let's initialize data thresholds to half of the actual FIFO size.
163*9ad9a52cSNicolas Pitre 	 * The start thresholds aren't used (set to 0) as the FIFO is always
164*9ad9a52cSNicolas Pitre 	 * serviced before the corresponding command is queued.
165*9ad9a52cSNicolas Pitre 	 */
166*9ad9a52cSNicolas Pitre 	rx_thresh = FIELD_GET(RX_DATA_BUFFER_SIZE, size_val);
167*9ad9a52cSNicolas Pitre 	tx_thresh = FIELD_GET(TX_DATA_BUFFER_SIZE, size_val);
168*9ad9a52cSNicolas Pitre 	if (hci->version_major == 1) {
169*9ad9a52cSNicolas Pitre 		/* those are expressed as 2^[n+1), so just sub 1 if not 0 */
170*9ad9a52cSNicolas Pitre 		if (rx_thresh)
171*9ad9a52cSNicolas Pitre 			rx_thresh -= 1;
172*9ad9a52cSNicolas Pitre 		if (tx_thresh)
173*9ad9a52cSNicolas Pitre 			tx_thresh -= 1;
174*9ad9a52cSNicolas Pitre 		pio->rx_thresh_size = 2 << rx_thresh;
175*9ad9a52cSNicolas Pitre 		pio->tx_thresh_size = 2 << tx_thresh;
176*9ad9a52cSNicolas Pitre 	} else {
177*9ad9a52cSNicolas Pitre 		/* size is 2^(n+1) and threshold is 2^n i.e. already halved */
178*9ad9a52cSNicolas Pitre 		pio->rx_thresh_size = 1 << rx_thresh;
179*9ad9a52cSNicolas Pitre 		pio->tx_thresh_size = 1 << tx_thresh;
180*9ad9a52cSNicolas Pitre 	}
181*9ad9a52cSNicolas Pitre 	val = FIELD_PREP(DATA_RX_BUF_THLD,   rx_thresh) |
182*9ad9a52cSNicolas Pitre 	      FIELD_PREP(DATA_TX_BUF_THLD,   tx_thresh);
183*9ad9a52cSNicolas Pitre 	pio_reg_write(DATA_BUFFER_THLD_CTRL, val);
184*9ad9a52cSNicolas Pitre 
185*9ad9a52cSNicolas Pitre 	/*
186*9ad9a52cSNicolas Pitre 	 * Let's raise an interrupt as soon as there is one free cmd slot
187*9ad9a52cSNicolas Pitre 	 * or one available response or IBI. For IBI data let's use half the
188*9ad9a52cSNicolas Pitre 	 * IBI queue size within allowed bounds.
189*9ad9a52cSNicolas Pitre 	 */
190*9ad9a52cSNicolas Pitre 	ibi_val = FIELD_GET(IBI_STATUS_SIZE, size_val);
191*9ad9a52cSNicolas Pitre 	pio->max_ibi_thresh = clamp_val(ibi_val/2, 1, 63);
192*9ad9a52cSNicolas Pitre 	val = FIELD_PREP(QUEUE_IBI_STATUS_THLD, 1) |
193*9ad9a52cSNicolas Pitre 	      FIELD_PREP(QUEUE_IBI_DATA_THLD, pio->max_ibi_thresh) |
194*9ad9a52cSNicolas Pitre 	      FIELD_PREP(QUEUE_RESP_BUF_THLD, 1) |
195*9ad9a52cSNicolas Pitre 	      FIELD_PREP(QUEUE_CMD_EMPTY_BUF_THLD, 1);
196*9ad9a52cSNicolas Pitre 	pio_reg_write(QUEUE_THLD_CTRL, val);
197*9ad9a52cSNicolas Pitre 	pio->reg_queue_thresh = val;
198*9ad9a52cSNicolas Pitre 
199*9ad9a52cSNicolas Pitre 	/* Disable all IRQs but allow all status bits */
200*9ad9a52cSNicolas Pitre 	pio_reg_write(INTR_SIGNAL_ENABLE, 0x0);
201*9ad9a52cSNicolas Pitre 	pio_reg_write(INTR_STATUS_ENABLE, 0xffffffff);
202*9ad9a52cSNicolas Pitre 
203*9ad9a52cSNicolas Pitre 	/* Always accept error interrupts (will be activated on first xfer) */
204*9ad9a52cSNicolas Pitre 	pio->enabled_irqs = STAT_ALL_ERRORS;
205*9ad9a52cSNicolas Pitre 
206*9ad9a52cSNicolas Pitre 	return 0;
207*9ad9a52cSNicolas Pitre }
208*9ad9a52cSNicolas Pitre 
hci_pio_cleanup(struct i3c_hci * hci)209*9ad9a52cSNicolas Pitre static void hci_pio_cleanup(struct i3c_hci *hci)
210*9ad9a52cSNicolas Pitre {
211*9ad9a52cSNicolas Pitre 	struct hci_pio_data *pio = hci->io_data;
212*9ad9a52cSNicolas Pitre 
213*9ad9a52cSNicolas Pitre 	pio_reg_write(INTR_SIGNAL_ENABLE, 0x0);
214*9ad9a52cSNicolas Pitre 
215*9ad9a52cSNicolas Pitre 	if (pio) {
216*9ad9a52cSNicolas Pitre 		DBG("status = %#x/%#x",
217*9ad9a52cSNicolas Pitre 		    pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
218*9ad9a52cSNicolas Pitre 		BUG_ON(pio->curr_xfer);
219*9ad9a52cSNicolas Pitre 		BUG_ON(pio->curr_rx);
220*9ad9a52cSNicolas Pitre 		BUG_ON(pio->curr_tx);
221*9ad9a52cSNicolas Pitre 		BUG_ON(pio->curr_resp);
222*9ad9a52cSNicolas Pitre 		kfree(pio);
223*9ad9a52cSNicolas Pitre 		hci->io_data = NULL;
224*9ad9a52cSNicolas Pitre 	}
225*9ad9a52cSNicolas Pitre }
226*9ad9a52cSNicolas Pitre 
hci_pio_write_cmd(struct i3c_hci * hci,struct hci_xfer * xfer)227*9ad9a52cSNicolas Pitre static void hci_pio_write_cmd(struct i3c_hci *hci, struct hci_xfer *xfer)
228*9ad9a52cSNicolas Pitre {
229*9ad9a52cSNicolas Pitre 	DBG("cmd_desc[%d] = 0x%08x", 0, xfer->cmd_desc[0]);
230*9ad9a52cSNicolas Pitre 	DBG("cmd_desc[%d] = 0x%08x", 1, xfer->cmd_desc[1]);
231*9ad9a52cSNicolas Pitre 	pio_reg_write(COMMAND_QUEUE_PORT, xfer->cmd_desc[0]);
232*9ad9a52cSNicolas Pitre 	pio_reg_write(COMMAND_QUEUE_PORT, xfer->cmd_desc[1]);
233*9ad9a52cSNicolas Pitre 	if (hci->cmd == &mipi_i3c_hci_cmd_v2) {
234*9ad9a52cSNicolas Pitre 		DBG("cmd_desc[%d] = 0x%08x", 2, xfer->cmd_desc[2]);
235*9ad9a52cSNicolas Pitre 		DBG("cmd_desc[%d] = 0x%08x", 3, xfer->cmd_desc[3]);
236*9ad9a52cSNicolas Pitre 		pio_reg_write(COMMAND_QUEUE_PORT, xfer->cmd_desc[2]);
237*9ad9a52cSNicolas Pitre 		pio_reg_write(COMMAND_QUEUE_PORT, xfer->cmd_desc[3]);
238*9ad9a52cSNicolas Pitre 	}
239*9ad9a52cSNicolas Pitre }
240*9ad9a52cSNicolas Pitre 
hci_pio_do_rx(struct i3c_hci * hci,struct hci_pio_data * pio)241*9ad9a52cSNicolas Pitre static bool hci_pio_do_rx(struct i3c_hci *hci, struct hci_pio_data *pio)
242*9ad9a52cSNicolas Pitre {
243*9ad9a52cSNicolas Pitre 	struct hci_xfer *xfer = pio->curr_rx;
244*9ad9a52cSNicolas Pitre 	unsigned int nr_words;
245*9ad9a52cSNicolas Pitre 	u32 *p;
246*9ad9a52cSNicolas Pitre 
247*9ad9a52cSNicolas Pitre 	p = xfer->data;
248*9ad9a52cSNicolas Pitre 	p += (xfer->data_len - xfer->data_left) / 4;
249*9ad9a52cSNicolas Pitre 
250*9ad9a52cSNicolas Pitre 	while (xfer->data_left >= 4) {
251*9ad9a52cSNicolas Pitre 		/* bail out if FIFO hasn't reached the threshold value yet */
252*9ad9a52cSNicolas Pitre 		if (!(pio_reg_read(INTR_STATUS) & STAT_RX_THLD))
253*9ad9a52cSNicolas Pitre 			return false;
254*9ad9a52cSNicolas Pitre 		nr_words = min(xfer->data_left / 4, pio->rx_thresh_size);
255*9ad9a52cSNicolas Pitre 		/* extract data from FIFO */
256*9ad9a52cSNicolas Pitre 		xfer->data_left -= nr_words * 4;
257*9ad9a52cSNicolas Pitre 		DBG("now %d left %d", nr_words * 4, xfer->data_left);
258*9ad9a52cSNicolas Pitre 		while (nr_words--)
259*9ad9a52cSNicolas Pitre 			*p++ = pio_reg_read(XFER_DATA_PORT);
260*9ad9a52cSNicolas Pitre 	}
261*9ad9a52cSNicolas Pitre 
262*9ad9a52cSNicolas Pitre 	/* trailing data is retrieved upon response reception */
263*9ad9a52cSNicolas Pitre 	return !xfer->data_left;
264*9ad9a52cSNicolas Pitre }
265*9ad9a52cSNicolas Pitre 
hci_pio_do_trailing_rx(struct i3c_hci * hci,struct hci_pio_data * pio,unsigned int count)266*9ad9a52cSNicolas Pitre static void hci_pio_do_trailing_rx(struct i3c_hci *hci,
267*9ad9a52cSNicolas Pitre 				   struct hci_pio_data *pio, unsigned int count)
268*9ad9a52cSNicolas Pitre {
269*9ad9a52cSNicolas Pitre 	struct hci_xfer *xfer = pio->curr_rx;
270*9ad9a52cSNicolas Pitre 	u32 *p;
271*9ad9a52cSNicolas Pitre 
272*9ad9a52cSNicolas Pitre 	DBG("%d remaining", count);
273*9ad9a52cSNicolas Pitre 
274*9ad9a52cSNicolas Pitre 	p = xfer->data;
275*9ad9a52cSNicolas Pitre 	p += (xfer->data_len - xfer->data_left) / 4;
276*9ad9a52cSNicolas Pitre 
277*9ad9a52cSNicolas Pitre 	if (count >= 4) {
278*9ad9a52cSNicolas Pitre 		unsigned int nr_words = count / 4;
279*9ad9a52cSNicolas Pitre 		/* extract data from FIFO */
280*9ad9a52cSNicolas Pitre 		xfer->data_left -= nr_words * 4;
281*9ad9a52cSNicolas Pitre 		DBG("now %d left %d", nr_words * 4, xfer->data_left);
282*9ad9a52cSNicolas Pitre 		while (nr_words--)
283*9ad9a52cSNicolas Pitre 			*p++ = pio_reg_read(XFER_DATA_PORT);
284*9ad9a52cSNicolas Pitre 	}
285*9ad9a52cSNicolas Pitre 
286*9ad9a52cSNicolas Pitre 	count &= 3;
287*9ad9a52cSNicolas Pitre 	if (count) {
288*9ad9a52cSNicolas Pitre 		/*
289*9ad9a52cSNicolas Pitre 		 * There are trailing bytes in the last word.
290*9ad9a52cSNicolas Pitre 		 * Fetch it and extract bytes in an endian independent way.
291*9ad9a52cSNicolas Pitre 		 * Unlike the TX case, we must not write memory past the
292*9ad9a52cSNicolas Pitre 		 * end of the destination buffer.
293*9ad9a52cSNicolas Pitre 		 */
294*9ad9a52cSNicolas Pitre 		u8 *p_byte = (u8 *)p;
295*9ad9a52cSNicolas Pitre 		u32 data = pio_reg_read(XFER_DATA_PORT);
296*9ad9a52cSNicolas Pitre 
297*9ad9a52cSNicolas Pitre 		xfer->data_word_before_partial = data;
298*9ad9a52cSNicolas Pitre 		xfer->data_left -= count;
299*9ad9a52cSNicolas Pitre 		data = (__force u32) cpu_to_le32(data);
300*9ad9a52cSNicolas Pitre 		while (count--) {
301*9ad9a52cSNicolas Pitre 			*p_byte++ = data;
302*9ad9a52cSNicolas Pitre 			data >>= 8;
303*9ad9a52cSNicolas Pitre 		}
304*9ad9a52cSNicolas Pitre 	}
305*9ad9a52cSNicolas Pitre }
306*9ad9a52cSNicolas Pitre 
hci_pio_do_tx(struct i3c_hci * hci,struct hci_pio_data * pio)307*9ad9a52cSNicolas Pitre static bool hci_pio_do_tx(struct i3c_hci *hci, struct hci_pio_data *pio)
308*9ad9a52cSNicolas Pitre {
309*9ad9a52cSNicolas Pitre 	struct hci_xfer *xfer = pio->curr_tx;
310*9ad9a52cSNicolas Pitre 	unsigned int nr_words;
311*9ad9a52cSNicolas Pitre 	u32 *p;
312*9ad9a52cSNicolas Pitre 
313*9ad9a52cSNicolas Pitre 	p = xfer->data;
314*9ad9a52cSNicolas Pitre 	p += (xfer->data_len - xfer->data_left) / 4;
315*9ad9a52cSNicolas Pitre 
316*9ad9a52cSNicolas Pitre 	while (xfer->data_left >= 4) {
317*9ad9a52cSNicolas Pitre 		/* bail out if FIFO free space is below set threshold */
318*9ad9a52cSNicolas Pitre 		if (!(pio_reg_read(INTR_STATUS) & STAT_TX_THLD))
319*9ad9a52cSNicolas Pitre 			return false;
320*9ad9a52cSNicolas Pitre 		/* we can fill up to that TX threshold */
321*9ad9a52cSNicolas Pitre 		nr_words = min(xfer->data_left / 4, pio->tx_thresh_size);
322*9ad9a52cSNicolas Pitre 		/* push data into the FIFO */
323*9ad9a52cSNicolas Pitre 		xfer->data_left -= nr_words * 4;
324*9ad9a52cSNicolas Pitre 		DBG("now %d left %d", nr_words * 4, xfer->data_left);
325*9ad9a52cSNicolas Pitre 		while (nr_words--)
326*9ad9a52cSNicolas Pitre 			pio_reg_write(XFER_DATA_PORT, *p++);
327*9ad9a52cSNicolas Pitre 	}
328*9ad9a52cSNicolas Pitre 
329*9ad9a52cSNicolas Pitre 	if (xfer->data_left) {
330*9ad9a52cSNicolas Pitre 		/*
331*9ad9a52cSNicolas Pitre 		 * There are trailing bytes to send. We can simply load
332*9ad9a52cSNicolas Pitre 		 * them from memory as a word which will keep those bytes
333*9ad9a52cSNicolas Pitre 		 * in their proper place even on a BE system. This will
334*9ad9a52cSNicolas Pitre 		 * also get some bytes past the actual buffer but no one
335*9ad9a52cSNicolas Pitre 		 * should care as they won't be sent out.
336*9ad9a52cSNicolas Pitre 		 */
337*9ad9a52cSNicolas Pitre 		if (!(pio_reg_read(INTR_STATUS) & STAT_TX_THLD))
338*9ad9a52cSNicolas Pitre 			return false;
339*9ad9a52cSNicolas Pitre 		DBG("trailing %d", xfer->data_left);
340*9ad9a52cSNicolas Pitre 		pio_reg_write(XFER_DATA_PORT, *p);
341*9ad9a52cSNicolas Pitre 		xfer->data_left = 0;
342*9ad9a52cSNicolas Pitre 	}
343*9ad9a52cSNicolas Pitre 
344*9ad9a52cSNicolas Pitre 	return true;
345*9ad9a52cSNicolas Pitre }
346*9ad9a52cSNicolas Pitre 
hci_pio_process_rx(struct i3c_hci * hci,struct hci_pio_data * pio)347*9ad9a52cSNicolas Pitre static bool hci_pio_process_rx(struct i3c_hci *hci, struct hci_pio_data *pio)
348*9ad9a52cSNicolas Pitre {
349*9ad9a52cSNicolas Pitre 	while (pio->curr_rx && hci_pio_do_rx(hci, pio))
350*9ad9a52cSNicolas Pitre 		pio->curr_rx = pio->curr_rx->next_data;
351*9ad9a52cSNicolas Pitre 	return !pio->curr_rx;
352*9ad9a52cSNicolas Pitre }
353*9ad9a52cSNicolas Pitre 
hci_pio_process_tx(struct i3c_hci * hci,struct hci_pio_data * pio)354*9ad9a52cSNicolas Pitre static bool hci_pio_process_tx(struct i3c_hci *hci, struct hci_pio_data *pio)
355*9ad9a52cSNicolas Pitre {
356*9ad9a52cSNicolas Pitre 	while (pio->curr_tx && hci_pio_do_tx(hci, pio))
357*9ad9a52cSNicolas Pitre 		pio->curr_tx = pio->curr_tx->next_data;
358*9ad9a52cSNicolas Pitre 	return !pio->curr_tx;
359*9ad9a52cSNicolas Pitre }
360*9ad9a52cSNicolas Pitre 
hci_pio_queue_data(struct i3c_hci * hci,struct hci_pio_data * pio)361*9ad9a52cSNicolas Pitre static void hci_pio_queue_data(struct i3c_hci *hci, struct hci_pio_data *pio)
362*9ad9a52cSNicolas Pitre {
363*9ad9a52cSNicolas Pitre 	struct hci_xfer *xfer = pio->curr_xfer;
364*9ad9a52cSNicolas Pitre 	struct hci_xfer *prev_queue_tail;
365*9ad9a52cSNicolas Pitre 
366*9ad9a52cSNicolas Pitre 	if (!xfer->data) {
367*9ad9a52cSNicolas Pitre 		xfer->data_len = xfer->data_left = 0;
368*9ad9a52cSNicolas Pitre 		return;
369*9ad9a52cSNicolas Pitre 	}
370*9ad9a52cSNicolas Pitre 
371*9ad9a52cSNicolas Pitre 	if (xfer->rnw) {
372*9ad9a52cSNicolas Pitre 		prev_queue_tail = pio->rx_queue;
373*9ad9a52cSNicolas Pitre 		pio->rx_queue = xfer;
374*9ad9a52cSNicolas Pitre 		if (pio->curr_rx) {
375*9ad9a52cSNicolas Pitre 			prev_queue_tail->next_data = xfer;
376*9ad9a52cSNicolas Pitre 		} else {
377*9ad9a52cSNicolas Pitre 			pio->curr_rx = xfer;
378*9ad9a52cSNicolas Pitre 			if (!hci_pio_process_rx(hci, pio))
379*9ad9a52cSNicolas Pitre 				pio->enabled_irqs |= STAT_RX_THLD;
380*9ad9a52cSNicolas Pitre 		}
381*9ad9a52cSNicolas Pitre 	} else {
382*9ad9a52cSNicolas Pitre 		prev_queue_tail = pio->tx_queue;
383*9ad9a52cSNicolas Pitre 		pio->tx_queue = xfer;
384*9ad9a52cSNicolas Pitre 		if (pio->curr_tx) {
385*9ad9a52cSNicolas Pitre 			prev_queue_tail->next_data = xfer;
386*9ad9a52cSNicolas Pitre 		} else {
387*9ad9a52cSNicolas Pitre 			pio->curr_tx = xfer;
388*9ad9a52cSNicolas Pitre 			if (!hci_pio_process_tx(hci, pio))
389*9ad9a52cSNicolas Pitre 				pio->enabled_irqs |= STAT_TX_THLD;
390*9ad9a52cSNicolas Pitre 		}
391*9ad9a52cSNicolas Pitre 	}
392*9ad9a52cSNicolas Pitre }
393*9ad9a52cSNicolas Pitre 
hci_pio_push_to_next_rx(struct i3c_hci * hci,struct hci_xfer * xfer,unsigned int words_to_keep)394*9ad9a52cSNicolas Pitre static void hci_pio_push_to_next_rx(struct i3c_hci *hci, struct hci_xfer *xfer,
395*9ad9a52cSNicolas Pitre 				    unsigned int words_to_keep)
396*9ad9a52cSNicolas Pitre {
397*9ad9a52cSNicolas Pitre 	u32 *from = xfer->data;
398*9ad9a52cSNicolas Pitre 	u32 from_last;
399*9ad9a52cSNicolas Pitre 	unsigned int received, count;
400*9ad9a52cSNicolas Pitre 
401*9ad9a52cSNicolas Pitre 	received = (xfer->data_len - xfer->data_left) / 4;
402*9ad9a52cSNicolas Pitre 	if ((xfer->data_len - xfer->data_left) & 3) {
403*9ad9a52cSNicolas Pitre 		from_last = xfer->data_word_before_partial;
404*9ad9a52cSNicolas Pitre 		received += 1;
405*9ad9a52cSNicolas Pitre 	} else {
406*9ad9a52cSNicolas Pitre 		from_last = from[received];
407*9ad9a52cSNicolas Pitre 	}
408*9ad9a52cSNicolas Pitre 	from += words_to_keep;
409*9ad9a52cSNicolas Pitre 	count = received - words_to_keep;
410*9ad9a52cSNicolas Pitre 
411*9ad9a52cSNicolas Pitre 	while (count) {
412*9ad9a52cSNicolas Pitre 		unsigned int room, left, chunk, bytes_to_move;
413*9ad9a52cSNicolas Pitre 		u32 last_word;
414*9ad9a52cSNicolas Pitre 
415*9ad9a52cSNicolas Pitre 		xfer = xfer->next_data;
416*9ad9a52cSNicolas Pitre 		if (!xfer) {
417*9ad9a52cSNicolas Pitre 			dev_err(&hci->master.dev, "pushing RX data to unexistent xfer\n");
418*9ad9a52cSNicolas Pitre 			return;
419*9ad9a52cSNicolas Pitre 		}
420*9ad9a52cSNicolas Pitre 
421*9ad9a52cSNicolas Pitre 		room = DIV_ROUND_UP(xfer->data_len, 4);
422*9ad9a52cSNicolas Pitre 		left = DIV_ROUND_UP(xfer->data_left, 4);
423*9ad9a52cSNicolas Pitre 		chunk = min(count, room);
424*9ad9a52cSNicolas Pitre 		if (chunk > left) {
425*9ad9a52cSNicolas Pitre 			hci_pio_push_to_next_rx(hci, xfer, chunk - left);
426*9ad9a52cSNicolas Pitre 			left = chunk;
427*9ad9a52cSNicolas Pitre 			xfer->data_left = left * 4;
428*9ad9a52cSNicolas Pitre 		}
429*9ad9a52cSNicolas Pitre 
430*9ad9a52cSNicolas Pitre 		bytes_to_move = xfer->data_len - xfer->data_left;
431*9ad9a52cSNicolas Pitre 		if (bytes_to_move & 3) {
432*9ad9a52cSNicolas Pitre 			/* preserve word  to become partial */
433*9ad9a52cSNicolas Pitre 			u32 *p = xfer->data;
434*9ad9a52cSNicolas Pitre 
435*9ad9a52cSNicolas Pitre 			xfer->data_word_before_partial = p[bytes_to_move / 4];
436*9ad9a52cSNicolas Pitre 		}
437*9ad9a52cSNicolas Pitre 		memmove(xfer->data + chunk, xfer->data, bytes_to_move);
438*9ad9a52cSNicolas Pitre 
439*9ad9a52cSNicolas Pitre 		/* treat last word specially because of partial word issues */
440*9ad9a52cSNicolas Pitre 		chunk -= 1;
441*9ad9a52cSNicolas Pitre 
442*9ad9a52cSNicolas Pitre 		memcpy(xfer->data, from, chunk * 4);
443*9ad9a52cSNicolas Pitre 		xfer->data_left -= chunk * 4;
444*9ad9a52cSNicolas Pitre 		from += chunk;
445*9ad9a52cSNicolas Pitre 		count -= chunk;
446*9ad9a52cSNicolas Pitre 
447*9ad9a52cSNicolas Pitre 		last_word = (count == 1) ? from_last : *from++;
448*9ad9a52cSNicolas Pitre 		if (xfer->data_left < 4) {
449*9ad9a52cSNicolas Pitre 			/*
450*9ad9a52cSNicolas Pitre 			 * Like in hci_pio_do_trailing_rx(), preserve original
451*9ad9a52cSNicolas Pitre 			 * word to be stored partially then store bytes it
452*9ad9a52cSNicolas Pitre 			 * in an endian independent way.
453*9ad9a52cSNicolas Pitre 			 */
454*9ad9a52cSNicolas Pitre 			u8 *p_byte = xfer->data;
455*9ad9a52cSNicolas Pitre 
456*9ad9a52cSNicolas Pitre 			p_byte += chunk * 4;
457*9ad9a52cSNicolas Pitre 			xfer->data_word_before_partial = last_word;
458*9ad9a52cSNicolas Pitre 			last_word = (__force u32) cpu_to_le32(last_word);
459*9ad9a52cSNicolas Pitre 			while (xfer->data_left--) {
460*9ad9a52cSNicolas Pitre 				*p_byte++ = last_word;
461*9ad9a52cSNicolas Pitre 				last_word >>= 8;
462*9ad9a52cSNicolas Pitre 			}
463*9ad9a52cSNicolas Pitre 		} else {
464*9ad9a52cSNicolas Pitre 			u32 *p = xfer->data;
465*9ad9a52cSNicolas Pitre 
466*9ad9a52cSNicolas Pitre 			p[chunk] = last_word;
467*9ad9a52cSNicolas Pitre 			xfer->data_left -= 4;
468*9ad9a52cSNicolas Pitre 		}
469*9ad9a52cSNicolas Pitre 		count--;
470*9ad9a52cSNicolas Pitre 	}
471*9ad9a52cSNicolas Pitre }
472*9ad9a52cSNicolas Pitre 
473*9ad9a52cSNicolas Pitre static void hci_pio_err(struct i3c_hci *hci, struct hci_pio_data *pio,
474*9ad9a52cSNicolas Pitre 			u32 status);
475*9ad9a52cSNicolas Pitre 
hci_pio_process_resp(struct i3c_hci * hci,struct hci_pio_data * pio)476*9ad9a52cSNicolas Pitre static bool hci_pio_process_resp(struct i3c_hci *hci, struct hci_pio_data *pio)
477*9ad9a52cSNicolas Pitre {
478*9ad9a52cSNicolas Pitre 	while (pio->curr_resp &&
479*9ad9a52cSNicolas Pitre 	       (pio_reg_read(INTR_STATUS) & STAT_RESP_READY)) {
480*9ad9a52cSNicolas Pitre 		struct hci_xfer *xfer = pio->curr_resp;
481*9ad9a52cSNicolas Pitre 		u32 resp = pio_reg_read(RESPONSE_QUEUE_PORT);
482*9ad9a52cSNicolas Pitre 		unsigned int tid = RESP_TID(resp);
483*9ad9a52cSNicolas Pitre 
484*9ad9a52cSNicolas Pitre 		DBG("resp = 0x%08x", resp);
485*9ad9a52cSNicolas Pitre 		if (tid != xfer->cmd_tid) {
486*9ad9a52cSNicolas Pitre 			dev_err(&hci->master.dev,
487*9ad9a52cSNicolas Pitre 				"response tid=%d when expecting %d\n",
488*9ad9a52cSNicolas Pitre 				tid, xfer->cmd_tid);
489*9ad9a52cSNicolas Pitre 			/* let's pretend it is a prog error... any of them  */
490*9ad9a52cSNicolas Pitre 			hci_pio_err(hci, pio, STAT_PROG_ERRORS);
491*9ad9a52cSNicolas Pitre 			return false;
492*9ad9a52cSNicolas Pitre 		}
493*9ad9a52cSNicolas Pitre 		xfer->response = resp;
494*9ad9a52cSNicolas Pitre 
495*9ad9a52cSNicolas Pitre 		if (pio->curr_rx == xfer) {
496*9ad9a52cSNicolas Pitre 			/*
497*9ad9a52cSNicolas Pitre 			 * Response availability implies RX completion.
498*9ad9a52cSNicolas Pitre 			 * Retrieve trailing RX data if any.
499*9ad9a52cSNicolas Pitre 			 * Note that short reads are possible.
500*9ad9a52cSNicolas Pitre 			 */
501*9ad9a52cSNicolas Pitre 			unsigned int received, expected, to_keep;
502*9ad9a52cSNicolas Pitre 
503*9ad9a52cSNicolas Pitre 			received = xfer->data_len - xfer->data_left;
504*9ad9a52cSNicolas Pitre 			expected = RESP_DATA_LENGTH(xfer->response);
505*9ad9a52cSNicolas Pitre 			if (expected > received) {
506*9ad9a52cSNicolas Pitre 				hci_pio_do_trailing_rx(hci, pio,
507*9ad9a52cSNicolas Pitre 						       expected - received);
508*9ad9a52cSNicolas Pitre 			} else if (received > expected) {
509*9ad9a52cSNicolas Pitre 				/* we consumed data meant for next xfer */
510*9ad9a52cSNicolas Pitre 				to_keep = DIV_ROUND_UP(expected, 4);
511*9ad9a52cSNicolas Pitre 				hci_pio_push_to_next_rx(hci, xfer, to_keep);
512*9ad9a52cSNicolas Pitre 			}
513*9ad9a52cSNicolas Pitre 
514*9ad9a52cSNicolas Pitre 			/* then process the RX list pointer */
515*9ad9a52cSNicolas Pitre 			if (hci_pio_process_rx(hci, pio))
516*9ad9a52cSNicolas Pitre 				pio->enabled_irqs &= ~STAT_RX_THLD;
517*9ad9a52cSNicolas Pitre 		}
518*9ad9a52cSNicolas Pitre 
519*9ad9a52cSNicolas Pitre 		/*
520*9ad9a52cSNicolas Pitre 		 * We're about to give back ownership of the xfer structure
521*9ad9a52cSNicolas Pitre 		 * to the waiting instance. Make sure no reference to it
522*9ad9a52cSNicolas Pitre 		 * still exists.
523*9ad9a52cSNicolas Pitre 		 */
524*9ad9a52cSNicolas Pitre 		if (pio->curr_rx == xfer) {
525*9ad9a52cSNicolas Pitre 			DBG("short RX ?");
526*9ad9a52cSNicolas Pitre 			pio->curr_rx = pio->curr_rx->next_data;
527*9ad9a52cSNicolas Pitre 		} else if (pio->curr_tx == xfer) {
528*9ad9a52cSNicolas Pitre 			DBG("short TX ?");
529*9ad9a52cSNicolas Pitre 			pio->curr_tx = pio->curr_tx->next_data;
530*9ad9a52cSNicolas Pitre 		} else if (xfer->data_left) {
531*9ad9a52cSNicolas Pitre 			DBG("PIO xfer count = %d after response",
532*9ad9a52cSNicolas Pitre 			    xfer->data_left);
533*9ad9a52cSNicolas Pitre 		}
534*9ad9a52cSNicolas Pitre 
535*9ad9a52cSNicolas Pitre 		pio->curr_resp = xfer->next_resp;
536*9ad9a52cSNicolas Pitre 		if (xfer->completion)
537*9ad9a52cSNicolas Pitre 			complete(xfer->completion);
538*9ad9a52cSNicolas Pitre 	}
539*9ad9a52cSNicolas Pitre 	return !pio->curr_resp;
540*9ad9a52cSNicolas Pitre }
541*9ad9a52cSNicolas Pitre 
hci_pio_queue_resp(struct i3c_hci * hci,struct hci_pio_data * pio)542*9ad9a52cSNicolas Pitre static void hci_pio_queue_resp(struct i3c_hci *hci, struct hci_pio_data *pio)
543*9ad9a52cSNicolas Pitre {
544*9ad9a52cSNicolas Pitre 	struct hci_xfer *xfer = pio->curr_xfer;
545*9ad9a52cSNicolas Pitre 	struct hci_xfer *prev_queue_tail;
546*9ad9a52cSNicolas Pitre 
547*9ad9a52cSNicolas Pitre 	if (!(xfer->cmd_desc[0] & CMD_0_ROC))
548*9ad9a52cSNicolas Pitre 		return;
549*9ad9a52cSNicolas Pitre 
550*9ad9a52cSNicolas Pitre 	prev_queue_tail = pio->resp_queue;
551*9ad9a52cSNicolas Pitre 	pio->resp_queue = xfer;
552*9ad9a52cSNicolas Pitre 	if (pio->curr_resp) {
553*9ad9a52cSNicolas Pitre 		prev_queue_tail->next_resp = xfer;
554*9ad9a52cSNicolas Pitre 	} else {
555*9ad9a52cSNicolas Pitre 		pio->curr_resp = xfer;
556*9ad9a52cSNicolas Pitre 		if (!hci_pio_process_resp(hci, pio))
557*9ad9a52cSNicolas Pitre 			pio->enabled_irqs |= STAT_RESP_READY;
558*9ad9a52cSNicolas Pitre 	}
559*9ad9a52cSNicolas Pitre }
560*9ad9a52cSNicolas Pitre 
hci_pio_process_cmd(struct i3c_hci * hci,struct hci_pio_data * pio)561*9ad9a52cSNicolas Pitre static bool hci_pio_process_cmd(struct i3c_hci *hci, struct hci_pio_data *pio)
562*9ad9a52cSNicolas Pitre {
563*9ad9a52cSNicolas Pitre 	while (pio->curr_xfer &&
564*9ad9a52cSNicolas Pitre 	       (pio_reg_read(INTR_STATUS) & STAT_CMD_QUEUE_READY)) {
565*9ad9a52cSNicolas Pitre 		/*
566*9ad9a52cSNicolas Pitre 		 * Always process the data FIFO before sending the command
567*9ad9a52cSNicolas Pitre 		 * so needed TX data or RX space is available upfront.
568*9ad9a52cSNicolas Pitre 		 */
569*9ad9a52cSNicolas Pitre 		hci_pio_queue_data(hci, pio);
570*9ad9a52cSNicolas Pitre 		/*
571*9ad9a52cSNicolas Pitre 		 * Then queue our response request. This will also process
572*9ad9a52cSNicolas Pitre 		 * the response FIFO in case it got suddenly filled up
573*9ad9a52cSNicolas Pitre 		 * with results from previous commands.
574*9ad9a52cSNicolas Pitre 		 */
575*9ad9a52cSNicolas Pitre 		hci_pio_queue_resp(hci, pio);
576*9ad9a52cSNicolas Pitre 		/*
577*9ad9a52cSNicolas Pitre 		 * Finally send the command.
578*9ad9a52cSNicolas Pitre 		 */
579*9ad9a52cSNicolas Pitre 		hci_pio_write_cmd(hci, pio->curr_xfer);
580*9ad9a52cSNicolas Pitre 		/*
581*9ad9a52cSNicolas Pitre 		 * And move on.
582*9ad9a52cSNicolas Pitre 		 */
583*9ad9a52cSNicolas Pitre 		pio->curr_xfer = pio->curr_xfer->next_xfer;
584*9ad9a52cSNicolas Pitre 	}
585*9ad9a52cSNicolas Pitre 	return !pio->curr_xfer;
586*9ad9a52cSNicolas Pitre }
587*9ad9a52cSNicolas Pitre 
hci_pio_queue_xfer(struct i3c_hci * hci,struct hci_xfer * xfer,int n)588*9ad9a52cSNicolas Pitre static int hci_pio_queue_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n)
589*9ad9a52cSNicolas Pitre {
590*9ad9a52cSNicolas Pitre 	struct hci_pio_data *pio = hci->io_data;
591*9ad9a52cSNicolas Pitre 	struct hci_xfer *prev_queue_tail;
592*9ad9a52cSNicolas Pitre 	int i;
593*9ad9a52cSNicolas Pitre 
594*9ad9a52cSNicolas Pitre 	DBG("n = %d", n);
595*9ad9a52cSNicolas Pitre 
596*9ad9a52cSNicolas Pitre 	/* link xfer instances together and initialize data count */
597*9ad9a52cSNicolas Pitre 	for (i = 0; i < n; i++) {
598*9ad9a52cSNicolas Pitre 		xfer[i].next_xfer = (i + 1 < n) ? &xfer[i + 1] : NULL;
599*9ad9a52cSNicolas Pitre 		xfer[i].next_data = NULL;
600*9ad9a52cSNicolas Pitre 		xfer[i].next_resp = NULL;
601*9ad9a52cSNicolas Pitre 		xfer[i].data_left = xfer[i].data_len;
602*9ad9a52cSNicolas Pitre 	}
603*9ad9a52cSNicolas Pitre 
604*9ad9a52cSNicolas Pitre 	spin_lock_irq(&pio->lock);
605*9ad9a52cSNicolas Pitre 	prev_queue_tail = pio->xfer_queue;
606*9ad9a52cSNicolas Pitre 	pio->xfer_queue = &xfer[n - 1];
607*9ad9a52cSNicolas Pitre 	if (pio->curr_xfer) {
608*9ad9a52cSNicolas Pitre 		prev_queue_tail->next_xfer = xfer;
609*9ad9a52cSNicolas Pitre 	} else {
610*9ad9a52cSNicolas Pitre 		pio->curr_xfer = xfer;
611*9ad9a52cSNicolas Pitre 		if (!hci_pio_process_cmd(hci, pio))
612*9ad9a52cSNicolas Pitre 			pio->enabled_irqs |= STAT_CMD_QUEUE_READY;
613*9ad9a52cSNicolas Pitre 		pio_reg_write(INTR_SIGNAL_ENABLE, pio->enabled_irqs);
614*9ad9a52cSNicolas Pitre 		DBG("status = %#x/%#x",
615*9ad9a52cSNicolas Pitre 		    pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
616*9ad9a52cSNicolas Pitre 	}
617*9ad9a52cSNicolas Pitre 	spin_unlock_irq(&pio->lock);
618*9ad9a52cSNicolas Pitre 	return 0;
619*9ad9a52cSNicolas Pitre }
620*9ad9a52cSNicolas Pitre 
hci_pio_dequeue_xfer_common(struct i3c_hci * hci,struct hci_pio_data * pio,struct hci_xfer * xfer,int n)621*9ad9a52cSNicolas Pitre static bool hci_pio_dequeue_xfer_common(struct i3c_hci *hci,
622*9ad9a52cSNicolas Pitre 					struct hci_pio_data *pio,
623*9ad9a52cSNicolas Pitre 					struct hci_xfer *xfer, int n)
624*9ad9a52cSNicolas Pitre {
625*9ad9a52cSNicolas Pitre 	struct hci_xfer *p, **p_prev_next;
626*9ad9a52cSNicolas Pitre 	int i;
627*9ad9a52cSNicolas Pitre 
628*9ad9a52cSNicolas Pitre 	/*
629*9ad9a52cSNicolas Pitre 	 * To safely dequeue a transfer request, it must be either entirely
630*9ad9a52cSNicolas Pitre 	 * processed, or not yet processed at all. If our request tail is
631*9ad9a52cSNicolas Pitre 	 * reachable from either the data or resp list that means the command
632*9ad9a52cSNicolas Pitre 	 * was submitted and not yet completed.
633*9ad9a52cSNicolas Pitre 	 */
634*9ad9a52cSNicolas Pitre 	for (p = pio->curr_resp; p; p = p->next_resp)
635*9ad9a52cSNicolas Pitre 		for (i = 0; i < n; i++)
636*9ad9a52cSNicolas Pitre 			if (p == &xfer[i])
637*9ad9a52cSNicolas Pitre 				goto pio_screwed;
638*9ad9a52cSNicolas Pitre 	for (p = pio->curr_rx; p; p = p->next_data)
639*9ad9a52cSNicolas Pitre 		for (i = 0; i < n; i++)
640*9ad9a52cSNicolas Pitre 			if (p == &xfer[i])
641*9ad9a52cSNicolas Pitre 				goto pio_screwed;
642*9ad9a52cSNicolas Pitre 	for (p = pio->curr_tx; p; p = p->next_data)
643*9ad9a52cSNicolas Pitre 		for (i = 0; i < n; i++)
644*9ad9a52cSNicolas Pitre 			if (p == &xfer[i])
645*9ad9a52cSNicolas Pitre 				goto pio_screwed;
646*9ad9a52cSNicolas Pitre 
647*9ad9a52cSNicolas Pitre 	/*
648*9ad9a52cSNicolas Pitre 	 * The command was completed, or wasn't yet submitted.
649*9ad9a52cSNicolas Pitre 	 * Unlink it from the que if the later.
650*9ad9a52cSNicolas Pitre 	 */
651*9ad9a52cSNicolas Pitre 	p_prev_next = &pio->curr_xfer;
652*9ad9a52cSNicolas Pitre 	for (p = pio->curr_xfer; p; p = p->next_xfer) {
653*9ad9a52cSNicolas Pitre 		if (p == &xfer[0]) {
654*9ad9a52cSNicolas Pitre 			*p_prev_next = xfer[n - 1].next_xfer;
655*9ad9a52cSNicolas Pitre 			break;
656*9ad9a52cSNicolas Pitre 		}
657*9ad9a52cSNicolas Pitre 		p_prev_next = &p->next_xfer;
658*9ad9a52cSNicolas Pitre 	}
659*9ad9a52cSNicolas Pitre 
660*9ad9a52cSNicolas Pitre 	/* return true if we actually unqueued something */
661*9ad9a52cSNicolas Pitre 	return !!p;
662*9ad9a52cSNicolas Pitre 
663*9ad9a52cSNicolas Pitre pio_screwed:
664*9ad9a52cSNicolas Pitre 	/*
665*9ad9a52cSNicolas Pitre 	 * Life is tough. We must invalidate the hardware state and
666*9ad9a52cSNicolas Pitre 	 * discard everything that is still queued.
667*9ad9a52cSNicolas Pitre 	 */
668*9ad9a52cSNicolas Pitre 	for (p = pio->curr_resp; p; p = p->next_resp) {
669*9ad9a52cSNicolas Pitre 		p->response = FIELD_PREP(RESP_ERR_FIELD, RESP_ERR_HC_TERMINATED);
670*9ad9a52cSNicolas Pitre 		if (p->completion)
671*9ad9a52cSNicolas Pitre 			complete(p->completion);
672*9ad9a52cSNicolas Pitre 	}
673*9ad9a52cSNicolas Pitre 	for (p = pio->curr_xfer; p; p = p->next_xfer) {
674*9ad9a52cSNicolas Pitre 		p->response = FIELD_PREP(RESP_ERR_FIELD, RESP_ERR_HC_TERMINATED);
675*9ad9a52cSNicolas Pitre 		if (p->completion)
676*9ad9a52cSNicolas Pitre 			complete(p->completion);
677*9ad9a52cSNicolas Pitre 	}
678*9ad9a52cSNicolas Pitre 	pio->curr_xfer = pio->curr_rx = pio->curr_tx = pio->curr_resp = NULL;
679*9ad9a52cSNicolas Pitre 
680*9ad9a52cSNicolas Pitre 	return true;
681*9ad9a52cSNicolas Pitre }
682*9ad9a52cSNicolas Pitre 
hci_pio_dequeue_xfer(struct i3c_hci * hci,struct hci_xfer * xfer,int n)683*9ad9a52cSNicolas Pitre static bool hci_pio_dequeue_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n)
684*9ad9a52cSNicolas Pitre {
685*9ad9a52cSNicolas Pitre 	struct hci_pio_data *pio = hci->io_data;
686*9ad9a52cSNicolas Pitre 	int ret;
687*9ad9a52cSNicolas Pitre 
688*9ad9a52cSNicolas Pitre 	spin_lock_irq(&pio->lock);
689*9ad9a52cSNicolas Pitre 	DBG("n=%d status=%#x/%#x", n,
690*9ad9a52cSNicolas Pitre 	    pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
691*9ad9a52cSNicolas Pitre 	DBG("main_status = %#x/%#x",
692*9ad9a52cSNicolas Pitre 	    readl(hci->base_regs + 0x20), readl(hci->base_regs + 0x28));
693*9ad9a52cSNicolas Pitre 
694*9ad9a52cSNicolas Pitre 	ret = hci_pio_dequeue_xfer_common(hci, pio, xfer, n);
695*9ad9a52cSNicolas Pitre 	spin_unlock_irq(&pio->lock);
696*9ad9a52cSNicolas Pitre 	return ret;
697*9ad9a52cSNicolas Pitre }
698*9ad9a52cSNicolas Pitre 
hci_pio_err(struct i3c_hci * hci,struct hci_pio_data * pio,u32 status)699*9ad9a52cSNicolas Pitre static void hci_pio_err(struct i3c_hci *hci, struct hci_pio_data *pio,
700*9ad9a52cSNicolas Pitre 			u32 status)
701*9ad9a52cSNicolas Pitre {
702*9ad9a52cSNicolas Pitre 	/* TODO: this ought to be more sophisticated eventually */
703*9ad9a52cSNicolas Pitre 
704*9ad9a52cSNicolas Pitre 	if (pio_reg_read(INTR_STATUS) & STAT_RESP_READY) {
705*9ad9a52cSNicolas Pitre 		/* this may happen when an error is signaled with ROC unset */
706*9ad9a52cSNicolas Pitre 		u32 resp = pio_reg_read(RESPONSE_QUEUE_PORT);
707*9ad9a52cSNicolas Pitre 
708*9ad9a52cSNicolas Pitre 		dev_err(&hci->master.dev,
709*9ad9a52cSNicolas Pitre 			"orphan response (%#x) on error\n", resp);
710*9ad9a52cSNicolas Pitre 	}
711*9ad9a52cSNicolas Pitre 
712*9ad9a52cSNicolas Pitre 	/* dump states on programming errors */
713*9ad9a52cSNicolas Pitre 	if (status & STAT_PROG_ERRORS) {
714*9ad9a52cSNicolas Pitre 		u32 queue = pio_reg_read(QUEUE_CUR_STATUS);
715*9ad9a52cSNicolas Pitre 		u32 data = pio_reg_read(DATA_BUFFER_CUR_STATUS);
716*9ad9a52cSNicolas Pitre 
717*9ad9a52cSNicolas Pitre 		dev_err(&hci->master.dev,
718*9ad9a52cSNicolas Pitre 			"prog error %#lx (C/R/I = %ld/%ld/%ld, TX/RX = %ld/%ld)\n",
719*9ad9a52cSNicolas Pitre 			status & STAT_PROG_ERRORS,
720*9ad9a52cSNicolas Pitre 			FIELD_GET(CUR_CMD_Q_EMPTY_LEVEL, queue),
721*9ad9a52cSNicolas Pitre 			FIELD_GET(CUR_RESP_Q_LEVEL, queue),
722*9ad9a52cSNicolas Pitre 			FIELD_GET(CUR_IBI_Q_LEVEL, queue),
723*9ad9a52cSNicolas Pitre 			FIELD_GET(CUR_TX_BUF_LVL, data),
724*9ad9a52cSNicolas Pitre 			FIELD_GET(CUR_RX_BUF_LVL, data));
725*9ad9a52cSNicolas Pitre 	}
726*9ad9a52cSNicolas Pitre 
727*9ad9a52cSNicolas Pitre 	/* just bust out everything with pending responses for now */
728*9ad9a52cSNicolas Pitre 	hci_pio_dequeue_xfer_common(hci, pio, pio->curr_resp, 1);
729*9ad9a52cSNicolas Pitre 	/* ... and half-way TX transfers if any */
730*9ad9a52cSNicolas Pitre 	if (pio->curr_tx && pio->curr_tx->data_left != pio->curr_tx->data_len)
731*9ad9a52cSNicolas Pitre 		hci_pio_dequeue_xfer_common(hci, pio, pio->curr_tx, 1);
732*9ad9a52cSNicolas Pitre 	/* then reset the hardware */
733*9ad9a52cSNicolas Pitre 	mipi_i3c_hci_pio_reset(hci);
734*9ad9a52cSNicolas Pitre 	mipi_i3c_hci_resume(hci);
735*9ad9a52cSNicolas Pitre 
736*9ad9a52cSNicolas Pitre 	DBG("status=%#x/%#x",
737*9ad9a52cSNicolas Pitre 	    pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
738*9ad9a52cSNicolas Pitre }
739*9ad9a52cSNicolas Pitre 
hci_pio_set_ibi_thresh(struct i3c_hci * hci,struct hci_pio_data * pio,unsigned int thresh_val)740*9ad9a52cSNicolas Pitre static void hci_pio_set_ibi_thresh(struct i3c_hci *hci,
741*9ad9a52cSNicolas Pitre 				   struct hci_pio_data *pio,
742*9ad9a52cSNicolas Pitre 				   unsigned int thresh_val)
743*9ad9a52cSNicolas Pitre {
744*9ad9a52cSNicolas Pitre 	u32 regval = pio->reg_queue_thresh;
745*9ad9a52cSNicolas Pitre 
746*9ad9a52cSNicolas Pitre 	regval &= ~QUEUE_IBI_STATUS_THLD;
747*9ad9a52cSNicolas Pitre 	regval |= FIELD_PREP(QUEUE_IBI_STATUS_THLD, thresh_val);
748*9ad9a52cSNicolas Pitre 	/* write the threshold reg only if it changes */
749*9ad9a52cSNicolas Pitre 	if (regval != pio->reg_queue_thresh) {
750*9ad9a52cSNicolas Pitre 		pio_reg_write(QUEUE_THLD_CTRL, regval);
751*9ad9a52cSNicolas Pitre 		pio->reg_queue_thresh = regval;
752*9ad9a52cSNicolas Pitre 		DBG("%d", thresh_val);
753*9ad9a52cSNicolas Pitre 	}
754*9ad9a52cSNicolas Pitre }
755*9ad9a52cSNicolas Pitre 
hci_pio_get_ibi_segment(struct i3c_hci * hci,struct hci_pio_data * pio)756*9ad9a52cSNicolas Pitre static bool hci_pio_get_ibi_segment(struct i3c_hci *hci,
757*9ad9a52cSNicolas Pitre 				    struct hci_pio_data *pio)
758*9ad9a52cSNicolas Pitre {
759*9ad9a52cSNicolas Pitre 	struct hci_pio_ibi_data *ibi = &pio->ibi;
760*9ad9a52cSNicolas Pitre 	unsigned int nr_words, thresh_val;
761*9ad9a52cSNicolas Pitre 	u32 *p;
762*9ad9a52cSNicolas Pitre 
763*9ad9a52cSNicolas Pitre 	p = ibi->data_ptr;
764*9ad9a52cSNicolas Pitre 	p += (ibi->seg_len - ibi->seg_cnt) / 4;
765*9ad9a52cSNicolas Pitre 
766*9ad9a52cSNicolas Pitre 	while ((nr_words = ibi->seg_cnt/4)) {
767*9ad9a52cSNicolas Pitre 		/* determine our IBI queue threshold value */
768*9ad9a52cSNicolas Pitre 		thresh_val = min(nr_words, pio->max_ibi_thresh);
769*9ad9a52cSNicolas Pitre 		hci_pio_set_ibi_thresh(hci, pio, thresh_val);
770*9ad9a52cSNicolas Pitre 		/* bail out if we don't have that amount of data ready */
771*9ad9a52cSNicolas Pitre 		if (!(pio_reg_read(INTR_STATUS) & STAT_IBI_STATUS_THLD))
772*9ad9a52cSNicolas Pitre 			return false;
773*9ad9a52cSNicolas Pitre 		/* extract the data from the IBI port */
774*9ad9a52cSNicolas Pitre 		nr_words = thresh_val;
775*9ad9a52cSNicolas Pitre 		ibi->seg_cnt -= nr_words * 4;
776*9ad9a52cSNicolas Pitre 		DBG("now %d left %d", nr_words * 4, ibi->seg_cnt);
777*9ad9a52cSNicolas Pitre 		while (nr_words--)
778*9ad9a52cSNicolas Pitre 			*p++ = pio_reg_read(IBI_PORT);
779*9ad9a52cSNicolas Pitre 	}
780*9ad9a52cSNicolas Pitre 
781*9ad9a52cSNicolas Pitre 	if (ibi->seg_cnt) {
782*9ad9a52cSNicolas Pitre 		/*
783*9ad9a52cSNicolas Pitre 		 * There are trailing bytes in the last word.
784*9ad9a52cSNicolas Pitre 		 * Fetch it and extract bytes in an endian independent way.
785*9ad9a52cSNicolas Pitre 		 * Unlike the TX case, we must not write past the end of
786*9ad9a52cSNicolas Pitre 		 * the destination buffer.
787*9ad9a52cSNicolas Pitre 		 */
788*9ad9a52cSNicolas Pitre 		u32 data;
789*9ad9a52cSNicolas Pitre 		u8 *p_byte = (u8 *)p;
790*9ad9a52cSNicolas Pitre 
791*9ad9a52cSNicolas Pitre 		hci_pio_set_ibi_thresh(hci, pio, 1);
792*9ad9a52cSNicolas Pitre 		if (!(pio_reg_read(INTR_STATUS) & STAT_IBI_STATUS_THLD))
793*9ad9a52cSNicolas Pitre 			return false;
794*9ad9a52cSNicolas Pitre 		DBG("trailing %d", ibi->seg_cnt);
795*9ad9a52cSNicolas Pitre 		data = pio_reg_read(IBI_PORT);
796*9ad9a52cSNicolas Pitre 		data = (__force u32) cpu_to_le32(data);
797*9ad9a52cSNicolas Pitre 		while (ibi->seg_cnt--) {
798*9ad9a52cSNicolas Pitre 			*p_byte++ = data;
799*9ad9a52cSNicolas Pitre 			data >>= 8;
800*9ad9a52cSNicolas Pitre 		}
801*9ad9a52cSNicolas Pitre 	}
802*9ad9a52cSNicolas Pitre 
803*9ad9a52cSNicolas Pitre 	return true;
804*9ad9a52cSNicolas Pitre }
805*9ad9a52cSNicolas Pitre 
hci_pio_prep_new_ibi(struct i3c_hci * hci,struct hci_pio_data * pio)806*9ad9a52cSNicolas Pitre static bool hci_pio_prep_new_ibi(struct i3c_hci *hci, struct hci_pio_data *pio)
807*9ad9a52cSNicolas Pitre {
808*9ad9a52cSNicolas Pitre 	struct hci_pio_ibi_data *ibi = &pio->ibi;
809*9ad9a52cSNicolas Pitre 	struct i3c_dev_desc *dev;
810*9ad9a52cSNicolas Pitre 	struct i3c_hci_dev_data *dev_data;
811*9ad9a52cSNicolas Pitre 	struct hci_pio_dev_ibi_data *dev_ibi;
812*9ad9a52cSNicolas Pitre 	u32 ibi_status;
813*9ad9a52cSNicolas Pitre 
814*9ad9a52cSNicolas Pitre 	/*
815*9ad9a52cSNicolas Pitre 	 * We have a new IBI. Try to set up its payload retrieval.
816*9ad9a52cSNicolas Pitre 	 * When returning true, the IBI data has to be consumed whether
817*9ad9a52cSNicolas Pitre 	 * or not we are set up to capture it. If we return true with
818*9ad9a52cSNicolas Pitre 	 * ibi->slot == NULL that means the data payload has to be
819*9ad9a52cSNicolas Pitre 	 * drained out of the IBI port and dropped.
820*9ad9a52cSNicolas Pitre 	 */
821*9ad9a52cSNicolas Pitre 
822*9ad9a52cSNicolas Pitre 	ibi_status = pio_reg_read(IBI_PORT);
823*9ad9a52cSNicolas Pitre 	DBG("status = %#x", ibi_status);
824*9ad9a52cSNicolas Pitre 	ibi->addr = FIELD_GET(IBI_TARGET_ADDR, ibi_status);
825*9ad9a52cSNicolas Pitre 	if (ibi_status & IBI_ERROR) {
826*9ad9a52cSNicolas Pitre 		dev_err(&hci->master.dev, "IBI error from %#x\n", ibi->addr);
827*9ad9a52cSNicolas Pitre 		return false;
828*9ad9a52cSNicolas Pitre 	}
829*9ad9a52cSNicolas Pitre 
830*9ad9a52cSNicolas Pitre 	ibi->last_seg = ibi_status & IBI_LAST_STATUS;
831*9ad9a52cSNicolas Pitre 	ibi->seg_len = FIELD_GET(IBI_DATA_LENGTH, ibi_status);
832*9ad9a52cSNicolas Pitre 	ibi->seg_cnt = ibi->seg_len;
833*9ad9a52cSNicolas Pitre 
834*9ad9a52cSNicolas Pitre 	dev = i3c_hci_addr_to_dev(hci, ibi->addr);
835*9ad9a52cSNicolas Pitre 	if (!dev) {
836*9ad9a52cSNicolas Pitre 		dev_err(&hci->master.dev,
837*9ad9a52cSNicolas Pitre 			"IBI for unknown device %#x\n", ibi->addr);
838*9ad9a52cSNicolas Pitre 		return true;
839*9ad9a52cSNicolas Pitre 	}
840*9ad9a52cSNicolas Pitre 
841*9ad9a52cSNicolas Pitre 	dev_data = i3c_dev_get_master_data(dev);
842*9ad9a52cSNicolas Pitre 	dev_ibi = dev_data->ibi_data;
843*9ad9a52cSNicolas Pitre 	ibi->max_len = dev_ibi->max_len;
844*9ad9a52cSNicolas Pitre 
845*9ad9a52cSNicolas Pitre 	if (ibi->seg_len > ibi->max_len) {
846*9ad9a52cSNicolas Pitre 		dev_err(&hci->master.dev, "IBI payload too big (%d > %d)\n",
847*9ad9a52cSNicolas Pitre 			ibi->seg_len, ibi->max_len);
848*9ad9a52cSNicolas Pitre 		return true;
849*9ad9a52cSNicolas Pitre 	}
850*9ad9a52cSNicolas Pitre 
851*9ad9a52cSNicolas Pitre 	ibi->slot = i3c_generic_ibi_get_free_slot(dev_ibi->pool);
852*9ad9a52cSNicolas Pitre 	if (!ibi->slot) {
853*9ad9a52cSNicolas Pitre 		dev_err(&hci->master.dev, "no free slot for IBI\n");
854*9ad9a52cSNicolas Pitre 	} else {
855*9ad9a52cSNicolas Pitre 		ibi->slot->len = 0;
856*9ad9a52cSNicolas Pitre 		ibi->data_ptr = ibi->slot->data;
857*9ad9a52cSNicolas Pitre 	}
858*9ad9a52cSNicolas Pitre 	return true;
859*9ad9a52cSNicolas Pitre }
860*9ad9a52cSNicolas Pitre 
hci_pio_free_ibi_slot(struct i3c_hci * hci,struct hci_pio_data * pio)861*9ad9a52cSNicolas Pitre static void hci_pio_free_ibi_slot(struct i3c_hci *hci, struct hci_pio_data *pio)
862*9ad9a52cSNicolas Pitre {
863*9ad9a52cSNicolas Pitre 	struct hci_pio_ibi_data *ibi = &pio->ibi;
864*9ad9a52cSNicolas Pitre 	struct hci_pio_dev_ibi_data *dev_ibi;
865*9ad9a52cSNicolas Pitre 
866*9ad9a52cSNicolas Pitre 	if (ibi->slot) {
867*9ad9a52cSNicolas Pitre 		dev_ibi = ibi->slot->dev->common.master_priv;
868*9ad9a52cSNicolas Pitre 		i3c_generic_ibi_recycle_slot(dev_ibi->pool, ibi->slot);
869*9ad9a52cSNicolas Pitre 		ibi->slot = NULL;
870*9ad9a52cSNicolas Pitre 	}
871*9ad9a52cSNicolas Pitre }
872*9ad9a52cSNicolas Pitre 
hci_pio_process_ibi(struct i3c_hci * hci,struct hci_pio_data * pio)873*9ad9a52cSNicolas Pitre static bool hci_pio_process_ibi(struct i3c_hci *hci, struct hci_pio_data *pio)
874*9ad9a52cSNicolas Pitre {
875*9ad9a52cSNicolas Pitre 	struct hci_pio_ibi_data *ibi = &pio->ibi;
876*9ad9a52cSNicolas Pitre 
877*9ad9a52cSNicolas Pitre 	if (!ibi->slot && !ibi->seg_cnt && ibi->last_seg)
878*9ad9a52cSNicolas Pitre 		if (!hci_pio_prep_new_ibi(hci, pio))
879*9ad9a52cSNicolas Pitre 			return false;
880*9ad9a52cSNicolas Pitre 
881*9ad9a52cSNicolas Pitre 	for (;;) {
882*9ad9a52cSNicolas Pitre 		u32 ibi_status;
883*9ad9a52cSNicolas Pitre 		unsigned int ibi_addr;
884*9ad9a52cSNicolas Pitre 
885*9ad9a52cSNicolas Pitre 		if (ibi->slot) {
886*9ad9a52cSNicolas Pitre 			if (!hci_pio_get_ibi_segment(hci, pio))
887*9ad9a52cSNicolas Pitre 				return false;
888*9ad9a52cSNicolas Pitre 			ibi->slot->len += ibi->seg_len;
889*9ad9a52cSNicolas Pitre 			ibi->data_ptr += ibi->seg_len;
890*9ad9a52cSNicolas Pitre 			if (ibi->last_seg) {
891*9ad9a52cSNicolas Pitre 				/* was the last segment: submit it and leave */
892*9ad9a52cSNicolas Pitre 				i3c_master_queue_ibi(ibi->slot->dev, ibi->slot);
893*9ad9a52cSNicolas Pitre 				ibi->slot = NULL;
894*9ad9a52cSNicolas Pitre 				hci_pio_set_ibi_thresh(hci, pio, 1);
895*9ad9a52cSNicolas Pitre 				return true;
896*9ad9a52cSNicolas Pitre 			}
897*9ad9a52cSNicolas Pitre 		} else if (ibi->seg_cnt) {
898*9ad9a52cSNicolas Pitre 			/*
899*9ad9a52cSNicolas Pitre 			 * No slot but a non-zero count. This is the result
900*9ad9a52cSNicolas Pitre 			 * of some error and the payload must be drained.
901*9ad9a52cSNicolas Pitre 			 * This normally does not happen therefore no need
902*9ad9a52cSNicolas Pitre 			 * to be extra optimized here.
903*9ad9a52cSNicolas Pitre 			 */
904*9ad9a52cSNicolas Pitre 			hci_pio_set_ibi_thresh(hci, pio, 1);
905*9ad9a52cSNicolas Pitre 			do {
906*9ad9a52cSNicolas Pitre 				if (!(pio_reg_read(INTR_STATUS) & STAT_IBI_STATUS_THLD))
907*9ad9a52cSNicolas Pitre 					return false;
908*9ad9a52cSNicolas Pitre 				pio_reg_read(IBI_PORT);
909*9ad9a52cSNicolas Pitre 			} while (--ibi->seg_cnt);
910*9ad9a52cSNicolas Pitre 			if (ibi->last_seg)
911*9ad9a52cSNicolas Pitre 				return true;
912*9ad9a52cSNicolas Pitre 		}
913*9ad9a52cSNicolas Pitre 
914*9ad9a52cSNicolas Pitre 		/* try to move to the next segment right away */
915*9ad9a52cSNicolas Pitre 		hci_pio_set_ibi_thresh(hci, pio, 1);
916*9ad9a52cSNicolas Pitre 		if (!(pio_reg_read(INTR_STATUS) & STAT_IBI_STATUS_THLD))
917*9ad9a52cSNicolas Pitre 			return false;
918*9ad9a52cSNicolas Pitre 		ibi_status = pio_reg_read(IBI_PORT);
919*9ad9a52cSNicolas Pitre 		ibi_addr = FIELD_GET(IBI_TARGET_ADDR, ibi_status);
920*9ad9a52cSNicolas Pitre 		if (ibi->addr != ibi_addr) {
921*9ad9a52cSNicolas Pitre 			/* target address changed before last segment */
922*9ad9a52cSNicolas Pitre 			dev_err(&hci->master.dev,
923*9ad9a52cSNicolas Pitre 				"unexp IBI address changed from %d to %d\n",
924*9ad9a52cSNicolas Pitre 				ibi->addr, ibi_addr);
925*9ad9a52cSNicolas Pitre 			hci_pio_free_ibi_slot(hci, pio);
926*9ad9a52cSNicolas Pitre 		}
927*9ad9a52cSNicolas Pitre 		ibi->last_seg = ibi_status & IBI_LAST_STATUS;
928*9ad9a52cSNicolas Pitre 		ibi->seg_len = FIELD_GET(IBI_DATA_LENGTH, ibi_status);
929*9ad9a52cSNicolas Pitre 		ibi->seg_cnt = ibi->seg_len;
930*9ad9a52cSNicolas Pitre 		if (ibi->slot && ibi->slot->len + ibi->seg_len > ibi->max_len) {
931*9ad9a52cSNicolas Pitre 			dev_err(&hci->master.dev,
932*9ad9a52cSNicolas Pitre 				"IBI payload too big (%d > %d)\n",
933*9ad9a52cSNicolas Pitre 				ibi->slot->len + ibi->seg_len, ibi->max_len);
934*9ad9a52cSNicolas Pitre 			hci_pio_free_ibi_slot(hci, pio);
935*9ad9a52cSNicolas Pitre 		}
936*9ad9a52cSNicolas Pitre 	}
937*9ad9a52cSNicolas Pitre 
938*9ad9a52cSNicolas Pitre 	return false;
939*9ad9a52cSNicolas Pitre }
940*9ad9a52cSNicolas Pitre 
hci_pio_request_ibi(struct i3c_hci * hci,struct i3c_dev_desc * dev,const struct i3c_ibi_setup * req)941*9ad9a52cSNicolas Pitre static int hci_pio_request_ibi(struct i3c_hci *hci, struct i3c_dev_desc *dev,
942*9ad9a52cSNicolas Pitre 			       const struct i3c_ibi_setup *req)
943*9ad9a52cSNicolas Pitre {
944*9ad9a52cSNicolas Pitre 	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
945*9ad9a52cSNicolas Pitre 	struct i3c_generic_ibi_pool *pool;
946*9ad9a52cSNicolas Pitre 	struct hci_pio_dev_ibi_data *dev_ibi;
947*9ad9a52cSNicolas Pitre 
948*9ad9a52cSNicolas Pitre 	dev_ibi = kmalloc(sizeof(*dev_ibi), GFP_KERNEL);
949*9ad9a52cSNicolas Pitre 	if (!dev_ibi)
950*9ad9a52cSNicolas Pitre 		return -ENOMEM;
951*9ad9a52cSNicolas Pitre 	pool = i3c_generic_ibi_alloc_pool(dev, req);
952*9ad9a52cSNicolas Pitre 	if (IS_ERR(pool)) {
953*9ad9a52cSNicolas Pitre 		kfree(dev_ibi);
954*9ad9a52cSNicolas Pitre 		return PTR_ERR(pool);
955*9ad9a52cSNicolas Pitre 	}
956*9ad9a52cSNicolas Pitre 	dev_ibi->pool = pool;
957*9ad9a52cSNicolas Pitre 	dev_ibi->max_len = req->max_payload_len;
958*9ad9a52cSNicolas Pitre 	dev_data->ibi_data = dev_ibi;
959*9ad9a52cSNicolas Pitre 	return 0;
960*9ad9a52cSNicolas Pitre }
961*9ad9a52cSNicolas Pitre 
hci_pio_free_ibi(struct i3c_hci * hci,struct i3c_dev_desc * dev)962*9ad9a52cSNicolas Pitre static void hci_pio_free_ibi(struct i3c_hci *hci, struct i3c_dev_desc *dev)
963*9ad9a52cSNicolas Pitre {
964*9ad9a52cSNicolas Pitre 	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
965*9ad9a52cSNicolas Pitre 	struct hci_pio_dev_ibi_data *dev_ibi = dev_data->ibi_data;
966*9ad9a52cSNicolas Pitre 
967*9ad9a52cSNicolas Pitre 	dev_data->ibi_data = NULL;
968*9ad9a52cSNicolas Pitre 	i3c_generic_ibi_free_pool(dev_ibi->pool);
969*9ad9a52cSNicolas Pitre 	kfree(dev_ibi);
970*9ad9a52cSNicolas Pitre }
971*9ad9a52cSNicolas Pitre 
hci_pio_recycle_ibi_slot(struct i3c_hci * hci,struct i3c_dev_desc * dev,struct i3c_ibi_slot * slot)972*9ad9a52cSNicolas Pitre static void hci_pio_recycle_ibi_slot(struct i3c_hci *hci,
973*9ad9a52cSNicolas Pitre 				    struct i3c_dev_desc *dev,
974*9ad9a52cSNicolas Pitre 				    struct i3c_ibi_slot *slot)
975*9ad9a52cSNicolas Pitre {
976*9ad9a52cSNicolas Pitre 	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
977*9ad9a52cSNicolas Pitre 	struct hci_pio_dev_ibi_data *dev_ibi = dev_data->ibi_data;
978*9ad9a52cSNicolas Pitre 
979*9ad9a52cSNicolas Pitre 	i3c_generic_ibi_recycle_slot(dev_ibi->pool, slot);
980*9ad9a52cSNicolas Pitre }
981*9ad9a52cSNicolas Pitre 
hci_pio_irq_handler(struct i3c_hci * hci,unsigned int unused)982*9ad9a52cSNicolas Pitre static bool hci_pio_irq_handler(struct i3c_hci *hci, unsigned int unused)
983*9ad9a52cSNicolas Pitre {
984*9ad9a52cSNicolas Pitre 	struct hci_pio_data *pio = hci->io_data;
985*9ad9a52cSNicolas Pitre 	u32 status;
986*9ad9a52cSNicolas Pitre 
987*9ad9a52cSNicolas Pitre 	spin_lock(&pio->lock);
988*9ad9a52cSNicolas Pitre 	status = pio_reg_read(INTR_STATUS);
989*9ad9a52cSNicolas Pitre 	DBG("(in) status: %#x/%#x", status, pio->enabled_irqs);
990*9ad9a52cSNicolas Pitre 	status &= pio->enabled_irqs | STAT_LATENCY_WARNINGS;
991*9ad9a52cSNicolas Pitre 	if (!status) {
992*9ad9a52cSNicolas Pitre 		spin_unlock(&pio->lock);
993*9ad9a52cSNicolas Pitre 		return false;
994*9ad9a52cSNicolas Pitre 	}
995*9ad9a52cSNicolas Pitre 
996*9ad9a52cSNicolas Pitre 	if (status & STAT_IBI_STATUS_THLD)
997*9ad9a52cSNicolas Pitre 		hci_pio_process_ibi(hci, pio);
998*9ad9a52cSNicolas Pitre 
999*9ad9a52cSNicolas Pitre 	if (status & STAT_RX_THLD)
1000*9ad9a52cSNicolas Pitre 		if (hci_pio_process_rx(hci, pio))
1001*9ad9a52cSNicolas Pitre 			pio->enabled_irqs &= ~STAT_RX_THLD;
1002*9ad9a52cSNicolas Pitre 	if (status & STAT_TX_THLD)
1003*9ad9a52cSNicolas Pitre 		if (hci_pio_process_tx(hci, pio))
1004*9ad9a52cSNicolas Pitre 			pio->enabled_irqs &= ~STAT_TX_THLD;
1005*9ad9a52cSNicolas Pitre 	if (status & STAT_RESP_READY)
1006*9ad9a52cSNicolas Pitre 		if (hci_pio_process_resp(hci, pio))
1007*9ad9a52cSNicolas Pitre 			pio->enabled_irqs &= ~STAT_RESP_READY;
1008*9ad9a52cSNicolas Pitre 
1009*9ad9a52cSNicolas Pitre 	if (unlikely(status & STAT_LATENCY_WARNINGS)) {
1010*9ad9a52cSNicolas Pitre 		pio_reg_write(INTR_STATUS, status & STAT_LATENCY_WARNINGS);
1011*9ad9a52cSNicolas Pitre 		dev_warn_ratelimited(&hci->master.dev,
1012*9ad9a52cSNicolas Pitre 				     "encountered warning condition %#lx\n",
1013*9ad9a52cSNicolas Pitre 				     status & STAT_LATENCY_WARNINGS);
1014*9ad9a52cSNicolas Pitre 	}
1015*9ad9a52cSNicolas Pitre 
1016*9ad9a52cSNicolas Pitre 	if (unlikely(status & STAT_ALL_ERRORS)) {
1017*9ad9a52cSNicolas Pitre 		pio_reg_write(INTR_STATUS, status & STAT_ALL_ERRORS);
1018*9ad9a52cSNicolas Pitre 		hci_pio_err(hci, pio, status & STAT_ALL_ERRORS);
1019*9ad9a52cSNicolas Pitre 	}
1020*9ad9a52cSNicolas Pitre 
1021*9ad9a52cSNicolas Pitre 	if (status & STAT_CMD_QUEUE_READY)
1022*9ad9a52cSNicolas Pitre 		if (hci_pio_process_cmd(hci, pio))
1023*9ad9a52cSNicolas Pitre 			pio->enabled_irqs &= ~STAT_CMD_QUEUE_READY;
1024*9ad9a52cSNicolas Pitre 
1025*9ad9a52cSNicolas Pitre 	pio_reg_write(INTR_SIGNAL_ENABLE, pio->enabled_irqs);
1026*9ad9a52cSNicolas Pitre 	DBG("(out) status: %#x/%#x",
1027*9ad9a52cSNicolas Pitre 	    pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
1028*9ad9a52cSNicolas Pitre 	spin_unlock(&pio->lock);
1029*9ad9a52cSNicolas Pitre 	return true;
1030*9ad9a52cSNicolas Pitre }
1031*9ad9a52cSNicolas Pitre 
1032*9ad9a52cSNicolas Pitre const struct hci_io_ops mipi_i3c_hci_pio = {
1033*9ad9a52cSNicolas Pitre 	.init			= hci_pio_init,
1034*9ad9a52cSNicolas Pitre 	.cleanup		= hci_pio_cleanup,
1035*9ad9a52cSNicolas Pitre 	.queue_xfer		= hci_pio_queue_xfer,
1036*9ad9a52cSNicolas Pitre 	.dequeue_xfer		= hci_pio_dequeue_xfer,
1037*9ad9a52cSNicolas Pitre 	.irq_handler		= hci_pio_irq_handler,
1038*9ad9a52cSNicolas Pitre 	.request_ibi		= hci_pio_request_ibi,
1039*9ad9a52cSNicolas Pitre 	.free_ibi		= hci_pio_free_ibi,
1040*9ad9a52cSNicolas Pitre 	.recycle_ibi_slot	= hci_pio_recycle_ibi_slot,
1041*9ad9a52cSNicolas Pitre };
1042