1 /*
2  * Copyright (c) 2018 Aurelien Jarno
3  * Copyright (c) 2023 Bjarki Arge Andreasen
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * This driver defines a page as the erase_block_size.
10  * This driver defines a write page as defined by the flash controller
11  * This driver defines a section as a contiguous array of bytes
12  * This driver defines an area as the entire flash area
13  * This driver defines the write block size as the minimum write block size
14  */
15 
16 #define DT_DRV_COMPAT atmel_sam_flash_controller
17 
18 #include <zephyr/kernel.h>
19 #include <zephyr/devicetree.h>
20 #include <zephyr/drivers/flash.h>
21 #include <zephyr/sys/barrier.h>
22 #include <string.h>
23 #include <soc.h>
24 
25 #include <zephyr/logging/log.h>
26 LOG_MODULE_REGISTER(flash_sam, CONFIG_FLASH_LOG_LEVEL);
27 
28 #define SAM_FLASH_WRITE_PAGE_SIZE (512)
29 
30 typedef void (*sam_flash_irq_init_fn_ptr)(void);
31 
32 struct sam_flash_config {
33 	Efc *regs;
34 	sam_flash_irq_init_fn_ptr irq_init;
35 	off_t area_address;
36 	off_t area_size;
37 	struct flash_parameters parameters;
38 	struct flash_pages_layout *pages_layouts;
39 	size_t pages_layouts_size;
40 };
41 
42 struct sam_flash_erase_data {
43 	off_t section_start;
44 	size_t section_end;
45 	bool succeeded;
46 };
47 
48 struct sam_flash_data {
49 	const struct device *dev;
50 	struct k_spinlock lock;
51 	struct sam_flash_erase_data erase_data;
52 	struct k_sem ready_sem;
53 };
54 
sam_flash_validate_offset_len(off_t offset,size_t len)55 static bool sam_flash_validate_offset_len(off_t offset, size_t len)
56 {
57 	if (offset < 0) {
58 		return false;
59 	}
60 
61 	if ((offset + len) < len) {
62 		return false;
63 	}
64 
65 	return true;
66 }
67 
sam_flash_aligned(size_t value,size_t alignment)68 static bool sam_flash_aligned(size_t value, size_t alignment)
69 {
70 	return (value & (alignment - 1)) == 0;
71 }
72 
sam_flash_offset_is_on_write_page_boundary(off_t offset)73 static bool sam_flash_offset_is_on_write_page_boundary(off_t offset)
74 {
75 	return sam_flash_aligned(offset, SAM_FLASH_WRITE_PAGE_SIZE);
76 }
77 
sam_flash_mask_ready_interrupt(const struct sam_flash_config * config)78 static inline void sam_flash_mask_ready_interrupt(const struct sam_flash_config *config)
79 {
80 	Efc *regs = config->regs;
81 
82 	regs->EEFC_FMR &= ~EEFC_FMR_FRDY;
83 }
84 
sam_flash_unmask_ready_interrupt(const struct sam_flash_config * config)85 static inline void sam_flash_unmask_ready_interrupt(const struct sam_flash_config *config)
86 {
87 	Efc *regs = config->regs;
88 
89 	regs->EEFC_FMR |= EEFC_FMR_FRDY;
90 }
91 
sam_flash_isr(const struct device * dev)92 static void sam_flash_isr(const struct device *dev)
93 {
94 	struct sam_flash_data *data = dev->data;
95 	const struct sam_flash_config *config = dev->config;
96 
97 	sam_flash_mask_ready_interrupt(config);
98 	k_sem_give(&data->ready_sem);
99 }
100 
sam_flash_section_wait_until_ready(const struct device * dev)101 static int sam_flash_section_wait_until_ready(const struct device *dev)
102 {
103 	struct sam_flash_data *data = dev->data;
104 	const struct sam_flash_config *config = dev->config;
105 	Efc *regs = config->regs;
106 	uint32_t eefc_fsr;
107 
108 	k_sem_reset(&data->ready_sem);
109 	sam_flash_unmask_ready_interrupt(config);
110 
111 	if (k_sem_take(&data->ready_sem, K_MSEC(500)) < 0) {
112 		LOG_ERR("Command did not execute in time");
113 		return -EFAULT;
114 	}
115 
116 	/* FSR register is cleared on read */
117 	eefc_fsr = regs->EEFC_FSR;
118 
119 	if (eefc_fsr & EEFC_FSR_FCMDE) {
120 		LOG_ERR("Invalid command requested");
121 		return -EPERM;
122 	}
123 
124 	if (eefc_fsr & EEFC_FSR_FLOCKE) {
125 		LOG_ERR("Tried to modify locked region");
126 		return -EPERM;
127 	}
128 
129 	if (eefc_fsr & EEFC_FSR_FLERR) {
130 		LOG_ERR("Programming failed");
131 		return -EPERM;
132 	}
133 
134 	return 0;
135 }
136 
sam_flash_section_is_within_area(const struct device * dev,off_t offset,size_t len)137 static bool sam_flash_section_is_within_area(const struct device *dev, off_t offset, size_t len)
138 {
139 	const struct sam_flash_config *config = dev->config;
140 
141 	if ((offset + ((off_t)len)) < offset) {
142 		return false;
143 	}
144 
145 	if ((offset >= 0) && ((offset + len) <= config->area_size)) {
146 		return true;
147 	}
148 
149 	LOG_WRN("Section from 0x%x to 0x%x is not within flash area (0x0 to %x)",
150 		(size_t)offset, (size_t)(offset + len), (size_t)config->area_size);
151 
152 	return false;
153 }
154 
sam_flash_section_is_aligned_with_write_block_size(const struct device * dev,off_t offset,size_t len)155 static bool sam_flash_section_is_aligned_with_write_block_size(const struct device *dev,
156 							       off_t offset, size_t len)
157 {
158 	const struct sam_flash_config *config = dev->config;
159 
160 	if (sam_flash_aligned(offset, config->parameters.write_block_size) &&
161 	    sam_flash_aligned(len, config->parameters.write_block_size)) {
162 		return true;
163 	}
164 
165 	LOG_WRN("Section from 0x%x to 0x%x is not aligned with write block size (%u)",
166 		(size_t)offset, (size_t)(offset + len), config->parameters.write_block_size);
167 
168 	return false;
169 }
170 
sam_flash_section_is_aligned_with_pages(const struct device * dev,off_t offset,size_t len)171 static bool sam_flash_section_is_aligned_with_pages(const struct device *dev, off_t offset,
172 						    size_t len)
173 {
174 	const struct sam_flash_config *config = dev->config;
175 	struct flash_pages_info pages_info;
176 
177 	/* Get the page offset points to */
178 	if (flash_get_page_info_by_offs(dev, offset, &pages_info) < 0) {
179 		return false;
180 	}
181 
182 	/* Validate offset points to start of page */
183 	if (offset != pages_info.start_offset) {
184 		return false;
185 	}
186 
187 	/* Check if end of section is aligned with end of area */
188 	if ((offset + len) == (config->area_size)) {
189 		return true;
190 	}
191 
192 	/* Get the page pointed to by end of section */
193 	if (flash_get_page_info_by_offs(dev, offset + len, &pages_info) < 0) {
194 		return false;
195 	}
196 
197 	/* Validate offset points to start of page */
198 	if ((offset + len) != pages_info.start_offset) {
199 		return false;
200 	}
201 
202 	return true;
203 }
204 
sam_flash_read(const struct device * dev,off_t offset,void * data,size_t len)205 static int sam_flash_read(const struct device *dev, off_t offset, void *data, size_t len)
206 {
207 	struct sam_flash_data *sam_data = dev->data;
208 	const struct sam_flash_config *sam_config = dev->config;
209 	k_spinlock_key_t key;
210 
211 	if (len == 0) {
212 		return 0;
213 	}
214 
215 	if (!sam_flash_validate_offset_len(offset, len)) {
216 		return -EINVAL;
217 	}
218 
219 	if (!sam_flash_section_is_within_area(dev, offset, len)) {
220 		return -EINVAL;
221 	}
222 
223 	key = k_spin_lock(&sam_data->lock);
224 	memcpy(data, (uint8_t *)(sam_config->area_address + offset), len);
225 	k_spin_unlock(&sam_data->lock, key);
226 	return 0;
227 }
228 
sam_flash_write_latch_buffer_to_page(const struct device * dev,off_t offset)229 static int sam_flash_write_latch_buffer_to_page(const struct device *dev, off_t offset)
230 {
231 	const struct sam_flash_config *sam_config = dev->config;
232 	Efc *regs = sam_config->regs;
233 	uint32_t page = offset / SAM_FLASH_WRITE_PAGE_SIZE;
234 
235 	regs->EEFC_FCR = EEFC_FCR_FCMD_WP | EEFC_FCR_FARG(page) | EEFC_FCR_FKEY_PASSWD;
236 	sam_flash_section_wait_until_ready(dev);
237 	return 0;
238 }
239 
sam_flash_write_latch_buffer_to_previous_page(const struct device * dev,off_t offset)240 static int sam_flash_write_latch_buffer_to_previous_page(const struct device *dev, off_t offset)
241 {
242 	return sam_flash_write_latch_buffer_to_page(dev, offset - SAM_FLASH_WRITE_PAGE_SIZE);
243 }
244 
sam_flash_write_dword_to_latch_buffer(off_t offset,uint32_t dword)245 static void sam_flash_write_dword_to_latch_buffer(off_t offset, uint32_t dword)
246 {
247 	*((uint32_t *)offset) = dword;
248 	barrier_dsync_fence_full();
249 }
250 
sam_flash_write_dwords_to_flash(const struct device * dev,off_t offset,const uint32_t * dwords,size_t size)251 static int sam_flash_write_dwords_to_flash(const struct device *dev, off_t offset,
252 					   const uint32_t *dwords, size_t size)
253 {
254 	for (size_t i = 0; i < size; i++) {
255 		sam_flash_write_dword_to_latch_buffer(offset, dwords[i]);
256 		offset += sizeof(uint32_t);
257 		if (sam_flash_offset_is_on_write_page_boundary(offset)) {
258 			sam_flash_write_latch_buffer_to_previous_page(dev, offset);
259 		}
260 	}
261 
262 	if (!sam_flash_offset_is_on_write_page_boundary(offset)) {
263 		sam_flash_write_latch_buffer_to_page(dev, offset);
264 	}
265 
266 	return 0;
267 }
268 
sam_flash_write(const struct device * dev,off_t offset,const void * data,size_t len)269 static int sam_flash_write(const struct device *dev, off_t offset, const void *data, size_t len)
270 {
271 	struct sam_flash_data *sam_data = dev->data;
272 	k_spinlock_key_t key;
273 
274 	if (len == 0) {
275 		return 0;
276 	}
277 
278 	if (!sam_flash_validate_offset_len(offset, len)) {
279 		return -EINVAL;
280 	}
281 
282 	if (!sam_flash_section_is_aligned_with_write_block_size(dev, offset, len)) {
283 		return -EINVAL;
284 	}
285 
286 	LOG_DBG("Writing sector from 0x%x to 0x%x", (size_t)offset, (size_t)(offset + len));
287 
288 	key = k_spin_lock(&sam_data->lock);
289 	if (sam_flash_write_dwords_to_flash(dev, offset, data, len / sizeof(uint32_t)) < 0) {
290 		k_spin_unlock(&sam_data->lock, key);
291 		return -EAGAIN;
292 	}
293 
294 	k_spin_unlock(&sam_data->lock, key);
295 	return 0;
296 }
297 
sam_flash_unlock_write_page(const struct device * dev,uint16_t page_index)298 static int sam_flash_unlock_write_page(const struct device *dev, uint16_t page_index)
299 {
300 	const struct sam_flash_config *sam_config = dev->config;
301 	Efc *regs = sam_config->regs;
302 
303 	/* Perform unlock command of write page */
304 	regs->EEFC_FCR = EEFC_FCR_FCMD_CLB
305 		       | EEFC_FCR_FARG(page_index)
306 		       | EEFC_FCR_FKEY_PASSWD;
307 
308 	return sam_flash_section_wait_until_ready(dev);
309 }
310 
sam_flash_unlock_page(const struct device * dev,const struct flash_pages_info * info)311 static int sam_flash_unlock_page(const struct device *dev, const struct flash_pages_info *info)
312 {
313 	uint16_t page_index_start;
314 	uint16_t page_index_end;
315 	int ret;
316 
317 	/* Convert from page offset and size to write page index and count */
318 	page_index_start = info->start_offset / SAM_FLASH_WRITE_PAGE_SIZE;
319 	page_index_end = page_index_start + (info->size / SAM_FLASH_WRITE_PAGE_SIZE);
320 
321 	for (uint16_t i = page_index_start; i < page_index_end; i++) {
322 		ret = sam_flash_unlock_write_page(dev, i);
323 		if (ret < 0) {
324 			return ret;
325 		}
326 	}
327 
328 	return 0;
329 }
330 
sam_flash_erase_page(const struct device * dev,const struct flash_pages_info * info)331 static int sam_flash_erase_page(const struct device *dev, const struct flash_pages_info *info)
332 {
333 	const struct sam_flash_config *sam_config = dev->config;
334 	Efc *regs = sam_config->regs;
335 	uint32_t page_index;
336 	int ret;
337 
338 	/* Convert from page offset to write page index */
339 	page_index = info->start_offset / SAM_FLASH_WRITE_PAGE_SIZE;
340 
341 	LOG_DBG("Erasing page at 0x%x of size 0x%x", (size_t)info->start_offset, info->size);
342 
343 	/* Perform erase command of page */
344 	switch (info->size) {
345 	case 0x800:
346 		regs->EEFC_FCR = EEFC_FCR_FCMD_EPA
347 			       | EEFC_FCR_FARG(page_index)
348 			       | EEFC_FCR_FKEY_PASSWD;
349 		break;
350 
351 	case 0x1000:
352 		regs->EEFC_FCR = EEFC_FCR_FCMD_EPA
353 			       | EEFC_FCR_FARG(page_index | 1)
354 			       | EEFC_FCR_FKEY_PASSWD;
355 		break;
356 
357 	case 0x2000:
358 		regs->EEFC_FCR = EEFC_FCR_FCMD_EPA
359 			       | EEFC_FCR_FARG(page_index | 2)
360 			       | EEFC_FCR_FKEY_PASSWD;
361 		break;
362 
363 	case 0x4000:
364 		regs->EEFC_FCR = EEFC_FCR_FCMD_EPA
365 			       | EEFC_FCR_FARG(page_index | 3)
366 			       | EEFC_FCR_FKEY_PASSWD;
367 		break;
368 
369 	default:
370 		return -EINVAL;
371 	}
372 
373 	ret = sam_flash_section_wait_until_ready(dev);
374 	if (ret == 0) {
375 		return ret;
376 	}
377 
378 	LOG_ERR("Failed to erase page at 0x%x of size 0x%x", (size_t)info->start_offset,
379 		info->size);
380 
381 	return ret;
382 }
383 
sam_flash_erase_foreach_page(const struct flash_pages_info * info,void * data)384 static bool sam_flash_erase_foreach_page(const struct flash_pages_info *info, void *data)
385 {
386 	struct sam_flash_data *sam_data = data;
387 	const struct device *dev = sam_data->dev;
388 	struct sam_flash_erase_data *erase_data = &sam_data->erase_data;
389 
390 	/* Validate we reached first page to erase */
391 	if (info->start_offset < erase_data->section_start) {
392 		/* Next page */
393 		return true;
394 	}
395 
396 	/* Check if we've reached the end of pages to erase */
397 	if (info->start_offset >= erase_data->section_end) {
398 		/* Succeeded, stop iterating */
399 		erase_data->succeeded = true;
400 		return false;
401 	}
402 
403 	if (sam_flash_unlock_page(dev, info) < 0) {
404 		/* Failed to unlock page, stop iterating */
405 		return false;
406 	}
407 
408 	if (sam_flash_erase_page(dev, info) < 0) {
409 		/* Failed to erase page, stop iterating */
410 		return false;
411 	}
412 
413 	/* Next page */
414 	return true;
415 }
416 
sam_flash_erase(const struct device * dev,off_t offset,size_t size)417 static int sam_flash_erase(const struct device *dev, off_t offset, size_t size)
418 {
419 	struct sam_flash_data *sam_data = dev->data;
420 	k_spinlock_key_t key;
421 
422 	if (size == 0) {
423 		return 0;
424 	}
425 
426 	if (!sam_flash_validate_offset_len(offset, size)) {
427 		return -EINVAL;
428 	}
429 
430 	if (!sam_flash_section_is_aligned_with_pages(dev, offset, size)) {
431 		return -EINVAL;
432 	}
433 
434 	LOG_DBG("Erasing sector from 0x%x to 0x%x", (size_t)offset, (size_t)(offset + size));
435 
436 	key = k_spin_lock(&sam_data->lock);
437 	sam_data->erase_data.section_start = offset;
438 	sam_data->erase_data.section_end = offset + size;
439 	sam_data->erase_data.succeeded = false;
440 	flash_page_foreach(dev, sam_flash_erase_foreach_page, sam_data);
441 	if (!sam_data->erase_data.succeeded) {
442 		k_spin_unlock(&sam_data->lock, key);
443 		return -EFAULT;
444 	}
445 
446 	k_spin_unlock(&sam_data->lock, key);
447 	return 0;
448 }
449 
sam_flash_get_parameters(const struct device * dev)450 static const struct flash_parameters *sam_flash_get_parameters(const struct device *dev)
451 {
452 	const struct sam_flash_config *config = dev->config;
453 
454 	return &config->parameters;
455 }
456 
sam_flash_api_pages_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)457 static void sam_flash_api_pages_layout(const struct device *dev,
458 				       const struct flash_pages_layout **layout,
459 				       size_t *layout_size)
460 {
461 	const struct sam_flash_config *config = dev->config;
462 
463 	*layout = config->pages_layouts;
464 	*layout_size = config->pages_layouts_size;
465 }
466 
467 static struct flash_driver_api sam_flash_api = {
468 	.read = sam_flash_read,
469 	.write = sam_flash_write,
470 	.erase = sam_flash_erase,
471 	.get_parameters = sam_flash_get_parameters,
472 	.page_layout = sam_flash_api_pages_layout,
473 };
474 
sam_flash_init(const struct device * dev)475 static int sam_flash_init(const struct device *dev)
476 {
477 	struct sam_flash_data *sam_data = dev->data;
478 	const struct sam_flash_config *sam_config = dev->config;
479 
480 	sam_data->dev = dev;
481 	k_sem_init(&sam_data->ready_sem, 0, 1);
482 	sam_flash_mask_ready_interrupt(sam_config);
483 	sam_config->irq_init();
484 	return 0;
485 }
486 
487 #define SAM_FLASH_DEVICE DT_INST(0, atmel_sam_flash)
488 
489 #define SAM_FLASH_PAGES_LAYOUT(node_id, prop, idx)						\
490 	{											\
491 		.pages_count = DT_PHA_BY_IDX(node_id, prop, idx, pages_count),			\
492 		.pages_size = DT_PHA_BY_IDX(node_id, prop, idx, pages_size),			\
493 	}
494 
495 #define SAM_FLASH_PAGES_LAYOUTS									\
496 	DT_FOREACH_PROP_ELEM_SEP(SAM_FLASH_DEVICE, erase_blocks, SAM_FLASH_PAGES_LAYOUT, (,))
497 
498 #define SAM_FLASH_CONTROLLER(inst)								\
499 	struct flash_pages_layout sam_flash_pages_layouts##inst[] = {				\
500 		SAM_FLASH_PAGES_LAYOUTS								\
501 	};											\
502 												\
503 	static void sam_flash_irq_init_##inst(void)						\
504 	{											\
505 		IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority),			\
506 			    sam_flash_isr, DEVICE_DT_INST_GET(inst), 0);			\
507 		irq_enable(DT_INST_IRQN(inst));							\
508 												\
509 	}											\
510 												\
511 	static const struct sam_flash_config sam_flash_config##inst = {				\
512 		.regs = (Efc *)DT_INST_REG_ADDR(inst),						\
513 		.irq_init = sam_flash_irq_init_##inst,						\
514 		.area_address = DT_REG_ADDR(SAM_FLASH_DEVICE),					\
515 		.area_size = DT_REG_SIZE(SAM_FLASH_DEVICE),					\
516 		.parameters = {									\
517 			.write_block_size = DT_PROP(SAM_FLASH_DEVICE, write_block_size),	\
518 			.erase_value = 0xFF,							\
519 		},										\
520 		.pages_layouts = sam_flash_pages_layouts##inst,					\
521 		.pages_layouts_size = ARRAY_SIZE(sam_flash_pages_layouts##inst),		\
522 	};											\
523 												\
524 	static struct sam_flash_data sam_flash_data##inst;					\
525 												\
526 	DEVICE_DT_INST_DEFINE(inst, sam_flash_init, NULL, &sam_flash_data##inst,		\
527 			      &sam_flash_config##inst, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY,	\
528 			      &sam_flash_api);
529 
530 SAM_FLASH_CONTROLLER(0)
531