Skip to content

Commit 106e26a

Browse files
committed
drivers: flash: add NXP S32 QSPI HyperFlash driver
Add support HyperFlash memory devices on a NXP S32 QSPI bus. This driver uses a fixed LUT configuration that defined in HAL RTD HyperFlash driver. Driver allows to read, write and erase HyperFlash devices. Signed-off-by: Cong Nguyen Huu <[email protected]>
1 parent 481262c commit 106e26a

File tree

4 files changed

+367
-8
lines changed

4 files changed

+367
-8
lines changed

drivers/flash/CMakeLists.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,11 @@ zephyr_library_include_directories_ifdef(
149149
)
150150

151151
zephyr_library_sources_ifdef(CONFIG_FLASH_NXP_S32_QSPI_NOR flash_nxp_s32_qspi_nor.c)
152-
zephyr_library_sources_ifdef(CONFIG_FLASH_NXP_S32_QSPI_NOR flash_nxp_s32_qspi.c)
153-
zephyr_library_include_directories_ifdef(
154-
CONFIG_FLASH_NXP_S32_QSPI_NOR
155-
${ZEPHYR_BASE}/drivers/memc
156-
)
152+
zephyr_library_sources_ifdef(CONFIG_FLASH_NXP_S32_QSPI_HYPERFLASH flash_nxp_s32_qspi_hyperflash.c)
153+
if(CONFIG_FLASH_NXP_S32_QSPI_NOR OR CONFIG_FLASH_NXP_S32_QSPI_HYPERFLASH)
154+
zephyr_library_sources(flash_nxp_s32_qspi.c)
155+
zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/memc)
156+
endif()
157157

158158
if(CONFIG_RA_FLASH_HP)
159159
zephyr_library_sources(flash_hp_ra.c)

drivers/flash/Kconfig.nxp_s32

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2023 NXP
1+
# Copyright 2023-2024 NXP
22
# SPDX-License-Identifier: Apache-2.0
33

44
config FLASH_NXP_S32_QSPI_NOR
@@ -14,10 +14,23 @@ config FLASH_NXP_S32_QSPI_NOR
1414
Enable the Flash driver for a NOR Serial Flash Memory device connected
1515
to an NXP S32 QSPI bus.
1616

17-
if FLASH_NXP_S32_QSPI_NOR
17+
config FLASH_NXP_S32_QSPI_HYPERFLASH
18+
bool "NXP S32 QSPI HYPERFLASH driver"
19+
default y
20+
depends on DT_HAS_NXP_S32_QSPI_HYPERFLASH_ENABLED
21+
select MEMC
22+
select FLASH_HAS_PAGE_LAYOUT
23+
select FLASH_HAS_DRIVER_ENABLED
24+
select FLASH_HAS_EXPLICIT_ERASE
25+
help
26+
Enable the Flash driver for a HyperFlash Memory device connected
27+
to an NXP S32 QSPI bus.
28+
29+
if FLASH_NXP_S32_QSPI_NOR || FLASH_NXP_S32_QSPI_HYPERFLASH
1830

1931
config FLASH_NXP_S32_QSPI_SFDP_RUNTIME
2032
bool "Read flash parameters at runtime"
33+
depends on FLASH_NXP_S32_QSPI_NOR
2134
help
2235
Read flash device characteristics from the device at runtime.
2336
This option should provide functionality for all supported
@@ -52,4 +65,4 @@ config FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE
5265
flash memory. Other options may include the 32K-byte erase size (32768),
5366
the block size (65536), or any non-zero multiple of the sector size.
5467

