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

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

22 23 24 25 26 27 28
#ifdef CONFIG_DM_MMC
struct sunxi_mmc_variant {
	u16 gate_offset;
	u16 mclk_offset;
};
#endif

29 30 31 32 33
struct sunxi_mmc_plat {
	struct mmc_config cfg;
	struct mmc mmc;
};

34
struct sunxi_mmc_priv {
I
Ian Campbell 已提交
35 36 37
	unsigned mmc_no;
	uint32_t *mclkreg;
	unsigned fatal_err;
38
	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
39
	int cd_inverted;		/* Inverted Card Detect */
I
Ian Campbell 已提交
40 41
	struct sunxi_mmc *reg;
	struct mmc_config cfg;
42 43 44
#ifdef CONFIG_DM_MMC
	const struct sunxi_mmc_variant *variant;
#endif
I
Ian Campbell 已提交
45 46
};

47
#if !CONFIG_IS_ENABLED(DM_MMC)
I
Ian Campbell 已提交
48
/* support 4 mmc hosts */
49
struct sunxi_mmc_priv mmc_host[4];
I
Ian Campbell 已提交
50

51 52 53 54 55 56 57 58
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);
	}
59
	return -EINVAL;
60 61
}

I
Ian Campbell 已提交
62 63
static int mmc_resource_init(int sdc_no)
{
64
	struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
I
Ian Campbell 已提交
65
	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
66
	int cd_pin, ret = 0;
I
Ian Campbell 已提交
67 68 69 70 71

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

	switch (sdc_no) {
	case 0:
72 73
		priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
		priv->mclkreg = &ccm->sd0_clk_cfg;
I
Ian Campbell 已提交
74 75
		break;
	case 1:
76 77
		priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
		priv->mclkreg = &ccm->sd1_clk_cfg;
I
Ian Campbell 已提交
78 79
		break;
	case 2:
80 81
		priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
		priv->mclkreg = &ccm->sd2_clk_cfg;
I
Ian Campbell 已提交
82
		break;
I
Icenowy Zheng 已提交
83
#ifdef SUNXI_MMC3_BASE
I
Ian Campbell 已提交
84
	case 3:
85 86
		priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
		priv->mclkreg = &ccm->sd3_clk_cfg;
I
Ian Campbell 已提交
87
		break;
I
Icenowy Zheng 已提交
88
#endif
I
Ian Campbell 已提交
89 90 91 92
	default:
		printf("Wrong mmc number %d\n", sdc_no);
		return -1;
	}
93
	priv->mmc_no = sdc_no;
I
Ian Campbell 已提交
94

95
	cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
96
	if (cd_pin >= 0) {
97
		ret = gpio_request(cd_pin, "mmc_cd");
98 99
		if (!ret) {
			sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
100
			ret = gpio_direction_input(cd_pin);
101
		}
102
	}
103 104

	return ret;
I
Ian Campbell 已提交
105
}
106
#endif
I
Ian Campbell 已提交
107

108
static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
109 110
{
	unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
111
	bool new_mode = true;
112
	bool calibrate = false;
M
Maxime Ripard 已提交
113 114
	u32 val = 0;

115 116 117 118 119 120
	if (!IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE))
		new_mode = false;

	/* A83T support new mode only on eMMC */
	if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2)
		new_mode = false;
M
Maxime Ripard 已提交
121

122 123 124 125
#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
	calibrate = true;
#endif

126 127 128 129
	if (hz <= 24000000) {
		pll = CCM_MMC_CTRL_OSCM24;
		pll_hz = 24000000;
	} else {
130 131 132
#ifdef CONFIG_MACH_SUN9I
		pll = CCM_MMC_CTRL_PLL_PERIPH0;
		pll_hz = clock_get_pll4_periph0();
I
Icenowy Zheng 已提交
133 134 135
#elif defined(CONFIG_MACH_SUN50I_H6)
		pll = CCM_MMC_CTRL_PLL6X2;
		pll_hz = clock_get_pll6() * 2;
136
#else
137 138
		pll = CCM_MMC_CTRL_PLL6;
		pll_hz = clock_get_pll6();
139
#endif
140 141 142 143 144 145 146 147 148 149 150 151 152
	}

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

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

	if (n > 3) {
153 154
		printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
		       hz);
