
25 Nov
2012
25 Nov
'12
7:09 p.m.
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@allwinnertech.com Signed-off-by: Henrik Nodstrom henrik@henriknordstrom.net Signed-off-by: Stefan Roese sr@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;
+}
[...]