Skip to content

Commit e2e518c

Browse files
drivers: flash: Initial support Flash-LP driver for Renesas RA
Initial support Flash-LP driver for Renesas RA Signed-off-by: Khoa Nguyen <khoa.nguyen.xh@renesas.com> Signed-off-by: Phi Tran <phi.tran.jg@bp.renesas.com>
1 parent a5c31db commit e2e518c

File tree

6 files changed

+496
-1
lines changed

6 files changed

+496
-1
lines changed

drivers/flash/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_MRAM soc_flash_nrf_mram.c)
5757
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_RRAM soc_flash_nrf_rram.c)
5858
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER soc_flash_numaker.c)
5959
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER_RMC soc_flash_numaker_rmc.c)
60+
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_RENESAS_RA_LP soc_flash_renesas_ra_lp.c)
6061
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_RV32M1 soc_flash_rv32m1.c)
6162
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c)
6263
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM0 flash_sam0.c)

drivers/flash/Kconfig.renesas_ra

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,19 @@ config SOC_FLASH_RENESAS_RA_HP
1414
select FLASH_HAS_EX_OP if(SOC_SERIES_RA8M1 || SOC_SERIES_RA8D1 || SOC_SERIES_RA8T1)
1515
select USE_RA_FSP_FLASH_HP
1616
help
17-
Enable Flash HP driver for RA series
17+
Enable Flash High-Performance driver for RA series
18+
19+
config SOC_FLASH_RENESAS_RA_LP
20+
bool "RA Flash LP driver"
21+
depends on DT_HAS_RENESAS_RA_FLASH_LP_CONTROLLER_ENABLED
22+
default y
23+
select FLASH_HAS_DRIVER_ENABLED
24+
select FLASH_PAGE_LAYOUT
25+
select FLASH_HAS_PAGE_LAYOUT
26+
select FLASH_HAS_EXPLICIT_ERASE
27+
select USE_RA_FSP_FLASH_LP
28+
help
29+
Enable Flash Low-Power driver for RA series
1830

1931
if SOC_FLASH_RENESAS_RA_HP
2032

@@ -32,3 +44,13 @@ config FLASH_RENESAS_RA_HP_BGO
3244
Enable Background operations (BGOs)
3345

