1 /*
2  * Copyright (c) 2023, Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #define DT_DRV_COMPAT cdns_nand
7 
8 #include "socfpga_system_manager.h"
9 
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/flash.h>
12 #include <zephyr/kernel.h>
13 
14 /* Check if reset property is defined */
15 #define CDNS_NAND_RESET_SUPPORT DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets)
16 
17 #if CDNS_NAND_RESET_SUPPORT
18 #include <zephyr/drivers/reset.h>
19 #endif
20 
21 #include "flash_cadence_nand_ll.h"
22 
23 #define DEV_CFG(_dev)  ((const struct flash_cadence_nand_config *)(_dev)->config)
24 #define DEV_DATA(_dev) ((struct flash_cadence_nand_data *const)(_dev)->data)
25 
26 #define FLASH_WRITE_SIZE DT_PROP(DT_INST(0, DT_DRV_COMPAT), block_size)
27 
28 #ifdef CONFIG_BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK
29 #define DFI_CFG_OFFSET 0xFC
30 /* To check the DFI register setting for NAND in the System Manager */
31 #define DFI_SEL_CHK    (SOCFPGA_SYSMGR_REG_BASE + DFI_CFG_OFFSET)
32 #endif
33 
34 LOG_MODULE_REGISTER(flash_cdns_nand, CONFIG_FLASH_LOG_LEVEL);
35 
36 struct flash_cadence_nand_data {
37 	DEVICE_MMIO_NAMED_RAM(nand_reg);
38 	DEVICE_MMIO_NAMED_RAM(sdma);
39 	/* device info structure */
40 	struct cadence_nand_params params;
41 	/* Mutex to prevent multiple processes from accessing the same driver api */
42 	struct k_mutex nand_mutex;
43 #if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT
44 	/* Semaphore to send a signal from an interrupt handler to a thread  */
45 	struct k_sem interrupt_sem;
46 #endif
47 };
48 
49 struct flash_cadence_nand_config {
50 	DEVICE_MMIO_NAMED_ROM(nand_reg);
51 	DEVICE_MMIO_NAMED_ROM(sdma);
52 #if CDNS_NAND_RESET_SUPPORT
53 	/* Reset controller device configuration for NAND*/
54 	const struct reset_dt_spec reset;
55 	/* Reset controller device configuration for Combo Phy*/
56 	const struct reset_dt_spec combo_phy_reset;
57 #endif
58 #if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT
59 	void (*irq_config)(void);
60 #endif
61 };
62 
63 static const struct flash_parameters flash_cdns_parameters = {.write_block_size = FLASH_WRITE_SIZE,
64 							      .erase_value = 0xFF};
65 
66 #if CONFIG_FLASH_PAGE_LAYOUT
67 
68 struct flash_pages_layout flash_cdns_pages_layout;
69 
flash_cdns_page_layout(const struct device * nand_dev,const struct flash_pages_layout ** layout,size_t * layout_size)70 void flash_cdns_page_layout(const struct device *nand_dev, const struct flash_pages_layout **layout,
71 			    size_t *layout_size)
72 {
73 	struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev);
74 	struct cadence_nand_params *nand_param = &nand_data->params;
75 
76 	flash_cdns_pages_layout.pages_count = nand_param->page_count;
77 	flash_cdns_pages_layout.pages_size = nand_param->page_size;
78 	*layout = &flash_cdns_pages_layout;
79 	*layout_size = 1;
80 }
81 
82 #endif
83 
flash_cdns_nand_erase(const struct device * nand_dev,off_t offset,size_t len)84 static int flash_cdns_nand_erase(const struct device *nand_dev, off_t offset, size_t len)
85 {
86 	struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev);
87 	struct cadence_nand_params *nand_param = &nand_data->params;
88 	int ret;
89 
90 	k_mutex_lock(&nand_data->nand_mutex, K_FOREVER);
91 
92 	ret = cdns_nand_erase(nand_param, offset, len);
93 
94 	k_mutex_unlock(&nand_data->nand_mutex);
95 
96 	return ret;
97 }
98 
flash_cdns_nand_write(const struct device * nand_dev,off_t offset,const void * data,size_t len)99 static int flash_cdns_nand_write(const struct device *nand_dev, off_t offset, const void *data,
100 				 size_t len)
101 {
102 	struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev);
103 	struct cadence_nand_params *nand_param = &nand_data->params;
104 	int ret;
105 
106 	if (data == NULL) {
107 		LOG_ERR("Invalid input parameter for NAND Flash Write!");
108 		return -EINVAL;
109 	}
110 
111 	k_mutex_lock(&nand_data->nand_mutex, K_FOREVER);
112 
113 	ret = cdns_nand_write(nand_param, data, offset, len);
114 
115 	k_mutex_unlock(&nand_data->nand_mutex);
116 
117 	return ret;
118 }
119 
flash_cdns_nand_read(const struct device * nand_dev,off_t offset,void * data,size_t len)120 static int flash_cdns_nand_read(const struct device *nand_dev, off_t offset, void *data, size_t len)
121 {
122 	struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev);
123 	struct cadence_nand_params *nand_param = &nand_data->params;
124 	int ret;
125 
126 	if (data == NULL) {
127 		LOG_ERR("Invalid input parameter for NAND Flash Read!");
128 		return -EINVAL;
129 	}
130 
131 	k_mutex_lock(&nand_data->nand_mutex, K_FOREVER);
132 
133 	ret = cdns_nand_read(nand_param, data, offset, len);
134 
135 	k_mutex_unlock(&nand_data->nand_mutex);
136 
137 	return ret;
138 }
139 
flash_cdns_get_parameters(const struct device * nand_dev)140 static const struct flash_parameters *flash_cdns_get_parameters(const struct device *nand_dev)
141 {
142 	ARG_UNUSED(nand_dev);
143 
144 	return &flash_cdns_parameters;
145 }
146 static const struct flash_driver_api flash_cdns_nand_api = {
147 	.erase = flash_cdns_nand_erase,
148 	.write = flash_cdns_nand_write,
149 	.read = flash_cdns_nand_read,
150 	.get_parameters = flash_cdns_get_parameters,
151 #ifdef CONFIG_FLASH_PAGE_LAYOUT
152 	.page_layout = flash_cdns_page_layout,
153 #endif
154 };
155 
156 #if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT
157 
cdns_nand_irq_handler(const struct device * nand_dev)158 static void cdns_nand_irq_handler(const struct device *nand_dev)
159 {
160 	struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev);
161 	struct cadence_nand_params *nand_param = &nand_data->params;
162 
163 	cdns_nand_irq_handler_ll(nand_param);
164 	k_sem_give(&nand_param->interrupt_sem_t);
165 }
166 
167 #endif
168 
flash_cdns_nand_init(const struct device * nand_dev)169 static int flash_cdns_nand_init(const struct device *nand_dev)
170 {
171 	DEVICE_MMIO_NAMED_MAP(nand_dev, nand_reg, K_MEM_CACHE_NONE);
172 	DEVICE_MMIO_NAMED_MAP(nand_dev, sdma, K_MEM_CACHE_NONE);
173 	const struct flash_cadence_nand_config *nand_config = DEV_CFG(nand_dev);
174 	struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev);
175 	struct cadence_nand_params *nand_param = &nand_data->params;
176 	int ret;
177 
178 #ifdef CONFIG_BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK
179 	uint32_t status;
180 
181 	status = sys_read32(DFI_SEL_CHK);
182 	if ((status & 1) != 0) {
183 		LOG_ERR("DFI not configured for NAND Flash controller!!!");
184 		return -ENODEV;
185 	}
186 #endif
187 
188 #if CDNS_NAND_RESET_SUPPORT
189 	/* Reset Combo phy and NAND only if reset controller driver is supported */
190 	if ((nand_config->combo_phy_reset.dev != NULL) && (nand_config->reset.dev != NULL)) {
191 		if (!device_is_ready(nand_config->reset.dev)) {
192 			LOG_ERR("Reset controller device not ready");
193 			return -ENODEV;
194 		}
195 
196 		ret = reset_line_toggle(nand_config->combo_phy_reset.dev,
197 					nand_config->combo_phy_reset.id);
198 		if (ret != 0) {
199 			LOG_ERR("Combo phy reset failed");
200 			return ret;
201 		}
202 
203 		ret = reset_line_toggle(nand_config->reset.dev, nand_config->reset.id);
204 		if (ret != 0) {
205 			LOG_ERR("NAND reset failed");
206 			return ret;
207 		}
208 	}
209 #endif
210 	nand_param->nand_base = DEVICE_MMIO_NAMED_GET(nand_dev, nand_reg);
211 	nand_param->sdma_base = DEVICE_MMIO_NAMED_GET(nand_dev, sdma);
212 	ret = k_mutex_init(&nand_data->nand_mutex);
213 	if (ret != 0) {
214 		LOG_ERR("Mutex creation Failed");
215 		return ret;
216 	}
217 
218 #if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT
219 
220 	if (nand_config->irq_config == NULL) {
221 		LOG_ERR("Interrupt function not initialized!!");
222 		return -EINVAL;
223 	}
224 	nand_config->irq_config();
225 	ret = k_sem_init(&nand_param->interrupt_sem_t, 0, 1);
226 	if (ret != 0) {
227 		LOG_ERR("Semaphore creation Failed");
228 		return ret;
229 	}
230 #endif
231 	nand_param->page_count =
232 		(nand_param->npages_per_block * nand_param->nblocks_per_lun * nand_param->nluns);
233 	/* NAND Memory Controller init */
234 	ret = cdns_nand_init(nand_param);
235 	if (ret != 0) {
236 		LOG_ERR("NAND initialization Failed");
237 		return ret;
238 	}
239 	return 0;
240 }
241 
242 #define CDNS_NAND_RESET_SPEC_INIT(inst)                                                            \
243 	.reset = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0),                                           \
244 	.combo_phy_reset = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1),
245 
246 #define CREATE_FLASH_CADENCE_NAND_DEVICE(inst)                                                     \
247 	IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT,                                             \
248 		   (static void cdns_nand_irq_config_##inst(void);))                               \
249 	struct flash_cadence_nand_data flash_cadence_nand_data_##inst = {                          \
250 		.params = {                                                                        \
251 			.datarate_mode = DT_INST_PROP(inst, data_rate_mode),                       \
252 		}};                                                                                \
253 	const struct flash_cadence_nand_config flash_cadence_nand_config_##inst = {                \
254 		DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(nand_reg, DT_DRV_INST(inst)),                   \
255 		DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(sdma, DT_DRV_INST(inst)),                       \
256 		IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), (CDNS_NAND_RESET_SPEC_INIT(inst))) \
257 			IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT,                             \
258 				   (.irq_config = cdns_nand_irq_config_##inst,))};                 \
259 	DEVICE_DT_INST_DEFINE(inst, flash_cdns_nand_init, NULL, &flash_cadence_nand_data_##inst,   \
260 			      &flash_cadence_nand_config_##inst, POST_KERNEL,                      \
261 			      CONFIG_FLASH_INIT_PRIORITY, &flash_cdns_nand_api);                   \
262 	IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT,                                             \
263 		   (static void cdns_nand_irq_config_##inst(void)                                  \
264 		   {										   \
265 			   IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority),            \
266 				       cdns_nand_irq_handler, DEVICE_DT_INST_GET(inst), 0);        \
267 			   irq_enable(DT_INST_IRQN(inst));                                         \
268 		   }))
269 
270 DT_INST_FOREACH_STATUS_OKAY(CREATE_FLASH_CADENCE_NAND_DEVICE)
271