sunxi_mmc.c 15.5 KB
Newer Older
I
Ian Campbell 已提交
1 2 3 4 5 6 7 8 9 10 11
/*
 * (C) Copyright 2007-2011
 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
 * Aaron <leafy.myeh@allwinnertech.com>
 *
 * MMC driver for allwinner sunxi platform.
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
12
#include <dm.h>
13
#include <errno.h>
I
Ian Campbell 已提交
14 15 16 17 18
#include <malloc.h>
#include <mmc.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/cpu.h>
19
#include <asm/arch/gpio.h>
I
Ian Campbell 已提交
20
#include <asm/arch/mmc.h>
21
#include <asm-generic/gpio.h>
I
Ian Campbell 已提交
22

23 24 25 26 27
struct sunxi_mmc_plat {
	struct mmc_config cfg;
	struct mmc mmc;
};

28
struct sunxi_mmc_priv {
I
Ian Campbell 已提交
29 30 31
	unsigned mmc_no;
	uint32_t *mclkreg;
	unsigned fatal_err;
32
	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
33
	int cd_inverted;		/* Inverted Card Detect */
I
Ian Campbell 已提交
34 35 36 37
	struct sunxi_mmc *reg;
	struct mmc_config cfg;
};

38
#if !CONFIG_IS_ENABLED(DM_MMC)
I
Ian Campbell 已提交
39
/* support 4 mmc hosts */
40
struct sunxi_mmc_priv mmc_host[4];
I
Ian Campbell 已提交
41

42 43 44 45 46 47 48 49
static int sunxi_mmc_getcd_gpio(int sdc_no)
{
	switch (sdc_no) {
	case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN);
	case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN);
	case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
	case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
	}
50
	return -EINVAL;
51 52
}

I
Ian Campbell 已提交
53 54
static int mmc_resource_init(int sdc_no)
{
55
	struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
I
Ian Campbell 已提交
56
	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
57
	int cd_pin, ret = 0;
I
Ian Campbell 已提交
58 59 60 61 62

	debug("init mmc %d resource\n", sdc_no);

	switch (sdc_no) {
	case 0:
63 64
		priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
		priv->mclkreg = &ccm->sd0_clk_cfg;
I
Ian Campbell 已提交
65 66
		break;
	case 1:
67 68
		priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
		priv->mclkreg = &ccm->sd1_clk_cfg;
I
Ian Campbell 已提交
69 70
		break;
	case 2:
71 72
		priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
		priv->mclkreg = &ccm->sd2_clk_cfg;
I
Ian Campbell 已提交
73 74
		break;
	case 3:
75 76
		priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
		priv->mclkreg = &ccm->sd3_clk_cfg;
I
Ian Campbell 已提交
77 78 79 80 81
		break;
	default:
		printf("Wrong mmc number %d\n", sdc_no);
		return -1;
	}
82
	priv->mmc_no = sdc_no;
I
Ian Campbell 已提交
83

84
	cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
85
	if (cd_pin >= 0) {
86
		ret = gpio_request(cd_pin, "mmc_cd");
87 88
		if (!ret) {
			sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
89
			ret = gpio_direction_input(cd_pin);
90
		}
91
	}
92 93

	return ret;
I
Ian Campbell 已提交
94
}
95
#endif
I
Ian Campbell 已提交
96

97
static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
98 99
{
	unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
M
Maxime Ripard 已提交
100 101 102 103 104 105 106 107 108 109 110 111
	bool new_mode = false;
	u32 val = 0;

	if (IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE) && (priv->mmc_no == 2))
		new_mode = true;

	/*
	 * The MMC clock has an extra /2 post-divider when operating in the new
	 * mode.
	 */
	if (new_mode)
		hz = hz * 2;
