1 /*
2 * Copyright (c) 2024-2025 Renesas Electronics Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
8 #include <zephyr/logging/log.h>
9 #include <string.h>
10 #include <soc.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/init.h>
15 #include <zephyr/irq.h>
16 #include "flash_hp_ra.h"
17
18 #define DT_DRV_COMPAT renesas_ra_flash_hp_controller
19
20 LOG_MODULE_REGISTER(flash_hp_ra, CONFIG_FLASH_LOG_LEVEL);
21
22 #define ERASE_BLOCK_SIZE_0 DT_PROP(DT_INST(0, renesas_ra_nv_flash), erase_block_size)
23 #define ERASE_BLOCK_SIZE_1 DT_PROP(DT_INST(1, renesas_ra_nv_flash), erase_block_size)
24
25 BUILD_ASSERT((ERASE_BLOCK_SIZE_0 % FLASH_HP_CF_BLOCK_8KB_SIZE) == 0,
26 "erase-block-size expected to be a multiple of a block size");
27 BUILD_ASSERT((ERASE_BLOCK_SIZE_1 % FLASH_HP_DF_BLOCK_SIZE) == 0,
28 "erase-block-size expected to be a multiple of a block size");
29
30 /* Flags, set from Callback function */
31 static volatile struct event_flash g_event_flash = {
32 .erase_complete = false,
33 .write_complete = false,
34 };
35
36 static struct flash_pages_layout flash_ra_layout[5];
37
38 void fcu_frdyi_isr(void);
39 void fcu_fiferr_isr(void);
40
bgo_callback(flash_callback_args_t * p_args)41 void bgo_callback(flash_callback_args_t *p_args)
42 {
43 if (FLASH_EVENT_ERASE_COMPLETE == p_args->event) {
44 g_event_flash.erase_complete = true;
45 } else {
46 g_event_flash.write_complete = true;
47 }
48 }
49
flash_ra_valid_range(struct flash_hp_ra_data * flash_data,off_t offset,size_t len)50 static bool flash_ra_valid_range(struct flash_hp_ra_data *flash_data, off_t offset, size_t len)
51 {
52 #if defined(CONFIG_DUAL_BANK_MODE)
53 if (flash_data->FlashRegion == DATA_FLASH) {
54 if ((offset < 0) || (offset >= flash_data->area_size) ||
55 (flash_data->area_size - offset < len) || (len > UINT32_MAX - offset)) {
56 return false;
57 }
58 } else {
59 if ((offset < 0) || (offset >= FLASH_HP_CF_DUAL_HIGH_END_ADDRESS) ||
60 (offset >= FLASH_HP_CF_DUAL_LOW_END_ADDRESS &&
61 offset < FLASH_HP_BANK2_OFFSET) ||
62 ((len + offset) > FLASH_HP_CF_DUAL_HIGH_END_ADDRESS) ||
63 ((len + offset) > FLASH_HP_CF_DUAL_LOW_END_ADDRESS &&
64 (len + offset) < FLASH_HP_BANK2_OFFSET) ||
65 (len > UINT32_MAX - offset)) {
66 return false;
67 }
68 }
69 #else
70 if ((offset < 0) || (offset >= flash_data->area_size) ||
71 (flash_data->area_size - offset < len) || (len > UINT32_MAX - offset)) {
72 return false;
73 }
74 #endif
75 return true;
76 }
77
flash_ra_read(const struct device * dev,off_t offset,void * data,size_t len)78 static int flash_ra_read(const struct device *dev, off_t offset, void *data, size_t len)
79 {
80 struct flash_hp_ra_data *flash_data = dev->data;
81
82 if (!flash_ra_valid_range(flash_data, offset, len)) {
83 return -EINVAL;
84 }
85
86 if (!len) {
87 return 0;
88 }
89
90 LOG_DBG("flash: read 0x%lx, len: %u", (long)(offset + flash_data->area_address), len);
91
92 memcpy(data, (uint8_t *)(offset + flash_data->area_address), len);
93
94 return 0;
95 }
96
flash_ra_erase(const struct device * dev,off_t offset,size_t len)97 static int flash_ra_erase(const struct device *dev, off_t offset, size_t len)
98 {
99 struct flash_hp_ra_data *flash_data = dev->data;
100 struct flash_hp_ra_controller *dev_ctrl = flash_data->controller;
101 static struct flash_pages_info page_info_off, page_info_len;
102 fsp_err_t err;
103 uint32_t block_num;
104 int rc, rc2;
105 int key = 0;
106 bool is_contain_end_block = false;
107
108 if (!flash_ra_valid_range(flash_data, offset, len)) {
109 return -EINVAL;
110 }
111
112 if (!len) {
113 return 0;
114 }
115
116 LOG_DBG("flash: erase 0x%lx, len: %u", (long)(offset + flash_data->area_address), len);
117
118 rc = flash_get_page_info_by_offs(dev, offset, &page_info_off);
119
120 if (rc != 0) {
121 return -EINVAL;
122 }
123
124 if (offset != page_info_off.start_offset) {
125 return -EINVAL;
126 }
127
128 if (flash_data->FlashRegion == CODE_FLASH) {
129 #if defined(CONFIG_DUAL_BANK_MODE)
130 if ((offset + len) == (uint32_t)FLASH_HP_CF_DUAL_HIGH_END_ADDRESS) {
131 page_info_len.index = FLASH_HP_CF_BLOCK_32KB_DUAL_HIGH_END + 1;
132 is_contain_end_block = true;
133 }
134 #else
135 if ((offset + len) == (uint32_t)DT_REG_SIZE(DT_NODELABEL(flash0))) {
136 page_info_len.index = FLASH_HP_CF_BLOCK_32KB_LINEAR_END + 1;
137 is_contain_end_block = true;
138 }
139 #endif
140 } else {
141 if ((offset + len) == (uint32_t)DT_REG_SIZE(DT_NODELABEL(flash1))) {
142 page_info_len.index = FLASH_HP_DF_BLOCK_END;
143 is_contain_end_block = true;
144 }
145 }
146
147 if (!is_contain_end_block) {
148 rc2 = flash_get_page_info_by_offs(dev, (offset + len), &page_info_len);
149 if (rc2 != 0) {
150 return -EINVAL;
151 }
152 if ((offset + len) != (page_info_len.start_offset)) {
153 return -EIO;
154 }
155 }
156
157 block_num = (uint32_t)((page_info_len.index) - page_info_off.index);
158
159 if (block_num > 0) {
160 if (flash_data->FlashRegion == CODE_FLASH) {
161 /* Disable interrupts during code flash operations */
162 key = irq_lock();
163 } else {
164 k_sem_take(&dev_ctrl->ctrl_sem, K_FOREVER);
165 }
166
167 err = R_FLASH_HP_Erase(&dev_ctrl->flash_ctrl,
168 (long)(flash_data->area_address + offset), block_num);
169
170 if (err != FSP_SUCCESS) {
171 if (flash_data->FlashRegion == CODE_FLASH) {
172 irq_unlock(key);
173 } else {
174 k_sem_give(&dev_ctrl->ctrl_sem);
175 }
176 return -EIO;
177 }
178
179 if (flash_data->FlashRegion == DATA_FLASH) {
180 /* Wait for the erase complete event flag, if BGO is SET */
181 if (true == dev_ctrl->fsp_config.data_flash_bgo) {
182 while (!g_event_flash.erase_complete) {
183 k_sleep(K_USEC(10));
184 }
185 g_event_flash.erase_complete = false;
186 }
187 }
188
189 if (flash_data->FlashRegion == CODE_FLASH) {
190 irq_unlock(key);
191 } else {
192 k_sem_give(&dev_ctrl->ctrl_sem);
193 }
194 }
195
196 return 0;
197 }
198
flash_ra_write(const struct device * dev,off_t offset,const void * data,size_t len)199 static int flash_ra_write(const struct device *dev, off_t offset, const void *data, size_t len)
200 {
201 fsp_err_t err;
202 struct flash_hp_ra_data *flash_data = dev->data;
203 struct flash_hp_ra_controller *dev_ctrl = flash_data->controller;
204 int key = 0;
205
206 if (!flash_ra_valid_range(flash_data, offset, len)) {
207 return -EINVAL;
208 }
209
210 if (!len) {
211 return 0;
212 }
213
214 LOG_DBG("flash: write 0x%lx, len: %u", (long)(offset + flash_data->area_address), len);
215
216 if (flash_data->FlashRegion == CODE_FLASH) {
217 /* Disable interrupts during code flash operations */
218 key = irq_lock();
219 } else {
220 k_sem_take(&dev_ctrl->ctrl_sem, K_FOREVER);
221 }
222
223 err = R_FLASH_HP_Write(&dev_ctrl->flash_ctrl, (uint32_t)data,
224 (long)(offset + flash_data->area_address), len);
225
226 if (err != FSP_SUCCESS) {
227 if (flash_data->FlashRegion == CODE_FLASH) {
228 irq_unlock(key);
229 } else {
230 k_sem_give(&dev_ctrl->ctrl_sem);
231 }
232 return -EIO;
233 }
234
235 if (flash_data->FlashRegion == DATA_FLASH) {
236 /* Wait for the write complete event flag, if BGO is SET */
237 if (true == dev_ctrl->fsp_config.data_flash_bgo) {
238 while (!g_event_flash.write_complete) {
239 k_sleep(K_USEC(10));
240 }
241 g_event_flash.write_complete = false;
242 }
243 }
244
245 if (flash_data->FlashRegion == CODE_FLASH) {
246 irq_unlock(key);
247 } else {
248 k_sem_give(&dev_ctrl->ctrl_sem);
249 }
250
251 return 0;
252 }
253
flash_ra_get_size(const struct device * dev,uint64_t * size)254 static int flash_ra_get_size(const struct device *dev, uint64_t *size)
255 {
256 struct flash_hp_ra_data *flash_data = dev->data;
257 *size = (uint64_t)flash_data->area_size;
258
259 return 0;
260 }
261
262 #ifdef CONFIG_FLASH_PAGE_LAYOUT
flash_ra_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)263 void flash_ra_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
264 size_t *layout_size)
265 {
266 struct flash_hp_ra_data *flash_data = dev->data;
267
268 if (flash_data->FlashRegion == DATA_FLASH) {
269 flash_ra_layout[0].pages_count = flash_data->area_size / FLASH_HP_DF_BLOCK_SIZE;
270 flash_ra_layout[0].pages_size = FLASH_HP_DF_BLOCK_SIZE;
271
272 *layout_size = 1;
273 } else {
274 #if defined(CONFIG_DUAL_BANK_MODE)
275 flash_ra_layout[0].pages_count =
276 (FLASH_HP_CF_BLOCK_8KB_LOW_END - FLASH_HP_CF_BLOCK_8KB_LOW_START) + 1;
277 flash_ra_layout[0].pages_size = FLASH_HP_CF_BLOCK_8KB_SIZE;
278
279 flash_ra_layout[1].pages_count = (FLASH_HP_CF_BLOCK_32KB_DUAL_LOW_END -
280 FLASH_HP_CF_BLOCK_32KB_DUAL_LOW_START) +
281 1;
282 flash_ra_layout[1].pages_size = FLASH_HP_CF_BLOCK_32KB_SIZE;
283
284 flash_ra_layout[2].pages_count = FLASH_HP_CF_NUM_BLOCK_RESERVED;
285 flash_ra_layout[2].pages_size =
286 (FLASH_HP_BANK2_OFFSET -
287 (flash_ra_layout[0].pages_count * flash_ra_layout[0].pages_size) -
288 (flash_ra_layout[1].pages_count * flash_ra_layout[1].pages_size)) /
289 FLASH_HP_CF_NUM_BLOCK_RESERVED;
290
291 flash_ra_layout[3].pages_count =
292 (FLASH_HP_CF_BLOCK_8KB_HIGH_END - FLASH_HP_CF_BLOCK_8KB_HIGH_START) + 1;
293 flash_ra_layout[3].pages_size = FLASH_HP_CF_BLOCK_8KB_SIZE;
294
295 /* The final block is the dummy block */
296 flash_ra_layout[4].pages_count = (FLASH_HP_CF_BLOCK_32KB_DUAL_HIGH_END + 1 -
297 FLASH_HP_CF_BLOCK_32KB_DUAL_HIGH_START) +
298 1;
299 flash_ra_layout[4].pages_size = FLASH_HP_CF_BLOCK_32KB_SIZE;
300
301 *layout_size = 5;
302 #else
303 flash_ra_layout[0].pages_count =
304 (FLASH_HP_CF_BLOCK_8KB_LOW_END - FLASH_HP_CF_BLOCK_8KB_LOW_START) + 1;
305 flash_ra_layout[0].pages_size = FLASH_HP_CF_BLOCK_8KB_SIZE;
306 flash_ra_layout[1].pages_count =
307 (FLASH_HP_CF_BLOCK_32KB_LINEAR_END - FLASH_HP_CF_BLOCK_32KB_LINEAR_START) +
308 1;
309 flash_ra_layout[1].pages_size = FLASH_HP_CF_BLOCK_32KB_SIZE;
310
311 *layout_size = 2;
312 #endif
313 }
314
315 *layout = flash_ra_layout;
316 }
317 #endif
318
flash_ra_get_parameters(const struct device * dev)319 static const struct flash_parameters *flash_ra_get_parameters(const struct device *dev)
320 {
321 const struct flash_hp_ra_config *config = dev->config;
322
323 return &config->flash_ra_parameters;
324 }
325
326 static struct flash_hp_ra_controller flash_hp_ra_controller = {
327 .fsp_config = {
328 .data_flash_bgo = true,
329 .p_callback = bgo_callback,
330 .p_context = NULL,
331 .irq = (IRQn_Type)DT_INST_IRQ_BY_NAME(0, frdyi, irq),
332 .err_irq = (IRQn_Type)DT_INST_IRQ_BY_NAME(0, fiferr, irq),
333 .err_ipl = DT_INST_IRQ_BY_NAME(0, fiferr, priority),
334 .ipl = DT_INST_IRQ_BY_NAME(0, frdyi, priority),
335 }};
336
337 #ifdef CONFIG_FLASH_EX_OP_ENABLED
flash_ra_ex_op(const struct device * dev,uint16_t code,const uintptr_t in,void * out)338 static int flash_ra_ex_op(const struct device *dev, uint16_t code, const uintptr_t in, void *out)
339 {
340 int err = -ENOTSUP;
341
342 switch (code) {
343 #if defined(CONFIG_FLASH_RA_WRITE_PROTECT)
344 case FLASH_RA_EX_OP_WRITE_PROTECT:
345 err = flash_ra_ex_op_write_protect(dev, in, out);
346 break;
347 #endif /* CONFIG_FLASH_RA_WRITE_PROTECT */
348
349 default:
350 break;
351 }
352
353 return err;
354 }
355 #endif
356
flash_ra_init(const struct device * dev)357 static int flash_ra_init(const struct device *dev)
358 {
359 const struct device *dev_ctrl = DEVICE_DT_INST_GET(0);
360 struct flash_hp_ra_data *flash_data = dev->data;
361
362 if (!device_is_ready(dev_ctrl)) {
363 return -ENODEV;
364 }
365
366 if (flash_data->area_address == FLASH_HP_DF_START) {
367 flash_data->FlashRegion = DATA_FLASH;
368 } else {
369 flash_data->FlashRegion = CODE_FLASH;
370 }
371
372 flash_data->controller = dev_ctrl->data;
373
374 return 0;
375 }
376
flash_controller_ra_irq_config_func(const struct device * dev)377 static void flash_controller_ra_irq_config_func(const struct device *dev)
378 {
379 ARG_UNUSED(dev);
380
381 R_ICU->IELSR[DT_IRQ_BY_NAME(DT_DRV_INST(0), frdyi, irq)] =
382 BSP_PRV_IELS_ENUM(EVENT_FCU_FRDYI);
383 R_ICU->IELSR[DT_IRQ_BY_NAME(DT_DRV_INST(0), fiferr, irq)] =
384 BSP_PRV_IELS_ENUM(EVENT_FCU_FIFERR);
385
386 IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), frdyi, irq),
387 DT_IRQ_BY_NAME(DT_DRV_INST(0), frdyi, priority), fcu_frdyi_isr,
388 DEVICE_DT_INST_GET(0), 0);
389 IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), fiferr, irq),
390 DT_IRQ_BY_NAME(DT_DRV_INST(0), fiferr, priority), fcu_fiferr_isr,
391 DEVICE_DT_INST_GET(0), 0);
392
393 irq_enable(DT_INST_IRQ_BY_NAME(0, frdyi, irq));
394 irq_enable(DT_INST_IRQ_BY_NAME(0, fiferr, irq));
395 }
396
flash_controller_ra_init(const struct device * dev)397 static int flash_controller_ra_init(const struct device *dev)
398 {
399 fsp_err_t err;
400 const struct flash_hp_ra_controller_config *cfg = dev->config;
401 struct flash_hp_ra_controller *data = dev->data;
402
403 cfg->irq_config(dev);
404
405 err = R_FLASH_HP_Open(&data->flash_ctrl, &data->fsp_config);
406
407 if (err != FSP_SUCCESS) {
408 LOG_DBG("flash: open error=%d", (int)err);
409 return -EIO;
410 }
411
412 k_sem_init(&data->ctrl_sem, 1, 1);
413
414 return 0;
415 }
416
417 static struct flash_hp_ra_controller_config flash_hp_ra_controller_config = {
418 .irq_config = flash_controller_ra_irq_config_func,
419 };
420
421 static DEVICE_API(flash, flash_ra_api) = {
422 .erase = flash_ra_erase,
423 .write = flash_ra_write,
424 .read = flash_ra_read,
425 .get_parameters = flash_ra_get_parameters,
426 .get_size = flash_ra_get_size,
427 #ifdef CONFIG_FLASH_PAGE_LAYOUT
428 .page_layout = flash_ra_page_layout,
429 #endif
430 #ifdef CONFIG_FLASH_EX_OP_ENABLED
431 .ex_op = flash_ra_ex_op,
432 #endif
433 };
434
435 #define RA_FLASH_INIT(index) \
436 struct flash_hp_ra_data flash_hp_ra_data_##index = {.area_address = DT_REG_ADDR(index), \
437 .area_size = DT_REG_SIZE(index)}; \
438 static struct flash_hp_ra_config flash_hp_ra_config_##index = { \
439 .flash_ra_parameters = { \
440 .write_block_size = GET_SIZE( \
441 (CHECK_EQ(DT_REG_ADDR(index), FLASH_HP_DF_START)), 4, 128), \
442 .erase_value = 0xff, \
443 }}; \
444 \
445 DEVICE_DT_DEFINE(index, flash_ra_init, NULL, &flash_hp_ra_data_##index, \
446 &flash_hp_ra_config_##index, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, \
447 &flash_ra_api);
448
449 DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(0), RA_FLASH_INIT);
450
451 /* define the flash controller device just to run the init. */
452 DEVICE_DT_DEFINE(DT_DRV_INST(0), flash_controller_ra_init, NULL, &flash_hp_ra_controller,
453 &flash_hp_ra_controller_config, PRE_KERNEL_1, CONFIG_FLASH_INIT_PRIORITY, NULL);
454