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