112 113 114 115 116

	if (hz <= 24000000) {
		pll = CCM_MMC_CTRL_OSCM24;
		pll_hz = 24000000;
	} else {
117 118 119 120
#ifdef CONFIG_MACH_SUN9I
		pll = CCM_MMC_CTRL_PLL_PERIPH0;
		pll_hz = clock_get_pll4_periph0();
#else
121 122
		pll = CCM_MMC_CTRL_PLL6;
		pll_hz = clock_get_pll6();
123
#endif
124 125 126 127 128 129 130 131 132 133 134 135 136
	}

	div = pll_hz / hz;
	if (pll_hz % hz)
		div++;

	n = 0;
	while (div > 16) {
		n++;
		div = (div + 1) / 2;
	}

	if (n > 3) {
137 138
		printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
		       hz);
139 140 141 142 143 144
		return -1;
	}

	/* determine delays */
	if (hz <= 400000) {
		oclk_dly = 0;
145
		sclk_dly = 0;
146 147 148
	} else if (hz <= 25000000) {
		oclk_dly = 0;
		sclk_dly = 5;
149
#ifdef CONFIG_MACH_SUN9I
S
Stefan Mavrodiev 已提交
150
	} else if (hz <= 52000000) {
151 152
		oclk_dly = 5;
		sclk_dly = 4;
153
	} else {
S
Stefan Mavrodiev 已提交
154
		/* hz > 52000000 */
155 156
		oclk_dly = 2;
		sclk_dly = 4;
157
#else
S
Stefan Mavrodiev 已提交
158
	} else if (hz <= 52000000) {
159 160 161
		oclk_dly = 3;
		sclk_dly = 4;
	} else {
S
Stefan Mavrodiev 已提交
162
		/* hz > 52000000 */
163 164 165
		oclk_dly = 1;
		sclk_dly = 4;
#endif
166 167
	}

M
Maxime Ripard 已提交
168 169 170
	if (new_mode) {
#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
		val = CCM_MMC_CTRL_MODE_SEL_NEW;
171
		setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
M
Maxime Ripard 已提交
172 173 174 175 176 177 178 179
#endif
	} else {
		val = CCM_MMC_CTRL_OCLK_DLY(oclk_dly) |
			CCM_MMC_CTRL_SCLK_DLY(sclk_dly);
	}

	writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) |
	       CCM_MMC_CTRL_M(div) | val, priv->mclkreg);
180 181

	debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
182
	      priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
183 184 185 186

	return 0;
}

187
static int mmc_update_clk(struct sunxi_mmc_priv *priv)
I
Ian Campbell 已提交
188 189 190
{
	unsigned int cmd;
	unsigned timeout_msecs = 2000;
191
	unsigned long start = get_timer(0);
I
Ian Campbell 已提交
192 193 194 195

	cmd = SUNXI_MMC_CMD_START |
	      SUNXI_MMC_CMD_UPCLK_ONLY |
	      SUNXI_MMC_CMD_WAIT_PRE_OVER;
196

197 198
	writel(cmd, &priv->reg->cmd);
	while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) {
199
		if (get_timer(start) > timeout_msecs)
I
Ian Campbell 已提交
200 201 202 203
			return -1;
	}

	/* clock update sets various irq status bits, clear these */
204
	writel(readl(&priv->reg->rint), &priv->reg->rint);
I
Ian Campbell 已提交
205 206 207 208

	return 0;
}

209
static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
I
Ian Campbell 已提交
210
{
211
	unsigned rval = readl(&priv->reg->clkcr);
I
Ian Campbell 已提交
212 213 214

	/* Disable Clock */
	rval &= ~SUNXI_MMC_CLK_ENABLE;
215
	writel(rval, &priv->reg->clkcr);
216
	if (mmc_update_clk(priv))
I
Ian Campbell 已提交
217 218
		return -1;

219
	/* Set mod_clk to new rate */
220
	if (mmc_set_mod_clk(priv, mmc->clock))
221 222 223
		return -1;

	/* Clear internal divider */
I
Ian Campbell 已提交
224
	rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
225
	writel(rval, &priv->reg->clkcr);
226

I
Ian Campbell 已提交
227 228
	/* Re-enable Clock */
	rval |= SUNXI_MMC_CLK_ENABLE;
229
	writel(rval, &priv->reg->clkcr);
230
	if (mmc_update_clk(priv))
I
Ian Campbell 已提交
231 232 233 234 235
		return -1;

	return 0;
}

