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