1 /*
2 * Copyright 2024 Cypress Semiconductor Corporation (an Infineon company) or
3 * an affiliate of Cypress Semiconductor Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT infineon_cat1_qspi_flash
9 #define SOC_NV_FLASH_NODE DT_PARENT(DT_INST(0, fixed_partitions))
10
11 #define PAGE_LEN DT_PROP(SOC_NV_FLASH_NODE, erase_block_size)
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/devicetree.h>
15 #include <zephyr/drivers/flash.h>
16 #include <zephyr/logging/log.h>
17
18 #include "cy_serial_flash_qspi.h"
19 #include "cy_smif_memslot.h"
20
21 LOG_MODULE_REGISTER(flash_infineon_cat1, CONFIG_FLASH_LOG_LEVEL);
22
23 /* Device config structure */
24 struct ifx_cat1_flash_config {
25 uint32_t base_addr;
26 uint32_t max_addr;
27 };
28
29 /* Data structure */
30 struct ifx_cat1_flash_data {
31 cyhal_flash_t flash_obj;
32 struct k_sem sem;
33 };
34
35 static struct flash_parameters ifx_cat1_flash_parameters = {
36 .write_block_size = DT_PROP(SOC_NV_FLASH_NODE, write_block_size),
37 .erase_value = 0xFF,
38 };
39
40 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_cmd = {0};
41
42 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_en_cmd = {0};
43
44 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_dis_cmd = {0};
45
46 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_erase_cmd = {0};
47
48 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_chip_erase_cmd = {0};
49
50 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_program_cmd = {0};
51
52 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_sts_reg_qe_cmd = {0};
53
54 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_sts_reg_wip_cmd = {0};
55
56 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_sts_reg_qe_cmd = {0};
57
58 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_sts_reg_oe_cmd = {0};
59
60 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_sts_reg_oe_cmd = {0};
61
62 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_latency_cmd = {0};
63
64 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_write_latency_cmd = {0};
65
66 cy_stc_smif_mem_cmd_t sfdp_slave_slot_0_read_sfdp_cmd = {
67 /* The 8-bit command. 1 x I/O read command. */
68 .command = 0x5AU,
69 /* The width of the command transfer. */
70 .cmdWidth = CY_SMIF_WIDTH_SINGLE,
71 /* The width of the address transfer. */
72 .addrWidth = CY_SMIF_WIDTH_SINGLE,
73 /* The 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present. */
74 .mode = 0xFFFFFFFFU,
75 /* The width of the mode command transfer. */
76 .modeWidth = CY_SMIF_WIDTH_SINGLE,
77 /* The number of dummy cycles. A zero value suggests no dummy cycles. */
78 .dummyCycles = 8U,
79 /* The width of the data transfer. */
80 .dataWidth = CY_SMIF_WIDTH_SINGLE,
81 };
82
83 cy_stc_smif_octal_ddr_en_seq_t oe_sequence_SFDP_SlaveSlot_0 = {
84 .cmdSeq1Len = CY_SMIF_SFDP_ODDR_CMD_SEQ_MAX_LEN,
85 .cmdSeq2Len = CY_SMIF_SFDP_ODDR_CMD_SEQ_MAX_LEN,
86 .cmdSeq1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
87 .cmdSeq2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
88 };
89
90 /* Support for memories with hybrid regions is added in the version 1.50
91 * Please refer to the changelog in
92 * https://iot-webserver.aus.cypress.com/projects/iot_release/
93 * ASSETS/repo/mtb-pdl-cat1/develop/Latest/deploy/docs/
94 * pdl_api_reference_manual/html/group__group__smif.html
95 * for more details
96 */
97 #if (CY_SMIF_DRV_VERSION_MAJOR > 1) && (CY_SMIF_DRV_VERSION_MINOR >= 50)
98 static cy_stc_smif_hybrid_region_info_t sfdp_slave_slot_0_region_info_storage[16];
99
100 #define GENERATE_REGION_INFO_PTR(index, _) &sfdp_slave_slot_0_region_info_storage[index],
101
102 static cy_stc_smif_hybrid_region_info_t *sfdp_slave_slot_0_region_info[16] = {
103 LISTIFY(16, GENERATE_REGION_INFO_PTR, ())};
104 #endif
105
106 cy_stc_smif_mem_device_cfg_t deviceCfg_SFDP_SlaveSlot_0 = {
107 /* Specifies the number of address bytes used by the memory slave device. */
108 .numOfAddrBytes = 0x03U,
109 /* The size of the memory. */
110 .memSize = 0x0000100U,
111 /* Specifies the Read command. */
112 .readCmd = &sfdp_slave_slot_0_read_cmd,
113 /* Specifies the Write Enable command. */
114 .writeEnCmd = &sfdp_slave_slot_0_write_en_cmd,
115 /* Specifies the Write Disable command. */
116 .writeDisCmd = &sfdp_slave_slot_0_write_dis_cmd,
117 /* Specifies the Erase command. */
118 .eraseCmd = &sfdp_slave_slot_0_erase_cmd,
119 /* Specifies the sector size of each erase. */
120 .eraseSize = 0x0001000U,
121 /* Specifies the Chip Erase command. */
122 .chipEraseCmd = &sfdp_slave_slot_0_chip_erase_cmd,
123 /* Specifies the Program command. */
124 .programCmd = &sfdp_slave_slot_0_program_cmd,
125 /* Specifies the page size for programming. */
126 .programSize = 0x0000100U,
127 /* Specifies the command to read the QE-containing status register. */
128 .readStsRegQeCmd = &sfdp_slave_slot_0_read_sts_reg_qe_cmd,
129 /* Specifies the command to read the WIP-containing status register. */
130 .readStsRegWipCmd = &sfdp_slave_slot_0_read_sts_reg_wip_cmd,
131 /* Specifies the read SFDP command */
132 .readSfdpCmd = &sfdp_slave_slot_0_read_sfdp_cmd,
133 /* Specifies the command to write into the QE-containing status register. */
134 .writeStsRegQeCmd = &sfdp_slave_slot_0_write_sts_reg_qe_cmd,
135 /* The mask for the status register. */
136 .stsRegBusyMask = 0x00U,
137 /* The mask for the status register. */
138 .stsRegQuadEnableMask = 0x00U,
139 /* The max time for the erase type-1 cycle-time in ms. */
140 .eraseTime = 1U,
141 /* The max time for the chip-erase cycle-time in ms. */
142 .chipEraseTime = 16U,
143 /* The max time for the page-program cycle-time in us. */
144 .programTime = 8U,
145 #if (CY_SMIF_DRV_VERSION_MAJOR > 1) && (CY_SMIF_DRV_VERSION_MINOR >= 50)
146 /* Points to NULL or to structure with info about sectors for hybrid memory. */
147 .hybridRegionCount = 0U,
148 .hybridRegionInfo = sfdp_slave_slot_0_region_info,
149 #endif
150 /* Specifies the command to read variable latency cycles configuration register */
151 .readLatencyCmd = &sfdp_slave_slot_0_read_latency_cmd,
152 /* Specifies the command to write variable latency cycles configuration register */
153 .writeLatencyCmd = &sfdp_slave_slot_0_write_latency_cmd,
154 /* Specifies the address for variable latency cycle address */
155 .latencyCyclesRegAddr = 0x00U,
156 /* Specifies variable latency cycles Mask */
157 .latencyCyclesMask = 0x00U,
158 /* Specifies data for memory with hybrid sectors */
159 .octalDDREnableSeq = &oe_sequence_SFDP_SlaveSlot_0,
160 /* Specifies the command to read the OE-containing status register. */
161 .readStsRegOeCmd = &sfdp_slave_slot_0_read_sts_reg_oe_cmd,
162 /* Specifies the command to write the OE-containing status register. */
163 .writeStsRegOeCmd = &sfdp_slave_slot_0_write_sts_reg_oe_cmd,
164 /* QE mask for the status registers */
165 .stsRegOctalEnableMask = 0x00U,
166 /* Octal enable register address */
167 .octalEnableRegAddr = 0x00U,
168 /* Frequency of operation used in Octal mode */
169 .freq_of_operation = CY_SMIF_100MHZ_OPERATION,
170 };
171
172 cy_stc_smif_mem_config_t sfdp_slave_slot_0 = {
173 /* Determines the slot number where the memory device is placed. */
174 .slaveSelect = CY_SMIF_SLAVE_SELECT_0,
175 /* Flags. */
176 .flags = CY_SMIF_FLAG_SMIF_REV_3 | CY_SMIF_FLAG_MEMORY_MAPPED | CY_SMIF_FLAG_WR_EN |
177 CY_SMIF_FLAG_DETECT_SFDP | CY_SMIF_FLAG_MERGE_ENABLE,
178 /* The data-line selection options for a slave device. */
179 .dataSelect = CY_SMIF_DATA_SEL0,
180 /* The base address the memory slave
181 * Valid when the memory-mapped mode is enabled.
182 */
183 .baseAddress = 0x60000000U,
184 /* The size allocated in the memory map, for the memory slave device.
185 * The size is allocated from the base address. Valid when the memory mapped mode is
186 * enabled.
187 */
188 .memMappedSize = 0x100000U,
189 /* If this memory device is one of the devices in the dual quad SPI configuration.
190 * Valid when the memory mapped mode is enabled.
191 */
192 .dualQuadSlots = 0,
193 /* The configuration of the device. */
194 .deviceCfg = &deviceCfg_SFDP_SlaveSlot_0,
195 /** Continuous transfer merge timeout.
196 * After this period the memory device is deselected. A later transfer, even from a
197 * continuous address, starts with the overhead phases (command, address, mode, dummy
198 * cycles). This configuration parameter is available for CAT1B devices.
199 */
200 .mergeTimeout = CY_SMIF_MERGE_TIMEOUT_1_CYCLE,
201 };
202
flash_ifx_sem_take(const struct device * dev)203 static inline void flash_ifx_sem_take(const struct device *dev)
204 {
205 struct ifx_cat1_flash_data *data = dev->data;
206
207 k_sem_take(&data->sem, K_FOREVER);
208 }
209
flash_ifx_sem_give(const struct device * dev)210 static inline void flash_ifx_sem_give(const struct device *dev)
211 {
212 struct ifx_cat1_flash_data *data = dev->data;
213
214 k_sem_give(&data->sem);
215 }
216
ifx_cat1_flash_read(const struct device * dev,off_t offset,void * data,size_t data_len)217 static int ifx_cat1_flash_read(const struct device *dev, off_t offset, void *data, size_t data_len)
218 {
219 cy_rslt_t rslt = CY_RSLT_SUCCESS;
220 int ret = 0;
221
222 if (!data_len) {
223 return 0;
224 }
225
226 flash_ifx_sem_take(dev);
227
228 rslt = cy_serial_flash_qspi_read(offset, data_len, data);
229 if (rslt != CY_RSLT_SUCCESS) {
230 LOG_ERR("Error reading @ %lu (Err:0x%x)", offset, rslt);
231 ret = -EIO;
232 }
233
234 flash_ifx_sem_give(dev);
235 return ret;
236 }
237
ifx_cat1_flash_write(const struct device * dev,off_t offset,const void * data,size_t data_len)238 static int ifx_cat1_flash_write(const struct device *dev, off_t offset, const void *data,
239 size_t data_len)
240 {
241 cy_rslt_t rslt = CY_RSLT_SUCCESS;
242 int ret = 0;
243
244 if (data_len == 0) {
245 return 0;
246 }
247
248 if (offset < 0) {
249 return -EINVAL;
250 }
251
252 flash_ifx_sem_take(dev);
253
254 rslt = cy_serial_flash_qspi_write(offset, data_len, data);
255 if (rslt != CY_RSLT_SUCCESS) {
256 LOG_ERR("Error in writing @ %lu (Err:0x%x)", offset, rslt);
257 ret = -EIO;
258 }
259
260 flash_ifx_sem_give(dev);
261 return ret;
262 }
263
ifx_cat1_flash_erase(const struct device * dev,off_t offset,size_t size)264 static int ifx_cat1_flash_erase(const struct device *dev, off_t offset, size_t size)
265 {
266 cy_rslt_t rslt;
267 int ret = 0;
268
269 if (offset < 0) {
270 return -EINVAL;
271 }
272
273 flash_ifx_sem_take(dev);
274
275 rslt = cy_serial_flash_qspi_erase(offset, size);
276 if (rslt != CY_RSLT_SUCCESS) {
277 LOG_ERR("Error in erasing : 0x%x", rslt);
278 ret = -EIO;
279 }
280
281 flash_ifx_sem_give(dev);
282 return ret;
283 }
284
285 #if CONFIG_FLASH_PAGE_LAYOUT
286 static const struct flash_pages_layout ifx_cat1_flash_pages_layout = {
287 .pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / PAGE_LEN,
288 .pages_size = PAGE_LEN,
289 };
290
ifx_cat1_flash_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)291 static void ifx_cat1_flash_page_layout(const struct device *dev,
292 const struct flash_pages_layout **layout,
293 size_t *layout_size)
294 {
295 *layout = &ifx_cat1_flash_pages_layout;
296
297 /*
298 * For flash memories which have uniform page sizes, this routine
299 * returns an array of length 1, which specifies the page size and
300 * number of pages in the memory.
301 */
302 *layout_size = 1;
303 }
304 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
305
ifx_cat1_flash_get_parameters(const struct device * dev)306 static const struct flash_parameters *ifx_cat1_flash_get_parameters(const struct device *dev)
307 {
308 ARG_UNUSED(dev);
309
310 return &ifx_cat1_flash_parameters;
311 }
312
ifx_cat1_flash_init(const struct device * dev)313 static int ifx_cat1_flash_init(const struct device *dev)
314 {
315 struct ifx_cat1_flash_data *data = dev->data;
316 cy_rslt_t rslt = CY_RSLT_SUCCESS;
317
318 rslt = cy_serial_flash_qspi_init(&sfdp_slave_slot_0, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC,
319 50000000lu);
320 if (rslt != CY_RSLT_SUCCESS) {
321 LOG_ERR("Serial Flash initialization failed [rslt: 0x%x]", rslt);
322 }
323
324 k_sem_init(&data->sem, 1, 1);
325
326 return 0;
327 }
328
329 static const struct flash_driver_api ifx_cat1_flash_driver_api = {
330 .read = ifx_cat1_flash_read,
331 .write = ifx_cat1_flash_write,
332 .erase = ifx_cat1_flash_erase,
333 .get_parameters = ifx_cat1_flash_get_parameters,
334 #ifdef CONFIG_FLASH_PAGE_LAYOUT
335 .page_layout = ifx_cat1_flash_page_layout,
336 #endif
337 };
338
339 static struct ifx_cat1_flash_data flash_data;
340
341 static const struct ifx_cat1_flash_config flash_config = {
342 .base_addr = DT_REG_ADDR(SOC_NV_FLASH_NODE),
343 .max_addr = DT_REG_ADDR(SOC_NV_FLASH_NODE) + DT_REG_SIZE(SOC_NV_FLASH_NODE)};
344
345 DEVICE_DT_INST_DEFINE(0, ifx_cat1_flash_init, NULL, &flash_data, &flash_config, POST_KERNEL,
346 CONFIG_FLASH_INIT_PRIORITY, &ifx_cat1_flash_driver_api);
347