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