blob: 9a1693940a792ba3dbd9520546b7e8f97bdfb1ca [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Michal Simek0dd222b2013-04-22 14:56:49 +02002/*
Michal Simek9ecd2682015-11-30 16:13:03 +01003 * (C) Copyright 2013 - 2015 Xilinx, Inc.
Michal Simek0dd222b2013-04-22 14:56:49 +02004 *
5 * Xilinx Zynq SD Host Controller Interface
Michal Simek0dd222b2013-04-22 14:56:49 +02006 */
7
Stefan Herbrechtsmeier739ae402017-01-17 16:27:32 +01008#include <clk.h>
Michal Simek0dd222b2013-04-22 14:56:49 +02009#include <common.h>
Michal Simek9ecd2682015-11-30 16:13:03 +010010#include <dm.h>
Michal Simekc57ba042014-02-24 11:16:31 +010011#include <fdtdec.h>
Simon Glassdbd79542020-05-10 11:40:11 -060012#include <linux/delay.h>
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +053013#include "mmc_private.h"
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070015#include <dm/device_compat.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070016#include <linux/err.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090017#include <linux/libfdt.h>
Ashok Reddy Soma7a5f8102021-08-02 23:20:44 -060018#include <asm/cache.h>
Michal Simek0dd222b2013-04-22 14:56:49 +020019#include <malloc.h>
20#include <sdhci.h>
Ashok Reddy Soma467d0782021-08-02 23:20:43 -060021#include <zynqmp_firmware.h>
Michal Simek0dd222b2013-04-22 14:56:49 +020022
Ashok Reddy Soma24a51072021-07-09 05:53:41 -060023#define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8
24#define SDHCI_ARASAN_ITAPDLY_SEL_MASK GENMASK(7, 0)
25#define SDHCI_ARASAN_OTAPDLY_REGISTER 0xF0FC
26#define SDHCI_ARASAN_OTAPDLY_SEL_MASK GENMASK(5, 0)
27#define SDHCI_ITAPDLY_CHGWIN BIT(9)
28#define SDHCI_ITAPDLY_ENABLE BIT(8)
29#define SDHCI_OTAPDLY_ENABLE BIT(6)
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -060030
Michal Simek5b5101e2020-10-23 04:58:59 -060031#define SDHCI_TUNING_LOOP_COUNT 40
Michal Simek33a6b772020-10-23 04:59:00 -060032#define MMC_BANK2 0x2
33
Ashok Reddy Soma7a5f8102021-08-02 23:20:44 -060034#define SD_DLL_CTRL 0xFF180358
35#define SD_ITAP_DLY 0xFF180314
36#define SD_OTAP_DLY 0xFF180318
37#define SD0_DLL_RST BIT(2)
38#define SD1_DLL_RST BIT(18)
39#define SD0_ITAPCHGWIN BIT(9)
40#define SD1_ITAPCHGWIN BIT(25)
41#define SD0_ITAPDLYENA BIT(8)
42#define SD1_ITAPDLYENA BIT(24)
43#define SD0_ITAPDLYSEL_MASK GENMASK(7, 0)
44#define SD1_ITAPDLYSEL_MASK GENMASK(23, 16)
45#define SD0_OTAPDLYSEL_MASK GENMASK(5, 0)
46#define SD1_OTAPDLYSEL_MASK GENMASK(21, 16)
47
Michal Simek33a6b772020-10-23 04:59:00 -060048struct arasan_sdhci_clk_data {
49 int clk_phase_in[MMC_TIMING_MMC_HS400 + 1];
50 int clk_phase_out[MMC_TIMING_MMC_HS400 + 1];
51};
Michal Simek5b5101e2020-10-23 04:58:59 -060052
Simon Glass4cc87fb2016-07-05 17:10:15 -060053struct arasan_sdhci_plat {
54 struct mmc_config cfg;
55 struct mmc mmc;
56};
57
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +053058struct arasan_sdhci_priv {
59 struct sdhci_host *host;
Michal Simek33a6b772020-10-23 04:59:00 -060060 struct arasan_sdhci_clk_data clk_data;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +053061 u8 deviceid;
62 u8 bank;
Ashok Reddy Soma61e0df92020-10-23 04:58:57 -060063 u8 no_1p8;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +053064};
65
Ashok Reddy Soma7a5f8102021-08-02 23:20:44 -060066/* For Versal platforms zynqmp_mmio_write() won't be available */
67__weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value)
68{
69 return 0;
70}
71
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -060072#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL)
Michal Simek33a6b772020-10-23 04:59:00 -060073/* Default settings for ZynqMP Clock Phases */
Michal Simek635cf4a2021-07-09 05:53:44 -060074static const u32 zynqmp_iclk_phases[] = {0, 63, 63, 0, 63, 0,
75 0, 183, 54, 0, 0};
76static const u32 zynqmp_oclk_phases[] = {0, 72, 60, 0, 60, 72,
77 135, 48, 72, 135, 0};
Michal Simek33a6b772020-10-23 04:59:00 -060078
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -060079/* Default settings for Versal Clock Phases */
Michal Simek635cf4a2021-07-09 05:53:44 -060080static const u32 versal_iclk_phases[] = {0, 132, 132, 0, 132,
81 0, 0, 162, 90, 0, 0};
82static const u32 versal_oclk_phases[] = {0, 60, 48, 0, 48, 72,
83 90, 36, 60, 90, 0};
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -060084
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +053085static const u8 mode2timing[] = {
Ashok Reddy Soma0afdfe32020-10-23 04:58:58 -060086 [MMC_LEGACY] = MMC_TIMING_LEGACY,
87 [MMC_HS] = MMC_TIMING_MMC_HS,
88 [SD_HS] = MMC_TIMING_SD_HS,
89 [MMC_HS_52] = MMC_TIMING_UHS_SDR50,
90 [MMC_DDR_52] = MMC_TIMING_UHS_DDR50,
91 [UHS_SDR12] = MMC_TIMING_UHS_SDR12,
92 [UHS_SDR25] = MMC_TIMING_UHS_SDR25,
93 [UHS_SDR50] = MMC_TIMING_UHS_SDR50,
94 [UHS_DDR50] = MMC_TIMING_UHS_DDR50,
95 [UHS_SDR104] = MMC_TIMING_UHS_SDR104,
96 [MMC_HS_200] = MMC_TIMING_MMC_HS200,
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +053097};
98
Ashok Reddy Soma7a5f8102021-08-02 23:20:44 -060099static inline int arasan_zynqmp_set_in_tapdelay(u8 node_id, u32 itap_delay)
100{
101 int ret;
102
103 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
104 if (node_id == NODE_SD_0) {
105 ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN,
106 SD0_ITAPCHGWIN);
107 if (ret)
108 return ret;
109
110 ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA,
111 SD0_ITAPDLYENA);
112 if (ret)
113 return ret;
114
115 ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK,
116 itap_delay);
117 if (ret)
118 return ret;
119
120 ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, 0);
121 if (ret)
122 return ret;
123 }
124 ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN,
125 SD1_ITAPCHGWIN);
126 if (ret)
127 return ret;
128
129 ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA,
130 SD1_ITAPDLYENA);
131 if (ret)
132 return ret;
133
134 ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK,
135 (itap_delay << 16));
136 if (ret)
137 return ret;
138
139 ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN, 0);
140 if (ret)
141 return ret;
142 } else {
143 return xilinx_pm_request(PM_IOCTL, (u32)node_id,
144 IOCTL_SET_SD_TAPDELAY,
145 PM_TAPDELAY_INPUT, itap_delay, NULL);
146 }
147
148 return 0;
149}
150
151static inline int arasan_zynqmp_set_out_tapdelay(u8 node_id, u32 otap_delay)
152{
153 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
154 if (node_id == NODE_SD_0)
155 return zynqmp_mmio_write(SD_OTAP_DLY,
156 SD0_OTAPDLYSEL_MASK,
157 otap_delay);
158
159 return zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
160 (otap_delay << 16));
161 } else {
162 return xilinx_pm_request(PM_IOCTL, (u32)node_id,
163 IOCTL_SET_SD_TAPDELAY,
164 PM_TAPDELAY_OUTPUT, otap_delay, NULL);
165 }
166}
167
168static inline int zynqmp_dll_reset(u8 node_id, u32 type)
169{
170 if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
171 if (node_id == NODE_SD_0)
172 return zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST,
173 type == PM_DLL_RESET_ASSERT ?
174 SD0_DLL_RST : 0);
175
176 return zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST,
177 type == PM_DLL_RESET_ASSERT ?
178 SD1_DLL_RST : 0);
179 } else {
180 return xilinx_pm_request(PM_IOCTL, (u32)node_id,
181 IOCTL_SD_DLL_RESET, type, 0, NULL);
182 }
183}
184
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600185static int arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 node_id)
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530186{
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600187 struct mmc *mmc = (struct mmc *)host->mmc;
188 struct udevice *dev = mmc->dev;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530189 unsigned long timeout;
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600190 int ret;
191 u16 clk;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530192
193 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
194 clk &= ~(SDHCI_CLOCK_CARD_EN);
195 sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
196
197 /* Issue DLL Reset */
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600198 ret = zynqmp_dll_reset(node_id, PM_DLL_RESET_ASSERT);
199 if (ret) {
200 dev_err(dev, "dll_reset assert failed with err: %d\n", ret);
201 return ret;
202 }
203
204 /* Allow atleast 1ms delay for proper DLL reset */
205 mdelay(1);
206 ret = zynqmp_dll_reset(node_id, PM_DLL_RESET_RELEASE);
207 if (ret) {
208 dev_err(dev, "dll_reset release failed with err: %d\n", ret);
209 return ret;
210 }
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530211
212 /* Wait max 20 ms */
213 timeout = 100;
214 while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
215 & SDHCI_CLOCK_INT_STABLE)) {
216 if (timeout == 0) {
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600217 dev_err(dev, ": Internal clock never stabilised.\n");
218 return -EBUSY;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530219 }
220 timeout--;
221 udelay(1000);
222 }
223
224 clk |= SDHCI_CLOCK_CARD_EN;
225 sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600226
227 return 0;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530228}
229
230static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
231{
232 struct mmc_cmd cmd;
233 struct mmc_data data;
234 u32 ctrl;
235 struct sdhci_host *host;
236 struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev);
Michal Simek91e95ff2018-06-13 09:12:29 +0200237 char tuning_loop_counter = SDHCI_TUNING_LOOP_COUNT;
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600238 u8 node_id = priv->deviceid ? NODE_SD_1 : NODE_SD_0;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530239
240 debug("%s\n", __func__);
241
242 host = priv->host;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530243
Faiz Abbas2eddc002019-06-11 00:43:40 +0530244 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530245 ctrl |= SDHCI_CTRL_EXEC_TUNING;
Faiz Abbas2eddc002019-06-11 00:43:40 +0530246 sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530247
248 mdelay(1);
249
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600250 arasan_zynqmp_dll_reset(host, node_id);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530251
252 sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
253 sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
254
255 do {
256 cmd.cmdidx = opcode;
257 cmd.resp_type = MMC_RSP_R1;
258 cmd.cmdarg = 0;
259
260 data.blocksize = 64;
261 data.blocks = 1;
262 data.flags = MMC_DATA_READ;
263
264 if (tuning_loop_counter-- == 0)
265 break;
266
267 if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200 &&
268 mmc->bus_width == 8)
269 data.blocksize = 128;
270
271 sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
272 data.blocksize),
273 SDHCI_BLOCK_SIZE);
274 sdhci_writew(host, data.blocks, SDHCI_BLOCK_COUNT);
275 sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
276
277 mmc_send_cmd(mmc, &cmd, NULL);
Faiz Abbas2eddc002019-06-11 00:43:40 +0530278 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530279
280 if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
281 udelay(1);
282
283 } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
284
285 if (tuning_loop_counter < 0) {
286 ctrl &= ~SDHCI_CTRL_TUNED_CLK;
Faiz Abbas2eddc002019-06-11 00:43:40 +0530287 sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530288 }
289
290 if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
291 printf("%s:Tuning failed\n", __func__);
292 return -1;
293 }
294
295 udelay(1);
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600296 arasan_zynqmp_dll_reset(host, node_id);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530297
298 /* Enable only interrupts served by the SD controller */
299 sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
300 SDHCI_INT_ENABLE);
301 /* Mask all sdhci interrupt sources */
302 sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
303
304 return 0;
305}
306
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600307/**
308 * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
309 *
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600310 * @host: Pointer to the sdhci_host structure.
311 * @degrees: The clock phase shift between 0 - 359.
Ashok Reddy Soma94a755d2021-07-09 05:53:39 -0600312 * Return: 0
Michal Simek2a43ab82021-07-09 05:53:43 -0600313 *
314 * Set the SD Output Clock Tap Delays for Output path
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600315 */
316static int sdhci_zynqmp_sdcardclk_set_phase(struct sdhci_host *host,
317 int degrees)
318{
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600319 struct mmc *mmc = (struct mmc *)host->mmc;
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600320 struct udevice *dev = mmc->dev;
321 struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev);
322 u8 node_id = priv->deviceid ? NODE_SD_1 : NODE_SD_0;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600323 u8 tap_delay, tap_max = 0;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600324 int timing = mode2timing[mmc->selected_mode];
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600325 int ret;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600326
327 /*
328 * This is applicable for SDHCI_SPEC_300 and above
329 * ZynqMP does not set phase for <=25MHz clock.
330 * If degrees is zero, no need to do anything.
331 */
Ashok Reddy Soma6f645382021-07-09 05:53:40 -0600332 if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300)
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600333 return 0;
334
335 switch (timing) {
336 case MMC_TIMING_MMC_HS:
337 case MMC_TIMING_SD_HS:
338 case MMC_TIMING_UHS_SDR25:
339 case MMC_TIMING_UHS_DDR50:
340 case MMC_TIMING_MMC_DDR52:
341 /* For 50MHz clock, 30 Taps are available */
342 tap_max = 30;
343 break;
344 case MMC_TIMING_UHS_SDR50:
345 /* For 100MHz clock, 15 Taps are available */
346 tap_max = 15;
347 break;
348 case MMC_TIMING_UHS_SDR104:
349 case MMC_TIMING_MMC_HS200:
350 /* For 200MHz clock, 8 Taps are available */
351 tap_max = 8;
352 default:
353 break;
354 }
355
356 tap_delay = (degrees * tap_max) / 360;
357
Ashok Reddy Soma39a177a2021-07-09 05:53:42 -0600358 /* Limit output tap_delay value to 6 bits */
359 tap_delay &= SDHCI_ARASAN_OTAPDLY_SEL_MASK;
360
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600361 /* Set the Clock Phase */
362 ret = arasan_zynqmp_set_out_tapdelay(node_id, tap_delay);
363 if (ret) {
364 dev_err(dev, "Error setting output Tap Delay\n");
365 return ret;
366 }
367
368 /* Release DLL Reset */
369 ret = zynqmp_dll_reset(node_id, PM_DLL_RESET_RELEASE);
370 if (ret) {
371 dev_err(dev, "dll_reset release failed with err: %d\n", ret);
372 return ret;
373 }
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600374
Ashok Reddy Soma94a755d2021-07-09 05:53:39 -0600375 return 0;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600376}
377
378/**
379 * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays
380 *
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600381 * @host: Pointer to the sdhci_host structure.
382 * @degrees: The clock phase shift between 0 - 359.
Ashok Reddy Soma94a755d2021-07-09 05:53:39 -0600383 * Return: 0
Michal Simek2a43ab82021-07-09 05:53:43 -0600384 *
385 * Set the SD Input Clock Tap Delays for Input path
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600386 */
387static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host,
388 int degrees)
389{
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600390 struct mmc *mmc = (struct mmc *)host->mmc;
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600391 struct udevice *dev = mmc->dev;
392 struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev);
393 u8 node_id = priv->deviceid ? NODE_SD_1 : NODE_SD_0;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600394 u8 tap_delay, tap_max = 0;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600395 int timing = mode2timing[mmc->selected_mode];
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600396 int ret;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600397
398 /*
399 * This is applicable for SDHCI_SPEC_300 and above
400 * ZynqMP does not set phase for <=25MHz clock.
401 * If degrees is zero, no need to do anything.
402 */
Ashok Reddy Soma6f645382021-07-09 05:53:40 -0600403 if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300)
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600404 return 0;
405
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600406 /* Assert DLL Reset */
407 ret = zynqmp_dll_reset(node_id, PM_DLL_RESET_ASSERT);
408 if (ret) {
409 dev_err(dev, "dll_reset assert failed with err: %d\n", ret);
410 return ret;
411 }
412
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600413 switch (timing) {
414 case MMC_TIMING_MMC_HS:
415 case MMC_TIMING_SD_HS:
416 case MMC_TIMING_UHS_SDR25:
417 case MMC_TIMING_UHS_DDR50:
418 case MMC_TIMING_MMC_DDR52:
419 /* For 50MHz clock, 120 Taps are available */
420 tap_max = 120;
421 break;
422 case MMC_TIMING_UHS_SDR50:
423 /* For 100MHz clock, 60 Taps are available */
424 tap_max = 60;
425 break;
426 case MMC_TIMING_UHS_SDR104:
427 case MMC_TIMING_MMC_HS200:
428 /* For 200MHz clock, 30 Taps are available */
429 tap_max = 30;
430 default:
431 break;
432 }
433
434 tap_delay = (degrees * tap_max) / 360;
435
Ashok Reddy Soma39a177a2021-07-09 05:53:42 -0600436 /* Limit input tap_delay value to 8 bits */
437 tap_delay &= SDHCI_ARASAN_ITAPDLY_SEL_MASK;
438
Ashok Reddy Soma467d0782021-08-02 23:20:43 -0600439 ret = arasan_zynqmp_set_in_tapdelay(node_id, tap_delay);
440 if (ret) {
441 dev_err(dev, "Error setting Input Tap Delay\n");
442 return ret;
443 }
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600444
Ashok Reddy Soma94a755d2021-07-09 05:53:39 -0600445 return 0;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600446}
447
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600448/**
449 * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
450 *
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600451 * @host: Pointer to the sdhci_host structure.
Michal Simek2a43ab82021-07-09 05:53:43 -0600452 * @degrees: The clock phase shift between 0 - 359.
Ashok Reddy Soma94a755d2021-07-09 05:53:39 -0600453 * Return: 0
Michal Simek2a43ab82021-07-09 05:53:43 -0600454 *
455 * Set the SD Output Clock Tap Delays for Output path
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600456 */
457static int sdhci_versal_sdcardclk_set_phase(struct sdhci_host *host,
458 int degrees)
459{
460 struct mmc *mmc = (struct mmc *)host->mmc;
461 u8 tap_delay, tap_max = 0;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600462 int timing = mode2timing[mmc->selected_mode];
Ashok Reddy Soma24a51072021-07-09 05:53:41 -0600463 u32 regval;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600464
465 /*
466 * This is applicable for SDHCI_SPEC_300 and above
467 * Versal does not set phase for <=25MHz clock.
468 * If degrees is zero, no need to do anything.
469 */
Ashok Reddy Soma6f645382021-07-09 05:53:40 -0600470 if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300)
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600471 return 0;
472
473 switch (timing) {
474 case MMC_TIMING_MMC_HS:
475 case MMC_TIMING_SD_HS:
476 case MMC_TIMING_UHS_SDR25:
477 case MMC_TIMING_UHS_DDR50:
478 case MMC_TIMING_MMC_DDR52:
479 /* For 50MHz clock, 30 Taps are available */
480 tap_max = 30;
481 break;
482 case MMC_TIMING_UHS_SDR50:
483 /* For 100MHz clock, 15 Taps are available */
484 tap_max = 15;
485 break;
486 case MMC_TIMING_UHS_SDR104:
487 case MMC_TIMING_MMC_HS200:
488 /* For 200MHz clock, 8 Taps are available */
489 tap_max = 8;
490 default:
491 break;
492 }
493
494 tap_delay = (degrees * tap_max) / 360;
495
Ashok Reddy Soma24a51072021-07-09 05:53:41 -0600496 /* Limit output tap_delay value to 6 bits */
497 tap_delay &= SDHCI_ARASAN_OTAPDLY_SEL_MASK;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600498
Ashok Reddy Soma24a51072021-07-09 05:53:41 -0600499 /* Set the Clock Phase */
500 regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER);
501 regval |= SDHCI_OTAPDLY_ENABLE;
502 sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
503 regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK;
504 regval |= tap_delay;
505 sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600506
Ashok Reddy Soma94a755d2021-07-09 05:53:39 -0600507 return 0;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600508}
509
510/**
511 * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays
512 *
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600513 * @host: Pointer to the sdhci_host structure.
Michal Simek2a43ab82021-07-09 05:53:43 -0600514 * @degrees: The clock phase shift between 0 - 359.
Ashok Reddy Soma94a755d2021-07-09 05:53:39 -0600515 * Return: 0
Michal Simek2a43ab82021-07-09 05:53:43 -0600516 *
517 * Set the SD Input Clock Tap Delays for Input path
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600518 */
519static int sdhci_versal_sampleclk_set_phase(struct sdhci_host *host,
520 int degrees)
521{
522 struct mmc *mmc = (struct mmc *)host->mmc;
523 u8 tap_delay, tap_max = 0;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600524 int timing = mode2timing[mmc->selected_mode];
Ashok Reddy Soma24a51072021-07-09 05:53:41 -0600525 u32 regval;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600526
527 /*
528 * This is applicable for SDHCI_SPEC_300 and above
529 * Versal does not set phase for <=25MHz clock.
530 * If degrees is zero, no need to do anything.
531 */
Ashok Reddy Soma6f645382021-07-09 05:53:40 -0600532 if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300)
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600533 return 0;
534
535 switch (timing) {
536 case MMC_TIMING_MMC_HS:
537 case MMC_TIMING_SD_HS:
538 case MMC_TIMING_UHS_SDR25:
539 case MMC_TIMING_UHS_DDR50:
540 case MMC_TIMING_MMC_DDR52:
541 /* For 50MHz clock, 120 Taps are available */
542 tap_max = 120;
543 break;
544 case MMC_TIMING_UHS_SDR50:
545 /* For 100MHz clock, 60 Taps are available */
546 tap_max = 60;
547 break;
548 case MMC_TIMING_UHS_SDR104:
549 case MMC_TIMING_MMC_HS200:
550 /* For 200MHz clock, 30 Taps are available */
551 tap_max = 30;
552 default:
553 break;
554 }
555
556 tap_delay = (degrees * tap_max) / 360;
557
Ashok Reddy Soma24a51072021-07-09 05:53:41 -0600558 /* Limit input tap_delay value to 8 bits */
559 tap_delay &= SDHCI_ARASAN_ITAPDLY_SEL_MASK;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600560
Ashok Reddy Soma24a51072021-07-09 05:53:41 -0600561 /* Set the Clock Phase */
562 regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER);
563 regval |= SDHCI_ITAPDLY_CHGWIN;
564 sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
565 regval |= SDHCI_ITAPDLY_ENABLE;
566 sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
567 regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK;
568 regval |= tap_delay;
569 sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
570 regval &= ~SDHCI_ITAPDLY_CHGWIN;
571 sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600572
Ashok Reddy Soma94a755d2021-07-09 05:53:39 -0600573 return 0;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600574}
575
Ashok Reddy Soma21fd7632021-08-02 23:20:40 -0600576static int arasan_sdhci_set_tapdelay(struct sdhci_host *host)
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530577{
578 struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600579 struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530580 struct mmc *mmc = (struct mmc *)host->mmc;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600581 struct udevice *dev = mmc->dev;
582 u8 timing = mode2timing[mmc->selected_mode];
583 u32 iclk_phase = clk_data->clk_phase_in[timing];
584 u32 oclk_phase = clk_data->clk_phase_out[timing];
Ashok Reddy Soma21fd7632021-08-02 23:20:40 -0600585 int ret;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530586
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600587 dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name, timing);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530588
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600589 if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) &&
590 device_is_compatible(dev, "xlnx,zynqmp-8.9a")) {
Ashok Reddy Soma21fd7632021-08-02 23:20:40 -0600591 ret = sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase);
592 if (ret)
593 return ret;
594
595 ret = sdhci_zynqmp_sdcardclk_set_phase(host, oclk_phase);
596 if (ret)
597 return ret;
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600598 } else if (IS_ENABLED(CONFIG_ARCH_VERSAL) &&
599 device_is_compatible(dev, "xlnx,versal-8.9a")) {
Ashok Reddy Soma21fd7632021-08-02 23:20:40 -0600600 ret = sdhci_versal_sampleclk_set_phase(host, iclk_phase);
601 if (ret)
602 return ret;
603
604 ret = sdhci_versal_sdcardclk_set_phase(host, oclk_phase);
605 if (ret)
606 return ret;
Ashok Reddy Soma8f629862020-10-23 04:59:01 -0600607 }
Ashok Reddy Soma21fd7632021-08-02 23:20:40 -0600608
609 return 0;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530610}
611
Michal Simek33a6b772020-10-23 04:59:00 -0600612static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned char timing,
613 const char *prop)
614{
615 struct arasan_sdhci_priv *priv = dev_get_priv(dev);
616 struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
617 u32 clk_phase[2] = {0};
618
619 /*
620 * Read Tap Delay values from DT, if the DT does not contain the
621 * Tap Values then use the pre-defined values
622 */
623 if (dev_read_u32_array(dev, prop, &clk_phase[0], 2)) {
624 dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n",
625 prop, clk_data->clk_phase_in[timing],
626 clk_data->clk_phase_out[timing]);
627 return;
628 }
629
630 /* The values read are Input and Output Clock Delays in order */
631 clk_data->clk_phase_in[timing] = clk_phase[0];
632 clk_data->clk_phase_out[timing] = clk_phase[1];
633}
634
635/**
636 * arasan_dt_parse_clk_phases - Read Tap Delay values from DT
637 *
Michal Simek33a6b772020-10-23 04:59:00 -0600638 * @dev: Pointer to our struct udevice.
Michal Simek2a43ab82021-07-09 05:53:43 -0600639 *
640 * Called at initialization to parse the values of Tap Delays.
Michal Simek33a6b772020-10-23 04:59:00 -0600641 */
642static void arasan_dt_parse_clk_phases(struct udevice *dev)
643{
644 struct arasan_sdhci_priv *priv = dev_get_priv(dev);
645 struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
646 int i;
647
648 if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) &&
649 device_is_compatible(dev, "xlnx,zynqmp-8.9a")) {
650 for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
651 clk_data->clk_phase_in[i] = zynqmp_iclk_phases[i];
652 clk_data->clk_phase_out[i] = zynqmp_oclk_phases[i];
653 }
654
655 if (priv->bank == MMC_BANK2) {
656 clk_data->clk_phase_out[MMC_TIMING_UHS_SDR104] = 90;
657 clk_data->clk_phase_out[MMC_TIMING_MMC_HS200] = 90;
658 }
659 }
660
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600661 if (IS_ENABLED(CONFIG_ARCH_VERSAL) &&
662 device_is_compatible(dev, "xlnx,versal-8.9a")) {
663 for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
664 clk_data->clk_phase_in[i] = versal_iclk_phases[i];
665 clk_data->clk_phase_out[i] = versal_oclk_phases[i];
666 }
667 }
668
Michal Simek33a6b772020-10-23 04:59:00 -0600669 arasan_dt_read_clk_phase(dev, MMC_TIMING_LEGACY,
670 "clk-phase-legacy");
671 arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS,
672 "clk-phase-mmc-hs");
673 arasan_dt_read_clk_phase(dev, MMC_TIMING_SD_HS,
674 "clk-phase-sd-hs");
675 arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR12,
676 "clk-phase-uhs-sdr12");
677 arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR25,
678 "clk-phase-uhs-sdr25");
679 arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR50,
680 "clk-phase-uhs-sdr50");
681 arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR104,
682 "clk-phase-uhs-sdr104");
683 arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_DDR50,
684 "clk-phase-uhs-ddr50");
685 arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_DDR52,
686 "clk-phase-mmc-ddr52");
687 arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS200,
688 "clk-phase-mmc-hs200");
689 arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS400,
690 "clk-phase-mmc-hs400");
691}
692
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530693static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
694{
695 struct mmc *mmc = (struct mmc *)host->mmc;
696 u32 reg;
697
Siva Durga Prasad Paladugued9c0122018-05-29 20:03:11 +0530698 if (!IS_SD(mmc))
699 return;
700
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530701 if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
Faiz Abbas2eddc002019-06-11 00:43:40 +0530702 reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
703 reg |= SDHCI_CTRL_VDD_180;
704 sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530705 }
706
707 if (mmc->selected_mode > SD_HS &&
Ashok Reddy Soma4179ee82020-10-23 04:59:03 -0600708 mmc->selected_mode <= MMC_HS_200)
Faiz Abbas2eddc002019-06-11 00:43:40 +0530709 sdhci_set_uhs_timing(host);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530710}
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530711
Michal Simek635cf4a2021-07-09 05:53:44 -0600712static const struct sdhci_ops arasan_ops = {
713 .platform_execute_tuning = &arasan_sdhci_execute_tuning,
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530714 .set_delay = &arasan_sdhci_set_tapdelay,
715 .set_control_reg = &arasan_sdhci_set_control_reg,
716};
717#endif
718
Michal Simek9ecd2682015-11-30 16:13:03 +0100719static int arasan_sdhci_probe(struct udevice *dev)
Michal Simek0dd222b2013-04-22 14:56:49 +0200720{
Simon Glassfa20e932020-12-03 16:55:20 -0700721 struct arasan_sdhci_plat *plat = dev_get_plat(dev);
Michal Simek9ecd2682015-11-30 16:13:03 +0100722 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530723 struct arasan_sdhci_priv *priv = dev_get_priv(dev);
724 struct sdhci_host *host;
Stefan Herbrechtsmeier739ae402017-01-17 16:27:32 +0100725 struct clk clk;
726 unsigned long clock;
Simon Glass4cc87fb2016-07-05 17:10:15 -0600727 int ret;
Michal Simek0dd222b2013-04-22 14:56:49 +0200728
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530729 host = priv->host;
730
Stefan Herbrechtsmeier739ae402017-01-17 16:27:32 +0100731 ret = clk_get_by_index(dev, 0, &clk);
732 if (ret < 0) {
733 dev_err(dev, "failed to get clock\n");
734 return ret;
735 }
736
737 clock = clk_get_rate(&clk);
738 if (IS_ERR_VALUE(clock)) {
739 dev_err(dev, "failed to get rate\n");
740 return clock;
741 }
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530742
Stefan Herbrechtsmeier739ae402017-01-17 16:27:32 +0100743 debug("%s: CLK %ld\n", __func__, clock);
744
745 ret = clk_enable(&clk);
Michal Simek41710952021-02-09 15:28:15 +0100746 if (ret) {
Stefan Herbrechtsmeier739ae402017-01-17 16:27:32 +0100747 dev_err(dev, "failed to enable clock\n");
748 return ret;
749 }
750
Siva Durga Prasad Paladugu049e0032014-07-08 15:31:04 +0530751 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
Siva Durga Prasad Paladugu0d6891b2014-01-22 09:17:09 +0100752 SDHCI_QUIRK_BROKEN_R1B;
Siva Durga Prasad Paladugua1619fe2016-01-12 15:12:16 +0530753
754#ifdef CONFIG_ZYNQ_HISPD_BROKEN
Hannes Schmelzer94a5bbc2018-03-07 08:00:57 +0100755 host->quirks |= SDHCI_QUIRK_BROKEN_HISPD_MODE;
Siva Durga Prasad Paladugua1619fe2016-01-12 15:12:16 +0530756#endif
757
Ashok Reddy Soma61e0df92020-10-23 04:58:57 -0600758 if (priv->no_1p8)
759 host->quirks |= SDHCI_QUIRK_NO_1_8_V;
760
Benedikt Grassl529e6f02020-04-14 07:32:12 +0200761 plat->cfg.f_max = CONFIG_ZYNQ_SDHCI_MAX_FREQ;
762
763 ret = mmc_of_parse(dev, &plat->cfg);
764 if (ret)
765 return ret;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530766
Stefan Herbrechtsmeier739ae402017-01-17 16:27:32 +0100767 host->max_clk = clock;
Stefan Herbrechtsmeierbc47e0e2017-01-17 15:58:48 +0100768
Matwey V. Kornilov194b8602019-08-01 18:00:05 +0300769 host->mmc = &plat->mmc;
770 host->mmc->dev = dev;
771 host->mmc->priv = host;
772
Benedikt Grassl529e6f02020-04-14 07:32:12 +0200773 ret = sdhci_setup_cfg(&plat->cfg, host, plat->cfg.f_max,
Jaehoon Chung8a5ffbb2016-07-26 19:06:24 +0900774 CONFIG_ZYNQ_SDHCI_MIN_FREQ);
Simon Glass4cc87fb2016-07-05 17:10:15 -0600775 if (ret)
776 return ret;
Simon Glass4cc87fb2016-07-05 17:10:15 -0600777 upriv->mmc = host->mmc;
Michal Simek9ecd2682015-11-30 16:13:03 +0100778
Simon Glass4cc87fb2016-07-05 17:10:15 -0600779 return sdhci_probe(dev);
Michal Simek0dd222b2013-04-22 14:56:49 +0200780}
Michal Simek9ecd2682015-11-30 16:13:03 +0100781
Simon Glassaad29ae2020-12-03 16:55:21 -0700782static int arasan_sdhci_of_to_plat(struct udevice *dev)
Michal Simek9ecd2682015-11-30 16:13:03 +0100783{
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530784 struct arasan_sdhci_priv *priv = dev_get_priv(dev);
Michal Simek9ecd2682015-11-30 16:13:03 +0100785
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530786 priv->host = calloc(1, sizeof(struct sdhci_host));
787 if (!priv->host)
788 return -1;
789
790 priv->host->name = dev->name;
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530791
Ashok Reddy Soma568edfd2020-10-23 04:59:02 -0600792#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL)
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530793 priv->host->ops = &arasan_ops;
Michal Simek33a6b772020-10-23 04:59:00 -0600794 arasan_dt_parse_clk_phases(dev);
Siva Durga Prasad Paladugucad14a82018-04-19 12:37:09 +0530795#endif
Michal Simek9ecd2682015-11-30 16:13:03 +0100796
Michal Simek921a8de2018-05-16 10:57:07 +0200797 priv->host->ioaddr = (void *)dev_read_addr(dev);
798 if (IS_ERR(priv->host->ioaddr))
799 return PTR_ERR(priv->host->ioaddr);
800
801 priv->deviceid = dev_read_u32_default(dev, "xlnx,device_id", -1);
Michal Simeke40ae572020-07-22 17:46:31 +0200802 priv->bank = dev_read_u32_default(dev, "xlnx,mio-bank", 0);
Ashok Reddy Soma61e0df92020-10-23 04:58:57 -0600803 priv->no_1p8 = dev_read_bool(dev, "no-1-8-v");
Stefan Herbrechtsmeier5567b422017-01-17 16:27:33 +0100804
Michal Simek9ecd2682015-11-30 16:13:03 +0100805 return 0;
806}
807
Simon Glass4cc87fb2016-07-05 17:10:15 -0600808static int arasan_sdhci_bind(struct udevice *dev)
809{
Simon Glassfa20e932020-12-03 16:55:20 -0700810 struct arasan_sdhci_plat *plat = dev_get_plat(dev);
Simon Glass4cc87fb2016-07-05 17:10:15 -0600811
Masahiro Yamadacdb67f32016-09-06 22:17:32 +0900812 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
Simon Glass4cc87fb2016-07-05 17:10:15 -0600813}
814
Michal Simek9ecd2682015-11-30 16:13:03 +0100815static const struct udevice_id arasan_sdhci_ids[] = {
816 { .compatible = "arasan,sdhci-8.9a" },
817 { }
818};
819
820U_BOOT_DRIVER(arasan_sdhci_drv) = {
821 .name = "arasan_sdhci",
822 .id = UCLASS_MMC,
823 .of_match = arasan_sdhci_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700824 .of_to_plat = arasan_sdhci_of_to_plat,
Simon Glass4cc87fb2016-07-05 17:10:15 -0600825 .ops = &sdhci_ops,
826 .bind = arasan_sdhci_bind,
Michal Simek9ecd2682015-11-30 16:13:03 +0100827 .probe = arasan_sdhci_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700828 .priv_auto = sizeof(struct arasan_sdhci_priv),
Simon Glass71fa5b42020-12-03 16:55:18 -0700829 .plat_auto = sizeof(struct arasan_sdhci_plat),
Michal Simek9ecd2682015-11-30 16:13:03 +0100830};