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