1 /*
2  * Copyright (c) 2017 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 
9 #include <zephyr/drivers/flash.h>
10 
flash_get_page_info(const struct device * dev,off_t offs,uint32_t index,struct flash_pages_info * info)11 static int flash_get_page_info(const struct device *dev, off_t offs,
12 			       uint32_t index, struct flash_pages_info *info)
13 {
14 	const struct flash_driver_api *api = dev->api;
15 	const struct flash_pages_layout *layout;
16 	size_t layout_size;
17 	uint32_t index_jmp;
18 
19 	info->start_offset = 0;
20 	info->index = 0U;
21 
22 	api->page_layout(dev, &layout, &layout_size);
23 
24 	while (layout_size--) {
25 		info->size = layout->pages_size;
26 		if (offs == 0) {
27 			index_jmp = index - info->index;
28 		} else {
29 			index_jmp = (offs - info->start_offset) / info->size;
30 		}
31 
32 		index_jmp = MIN(index_jmp, layout->pages_count);
33 		info->start_offset += (index_jmp * info->size);
34 		info->index += index_jmp;
35 		if (index_jmp < layout->pages_count) {
36 			return 0;
37 		}
38 
39 		layout++;
40 	}
41 
42 	return -EINVAL; /* page at offs or idx doesn't exist */
43 }
44 
z_impl_flash_get_page_info_by_offs(const struct device * dev,off_t offs,struct flash_pages_info * info)45 int z_impl_flash_get_page_info_by_offs(const struct device *dev, off_t offs,
46 				       struct flash_pages_info *info)
47 {
48 	return flash_get_page_info(dev, offs, 0U, info);
49 }
50 
z_impl_flash_get_page_info_by_idx(const struct device * dev,uint32_t page_index,struct flash_pages_info * info)51 int z_impl_flash_get_page_info_by_idx(const struct device *dev,
52 				      uint32_t page_index,
53 				      struct flash_pages_info *info)
54 {
55 	return flash_get_page_info(dev, 0, page_index, info);
56 }
57 
z_impl_flash_get_page_count(const struct device * dev)58 size_t z_impl_flash_get_page_count(const struct device *dev)
59 {
60 	const struct flash_driver_api *api = dev->api;
61 	const struct flash_pages_layout *layout;
62 	size_t layout_size;
63 	size_t count = 0;
64 
65 	api->page_layout(dev, &layout, &layout_size);
66 
67 	while (layout_size--) {
68 		count += layout->pages_count;
69 		layout++;
70 	}
71 
72 	return count;
73 }
74 
flash_page_foreach(const struct device * dev,flash_page_cb cb,void * data)75 void flash_page_foreach(const struct device *dev, flash_page_cb cb,
76 			void *data)
77 {
78 	const struct flash_driver_api *api = dev->api;
79 	const struct flash_pages_layout *layout;
80 	struct flash_pages_info page_info;
81 	size_t block, num_blocks, page = 0, i;
82 	off_t off = 0;
83 
84 	api->page_layout(dev, &layout, &num_blocks);
85 
86 	for (block = 0; block < num_blocks; block++) {
87 		const struct flash_pages_layout *l = &layout[block];
88 		page_info.size = l->pages_size;
89 
90 		for (i = 0; i < l->pages_count; i++) {
91 			page_info.start_offset = off;
92 			page_info.index = page;
93 
94 			if (!cb(&page_info, data)) {
95 				return;
96 			}
97 
98 			off += page_info.size;
99 			page++;
100 		}
101 	}
102 }
103