236 237
static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv,
				    struct mmc *mmc)
I
Ian Campbell 已提交
238
{
239 240
	debug("set ios: bus_width: %x, clock: %d\n",
	      mmc->bus_width, mmc->clock);
I
Ian Campbell 已提交
241 242

	/* Change clock first */
243
	if (mmc->clock && mmc_config_clock(priv, mmc) != 0) {
244
		priv->fatal_err = 1;
245
		return -EINVAL;
I
Ian Campbell 已提交
246 247 248 249
	}

	/* Change bus width */
	if (mmc->bus_width == 8)
250
		writel(0x2, &priv->reg->width);
I
Ian Campbell 已提交
251
	else if (mmc->bus_width == 4)
252
		writel(0x1, &priv->reg->width);
I
Ian Campbell 已提交
253
	else
254
		writel(0x0, &priv->reg->width);
255 256

	return 0;
I
Ian Campbell 已提交
257 258
}

259
#if !CONFIG_IS_ENABLED(DM_MMC)
260
static int sunxi_mmc_core_init(struct mmc *mmc)
I
Ian Campbell 已提交
261
{
262
	struct sunxi_mmc_priv *priv = mmc->priv;
I
Ian Campbell 已提交
263 264

	/* Reset controller */
265
	writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
H
Hans de Goede 已提交
266
	udelay(1000);
I
Ian Campbell 已提交
267 268 269

	return 0;
}
270
#endif
I
Ian Campbell 已提交
271

272 273
static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
				 struct mmc_data *data)
I
Ian Campbell 已提交
274 275 276 277 278 279
{
	const int reading = !!(data->flags & MMC_DATA_READ);
	const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
					      SUNXI_MMC_STATUS_FIFO_FULL;
	unsigned i;
	unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
280
	unsigned byte_cnt = data->blocksize * data->blocks;
281 282 283 284 285
	unsigned timeout_msecs = byte_cnt >> 8;
	unsigned long  start;

	if (timeout_msecs < 2000)
		timeout_msecs = 2000;
I
Ian Campbell 已提交
286

H
Hans de Goede 已提交
287
	/* Always read / write data through the CPU */
288
	setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
H
Hans de Goede 已提交
289

290 291
	start = get_timer(0);

I
Ian Campbell 已提交
292
	for (i = 0; i < (byte_cnt >> 2); i++) {
293
		while (readl(&priv->reg->status) & status_bit) {
294
			if (get_timer(start) > timeout_msecs)
I
Ian Campbell 已提交
295 296 297 298
				return -1;
		}

		if (reading)
299
			buff[i] = readl(&priv->reg->fifo);
I
Ian Campbell 已提交
300
		else
301
			writel(buff[i], &priv->reg->fifo);
I
Ian Campbell 已提交
302 303 304 305 306
	}

	return 0;
}

307 308
static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc,
			 uint timeout_msecs, uint done_bit, const char *what)
