1 /*
2  * Copyright (c) 2022 Renesas Electronics Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT renesas_smartbond_flash_controller
8 #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)
9 #define QSPIF_NODE DT_NODELABEL(qspif)
10 
11 #include <stddef.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/device.h>
16 #include <zephyr/drivers/flash.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <DA1469xAB.h>
19 
20 #define FLASH_ERASE_SIZE	DT_PROP(SOC_NV_FLASH_NODE, erase_block_size)
21 #define FLASH_PAGE_SIZE		256
22 
23 struct flash_smartbond_config {
24 	uint32_t qspif_base_address;
25 };
26 
27 static const struct flash_parameters flash_smartbond_parameters = {
28 	.write_block_size = DT_PROP(SOC_NV_FLASH_NODE, write_block_size),
29 	.erase_value = 0xff,
30 };
31 
range_is_valid(off_t offset,uint32_t size)32 static bool range_is_valid(off_t offset, uint32_t size)
33 {
34 	return (offset + size) <= (CONFIG_FLASH_SIZE * 1024);
35 }
36 
qspic_data_write8(uint8_t data)37 static ALWAYS_INLINE void qspic_data_write8(uint8_t data)
38 {
39 	volatile uint8_t *reg8 = (uint8_t *)&QSPIC->QSPIC_WRITEDATA_REG;
40 
41 	*reg8 = data;
42 }
43 
qspic_data_write32(uint32_t data)44 static ALWAYS_INLINE void qspic_data_write32(uint32_t data)
45 {
46 	volatile uint32_t *reg32 = (uint32_t *)&QSPIC->QSPIC_WRITEDATA_REG;
47 
48 	*reg32 = data;
49 }
50 
qspic_data_read8(void)51 static ALWAYS_INLINE uint8_t qspic_data_read8(void)
52 {
53 	volatile uint8_t *reg8 = (uint8_t *)&QSPIC->QSPIC_READDATA_REG;
54 
55 	return *reg8;
56 }
57 
qspic_read_status(void)58 static __ramfunc uint8_t qspic_read_status(void)
59 {
60 	uint8_t status;
61 
62 	QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_EN_CS_Msk;
63 	qspic_data_write8(0x05);
64 	status = qspic_data_read8();
65 	QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_DIS_CS_Msk;
66 
67 	return status;
68 }
69 
70 
qspic_wait_busy(void)71 static __ramfunc void qspic_wait_busy(void)
72 {
73 	do {
74 	} while (qspic_read_status() & 0x01);
75 }
76 
qspic_automode_exit(void)77 static __ramfunc void qspic_automode_exit(void)
78 {
79 	QSPIC->QSPIC_CTRLMODE_REG &= ~QSPIC_QSPIC_CTRLMODE_REG_QSPIC_AUTO_MD_Msk;
80 	QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_SET_SINGLE_Msk;
81 	QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_EN_CS_Msk;
82 	qspic_data_write8(0xff);
83 	qspic_data_write8(0xff);
84 	QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_DIS_CS_Msk;
85 }
86 
qspic_write_enable(void)87 static __ramfunc void qspic_write_enable(void)
88 {
89 	uint8_t status;
90 
91 	do {
92 		QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_EN_CS_Msk;
93 		qspic_data_write8(0x06);
94 		QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_DIS_CS_Msk;
95 
96 		do {
97 			status = qspic_read_status();
98 		} while (status & 0x01);
99 	} while (!(status & 0x02));
100 }
101 
qspic_write_page(uint32_t address,const uint8_t * data,size_t size)102 static __ramfunc size_t qspic_write_page(uint32_t address, const uint8_t *data, size_t size)
103 {
104 	size_t written;
105 
106 	/* Make sure we write up to page boundary */
107 	size = MIN(size, FLASH_PAGE_SIZE - (address & (FLASH_PAGE_SIZE - 1)));
108 	written = size;
109 
110 	QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_EN_CS_Msk;
111 
112 	address = sys_cpu_to_be32(address);
113 	qspic_data_write32(address | 0x02);
114 
115 	while (size >= 4) {
116 		qspic_data_write32(*(uint32_t *) data);
117 		data += 4;
118 		size -= 4;
119 	}
120 
121 	while (size) {
122 		qspic_data_write8(*data);
123 		data++;
124 		size--;
125 	}
126 
127 	QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_DIS_CS_Msk;
128 
129 	return written;
130 }
131 
qspic_write(uint32_t address,const uint8_t * data,size_t size)132 static __ramfunc void qspic_write(uint32_t address, const uint8_t *data, size_t size)
133 {
134 	size_t written;
135 
136 	while (size) {
137 		qspic_write_enable();
138 
139 		written = qspic_write_page(address, data, size);
140 		address += written;
141 		data += written;
142 		size -= written;
143 
144 		qspic_wait_busy();
145 	}
146 }
147 
flash_smartbond_read(const struct device * dev,off_t offset,void * data,size_t size)148 static int flash_smartbond_read(const struct device *dev, off_t offset,
149 			      void *data, size_t size)
150 {
151 	const struct flash_smartbond_config *config = dev->config;
152 
153 	if (!range_is_valid(offset, size)) {
154 		return -EINVAL;
155 	}
156 
157 	if (!size) {
158 		return 0;
159 	}
160 
161 	memcpy(data, (uint8_t *)(config->qspif_base_address + offset), size);
162 
163 	return 0;
164 }
165 
flash_smartbond_write(const struct device * dev,off_t offset,const void * data,size_t size)166 static __ramfunc int flash_smartbond_write(const struct device *dev,
167 					 off_t offset, const void *data,
168 					 size_t size)
169 {
170 	unsigned int key;
171 	uint32_t ctrlmode;
172 
173 	if (!range_is_valid(offset, size)) {
174 		return -EINVAL;
175 	}
176 
177 	if (!size) {
178 		return 0;
179 	}
180 
181 	key = irq_lock();
182 
183 	ctrlmode = QSPIC->QSPIC_CTRLMODE_REG;
184 	qspic_automode_exit();
185 	qspic_wait_busy();
186 
187 	qspic_write(offset, data, size);
188 
189 	QSPIC->QSPIC_CTRLMODE_REG = ctrlmode;
190 	CACHE->CACHE_CTRL1_REG |= CACHE_CACHE_CTRL1_REG_CACHE_FLUSH_Msk;
191 
192 	irq_unlock(key);
193 
194 	return 0;
195 }
196 
flash_smartbond_erase(const struct device * dev,off_t offset,size_t size)197 static __ramfunc int flash_smartbond_erase(const struct device *dev, off_t offset,
198 					 size_t size)
199 {
200 	unsigned int key;
201 	uint32_t ctrlmode;
202 	uint32_t address;
203 
204 	if (!range_is_valid(offset, size)) {
205 		return -EINVAL;
206 	}
207 
208 	if ((offset % FLASH_ERASE_SIZE) != 0) {
209 		return -EINVAL;
210 	}
211 
212 	if ((size % FLASH_ERASE_SIZE) != 0) {
213 		return -EINVAL;
214 	}
215 
216 	if (!size) {
217 		return 0;
218 	}
219 
220 	key = irq_lock();
221 
222 	ctrlmode = QSPIC->QSPIC_CTRLMODE_REG;
223 	qspic_automode_exit();
224 	qspic_wait_busy();
225 
226 	while (size) {
227 		qspic_write_enable();
228 
229 		QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_EN_CS_Msk;
230 
231 		address = sys_cpu_to_be32(offset);
232 		qspic_data_write32(address | 0x20);
233 		QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_DIS_CS_Msk;
234 
235 		qspic_wait_busy();
236 
237 		offset += FLASH_ERASE_SIZE;
238 		size -= FLASH_ERASE_SIZE;
239 	}
240 
241 	QSPIC->QSPIC_CTRLMODE_REG = ctrlmode;
242 	CACHE->CACHE_CTRL1_REG |= CACHE_CACHE_CTRL1_REG_CACHE_FLUSH_Msk;
243 
244 	irq_unlock(key);
245 
246 	return 0;
247 }
248 
249 static const struct flash_parameters *
flash_smartbond_get_parameters(const struct device * dev)250 flash_smartbond_get_parameters(const struct device *dev)
251 {
252 	ARG_UNUSED(dev);
253 
254 	return &flash_smartbond_parameters;
255 }
256 
257 #if CONFIG_FLASH_PAGE_LAYOUT
258 static const struct flash_pages_layout flash_smartbond_0_pages_layout = {
259 	.pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) /
260 				DT_PROP(SOC_NV_FLASH_NODE, erase_block_size),
261 	.pages_size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size),
262 };
263 
flash_smartbond_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)264 void flash_smartbond_page_layout(const struct device *dev,
265 			       const struct flash_pages_layout **layout,
266 			       size_t *layout_size)
267 {
268 	*layout = &flash_smartbond_0_pages_layout;
269 	*layout_size = 1;
270 }
271 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
272 
273 static const struct flash_driver_api flash_smartbond_driver_api = {
274 	.read = flash_smartbond_read,
275 	.write = flash_smartbond_write,
276 	.erase = flash_smartbond_erase,
277 	.get_parameters = flash_smartbond_get_parameters,
278 #ifdef CONFIG_FLASH_PAGE_LAYOUT
279 	.page_layout = flash_smartbond_page_layout,
280 #endif
281 };
282 
283 static const struct flash_smartbond_config flash_smartbond_0_config = {
284 	.qspif_base_address = DT_REG_ADDR(QSPIF_NODE),
285 };
286 
287 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &flash_smartbond_0_config,
288 		      POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, &flash_smartbond_driver_api);
289