155 156 157 158 159 160
		return -1;
	}

	/* determine delays */
	if (hz <= 400000) {
		oclk_dly = 0;
161
		sclk_dly = 0;
162 163 164
	} else if (hz <= 25000000) {
		oclk_dly = 0;
		sclk_dly = 5;
165
#ifdef CONFIG_MACH_SUN9I
S
Stefan Mavrodiev 已提交
166
	} else if (hz <= 52000000) {
167 168
		oclk_dly = 5;
		sclk_dly = 4;
169
	} else {
S
Stefan Mavrodiev 已提交
170
		/* hz > 52000000 */
171 172
		oclk_dly = 2;
		sclk_dly = 4;
173
#else
S
Stefan Mavrodiev 已提交
174
	} else if (hz <= 52000000) {
175 176 177
		oclk_dly = 3;
		sclk_dly = 4;
	} else {
S
Stefan Mavrodiev 已提交
178
		/* hz > 52000000 */
179 180 181
		oclk_dly = 1;
		sclk_dly = 4;
#endif
182 183
	}

M
Maxime Ripard 已提交
184 185
	if (new_mode) {
#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
186
#ifdef CONFIG_MMC_SUNXI_HAS_MODE_SWITCH
M
Maxime Ripard 已提交
187
		val = CCM_MMC_CTRL_MODE_SEL_NEW;
188
#endif
189
		setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
M
Maxime Ripard 已提交
190
#endif
191 192 193 194 195
	} else if (!calibrate) {
		/*
		 * Use hardcoded delay values if controller doesn't support
		 * calibration
		 */
M
Maxime Ripard 已提交
196 197 198 199 200 201
		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);
202 203

	debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
204
	      priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
205 206 207 208

	return 0;
}

209
static int mmc_update_clk(struct sunxi_mmc_priv *priv)
I
Ian Campbell 已提交
210 211 212
{
	unsigned int cmd;
	unsigned timeout_msecs = 2000;
213
	unsigned long start = get_timer(0);
I
Ian Campbell 已提交
214 215 216 217

	cmd = SUNXI_MMC_CMD_START |
	      SUNXI_MMC_CMD_UPCLK_ONLY |
	      SUNXI_MMC_CMD_WAIT_PRE_OVER;
218

219 220
	writel(cmd, &priv->reg->cmd);
	while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) {
221
		if (get_timer(start) > timeout_msecs)
I
Ian Campbell 已提交
222 223 224 225
			return -1;
	}

	/* clock update sets various irq status bits, clear these */
226
	writel(readl(&priv->reg->rint), &priv->reg->rint);
I
Ian Campbell 已提交
227 228 229 230

	return 0;
}

231
static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
I
Ian Campbell 已提交
232
{
233
	unsigned rval = readl(&priv->reg->clkcr);
I
Ian Campbell 已提交
234 235 236

	/* Disable Clock */
	rval &= ~SUNXI_MMC_CLK_ENABLE;
237
	writel(rval, &priv->reg->clkcr);
238
	if (mmc_update_clk(priv))
I
Ian Campbell 已提交
239 240
		return -1;

241
	/* Set mod_clk to new rate */
242
	if (mmc_set_mod_clk(priv, mmc->clock))
243 244 245
		return -1;

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

249 250 251 252 253 254 255 256 257 258
#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
	/* A64 supports calibration of delays on MMC controller and we
	 * have to set delay of zero before starting calibration.
	 * Allwinner BSP driver sets a delay only in the case of
	 * using HS400 which is not supported by mainline U-Boot or
	 * Linux at the moment
	 */
	writel(SUNXI_MMC_CAL_DL_SW_EN, &priv->reg->samp_dl);
#endif

I
Ian Campbell 已提交
259 260
	/* Re-enable Clock */
	rval |= SUNXI_MMC_CLK_ENABLE;
261
	writel(rval, &priv->reg->clkcr);
262
	if (mmc_update_clk(priv))
I
Ian Campbell 已提交
263 264 265 266 267
		return -1;

	return 0;
}

268 269
static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv,
				    struct mmc *mmc)
I
Ian Campbell 已提交
270
{
271 272
	debug("set ios: bus_width: %x, clock: %d\n",
	      mmc->bus_width, mmc->clock);
I
Ian Campbell 已提交
273 274

	/* Change clock first */
275
	if (mmc->clock && mmc_config_clock(priv, mmc) != 0) {
276
		priv->fatal_err = 1;
277
		return -EINVAL;
I
Ian Campbell 已提交
278 279 280 281
	}

	/* Change bus width */
	if (mmc->bus_width == 8)
282
		writel(0x2, &priv->reg->width);
I
Ian Campbell 已提交
283
	else if (mmc->bus_width == 4)
284
		writel(0x1, &priv->reg->width);
I
Ian Campbell 已提交
285
	else
286
		writel(0x0, &priv->reg->width);
287 288

	return 0;
I
Ian Campbell 已提交
289 290
}

