1 /*
2 * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stddef.h>
7 #include <stdint.h>
8
9 #include <device_mec5.h>
10 #include "mec_pcfg.h"
11 #include "mec_defs.h"
12 #include "mec_ecia_api.h"
13 #include "mec_espi_api.h"
14 #include "mec_pcr_api.h"
15 #include "mec_retval.h"
16
17 /* ---- eSPI Out-Of-Band (OOB) Channel ---- */
18 #define MEC5_ESPI_GIRQ 19
19 #define MEC5_ESPI_GIRQ_AGGR_NVIC 11
20 #define MEC5_ESPI_OOB_UP_GIRQ_POS 4
21 #define MEC5_ESPI_OOB_UP_NVIC_DIRECT 107
22 #define MEC5_ESPI_OOB_DN_GIRQ_POS 5
23 #define MEC5_ESPI_OOB_DN_NVIC_DIRECT 108
24
25 #define MEC_ESPI_OOB_UP_ECIA_INFO MEC5_ECIA_INFO(MEC5_ESPI_GIRQ, MEC5_ESPI_OOB_UP_GIRQ_POS, \
26 MEC5_ESPI_GIRQ_AGGR_NVIC, \
27 MEC5_ESPI_OOB_UP_NVIC_DIRECT)
28 #define MEC_ESPI_OOB_DN_ECIA_INFO MEC5_ECIA_INFO(MEC5_ESPI_GIRQ, MEC5_ESPI_OOB_DN_GIRQ_POS, \
29 MEC5_ESPI_GIRQ_AGGR_NVIC, \
30 MEC5_ESPI_OOB_DN_NVIC_DIRECT)
31
32 #define MEC_ESPI_OOB_TX_STS_RW1C \
33 (MEC_ESPI_IO_OOBTXSTS_DONE_Msk | MEC_ESPI_IO_OOBTXSTS_CHEN_CHG_Msk \
34 | MEC_ESPI_IO_OOBTXSTS_EC_BUS_ERR_Msk | MEC_ESPI_IO_OOBTXSTS_START_OVRUN_Msk \
35 | MEC_ESPI_IO_OOBTXSTS_BAD_REQ_Msk)
36
37 #define MEC_ESPI_OOB_RX_STS_RW1C \
38 (MEC_ESPI_IO_OOBRXSTS_DONE_Msk | MEC_ESPI_IO_OOBRXSTS_EC_BUS_ERR_Msk \
39 | MEC_ESPI_IO_OOBRXSTS_DATA_OVRUN_Msk)
40
41
msk_to_girq_bitmap(uint8_t msk)42 static uint32_t msk_to_girq_bitmap(uint8_t msk)
43 {
44 uint32_t bitmap = 0;
45
46 if (msk & MEC_ESPI_OOB_DIR_UP) {
47 bitmap |= MEC_BIT(MEC5_ESPI_OOB_UP_GIRQ_POS);
48 }
49 if (msk & MEC_ESPI_OOB_DIR_DN) {
50 bitmap |= MEC_BIT(MEC5_ESPI_OOB_DN_GIRQ_POS);
51 }
52
53 return bitmap;
54 }
55
bitmap_to_msk(uint32_t bitmap)56 static uint32_t bitmap_to_msk(uint32_t bitmap)
57 {
58 uint32_t msk = 0;
59
60 if (bitmap & MEC_BIT(MEC5_ESPI_OOB_UP_GIRQ_POS)) {
61 msk |= MEC_ESPI_OOB_DIR_UP;
62 }
63 if (bitmap & MEC_BIT(MEC5_ESPI_OOB_DN_GIRQ_POS)) {
64 msk |= MEC_ESPI_OOB_DIR_DN;
65 }
66
67 return msk;
68 }
69
70 /* ---- Public API ---- */
71
mec_hal_espi_oob_girq_ctrl(uint8_t enable,uint8_t msk)72 void mec_hal_espi_oob_girq_ctrl(uint8_t enable, uint8_t msk)
73 {
74 uint32_t bitmap = msk_to_girq_bitmap(msk);
75
76 mec_hal_girq_bm_en(MEC5_ESPI_GIRQ, bitmap, enable);
77 }
78
mec_hal_espi_oob_girq_status_clr(uint8_t msk)79 void mec_hal_espi_oob_girq_status_clr(uint8_t msk)
80 {
81 uint32_t bitmap = msk_to_girq_bitmap(msk);
82
83 mec_hal_girq_bm_clr_src(MEC5_ESPI_GIRQ, bitmap);
84 }
85
mec_hal_espi_oob_girq_status(void)86 uint32_t mec_hal_espi_oob_girq_status(void)
87 {
88 uint32_t src = mec_hal_girq_source_get(MEC5_ESPI_GIRQ);
89
90 return bitmap_to_msk(src);
91 }
92
mec_hal_espi_oob_girq_result(void)93 uint32_t mec_hal_espi_oob_girq_result(void)
94 {
95 uint32_t result = mec_hal_girq_result_get(MEC5_ESPI_GIRQ);
96
97 return bitmap_to_msk(result);
98 }
99
mec_hal_espi_oob_ready_set(struct mec_espi_io_regs * iobase)100 void mec_hal_espi_oob_ready_set(struct mec_espi_io_regs *iobase)
101 {
102 iobase->OOBRDY = MEC_BIT(MEC_ESPI_IO_OOBRDY_OOB_READY_Pos);
103 }
104
mec_hal_espi_oob_is_ready(struct mec_espi_io_regs * iobase)105 int mec_hal_espi_oob_is_ready(struct mec_espi_io_regs *iobase)
106 {
107 if (iobase->OOBRDY & MEC_BIT(MEC_ESPI_IO_OOBRDY_OOB_READY_Pos)) {
108 return 1;
109 }
110
111 return 0;
112 }
113
114 /* OOB TX Status register channel enable change bit matches API defined
115 * position (bit[1]). Current channel enable state is at bit[9] in the
116 * register; move to bit[0].
117 */
mec_hal_espi_oob_en_status(struct mec_espi_io_regs * iobase)118 uint32_t mec_hal_espi_oob_en_status(struct mec_espi_io_regs *iobase)
119 {
120 uint32_t txsts = iobase->OOBTXSTS;
121 uint32_t en = txsts & MEC_BIT(MEC_ESPI_IO_OOBTXSTS_CHEN_CHG_Pos); /* bit[1] */
122
123 if (txsts & MEC_BIT(MEC_ESPI_IO_OOBTXSTS_CHEN_STATE_Pos)) {
124 en |= MEC_BIT(MEC_ESPI_CHAN_ENABLED_POS);
125 }
126
127 return en;
128 }
129
130 /* Return the maximum eSPI OOB packet size in bytes selected by the eSPI Host when
131 * it configured the OOB channel.
132 * OOB is different than the other channels. Size encoding are the
133 * same but OOB adds 9 bytes to the standard sizes.
134 */
mec_hal_espi_oob_max_pkt_size(struct mec_espi_io_regs * iobase)135 uint32_t mec_hal_espi_oob_max_pkt_size(struct mec_espi_io_regs *iobase)
136 {
137 uint32_t sz;
138
139 sz = (iobase->OOBRXC & MEC_ESPI_IO_OOBRXC_MAX_PLD_SZ_Msk) >> MEC_ESPI_IO_OOBRXC_MAX_PLD_SZ_Pos;
140 if ((sz == 0) || (sz > 3u)) { /* reserved values */
141 return 0;
142 }
143
144 sz += 5u;
145 sz = (1u << sz) + 9u; /* add OOB MCHP packet wrapper size of 9 bytes */
146
147 return sz;
148 }
149
150 /* Set OOB buffer address for upstream or downstream direction.
151 * We set the buffer size to the passed value if it is <= OOB Configuration Max Packet Size.
152 * Otherwise we set size to Max Packet Size.
153 * For upstream, if the buffer size is 0 or > the Max Packet Size in the OOB Configuration
154 * register then HW when started will generate a Bad Request error.
155 * For downstream, if the specified buffer length >= OOB Config Max Packet Size the
156 * HW limit check is disabled. This means no Data Overrun check will be made on
157 * incoming data allowing potential buffer overrun corrupting memory.
158 */
mec_hal_espi_oob_buffer_set(struct mec_espi_io_regs * iobase,uint8_t dir,struct mec_espi_oob_buf * buf)159 int mec_hal_espi_oob_buffer_set(struct mec_espi_io_regs *iobase, uint8_t dir,
160 struct mec_espi_oob_buf * buf)
161 {
162 uint32_t temp, lenb, maxlen;
163
164 if (!iobase || !buf) {
165 return MEC_RET_ERR_INVAL;
166 }
167
168 if (buf->maddr & 0x03u) {
169 return MEC_RET_ERR_DATA_ALIGN;
170 }
171
172 if (!buf->len) {
173 return MEC_RET_ERR_DATA_LEN;
174 }
175
176 maxlen = mec_hal_espi_oob_max_pkt_size(iobase);
177 lenb = buf->len;
178 if (lenb > maxlen) {
179 lenb = maxlen;
180 }
181
182 if (dir == MEC_ESPI_OOB_DIR_DN) {
183 iobase->OOBRXA = buf->maddr;
184 temp = iobase->OOBRXL & (uint32_t)~(MEC_ESPI_IO_OOBRXL_RX_BUF_LEN_Msk);
185 temp |= ((lenb << MEC_ESPI_IO_OOBRXL_RX_BUF_LEN_Pos) & MEC_ESPI_IO_OOBRXL_RX_BUF_LEN_Msk);
186 iobase->OOBRXL = temp;
187 } else {
188 iobase->OOBTXA = buf->maddr;
189 temp = iobase->OOBTXL & (uint32_t)~(MEC_ESPI_IO_OOBTXL_TX_MSG_LEN_Msk);
190 temp |= ((lenb << MEC_ESPI_IO_OOBTXL_TX_MSG_LEN_Pos) & MEC_ESPI_IO_OOBTXL_TX_MSG_LEN_Msk);
191 iobase->OOBTXL = temp;
192 }
193
194 return MEC_RET_OK;
195 }
196
197 /* Inform the hardware we are ready to receive OOB packets from the upstream eSPI Host.
198 * The RX buffer must be set before calling this routine.
199 * NOTE: RX available bit is write-only. Once set it causes the OOB receive enable to be
200 * set in the OOB RX Status register.
201 */
mec_hal_espi_oob_rx_buffer_avail(struct mec_espi_io_regs * iobase)202 void mec_hal_espi_oob_rx_buffer_avail(struct mec_espi_io_regs *iobase)
203 {
204 iobase->OOBRXC |= MEC_BIT(MEC_ESPI_IO_OOBRXC_RX_AVAIL_Pos);
205 }
206
207 /* Enable OOB channel interrupts to the EC
208 * NOTE: All of the OOB errors cause DONE status to be set.
209 */
mec_hal_espi_oob_intr_ctrl(struct mec_espi_io_regs * iobase,uint32_t msk,uint8_t en)210 void mec_hal_espi_oob_intr_ctrl(struct mec_espi_io_regs *iobase, uint32_t msk, uint8_t en)
211 {
212 uint32_t txien = 0;
213
214 if (msk & MEC_BIT(MEC_ESPI_OOB_DN_INTR_DONE_POS)) {
215 if (en) {
216 iobase->OOBRXIEN |= MEC_BIT(MEC_ESPI_IO_OOBRXIEN_DONE_Pos);
217 } else {
218 iobase->OOBRXIEN &= (uint32_t)~MEC_BIT(MEC_ESPI_IO_OOBRXIEN_DONE_Pos);
219 }
220 }
221
222 if (msk & MEC_BIT(MEC_ESPI_OOB_UP_INTR_DONE_POS)) {
223 txien |= MEC_BIT(MEC_ESPI_IO_OOBTXIEN_DONE_Pos);
224 }
225 if (msk & MEC_BIT(MEC_ESPI_OOB_UP_INTR_CHEN_CHG_POS)) {
226 txien |= MEC_BIT(MEC_ESPI_IO_OOBTXIEN_CHEN_CHG_Pos);
227 }
228
229 if (en) {
230 iobase->OOBTXIEN |= txien;
231 } else {
232 iobase->OOBTXIEN &= ~txien;
233 }
234 }
235
mec_hal_espi_oob_tx_start(struct mec_espi_io_regs * iobase,uint8_t tag,uint8_t start)236 void mec_hal_espi_oob_tx_start(struct mec_espi_io_regs *iobase, uint8_t tag, uint8_t start)
237 {
238 uint32_t txctrl = iobase->OOBTXC & (uint32_t)~(MEC_ESPI_IO_OOBTXC_OOB_TX_TAG_Msk);
239
240 txctrl |= (((uint32_t)tag << MEC_ESPI_IO_OOBTXC_OOB_TX_TAG_Pos)
241 & MEC_ESPI_IO_OOBTXC_OOB_TX_TAG_Msk);
242 iobase->OOBTXC = txctrl;
243
244 if (start) {
245 iobase->OOBTXC |= MEC_BIT(MEC_ESPI_IO_OOBTXC_START_Pos);
246 }
247 }
248
mec_hal_espi_oob_tx_is_busy(struct mec_espi_io_regs * iobase)249 int mec_hal_espi_oob_tx_is_busy(struct mec_espi_io_regs *iobase)
250 {
251 if (iobase->OOBTXSTS & MEC_BIT(MEC_ESPI_IO_OOBTXSTS_BUSY_Pos)) {
252 return 1;
253 }
254
255 return 0;
256 }
257
mec_hal_espi_oob_rx_tag(struct mec_espi_io_regs * iobase)258 uint8_t mec_hal_espi_oob_rx_tag(struct mec_espi_io_regs *iobase)
259 {
260 uint32_t tag = ((iobase->OOBRXSTS & MEC_ESPI_IO_OOBRXSTS_OOB_RX_TAG_Msk) >>
261 MEC_ESPI_IO_OOBRXSTS_OOB_RX_TAG_Pos);
262
263 return (uint8_t)(tag & 0xffu);
264 }
265
mec_hal_espi_oob_received_len(struct mec_espi_io_regs * iobase)266 uint32_t mec_hal_espi_oob_received_len(struct mec_espi_io_regs *iobase)
267 {
268 uint32_t recvlen = 0;
269
270 if (iobase) {
271 recvlen = iobase->OOBRXL & MEC_ESPI_IO_OOBRXL_RECV_MSG_LEN_Msk;
272 recvlen >>= MEC_ESPI_IO_OOBRXL_RECV_MSG_LEN_Pos;
273 }
274
275 return recvlen;
276 }
277
mec_hal_espi_oob_status(struct mec_espi_io_regs * iobase,uint8_t dir)278 uint32_t mec_hal_espi_oob_status(struct mec_espi_io_regs *iobase, uint8_t dir)
279 {
280 if (dir == MEC_ESPI_OOB_DIR_DN) {
281 return iobase->OOBRXSTS;
282 } else {
283 return iobase->OOBTXSTS;
284 }
285 }
286
mec_hal_espi_oob_is_done(uint32_t status,uint8_t dir)287 int mec_hal_espi_oob_is_done(uint32_t status, uint8_t dir)
288 {
289 uint8_t done_pos = MEC_ESPI_IO_OOBTXSTS_DONE_Pos;
290
291 if (dir == MEC_ESPI_OOB_DIR_DN) {
292 done_pos = MEC_ESPI_IO_OOBRXSTS_DONE_Pos;
293 }
294
295 if (status & MEC_BIT(done_pos)) {
296 return 1;
297 }
298
299 return 0;
300 }
301
mec_hal_espi_oob_is_error(uint32_t status,uint8_t dir)302 int mec_hal_espi_oob_is_error(uint32_t status, uint8_t dir)
303 {
304 uint32_t msk = (MEC_ESPI_IO_OOBTXSTS_EC_BUS_ERR_Msk
305 | MEC_ESPI_IO_OOBTXSTS_START_OVRUN_Msk
306 | MEC_ESPI_IO_OOBTXSTS_BAD_REQ_Msk);
307
308 if (dir == MEC_ESPI_OOB_DIR_DN) {
309 msk = (MEC_ESPI_IO_OOBRXSTS_EC_BUS_ERR_Msk | MEC_ESPI_IO_OOBRXSTS_DATA_OVRUN_Msk);
310 }
311
312 if (status & msk) {
313 return 1;
314 }
315
316 return 0;
317 }
318
mec_hal_espi_oob_up_is_chan_event(uint32_t status)319 int mec_hal_espi_oob_up_is_chan_event(uint32_t status)
320 {
321 int ev = 0; /* no event */
322
323 if (status & MEC_BIT(MEC_ESPI_IO_OOBTXSTS_CHEN_CHG_Pos)) {
324 if (status & MEC_BIT(MEC_ESPI_IO_OOBTXSTS_CHEN_STATE_Pos)) {
325 /* 0 -> 1 is enable */
326 ev = 1;
327 } else {
328 ev = -1; /* 1 -> 0 disable */
329 }
330 }
331
332 return ev;
333 }
334
mec_hal_espi_oob_status_clr_done(struct mec_espi_io_regs * iobase,uint8_t dir)335 void mec_hal_espi_oob_status_clr_done(struct mec_espi_io_regs *iobase, uint8_t dir)
336 {
337 if (dir == MEC_ESPI_OOB_DIR_UP) {
338 iobase->OOBTXSTS = MEC_BIT(MEC_ESPI_IO_OOBTXSTS_DONE_Pos);
339 } else {
340 iobase->OOBRXSTS = MEC_BIT(MEC_ESPI_IO_OOBRXSTS_DONE_Pos);
341 }
342
343
344 }
345
mec_hal_espi_oob_status_clr_err(struct mec_espi_io_regs * iobase,uint8_t dir)346 void mec_hal_espi_oob_status_clr_err(struct mec_espi_io_regs *iobase, uint8_t dir)
347 {
348 if (dir == MEC_ESPI_OOB_DIR_UP) {
349 iobase->OOBTXSTS = (MEC_ESPI_IO_OOBTXSTS_EC_BUS_ERR_Msk
350 | MEC_ESPI_IO_OOBTXSTS_START_OVRUN_Msk
351 | MEC_ESPI_IO_OOBTXSTS_BAD_REQ_Msk);
352 } else {
353 iobase->OOBRXSTS = (MEC_ESPI_IO_OOBRXSTS_EC_BUS_ERR_Msk
354 | MEC_ESPI_IO_OOBRXSTS_DATA_OVRUN_Msk);
355 }
356 }
357
mec_hal_espi_oob_status_clr_chen_change(struct mec_espi_io_regs * iobase)358 void mec_hal_espi_oob_status_clr_chen_change(struct mec_espi_io_regs *iobase)
359 {
360 iobase->OOBTXSTS = MEC_BIT(MEC_ESPI_IO_OOBTXSTS_CHEN_CHG_Pos);
361 }
362
mec_hal_espi_oob_status_clr_all(struct mec_espi_io_regs * iobase,uint8_t dir)363 void mec_hal_espi_oob_status_clr_all(struct mec_espi_io_regs *iobase, uint8_t dir)
364 {
365 if (dir == MEC_ESPI_OOB_DIR_DN) {
366 iobase->OOBRXSTS = MEC_ESPI_OOB_RX_STS_RW1C;
367 } else {
368 iobase->OOBTXSTS = MEC_ESPI_OOB_TX_STS_RW1C;
369 }
370 }
371
372 /* end mec_espi_oob.c */
373