Message ID | 1391461382-24986-6-git-send-email-drambo@broadcom.com |
---|---|
State | New |
Headers | show |
On 14-02-03 05:12 PM, Jaehoon Chung wrote: > On 02/04/2014 06:03 AM, Darwin Rambo wrote: >> 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 | 1 + >> drivers/mmc/kona_sdhci.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 126 insertions(+) >> create mode 100644 drivers/mmc/kona_sdhci.c >> >> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile >> index e793ed9..931922b 100644 >> --- a/drivers/mmc/Makefile >> +++ b/drivers/mmc/Makefile >> @@ -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 >> index 0000000..69e6f17 >> --- /dev/null >> +++ b/drivers/mmc/kona_sdhci.c >> @@ -0,0 +1,125 @@ >> +/* >> + * Copyright 2013 Broadcom Corporation. All rights reserved. >> + * >> + * 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_mmc_core(struct sdhci_host *host) > > I think that function name is used to "_kona_". > This function isn't general mmc function, right? Correct. I should rename it to init_kona_mmc_core(). Thanks. > > Best Regards, > Jaehoon Chung > >> +{ >> + 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); >> + udelay(10); >> + >> + /* 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); BTW I think that this is a good spot to test and wait for CARD_PRESENT with timeout. I should add it here. This avoids timing issues if the core code tries to power up the card before it is recognized. Thanks. >> + >> + 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_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; >> +} >> >
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index e793ed9..931922b 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -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 index 0000000..69e6f17 --- /dev/null +++ b/drivers/mmc/kona_sdhci.c @@ -0,0 +1,125 @@ +/* + * Copyright 2013 Broadcom Corporation. All rights reserved. + * + * 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_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); + udelay(10); + + /* 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); + + 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_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; +}