3446
endif # SOC_FLASH_RENESAS_RA_HP
47+
48+
if SOC_FLASH_RENESAS_RA_LP
49+
50+
config FLASH_RENESAS_RA_LP_BGO
51+
bool "Background operations feature"
52+
default y
53+
help
54+
Enable Background operations (BGOs)
55+
56+
endif # SOC_FLASH_RENESAS_RA_LP
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
/*
2+
* Copyright (c) 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 "soc_flash_renesas_ra_lp.h"
17+
18+
LOG_MODULE_REGISTER(flash_renesas_ra_lp, CONFIG_FLASH_LOG_LEVEL);
19+
20+
static struct flash_pages_layout code_flash_ra_layout[1];
21+
static struct flash_pages_layout data_flash_ra_layout[1];
22+
23+
#if defined(CONFIG_FLASH_RENESAS_RA_LP_BGO)
24+
void fcu_frdyi_isr(void);
25+
26+
void flash_bgo_callback(flash_callback_args_t *p_args)
27+
{
28+
atomic_t *event_flag = (atomic_t *)(p_args->p_context);
29+
30+
if (FLASH_EVENT_ERASE_COMPLETE == p_args->event) {
31+
atomic_or(event_flag, FLASH_FLAG_ERASE_COMPLETE);
32+
} else if (FLASH_EVENT_WRITE_COMPLETE == p_args->event) {
33+
atomic_or(event_flag, FLASH_FLAG_WRITE_COMPLETE);
34+
} else {
35+
atomic_or(event_flag, FLASH_FLAG_GET_ERROR);
36+
}
37+
}
38+
#endif /* CONFIG_FLASH_RENESAS_RA_LP_BGO */
39+
40+
static bool flash_ra_valid_range(off_t area_size, off_t offset, size_t len)
41+
{
42+
if ((offset < 0) || offset >= area_size || (area_size - offset) < len ||
43+
(len > UINT32_MAX - offset)) {
44+
return false;
45+
}
46+
47+
return true;
48+
}
49+
50+
static int flash_ra_read(const struct device *dev, off_t offset, void *data, size_t len)
51+
{
52+
struct flash_lp_ra_data *flash_data = dev->data;
53+
54+
if (!flash_ra_valid_range(flash_data->area_size, offset, len)) {
55+
return -EINVAL;
56+
}
57+
58+
if (!len) {
59+
return 0;
60+
}
61+
62+
LOG_DBG("flash: read 0x%lx, len: %u", (long)(offset + flash_data->area_address), len);
63+
64+
memcpy(data, (uint8_t *)(offset + flash_data->area_address), len);
65+
66+
return 0;
67+
}
68+
69+
static int flash_ra_erase(const struct device *dev, off_t offset, size_t len)
70+
{
71+
struct flash_lp_ra_data *flash_data = dev->data;
72+
struct flash_lp_ra_controller *dev_ctrl = flash_data->controller;
73+
static struct flash_pages_info page_info_off, page_info_len;
74+
fsp_err_t err;
75+
uint32_t block_num;
76+
int rc, rc2, ret = 0;
77+
int key = 0;
78+
bool is_contain_end_block = false;
79+
80+
if (!flash_ra_valid_range(flash_data->area_size, offset, len)) {
81+
return -EINVAL;
82+
}
83+
84+
if (!len) {
85+
return 0;
86+
}
87+
88+
LOG_DBG("flash: erase 0x%lx, len: %u", (long)(offset + flash_data->area_address), len);
89+
90+
rc = flash_get_page_info_by_offs(dev, offset, &page_info_off);
91+
92+
if (rc != 0) {
93+
return -EINVAL;
94+
}
95+
96+
if (offset != page_info_off.start_offset) {
97+
return -EINVAL;
98+
}
99+
100+
if (flash_data->FlashRegion == CODE_FLASH) {
101+
if ((offset + len) == (uint32_t)FLASH_LP_CF_SIZE) {
102+
page_info_len.index = FLASH_LP_CF_BLOCKS_COUNT;
103+
is_contain_end_block = true;
104+
}
105+
} else {
106+
if ((offset + len) == (uint32_t)FLASH_LP_DF_SIZE) {
107+
page_info_len.index = FLASH_LP_DF_BLOCKS_COUNT;
108+
is_contain_end_block = true;
109+
}
110+
}
111+
112+
if (!is_contain_end_block) {
113+
rc2 = flash_get_page_info_by_offs(dev, (offset + len), &page_info_len);
114+
if (rc2 != 0) {
115+
return -EINVAL;
116+
}
117+
if ((offset + len) != (page_info_len.start_offset)) {
118+
return -EIO;
119+
}
120+
}
121+
122+
block_num = (uint32_t)((page_info_len.index) - page_info_off.index);
123+
124+
if (block_num > 0) {
125+
if (flash_data->FlashRegion == CODE_FLASH) {
126+
/* Disable interrupts during code flash operations */
127+
key = irq_lock();
128+
} else {
129+
k_sem_take(&dev_ctrl->ctrl_sem, K_FOREVER);
130+
}
131+
132+
err = R_FLASH_LP_Erase(&dev_ctrl->flash_ctrl,
133+
(long)(flash_data->area_address + offset), block_num);
134+
135+
if (err != FSP_SUCCESS) {
136+
ret = -EIO;
137+
goto end;
138+
}
139+
140+
#if defined(CONFIG_FLASH_RENESAS_RA_LP_BGO)
141+
if (flash_data->FlashRegion == DATA_FLASH) {
142+
/* Wait for the erase complete event flag, if BGO is SET */
143+
while (!(dev_ctrl->flags & FLASH_FLAG_ERASE_COMPLETE)) {
144+
if (dev_ctrl->flags & FLASH_FLAG_GET_ERROR) {
145+
ret = -EIO;
146+
atomic_and(&dev_ctrl->flags, ~FLASH_FLAG_GET_ERROR);
147+
break;
148+
}
149+
k_sleep(K_USEC(10));
150+
}
151+
atomic_and(&dev_ctrl->flags, ~FLASH_FLAG_ERASE_COMPLETE);
152+
}
153+
#endif /* CONFIG_FLASH_RENESAS_RA_LP_BGO */
154+
155+
end:
156+
if (flash_data->FlashRegion == CODE_FLASH) {
157+
irq_unlock(key);
158+
} else {
159+
k_sem_give(&dev_ctrl->ctrl_sem);
160+
}
161+
}
162+
163+
return ret;
164+
}
165+
166+
static int flash_ra_write(const struct device *dev, off_t offset, const void *data, size_t len)
167+
{
168+
fsp_err_t err;
169+
struct flash_lp_ra_data *flash_data = dev->data;
170+
struct flash_lp_ra_controller *dev_ctrl = flash_data->controller;
171+
int key = 0;
172+
int ret = 0;
173+
174+
if (!flash_ra_valid_range(flash_data->area_size, offset, len)) {
175+
return -EINVAL;
176+
}
177+
178+
if (!len) {
179+
return 0;
180+
}
181+
182+
LOG_DBG("flash: write 0x%lx, len: %u", (long)(offset + flash_data->area_address), len);
183+
184+
if (flash_data->FlashRegion == CODE_FLASH) {
185+
/* Disable interrupts during code flash operations */
186+
key = irq_lock();
187+
} else {
188+
k_sem_take(&dev_ctrl->ctrl_sem, K_FOREVER);
189+
}
190+
191+
err = R_FLASH_LP_Write(&dev_ctrl->flash_ctrl, (uint32_t)data,
192+
(long)(offset + flash_data->area_address), len);
193+
194+
if (err != FSP_SUCCESS) {
195+
ret = -EIO;
196+
goto end;
197+
}
198+
199+
#if defined(CONFIG_FLASH_RENESAS_RA_LP_BGO)
200+
if (flash_data->FlashRegion == DATA_FLASH) {
201+
/* Wait for the write complete event flag, if BGO is SET */
202+
while (!(dev_ctrl->flags & FLASH_FLAG_WRITE_COMPLETE)) {
203+
if (dev_ctrl->flags & FLASH_FLAG_GET_ERROR) {
204+
ret = -EIO;
205+
atomic_and(&dev_ctrl->flags, ~FLASH_FLAG_GET_ERROR);
206+
break;
207+
}
208+
k_sleep(K_USEC(10));
209+
}
210+
atomic_and(&dev_ctrl->flags, ~FLASH_FLAG_WRITE_COMPLETE);
211+
}
212+
#endif /* CONFIG_FLASH_RENESAS_RA_LP_BGO */
213+
214+
end:
215+
if (flash_data->FlashRegion == CODE_FLASH) {
216+
irq_unlock(key);
217+
} else {
218+
k_sem_give(&dev_ctrl->ctrl_sem);
219+
}
220+
221+
return ret;
222+
}
223+
224+
static int flash_ra_get_size(const struct device *dev, uint64_t *size)
225+
{
226+
struct flash_lp_ra_data *flash_data = dev->data;
227+
*size = (uint64_t)flash_data->area_size;
228+
229+
return 0;
230+
}
231+
232+
#ifdef CONFIG_FLASH_PAGE_LAYOUT
233+
void flash_ra_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
234+
size_t *layout_size)
235+
{
236+
struct flash_lp_ra_data *flash_data = dev->data;
237+
238+
if (flash_data->FlashRegion == DATA_FLASH) {
239+
data_flash_ra_layout[0].pages_count = FLASH_LP_DF_BLOCKS_COUNT;
240+
data_flash_ra_layout[0].pages_size = FLASH_LP_DF_BLOCK_SIZE;
241+
*layout = data_flash_ra_layout;
242+
} else {
243+
code_flash_ra_layout[0].pages_count = FLASH_LP_CF_BLOCKS_COUNT;
244+
code_flash_ra_layout[0].pages_size = FLASH_LP_CF_BLOCK_SIZE;
245+
*layout = code_flash_ra_layout;
246+
}
247+
248+
*layout_size = 1;
249+
}
250+
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
251+
252+
static const struct flash_parameters *flash_ra_get_parameters(const struct device *dev)
253+
{
254+
const struct flash_lp_ra_config *config = dev->config;
255+
256+
return &config->flash_ra_parameters;
257+
}
258+
259+
static struct flash_lp_ra_controller flash_lp_ra_controller = {
260+
.fsp_config = {
261+
.data_flash_bgo = IS_ENABLED(CONFIG_FLASH_RENESAS_RA_LP_BGO),
262+
#if defined(CONFIG_FLASH_RENESAS_RA_LP_BGO)
263+
.p_callback = flash_bgo_callback,
264+
.p_context = NULL,
265+
.irq = (IRQn_Type)DT_INST_IRQ_BY_NAME(0, frdyi, irq),
266+
.ipl = DT_INST_IRQ_BY_NAME(0, frdyi, priority),
267+
#endif /* CONFIG_FLASH_RENESAS_RA_LP_BGO */
268+
}};
269+
270+
static int flash_ra_init(const struct device *dev)
271+
{
272+
const struct device *dev_ctrl = DEVICE_DT_INST_GET(0);
273+
struct flash_lp_ra_data *flash_data = dev->data;
274+
275+
if (!device_is_ready(dev_ctrl)) {
276+
return -ENODEV;
277+
}
278+
279+
if (flash_data->area_address == FLASH_LP_DF_START) {
280+
flash_data->FlashRegion = DATA_FLASH;
281+
} else {
282+
flash_data->FlashRegion = CODE_FLASH;
283+
}
284+
285+
flash_data->controller = dev_ctrl->data;
286+
287+
return 0;
288+
}
289+
290+
#if defined(CONFIG_FLASH_RENESAS_RA_LP_BGO)
291+
#define FLASH_CONTROLLER_RA_IRQ_INIT \
292+
{ \
293+
R_ICU->IELSR[DT_IRQ_BY_NAME(DT_DRV_INST(0), frdyi, irq)] = \
294+
BSP_PRV_IELS_ENUM(EVENT_FCU_FRDYI); \
295+
\
296+
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), frdyi, irq), \
297+
DT_IRQ_BY_NAME(DT_DRV_INST(0), frdyi, priority), fcu_frdyi_isr, \
298+
DEVICE_DT_INST_GET(0), 0); \
299+
\
300+
irq_enable(DT_INST_IRQ_BY_NAME(0, frdyi, irq)); \
301+
}
302+
#endif /* CONFIG_FLASH_RENESAS_RA_LP_BGO */
303+
304+
static int flash_controller_ra_init(const struct device *dev)
305+
{
306+
fsp_err_t err;
307+
struct flash_lp_ra_controller *data = dev->data;
308+
309+
#if defined(CONFIG_FLASH_RENESAS_RA_LP_BGO)
310+
FLASH_CONTROLLER_RA_IRQ_INIT
311+
#endif /* CONFIG_FLASH_RENESAS_RA_LP_BGO */
312+
313+
k_sem_init(&data->ctrl_sem, 1, 1);
314+
315+
data->fsp_config.p_context = &data->flags;
316+
317+
err = R_FLASH_LP_Open(&data->flash_ctrl, &data->fsp_config);
318+
if (err != FSP_SUCCESS) {
319+
LOG_DBG("flash: open error=%d", (int)err);
320+
return -EIO;
321+
}
322+
323+
return 0;
324+
}
325+
326+
static DEVICE_API(flash, flash_ra_api) = {
327+
.erase = flash_ra_erase,
328+
.write = flash_ra_write,
329+
.read = flash_ra_read,
330+
.get_parameters = flash_ra_get_parameters,
331+
.get_size = flash_ra_get_size,
332+
#ifdef CONFIG_FLASH_PAGE_LAYOUT
333+
.page_layout = flash_ra_page_layout,
334+
#endif
335+
};
336+
337+
#define RA_FLASH_INIT(index) \
338+
static struct flash_lp_ra_config flash_lp_ra_config_##index = { \
339+
.flash_ra_parameters = { \
340+
.write_block_size = DT_PROP(index, write_block_size), \
341+
.erase_value = 0xff, \
342+
}}; \
343+
struct flash_lp_ra_data flash_lp_ra_data_##index = { \
344+
.area_address = DT_REG_ADDR(index), \
345+
.area_size = DT_REG_SIZE(index), \
346+
}; \
347+
\
348+
DEVICE_DT_DEFINE(index, flash_ra_init, NULL, &flash_lp_ra_data_##index, \
349+
&flash_lp_ra_config_##index, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, \
350+
&flash_ra_api);
351+
352+
DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(0), RA_FLASH_INIT);
353+
354+
/* define the flash controller device just to run the init. */
355+
DEVICE_DT_DEFINE(DT_DRV_INST(0), flash_controller_ra_init, NULL, &flash_lp_ra_controller, NULL,
356+
PRE_KERNEL_1, CONFIG_FLASH_INIT_PRIORITY, NULL);

0 commit comments

Comments
 (0)