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_retval.h"
15
16 /* ---- eSPI Flash Channel ----
17 * eSPI target controller in the EC can access the flash device(s) attached
18 * to the Host eSPI controller.
19 */
20 #define MEC_ESPI_FC_ECIA_INFO MEC5_ECIA_INFO(19, 6, 11, 109)
21
22 /* Flash erase request size must be non-zero.
23 * Actual erase size is chosen by eSPI Host.
24 * Specification recommands a value of 1.
25 */
26 #define MEC_ESPI_FC_ERASE_SIZE 1u
27
28 /* Flash channel status errors */
29 #define MEC_ESPI_FC_ERR_ALL \
30 (MEC_BIT(MEC_ESPI_IO_FCSTS_BAD_REQ_Pos) | MEC_BIT(MEC_ESPI_IO_FCSTS_START_OVRFL_Pos) \
31 | MEC_BIT(MEC_ESPI_IO_FCSTS_FAIL_Pos) | MEC_BIT(MEC_ESPI_IO_FCSTS_DATA_INCOMPL_Pos) \
32 | MEC_BIT(MEC_ESPI_IO_FCSTS_DATA_OVRUN_Pos) | MEC_BIT(MEC_ESPI_IO_FCSTS_ABORT_FW_Pos) \
33 | MEC_BIT(MEC_ESPI_IO_FCSTS_EC_BUS_ERR_Pos) | MEC_BIT(MEC_ESPI_IO_FCSTS_DIS_BY_HOST_Pos))
34
35 /* ---- Public API ---- */
36
mec_hal_espi_fc_girq_ctrl(uint8_t enable)37 void mec_hal_espi_fc_girq_ctrl(uint8_t enable)
38 {
39 mec_hal_girq_ctrl(MEC_ESPI_FC_ECIA_INFO, (int)enable);
40 }
41
mec_hal_espi_fc_girq_status_clr(void)42 void mec_hal_espi_fc_girq_status_clr(void)
43 {
44 mec_hal_girq_clr_src(MEC_ESPI_FC_ECIA_INFO);
45 }
46
mec_hal_espi_fc_girq_status(void)47 uint32_t mec_hal_espi_fc_girq_status(void)
48 {
49 return mec_hal_girq_src(MEC_ESPI_FC_ECIA_INFO);
50 }
51
mec_hal_espi_fc_girq_result(void)52 uint32_t mec_hal_espi_fc_girq_result(void)
53 {
54 return mec_hal_girq_result(MEC_ESPI_FC_ECIA_INFO);
55 }
56
57 /* Flash channel HW bits for channel enable state and enable change match API definition:
58 * bit[0] = enable state
59 * bit[1] = enable state changed
60 */
mec_hal_espi_fc_en_status(struct mec_espi_io_regs * iobase)61 uint32_t mec_hal_espi_fc_en_status(struct mec_espi_io_regs *iobase)
62 {
63 return (iobase->FCSTS & 0x3u);
64 }
65
mec_hal_espi_fc_ready_set(struct mec_espi_io_regs * iobase)66 void mec_hal_espi_fc_ready_set(struct mec_espi_io_regs *iobase)
67 {
68 iobase->FCRDY = MEC_BIT(MEC_ESPI_IO_FCRDY_FC_READY_Pos);
69 }
70
mec_hal_espi_fc_is_ready(struct mec_espi_io_regs * iobase)71 int mec_hal_espi_fc_is_ready(struct mec_espi_io_regs *iobase)
72 {
73 if (iobase->FCRDY & MEC_BIT(MEC_ESPI_IO_FCRDY_FC_READY_Pos)) {
74 return 1;
75 }
76
77 return 0;
78 }
79
mec_hal_espi_fc_is_busy(struct mec_espi_io_regs * iobase)80 int mec_hal_espi_fc_is_busy(struct mec_espi_io_regs *iobase)
81 {
82 if (iobase->FCCFG & MEC_BIT(MEC_ESPI_IO_FCCFG_BUSY_Pos)) {
83 return 1;
84 }
85
86 return 0;
87 }
88
89 /* Start previoulsy configured Flash channel operation.
90 * 1. Clear R/W1C status except for Flash channel enable change as this
91 * is asynchronous and must be handled separately. Preferably by
92 * by an ISR.
93 * 2. Enable or disable FC transfer done interrupt per passed flag
94 * 3. Start transaction.
95 */
mec_hal_espi_fc_op_start(struct mec_espi_io_regs * iobase,uint32_t flags)96 void mec_hal_espi_fc_op_start(struct mec_espi_io_regs *iobase, uint32_t flags)
97 {
98 iobase->FCSTS = MEC_ESPI_FC_ERR_ALL | MEC_BIT(MEC_ESPI_IO_FCSTS_DONE_Pos);
99
100 if (flags & MEC_BIT(MEC_ESPI_FC_XFR_FLAG_START_IEN_POS)) {
101 iobase->FCIEN |= MEC_BIT(MEC_ESPI_IO_FCIEN_DONE_Pos);
102 } else {
103 iobase->FCIEN &= (uint32_t)~MEC_BIT(MEC_ESPI_IO_FCIEN_DONE_Pos);
104 }
105
106 iobase->FCCTL |= MEC_BIT(MEC_ESPI_IO_FCCTL_START_Pos);
107 }
108
mec_hal_espi_fc_op_abort(struct mec_espi_io_regs * iobase)109 void mec_hal_espi_fc_op_abort(struct mec_espi_io_regs *iobase)
110 {
111 iobase->FCCTL |= MEC_BIT(MEC_ESPI_IO_FCCTL_ABORT_Pos);
112 }
113
mec_hal_espi_fc_intr_ctrl(struct mec_espi_io_regs * iobase,uint32_t msk,uint8_t en)114 void mec_hal_espi_fc_intr_ctrl(struct mec_espi_io_regs *iobase, uint32_t msk, uint8_t en)
115 {
116 uint32_t r = 0;
117
118 if (!iobase) {
119 return;
120 }
121
122 if (msk & MEC_BIT(MEC_ESPI_FC_INTR_DONE_POS)) {
123 r |= MEC_BIT(MEC_ESPI_IO_FCIEN_DONE_Pos);
124 }
125 if (msk & MEC_BIT(MEC_ESPI_FC_INTR_CHEN_CHG_POS)) {
126 r |= MEC_BIT(MEC_ESPI_IO_FCIEN_CHEN_CHG_Pos);
127 }
128
129 if (en) {
130 iobase->FCIEN |= r;
131 } else {
132 iobase->FCIEN &= ~r;
133 }
134 }
135
mec_hal_espi_fc_status(struct mec_espi_io_regs * iobase)136 uint32_t mec_hal_espi_fc_status(struct mec_espi_io_regs *iobase)
137 {
138 if (!iobase) {
139 return 0;
140 }
141
142 return iobase->FCSTS;
143 }
144
mec_hal_espi_fc_status_clr(struct mec_espi_io_regs * iobase,uint32_t msk)145 void mec_hal_espi_fc_status_clr(struct mec_espi_io_regs *iobase, uint32_t msk)
146 {
147 if (!iobase) {
148 return;
149 }
150
151 iobase->FCSTS = msk;
152 mec_hal_girq_clr_src(MEC_ESPI_FC_ECIA_INFO);
153 }
154
mec_hal_espi_fc_is_error(uint32_t fc_status)155 int mec_hal_espi_fc_is_error(uint32_t fc_status)
156 {
157 if (fc_status & (MEC_ESPI_FC_ERR_ALL)) {
158 return 1;
159 }
160
161 return 0;
162 }
163
164 /* Return flash channel maximum read size selected by eSPI Host */
mec_hal_espi_fc_max_read_req_sz(struct mec_espi_io_regs * iobase)165 uint32_t mec_hal_espi_fc_max_read_req_sz(struct mec_espi_io_regs *iobase)
166 {
167 uint32_t exp = 0;
168
169 exp = ((iobase->FCCFG & MEC_ESPI_IO_FCCFG_MAX_RD_REQ_SZ_Msk) >>
170 MEC_ESPI_IO_FCCFG_MAX_RD_REQ_SZ_Pos);
171 if (exp == 0u) {
172 return 0u;
173 }
174
175 exp += 5u;
176
177 return (1u << exp);
178 }
179
180 /* Return flash channel maximum payload size selected by eSPI Host */
mec_hal_espi_fc_max_pld_sz(struct mec_espi_io_regs * iobase)181 uint32_t mec_hal_espi_fc_max_pld_sz(struct mec_espi_io_regs *iobase)
182 {
183 uint32_t exp = 0;
184
185 exp = (iobase->FCCFG & MEC_ESPI_IO_FCCFG_MAX_PLD_SZ_Msk) >> MEC_ESPI_IO_FCCFG_MAX_PLD_SZ_Pos;
186 if ((exp == 0u) || (exp > 3u)) { /* reserved values */
187 return 0u;
188 }
189
190 exp += 5u;
191
192 return (1u << exp);
193 }
194
195 /* Return the two allowed erase block sizes in b[15:0] and b[31:16] in units
196 * of KB. If only one erase size allowed both fields will be identical.
197 * A return value of 0 indicates the flash channel has not been properly
198 * configured during eSPI link negoitation.
199 */
mec_hal_espi_fc_get_erase_sz(struct mec_espi_io_regs * iobase)200 uint32_t mec_hal_espi_fc_get_erase_sz(struct mec_espi_io_regs *iobase)
201 {
202 uint16_t erb1, erb2;
203 uint8_t ersz_encoding;
204
205 if (!iobase) {
206 return 0;
207 }
208
209 ersz_encoding =
210 (uint8_t)((iobase->FCCFG & MEC_ESPI_IO_FCCFG_EBSZ_Msk) >> MEC_ESPI_IO_FCCFG_EBSZ_Pos);
211 switch (ersz_encoding) {
212 case MEC_ESPI_IO_FCCFG_EBSZ_4KB:
213 erb1 = 4u;
214 erb2 = erb1;
215 break;
216 case MEC_ESPI_IO_FCCFG_EBSZ_64KB:
217 erb1 = 64u;
218 erb2 = erb1;
219 break;
220 case MEC_ESPI_IO_FCCFG_EBSZ_4KB_OR_64KB:
221 erb1 = 4u;
222 erb2 = 64u;
223 break;
224 case MEC_ESPI_IO_FCCFG_EBSZ_128KB:
225 erb1 = 128u;
226 erb2 = erb1;
227 break;
228 case MEC_ESPI_IO_FCCFG_EBSZ_256KB:
229 erb1 = 256u;
230 erb2 = erb1;
231 break;
232 default:
233 erb1 = 0;
234 erb2 = 0;
235 break;
236 }
237
238 return (uint32_t)erb1 + ((uint32_t)erb2 << 16);
239 }
240
mec_hal_espi_fc_check_erase_sz(struct mec_espi_io_regs * iobase,uint32_t ersz_bytes)241 int mec_hal_espi_fc_check_erase_sz(struct mec_espi_io_regs *iobase, uint32_t ersz_bytes)
242 {
243 uint32_t ersz = mec_hal_espi_fc_get_erase_sz(iobase);
244 uint32_t er1 = (ersz & 0xffffu) * 1024u;
245 uint32_t er2 = ((ersz >> 16) & 0xffffu) * 1024u;
246
247 if ((ersz_bytes == er1) || (ersz_bytes == er2)) {
248 return MEC_RET_OK;
249 }
250
251 return MEC_RET_ERR_DATA_LEN;
252 }
253
254 /* Start transmit of a flash request to the eSPI Host Controller.
255 * Operations are: read, erase, or write. The caller can select
256 * from two erase operations: Ask Host to erase smaller or larger
257 * of two address ranges if the Host has a choice. This is based
258 * upon flash devices connected to Host chipset and its policies.
259 * The specs recommend using a value of 1 for erase size in the
260 * request packet sent to the Host.
261 * Read and write operations data lengths must be non-zero. The
262 * FC hardware will break up requests into chunks of maximum payload
263 * size. FC hardware will signal done or error when the last request
264 * is done or there was an error on any packet in the transaction.
265 */
mec_hal_espi_fc_xfr_start(struct mec_espi_io_regs * iobase,struct mec_espi_fc_xfr * pxfr,uint32_t flags)266 int mec_hal_espi_fc_xfr_start(struct mec_espi_io_regs *iobase,
267 struct mec_espi_fc_xfr *pxfr,
268 uint32_t flags)
269 {
270 uint32_t xfr_len, fc_op;
271
272 if (!iobase || !pxfr || !pxfr->byte_len || !pxfr->buf_addr
273 || (pxfr->operation >= MEC_ESPI_FC_OP_MAX)) {
274 return MEC_RET_ERR_INVAL;
275 }
276
277 if (!MEC_IS_PTR_ALIGNED32(pxfr->buf_addr)) {
278 return MEC_RET_ERR_DATA_ALIGN;
279 }
280
281 if (mec_hal_espi_fc_is_ready(iobase)) {
282 return MEC_RET_ERR_HW_NOT_INIT;
283 }
284
285 if (mec_hal_espi_fc_is_busy(iobase)) {
286 return MEC_RET_ERR_BUSY;
287 }
288
289 switch (pxfr->operation) {
290 case MEC_ESPI_FC_OP_ERASE_L:
291 fc_op = MEC_ESPI_IO_FCCTL_OP_ERASE_LARGER;
292 xfr_len = MEC_ESPI_FC_ERASE_SIZE;
293 break;
294 case MEC_ESPI_FC_OP_ERASE_S:
295 fc_op = MEC_ESPI_IO_FCCTL_OP_ERASE_SMALLER;
296 xfr_len = MEC_ESPI_FC_ERASE_SIZE;
297 break;
298 case MEC_ESPI_FC_OP_WRITE:
299 fc_op = MEC_ESPI_IO_FCCTL_OP_WRITE;
300 xfr_len = pxfr->byte_len;
301 break;
302 default:
303 fc_op = MEC_ESPI_IO_FCCTL_OP_READ;
304 xfr_len = pxfr->byte_len;
305 break;
306 }
307
308 iobase->FCIEN &= (uint32_t)~MEC_BIT(MEC_ESPI_IO_FCIEN_DONE_Pos);
309 iobase->FCSTS = MEC_ESPI_FC_ERR_ALL | MEC_BIT(MEC_ESPI_IO_FCSTS_DONE_Pos);
310 iobase->FCFA = pxfr->flash_addr;
311 iobase->FCBA = pxfr->buf_addr;
312 iobase->FCLEN = xfr_len;
313 if (flags & MEC_BIT(MEC_ESPI_FC_XFR_FLAG_START_IEN_POS)) {
314 iobase->FCIEN |= MEC_BIT(MEC_ESPI_IO_FCIEN_DONE_Pos);
315 }
316
317 iobase->FCCTL = ((((uint32_t)pxfr->tag << MEC_ESPI_IO_FCCTL_TAG_Pos)
318 & MEC_ESPI_IO_FCCTL_TAG_Msk)
319 | ((fc_op << MEC_ESPI_IO_FCCTL_OP_Pos) & MEC_ESPI_IO_FCCTL_OP_Msk)
320 | MEC_BIT(MEC_ESPI_IO_FCCTL_START_Pos));
321
322 return MEC_RET_OK;
323 }
324
325 /* end mec_espi_fc.c */
326