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(®s->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(®s->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, ®s->geni_tx_fifon,
47 0, BYTES_PER_FIFO_WORD);
48
49 if (tx_rem_bytes == max_bytes)
50 write32(®s->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(®s->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, ®s->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(®s->geni_tx_watermark_reg, 0);
75 write32(®s->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(®s->geni_m_irq_clear, m_irq);
82 break;
83 }
84 write32(®s->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(®s->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(®s->geni_m_irq_clear, m_irq);
97 break;
98 }
99 write32(®s->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(®s->geni_tx_watermark_reg, 0);
116 write32(®s->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(®s->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(®s->geni_s_irq_clear, s_irq);
127 break;
128 }
129 write32(®s->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(®s->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(®s->geni_s_irq_clear, s_irq);
142 break;
143 }
144 write32(®s->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(®s->geni_m_irq_clear, m_irq);
171 break;
172 }
173 write32(®s->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