xref: /aosp_15_r20/external/coreboot/src/soc/qualcomm/common/qup_se_handler.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <soc/qup_se_handlers_common.h>
5 #include <soc/qcom_qup_se.h>
6 
qup_wait_for_m_irq(unsigned int bus)7 u32 qup_wait_for_m_irq(unsigned int bus)
8 {
9 	struct stopwatch sw;
10 	unsigned int m_irq = 0;
11 	struct qup_regs *regs = qup[bus].regs;
12 
13 	stopwatch_init_usecs_expire(&sw, 25);
14 	while (!stopwatch_expired(&sw)) {
15 		m_irq = read32(&regs->geni_m_irq_status);
16 		if (m_irq)
17 			break;
18 	}
19 	return m_irq;
20 }
21 
qup_wait_for_s_irq(unsigned int bus)22 u32 qup_wait_for_s_irq(unsigned int bus)
23 {
24 	struct stopwatch sw;
25 	unsigned int s_irq = 0;
26 	struct qup_regs *regs = qup[bus].regs;
27 
28 	stopwatch_init_usecs_expire(&sw, 25);
29 	while (!stopwatch_expired(&sw)) {
30 		s_irq = read32(&regs->geni_s_irq_status);
31 		if (s_irq)
32 			break;
33 	}
34 	return s_irq;
35 }
36 
handle_tx(unsigned int bus,const u8 * dout,unsigned int tx_rem_bytes)37 static int handle_tx(unsigned int bus, const u8 *dout,
38 	unsigned int tx_rem_bytes)
39 {
40 	int max_bytes = 0;
41 	struct qup_regs *regs = qup[bus].regs;
42 
43 	max_bytes = (FIFO_DEPTH - TX_WATERMARK) * BYTES_PER_FIFO_WORD;
44 	max_bytes = MIN(tx_rem_bytes, max_bytes);
45 
46 	buffer_to_fifo32((void *)dout, max_bytes, &regs->geni_tx_fifon,
47 					0, BYTES_PER_FIFO_WORD);
48 
49 	if (tx_rem_bytes == max_bytes)
50 		write32(&regs->geni_tx_watermark_reg, 0);
51 	return max_bytes;
52 }
53 
handle_rx(unsigned int bus,u8 * din,unsigned int rx_rem_bytes)54 static int handle_rx(unsigned int bus, u8 *din, unsigned int rx_rem_bytes)
55 {
56 	struct qup_regs *regs = qup[bus].regs;
57 	u32 rx_fifo_status = read32(&regs->geni_rx_fifo_status);
58 	int rx_bytes = 0;
59 
60 	rx_bytes = (rx_fifo_status & RX_FIFO_WC_MSK) * BYTES_PER_FIFO_WORD;
61 	rx_bytes = MIN(rx_rem_bytes, rx_bytes);
62 
63 	buffer_from_fifo32(din, rx_bytes, &regs->geni_rx_fifon,
64 					0, BYTES_PER_FIFO_WORD);
65 	return rx_bytes;
66 }
67 
qup_m_cancel_and_abort(unsigned int bus)68 void qup_m_cancel_and_abort(unsigned int bus)
69 {
70 	struct qup_regs *regs = qup[bus].regs;
71 	struct stopwatch sw;
72 	unsigned int m_irq;
73 
74 	write32(&regs->geni_tx_watermark_reg, 0);
75 	write32(&regs->geni_m_cmd_ctrl_reg, M_GENI_CMD_CANCEL);
76 
77 	stopwatch_init_msecs_expire(&sw, 100);
78 	do {
79 		m_irq = qup_wait_for_m_irq(bus);
80 		if (m_irq & M_CMD_CANCEL_EN) {
81 			write32(&regs->geni_m_irq_clear, m_irq);
82 			break;
83 		}
84 		write32(&regs->geni_m_irq_clear, m_irq);
85 	} while (!stopwatch_expired(&sw));
86 
87 	if (!(m_irq & M_CMD_CANCEL_EN)) {
88 		printk(BIOS_INFO, "%s:Cancel failed, Abort the operation\n",
89 								__func__);
90 
91 		write32(&regs->geni_m_cmd_ctrl_reg, M_GENI_CMD_ABORT);
92 		stopwatch_init_msecs_expire(&sw, 100);
93 		do {
94 			m_irq = qup_wait_for_m_irq(bus);
95 			if (m_irq & M_CMD_ABORT_EN) {
96 				write32(&regs->geni_m_irq_clear, m_irq);
97 				break;
98 			}
99 			write32(&regs->geni_m_irq_clear, m_irq);
100 		} while (!stopwatch_expired(&sw));
101 
102 		if (!(m_irq & M_CMD_ABORT_EN))
103 			printk(BIOS_INFO, "%s:Abort failed\n", __func__);
104 	}
105 }
106 
qup_s_cancel_and_abort(unsigned int bus)107 void qup_s_cancel_and_abort(unsigned int bus)
108 {
109 	struct qup_regs *regs = qup[bus].regs;
110 	struct stopwatch sw;
111 	unsigned int s_irq;
112 	u32 rx_fifo_status;
113 	u8 buf[64]; /* FIFO size */
114 
115 	write32(&regs->geni_tx_watermark_reg, 0);
116 	write32(&regs->geni_s_cmd_ctrl_reg, S_GENI_CMD_CANCEL);
117 
118 	stopwatch_init_msecs_expire(&sw, 100);
119 	do {
120 		s_irq = qup_wait_for_s_irq(bus);
121 		rx_fifo_status  = read32(&regs->geni_rx_fifo_status);
122 		if (rx_fifo_status & RX_LAST)
123 			/* Read whatever data available in FIFO */
124 			handle_rx(bus, buf, 64);
125 		if (s_irq & S_CMD_CANCEL_EN) {
126 			write32(&regs->geni_s_irq_clear, s_irq);
127 			break;
128 		}
129 		write32(&regs->geni_s_irq_clear, s_irq);
130 	} while (!stopwatch_expired(&sw));
131 
132 	if (!(s_irq & S_CMD_CANCEL_EN)) {
133 		printk(BIOS_INFO, "%s:Cancel failed, Abort the operation\n",
134 								__func__);
135 
136 		write32(&regs->geni_s_cmd_ctrl_reg, S_GENI_CMD_ABORT);
137 		stopwatch_init_msecs_expire(&sw, 100);
138 		do {
139 			s_irq = qup_wait_for_s_irq(bus);
140 			if (s_irq & S_CMD_ABORT_EN) {
141 				write32(&regs->geni_s_irq_clear, s_irq);
142 				break;
143 			}
144 			write32(&regs->geni_s_irq_clear, s_irq);
145 		} while (!stopwatch_expired(&sw));
146 
147 		if (!(s_irq & S_CMD_ABORT_EN))
148 			printk(BIOS_INFO, "%s:Abort failed\n", __func__);
149 	}
150 }
151 
qup_handle_transfer(unsigned int bus,const void * dout,void * din,int size,struct stopwatch * timeout)152 int qup_handle_transfer(unsigned int bus, const void *dout, void *din, int size,
153 			struct stopwatch *timeout)
154 {
155 	unsigned int m_irq;
156 	unsigned int rx_rem_bytes = din ? size : 0;
157 	unsigned int tx_rem_bytes = dout ? size : 0;
158 	struct qup_regs *regs = qup[bus].regs;
159 
160 	do {
161 		m_irq = qup_wait_for_m_irq(bus);
162 		if ((m_irq & M_RX_FIFO_WATERMARK_EN) ||
163 					(m_irq & M_RX_FIFO_LAST_EN))
164 			rx_rem_bytes -= handle_rx(bus, din + size
165 						- rx_rem_bytes, rx_rem_bytes);
166 		if (m_irq & M_TX_FIFO_WATERMARK_EN)
167 			tx_rem_bytes -= handle_tx(bus, dout + size
168 						- tx_rem_bytes, tx_rem_bytes);
169 		if (m_irq & M_CMD_DONE_EN) {
170 			write32(&regs->geni_m_irq_clear, m_irq);
171 			break;
172 		}
173 		write32(&regs->geni_m_irq_clear, m_irq);
174 	} while (!stopwatch_expired(timeout));
175 
176 	if (!(m_irq & M_CMD_DONE_EN) || tx_rem_bytes || rx_rem_bytes) {
177 		printk(BIOS_INFO, "%s:Error: Transfer failed\n", __func__);
178 		qup_m_cancel_and_abort(bus);
179 		return -1;
180 	}
181 	return 0;
182 }
183