1 /*
2  * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stddef.h>
7 
8 #include <device_mec5.h>
9 #include "mec_defs.h"
10 #include "mec_ecia_api.h"
11 #include "mec_espi_pc.h"
12 #include "mec_pcr_api.h"
13 #include "mec_emi_api.h"
14 #include "mec_retval.h"
15 
16 #define MEC_EMI_GIRQ 15
17 
18 #define MEC_EMI0_GIRQ_POS 2
19 #define MEC_EMI1_GIRQ_POS 3
20 #define MEC_EMI2_GIRQ_POS 4
21 
22 #define MEC_EMI0_ECIA_INFO MEC5_ECIA_INFO(15, 2, 7, 42)
23 #define MEC_EMI1_ECIA_INFO MEC5_ECIA_INFO(15, 3, 7, 43)
24 #define MEC_EMI2_ECIA_INFO MEC5_ECIA_INFO(15, 4, 7, 44)
25 
26 
27 struct mec_emi_info {
28     uintptr_t base_addr;
29     uint16_t pcr_id;
30     uint8_t ldn;
31     uint32_t devi;
32 };
33 
34 static const struct mec_emi_info emi_instances[] = {
35     { MEC_EMI0_BASE, MEC_PCR_EMI0, MEC_ESPI_LDN_EMI0, MEC_EMI0_ECIA_INFO },
36     { MEC_EMI1_BASE, MEC_PCR_EMI1, MEC_ESPI_LDN_EMI1, MEC_EMI1_ECIA_INFO },
37     { MEC_EMI2_BASE, MEC_PCR_EMI2, MEC_ESPI_LDN_EMI2, MEC_EMI2_ECIA_INFO },
38 };
39 #define NUM_EMI_INSTANCES \
40     (sizeof(emi_instances) / sizeof(struct mec_emi_info))
41 
find_emi_info(uintptr_t base_addr)42 static struct mec_emi_info const *find_emi_info(uintptr_t base_addr)
43 {
44     for (size_t i = 0; i < NUM_EMI_INSTANCES; i++) {
45         if (base_addr == emi_instances[i].base_addr) {
46             return &emi_instances[i];
47         }
48     }
49 
50     return NULL;
51 }
52 
53 /* Each EMI contains:
54  * One 8-bit Host-to-EC mailbox register.
55  * One 8-bit EC-to-Host mailbox register.
56  * Two memory regions BAR's. Each BAR allows the Host to access
57  * the SRAM via a Host facing EC-Index/Data registers with
58  * auto-increment of the index. Access size can be 8, 16, or 32-bit.
59  * Application ID registers.
60  *
61  */
62 
63 /* ---- Public API ---- */
64 
mec_hal_emi_girq_ctrl(struct mec_emi_regs * base,uint8_t enable)65 int mec_hal_emi_girq_ctrl(struct mec_emi_regs *base, uint8_t enable)
66 {
67     const struct mec_emi_info *info = find_emi_info((uintptr_t)base);
68 
69     if (!info) {
70         return MEC_RET_ERR_INVAL;
71     }
72 
73     mec_hal_girq_ctrl(info->devi, enable);
74 
75     return MEC_RET_OK;
76 }
77 
mec_hal_emi_girq_clr(struct mec_emi_regs * base)78 int mec_hal_emi_girq_clr(struct mec_emi_regs *base)
79 {
80     const struct mec_emi_info *info = find_emi_info((uintptr_t)base);
81 
82     if (!info) {
83         return MEC_RET_ERR_INVAL;
84     }
85 
86     mec_hal_girq_clr_src(info->devi);
87 
88     return MEC_RET_OK;
89 }
90 
mec_hal_emi_girq_result(struct mec_emi_regs * base)91 uint32_t mec_hal_emi_girq_result(struct mec_emi_regs *base)
92 {
93     const struct mec_emi_info *info = find_emi_info((uintptr_t)base);
94 
95     if (!info) {
96         return 0;
97     }
98 
99     return mec_hal_girq_result(info->devi);
100 }
101 
102 /* Initialize an EMI controller.
103  * This peripheral is reset by chip reset (RESET_SYS).
104  * The Host I/O and Memory BAR's in the eSPI I/O component are reset by
105  * RESET_VCC and RESET_HOST (PCI_RESET# or PLTRST#).
106  */
mec_hal_emi_init(struct mec_emi_regs * regs,uint32_t flags)107 int mec_hal_emi_init(struct mec_emi_regs *regs, uint32_t flags)
108 {
109     const struct mec_emi_info *info = find_emi_info((uintptr_t)regs);
110 
111     if (!info) {
112         return MEC_RET_ERR_INVAL;
113     }
114 
115     mec_hal_girq_ctrl(info->devi, 0);
116     mec_hal_pcr_clr_blk_slp_en(info->pcr_id);
117 
118     if (flags & MEC_EMI_RESET) {
119         mec_hal_pcr_blk_reset(info->pcr_id);
120     }
121 
122     mec_hal_girq_clr_src(info->devi);
123 
124     return MEC_RET_OK;
125 }
126 
127 /* Configure one of an EMI's memory access regions.
128  * region: 0 or 1. Each EMI has two sets of memory region access registers.
129  * mbase: physical address of region start in EC SRAM memory. Hardware ignores
130  *   bits[1:0] resulting in minimal 4-byte alignment.
131  * rwlimits: b[15:0] is the read limit and b[31:16] is the write limit. The limit
132  *   values are offsets from the base not actual EC SRAM address values. The Host
133  *   writes an offset into the region to the host facing EC-Address register.
134  *   If bits[14:2] of EC-Address are less than the read or write limit then the access
135  *   occurs (bus cycles to actual EC SRAM).
136  *   Hardware implementation allows
137  *   1. read_size == write_size == 0. Region disabled
138  *
139  *   2. read_size != 0, write_size == 0: Region is read-only
140  *      read-only: 0 <= offset < read_size
141  *
142  *   3. read_size == 0, write_size != 0: Region is write-only
143  *      write-only: 0 <= offset < write_size
144  *
145  *   4. write_size < read_size: Lower section read/write, upper section read-only
146  *      read/write: 0 <= offset < write_size
147  *      read-only:  write_size <= offset < read_size
148  *
149  *   5. read_size < write_size: Lower section read/write, upper section write-only
150  *      read/write: 0 <= offset < read_size
151  *      write-only: read_size <= offset < write_size
152  */
mec_hal_emi_mem_region_config(struct mec_emi_regs * regs,uint8_t region,uint32_t mbase,uint32_t rwszs)153 int mec_hal_emi_mem_region_config(struct mec_emi_regs *regs, uint8_t region,
154                                   uint32_t mbase, uint32_t rwszs)
155 {
156     const struct mec_emi_info *info = find_emi_info((uintptr_t)regs);
157     uint32_t mend, rlim, wlim;
158 
159     if (!info || (region >= MEC_EMI_MEM_REGION_NUM) || (mbase < MEC5_CODE_SRAM_BASE)
160         || (mbase > (MEC5_DATA_SRAM_BASE + MEC5_DATA_SRAM_SIZE))
161         || (mbase & 0x3u) || (rwszs & 0x30003u)) {
162         return MEC_RET_ERR_INVAL;
163     }
164 
165     rlim = rwszs & MEC_EMI_MEMR_CFG_RDSZ_MSK;
166     wlim = (rwszs >> MEC_EMI_MEMR_CFG_WRSZ_POS) & MEC_EMI_MEMR_CFG_RDSZ_MSK;
167     mend = (rlim > wlim) ? rlim : wlim;
168     if ((mbase + mend) > (MEC5_DATA_SRAM_BASE + MEC5_DATA_SRAM_SIZE)) {
169         return MEC_RET_ERR_INVAL;
170     }
171 
172     if (region == MEC_EMI_MEM_REGION_0) {
173         regs->MR0L = 0u;
174         regs->MR0B = mbase;
175         regs->MR0L = rwszs;
176     } else {
177         regs->MR1L = 0u;
178         regs->MR1B = mbase;
179         regs->MR1L = rwszs;
180     }
181 
182     return MEC_RET_OK;
183 }
184 
185 /* Write 8-bit value to the Host-to-EC or EC-to-Host mailbox register.
186  * Write of 1-bits to Host-to-EC clears the respective bits.
187  * A write to EC-to-Host generates an event to the system Host if configured.
188  * Events are Serial IRQ or SMI.
189  */
mec_hal_emi_mbox_wr(struct mec_emi_regs * regs,uint8_t host_to_ec,uint8_t val)190 int mec_hal_emi_mbox_wr(struct mec_emi_regs *regs, uint8_t host_to_ec, uint8_t val)
191 {
192     if (!regs) {
193         return MEC_RET_ERR_INVAL;
194     }
195 
196     if (host_to_ec) {
197         regs->H2EMB = val;
198     } else {
199         regs->E2HMB = val;
200     }
201 
202     return MEC_RET_OK;
203 }
204 
mec_hal_emi_mbox_rd(struct mec_emi_regs * regs,uint8_t host_to_ec)205 uint8_t mec_hal_emi_mbox_rd(struct mec_emi_regs *regs, uint8_t host_to_ec)
206 {
207     uint8_t mbox_val;
208 
209     if (host_to_ec) {
210         mbox_val = regs->H2EMB;
211     } else {
212         mbox_val = regs->E2HMB;
213     }
214 
215     return mbox_val;
216 }
217 
218 /* Set one software interrupt bit [1:15] which is reflected in the
219  * Host visible Interrupt Source LSB and MSB registers.
220  */
mec_hal_emi_swi_set_one(struct mec_emi_regs * regs,uint8_t swi_pos)221 int mec_hal_emi_swi_set_one(struct mec_emi_regs *regs, uint8_t swi_pos)
222 {
223     if ((!regs) || (swi_pos == 0) || (swi_pos > 15)) {
224         return MEC_RET_ERR_INVAL;
225     }
226 
227     /* read/write-one-to-set register. 0 bits have no effect */
228     regs->ISEN = MEC_BIT(swi_pos);
229 
230     return MEC_RET_OK;
231 }
232 
mec_hal_emi_swi_set(struct mec_emi_regs * regs,uint16_t swi_bit_map)233 int mec_hal_emi_swi_set(struct mec_emi_regs *regs, uint16_t swi_bit_map)
234 {
235     if (!regs) {
236         return MEC_RET_ERR_INVAL;
237     }
238 
239     /* read/write-one-to-set register. 0 bits have no effect */
240     regs->ISEN = swi_bit_map;
241 
242     return MEC_RET_OK;
243 }
244 
245 /* Specify the bit map of SWI bits the Host can clear via Host Interrupt Source
246  * register. By default the Host is unable to clear any SWI bits set by the EC.
247  * Allowing the Host to clear SWI interrupt status makes the SWI status bits
248  * behave as "edge" status.
249  */
mec_hal_emi_swi_host_clear_enable(struct mec_emi_regs * regs,uint16_t mask,uint16_t enable)250 int mec_hal_emi_swi_host_clear_enable(struct mec_emi_regs *regs, uint16_t mask, uint16_t enable)
251 {
252     if (!regs) {
253         return MEC_RET_ERR_INVAL;
254     }
255 
256     regs->IHCEN = (regs->IHCEN & ~mask) | (enable & mask);
257 
258     return MEC_RET_OK;
259 }
260 
261 /* Application ID mechanism
262  * EMI hardware implements in incrementing 8-bit Application ID
263  * value for software to use as an ownership token. The value 0
264  * is not used and signifies all the remaining 255 ApplicationID
265  * values (1 - 255) are in use.
266  * EMI has two Host facing 8-bit Application ID registers.
267  * Host_AppID register.
268  *  Read: 0, Indicates AppID has been cleared.
269  *  Read: non-zero, AppID value currently owning the EMI HW.
270  *  Write: 0 non-effect
271  *  Write: non-zero, a write of the current value clears that value.
272  *         This is how the Host application clears the AppID it was
273  *         granted.
274  * Host_AppID_Assign register.
275  *  Read: allocates the next AppID value. If 0 was read it indicates
276  *        all AppID's are in use. The application should continue polling
277  *        this register until it reads a non-zero (valid AppID).
278  *        !!! Each read of this register causes the hardware to increment
279  *        !!! the AppID value.
280  *  Write: Increments AppID value.
281  *
282  * Usage scenario:
283  * Host:
284  * 1. AppId = read Host_AppID_Assign register
285  * 2. If AppID == 0 goto 1
286  * 3. Host makes use of EMI: mailbox and/or access to EMI memory regions.
287  * 4. Host write AppID to Host_AppID register to signal it is done.
288  *    EMI hardware internally frees the AppID allowing another Host thread
289  *    to use the EMI instance.
290  *
291  */
292 
mec_hal_emi_is_appid(struct mec_emi_regs * regs,uint8_t appid)293 int mec_hal_emi_is_appid(struct mec_emi_regs *regs, uint8_t appid)
294 {
295     if (!regs) {
296         return 0;
297     }
298 
299     uint8_t idx = (appid >> 5);
300     uint8_t pos = (appid & 0x1fu);
301 
302     if (regs->AIDS[idx] & MEC_BIT(pos)) {
303         return 1;
304     }
305 
306     return 0;
307 }
308 
309 /* Clear specified ApplicationID */
mec_hal_emi_clear_appid(struct mec_emi_regs * regs,uint8_t appid)310 int mec_hal_emi_clear_appid(struct mec_emi_regs *regs, uint8_t appid)
311 {
312     if (!regs) {
313         return MEC_RET_ERR_INVAL;
314     }
315 
316     uint8_t idx = (appid >> 5);
317     uint8_t pos = (appid & 0x1fu);
318 
319     regs->AIDS[idx] &= ~MEC_BIT(pos);
320 
321     return MEC_RET_OK;
322 }
323 
mec_hal_emi_clear_all_appid(struct mec_emi_regs * regs)324 int mec_hal_emi_clear_all_appid(struct mec_emi_regs *regs)
325 {
326     if (!regs) {
327         return MEC_RET_ERR_INVAL;
328     }
329 
330     for (int i = 0; i < 8; i++) {
331         regs->AIDS[i] = 0u;
332     }
333 
334     return MEC_RET_OK;
335 }
336 
337 /* end mec_emi.c */
338