sunxi_mmc.c 17.9 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>
13
#include <log.h>
I
Ian Campbell 已提交
14 15
#include <malloc.h>
#include <mmc.h>
16 17
#include <clk.h>
#include <reset.h>
I
Ian Campbell 已提交
18 19 20
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/cpu.h>
21
#include <asm/arch/gpio.h>
I
Ian Campbell 已提交
22
#include <asm/arch/mmc.h>
23
#include <asm-generic/gpio.h>
I
Ian Campbell 已提交
24

25 26 27 28 29 30
#ifdef CONFIG_DM_MMC
struct sunxi_mmc_variant {
	u16 mclk_offset;
};
#endif

31 32 33 34 35
struct sunxi_mmc_plat {
	struct mmc_config cfg;
	struct mmc mmc;
};

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

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

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

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

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

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

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

	return ret;
I
Ian Campbell 已提交
107
}
108
#endif
I
Ian Campbell 已提交
109

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

117 118 119 120 121 122
	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 已提交
123

124 125 126 127
#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
	calibrate = true;
#endif

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

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

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

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

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

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

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

	return 0;
}

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

	cmd = SUNXI_MMC_CMD_START |
	      SUNXI_MMC_CMD_UPCLK_ONLY |
	      SUNXI_MMC_CMD_WAIT_PRE_OVER;
220

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

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

	return 0;
}

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

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

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

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

251 252 253 254 255 256 257 258 259 260
#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 已提交
261 262
	/* Re-enable Clock */
	rval |= SUNXI_MMC_CLK_ENABLE;
263
	writel(rval, &priv->reg->clkcr);
264
	if (mmc_update_clk(priv))
I
Ian Campbell 已提交
265 266 267 268 269
		return -1;

	return 0;
}

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

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

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

	return 0;
I
Ian Campbell 已提交
291 292
}

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

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

	return 0;
}
304
#endif
I
Ian Campbell 已提交
305

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

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

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

324 325
	start = get_timer(0);

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

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

	return 0;
}

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

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

	return 0;
}

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

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

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

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

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

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

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

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

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

	return error;
}

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

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

508
	return !gpio_get_value(cd_pin);
509 510
}

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

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

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

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

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

542 543 544
	if (mmc_resource_init(sdc_no) != 0)
		return NULL;

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

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

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

596 597
		return cd_state ^ priv->cd_inverted;
	}
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);
612 613
	struct reset_ctl_bulk reset_bulk;
	struct clk gate_clk;
614 615
	struct mmc_config *cfg = &plat->cfg;
	struct ofnode_phandle_args args;
616
	u32 *ccu_reg;
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
	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);
635 636
	priv->variant =
		(const struct sunxi_mmc_variant *)dev_get_driver_data(dev);
637 638 639 640 641 642

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

645 646 647
	priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000;
	priv->mclkreg = (void *)ccu_reg +
			(priv->variant->mclk_offset + (priv->mmc_no * 4));
648 649 650 651 652 653 654 655

	ret = clk_get_by_name(dev, "ahb", &gate_clk);
	if (!ret)
		clk_enable(&gate_clk);

	ret = reset_get_bulk(dev, &reset_bulk);
	if (!ret)
		reset_deassert_bulk(&reset_bulk);
656 657 658 659 660 661

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

	/* This GPIO is optional */
662 663
	if (!dev_read_bool(dev, "non-removable") &&
	    !gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
664 665 666 667 668 669
				  GPIOD_IS_IN)) {
		int cd_pin = gpio_get_number(&priv->cd_gpio);

		sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
	}

670 671 672
	/* Check if card detect is inverted */
	priv->cd_inverted = dev_read_bool(dev, "cd-inverted");

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
	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);
}

689 690 691 692
static const struct sunxi_mmc_variant sun4i_a10_variant = {
	.mclk_offset = 0x88,
};

693 694 695 696
static const struct sunxi_mmc_variant sun9i_a80_variant = {
	.mclk_offset = 0x410,
};

697 698 699 700
static const struct sunxi_mmc_variant sun50i_h6_variant = {
	.mclk_offset = 0x830,
};

701
static const struct udevice_id sunxi_mmc_ids[] = {
702 703 704 705 706 707 708 709 710 711 712 713
	{
	  .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,
	},
714 715 716 717
	{
	  .compatible = "allwinner,sun8i-a83t-emmc",
	  .data = (ulong)&sun4i_a10_variant,
	},
718 719 720 721
	{
	  .compatible = "allwinner,sun9i-a80-mmc",
	  .data = (ulong)&sun9i_a80_variant,
	},
722 723 724 725 726 727 728 729
	{
	  .compatible = "allwinner,sun50i-a64-mmc",
	  .data = (ulong)&sun4i_a10_variant,
	},
	{
	  .compatible = "allwinner,sun50i-a64-emmc",
	  .data = (ulong)&sun4i_a10_variant,
	},
730 731 732 733 734 735 736 737
	{
	  .compatible = "allwinner,sun50i-h6-mmc",
	  .data = (ulong)&sun50i_h6_variant,
	},
	{
	  .compatible = "allwinner,sun50i-h6-emmc",
	  .data = (ulong)&sun50i_h6_variant,
	},
738
	{ /* sentinel */ }
739 740 741 742 743 744 745 746 747 748 749 750 751
};

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