291
#if !CONFIG_IS_ENABLED(DM_MMC)
292
static int sunxi_mmc_core_init(struct mmc *mmc)
I
Ian Campbell 已提交
293
{
294
	struct sunxi_mmc_priv *priv = mmc->priv;
I
Ian Campbell 已提交
295 296

	/* Reset controller */
297
	writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
H
Hans de Goede 已提交
298
	udelay(1000);
I
Ian Campbell 已提交
299 300 301

	return 0;
}
302
#endif
I
Ian Campbell 已提交
303

304 305
static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
				 struct mmc_data *data)
I
Ian Campbell 已提交
306 307 308 309 310 311
{
	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);
312
	unsigned byte_cnt = data->blocksize * data->blocks;
313 314 315 316 317
	unsigned timeout_msecs = byte_cnt >> 8;
	unsigned long  start;

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

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

322 323
	start = get_timer(0);

I
Ian Campbell 已提交
324
	for (i = 0; i < (byte_cnt >> 2); i++) {
325
		while (readl(&priv->reg->status) & status_bit) {
326
			if (get_timer(start) > timeout_msecs)
I
Ian Campbell 已提交
327 328 329 330
				return -1;
		}

		if (reading)
331
			buff[i] = readl(&priv->reg->fifo);
I
Ian Campbell 已提交
332
		else
333
			writel(buff[i], &priv->reg->fifo);
I
Ian Campbell 已提交
334 335 336 337 338
	}

	return 0;
}

339 340
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 已提交
341 342
{
	unsigned int status;
343
	unsigned long start = get_timer(0);
I
Ian Campbell 已提交
344 345

	do {
346
		status = readl(&priv->reg->rint);
347
		if ((get_timer(start) > timeout_msecs) ||
I
Ian Campbell 已提交
348 349 350
		    (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
			debug("%s timeout %x\n", what,
			      status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
351
			return -ETIMEDOUT;
I
Ian Campbell 已提交
352 353 354 355 356 357
		}
	} while (!(status & done_bit));

	return 0;
}

358 359 360
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 已提交
361 362 363 364 365 366 367
{
	unsigned int cmdval = SUNXI_MMC_CMD_START;
	unsigned int timeout_msecs;
	int error = 0;
	unsigned int status = 0;
	unsigned int bytecnt = 0;

368
	if (priv->fatal_err)
I
Ian Campbell 已提交
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
		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) {
385
		if ((u32)(long)data->dest & 0x3) {
I
Ian Campbell 已提交
386 387 388 389 390 391 392 393 394
			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;
395 396
		writel(data->blocksize, &priv->reg->blksz);
		writel(data->blocks * data->blocksize, &priv->reg->bytecnt);
I
Ian Campbell 已提交
397 398
	}

399
	debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no,
I
Ian Campbell 已提交
400
	      cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
401
	writel(cmd->cmdarg, &priv->reg->arg);
I
Ian Campbell 已提交
402 403

	if (!data)
404
		writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
I
Ian Campbell 已提交
405 406 407 408 409 410 411 412 413 414 415

	/*
	 * 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);
416
		writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
417
		ret = mmc_trans_data_by_cpu(priv, mmc, data);
I
Ian Campbell 已提交
418
		if (ret) {
419
			error = readl(&priv->reg->rint) &
I
Ian Campbell 已提交
420
				SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
421
			error = -ETIMEDOUT;
I
Ian Campbell 已提交
422 423 424 425
			goto out;
		}
	}

426 427
	error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
			      "cmd");
I
Ian Campbell 已提交
428 429 430 431
	if (error)
		goto out;

	if (data) {
H
Hans de Goede 已提交
432
		timeout_msecs = 120;
I
Ian Campbell 已提交
433
		debug("cacl timeout %x msec\n", timeout_msecs);
434
		error = mmc_rint_wait(priv, mmc, timeout_msecs,
I
Ian Campbell 已提交
435 436 437 438 439 440 441 442 443
				      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) {
444
		unsigned long start = get_timer(0);
I
Ian Campbell 已提交
445
		timeout_msecs = 2000;
446

I
Ian Campbell 已提交
447
		do {
448
			status = readl(&priv->reg->status);
449
			if (get_timer(start) > timeout_msecs) {
I
Ian Campbell 已提交
450
				debug("busy timeout\n");
451
				error = -ETIMEDOUT;
I
Ian Campbell 已提交
452 453 454 455 456 457
				goto out;
			}
		} while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
	}

	if (cmd->resp_type & MMC_RSP_136) {
458 459 460 461
		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 已提交
462 463 464 465
		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 {
466
		cmd->response[0] = readl(&priv->reg->resp0);
I
Ian Campbell 已提交
467 468 469 470
		debug("mmc resp 0x%08x\n", cmd->response[0]);
	}
out:
	if (error < 0) {
471
		writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
472
		mmc_update_clk(priv);
I
Ian Campbell 已提交
473
	}
474 475 476
	writel(0xffffffff, &priv->reg->rint);
	writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
	       &priv->reg->gctrl);
I
Ian Campbell 已提交
477 478 479 480

	return error;
}

481
#if !CONFIG_IS_ENABLED(DM_MMC)
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
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)
498
{
499
	struct sunxi_mmc_priv *priv = mmc->priv;
500
	int cd_pin;
501

502
	cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
503
	if (cd_pin < 0)
504 505
		return 1;

506
	return !gpio_get_value(cd_pin);
507 508
}

I
Ian Campbell 已提交
509
static const struct mmc_ops sunxi_mmc_ops = {
510 511
	.send_cmd	= sunxi_mmc_send_cmd_legacy,
	.set_ios	= sunxi_mmc_set_ios_legacy,
512
	.init		= sunxi_mmc_core_init,
513
	.getcd		= sunxi_mmc_getcd_legacy,
I
Ian Campbell 已提交
514 515
};

516
struct mmc *sunxi_mmc_init(int sdc_no)
I
Ian Campbell 已提交
517
{
518
	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
519 520
	struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
	struct mmc_config *cfg = &priv->cfg;
521
	int ret;
I
Ian Campbell 已提交
522

523
	memset(priv, '\0', sizeof(struct sunxi_mmc_priv));
I
Ian Campbell 已提交
524 525 526 527 528 529

	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;
I
Icenowy Zheng 已提交
530
#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I_H6)
531 532 533
	if (sdc_no == 2)
		cfg->host_caps = MMC_MODE_8BIT;
#endif
R
Rob Herring 已提交
534
	cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
I
Ian Campbell 已提交
535 536 537 538 539
	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;

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

540 541 542
	if (mmc_resource_init(sdc_no) != 0)
		return NULL;

543 544
	/* config ahb clock */
	debug("init mmc %d clock and io\n", sdc_no);
I
Icenowy Zheng 已提交
545
#if !defined(CONFIG_MACH_SUN50I_H6)
546 547 548 549 550 551 552 553 554 555
	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);
I
Icenowy Zheng 已提交
556 557 558 559 560
#endif
#else /* CONFIG_MACH_SUN50I_H6 */
	setbits_le32(&ccm->sd_gate_reset, 1 << sdc_no);
	/* unassert reset */
	setbits_le32(&ccm->sd_gate_reset, 1 << (RESET_SHIFT + sdc_no));
561 562 563 564
#endif
	ret = mmc_set_mod_clk(priv, 24000000);
	if (ret)
		return NULL;
I
Ian Campbell 已提交
565

566
	return mmc_create(cfg, priv);
I
Ian Campbell 已提交
567
}
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
#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);

591 592
	if (dm_gpio_is_valid(&priv->cd_gpio)) {
		int cd_state = dm_gpio_get_value(&priv->cd_gpio);
593

594 595
		return cd_state ^ priv->cd_inverted;
	}
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
	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;
612
	u32 *gate_reg, *ccu_reg;
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
	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);
