1 /*
2  * Copyright (C) 2023 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT cdns_sdhc
8 
9 #include <zephyr/drivers/sdhc.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/drivers/reset.h>
13 
14 #include "sdhc_cdns_ll.h"
15 
16 #define SDHC_CDNS_DESC_SIZE	(1<<20)
17 #define COMBOPHY_ADDR_MASK	0x0000FFFFU
18 
19 #define DEV_CFG(_dev)	((const struct sdhc_cdns_config *)(_dev)->config)
20 #define DEV_DATA(_dev)	((struct sdhc_cdns_data *const)(_dev)->data)
21 
22 LOG_MODULE_REGISTER(sdhc_cdns, CONFIG_SDHC_LOG_LEVEL);
23 
24 /* SDMMC operations FPs are the element of structure*/
25 static const struct sdhc_cdns_ops *cdns_sdmmc_ops;
26 
27 struct sdhc_cdns_config {
28 	DEVICE_MMIO_NAMED_ROM(reg_base);
29 	DEVICE_MMIO_NAMED_ROM(combo_phy);
30 	/* Clock rate for host */
31 	uint32_t clk_rate;
32 	/* power delay prop for host */
33 	uint32_t power_delay_ms;
34 	/* run time device structure */
35 	const struct device *cdns_clk_dev;
36 	/* type to identify a clock controller sub-system */
37 	clock_control_subsys_t clkid;
38 	/* Reset controller device configuration. */
39 	const struct reset_dt_spec reset_sdmmc;
40 	const struct reset_dt_spec reset_sdmmcocp;
41 	const struct reset_dt_spec reset_softphy;
42 };
43 
44 struct sdhc_cdns_data {
45 	DEVICE_MMIO_NAMED_RAM(reg_base);
46 	DEVICE_MMIO_NAMED_RAM(combo_phy);
47 	/* Host controller parameters */
48 	struct sdhc_cdns_params params;
49 	/* sdmmc device informartaion for host */
50 	struct sdmmc_device_info info;
51 	/* Input/Output configuration */
52 	struct sdhc_io host_io;
53 };
54 
sdhc_cdns_request(const struct device * dev,struct sdhc_command * cmd,struct sdhc_data * data)55 static int sdhc_cdns_request(const struct device *dev,
56 	struct sdhc_command *cmd,
57 	struct sdhc_data *data)
58 {
59 	int ret = 0;
60 	struct sdmmc_cmd cdns_sdmmc_cmd;
61 
62 	if (cmd == NULL) {
63 		LOG_ERR("Wrong CMD parameter");
64 		return -EINVAL;
65 	}
66 
67 	/* Initialization of command structure */
68 	cdns_sdmmc_cmd.cmd_idx =  cmd->opcode;
69 	cdns_sdmmc_cmd.cmd_arg = cmd->arg;
70 	cdns_sdmmc_cmd.resp_type = (cmd->response_type & SDHC_NATIVE_RESPONSE_MASK);
71 
72 	/* Sending command as per the data or non data */
73 	if (data) {
74 		ret = cdns_sdmmc_ops->prepare(data->block_addr, (uintptr_t)data->data,
75 				data);
76 		if (ret != 0) {
77 			LOG_ERR("DMA Prepare failed");
78 			return -EINVAL;
79 		}
80 	}
81 
82 	ret = cdns_sdmmc_ops->send_cmd(&cdns_sdmmc_cmd, data);
83 
84 	if (ret == 0) {
85 		if (cmd->opcode == SD_READ_SINGLE_BLOCK || cmd->opcode == SD_APP_SEND_SCR ||
86 			cmd->opcode == SD_READ_MULTIPLE_BLOCK) {
87 
88 			if (data == NULL) {
89 				LOG_ERR("Invalid data parameter");
90 				return -ENODATA;
91 			}
92 			ret = cdns_sdmmc_ops->cache_invd(data->block_addr, (uintptr_t)data->data,
93 				data->block_size);
94 			if (ret != 0) {
95 				return ret;
96 			}
97 		}
98 	}
99 	/* copying all responses as per response type */
100 	for (int i = 0; i < 4; i++) {
101 		cmd->response[i] = cdns_sdmmc_cmd.resp_data[i];
102 	}
103 	return ret;
104 }
105 
sdhc_cdns_get_card_present(const struct device * dev)106 static int sdhc_cdns_get_card_present(const struct device *dev)
107 {
108 	return cdns_sdmmc_ops->card_present();
109 }
110 
sdhc_cdns_card_busy(const struct device * dev)111 static int sdhc_cdns_card_busy(const struct device *dev)
112 {
113 	return cdns_sdmmc_ops->busy();
114 }
115 
sdhc_cdns_get_host_props(const struct device * dev,struct sdhc_host_props * props)116 static int sdhc_cdns_get_host_props(const struct device *dev,
117 	struct sdhc_host_props *props)
118 {
119 	const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev);
120 
121 	memset(props, 0, sizeof(struct sdhc_host_props));
122 	props->f_min = SDMMC_CLOCK_400KHZ;
123 	/*
124 	 * default max speed is 25MHZ, as per SCR register
125 	 * it will switch accordingly
126 	 */
127 	props->f_max = SD_CLOCK_25MHZ;
128 	props->power_delay = sdhc_config->power_delay_ms;
129 	props->host_caps.vol_330_support = true;
130 	props->is_spi = false;
131 	return 0;
132 }
133 
sdhc_cdns_reset(const struct device * dev)134 static int sdhc_cdns_reset(const struct device *dev)
135 {
136 	return cdns_sdmmc_ops->reset();
137 }
138 
sdhc_cdns_init(const struct device * dev)139 static int sdhc_cdns_init(const struct device *dev)
140 {
141 	struct sdhc_cdns_data *const data = DEV_DATA(dev);
142 	const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev);
143 	int ret;
144 
145 	/* SDHC reg base */
146 	DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE);
147 	/* ComboPhy reg base */
148 	DEVICE_MMIO_NAMED_MAP(dev, combo_phy, K_MEM_CACHE_NONE);
149 
150 	/* clock setting */
151 	if (sdhc_config->clk_rate == 0U) {
152 		if (!device_is_ready(sdhc_config->cdns_clk_dev)) {
153 			LOG_ERR("Clock controller device is not ready");
154 			return -EINVAL;
155 		}
156 
157 		ret = clock_control_get_rate(sdhc_config->cdns_clk_dev,
158 			sdhc_config->clkid, &data->params.clk_rate);
159 
160 		if (ret != 0) {
161 			return ret;
162 		}
163 	} else {
164 		data->params.clk_rate = sdhc_config->clk_rate;
165 	}
166 
167 	/* Setting regbase */
168 	data->params.reg_base = DEVICE_MMIO_NAMED_GET(dev, reg_base);
169 	data->params.reg_phy = DEVICE_MMIO_NAMED_GET(dev, combo_phy);
170 	data->params.combophy = (DEVICE_MMIO_NAMED_ROM_PTR((dev),
171 		combo_phy)->phys_addr);
172 	data->params.combophy = (data->params.combophy & COMBOPHY_ADDR_MASK);
173 
174 	/* resetting the lines */
175 	if (sdhc_config->reset_sdmmc.dev != NULL) {
176 		if (!device_is_ready(sdhc_config->reset_sdmmc.dev) ||
177 			!device_is_ready(sdhc_config->reset_sdmmcocp.dev) ||
178 			!device_is_ready(sdhc_config->reset_softphy.dev)) {
179 			LOG_ERR("Reset device not found");
180 			return -ENODEV;
181 		}
182 
183 		ret = reset_line_toggle(sdhc_config->reset_softphy.dev,
184 			sdhc_config->reset_softphy.id);
185 		if (ret != 0) {
186 			LOG_ERR("Softphy Reset failed");
187 			return ret;
188 		}
189 
190 		ret = reset_line_toggle(sdhc_config->reset_sdmmc.dev,
191 			sdhc_config->reset_sdmmc.id);
192 		if (ret != 0) {
193 			LOG_ERR("sdmmc Reset failed");
194 			return ret;
195 		}
196 
197 		ret = reset_line_toggle(sdhc_config->reset_sdmmcocp.dev,
198 			sdhc_config->reset_sdmmcocp.id);
199 		if (ret != 0) {
200 			LOG_ERR("sdmmcocp Reset failed");
201 			return ret;
202 		}
203 	}
204 
205 	/* Init function to call lower layer file */
206 	sdhc_cdns_sdmmc_init(&data->params, &data->info, &cdns_sdmmc_ops);
207 
208 	ret = sdhc_cdns_reset(dev);
209 	if (ret != 0U) {
210 		LOG_ERR("Card reset failed");
211 		return ret;
212 	}
213 
214 	/* Init operation called for register initialisation */
215 	ret = cdns_sdmmc_ops->init();
216 	if (ret != 0U) {
217 		LOG_ERR("Card initialization failed");
218 		return ret;
219 	}
220 
221 	return 0;
222 }
223 
sdhc_cdns_set_io(const struct device * dev,struct sdhc_io * ios)224 static int sdhc_cdns_set_io(const struct device *dev, struct sdhc_io *ios)
225 {
226 	struct sdhc_cdns_data *data = dev->data;
227 	struct sdhc_io *host_io = &data->host_io;
228 
229 	if (host_io->bus_width != ios->bus_width || host_io->clock !=
230 		ios->clock) {
231 		host_io->bus_width = ios->bus_width;
232 		host_io->clock = ios->clock;
233 		return cdns_sdmmc_ops->set_ios(ios->clock, ios->bus_width);
234 	}
235 	return 0;
236 }
237 
238 static const struct sdhc_driver_api sdhc_cdns_api = {
239 	.request = sdhc_cdns_request,
240 	.set_io = sdhc_cdns_set_io,
241 	.get_host_props = sdhc_cdns_get_host_props,
242 	.get_card_present = sdhc_cdns_get_card_present,
243 	.reset = sdhc_cdns_reset,
244 	.card_busy = sdhc_cdns_card_busy,
245 };
246 
247 #define SDHC_CDNS_CLOCK_RATE_INIT(inst) \
248 		COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \
249 			( \
250 				.clk_rate = DT_INST_PROP(inst, clock_frequency), \
251 				.cdns_clk_dev = NULL, \
252 				.clkid = (clock_control_subsys_t)0, \
253 			), \
254 			( \
255 				.clk_rate = 0, \
256 				.cdns_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \
257 				.clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \
258 			) \
259 		)
260 
261 #define SDHC_CDNS_RESET_SPEC_INIT(inst) \
262 	.reset_sdmmc = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0),	\
263 	.reset_sdmmcocp = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1),\
264 	.reset_softphy = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 2),
265 
266 #define SDHC_CDNS_INIT(inst)						\
267 	static struct sdhc_cdns_desc cdns_desc				\
268 			[CONFIG_CDNS_DESC_COUNT];			\
269 									\
270 	static const struct sdhc_cdns_config sdhc_cdns_config_##inst = {\
271 		DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(			\
272 				reg_base, DT_DRV_INST(inst)),		\
273 		DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(			\
274 				combo_phy, DT_DRV_INST(inst)),		\
275 		SDHC_CDNS_CLOCK_RATE_INIT(inst)				\
276 		IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets),		\
277 			(SDHC_CDNS_RESET_SPEC_INIT(inst)))	\
278 		.power_delay_ms = DT_INST_PROP(inst, power_delay_ms),	\
279 	};								\
280 	static struct sdhc_cdns_data sdhc_cdns_data_##inst = {		\
281 		.params = {						\
282 			.bus_width = SDHC_BUS_WIDTH1BIT,		\
283 			.desc_base = (uintptr_t) &cdns_desc,		\
284 			.desc_size = SDHC_CDNS_DESC_SIZE,		\
285 			.flags = 0,					\
286 		},							\
287 		.info = {						\
288 			.cdn_sdmmc_dev_type = SD_DS,			\
289 			.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3,	\
290 		},							\
291 	};								\
292 	DEVICE_DT_INST_DEFINE(inst,					\
293 			&sdhc_cdns_init,				\
294 			NULL,						\
295 			&sdhc_cdns_data_##inst,				\
296 			&sdhc_cdns_config_##inst,			\
297 			POST_KERNEL,					\
298 			CONFIG_SDHC_INIT_PRIORITY,			\
299 			&sdhc_cdns_api);
300 
301 DT_INST_FOREACH_STATUS_OKAY(SDHC_CDNS_INIT)
302