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_defs.h"
11 #include "mec_adc_api.h"
12 #include "mec_ecia_api.h"
13 #include "mec_eeprom_api.h"
14 #include "mec_pcr_api.h"
15 #include "mec_retval.h"
16
17 #define MEC_EEPROM_GIRQ 18
18 #define MEC_EEPROM_GIRQ_POS 13
19 #define MEC_EEPROM_AGGR_NVIC 10
20 #define MEC_EEPROM_DIRECT_NVIC 155
21 #define MEC_EEPROM_ECIA_INFO \
22 MEC5_ECIA_INFO(MEC_EEPROM_GIRQ, MEC_EEPROM_GIRQ_POS, \
23 MEC_EEPROM_AGGR_NVIC, MEC_EEPROM_DIRECT_NVIC)
24
25 /* ---- Public API ---- */
26
27 /* Initialize EEPROM controller */
mec_hal_eeprom_init(struct mec_eeprom_ctrl_regs * regs,uint32_t flags,uint32_t password)28 int mec_hal_eeprom_init(struct mec_eeprom_ctrl_regs *regs, uint32_t flags, uint32_t password)
29 {
30 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
31 return MEC_RET_ERR_INVAL;
32 }
33
34 mec_hal_pcr_clr_blk_slp_en(MEC_PCR_PSPI); /* clear sleep enable */
35
36 mec_hal_girq_ctrl(MEC_EEPROM_ECIA_INFO, 0);
37 mec_hal_girq_clr_src(MEC_EEPROM_ECIA_INFO);
38
39 if (flags & MEC_HAL_EEPROM_CFG_SRST) {
40 regs->MODE |= MEC_BIT(MEC_EEPROM_CTRL_MODE_SRST_Pos);
41 } else {
42 regs->MODE = 0;
43 regs->INTR_EN = 0;
44 regs->STATUS = UINT32_MAX;
45 }
46
47 if (flags & MEC_HAL_EEPROM_CFG_LOAD_PSWD) {
48 regs->PSWD = password;
49 }
50
51 if (flags & MEC_HAL_EEPROM_CFG_LOCK_ON_PSWD) {
52 regs->LOCK |= MEC_BIT(MEC_EEPROM_CTRL_LOCK_LOCK_Pos);
53 }
54
55 if (flags & MEC_HAL_EEPROM_CFG_LOCK_ON_JTAG) {
56 regs->LOCK |= MEC_BIT(MEC_EEPROM_CTRL_LOCK_JTAG_LOCK_Pos);
57 }
58
59 if (flags & MEC_HAL_EEPROM_CFG_DONE_IEN) {
60 regs->INTR_EN |= MEC_BIT(MEC_EEPROM_CTRL_INTR_EN_XFR_DONE_Pos);
61 }
62 if (flags & MEC_HAL_EEPROM_CFG_EXE_ERR_IEN) {
63 regs->INTR_EN |= MEC_BIT(MEC_EEPROM_CTRL_INTR_EN_ERROR_Pos);
64 }
65
66 if (flags & MEC_HAL_EEPROM_CFG_ENABLE) {
67 regs->MODE |= MEC_BIT(MEC_EEPROM_CTRL_MODE_ACTV_Pos);
68 }
69
70 return MEC_RET_OK;
71 }
72
mec_hal_eeprom_girq_ctrl(struct mec_eeprom_ctrl_regs * regs,uint8_t enable)73 int mec_hal_eeprom_girq_ctrl(struct mec_eeprom_ctrl_regs *regs, uint8_t enable)
74 {
75 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
76 return MEC_RET_ERR_INVAL;
77 }
78
79 mec_hal_girq_ctrl(MEC_EEPROM_ECIA_INFO, enable);
80
81 return 0;
82 }
83
mec_hal_eeprom_girq_status_clr(struct mec_eeprom_ctrl_regs * regs)84 int mec_hal_eeprom_girq_status_clr(struct mec_eeprom_ctrl_regs *regs)
85 {
86 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
87 return MEC_RET_ERR_INVAL;
88 }
89
90 mec_hal_girq_clr_src(MEC_EEPROM_ECIA_INFO);
91
92 return 0;
93 }
94
mec_hal_eeprom_activate(struct mec_eeprom_ctrl_regs * regs,uint8_t enable)95 int mec_hal_eeprom_activate(struct mec_eeprom_ctrl_regs *regs, uint8_t enable)
96 {
97 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
98 return MEC_RET_ERR_INVAL;
99 }
100
101 if (enable) {
102 regs->MODE |= MEC_BIT(MEC_EEPROM_CTRL_MODE_ACTV_Pos);
103 } else {
104 regs->MODE &= (uint32_t)~MEC_BIT(MEC_EEPROM_CTRL_MODE_ACTV_Pos);
105 }
106
107 return MEC_RET_OK;
108 }
109
mec_hal_eeprom_status(struct mec_eeprom_ctrl_regs * regs)110 uint32_t mec_hal_eeprom_status(struct mec_eeprom_ctrl_regs *regs)
111 {
112 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
113 return 0;
114 }
115
116 return regs->STATUS;
117 }
118
mec_hal_eeprom_status_clr(struct mec_eeprom_ctrl_regs * regs,uint32_t clrmsk)119 int mec_hal_eeprom_status_clr(struct mec_eeprom_ctrl_regs *regs, uint32_t clrmsk)
120 {
121 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
122 return MEC_RET_ERR_INVAL;
123 }
124
125 regs->STATUS = clrmsk;
126
127 return MEC_RET_OK;
128 }
129
mec_hal_eeprom_is_busy(struct mec_eeprom_ctrl_regs * regs)130 bool mec_hal_eeprom_is_busy(struct mec_eeprom_ctrl_regs *regs)
131 {
132 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
133 return false;
134 }
135
136 if (regs->STATUS & MEC_BIT(MEC_EEPROM_CTRL_STATUS_XFR_ACTIVE_Pos)) {
137 return true;
138 }
139
140 return false;
141 }
142
mec_hal_eeprom_intr_en(struct mec_eeprom_ctrl_regs * regs,uint8_t enable,uint32_t flags)143 int mec_hal_eeprom_intr_en(struct mec_eeprom_ctrl_regs *regs, uint8_t enable, uint32_t flags)
144 {
145 uint32_t msk = 0, rval = 0;
146
147 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
148 return MEC_RET_ERR_INVAL;
149 }
150
151 if (flags & MEC_BIT(MEC_HAL_EEPROM_INTR_DONE_POS)) {
152 msk |= MEC_BIT(MEC_EEPROM_CTRL_INTR_EN_XFR_DONE_Pos);
153 if (enable) {
154 rval |= MEC_BIT(MEC_EEPROM_CTRL_INTR_EN_XFR_DONE_Pos);
155 }
156 }
157 if (flags & MEC_BIT(MEC_HAL_EEPROM_INTR_ERR_POS)) {
158 msk |= MEC_BIT(MEC_EEPROM_CTRL_INTR_EN_ERROR_Pos);
159 if (enable) {
160 rval |= MEC_BIT(MEC_EEPROM_CTRL_INTR_EN_XFR_DONE_Pos);
161 }
162 }
163
164 if (msk) {
165 regs->INTR_EN = (regs->INTR_EN & (uint32_t)~msk) | rval;
166 }
167
168 return 0;
169 }
170
171 /* Write-once. No indicator if it has been written before */
mec_hal_eeprom_set_password(struct mec_eeprom_ctrl_regs * regs,uint32_t password)172 int mec_hal_eeprom_set_password(struct mec_eeprom_ctrl_regs *regs, uint32_t password)
173 {
174 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
175 return MEC_RET_ERR_INVAL;
176 }
177
178 regs->PSWD = password;
179
180 return MEC_RET_OK;
181 }
182
mec_hal_eeprom_lock(struct mec_eeprom_ctrl_regs * regs)183 int mec_hal_eeprom_lock(struct mec_eeprom_ctrl_regs *regs)
184 {
185 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
186 return MEC_RET_ERR_INVAL;
187 }
188
189 regs->LOCK |= MEC_BIT(MEC_EEPROM_CTRL_LOCK_LOCK_Pos);
190
191 return MEC_RET_OK;
192 }
193
mec_hal_eeprom_is_locked(struct mec_eeprom_ctrl_regs * regs)194 bool mec_hal_eeprom_is_locked(struct mec_eeprom_ctrl_regs *regs)
195 {
196 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
197 return false;
198 }
199
200 if (regs->LOCK & MEC_BIT(MEC_EEPROM_CTRL_LOCK_LOCK_Pos)) {
201 return true;
202 }
203
204 return false;
205 }
206
mec_hal_eeprom_unlock(struct mec_eeprom_ctrl_regs * regs,uint32_t password)207 int mec_hal_eeprom_unlock(struct mec_eeprom_ctrl_regs *regs, uint32_t password)
208 {
209 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
210 return MEC_RET_ERR_INVAL;
211 }
212
213 regs->PSWD = password;
214
215 return MEC_RET_OK;
216 }
217
mec_hal_eeprom_buffer_rd(struct mec_eeprom_ctrl_regs * regs,uint8_t * dest,uint32_t nbytes)218 int mec_hal_eeprom_buffer_rd(struct mec_eeprom_ctrl_regs *regs, uint8_t *dest, uint32_t nbytes)
219 {
220 uint32_t buf_addr = 0;
221
222 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
223 return MEC_RET_ERR_INVAL;
224 }
225
226 if (!dest || !nbytes || (nbytes > MEC_HAL_EEPROM_MAX_XFR_LEN)) {
227 return MEC_RET_ERR_INVAL;
228 }
229
230
231 buf_addr = (uint32_t)®s->DATA;
232 for (uint32_t n = 0; n < nbytes; n++) {
233 dest[n] = MEC_MMCR8(buf_addr);
234 buf_addr++;
235 }
236
237 return MEC_RET_OK;
238 }
239
mec_hal_eeprom_buffer_wr(struct mec_eeprom_ctrl_regs * regs,const uint8_t * src,uint32_t nbytes)240 int mec_hal_eeprom_buffer_wr(struct mec_eeprom_ctrl_regs *regs, const uint8_t *src,
241 uint32_t nbytes)
242 {
243 uint32_t buf_addr = 0;
244
245 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
246 return MEC_RET_ERR_INVAL;
247 }
248
249 if (!src || !nbytes || (nbytes > MEC_HAL_EEPROM_MAX_XFR_LEN)) {
250 return MEC_RET_ERR_INVAL;
251 }
252
253 buf_addr = (uint32_t)®s->DATA;
254 for (uint32_t n = 0; n < nbytes; n++) {
255 MEC_MMCR8(buf_addr) = src[n];
256 buf_addr++;
257 }
258
259 return MEC_RET_OK;
260 }
261
262
263 /* Send command to EEPROM
264 * Read/Write data. Read can be at any address.
265 * Writes cannot cross any 32 byte page boundary.
266 * Read/Write Status
267 * Timing: read transfer 7 us / byte plus 50 us if full 32-bytes.
268 * write transfer ~5ms
269 */
270 /* TODO BUG
271 * if op is MEC_HAL_EEPROM_OP_READ_STATUS then offset and nbytes are don't cares
272 * if op is MEC_HAL_EEPROM_OP_WRITE_STATUS then offset is don't care and nbytes should be 1
273 */
mec_hal_eeprom_xfr_start(struct mec_eeprom_ctrl_regs * regs,uint8_t op,uint32_t offset,uint32_t nbytes)274 int mec_hal_eeprom_xfr_start(struct mec_eeprom_ctrl_regs *regs, uint8_t op,
275 uint32_t offset, uint32_t nbytes)
276 {
277 uint32_t rexe = 0, temp = 0;
278 uint8_t cmd = 0;
279 uint8_t xfrsz = 0; /* 0 transfer size encoded in HW as maximum (32 bytes) */
280
281 if ((uintptr_t)regs != (uintptr_t)MEC_EEPROM_CTRL0_BASE) {
282 return MEC_RET_ERR_INVAL;
283 }
284
285 if (op == MEC_HAL_EEPROM_OP_READ_DATA) {
286 if (!nbytes) {
287 return MEC_RET_ERR_INVAL;
288 }
289 /* reads can cross page boundaries */
290 if (nbytes < MEC_HAL_EEPROM_MAX_XFR_LEN) {
291 xfrsz = (uint8_t)nbytes;
292 }
293 rexe = ((uint32_t)offset << MEC_EEPROM_CTRL_EXE_TADDR_Pos)
294 & MEC_EEPROM_CTRL_EXE_TADDR_Msk;
295 cmd = MEC_EEPROM_CTRL0_EXE_CMD_READ;
296 } else if (op == MEC_HAL_EEPROM_OP_WRITE_DATA) {
297 if (!nbytes) {
298 return MEC_RET_ERR_INVAL;
299 }
300 /* writes cannot cross 32-byte page boundaries */
301 xfrsz = (uint8_t)nbytes;
302 rexe = offset & (MEC5_EEPROM_SIZE_IN_BYTES - 1u);
303 temp = MEC5_EEPROM_WRITE_PAGE_SIZE - (rexe % MEC5_EEPROM_WRITE_PAGE_SIZE);
304 if ((uint32_t)xfrsz > temp) {
305 xfrsz = (uint8_t)temp;
306 }
307 if (xfrsz >= MEC5_EEPROM_WRITE_PAGE_SIZE) {
308 xfrsz = 0;
309 }
310 rexe <<= MEC_EEPROM_CTRL_EXE_TADDR_Pos;
311 rexe &= MEC_EEPROM_CTRL_EXE_TADDR_Msk;
312 cmd = MEC_EEPROM_CTRL0_EXE_CMD_WRITE;
313 } else if (op == MEC_HAL_EEPROM_OP_READ_STATUS) {
314 /* offset and nbytes are don't cares */
315 cmd = MEC_EEPROM_CTRL0_EXE_CMD_RDSTS;
316 } else if (op == MEC_HAL_EEPROM_OP_WRITE_STATUS) {
317 /* offset is don't care. Data sheet is not clear if nbytes is don't care */
318 cmd = MEC_EEPROM_CTRL0_EXE_CMD_WRSTS;
319 } else {
320 return MEC_RET_ERR_INVAL;
321 }
322
323 rexe |= ((uint32_t)cmd << MEC_EEPROM_CTRL_EXE_CMD_Pos) |
324 (((uint32_t)xfrsz << MEC_EEPROM_CTRL_EXE_XFRSZ_Pos)
325 & MEC_EEPROM_CTRL_EXE_XFRSZ_Msk);
326
327 regs->EXE = rexe; /* transfer started */
328
329 return MEC_RET_OK;
330 }
331
332 /* end mec_eeprom.c */
333