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