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