1 /*
2  * Copyright 2023 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_flash_controller
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 "cyhal_flash.h"
19 
20 LOG_MODULE_REGISTER(flash_infineon_cat1, CONFIG_FLASH_LOG_LEVEL);
21 
22 /* Device config structure */
23 struct ifx_cat1_flash_config {
24 	uint32_t base_addr;
25 	uint32_t max_addr;
26 };
27 
28 /* Data structure */
29 struct ifx_cat1_flash_data {
30 	cyhal_flash_t flash_obj;
31 	struct k_sem sem;
32 };
33 
34 static struct flash_parameters ifx_cat1_flash_parameters = {
35 	.write_block_size = DT_PROP(SOC_NV_FLASH_NODE, write_block_size),
36 	.erase_value = 0x00,
37 };
38 
flash_ifx_sem_take(const struct device * dev)39 static inline void flash_ifx_sem_take(const struct device *dev)
40 {
41 	struct ifx_cat1_flash_data *data = dev->data;
42 
43 	k_sem_take(&data->sem, K_FOREVER);
44 }
45 
flash_ifx_sem_give(const struct device * dev)46 static inline void flash_ifx_sem_give(const struct device *dev)
47 {
48 	struct ifx_cat1_flash_data *data = dev->data;
49 
50 	k_sem_give(&data->sem);
51 }
52 
ifx_cat1_flash_read(const struct device * dev,off_t offset,void * data,size_t data_len)53 static int ifx_cat1_flash_read(const struct device *dev, off_t offset, void *data, size_t data_len)
54 {
55 	struct ifx_cat1_flash_data *dev_data = dev->data;
56 	const struct ifx_cat1_flash_config *dev_config = dev->config;
57 	uint32_t read_offset = dev_config->base_addr + offset;
58 	cy_rslt_t rslt = CY_RSLT_SUCCESS;
59 	int ret = 0;
60 
61 	flash_ifx_sem_take(dev);
62 
63 	rslt = cyhal_flash_read(&dev_data->flash_obj, read_offset, (uint8_t *)data, data_len);
64 	if (rslt != CY_RSLT_SUCCESS) {
65 		LOG_ERR("Error reading @ 0x%x (Err:0x%x)", read_offset, rslt);
66 		ret = -EIO;
67 		goto out;
68 	}
69 
70 out:
71 	flash_ifx_sem_give(dev);
72 	return ret;
73 }
74 
ifx_cat1_flash_write(const struct device * dev,off_t offset,const void * data,size_t data_len)75 static int ifx_cat1_flash_write(const struct device *dev, off_t offset, const void *data,
76 				size_t data_len)
77 {
78 	struct ifx_cat1_flash_data *dev_data = dev->data;
79 	const struct ifx_cat1_flash_config *dev_config = dev->config;
80 	uint32_t write_offset = dev_config->base_addr + (uint32_t)offset;
81 	const uint8_t *data_ptr = (const uint8_t *)data;
82 	cy_rslt_t rslt = CY_RSLT_SUCCESS;
83 	int ret = 0;
84 
85 	if (data_len == 0) {
86 		return 0;
87 	}
88 
89 	if ((offset < 0) || (data_len % PAGE_LEN != 0) || (offset % PAGE_LEN != 0)) {
90 		return -EINVAL;
91 	}
92 
93 	flash_ifx_sem_take(dev);
94 
95 	while (data_len) {
96 		rslt = cyhal_flash_write(&dev_data->flash_obj, write_offset,
97 					 (const uint32_t *)data_ptr);
98 		if (rslt != CY_RSLT_SUCCESS) {
99 			LOG_ERR("Error in writing @ 0x%x (Err:0x%x)", write_offset, rslt);
100 			ret = -EIO;
101 			goto out;
102 		}
103 
104 		data_ptr += PAGE_LEN;
105 		write_offset += PAGE_LEN;
106 		data_len -= PAGE_LEN;
107 	}
108 
109 out:
110 	flash_ifx_sem_give(dev);
111 	return ret;
112 }
113 
ifx_cat1_flash_erase(const struct device * dev,off_t offset,size_t size)114 static int ifx_cat1_flash_erase(const struct device *dev, off_t offset, size_t size)
115 {
116 	struct ifx_cat1_flash_data *data = dev->data;
117 	const struct ifx_cat1_flash_config *config = dev->config;
118 	uint32_t erase_offset = config->base_addr + (uint32_t)offset;
119 	cy_rslt_t rslt;
120 
121 	if ((offset < 0) || ((offset % PAGE_LEN) != 0)) {
122 		return -EINVAL;
123 	}
124 
125 	if (((erase_offset + size) > config->max_addr) || ((size % PAGE_LEN) != 0)) {
126 		return -EINVAL;
127 	}
128 
129 	while (size) {
130 		rslt = cyhal_flash_erase(&data->flash_obj, erase_offset);
131 		if (rslt != CY_RSLT_SUCCESS) {
132 			LOG_ERR("Error in erasing : 0x%x", rslt);
133 			return -EIO;
134 		}
135 
136 		size -= PAGE_LEN;
137 		erase_offset += PAGE_LEN;
138 	}
139 
140 	return 0;
141 }
142 
143 #if CONFIG_FLASH_PAGE_LAYOUT
144 static const struct flash_pages_layout ifx_cat1_flash_pages_layout = {
145 	.pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / PAGE_LEN,
146 	.pages_size = PAGE_LEN,
147 };
148 
ifx_cat1_flash_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)149 static void ifx_cat1_flash_page_layout(const struct device *dev,
150 				       const struct flash_pages_layout **layout,
151 				       size_t *layout_size)
152 {
153 	*layout = &ifx_cat1_flash_pages_layout;
154 
155 	/*
156 	 * For flash memories which have uniform page sizes, this routine
157 	 * returns an array of length 1, which specifies the page size and
158 	 * number of pages in the memory.
159 	 */
160 	*layout_size = 1;
161 }
162 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
163 
ifx_cat1_flash_get_parameters(const struct device * dev)164 static const struct flash_parameters *ifx_cat1_flash_get_parameters(const struct device *dev)
165 {
166 	ARG_UNUSED(dev);
167 
168 	return &ifx_cat1_flash_parameters;
169 }
170 
ifx_cat1_flash_init(const struct device * dev)171 static int ifx_cat1_flash_init(const struct device *dev)
172 {
173 	struct ifx_cat1_flash_data *data = dev->data;
174 	cy_rslt_t rslt = CY_RSLT_SUCCESS;
175 
176 	rslt = cyhal_flash_init(&data->flash_obj);
177 	if (rslt != CY_RSLT_SUCCESS) {
178 		LOG_ERR("Failed to init flash hal driver (Err:0x%x)", rslt);
179 		return -EIO;
180 	}
181 
182 	k_sem_init(&data->sem, 1, 1);
183 
184 	return 0;
185 }
186 
187 static const struct flash_driver_api ifx_cat1_flash_driver_api = {
188 	.read = ifx_cat1_flash_read,
189 	.write = ifx_cat1_flash_write,
190 	.erase = ifx_cat1_flash_erase,
191 	.get_parameters = ifx_cat1_flash_get_parameters,
192 #ifdef CONFIG_FLASH_PAGE_LAYOUT
193 	.page_layout = ifx_cat1_flash_page_layout,
194 #endif
195 };
196 
197 static struct ifx_cat1_flash_data flash_data;
198 
199 static const struct ifx_cat1_flash_config ifx_cat1_flash_config = {
200 	.base_addr = DT_REG_ADDR(SOC_NV_FLASH_NODE),
201 	.max_addr = DT_REG_ADDR(SOC_NV_FLASH_NODE) + DT_REG_SIZE(SOC_NV_FLASH_NODE)};
202 
203 DEVICE_DT_INST_DEFINE(0, ifx_cat1_flash_init, NULL, &flash_data, &ifx_cat1_flash_config,
204 		      POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, &ifx_cat1_flash_driver_api);
205