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_espi_api.h"
13 #include "mec_retval.h"
14 
15 /* Logical device to BAR index table. Note: not all logical devices have
16  * a memory BAR. BAR indices are stored +1. A value of zero indicates no
17  * BAR of that type exists for the logical device.
18  */
19 struct ld_info {
20     uint8_t ldn;
21     uint8_t io_bar_idx;
22     uint8_t mem_bar_idx;
23     uint8_t num_sirqs;
24     uint8_t sirq_idx;
25     uint8_t rsvd[3];
26 };
27 
28 const struct ld_info ld_table[] = {
29     { MEC_ESPI_LDN_MBOX, 3, 1, 2, 0, {0, 0, 0} },
30     { MEC_ESPI_LDN_KBC, 4, 0, 2, 2, {0, 0, 0} },
31     { MEC_ESPI_LDN_ACPI_EC0, 5, 2, 1, 4, {0, 0, 0} },
32     { MEC_ESPI_LDN_ACPI_EC1, 6, 3, 1, 5, {0, 0, 0} },
33     { MEC_ESPI_LDN_ACPI_EC2, 7, 4, 1, 6, {0, 0, 0} },
34     { MEC_ESPI_LDN_ACPI_EC3, 8, 5, 1, 7, {0, 0, 0} },
35     { MEC_ESPI_LDN_ACPI_EC4, 9, 6, 1, 8, {0, 0, 0} },
36     { MEC_ESPI_LDN_ACPI_PM1, 10, 0, 0, 0, {0, 0, 0} },
37     { MEC_ESPI_LDN_KB_PORT92, 11, 0, 0, 0, {0, 0, 0} },
38     { MEC_ESPI_LDN_UART0, 12, 0, 1, 9, {0, 0, 0} },
39     { MEC_ESPI_LDN_UART1, 13, 0, 1, 10, {0, 0, 0} },
40     { MEC_ESPI_LDN_UART2, 22, 0, 1, 19, {0, 0, 0} },
41     { MEC_ESPI_LDN_UART3, 24, 0, 1, 21, {0, 0, 0} },
42     { MEC_ESPI_LDN_IOC, 1, 0, 0, 0, {0, 0, 0} },
43     { MEC_ESPI_LDN_IOMC, 2, 0, 0, 0, {0, 0, 0} },
44     { MEC_ESPI_LDN_GLUE, 23, 0, 0, 0, {0, 0, 0} },
45     { MEC_ESPI_LDN_EMI0, 14, 7, 2, 11, {0, 0, 0} },
46     { MEC_ESPI_LDN_EMI1, 15, 8, 2, 13, {0, 0, 0} },
47     { MEC_ESPI_LDN_EMI2, 16, 9, 2, 15, {0, 0, 0} },
48     { MEC_ESPI_LDN_RTC, 19, 0, 1, 17, {0, 0, 0} },
49     { MEC_ESPI_LDN_PP0, 25, 0, 0, 0, {0, 0, 0} }, /* desktop devices */
50     { MEC_ESPI_LDN_BDBG0, 17, 0, 0, 0, {0, 0, 0} },
51     { MEC_ESPI_LDN_BDBG0_ALIAS, 18, 0, 0, 0, {0, 0, 0} },
52     { MEC_ESPI_LDN_TB32, 21, 0, 0, 0, {0, 0, 0} },
53     { MEC_ESPI_LDN_EC, 0, 0, 1, 18, {0, 0, 0} },
54 };
55 #define LD_TBL_NUM_ENTRIES (sizeof(ld_table) / sizeof(struct ld_info))
56 
find_bar(uint8_t ldn)57 static struct ld_info const *find_bar(uint8_t ldn)
58 {
59     if (ldn >= MEC_ESPI_LDN_MAX) {
60         return NULL;
61     }
62 
63     for (size_t i = 0; i < LD_TBL_NUM_ENTRIES; i++) {
64         if (ld_table[i].ldn == ldn) {
65             return &ld_table[i];
66         }
67     }
68 
69     return NULL;
70 }
71 
ldn_has_iob(uint8_t ldn)72 static inline int ldn_has_iob(uint8_t ldn)
73 {
74     if (ldn < 32) {
75         return (int)(MEC_BIT(ldn) & (uint32_t)(MEC5_ESPI_LDN_IOB_MSK_LO));
76     } else {
77         ldn = ldn - (uint8_t)32u;
78         return (int)(MEC_BIT(ldn) & (uint32_t)(MEC5_ESPI_LDN_IOB_MSK_HI));
79     }
80 }
81 
ldn_has_memb(uint8_t ldn)82 static inline int ldn_has_memb(uint8_t ldn)
83 {
84     if (ldn < 32) {
85         return (int)(MEC_BIT(ldn) & (uint32_t)(MEC5_ESPI_LDN_MEMB_MSK_LO));
86     } else {
87         ldn = ldn - (uint8_t)32u;
88         return (int)(MEC_BIT(ldn) & (uint32_t)(MEC5_ESPI_LDN_MEMB_MSK_HI));
89     }
90 }
91 
mec_espi_sirq_get(struct mec_espi_io_regs * iobase,uint8_t sirq_idx)92 static uint8_t mec_espi_sirq_get(struct mec_espi_io_regs *iobase, uint8_t sirq_idx)
93 {
94     if ((sirq_idx > 31) || !(MEC_BIT(sirq_idx) & MEC5_ESPI_PC_SIRQ_BITMAP)) {
95         return MEC_ESPI_SIRQ_SLOT_DIS;
96     }
97 
98     return iobase->SERIRQ[sirq_idx];
99 }
100 
101 /* Set SERIRQ slot number for specified SERIRQ index */
espi_sirq_set(struct mec_espi_io_regs * iobase,uint8_t sirq_idx,uint8_t slot)102 static void espi_sirq_set(struct mec_espi_io_regs *iobase, uint8_t sirq_idx, uint8_t slot)
103 {
104     if ((sirq_idx > 31) || !(MEC_BIT(sirq_idx) & MEC5_ESPI_PC_SIRQ_BITMAP)) {
105         return;
106     }
107 
108     iobase->SERIRQ[sirq_idx] = slot;
109 }
110 
111 /*-----------------------------------------------------------------------*/
112 
mec_hal_espi_iobar_cfg(struct mec_espi_io_regs * base,uint8_t ldn,uint16_t io_base,uint8_t enable)113 int mec_hal_espi_iobar_cfg(struct mec_espi_io_regs *base, uint8_t ldn,
114                            uint16_t io_base, uint8_t enable)
115 {
116     const struct ld_info *ldi = find_bar(ldn);
117     uint32_t bar_val = (uint32_t)io_base << 16;
118     uint8_t idx = 0;
119 
120     if (!base || !ldi) {
121         return MEC_RET_ERR_INVAL;
122     }
123 
124     if (!ldi->io_bar_idx) { /* Logical device does not implement an I/O BAR */
125         return MEC_RET_ERR_INVAL;
126     }
127 
128     idx = (uint8_t)(ldi->io_bar_idx - 1u);
129 
130     /* disable and update */
131     base->HOST_BAR[idx] = bar_val;
132 
133     if (enable) {
134         base->HOST_BAR[idx] |= MEC_BIT(MEC_ESPI_IO_HOST_BAR_VALID_Pos);
135     }
136 
137     return MEC_RET_OK;
138 }
139 
mec_hal_espi_iobar_enable(struct mec_espi_io_regs * base,uint8_t ldn,uint8_t enable)140 int mec_hal_espi_iobar_enable(struct mec_espi_io_regs *base, uint8_t ldn, uint8_t enable)
141 {
142     const struct ld_info *ldi = find_bar(ldn);
143     uint8_t idx;
144 
145     if (!base || !ldi) {
146         return MEC_RET_ERR_INVAL;
147     }
148 
149     if (!ldi->io_bar_idx) { /* Logical device does not implement an I/O BAR */
150         return MEC_RET_ERR_INVAL;
151     }
152 
153     idx = (uint8_t)(ldi->io_bar_idx - 1u);
154 
155     if (enable) {
156         base->HOST_BAR[idx] |= MEC_BIT(MEC_ESPI_IO_HOST_BAR_VALID_Pos);
157     } else {
158         base->HOST_BAR[idx] &= (uint32_t)~MEC_BIT(MEC_ESPI_IO_HOST_BAR_VALID_Pos);
159     }
160 
161     return MEC_RET_OK;
162 }
163 
mec_hal_espi_iobar_is_enabled(struct mec_espi_io_regs * base,uint8_t ldn)164 int mec_hal_espi_iobar_is_enabled(struct mec_espi_io_regs *base, uint8_t ldn)
165 {
166     const struct ld_info *ldi = find_bar(ldn);
167     uint8_t idx;
168 
169     if (!base || !ldi) {
170         return 0;
171     }
172 
173     if (!ldi->io_bar_idx) { /* Logical device does not implement an I/O BAR */
174         return 0;
175     }
176 
177     idx = (uint8_t)(ldi->io_bar_idx - 1u);
178     if (base->HOST_BAR[idx] & MEC_BIT(MEC_ESPI_IO_HOST_BAR_VALID_Pos)) {
179         return 1;
180     }
181 
182     return 0;
183 }
184 
mec_hal_espi_iobar_mask(struct mec_espi_io_regs * base,uint8_t ldn)185 uint32_t mec_hal_espi_iobar_mask(struct mec_espi_io_regs *base, uint8_t ldn)
186 {
187     const struct ld_info *ldi = find_bar(ldn);
188     uint8_t idx;
189 
190     if (!base || !ldi) {
191         return MEC_RET_ERR_INVAL;
192     }
193 
194     if (!ldi->io_bar_idx) { /* Logical device does not implement an I/O BAR */
195         return MEC_RET_ERR_INVAL;
196     }
197 
198     idx = (uint8_t)(ldi->io_bar_idx - 1u);
199 
200     return (base->EC_LDN_MSK[idx] & 0xffu);
201 }
202 
203 /* Set the logical device's I/O BAR mask field.
204  * NOTE1: Only the ACPI_EC logical devices mask fiels is writable.
205  * NOTE2: The mask field is only writable when the I/O BAR is not in reset
206  * and the valid bit in the corresponding LDN's Host I/O BAR is not set.
207  */
mec_hal_espi_iobar_mask_set(struct mec_espi_io_regs * base,uint8_t ldn,uint8_t mask)208 int mec_hal_espi_iobar_mask_set(struct mec_espi_io_regs *base, uint8_t ldn, uint8_t mask)
209 {
210     const struct ld_info *ldi = find_bar(ldn);
211 
212     if (!base || !ldi) {
213         return MEC_RET_ERR_INVAL;
214     }
215 
216     if (!ldi->io_bar_idx) { /* Logical device does not implement an I/O BAR */
217         return MEC_RET_ERR_INVAL;
218     }
219 
220     uint8_t idx = (uint8_t)(ldi->io_bar_idx - 1u);
221     uint32_t temp = base->EC_LDN_MSK[idx];
222 
223     temp &= ~(MEC_ESPI_IO_EC_LDN_MSK_MSK_Msk << MEC_ESPI_IO_EC_LDN_MSK_MSK_Pos);
224     temp |= (((uint32_t)mask << MEC_ESPI_IO_EC_LDN_MSK_MSK_Pos) | MEC_ESPI_IO_EC_LDN_MSK_MSK_Msk);
225 
226     *((volatile uint32_t *)&base->EC_LDN_MSK[idx]) = temp;
227 
228     return MEC_RET_OK;
229 }
230 
231 /* eSPI logical device memory BAR's are 80-bit registers packed in address space
232  * resulting 16-bit alignment.
233  * b[0] = 0(disabled), 1(enabled/valid)
234  * b[47:16] = bits[31:0] of the Host address.
235  * NOTE: If Host requires more than a 32-bit memory address, all eSPI I/O memory
236  * BAR's must be located in the same 4GB region and the upper address bits are
237  * specified in the MBAR Host Extended Address register.
238  */
mec_hal_espi_mbar_cfg(struct mec_espi_mem_regs * base,uint8_t ldn,uint32_t mem_base,uint8_t enable)239 int mec_hal_espi_mbar_cfg(struct mec_espi_mem_regs *base, uint8_t ldn,
240                           uint32_t mem_base, uint8_t enable)
241 {
242     const struct ld_info *ldi = find_bar(ldn);
243     uint8_t idx;
244 
245     if (!base || !ldi) {
246         return MEC_RET_ERR_INVAL;
247     }
248 
249     if (!ldi->mem_bar_idx) { /* Logical device does not implement a memory BAR */
250         return MEC_RET_ERR_INVAL;
251     }
252 
253     idx = (uint8_t)(ldi->mem_bar_idx - 1u);
254 
255     volatile struct mec_espi_mem_host_mem_bar_regs *mbar = &base->HOST_MEM_BAR[idx];
256 
257     mbar->VALID &= (uint16_t)~MEC_BIT(MEC_ESPI_MEM_HOST_MEM_BAR_VALID_EN_Pos);
258     mbar->HOST_MEM_ADDR_B15_0 = (uint16_t)mem_base;
259     mbar->HOST_MEM_ADDR_B31_16 = (uint16_t)(mem_base >> 16);
260 
261     if (enable) {
262         mbar->VALID |= MEC_BIT(MEC_ESPI_MEM_HOST_MEM_BAR_VALID_EN_Pos);
263     }
264 
265     return MEC_RET_OK;
266 }
267 
mec_hal_espi_sram_bar_cfg(struct mec_espi_mem_regs * base,const struct espi_mec5_sram_bar_cfg * barcfg,uint8_t sram_bar_id,uint8_t enable)268 int mec_hal_espi_sram_bar_cfg(struct mec_espi_mem_regs *base,
269                               const struct espi_mec5_sram_bar_cfg *barcfg,
270                               uint8_t sram_bar_id, uint8_t enable)
271 {
272     uint32_t temp;
273 
274     if (!base || !barcfg || (sram_bar_id >= MEC_ESPI_SRAM_BAR_MAX)
275         || (barcfg->access > MEC_ESPI_SRAM_HOST_ACCESS_RW)
276         || (barcfg->size > MEC_ESPI_SRAM_BAR_SIZE_32KB)) {
277             return MEC_RET_ERR_INVAL;
278     }
279 
280     base->EC_SRAM_BAR[sram_bar_id].VASZ = 0; /* disable before modification */
281     temp = barcfg->size;
282     temp = (temp << MEC_ESPI_MEM_EC_SRAM_BAR_VASZ_SIZE_Pos)
283            & MEC_ESPI_MEM_EC_SRAM_BAR_VASZ_SIZE_Msk;
284     temp |= (((uint32_t)barcfg->access << MEC_ESPI_MEM_EC_SRAM_BAR_VASZ_ACCESS_Pos) &
285             MEC_ESPI_MEM_EC_SRAM_BAR_VASZ_ACCESS_Msk);
286     base->EC_SRAM_BAR[sram_bar_id].VASZ = (uint16_t)temp;
287 
288     base->EC_SRAM_BAR[sram_bar_id].EC_SRAM_ADDR_15_0 = barcfg->maddr & 0xffffu;
289     base->EC_SRAM_BAR[sram_bar_id].EC_SRAM_ADDR_31_16 = (uint16_t)(barcfg->maddr >> 16);
290 
291     base->HOST_SRAM_BAR[sram_bar_id].HOST_ADDR_15_0 = barcfg->haddr & 0xffffu;
292     base->HOST_SRAM_BAR[sram_bar_id].HOST_ADDR_31_16 = (uint16_t)(barcfg->haddr >> 16);
293 
294     if (enable) {
295         base->EC_SRAM_BAR[sram_bar_id].VASZ |= MEC_BIT(MEC_ESPI_MEM_EC_SRAM_BAR_VASZ_VALID_Pos);
296     }
297 
298     return MEC_RET_OK;
299 }
300 
301 /* Set host address bits[47:32] for memory BAR's
302  * Each Logical device implementing a memory BAR includes Host address bits [31:0].
303  * Host address bits [47:32] are the same for all memory BAR's. Therefore all memory
304  * BAR's must be located in the same 4GB host address space range.
305  */
mec_hal_espi_mbar_extended_addr_set(struct mec_espi_mem_regs * base,uint32_t extended_addr)306 int mec_hal_espi_mbar_extended_addr_set(struct mec_espi_mem_regs *base, uint32_t extended_addr)
307 {
308     if (!base) {
309         return MEC_RET_ERR_INVAL;
310     }
311 
312     base->MBAR_HOST_EXTEND = extended_addr;
313 
314     return MEC_RET_OK;
315 }
316 
mec_hal_espi_sram_bar_extended_addr_set(struct mec_espi_mem_regs * base,uint32_t extended_addr)317 int mec_hal_espi_sram_bar_extended_addr_set(struct mec_espi_mem_regs *base,
318                                             uint32_t extended_addr)
319 {
320     if (!base) {
321         return MEC_RET_ERR_INVAL;
322     }
323 
324     base->SRAM_BAR_HOST_EXTEND = extended_addr;
325 
326     return MEC_RET_OK;
327 }
328 
mec_hal_espi_mbar_enable(struct mec_espi_mem_regs * base,uint8_t ldn,uint8_t enable)329 int mec_hal_espi_mbar_enable(struct mec_espi_mem_regs *base, uint8_t ldn, uint8_t enable)
330 {
331     const struct ld_info *ldi = find_bar(ldn);
332     uint8_t idx;
333 
334     if (!base || !ldi) {
335         return MEC_RET_ERR_INVAL;
336     }
337 
338     if (!ldi->mem_bar_idx) { /* Logical device does not implement a memory BAR */
339         return MEC_RET_ERR_INVAL;
340     }
341 
342     idx = (uint8_t)(ldi->mem_bar_idx - 1u);
343 
344     volatile struct mec_espi_mem_host_mem_bar_regs *mbar = &base->HOST_MEM_BAR[idx];
345 
346     if (enable) {
347         mbar->VALID |= MEC_BIT(MEC_ESPI_MEM_HOST_MEM_BAR_VALID_EN_Pos);
348     } else {
349         mbar->VALID &= (uint16_t)~MEC_BIT(MEC_ESPI_MEM_HOST_MEM_BAR_VALID_EN_Pos);
350     }
351 
352     return MEC_RET_OK;
353 }
354 
mec_hal_espi_mbar_is_enabled(struct mec_espi_mem_regs * base,uint8_t ldn)355 int mec_hal_espi_mbar_is_enabled(struct mec_espi_mem_regs *base, uint8_t ldn)
356 {
357     const struct ld_info *ldi = find_bar(ldn);
358     uint8_t idx;
359 
360     if (!base || !ldi) {
361         return MEC_RET_ERR_INVAL;
362     }
363 
364     if (!ldi->mem_bar_idx) { /* Logical device does not implement a memory BAR */
365         return MEC_RET_ERR_INVAL;
366     }
367 
368     idx = (uint8_t)(ldi->mem_bar_idx - 1u);
369 
370     volatile struct mec_espi_mem_host_mem_bar_regs *mbar = &base->HOST_MEM_BAR[idx];
371 
372     if (mbar->VALID & MEC_BIT(MEC_ESPI_MEM_HOST_MEM_BAR_VALID_EN_Pos)) {
373         return 1;
374     }
375 
376     return 0;
377 }
378 
379 /* Disable I/O and Memory BARs for a logical device */
mec_hal_espi_bar_inhibit(struct mec_espi_io_regs * base,uint8_t ldn,uint8_t inhibit)380 int mec_hal_espi_bar_inhibit(struct mec_espi_io_regs *base, uint8_t ldn, uint8_t inhibit)
381 {
382     const struct ld_info *ldi = find_bar(ldn);
383 
384     if (!base || !ldi) {
385         return MEC_RET_ERR_INVAL;
386     }
387 
388     if (!ldi->io_bar_idx && !ldi->mem_bar_idx) { /* Logical device does not implement any BAR */
389         return MEC_RET_ERR_INVAL;
390     }
391 
392     if (ldn < 32) {
393         if (inhibit) {
394             base->PCBINH[0] |= MEC_BIT(ldn);
395         } else {
396             base->PCBINH[0] &= (uint32_t)~MEC_BIT(ldn);
397         }
398     } else {
399         ldn = ldn - (uint8_t)32u;
400         if (inhibit) {
401             base->PCBINH[1] |= MEC_BIT(ldn);
402         } else {
403             base->PCBINH[1] &= (uint32_t)~MEC_BIT(ldn);
404         }
405     }
406 
407     return MEC_RET_OK;
408 }
409 
mec_hal_espi_bar_inhibit_msk(struct mec_espi_io_regs * base,uint8_t inhibit,uint32_t msklo,uint32_t mskhi)410 int mec_hal_espi_bar_inhibit_msk(struct mec_espi_io_regs *base, uint8_t inhibit,
411                                  uint32_t msklo, uint32_t mskhi)
412 {
413     if (!base) {
414         return MEC_RET_ERR_INVAL;
415     }
416 
417     if (inhibit) {
418         base->PCBINH[0] |= msklo;
419         base->PCBINH[1] |= mskhi;
420     } else {
421         base->PCBINH[0] &= ~msklo;
422         base->PCBINH[1] &= ~mskhi;
423     }
424 
425     return MEC_RET_OK;
426 }
427 
428 /* ---- Logical Device Serial IRQ ---- */
429 
430 /* Return the number of Serial IRQs a logical device implements */
mec_hal_espi_ld_sirq_num(struct mec_espi_io_regs * iobase,uint8_t ldn)431 uint8_t mec_hal_espi_ld_sirq_num(struct mec_espi_io_regs *iobase, uint8_t ldn)
432 {
433     const struct ld_info *ldi = find_bar(ldn);
434 
435     if (!iobase || !ldi) {
436         return 0;
437     }
438 
439     return ldi->num_sirqs;
440 }
441 
442 /* get current slot number the specified logical device SIRQ instance is programmed to.
443  * NOTE: a value of 255 (0xff) indicates this SIRQ is disabled.
444  */
mec_hal_espi_ld_sirq_get(struct mec_espi_io_regs * iobase,uint8_t ldn,uint8_t ldn_sirq_id)445 uint8_t mec_hal_espi_ld_sirq_get(struct mec_espi_io_regs *iobase, uint8_t ldn, uint8_t ldn_sirq_id)
446 {
447     const struct ld_info *ldi = find_bar(ldn);
448     uint8_t idx = 0;
449 
450     if (!iobase || !ldi) {
451         return 0;
452     }
453 
454     if ((!ldi->num_sirqs) || (ldn_sirq_id > ldi->num_sirqs)) {
455         return 0xffu;
456     }
457 
458     idx = ldi->sirq_idx + ldn_sirq_id;
459 
460     return mec_espi_sirq_get(iobase, idx);
461 }
462 
mec_hal_espi_ld_sirq_set(struct mec_espi_io_regs * iobase,uint8_t ldn,uint8_t ldn_sirq_id,uint8_t slot)463 void mec_hal_espi_ld_sirq_set(struct mec_espi_io_regs *iobase, uint8_t ldn,
464                              uint8_t ldn_sirq_id, uint8_t slot)
465 {
466     const struct ld_info *ldi = find_bar(ldn);
467     uint8_t idx = 0;
468 
469     if (!iobase || !ldi) {
470         return;
471     }
472 
473     if ((!ldi->num_sirqs) || (ldn_sirq_id > ldi->num_sirqs)) {
474         return;
475     }
476 
477     idx = ldi->sirq_idx + ldn_sirq_id;
478 
479     espi_sirq_set(iobase, idx, slot);
480 }
481 
482 /* Generate EC_IRQ Serial IRQ to the Host using the Serial IRQ slot
483  * number previously programmed by mec_espi_ld_sirq_set().
484  */
mec_hal_espi_gen_ec_sirq(struct mec_espi_io_regs * iobase)485 int mec_hal_espi_gen_ec_sirq(struct mec_espi_io_regs *iobase)
486 {
487     if (!iobase) {
488         return MEC_RET_ERR_INVAL;
489     }
490 
491     iobase->PCECIRQ |= MEC_BIT(MEC_ESPI_IO_PCECIRQ_GEN_EC_IRQ_Pos);
492 
493     return MEC_RET_OK;
494 }
495 
496 /* end mec_espi_host_dev.c */
497