I
Ian Campbell 已提交
309 310
{
	unsigned int status;
311
	unsigned long start = get_timer(0);
I
Ian Campbell 已提交
312 313

	do {
314
		status = readl(&priv->reg->rint);
315
		if ((get_timer(start) > timeout_msecs) ||
I
Ian Campbell 已提交
316 317 318
		    (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
			debug("%s timeout %x\n", what,
			      status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
319
			return -ETIMEDOUT;
I
Ian Campbell 已提交
320 321 322 323 324 325
		}
	} while (!(status & done_bit));

	return 0;
}

326 327 328
static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
				     struct mmc *mmc, struct mmc_cmd *cmd,
				     struct mmc_data *data)
I
Ian Campbell 已提交
329 330 331 332 333 334 335
{
	unsigned int cmdval = SUNXI_MMC_CMD_START;
	unsigned int timeout_msecs;
	int error = 0;
	unsigned int status = 0;
	unsigned int bytecnt = 0;

336
	if (priv->fatal_err)
I
Ian Campbell 已提交
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
		return -1;
	if (cmd->resp_type & MMC_RSP_BUSY)
		debug("mmc cmd %d check rsp busy\n", cmd->cmdidx);
	if (cmd->cmdidx == 12)
		return 0;

	if (!cmd->cmdidx)
		cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ;
	if (cmd->resp_type & MMC_RSP_PRESENT)
		cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE;
	if (cmd->resp_type & MMC_RSP_136)
		cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE;
	if (cmd->resp_type & MMC_RSP_CRC)
		cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;

	if (data) {
353
		if ((u32)(long)data->dest & 0x3) {
I
Ian Campbell 已提交
354 355 356 357 358 359 360 361 362
			error = -1;
			goto out;
		}

		cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER;
		if (data->flags & MMC_DATA_WRITE)
			cmdval |= SUNXI_MMC_CMD_WRITE;
		if (data->blocks > 1)
			cmdval |= SUNXI_MMC_CMD_AUTO_STOP;
363 364
		writel(data->blocksize, &priv->reg->blksz);
		writel(data->blocks * data->blocksize, &priv->reg->bytecnt);
I
Ian Campbell 已提交
365 366
	}

367
	debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no,
I
Ian Campbell 已提交
368
	      cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
369
	writel(cmd->cmdarg, &priv->reg->arg);
I
Ian Campbell 已提交
370 371

	if (!data)
372
		writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
I
Ian Campbell 已提交
373 374 375 376 377 378 379 380 381 382 383

	/*
	 * transfer data and check status
	 * STATREG[2] : FIFO empty
	 * STATREG[3] : FIFO full
	 */
	if (data) {
		int ret = 0;

		bytecnt = data->blocksize * data->blocks;
		debug("trans data %d bytes\n", bytecnt);
384
		writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
385
		ret = mmc_trans_data_by_cpu(priv, mmc, data);
I
Ian Campbell 已提交
386
		if (ret) {
387
			error = readl(&priv->reg->rint) &
I
Ian Campbell 已提交
388
				SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
389
			error = -ETIMEDOUT;
I
Ian Campbell 已提交
390 391 392 393
			goto out;
		}
	}

394 395
	error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
			      "cmd");
I
Ian Campbell 已提交
396 397 398 399
	if (error)
		goto out;

	if (data) {
H
Hans de Goede 已提交
400
		timeout_msecs = 120;
I
Ian Campbell 已提交
401
		debug("cacl timeout %x msec\n", timeout_msecs);
402
		error = mmc_rint_wait(priv, mmc, timeout_msecs,
I
Ian Campbell 已提交
403 404 405 406 407 408 409 410 411
				      data->blocks > 1 ?
				      SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
				      SUNXI_MMC_RINT_DATA_OVER,
				      "data");
		if (error)
			goto out;
	}

	if (cmd->resp_type & MMC_RSP_BUSY) {
412
		unsigned long start = get_timer(0);
I
Ian Campbell 已提交
413
		timeout_msecs = 2000;
414

I
Ian Campbell 已提交
415
		do {
416
			status = readl(&priv->reg->status);
417
			if (get_timer(start) > timeout_msecs) {
I
Ian Campbell 已提交
418
				debug("busy timeout\n");
419
				error = -ETIMEDOUT;
I
Ian Campbell 已提交
420 421 422 423 424 425
				goto out;
			}
		} while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
	}

	if (cmd->resp_type & MMC_RSP_136) {
426 427 428 429
		cmd->response[0] = readl(&priv->reg->resp3);
		cmd->response[1] = readl(&priv->reg->resp2);
		cmd->response[2] = readl(&priv->reg->resp1);
		cmd->response[3] = readl(&priv->reg->resp0);
I
Ian Campbell 已提交
430 431 432 433
		debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
		      cmd->response[3], cmd->response[2],
		      cmd->response[1], cmd->response[0]);
	} else {
434
		cmd->response[0] = readl(&priv->reg->resp0);
I
Ian Campbell 已提交
435 436 437 438
		debug("mmc resp 0x%08x\n", cmd->response[0]);
	}
