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