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)&regs->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)&regs->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