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
nxp_s32_qspi_init(const struct device * dev)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)
248