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