out:
	if (error < 0) {
439
		writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
440
		mmc_update_clk(priv);
I
Ian Campbell 已提交
441
	}
442 443 444
	writel(0xffffffff, &priv->reg->rint);
	writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
	       &priv->reg->gctrl);
I
Ian Campbell 已提交
445 446 447 448

	return error;
}

449
#if !CONFIG_IS_ENABLED(DM_MMC)
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
static int sunxi_mmc_set_ios_legacy(struct mmc *mmc)
{
	struct sunxi_mmc_priv *priv = mmc->priv;

	return sunxi_mmc_set_ios_common(priv, mmc);
}

static int sunxi_mmc_send_cmd_legacy(struct mmc *mmc, struct mmc_cmd *cmd,
				     struct mmc_data *data)
{
	struct sunxi_mmc_priv *priv = mmc->priv;

	return sunxi_mmc_send_cmd_common(priv, mmc, cmd, data);
}

static int sunxi_mmc_getcd_legacy(struct mmc *mmc)
466
{
467
	struct sunxi_mmc_priv *priv = mmc->priv;
468
	int cd_pin;
469

470
	cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
471
	if (cd_pin < 0)
472 473
		return 1;

474
	return !gpio_get_value(cd_pin);
475 476
}

I
Ian Campbell 已提交
477
static const struct mmc_ops sunxi_mmc_ops = {
478 479
	.send_cmd	= sunxi_mmc_send_cmd_legacy,
	.set_ios	= sunxi_mmc_set_ios_legacy,
480
	.init		= sunxi_mmc_core_init,
481
	.getcd		= sunxi_mmc_getcd_legacy,
I
Ian Campbell 已提交
482 483
};

484
struct mmc *sunxi_mmc_init(int sdc_no)
I
Ian Campbell 已提交
485
{
486
	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
487 488
	struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
	struct mmc_config *cfg = &priv->cfg;
489
	int ret;
I
Ian Campbell 已提交
490

491
	memset(priv, '\0', sizeof(struct sunxi_mmc_priv));
I
Ian Campbell 已提交
492 493 494 495 496 497

	cfg->name = "SUNXI SD/MMC";
	cfg->ops  = &sunxi_mmc_ops;

	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
	cfg->host_caps = MMC_MODE_4BIT;
498
#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I)
499 500 501
	if (sdc_no == 2)
		cfg->host_caps = MMC_MODE_8BIT;
#endif
R
Rob Herring 已提交
502
	cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
I
Ian Campbell 已提交
503 504 505 506 507
	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;

	cfg->f_min = 400000;
	cfg->f_max = 52000000;

508 509 510
	if (mmc_resource_init(sdc_no) != 0)
		return NULL;

511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
	/* config ahb clock */
	debug("init mmc %d clock and io\n", sdc_no);
	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));

#ifdef CONFIG_SUNXI_GEN_SUN6I
	/* unassert reset */
	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
#endif
#if defined(CONFIG_MACH_SUN9I)
	/* sun9i has a mmc-common module, also set the gate and reset there */
	writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
	       SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
#endif
	ret = mmc_set_mod_clk(priv, 24000000);
	if (ret)
		return NULL;
I
Ian Campbell 已提交
527