55-
endif # FLASH_NXP_S32_QSPI_NOR
68+
endif # FLASH_NXP_S32_QSPI_NOR || FLASH_NXP_S32_QSPI_HYPERFLASH
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/*
2+
* Copyright 2024 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT nxp_s32_qspi_hyperflash
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/drivers/flash.h>
11+
#include <zephyr/logging/log.h>
12+
13+
#include <Qspi_Ip.h>
14+
15+
#include "memc_nxp_s32_qspi.h"
16+
#include "flash_nxp_s32_qspi.h"
17+
18+
LOG_MODULE_REGISTER(nxp_s32_qspi_hyperflash, CONFIG_FLASH_LOG_LEVEL);
19+
20+
/* Use the fixed command sets from Qspi_Ip_Hyperflash.c */
21+
extern Qspi_Ip_InstrOpType QSPI_IP_HF_LUT_NAME[QSPI_IP_HF_LUT_SIZE];
22+
23+
static int nxp_s32_qspi_init(const struct device *dev)
24+
{
25+
struct nxp_s32_qspi_data *data = dev->data;
26+
const struct nxp_s32_qspi_config *config = dev->config;
27+
Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev);
28+
uint8_t dev_id[memory_cfg->readIdSettings.readIdSize];
29+
Qspi_Ip_StatusType status;
30+
int ret = 0;
31+
32+
/* Used by the HAL to retrieve the internal driver state */
33+
data->instance = nxp_s32_qspi_register_device();
34+
__ASSERT_NO_MSG(data->instance < QSPI_IP_MEM_INSTANCE_COUNT);
35+
data->memory_conn_cfg.qspiInstance = memc_nxp_s32_qspi_get_instance(config->controller);
36+
37+
#if defined(CONFIG_MULTITHREADING)
38+
k_sem_init(&data->sem, 1, 1);
39+
#endif
40+
41+
if (!device_is_ready(config->controller)) {
42+
LOG_ERR("Memory control device not ready");
43+
return -ENODEV;
44+
}
45+
46+
status = Qspi_Ip_Init(data->instance, (const Qspi_Ip_MemoryConfigType *)memory_cfg,
47+
(const Qspi_Ip_MemoryConnectionType *)&data->memory_conn_cfg);
48+
if (status != STATUS_QSPI_IP_SUCCESS) {
49+
LOG_ERR("Fail to init memory device %d (%d)", data->instance, status);
50+
return -EIO;
51+
}
52+
53+
/* Verify connectivity by reading the device ID */
54+
ret = nxp_s32_qspi_read_id(dev, dev_id);
55+
if (ret != 0) {
56+
LOG_ERR("Device ID read failed (%d)", ret);
57+
return -ENODEV;
58+
}
59+
60+
if (memcmp(dev_id, memory_cfg->readIdSettings.readIdExpected, sizeof(dev_id))) {
61+
LOG_ERR("Device id does not match config");
62+
return -EINVAL;
63+
}
64+
65+
return ret;
66+
}
67+
68+
static DEVICE_API(flash, nxp_s32_qspi_api) = {
69+
.erase = nxp_s32_qspi_erase,
70+
.write = nxp_s32_qspi_write,
71+
.read = nxp_s32_qspi_read,
72+
.get_parameters = nxp_s32_qspi_get_parameters,
73+
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
74+
.page_layout = nxp_s32_qspi_pages_layout,
75+
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
76+
};
77+
78+
#define QSPI_PAGE_LAYOUT(n) \
79+
.layout = { \
80+
.pages_count = (DT_INST_PROP(n, size) / 8) \
81+
/ CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \
82+
.pages_size = CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \
83+
}
84+
85+
#define QSPI_READ_ID_CFG(n) \
86+
{ \
87+
.readIdLut = QSPI_IP_HF_LUT_READ, \
88+
.readIdSize = DT_INST_PROP_LEN(n, jedec_id), \
89+
.readIdExpected = DT_INST_PROP(n, jedec_id), \
90+
}
91+
92+
#define QSPI_MEMORY_CONN_CFG(n) \
93+
{ \
94+
.connectionType = (Qspi_Ip_ConnectionType)DT_INST_REG_ADDR(n), \
95+
.memAlignment = DT_INST_PROP(n, write_block_size) \
96+
}
97+
98+
#define QSPI_ERASE_CFG(n) \
99+
{ \
100+
.eraseTypes = { \
101+
{ \
102+
.eraseLut = QSPI_IP_HF_LUT_SE, \
103+
.size = 12, /* 4 KB */ \
104+
}, \
105+
{ \
106+
.eraseLut = QSPI_IP_HF_LUT_SE, \
107+
.size = 18, /* 256 KB */ \
108+
}, \
109+
{ \
110+
.eraseLut = QSPI_IP_LUT_INVALID, \
111+
.size = 0, \
112+
}, \
113+
{ \
114+
.eraseLut = QSPI_IP_LUT_INVALID, \
115+
.size = 0, \
116+
}, \
117+
}, \
118+
.chipEraseLut = QSPI_IP_HF_LUT_CE, \
119+
}
120+
121+
#define QSPI_RESET_CFG(n) \
122+
{ \
123+
.resetCmdLut = QSPI_IP_HF_LUT_RST, \
124+
.resetCmdCount = QSPI_IP_HF_RST_CNT, \
125+
}
126+
127+
#define QSPI_STATUS_REG_CFG(n) \
128+
{ \
129+
.statusRegInitReadLut = QSPI_IP_HF_LUT_RDSR, \
130+
.statusRegReadLut = QSPI_IP_HF_LUT_RDSR, \
131+
.statusRegWriteLut = QSPI_IP_LUT_INVALID, \
132+
.writeEnableSRLut = QSPI_IP_LUT_INVALID, \
133+
.writeEnableLut = QSPI_IP_LUT_INVALID, \
134+
.regSize = 1U, \
135+
.busyOffset = 0U, \
136+
.busyValue = 1U, \
137+
.writeEnableOffset = 1U, \
138+
}
139+
140+
#define QSPI_INIT_CFG(n) \
141+
{ \
142+
.opCount = 0U, \
143+
.operations = NULL, \
144+
}
145+
146+
#define QSPI_LUT_CFG(n) \
147+
{ \
148+
.opCount = QSPI_IP_HF_LUT_SIZE, \
149+
.lutOps = (Qspi_Ip_InstrOpType *)QSPI_IP_HF_LUT_NAME, \
150+
}
151+
152+
#define QSPI_SUSPEND_CFG(n) \
153+
{ \
154+
.eraseSuspendLut = QSPI_IP_HF_LUT_ES, \
155+
.eraseResumeLut = QSPI_IP_HF_LUT_ER, \
156+
.programSuspendLut = QSPI_IP_HF_LUT_PS, \
157+
.programResumeLut = QSPI_IP_HF_LUT_PR, \
158+
}
159+
160+
#define QSPI_MEMORY_CFG(n) \
161+
{ \
162+
.memType = QSPI_IP_HYPER_FLASH, \
163+
.hfConfig = &hyperflash_config_##n, \
164+
.memSize = DT_INST_PROP(n, size) / 8, \
165+
.pageSize = DT_INST_PROP(n, max_program_buffer_size), \
166+
.writeLut = QSPI_IP_HF_LUT_WRITE, \
167+
.readLut = QSPI_IP_HF_LUT_READ, \
168+
.read0xxLut = QSPI_IP_LUT_INVALID, \
169+
.read0xxLutAHB = QSPI_IP_LUT_INVALID, \
170+
.eraseSettings = QSPI_ERASE_CFG(n), \
171+
.statusConfig = QSPI_STATUS_REG_CFG(n), \
172+
.resetSettings = QSPI_RESET_CFG(n), \
173+
.initResetSettings = QSPI_RESET_CFG(n), \
174+
.initConfiguration = QSPI_INIT_CFG(n), \
175+
.lutSequences = QSPI_LUT_CFG(n), \
176+
.readIdSettings = QSPI_READ_ID_CFG(n), \
177+
.suspendSettings = QSPI_SUSPEND_CFG(n), \
178+
.initCallout = NULL, \
179+
.resetCallout = NULL, \
180+
.errorCheckCallout = NULL, \
181+
.eccCheckCallout = NULL, \
182+
.ctrlAutoCfgPtr = NULL, \
183+
}
184+
185+
#define FLASH_NXP_S32_QSPI_DRV_STRENGTH(n) \
186+
COND_CODE_1(DT_INST_ENUM_IDX(n, vcc_mv), \
187+
(DT_INST_PROP(n, drive_strength_ohm) == 12 ? QSPI_IP_HF_DRV_STRENGTH_007 : \
188+
(DT_INST_PROP(n, drive_strength_ohm) == 14 ? QSPI_IP_HF_DRV_STRENGTH_006 : \
189+
(DT_INST_PROP(n, drive_strength_ohm) == 16 ? QSPI_IP_HF_DRV_STRENGTH_005 : \
190+
(DT_INST_PROP(n, drive_strength_ohm) == 20 ? QSPI_IP_HF_DRV_STRENGTH_000 : \
191+
(DT_INST_PROP(n, drive_strength_ohm) == 27 ? QSPI_IP_HF_DRV_STRENGTH_003 : \
192+
(DT_INST_PROP(n, drive_strength_ohm) == 40 ? QSPI_IP_HF_DRV_STRENGTH_002 : \
193+
(DT_INST_PROP(n, drive_strength_ohm) == 71 ? QSPI_IP_HF_DRV_STRENGTH_001 : \
194+
QSPI_IP_HF_DRV_STRENGTH_000))))))), \
195+
(DT_INST_PROP(n, drive_strength_ohm) == 20 ? QSPI_IP_HF_DRV_STRENGTH_007 : \
196+
(DT_INST_PROP(n, drive_strength_ohm) == 24 ? QSPI_IP_HF_DRV_STRENGTH_006 : \
197+
(DT_INST_PROP(n, drive_strength_ohm) == 27 ? QSPI_IP_HF_DRV_STRENGTH_000 : \
198+
(DT_INST_PROP(n, drive_strength_ohm) == 34 ? QSPI_IP_HF_DRV_STRENGTH_004 : \
199+
(DT_INST_PROP(n, drive_strength_ohm) == 45 ? QSPI_IP_HF_DRV_STRENGTH_003 : \
200+
(DT_INST_PROP(n, drive_strength_ohm) == 68 ? QSPI_IP_HF_DRV_STRENGTH_002 : \
201+
(DT_INST_PROP(n, drive_strength_ohm) == 117 ? QSPI_IP_HF_DRV_STRENGTH_001 : \
202+
QSPI_IP_HF_DRV_STRENGTH_000))))))))
203+
204+
#define FLASH_NXP_S32_QSPI_SECTOR_MAP(n) \
205+
COND_CODE_1(DT_INST_PROP(n, support_only_uniform_sectors), \
206+
(DT_INST_ENUM_IDX(n, ppw_sectors_addr_mapping) ? \
207+
QSPI_IP_HF_UNIFORM_SECTORS_READ_PASSWORD_HIGH : \
208+
QSPI_IP_HF_UNIFORM_SECTORS_READ_PASSWORD_LOW), \
209+
(DT_INST_ENUM_IDX(n, ppw_sectors_addr_mapping) ? \
210+
QSPI_IP_HF_PARAM_AND_PASSWORD_MAP_HIGH : \
211+
QSPI_IP_HF_PARAM_AND_PASSWORD_MAP_LOW))
212+
213+
#define FLASH_NXP_S32_QSPI_INIT_DEVICE(n) \
214+
static Qspi_Ip_HyperFlashConfigType hyperflash_config_##n = \
215+
{ \
216+
.outputDriverStrength = FLASH_NXP_S32_QSPI_DRV_STRENGTH(n), \
217+
.RWDSLowOnDualError = DT_INST_PROP(n, rwds_low_dual_error), \
218+
.secureRegionUnlocked = !DT_INST_PROP(n, secure_region_locked), \
219+
.readLatency = DT_INST_ENUM_IDX(n, read_latency_cycles), \
220+
.paramSectorMap = FLASH_NXP_S32_QSPI_SECTOR_MAP(n), \
221+
.deviceIdWordAddress = DT_INST_PROP(n, device_id_word_addr), \
222+
}; \
223+
static const struct nxp_s32_qspi_config nxp_s32_qspi_config_##n = { \
224+
.controller = DEVICE_DT_GET(DT_INST_BUS(n)), \
225+
.flash_parameters = { \
226+
.write_block_size = DT_INST_PROP(n, write_block_size), \
227+
.erase_value = QSPI_ERASE_VALUE, \
228+
}, \
229+
IF_ENABLED(CONFIG_FLASH_PAGE_LAYOUT, \
230+
(QSPI_PAGE_LAYOUT(n),)) \
231+
.memory_cfg = QSPI_MEMORY_CFG(n), \
232+
}; \
233+
\
234+
static struct nxp_s32_qspi_data nxp_s32_qspi_data_##n = { \
235+
.memory_conn_cfg = QSPI_MEMORY_CONN_CFG(n), \
236+
}; \
237+
\
238+
DEVICE_DT_INST_DEFINE(n, \
239+
nxp_s32_qspi_init, \
240+
NULL, \
241+
&nxp_s32_qspi_data_##n, \
242+
&nxp_s32_qspi_config_##n, \
243+
POST_KERNEL, \
244+
CONFIG_FLASH_INIT_PRIORITY, \
245+
&nxp_s32_qspi_api);
246+
247+
DT_INST_FOREACH_STATUS_OKAY(FLASH_NXP_S32_QSPI_INIT_DEVICE)

0 commit comments

Comments
 (0)