1 /*
2 * Copyright (c) 2021 Telink Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT telink_b91_flash_controller
8 #define FLASH_SIZE DT_REG_SIZE(DT_INST(0, soc_nv_flash))
9 #define FLASH_ORIGIN DT_REG_ADDR(DT_INST(0, soc_nv_flash))
10
11 #include "flash.h"
12 #include <string.h>
13 #include <zephyr/device.h>
14 #include <zephyr/drivers/flash.h>
15 #include <zephyr/kernel.h>
16
17 /* driver definitions */
18 #define BLOCK_64K_SIZE (0x10000u)
19 #define BLOCK_64K_PAGES (BLOCK_64K_SIZE / PAGE_SIZE)
20 #define BLOCK_32K_SIZE (0x8000u)
21 #define BLOCK_32K_PAGES (BLOCK_32K_SIZE / PAGE_SIZE)
22 #define SECTOR_SIZE (0x1000u)
23 #define SECTOR_PAGES (SECTOR_SIZE / PAGE_SIZE)
24
25
26 /* driver data structure */
27 struct flash_b91_data {
28 struct k_sem write_lock;
29 };
30
31 /* driver parameters structure */
32 static const struct flash_parameters flash_b91_parameters = {
33 .write_block_size = DT_PROP(DT_INST(0, soc_nv_flash), write_block_size),
34 .erase_value = 0xff,
35 };
36
37
38 /* Check for correct offset and length */
flash_b91_is_range_valid(off_t offset,size_t len)39 static bool flash_b91_is_range_valid(off_t offset, size_t len)
40 {
41 /* check for min value */
42 if ((offset < 0) || (len < 1)) {
43 return false;
44 }
45
46 /* check for max value */
47 if ((offset + len) > FLASH_SIZE) {
48 return false;
49 }
50
51 return true;
52 }
53
54 /* API implementation: driver initialization */
flash_b91_init(const struct device * dev)55 static int flash_b91_init(const struct device *dev)
56 {
57 struct flash_b91_data *dev_data = dev->data;
58
59 k_sem_init(&dev_data->write_lock, 1, 1);
60
61 return 0;
62 }
63
64 /* API implementation: erase */
flash_b91_erase(const struct device * dev,off_t offset,size_t len)65 static int flash_b91_erase(const struct device *dev, off_t offset, size_t len)
66 {
67 int page_nums = len / PAGE_SIZE;
68 struct flash_b91_data *dev_data = dev->data;
69
70 /* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
71 if (!len) {
72 return 0;
73 }
74
75 /* check for valid range */
76 if (!flash_b91_is_range_valid(offset, len)) {
77 return -EINVAL;
78 }
79
80 /* erase can be done only by pages */
81 if (((offset % PAGE_SIZE) != 0) || ((len % PAGE_SIZE) != 0)) {
82 return -EINVAL;
83 }
84
85 /* take semaphore */
86 if (k_sem_take(&dev_data->write_lock, K_NO_WAIT)) {
87 return -EACCES;
88 }
89
90 while (page_nums) {
91 /* check for 64K erase possibility, then check for 32K and so on.. */
92 if ((page_nums >= BLOCK_64K_PAGES) && ((offset % BLOCK_64K_SIZE) == 0)) {
93 /* erase 64K block */
94 flash_erase_64kblock(offset);
95 page_nums -= BLOCK_64K_PAGES;
96 offset += BLOCK_64K_SIZE;
97 } else if ((page_nums >= BLOCK_32K_PAGES) && ((offset % BLOCK_32K_SIZE) == 0)) {
98 /* erase 32K block */
99 flash_erase_32kblock(offset);
100 page_nums -= BLOCK_32K_PAGES;
101 offset += BLOCK_32K_SIZE;
102 } else if ((page_nums >= SECTOR_PAGES) && ((offset % SECTOR_SIZE) == 0)) {
103 /* erase sector */
104 flash_erase_sector(offset);
105 page_nums -= SECTOR_PAGES;
106 offset += SECTOR_SIZE;
107 } else {
108 /* erase page */
109 flash_erase_page(offset);
110 page_nums--;
111 offset += PAGE_SIZE;
112 }
113 }
114
115 /* release semaphore */
116 k_sem_give(&dev_data->write_lock);
117
118 return 0;
119 }
120
121 /* API implementation: write */
flash_b91_write(const struct device * dev,off_t offset,const void * data,size_t len)122 static int flash_b91_write(const struct device *dev, off_t offset,
123 const void *data, size_t len)
124 {
125 void *buf = NULL;
126 struct flash_b91_data *dev_data = dev->data;
127
128 /* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
129 if (!len) {
130 return 0;
131 }
132
133 /* check for valid range */
134 if (!flash_b91_is_range_valid(offset, len)) {
135 return -EINVAL;
136 }
137
138 /* take semaphore */
139 if (k_sem_take(&dev_data->write_lock, K_NO_WAIT)) {
140 return -EACCES;
141 }
142
143 /* need to store data in intermediate RAM buffer in case from flash to flash write */
144 if (((uint32_t)data >= FLASH_ORIGIN) &&
145 ((uint32_t)data < (FLASH_ORIGIN + FLASH_SIZE))) {
146
147 buf = k_malloc(len);
148 if (buf == NULL) {
149 k_sem_give(&dev_data->write_lock);
150 return -ENOMEM;
151 }
152
153 /* copy Flash data to RAM */
154 memcpy(buf, data, len);
155
156 /* substitute data with allocated buffer */
157 data = buf;
158 }
159
160 /* write flash */
161 flash_write_page(offset, len, (unsigned char *)data);
162
163 /* if ram memory is allocated for flash writing it should be free */
164 if (buf != NULL) {
165 k_free(buf);
166 }
167
168 /* release semaphore */
169 k_sem_give(&dev_data->write_lock);
170
171 return 0;
172 }
173
174 /* API implementation: read */
flash_b91_read(const struct device * dev,off_t offset,void * data,size_t len)175 static int flash_b91_read(const struct device *dev, off_t offset,
176 void *data, size_t len)
177 {
178 ARG_UNUSED(dev);
179
180 /* return SUCCESS if len equals 0 (required by tests/drivers/flash) */
181 if (!len) {
182 return 0;
183 }
184
185 /* check for valid range */
186 if (!flash_b91_is_range_valid(offset, len)) {
187 return -EINVAL;
188 }
189
190 /* read flash */
191 flash_read_page(offset, len, (unsigned char *)data);
192
193 return 0;
194 }
195
196 /* API implementation: get_parameters */
197 static const struct flash_parameters *
flash_b91_get_parameters(const struct device * dev)198 flash_b91_get_parameters(const struct device *dev)
199 {
200 ARG_UNUSED(dev);
201
202 return &flash_b91_parameters;
203 }
204
205 /* API implementation: page_layout */
206 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
207 static const struct flash_pages_layout dev_layout = {
208 .pages_count = FLASH_SIZE / PAGE_SIZE,
209 .pages_size = PAGE_SIZE,
210 };
211
flash_b91_pages_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)212 static void flash_b91_pages_layout(const struct device *dev,
213 const struct flash_pages_layout **layout,
214 size_t *layout_size)
215 {
216 *layout = &dev_layout;
217 *layout_size = 1;
218 }
219 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
220
221 static struct flash_b91_data flash_data;
222
223 static const struct flash_driver_api flash_b91_api = {
224 .erase = flash_b91_erase,
225 .write = flash_b91_write,
226 .read = flash_b91_read,
227 .get_parameters = flash_b91_get_parameters,
228 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
229 .page_layout = flash_b91_pages_layout,
230 #endif
231 };
232
233 /* Driver registration */
234 DEVICE_DT_INST_DEFINE(0, flash_b91_init,
235 NULL, &flash_data, NULL, POST_KERNEL,
236 CONFIG_FLASH_INIT_PRIORITY, &flash_b91_api);
237