1 /*
2  * Copyright (c) 2018 Google LLC.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT atmel_sam0_nvmctrl
8 #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)
9 
10 #define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(flash_sam0);
13 
14 #include <zephyr/device.h>
15 #include <zephyr/drivers/flash.h>
16 #include <zephyr/init.h>
17 #include <zephyr/kernel.h>
18 #include <soc.h>
19 #include <string.h>
20 
21 #define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size)
22 BUILD_ASSERT((FLASH_WRITE_BLK_SZ % sizeof(uint32_t)) == 0, "unsupported write-block-size");
23 
24 /*
25  * Zephyr and the SAM0 series use different and conflicting names for
26  * the erasable units and programmable units:
27  *
28  * The erase unit is a row, which is a 'page' in Zephyr terms.
29  * The program unit is a page, which is a 'write_block' in Zephyr.
30  *
31  * This file uses the SAM0 names internally and the Zephyr names in
32  * any error messages.
33  */
34 
35 /*
36  * Number of lock regions.  The number is fixed and the region size
37  * grows with the flash size.
38  */
39 #define LOCK_REGIONS DT_INST_PROP(0, lock_regions)
40 #define LOCK_REGION_SIZE (FLASH_SIZE / LOCK_REGIONS)
41 
42 #if defined(NVMCTRL_BLOCK_SIZE)
43 #define ROW_SIZE NVMCTRL_BLOCK_SIZE
44 #elif defined(NVMCTRL_ROW_SIZE)
45 #define ROW_SIZE NVMCTRL_ROW_SIZE
46 #endif
47 
48 #define PAGES_PER_ROW (ROW_SIZE / FLASH_PAGE_SIZE)
49 
50 #define FLASH_MEM(_a) ((uint32_t *)((uint8_t *)((_a) + CONFIG_FLASH_BASE_ADDRESS)))
51 
52 struct flash_sam0_data {
53 #if CONFIG_SOC_FLASH_SAM0_EMULATE_BYTE_PAGES
54 	/* NOTE: this buffer can be large, avoid placing it on the stack... */
55 	uint8_t buf[ROW_SIZE];
56 #endif
57 
58 #if defined(CONFIG_MULTITHREADING)
59 	struct k_sem sem;
60 #endif
61 };
62 
63 #if CONFIG_FLASH_PAGE_LAYOUT
64 static const struct flash_pages_layout flash_sam0_pages_layout = {
65 	.pages_count = CONFIG_FLASH_SIZE * 1024 / ROW_SIZE,
66 	.pages_size = ROW_SIZE,
67 };
68 #endif
69 
70 static const struct flash_parameters flash_sam0_parameters = {
71 #if CONFIG_SOC_FLASH_SAM0_EMULATE_BYTE_PAGES
72 	.write_block_size = 1,
73 #else
74 	.write_block_size = FLASH_WRITE_BLK_SZ,
75 #endif
76 	.erase_value = 0xff,
77 };
78 
79 static int flash_sam0_write_protection(const struct device *dev, bool enable);
80 
flash_sam0_sem_take(const struct device * dev)81 static inline void flash_sam0_sem_take(const struct device *dev)
82 {
83 #if defined(CONFIG_MULTITHREADING)
84 	struct flash_sam0_data *ctx = dev->data;
85 
86 	k_sem_take(&ctx->sem, K_FOREVER);
87 #endif
88 }
89 
flash_sam0_sem_give(const struct device * dev)90 static inline void flash_sam0_sem_give(const struct device *dev)
91 {
92 #if defined(CONFIG_MULTITHREADING)
93 	struct flash_sam0_data *ctx = dev->data;
94 
95 	k_sem_give(&ctx->sem);
96 #endif
97 }
98 
flash_sam0_valid_range(off_t offset,size_t len)99 static int flash_sam0_valid_range(off_t offset, size_t len)
100 {
101 	if (offset < 0) {
102 		LOG_WRN("0x%lx: before start of flash", (long)offset);
103 		return -EINVAL;
104 	}
105 	if ((offset + len) > CONFIG_FLASH_SIZE * 1024) {
106 		LOG_WRN("0x%lx: ends past the end of flash", (long)offset);
107 		return -EINVAL;
108 	}
109 
110 	return 0;
111 }
112 
flash_sam0_wait_ready(void)113 static void flash_sam0_wait_ready(void)
114 {
115 #ifdef NVMCTRL_STATUS_READY
116 	while (NVMCTRL->STATUS.bit.READY == 0) {
117 	}
118 #else
119 	while (NVMCTRL->INTFLAG.bit.READY == 0) {
120 	}
121 #endif
122 }
123 
flash_sam0_check_status(off_t offset)124 static int flash_sam0_check_status(off_t offset)
125 {
126 	flash_sam0_wait_ready();
127 
128 #ifdef NVMCTRL_INTFLAG_PROGE
129 	NVMCTRL_INTFLAG_Type status = NVMCTRL->INTFLAG;
130 
131 	/* Clear any flags */
132 	NVMCTRL->INTFLAG.reg = status.reg;
133 #else
134 	NVMCTRL_STATUS_Type status = NVMCTRL->STATUS;
135 
136 	/* Clear any flags */
137 	NVMCTRL->STATUS = status;
138 #endif
139 
140 	if (status.bit.PROGE) {
141 		LOG_ERR("programming error at 0x%lx", (long)offset);
142 		return -EIO;
143 	} else if (status.bit.LOCKE) {
144 		LOG_ERR("lock error at 0x%lx", (long)offset);
145 		return -EROFS;
146 	} else if (status.bit.NVME) {
147 		LOG_ERR("NVM error at 0x%lx", (long)offset);
148 		return -EIO;
149 	}
150 
151 	return 0;
152 }
153 
154 /*
155  * Data to be written to the NVM block are first written to and stored
156  * in an internal buffer called the page buffer. The page buffer contains
157  * the same number of bytes as an NVM page. Writes to the page buffer must
158  * be 16 or 32 bits. 8-bit writes to the page buffer are not allowed and
159  * will cause a system exception
160  */
flash_sam0_write_page(const struct device * dev,off_t offset,const void * data,size_t len)161 static int flash_sam0_write_page(const struct device *dev, off_t offset,
162 				 const void *data, size_t len)
163 {
164 	const uint32_t *src = data;
165 	const uint32_t *end = src + (len / sizeof(*src));
166 	uint32_t *dst = FLASH_MEM(offset);
167 	int err;
168 
169 #ifdef NVMCTRL_CTRLA_CMD_PBC
170 	NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_PBC | NVMCTRL_CTRLA_CMDEX_KEY;
171 #else
172 	NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMD_PBC | NVMCTRL_CTRLB_CMDEX_KEY;
173 #endif
174 	flash_sam0_wait_ready();
175 
176 	/* Ensure writes happen 32 bits at a time. */
177 	for (; src != end; src++, dst++) {
178 		*dst = UNALIGNED_GET((uint32_t *)src);
179 	}
180 
181 #ifdef NVMCTRL_CTRLA_CMD_WP
182 	NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_WP | NVMCTRL_CTRLA_CMDEX_KEY;
183 #else
184 	NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMD_WP | NVMCTRL_CTRLB_CMDEX_KEY;
185 #endif
186 
187 	err = flash_sam0_check_status(offset);
188 	if (err != 0) {
189 		return err;
190 	}
191 
192 	if (memcmp(data, FLASH_MEM(offset), len) != 0) {
193 		LOG_ERR("verify error at offset 0x%lx", (long)offset);
194 		return -EIO;
195 	}
196 
197 	return 0;
198 }
199 
flash_sam0_erase_row(const struct device * dev,off_t offset)200 static int flash_sam0_erase_row(const struct device *dev, off_t offset)
201 {
202 	*FLASH_MEM(offset) = 0U;
203 #ifdef NVMCTRL_CTRLA_CMD_ER
204 	NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_ER | NVMCTRL_CTRLA_CMDEX_KEY;
205 #else
206 	NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMD_EB | NVMCTRL_CTRLB_CMDEX_KEY;
207 #endif
208 	return flash_sam0_check_status(offset);
209 }
210 
211 #if CONFIG_SOC_FLASH_SAM0_EMULATE_BYTE_PAGES
212 
flash_sam0_commit(const struct device * dev,off_t base)213 static int flash_sam0_commit(const struct device *dev, off_t base)
214 {
215 	struct flash_sam0_data *ctx = dev->data;
216 	int err;
217 	int page;
218 
219 	err = flash_sam0_erase_row(dev, base);
220 	if (err != 0) {
221 		return err;
222 	}
223 
224 	for (page = 0; page < PAGES_PER_ROW; page++) {
225 		err = flash_sam0_write_page(
226 			dev, base + page * FLASH_PAGE_SIZE,
227 			&ctx->buf[page * FLASH_PAGE_SIZE], ROW_SIZE);
228 		if (err != 0) {
229 			return err;
230 		}
231 	}
232 
233 	return 0;
234 }
235 
flash_sam0_write(const struct device * dev,off_t offset,const void * data,size_t len)236 static int flash_sam0_write(const struct device *dev, off_t offset,
237 			    const void *data, size_t len)
238 {
239 	struct flash_sam0_data *ctx = dev->data;
240 	const uint8_t *pdata = data;
241 	int err;
242 
243 	LOG_DBG("0x%lx: len %zu", (long)offset, len);
244 
245 	err = flash_sam0_valid_range(offset, len);
246 	if (err != 0) {
247 		return err;
248 	}
249 
250 	if (len == 0) {
251 		return 0;
252 	}
253 
254 	flash_sam0_sem_take(dev);
255 
256 	err = flash_sam0_write_protection(dev, false);
257 
258 	size_t pos = 0;
259 
260 	while ((err == 0) && (pos < len)) {
261 		off_t  start    = offset % sizeof(ctx->buf);
262 		off_t  base     = offset - start;
263 		size_t len_step = sizeof(ctx->buf) - start;
264 		size_t len_copy = MIN(len - pos, len_step);
265 
266 		if (len_copy < sizeof(ctx->buf)) {
267 			memcpy(ctx->buf, (void *)base, sizeof(ctx->buf));
268 		}
269 		memcpy(&(ctx->buf[start]), &(pdata[pos]), len_copy);
270 		err = flash_sam0_commit(dev, base);
271 
272 		offset += len_step;
273 		pos    += len_copy;
274 	}
275 
276 	int err2 = flash_sam0_write_protection(dev, true);
277 
278 	if (!err) {
279 		err = err2;
280 	}
281 
282 	flash_sam0_sem_give(dev);
283 
284 	return err;
285 }
286 
287 #else /* CONFIG_SOC_FLASH_SAM0_EMULATE_BYTE_PAGES */
288 
flash_sam0_write(const struct device * dev,off_t offset,const void * data,size_t len)289 static int flash_sam0_write(const struct device *dev, off_t offset,
290 			    const void *data, size_t len)
291 {
292 	const uint8_t *pdata = data;
293 	int err;
294 
295 	err = flash_sam0_valid_range(offset, len);
296 	if (err != 0) {
297 		return err;
298 	}
299 
300 	if ((offset % FLASH_WRITE_BLK_SZ) != 0) {
301 		LOG_WRN("0x%lx: not on a write block boundary", (long)offset);
302 		return -EINVAL;
303 	}
304 
305 	if ((len % FLASH_WRITE_BLK_SZ) != 0) {
306 		LOG_WRN("%zu: not a integer number of write blocks", len);
307 		return -EINVAL;
308 	}
309 
310 	flash_sam0_sem_take(dev);
311 
312 	err = flash_sam0_write_protection(dev, false);
313 	if (err == 0) {
314 		/* Maximum size without crossing a page */
315 		size_t eop_len = FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE);
316 		size_t write_len = MIN(len, eop_len);
317 
318 		while (len > 0) {
319 			err = flash_sam0_write_page(dev, offset, pdata, write_len);
320 			if (err != 0) {
321 				break;
322 			}
323 
324 			offset += write_len;
325 			pdata += write_len;
326 			len -= write_len;
327 			write_len = MIN(len, FLASH_PAGE_SIZE);
328 		}
329 	}
330 
331 	int err2 = flash_sam0_write_protection(dev, true);
332 
333 	if (!err) {
334 		err = err2;
335 	}
336 
337 	flash_sam0_sem_give(dev);
338 
339 	return err;
340 }
341 
342 #endif
343 
flash_sam0_read(const struct device * dev,off_t offset,void * data,size_t len)344 static int flash_sam0_read(const struct device *dev, off_t offset, void *data,
345 			   size_t len)
346 {
347 	int err;
348 
349 	err = flash_sam0_valid_range(offset, len);
350 	if (err != 0) {
351 		return err;
352 	}
353 
354 	memcpy(data, (uint8_t *)CONFIG_FLASH_BASE_ADDRESS + offset, len);
355 
356 	return 0;
357 }
358 
flash_sam0_erase(const struct device * dev,off_t offset,size_t size)359 static int flash_sam0_erase(const struct device *dev, off_t offset,
360 			    size_t size)
361 {
362 	int err;
363 
364 	err = flash_sam0_valid_range(offset, ROW_SIZE);
365 	if (err != 0) {
366 		return err;
367 	}
368 
369 	if ((offset % ROW_SIZE) != 0) {
370 		LOG_WRN("0x%lx: not on a page boundary", (long)offset);
371 		return -EINVAL;
372 	}
373 
374 	if ((size % ROW_SIZE) != 0) {
375 		LOG_WRN("%zu: not a integer number of pages", size);
376 		return -EINVAL;
377 	}
378 
379 	flash_sam0_sem_take(dev);
380 
381 	err = flash_sam0_write_protection(dev, false);
382 	if (err == 0) {
383 		for (size_t addr = offset; addr < offset + size;
384 		     addr += ROW_SIZE) {
385 			err = flash_sam0_erase_row(dev, addr);
386 			if (err != 0) {
387 				break;
388 			}
389 		}
390 	}
391 
392 	int err2 = flash_sam0_write_protection(dev, true);
393 
394 	if (!err) {
395 		err = err2;
396 	}
397 
398 	flash_sam0_sem_give(dev);
399 
400 	return err;
401 }
402 
flash_sam0_write_protection(const struct device * dev,bool enable)403 static int flash_sam0_write_protection(const struct device *dev, bool enable)
404 {
405 	off_t offset;
406 	int err;
407 
408 	for (offset = 0; offset < CONFIG_FLASH_SIZE * 1024;
409 	     offset += LOCK_REGION_SIZE) {
410 		NVMCTRL->ADDR.reg = offset + CONFIG_FLASH_BASE_ADDRESS;
411 
412 #ifdef NVMCTRL_CTRLA_CMD_LR
413 		if (enable) {
414 			NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_LR |
415 					     NVMCTRL_CTRLA_CMDEX_KEY;
416 		} else {
417 			NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_UR |
418 					     NVMCTRL_CTRLA_CMDEX_KEY;
419 		}
420 #else
421 		if (enable) {
422 			NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMD_LR |
423 					     NVMCTRL_CTRLB_CMDEX_KEY;
424 		} else {
425 			NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMD_UR |
426 					     NVMCTRL_CTRLB_CMDEX_KEY;
427 		}
428 #endif
429 		err = flash_sam0_check_status(offset);
430 		if (err != 0) {
431 			goto done;
432 		}
433 	}
434 
435 done:
436 	return err;
437 }
438 
439 #if CONFIG_FLASH_PAGE_LAYOUT
flash_sam0_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)440 void flash_sam0_page_layout(const struct device *dev,
441 			    const struct flash_pages_layout **layout,
442 			    size_t *layout_size)
443 {
444 	*layout = &flash_sam0_pages_layout;
445 	*layout_size = 1;
446 }
447 #endif
448 
449 static const struct flash_parameters *
flash_sam0_get_parameters(const struct device * dev)450 flash_sam0_get_parameters(const struct device *dev)
451 {
452 	ARG_UNUSED(dev);
453 
454 	return &flash_sam0_parameters;
455 }
456 
flash_sam0_init(const struct device * dev)457 static int flash_sam0_init(const struct device *dev)
458 {
459 #if defined(CONFIG_MULTITHREADING)
460 	struct flash_sam0_data *ctx = dev->data;
461 
462 	k_sem_init(&ctx->sem, 1, 1);
463 #endif
464 
465 #ifdef PM_APBBMASK_NVMCTRL
466 	/* Ensure the clock is on. */
467 	PM->APBBMASK.bit.NVMCTRL_ = 1;
468 #else
469 	MCLK->APBBMASK.reg |= MCLK_APBBMASK_NVMCTRL;
470 #endif
471 
472 #ifdef NVMCTRL_CTRLB_MANW
473 	/* Require an explicit write command */
474 	NVMCTRL->CTRLB.bit.MANW = 1;
475 #elif NVMCTRL_CTRLA_WMODE
476 	/* Set manual write mode */
477 	NVMCTRL->CTRLA.bit.WMODE = NVMCTRL_CTRLA_WMODE_MAN_Val;
478 #endif
479 
480 	return flash_sam0_write_protection(dev, false);
481 }
482 
483 static const struct flash_driver_api flash_sam0_api = {
484 	.erase = flash_sam0_erase,
485 	.write = flash_sam0_write,
486 	.read = flash_sam0_read,
487 	.get_parameters = flash_sam0_get_parameters,
488 #ifdef CONFIG_FLASH_PAGE_LAYOUT
489 	.page_layout = flash_sam0_page_layout,
490 #endif
491 };
492 
493 static struct flash_sam0_data flash_sam0_data_0;
494 
495 DEVICE_DT_INST_DEFINE(0, flash_sam0_init, NULL,
496 		    &flash_sam0_data_0, NULL, POST_KERNEL,
497 		    CONFIG_FLASH_INIT_PRIORITY, &flash_sam0_api);
498