631 632
	priv->variant =
		(const struct sunxi_mmc_variant *)dev_get_driver_data(dev);
633 634 635 636 637 638

	/* 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;
639
	ccu_reg = (u32 *)ofnode_get_addr(args.node);
640

641 642 643 644 645
	priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000;
	priv->mclkreg = (void *)ccu_reg +
			(priv->variant->mclk_offset + (priv->mmc_no * 4));
	gate_reg = (void *)ccu_reg + priv->variant->gate_offset;
	setbits_le32(gate_reg, BIT(AHB_GATE_OFFSET_MMC(priv->mmc_no)));
646 647 648 649 650 651 652 653 654 655 656 657 658

	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);
	}

659 660 661
	/* Check if card detect is inverted */
	priv->cd_inverted = dev_read_bool(dev, "cd-inverted");

662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
	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);
}

678 679 680 681 682
static const struct sunxi_mmc_variant sun4i_a10_variant = {
	.gate_offset = 0x60,
	.mclk_offset = 0x88,
};

683
static const struct udevice_id sunxi_mmc_ids[] = {
684 685 686 687 688 689 690 691 692 693 694 695 696
	{
	  .compatible = "allwinner,sun4i-a10-mmc",
	  .data = (ulong)&sun4i_a10_variant,
	},
	{
	  .compatible = "allwinner,sun5i-a13-mmc",
	  .data = (ulong)&sun4i_a10_variant,
	},
	{
	  .compatible = "allwinner,sun7i-a20-mmc",
	  .data = (ulong)&sun4i_a10_variant,
	},
	{ /* sentinel */ }
697 698 699 700 701 702 703 704 705 706 707 708 709
};

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