528
	return mmc_create(cfg, priv);
I
Ian Campbell 已提交
529
}
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
#else

static int sunxi_mmc_set_ios(struct udevice *dev)
{
	struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
	struct sunxi_mmc_priv *priv = dev_get_priv(dev);

	return sunxi_mmc_set_ios_common(priv, &plat->mmc);
}

static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
			      struct mmc_data *data)
{
	struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
	struct sunxi_mmc_priv *priv = dev_get_priv(dev);

	return sunxi_mmc_send_cmd_common(priv, &plat->mmc, cmd, data);
}

static int sunxi_mmc_getcd(struct udevice *dev)
{
	struct sunxi_mmc_priv *priv = dev_get_priv(dev);

553 554
	if (dm_gpio_is_valid(&priv->cd_gpio)) {
		int cd_state = dm_gpio_get_value(&priv->cd_gpio);
555

556 557
		return cd_state ^ priv->cd_inverted;
	}
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
	return 1;
}

static const struct dm_mmc_ops sunxi_mmc_ops = {
	.send_cmd	= sunxi_mmc_send_cmd,
	.set_ios	= sunxi_mmc_set_ios,
	.get_cd		= sunxi_mmc_getcd,
};

static int sunxi_mmc_probe(struct udevice *dev)
{
	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
	struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
	struct sunxi_mmc_priv *priv = dev_get_priv(dev);
	struct mmc_config *cfg = &plat->cfg;
	struct ofnode_phandle_args args;
	u32 *gate_reg;
	int bus_width, ret;

	cfg->name = dev->name;
	bus_width = dev_read_u32_default(dev, "bus-width", 1);

	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
	cfg->host_caps = 0;
	if (bus_width == 8)
		cfg->host_caps |= MMC_MODE_8BIT;
	if (bus_width >= 4)
		cfg->host_caps |= MMC_MODE_4BIT;
	cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;

	cfg->f_min = 400000;
	cfg->f_max = 52000000;

	priv->reg = (void *)dev_read_addr(dev);

	/* We don't have a sunxi clock driver so find the clock address here */
	ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
					  1, &args);
	if (ret)
		return ret;
	priv->mclkreg = (u32 *)ofnode_get_addr(args.node);

	ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
					  0, &args);
	if (ret)
		return ret;
	gate_reg = (u32 *)ofnode_get_addr(args.node);
	setbits_le32(gate_reg, 1 << args.args[0]);
	priv->mmc_no = args.args[0] - 8;

	ret = mmc_set_mod_clk(priv, 24000000);
	if (ret)
		return ret;

	/* This GPIO is optional */
	if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
				  GPIOD_IS_IN)) {
		int cd_pin = gpio_get_number(&priv->cd_gpio);

		sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
	}

621 622 623
	/* Check if card detect is inverted */
	priv->cd_inverted = dev_read_bool(dev, "cd-inverted");

624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
	upriv->mmc = &plat->mmc;

	/* Reset controller */
	writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
	udelay(1000);

	return 0;
}

static int sunxi_mmc_bind(struct udevice *dev)
{
	struct sunxi_mmc_plat *plat = dev_get_platdata(dev);

	return mmc_bind(dev, &plat->mmc, &plat->cfg);
}

static const struct udevice_id sunxi_mmc_ids[] = {
	{ .compatible = "allwinner,sun5i-a13-mmc" },
	{ }
};

U_BOOT_DRIVER(sunxi_mmc_drv) = {
	.name		= "sunxi_mmc",
	.id		= UCLASS_MMC,
	.of_match	= sunxi_mmc_ids,
	.bind		= sunxi_mmc_bind,
	.probe		= sunxi_mmc_probe,
	.ops		= &sunxi_mmc_ops,
	.platdata_auto_alloc_size = sizeof(struct sunxi_mmc_plat),
	.priv_auto_alloc_size = sizeof(struct sunxi_mmc_priv),
};
#endif