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