1 /*
2  * Copyright (c) 2025 Renesas Electronics Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 #include <string.h>
9 #include <soc.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/init.h>
14 #include <zephyr/irq.h>
15 #include "soc_flash_renesas_rx.h"
16 #include "r_flash_rx_if.h"
17 
18 /*
19  * The extern function below is implemented in the r_flash_nofcu.c source file.
20  * For more information, please refer to r_flash_nofcu.c in HAL Renesas
21  */
22 #ifdef CONFIG_FLASH_RENESAS_RX_BGO_ENABLED
23 extern void Excep_FCU_FRDYI(void);
24 #endif
25 
26 #define DT_DRV_COMPAT renesas_rx_flash
27 
28 LOG_MODULE_REGISTER(flash_rx, CONFIG_FLASH_LOG_LEVEL);
29 
30 #define FLASH_RX_CF_INCLUDED DT_PROP(DT_NODELABEL(code_flash), programming_enable)
31 #define ERASE_BLOCK_SIZE_0   DT_PROP(DT_INST(0, renesas_rx_nv_flash), erase_block_size)
32 #define ERASE_BLOCK_SIZE_1   DT_PROP(DT_INST(1, renesas_rx_nv_flash), erase_block_size)
33 
34 BUILD_ASSERT((ERASE_BLOCK_SIZE_0 % FLASH_CF_BLOCK_SIZE) == 0,
35 	     "erase-block-size expected to be a multiple of a block size");
36 BUILD_ASSERT((ERASE_BLOCK_SIZE_1 % FLASH_DF_BLOCK_SIZE) == 0,
37 	     "erase-block-size expected to be a multiple of a block size");
38 
39 /* Flags, set from Callback function */
40 static volatile struct flash_rx_event flash_event = {
41 	.erase_complete = false,
42 	.write_complete = false,
43 	.error = false,
44 };
45 
46 #ifdef CONFIG_FLASH_RENESAS_RX_BGO_ENABLED
flash_bgo_callback(void * event)47 static void flash_bgo_callback(void *event)
48 {
49 	flash_int_cb_args_t *ready_event = event;
50 
51 	if (FLASH_INT_EVENT_ERASE_COMPLETE == ready_event->event) {
52 		flash_event.erase_complete = true;
53 	} else if (FLASH_INT_EVENT_WRITE_COMPLETE == ready_event->event) {
54 		flash_event.write_complete = true;
55 	} else if (FLASH_INT_EVENT_ERR_FAILURE == ready_event->event) {
56 		flash_event.error = true;
57 	} else {
58 		/* Do nothing */
59 	}
60 }
61 #endif
62 
flash_rx_valid_range(off_t area_size,off_t offset,size_t len)63 static inline bool flash_rx_valid_range(off_t area_size, off_t offset, size_t len)
64 {
65 	if ((offset < 0) || (offset >= area_size) || ((area_size - offset) < len)) {
66 		return false;
67 	}
68 
69 	return true;
70 }
71 
flash_rx_get_size(const struct device * dev,uint64_t * size)72 static int flash_rx_get_size(const struct device *dev, uint64_t *size)
73 {
74 	struct flash_rx_data *flash_data = dev->data;
75 	*size = (uint64_t)flash_data->area_size;
76 
77 	return 0;
78 }
79 
80 #if CONFIG_FLASH_PAGE_LAYOUT
flash_rx_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)81 static void flash_rx_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
82 				 size_t *layout_size)
83 {
84 	struct flash_rx_data *flash_data = dev->data;
85 	static struct flash_pages_layout flash_rx_layout[1];
86 
87 	if (flash_data->FlashRegion == DATA_FLASH) {
88 		/* Flash layout in data flash region */
89 		flash_rx_layout[0].pages_count = flash_data->area_size / FLASH_DF_BLOCK_SIZE;
90 		flash_rx_layout[0].pages_size = FLASH_DF_BLOCK_SIZE;
91 	} else {
92 		/* Flash layout in code flash region */
93 		flash_rx_layout[0].pages_count = flash_data->area_size / FLASH_CF_BLOCK_SIZE;
94 		flash_rx_layout[0].pages_size = FLASH_CF_BLOCK_SIZE;
95 	}
96 
97 	*layout = flash_rx_layout;
98 	*layout_size = 1;
99 }
100 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
101 
flash_rx_get_parameters(const struct device * dev)102 static const struct flash_parameters *flash_rx_get_parameters(const struct device *dev)
103 {
104 	const struct flash_rx_config *config = dev->config;
105 
106 	return &config->flash_rx_parameters;
107 }
108 
flash_rx_read(const struct device * dev,off_t offset,void * data,size_t len)109 static int flash_rx_read(const struct device *dev, off_t offset, void *data, size_t len)
110 {
111 	struct flash_rx_data *flash_data = dev->data;
112 
113 	if (!len) {
114 		return 0;
115 	}
116 
117 	if (!flash_rx_valid_range(flash_data->area_size, offset, len)) {
118 		return -EINVAL;
119 	}
120 
121 	LOG_DBG("read 0x%lx, len: %u", (long)(offset + flash_data->area_address),
122 		(unsigned int)len);
123 
124 	memcpy(data, (uint8_t *)(offset + flash_data->area_address), len);
125 
126 	return 0;
127 }
128 
flash_rx_write(const struct device * dev,off_t offset,const void * data,size_t len)129 static int flash_rx_write(const struct device *dev, off_t offset, const void *data, size_t len)
130 {
131 	struct flash_rx_data *flash_data = dev->data;
132 	flash_err_t err;
133 	int key = 0, result = 0;
134 
135 	if (!len) {
136 		return 0;
137 	}
138 
139 	if (!flash_rx_valid_range(flash_data->area_size, offset, len)) {
140 		return -EINVAL;
141 	}
142 
143 	LOG_DBG("write 0x%lx, len: %u", (long)(offset + flash_data->area_address),
144 		(unsigned int)len);
145 
146 	/* Disable interrupts during code flash operations */
147 	if (flash_data->FlashRegion == CODE_FLASH) {
148 		key = irq_lock();
149 	}
150 
151 	k_sem_take(&flash_data->transfer_sem, K_FOREVER);
152 
153 	err = R_FLASH_Write((uint32_t)data, (long)(offset + flash_data->area_address), len);
154 	if (err != FLASH_SUCCESS) {
155 		result = -EIO;
156 		goto out;
157 	}
158 
159 	if (flash_data->FlashRegion == DATA_FLASH) {
160 #ifdef CONFIG_FLASH_RENESAS_RX_BGO_ENABLED
161 		/* Waitting for the write complete event flag, if BGO is SET */
162 		while (!(flash_event.write_complete || flash_event.error)) {
163 			k_sleep(K_USEC(10));
164 		}
165 
166 		if (flash_event.error) {
167 			LOG_ERR("write error=%d", (int)err);
168 			result = -EIO;
169 			goto out;
170 		}
171 		flash_event.error = false;
172 		flash_event.write_complete = false;
173 #endif /* CONFIG_FLASH_RENESAS_RX_BGO_ENABLED */
174 	}
175 
176 out:
177 	if (flash_data->FlashRegion == CODE_FLASH) {
178 		irq_unlock(key);
179 	}
180 
181 	k_sem_give(&flash_data->transfer_sem);
182 
183 	return result;
184 }
185 
flash_rx_erase(const struct device * dev,off_t offset,size_t len)186 static int flash_rx_erase(const struct device *dev, off_t offset, size_t len)
187 {
188 	struct flash_rx_data *flash_data = dev->data;
189 	static struct flash_pages_info page_info_off;
190 	flash_err_t err;
191 	uint32_t block_num;
192 	int ret, key = 0, result = 0;
193 
194 	if (!len) {
195 		return 0;
196 	}
197 
198 	if (!flash_rx_valid_range(flash_data->area_size, offset, len)) {
199 		return -EINVAL;
200 	}
201 
202 	/* Get the info of the input offset */
203 	ret = flash_get_page_info_by_offs(dev, offset, &page_info_off);
204 	if (ret != 0) {
205 		return -EINVAL;
206 	}
207 
208 	/* offset is expected to be a start of block address */
209 	if (offset != page_info_off.start_offset) {
210 		return -EINVAL;
211 	}
212 
213 	/* len expected to a multiple of block size */
214 	/* code and data region have the same block size */
215 	if ((len % FLASH_DF_BLOCK_SIZE) != 0) {
216 		return -EINVAL;
217 	}
218 
219 	/* get the number block to erase */
220 	block_num = (uint32_t)(len / FLASH_DF_BLOCK_SIZE);
221 
222 	LOG_DBG("erase 0x%lx, len: %u", (long)(offset + flash_data->area_address),
223 		(unsigned int)len);
224 
225 	if (block_num > 0) {
226 
227 		/* Disable interrupts during code flash operations */
228 		if (flash_data->FlashRegion == CODE_FLASH) {
229 			key = irq_lock();
230 		}
231 
232 		k_sem_take(&flash_data->transfer_sem, K_FOREVER);
233 
234 		err = R_FLASH_Erase((long)(flash_data->area_address + offset), block_num);
235 		if (err != FLASH_SUCCESS) {
236 			result = -EIO;
237 			goto out;
238 		}
239 
240 		if (flash_data->FlashRegion == DATA_FLASH) {
241 #ifdef CONFIG_FLASH_RENESAS_RX_BGO_ENABLED
242 			/* Waitting for the write complete event flag, if BGO is SET */
243 			while (!(flash_event.erase_complete || flash_event.error)) {
244 				k_sleep(K_USEC(10));
245 			}
246 
247 			if (flash_event.error) {
248 				LOG_ERR("erase error=%d", (int)err);
249 				result = -EIO;
250 				goto out;
251 			}
252 			flash_event.error = false;
253 			flash_event.erase_complete = false;
254 #endif /* CONFIG_FLASH_RENESAS_RX_BGO_ENABLED */
255 		}
256 	}
257 
258 out:
259 	if (flash_data->FlashRegion == CODE_FLASH) {
260 		irq_unlock(key);
261 	}
262 
263 	k_sem_give(&flash_data->transfer_sem);
264 
265 	return result;
266 }
267 
268 #ifdef CONFIG_FLASH_RENESAS_RX_BGO_ENABLED
269 #define IRQ_FLASH_CONFIG_INIT(index)                                                               \
270 	IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(index), frdyi, irq),                                \
271 		    DT_IRQ_BY_NAME(DT_DRV_INST(index), frdyi, priority), Excep_FCU_FRDYI,          \
272 		    DEVICE_DT_INST_GET(index), 0);                                                 \
273                                                                                                    \
274 	irq_enable(DT_INST_IRQ_BY_NAME(index, frdyi, irq));
275 #endif /* CONFIG_FLASH_RENESAS_RX_BGO_ENABLED */
276 
flash_rx_controller_init(const struct device * dev)277 static int flash_rx_controller_init(const struct device *dev)
278 {
279 	const struct device *dev_ctrl = DEVICE_DT_INST_GET(0);
280 	struct flash_rx_data *flash_data = dev->data;
281 
282 	if (!device_is_ready(dev_ctrl)) {
283 		return -ENODEV;
284 	}
285 
286 	if (flash_data->area_address == FLASH_DF_BLOCK_0) {
287 		flash_data->FlashRegion = DATA_FLASH;
288 	} else {
289 #ifdef CONFIG_FLASH_RENESAS_RX_BGO_ENABLED
290 		LOG_ERR("Please do not enable BGO in code flash programming");
291 		return -EPERM;
292 #endif
293 		if (!FLASH_RX_CF_INCLUDED) {
294 			/* Enables code flash configuration before usage */
295 			LOG_ERR("Code flash is not enabled");
296 			return -ENODEV;
297 		}
298 
299 		flash_data->FlashRegion = CODE_FLASH;
300 	}
301 
302 	if (flash_data->FlashRegion == DATA_FLASH) {
303 #ifdef CONFIG_FLASH_RENESAS_RX_BGO_ENABLED
304 		/* Register irq flash configs */
305 		IRQ_FLASH_CONFIG_INIT(0);
306 		flash_interrupt_config_t cb_func_info;
307 
308 		cb_func_info.pcallback = flash_bgo_callback;
309 		cb_func_info.int_priority = DT_IRQ_BY_NAME(DT_DRV_INST(0), frdyi, priority);
310 
311 		/* Set callback function */
312 		flash_err_t err =
313 			R_FLASH_Control(FLASH_CMD_SET_BGO_CALLBACK, (void *)&cb_func_info);
314 		if (err != FLASH_SUCCESS) {
315 			LOG_DBG("set bgo callback error=%d", (int)err);
316 			return -EIO;
317 		}
318 #endif
319 	}
320 	/* Init semaphore */
321 	k_sem_init(&flash_data->transfer_sem, 1, 1);
322 
323 	return 0;
324 }
325 
flash_rx_init(const struct device * dev)326 static int flash_rx_init(const struct device *dev)
327 {
328 	ARG_UNUSED(dev);
329 	flash_err_t err;
330 
331 	err = R_FLASH_Open();
332 	if (err != FLASH_SUCCESS) {
333 		LOG_DBG("open error=%d", (int)err);
334 		return -EIO;
335 	}
336 
337 	return 0;
338 }
339 
340 static DEVICE_API(flash, flash_rx_api) = {
341 	.erase = flash_rx_erase,
342 	.write = flash_rx_write,
343 	.read = flash_rx_read,
344 	.get_parameters = flash_rx_get_parameters,
345 	.get_size = flash_rx_get_size,
346 #ifdef CONFIG_FLASH_PAGE_LAYOUT
347 	.page_layout = flash_rx_page_layout,
348 #endif
349 };
350 
351 #define FLASH_RX_INIT(index)                                                                       \
352 	struct flash_rx_data flash_rx_data_##index = {                                             \
353 		.area_address = DT_REG_ADDR(index),                                                \
354 		.area_size = DT_REG_SIZE(index),                                                   \
355 	};                                                                                         \
356 	static struct flash_rx_config flash_rx_config_##index = {                                  \
357 		.flash_rx_parameters = {                                                           \
358 			.erase_value = (0xff),                                                     \
359 			.write_block_size = DT_PROP(index, write_block_size),                      \
360 		}};                                                                                \
361 	DEVICE_DT_DEFINE(index, flash_rx_controller_init, NULL, &flash_rx_data_##index,            \
362 			 &flash_rx_config_##index, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY,        \
363 			 &flash_rx_api);
364 
365 DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(0), FLASH_RX_INIT);
366 
367 /* define the flash controller device just to run the init. */
368 DEVICE_DT_DEFINE(DT_DRV_INST(0), flash_rx_init, NULL, NULL, NULL, PRE_KERNEL_1,
369 		 CONFIG_FLASH_INIT_PRIORITY, NULL);
370