[U-Boot] [PATCH 02/22] ARM: sunxi: MMC driver

Marek Vasut marex at denx.de
Sun Nov 25 19:09:02 CET 2012


Dear Henrik Nordström,

> This adds a basic MMC driver for Allwinner sun4i/sun5i family of SoC
> this driver is limited to a single MMC channel.
> 
> Signed-off-by: Tom Cubie <tangliang at allwinnertech.com>
> Signed-off-by: Henrik Nodstrom <henrik at henriknordstrom.net>
> Signed-off-by: Stefan Roese <sr at denx.de>
> ---
[...]

> +#undef SUNXI_MMCDBG

debug_cond() won't work for you ?
[...]

> +	case 0:
> +		/* D1-PF0, D0-PF1, CLK-PF2, CMD-PF3, D3-PF4, D4-PF5 */

Magic goo below?

> +		writel(0x222222, &gpio_f->cfg[0]);
> +		writel(0x555, &gpio_f->pull[0]);
> +		writel(0xaaa, &gpio_f->drv[0]);
> +		break;
> +
> +	case 1:
> +#if CONFIG_MMC1_PG
> +		/* PG0-CMD, PG1-CLK, PG2~5-D0~3 : 4 */
> +		writel(0x444444, &gpio_g->cfg[0]);
> +		writel(0x555, &gpio_g->pull[0]);
> +		writel(0xaaa, &gpio_g->drv[0]);
> +#else
> +		/* PH22-CMD, PH23-CLK, PH24~27-D0~D3 : 5 */
> +		writel(0x55 << 24, &gpio_h->cfg[2]);
> +		writel(0x5555, &gpio_h->cfg[3]);
> +		writel(0x555 << 12, &gpio_h->pull[1]);
> +		writel(0xaaa << 12, &gpio_h->drv[1]);
> +#endif
> +		break;
> +
> +	case 2:
> +		/* CMD-PC6, CLK-PC7, D0-PC8, D1-PC9, D2-PC10, D3-PC11 */
> +		writel(0x33 << 24, &gpio_c->cfg[0]);
> +		writel(0x3333, &gpio_c->cfg[1]);
> +		writel(0x555 << 12, &gpio_c->pull[0]);
> +		writel(0xaaa << 12, &gpio_c->drv[0]);
> +		break;
> +
> +	case 3:
> +		/* PI4-CMD, PI5-CLK, PI6~9-D0~D3 : 2 */
> +		writel(0x2222 << 16, &gpio_i->cfg[0]);
> +		writel(0x22, &gpio_i->cfg[1]);
> +		writel(0x555 << 8, &gpio_i->pull[0]);
> +		writel(0x555 << 8, &gpio_i->drv[0]);
> +		break;
> +
> +	default:
> +		return -1;
> +	}
> +
> +	/* config ahb clock */
> +	rval = readl(&ccm->ahb_gate0);
> +	rval |= (1 << (8 + sdc_no));
> +	writel(rval, &ccm->ahb_gate0);
> +
> +	/* config mod clock */
> +	pll5_clk = clock_get_pll5();
> +	if (pll5_clk > 400000000)
> +		divider = 4;
> +	else
> +		divider = 3;
> +	writel((1U << 31) | (2U << 24) | divider, mmchost->mclkreg);
> +	mmchost->mod_clk = pll5_clk / (divider + 1);
> +
> +	dumphex32("ccmu", (char *)SUNXI_CCM_BASE, 0x100);
> +	dumphex32("gpio", (char *)SUNXI_PIO_BASE, 0x100);
> +	dumphex32("mmc", (char *)mmchost->reg, 0x100);
> +
> +	return 0;
> +}
> +
> +static int mmc_update_clk(struct mmc *mmc)
> +{
> +	struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)mmc->priv;
> +	unsigned int cmd;
> +	unsigned timeout = 0xfffff;
> +
> +	cmd = (1U << 31) | (1 << 21) | (1 << 13);
> +	writel(cmd, &mmchost->reg->cmd);
> +	while ((readl(&mmchost->reg->cmd) & 0x80000000) && timeout--)
> +		;
> +	if (!timeout)
> +		return -1;
> +
> +	writel(readl(&mmchost->reg->rint), &mmchost->reg->rint);
> +
> +	return 0;
> +}
> +
> +static int mmc_config_clock(struct mmc *mmc, unsigned div)
> +{
> +	struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)mmc->priv;
> +	unsigned rval = readl(&mmchost->reg->clkcr);
> +
> +	/*
> +	 * CLKCREG[7:0]: divider
> +	 * CLKCREG[16]:  on/off
> +	 * CLKCREG[17]:  power save
> +	 */
> +	/* Disable Clock */
> +	rval &= ~(1 << 16);
> +	writel(rval, &mmchost->reg->clkcr);
> +	if (mmc_update_clk(mmc))
> +		return -1;
> +
> +	/* Change Divider Factor */
> +	rval &= ~(0xFF);
> +	rval |= div;
> +	writel(rval, &mmchost->reg->clkcr);
> +	if (mmc_update_clk(mmc))
> +		return -1;
> +	/* Re-enable Clock */
> +	rval |= (1 << 16);
> +	writel(rval, &mmchost->reg->clkcr);
> +
> +	if (mmc_update_clk(mmc))
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static void mmc_set_ios(struct mmc *mmc)
> +{
> +	struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)mmc->priv;
> +	unsigned int clkdiv = 0;
> +
> +	MMCDBG("set ios: bus_width: %x, clock: %d, mod_clk\n", mmc->bus_width,
> +	       mmc->clock, mmchost->mod_clk);
> +
> +	/* Change clock first */
> +	clkdiv = (mmchost->mod_clk + (mmc->clock >> 1)) / mmc->clock / 2;
> +	if (mmc->clock)
> +		if (mmc_config_clock(mmc, clkdiv)) {
> +			mmchost->fatal_err = 1;
> +			return;
> +		}
> +
> +	/* Change bus width */
> +	if (mmc->bus_width == 8)
> +		writel(2, &mmchost->reg->width);
> +	else if (mmc->bus_width == 4)
> +		writel(1, &mmchost->reg->width);
> +	else
> +		writel(0, &mmchost->reg->width);
> +}
> +
> +static int mmc_core_init(struct mmc *mmc)
> +{
> +	struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)mmc->priv;
> +
> +	/* Reset controller */
> +	writel(0x7, &mmchost->reg->gctrl);
> +
> +	return 0;
> +}
> +
> +static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data)
> +{
> +	struct sunxi_mmc_host *mmchost = (struct sunxi_mmc_host *)mmc->priv;
> +	unsigned i;
> +	unsigned byte_cnt = data->blocksize * data->blocks;
> +	unsigned *buff;
> +	unsigned timeout = 0xfffff;
> +
> +	if (data->flags & MMC_DATA_READ) {
> +		buff = (unsigned int *)data->dest;
> +		for (i = 0; i < (byte_cnt >> 2); i++) {
> +			while (--timeout
> +			       && (readl(&mmchost->reg->status) & (1 << 2)))

More magic.

> +				;
> +			if (timeout <= 0)
> +				goto out;
> +			buff[i] = readl(mmchost->database);
> +			timeout = 0xfffff;
> +		}
> +	} else {
> +		buff = (unsigned int *)data->src;
> +		for (i = 0; i < (byte_cnt >> 2); i++) {
> +			while (--timeout
> +			       && (readl(&mmchost->reg->status) & (1 << 3)))
> +				;
> +			if (timeout <= 0)
> +				goto out;
> +			writel(buff[i], mmchost->database);
> +			timeout = 0xfffff;
> +		}
> +	}
> +
> +out:
> +	if (timeout <= 0)
> +		return -1;
> +
> +	return 0;
> +}
> +
[...]


More information about the U-Boot mailing list