[U-Boot] [PATCH 4/9] drivers:mmc:sdhci: enable support for DT
Piotr Wilczek
p.wilczek at samsung.com
Tue Jan 28 13:31:54 CET 2014
Hi Jaehoon,
> Hi, Piotr.
>
> On 01/27/2014 11:15 PM, Piotr Wilczek wrote:
> > This patch enables support for device tree for sdhci driver.
> > Non DT case is still supported.
> >
> > Signed-off-by: Piotr Wilczek <p.wilczek at samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
> > Cc: Minkyu Kang <mk7.kang at samsung.com>
> > ---
> > arch/arm/include/asm/arch-exynos/mmc.h | 7 ++
> > drivers/mmc/s5p_sdhci.c | 130
> +++++++++++++++++++++++++++++++-
> > include/fdtdec.h | 1 +
> > include/sdhci.h | 5 ++
> > lib/fdtdec.c | 1 +
> > 5 files changed, 143 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm/include/asm/arch-exynos/mmc.h
> > b/arch/arm/include/asm/arch-exynos/mmc.h
> > index 98d6530..0fb6461 100644
> > --- a/arch/arm/include/asm/arch-exynos/mmc.h
> > +++ b/arch/arm/include/asm/arch-exynos/mmc.h
> > @@ -53,6 +53,8 @@
> > #define SDHCI_CTRL4_DRIVE_MASK(_x) ((_x) << 16)
> > #define SDHCI_CTRL4_DRIVE_SHIFT (16)
> >
> > +#define SDHCI_MAX_HOSTS 4
> > +
> > int s5p_sdhci_init(u32 regbase, int index, int bus_width);
> >
> > static inline int s5p_mmc_init(int index, int bus_width) @@ -62,4
> > +64,9 @@ static inline int s5p_mmc_init(int index, int bus_width)
> >
> > return s5p_sdhci_init(base, index, bus_width); }
> > +
> > +#ifdef CONFIG_OF_CONTROL
> > +int exynos_mmc_init(const void *blob); #endif
> > +
> > #endif
> > diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index
> > 40ff873..7456ee0 100644
> > --- a/drivers/mmc/s5p_sdhci.c
> > +++ b/drivers/mmc/s5p_sdhci.c
> > @@ -8,9 +8,15 @@
> > #include <common.h>
> > #include <malloc.h>
> > #include <sdhci.h>
> > +#include <fdtdec.h>
> > +#include <libfdt.h>
> > +#include <asm/gpio.h>
> > #include <asm/arch/mmc.h>
> > #include <asm/arch/clk.h>
> > -
> > +#include <errno.h>
> > +#ifdef CONFIG_OF_CONTROL
> > +#include <asm/arch/pinmux.h>
> > +#endif
> > static char *S5P_NAME = "SAMSUNG SDHCI"; static void
> > s5p_sdhci_set_control_reg(struct sdhci_host *host) { @@ -86,3
> +92,125
> > @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)
> >
> > return add_sdhci(host, 52000000, 400000); }
> > +
> > +#ifdef CONFIG_OF_CONTROL
> > +struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS];
> > +
> > +static int do_sdhci_init(struct sdhci_host *host) {
> > + int dev_id, flag;
> > + int err = 0;
> > +
> > + flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE :
> PINMUX_FLAG_NONE;
> > + dev_id = host->index + PERIPH_ID_SDMMC0;
> > +
> > + if (fdt_gpio_isvalid(&host->pwr_gpio)) {
> > + gpio_direction_output(host->pwr_gpio.gpio, 1);
>
> what's pwr_gpio? Is it used for the both(eMMC and SD card)?
pwr_gpio is used only for eMMC.
cd_gpio is used for SD Card.
>
> > + err = exynos_pinmux_config(dev_id, flag);
> > + if (err) {
> > + debug("MMC not configured\n");
> > + return err;
> > + }
> > + }
> > +
> > + if (fdt_gpio_isvalid(&host->cd_gpio)) {
> > + gpio_direction_output(host->cd_gpio.gpio, 0xf);
> > + if (gpio_get_value(host->cd_gpio.gpio))
> > + return -ENODEV;
> > +
> > + err = exynos_pinmux_config(dev_id, flag);
> > + if (err) {
> > + printf("external SD not configured\n");
> > + return err;
> > + }
> > + }
> > +
> > + host->name = S5P_NAME;
> > +
> > + host->quirks = SDHCI_QUIRK_NO_HISPD_BIT |
> SDHCI_QUIRK_BROKEN_VOLTAGE |
> > + SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR |
> > + SDHCI_QUIRK_WAIT_SEND_CMD;
> > + host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
> > + host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
> > +
> > + host->set_control_reg = &s5p_sdhci_set_control_reg;
> > + host->set_clock = set_mmc_clk;
> > +
> > + host->host_caps = MMC_MODE_HC;
> > +
> > + return add_sdhci(host, 52000000, 400000); }
> > +
> > +static int sdhci_get_config(const void *blob, int node, struct
> > +sdhci_host *host) {
> > + int bus_width, dev_id;
> > + unsigned int base;
> > +
> > + /* Get device id */
> > + dev_id = pinmux_decode_periph_id(blob, node);
> > + if (dev_id < PERIPH_ID_SDMMC0) {
>
> Didn't need to check other boundary?
Yes, I should check for the PERIPH_ID_SDMMC3
>
> > + debug("MMC: Can't get device id\n");
> > + return -1;
> > + }
> > + host->index = dev_id - PERIPH_ID_SDMMC0;
> > +
> > + /* Get bus width */
> > + bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
> > + if (bus_width <= 0) {
> > + debug("MMC: Can't get bus-width\n");
> > + return -1;
> > + }
> > + host->bus_width = bus_width;
> > +
> > + /* Get the base address from the device node */
> > + base = fdtdec_get_addr(blob, node, "reg");
> > + if (!base) {
> > + debug("DWMMC: Can't get base address\n");
>
> DWMMC?
MMC
>
> > + return -1;
> > + }
> > + host->ioaddr = (void *)base;
> > +
> > + fdtdec_decode_gpio(blob, node, "pwr-gpios", &host->pwr_gpio);
> > + fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
> > +
> > + return 0;
> > +}
> > +
> > +static int process_nodes(const void *blob, int node_list[], int
> > +count) {
> > + struct sdhci_host *host;
> > + int i, node;
> > +
> > + debug("%s: count = %d\n", __func__, count);
> > +
> > + /* build sdhci_host[] for each controller */
> > + for (i = 0; i < count; i++) {
> > + node = node_list[i];
> > + if (node <= 0)
> > + continue;
> > +
> > + host = &sdhci_host[i];
> > +
> > + if (sdhci_get_config(blob, node, host)) {
> > + printf("%s: failed to decode dev %d\n", __func__,
> i);
> > + return -1;
> > + }
> > + do_sdhci_init(host);
> > + }
> > + return 0;
> > +}
> > +
> > +int exynos_mmc_init(const void *blob) {
> > + int count;
> > + int node_list[SDHCI_MAX_HOSTS];
> > +
> > + count = fdtdec_find_aliases_for_id(blob, "mmc",
> > + COMPAT_SAMSUNG_EXYNOS_MMC, node_list,
> > + SDHCI_MAX_HOSTS);
> > +
> > + process_nodes(blob, node_list, count);
> > +
> > + return 1;
> > +}
> > +#endif
> > diff --git a/include/fdtdec.h b/include/fdtdec.h index
> > f12b4aa..d637f88 100644
> > --- a/include/fdtdec.h
> > +++ b/include/fdtdec.h
> > @@ -81,6 +81,7 @@ enum fdt_compat_id {
> > COMPAT_SAMSUNG_EXYNOS_MIPI_DSI, /* Exynos mipi dsi */
> > COMPAT_SAMSUNG_EXYNOS5_DP, /* Exynos Display port controller */
> > COMPAT_SAMSUNG_EXYNOS5_DWMMC, /* Exynos5 DWMMC controller */
> > + COMPAT_SAMSUNG_EXYNOS_MMC, /* Exynos MMC controller */
> > COMPAT_SAMSUNG_EXYNOS_SERIAL, /* Exynos UART */
> > COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */
> > COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */
> > diff --git a/include/sdhci.h b/include/sdhci.h index 74d06ae..0cba703
> > 100644
> > --- a/include/sdhci.h
> > +++ b/include/sdhci.h
> > @@ -12,6 +12,7 @@
> >
> > #include <asm/io.h>
> > #include <mmc.h>
> > +#include <fdtdec.h>
> >
> > /*
> > * Controller registers
> > @@ -244,6 +245,10 @@ struct sdhci_host {
> > const struct sdhci_ops *ops;
> > int index;
> >
> > + int bus_width;
> > + struct fdt_gpio_state pwr_gpio; /* Change Detect GPIO */
>
> pwr_gpio is Change Detect GPIO? I think that Comment is wrong.
Yes, the comment is wrong.
>
> > + struct fdt_gpio_state cd_gpio; /* Change Detect GPIO */
>
> Maybe Card detect GPIO is right.
Yes
> > +
> > void (*set_control_reg)(struct sdhci_host *host);
> > void (*set_clock)(int dev_index, unsigned int div);
> > uint voltages;
> > diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 46e67ff..a88f648
> 100644
> > --- a/lib/fdtdec.c
> > +++ b/lib/fdtdec.c
> > @@ -54,6 +54,7 @@ static const char * const
> compat_names[COMPAT_COUNT] = {
> > COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"),
> > COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"),
> > COMPAT(SAMSUNG_EXYNOS5_DWMMC, "samsung,exynos5250-dwmmc"),
> > + COMPAT(SAMSUNG_EXYNOS_MMC, "samsung,exynos-mmc"),
>
> how about using "exynos4-mmc" instead of "exynos-mmc"?
Is this driver only for Exynos4?
>
> Best Regards,
> Jaehoon Chung
>
> > COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"),
> > COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
> > COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
> >
Best regards,
Piotr Wilczek
More information about the U-Boot
mailing list