1 /*
2 * Copyright (c) 2022 Microchip Technology Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT microchip_xec_eeprom
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/eeprom.h>
11 #include <zephyr/kernel.h>
12 #include <soc.h>
13
14 #include <zephyr/drivers/pinctrl.h>
15
16 #include <zephyr/logging/log.h>
17 #include <zephyr/pm/device.h>
18 #include <zephyr/pm/policy.h>
19
20 LOG_MODULE_REGISTER(eeprom_xec, CONFIG_EEPROM_LOG_LEVEL);
21
22 /* EEPROM Mode Register */
23 #define XEC_EEPROM_MODE_ACTIVATE BIT(0)
24
25 /* EEPROM Status Register */
26 #define XEC_EEPROM_STS_TRANSFER_COMPL BIT(0)
27
28 /* EEPROM Execute Register - Transfer size bit position */
29 #define XEC_EEPROM_EXC_TRANSFER_SZ_BITPOS (24)
30
31 /* EEPROM Execute Register - Commands */
32 #define XEC_EEPROM_EXC_CMD_READ 0x00000U
33 #define XEC_EEPROM_EXC_CMD_WRITE 0x10000U
34 #define XEC_EEPROM_EXC_CMD_READ_STS 0x20000U
35 #define XEC_EEPROM_EXC_CMD_WRITE_STS 0x30000U
36
37 /* EEPROM Execute Register - Address mask */
38 #define XEC_EEPROM_EXC_ADDR_MASK 0x7FFU
39
40 /* EEPROM Status Byte */
41 #define XEC_EEPROM_STS_BYTE_WIP BIT(0)
42 #define XEC_EEPROM_STS_BYTE_WENB BIT(1)
43
44 /* EEPROM Read/Write Transfer Size */
45 #define XEC_EEPROM_PAGE_SIZE 32U
46 #define XEC_EEPROM_TRANSFER_SIZE_READ XEC_EEPROM_PAGE_SIZE
47 #define XEC_EEPROM_TRANSFER_SIZE_WRITE XEC_EEPROM_PAGE_SIZE
48
49 #define XEC_EEPROM_DELAY_US 500U
50 #define XEC_EEPROM_DELAY_BUSY_POLL_US 50U
51 #define XEC_EEPROM_XFER_COMPL_RETRY_COUNT 10U
52
53 struct eeprom_xec_regs {
54 uint32_t mode;
55 uint32_t execute;
56 uint32_t status;
57 uint32_t intr_enable;
58 uint32_t password;
59 uint32_t unlock;
60 uint32_t lock;
61 uint32_t _reserved;
62 uint8_t buffer[XEC_EEPROM_PAGE_SIZE];
63 };
64
65 struct eeprom_xec_config {
66 struct eeprom_xec_regs * const regs;
67 size_t size;
68 const struct pinctrl_dev_config *pcfg;
69 };
70
71 struct eeprom_xec_data {
72 struct k_mutex lock_mtx;
73 };
74
eeprom_xec_execute_reg_set(struct eeprom_xec_regs * const regs,uint32_t transfer_size,uint32_t command,uint16_t eeprom_addr)75 static void eeprom_xec_execute_reg_set(struct eeprom_xec_regs * const regs,
76 uint32_t transfer_size, uint32_t command,
77 uint16_t eeprom_addr)
78 {
79 uint32_t temp = command + (eeprom_addr & XEC_EEPROM_EXC_ADDR_MASK);
80
81 if (transfer_size != XEC_EEPROM_PAGE_SIZE) {
82 temp += (transfer_size << XEC_EEPROM_EXC_TRANSFER_SZ_BITPOS);
83 }
84 regs->execute = temp;
85 }
86
eeprom_xec_data_buffer_read(struct eeprom_xec_regs * const regs,uint8_t transfer_size,uint8_t * destination_ptr)87 static uint8_t eeprom_xec_data_buffer_read(struct eeprom_xec_regs * const regs,
88 uint8_t transfer_size, uint8_t *destination_ptr)
89 {
90 uint8_t count;
91
92 if (transfer_size > XEC_EEPROM_PAGE_SIZE) {
93 transfer_size = XEC_EEPROM_PAGE_SIZE;
94 }
95 for (count = 0; count < transfer_size; count++) {
96 *destination_ptr = regs->buffer[count];
97 destination_ptr++;
98 }
99
100 return transfer_size;
101 }
102
eeprom_xec_data_buffer_write(struct eeprom_xec_regs * const regs,uint8_t transfer_size,uint8_t * source_ptr)103 static uint8_t eeprom_xec_data_buffer_write(struct eeprom_xec_regs * const regs,
104 uint8_t transfer_size, uint8_t *source_ptr)
105 {
106 uint8_t count;
107
108 if (transfer_size > XEC_EEPROM_PAGE_SIZE) {
109 transfer_size = XEC_EEPROM_PAGE_SIZE;
110 }
111 for (count = 0; count < transfer_size; count++) {
112 regs->buffer[count] = *source_ptr;
113 source_ptr++;
114 }
115
116 return transfer_size;
117 }
118
eeprom_xec_wait_transfer_compl(struct eeprom_xec_regs * const regs)119 static void eeprom_xec_wait_transfer_compl(struct eeprom_xec_regs * const regs)
120 {
121 uint8_t sts = 0;
122 uint8_t retry_count = 0;
123
124 k_sleep(K_USEC(XEC_EEPROM_DELAY_US));
125
126 do {
127 if (retry_count >= XEC_EEPROM_XFER_COMPL_RETRY_COUNT) {
128 LOG_ERR("XEC EEPROM retry count exceeded");
129 break;
130 }
131 k_sleep(K_USEC(XEC_EEPROM_DELAY_BUSY_POLL_US));
132
133 sts = XEC_EEPROM_STS_TRANSFER_COMPL & regs->status;
134 retry_count++;
135
136 } while (sts == 0);
137
138 if (sts != 0) {
139 /* Clear the appropriate status bits */
140 regs->status = XEC_EEPROM_STS_TRANSFER_COMPL;
141 }
142 }
143
eeprom_xec_wait_write_compl(struct eeprom_xec_regs * const regs)144 static void eeprom_xec_wait_write_compl(struct eeprom_xec_regs * const regs)
145 {
146 uint8_t sts = 0;
147 uint8_t retry_count = 0;
148
149 do {
150 if (retry_count >= XEC_EEPROM_XFER_COMPL_RETRY_COUNT) {
151 LOG_ERR("XEC EEPROM retry count exceeded");
152 break;
153 }
154
155 regs->buffer[0] = 0;
156
157 /* Issue the READ_STS command */
158 regs->execute = XEC_EEPROM_EXC_CMD_READ_STS;
159
160 eeprom_xec_wait_transfer_compl(regs);
161
162 sts = regs->buffer[0] & (XEC_EEPROM_STS_BYTE_WIP |
163 XEC_EEPROM_STS_BYTE_WENB);
164
165 retry_count++;
166
167 } while (sts != 0);
168 }
169
eeprom_xec_data_read_32_bytes(struct eeprom_xec_regs * const regs,uint8_t * buf,size_t len,off_t offset)170 static void eeprom_xec_data_read_32_bytes(struct eeprom_xec_regs * const regs,
171 uint8_t *buf, size_t len, off_t offset)
172 {
173 /* Issue the READ command to transfer buffer to EEPROM memory */
174 eeprom_xec_execute_reg_set(regs, len, XEC_EEPROM_EXC_CMD_READ, offset);
175
176 /* Wait until the read operation has completed */
177 eeprom_xec_wait_transfer_compl(regs);
178
179 /* Read the data in to the software buffer */
180 eeprom_xec_data_buffer_read(regs, len, buf);
181 }
182
eeprom_xec_data_write_32_bytes(struct eeprom_xec_regs * const regs,uint8_t * buf,size_t len,off_t offset)183 static void eeprom_xec_data_write_32_bytes(struct eeprom_xec_regs * const regs,
184 uint8_t *buf, size_t len, off_t offset)
185 {
186 uint16_t sz;
187 uint16_t rem_bytes;
188
189 sz = offset % XEC_EEPROM_PAGE_SIZE;
190
191 /* If EEPROM Addr is not on page boundary */
192 if (sz != 0) {
193 /* Check if we are crossing page boundary */
194 if ((sz + len) > XEC_EEPROM_PAGE_SIZE) {
195 rem_bytes = (XEC_EEPROM_PAGE_SIZE - sz);
196 /* Update the EEPROM buffer */
197 eeprom_xec_data_buffer_write(regs, rem_bytes, buf);
198
199 /* Issue the WRITE command to transfer buffer to EEPROM memory */
200 eeprom_xec_execute_reg_set(regs, rem_bytes,
201 XEC_EEPROM_EXC_CMD_WRITE, offset);
202
203 eeprom_xec_wait_transfer_compl(regs);
204
205 eeprom_xec_wait_write_compl(regs);
206
207 offset += rem_bytes;
208 buf += rem_bytes;
209 len = (len - rem_bytes);
210 }
211 }
212 /* Update the EEPROM buffer */
213 eeprom_xec_data_buffer_write(regs, len, buf);
214
215 /* Issue the WRITE command to transfer buffer to EEPROM memory */
216 eeprom_xec_execute_reg_set(regs, len, XEC_EEPROM_EXC_CMD_WRITE, offset);
217
218 eeprom_xec_wait_transfer_compl(regs);
219
220 eeprom_xec_wait_write_compl(regs);
221 }
222
eeprom_xec_read(const struct device * dev,off_t offset,void * buf,size_t len)223 static int eeprom_xec_read(const struct device *dev, off_t offset,
224 void *buf,
225 size_t len)
226 {
227 const struct eeprom_xec_config *config = dev->config;
228 struct eeprom_xec_data * const data = dev->data;
229 struct eeprom_xec_regs * const regs = config->regs;
230 uint8_t *data_buf = (uint8_t *)buf;
231 uint32_t chunk_idx = 0;
232 uint32_t chunk_size = XEC_EEPROM_TRANSFER_SIZE_READ;
233
234 if (len == 0) {
235 return 0;
236 }
237
238 if ((offset + len) > config->size) {
239 LOG_WRN("attempt to read past device boundary");
240 return -EINVAL;
241 }
242
243 k_mutex_lock(&data->lock_mtx, K_FOREVER);
244 pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
245
246 /* EEPROM HW READ */
247 for (chunk_idx = 0; chunk_idx < len; chunk_idx += XEC_EEPROM_TRANSFER_SIZE_READ) {
248 if ((len-chunk_idx) < XEC_EEPROM_TRANSFER_SIZE_READ) {
249 chunk_size = (len-chunk_idx);
250 }
251 eeprom_xec_data_read_32_bytes(regs, &data_buf[chunk_idx],
252 chunk_size, (offset+chunk_idx));
253 }
254 pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
255 k_mutex_unlock(&data->lock_mtx);
256
257 return 0;
258 }
259
eeprom_xec_write(const struct device * dev,off_t offset,const void * buf,size_t len)260 static int eeprom_xec_write(const struct device *dev, off_t offset,
261 const void *buf, size_t len)
262 {
263 const struct eeprom_xec_config *config = dev->config;
264 struct eeprom_xec_data * const data = dev->data;
265 struct eeprom_xec_regs * const regs = config->regs;
266 uint8_t *data_buf = (uint8_t *)buf;
267 uint32_t chunk_idx = 0;
268 uint32_t chunk_size = XEC_EEPROM_TRANSFER_SIZE_WRITE;
269
270 if (len == 0) {
271 return 0;
272 }
273
274 if ((offset + len) > config->size) {
275 LOG_WRN("attempt to write past device boundary");
276 return -EINVAL;
277 }
278
279 k_mutex_lock(&data->lock_mtx, K_FOREVER);
280 pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
281
282 /* EEPROM HW WRITE */
283 for (chunk_idx = 0; chunk_idx < len; chunk_idx += XEC_EEPROM_TRANSFER_SIZE_WRITE) {
284 if ((len-chunk_idx) < XEC_EEPROM_TRANSFER_SIZE_WRITE) {
285 chunk_size = (len-chunk_idx);
286 }
287 eeprom_xec_data_write_32_bytes(regs, &data_buf[chunk_idx],
288 chunk_size, (offset+chunk_idx));
289 }
290
291 pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
292 k_mutex_unlock(&data->lock_mtx);
293
294 return 0;
295 }
296
eeprom_xec_size(const struct device * dev)297 static size_t eeprom_xec_size(const struct device *dev)
298 {
299 const struct eeprom_xec_config *config = dev->config;
300
301 return config->size;
302 }
303
304 #ifdef CONFIG_PM_DEVICE
eeprom_xec_pm_action(const struct device * dev,enum pm_device_action action)305 static int eeprom_xec_pm_action(const struct device *dev, enum pm_device_action action)
306 {
307 const struct eeprom_xec_config *const devcfg = dev->config;
308 struct eeprom_xec_regs * const regs = devcfg->regs;
309 int ret;
310
311 switch (action) {
312 case PM_DEVICE_ACTION_RESUME:
313 ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT);
314 if (ret != 0) {
315 LOG_ERR("XEC EEPROM pinctrl setup failed (%d)", ret);
316 return ret;
317 }
318 regs->mode |= XEC_EEPROM_MODE_ACTIVATE;
319 break;
320 case PM_DEVICE_ACTION_SUSPEND:
321 /* Disable EEPROM Controller */
322 regs->mode &= (~XEC_EEPROM_MODE_ACTIVATE);
323 ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_SLEEP);
324 /* pinctrl-1 does not exist. */
325 if (ret == -ENOENT) {
326 ret = 0;
327 }
328 break;
329 default:
330 ret = -ENOTSUP;
331 }
332
333 return ret;
334 }
335 #endif /* CONFIG_PM_DEVICE */
336
eeprom_xec_init(const struct device * dev)337 static int eeprom_xec_init(const struct device *dev)
338 {
339 const struct eeprom_xec_config *config = dev->config;
340 struct eeprom_xec_data * const data = dev->data;
341 struct eeprom_xec_regs * const regs = config->regs;
342
343 k_mutex_init(&data->lock_mtx);
344
345 int ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
346
347 if (ret != 0) {
348 LOG_ERR("XEC EEPROM pinctrl init failed (%d)", ret);
349 return ret;
350 }
351
352 regs->mode |= XEC_EEPROM_MODE_ACTIVATE;
353
354 return 0;
355 }
356
357 static DEVICE_API(eeprom, eeprom_xec_api) = {
358 .read = eeprom_xec_read,
359 .write = eeprom_xec_write,
360 .size = eeprom_xec_size,
361 };
362
363 PINCTRL_DT_INST_DEFINE(0);
364
365 static const struct eeprom_xec_config eeprom_config = {
366 .regs = (struct eeprom_xec_regs * const)DT_INST_REG_ADDR(0),
367 .size = DT_INST_PROP(0, size),
368 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
369 };
370
371 static struct eeprom_xec_data eeprom_data;
372
373 PM_DEVICE_DT_INST_DEFINE(0, eeprom_xec_pm_action);
374
375 DEVICE_DT_INST_DEFINE(0, &eeprom_xec_init, PM_DEVICE_DT_INST_GET(0), &eeprom_data,
376 &eeprom_config, POST_KERNEL,
377 CONFIG_EEPROM_INIT_PRIORITY, &eeprom_xec_api);
378