mmc: kona: Add Kona mmc driver
authorDarwin Rambo <drambo@broadcom.com>
Tue, 11 Feb 2014 19:06:37 +0000 (11:06 -0800)
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>
Sat, 22 Feb 2014 18:30:41 +0000 (19:30 +0100)
Add support for the Kona SDHCI found on Broadcom mobile SoCs.

Signed-off-by: Darwin Rambo <drambo@broadcom.com>
Reviewed-by: Steve Rae <srae@broadcom.com>
Reviewed-by: Tim Kryger <tkryger@linaro.org>
drivers/mmc/Makefile
drivers/mmc/kona_sdhci.c [new file with mode: 0644]

index e793ed9..931922b 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
 obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
 obj-$(CONFIG_SDHCI) += sdhci.o
 obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
+obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o
 obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
 obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
diff --git a/drivers/mmc/kona_sdhci.c b/drivers/mmc/kona_sdhci.c
new file mode 100644 (file)
index 0000000..77e42c8
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/errno.h>
+#include <asm/kona-common/clk.h>
+
+#define SDHCI_CORECTRL_OFFSET          0x00008000
+#define SDHCI_CORECTRL_EN              0x01
+#define SDHCI_CORECTRL_RESET           0x02
+
+#define SDHCI_CORESTAT_OFFSET          0x00008004
+#define SDHCI_CORESTAT_CD_SW           0x01
+
+#define SDHCI_COREIMR_OFFSET           0x00008008
+#define SDHCI_COREIMR_IP               0x01
+
+static int init_kona_mmc_core(struct sdhci_host *host)
+{
+       unsigned int mask;
+       unsigned int timeout;
+
+       if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) {
+               printf("%s: sd host controller reset error\n", __func__);
+               return 1;
+       }
+
+       /* For kona a hardware reset before anything else. */
+       mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET;
+       sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
+
+       /* Wait max 100 ms */
+       timeout = 1000;
+       do {
+               if (timeout == 0) {
+                       printf("%s: reset timeout error\n", __func__);
+                       return 1;
+               }
+               timeout--;
+               udelay(100);
+       } while (0 ==
+                (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) &
+                 SDHCI_CORECTRL_RESET));
+
+       /* Clear the reset bit. */
+       mask = mask & ~SDHCI_CORECTRL_RESET;
+       sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
+
+       /* Enable AHB clock */
+       mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET);
+       sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET);
+
+       /* Enable interrupts */
+       sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET);
+
+       /* Make sure Card is detected in controller */
+       mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET);
+       sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET);
+
+       /* Wait max 100 ms */
+       timeout = 1000;
+       while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+               if (timeout == 0) {
+                       printf("%s: CARD DETECT timeout error\n", __func__);
+                       return 1;
+               }
+               timeout--;
+               udelay(100);
+       }
+       return 0;
+}
+
+int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks)
+{
+       int ret = 0;
+       u32 max_clk;
+       void *reg_base;
+       struct sdhci_host *host = NULL;
+
+       host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
+       if (!host) {
+               printf("%s: sdhci host malloc fail!\n", __func__);
+               return -ENOMEM;
+       }
+       switch (dev_index) {
+       case 0:
+               reg_base = (void *)CONFIG_SYS_SDIO_BASE0;
+               ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO0_MAX_CLK,
+                                     &max_clk);
+               break;
+       case 1:
+               reg_base = (void *)CONFIG_SYS_SDIO_BASE1;
+               ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO1_MAX_CLK,
+                                     &max_clk);
+               break;
+       case 2:
+               reg_base = (void *)CONFIG_SYS_SDIO_BASE2;
+               ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO2_MAX_CLK,
+                                     &max_clk);
+               break;
+       case 3:
+               reg_base = (void *)CONFIG_SYS_SDIO_BASE3;
+               ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO3_MAX_CLK,
+                                     &max_clk);
+               break;
+       default:
+               printf("%s: sdio dev index %d not supported\n",
+                      __func__, dev_index);
+               ret = -EINVAL;
+       }
+       if (ret)
+               return ret;
+
+       host->name = "kona-sdhci";
+       host->ioaddr = reg_base;
+       host->quirks = quirks;
+       host->host_caps = MMC_MODE_HC;
+
+       if (init_kona_mmc_core(host))
+               return -EINVAL;
+
+       if (quirks & SDHCI_QUIRK_REG32_RW)
+               host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
+       else
+               host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+       add_sdhci(host, max_clk, min_clk);
+       return ret;
+}