Message ID | 1390832143-372-5-git-send-email-p.wilczek@samsung.com |
---|---|
State | Changes Requested |
Delegated to: | Minkyu Kang |
Headers | show |
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@samsung.com> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> > Cc: Minkyu Kang <mk7.kang@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)? > + 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? > + 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? > + 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. > + struct fdt_gpio_state cd_gpio; /* Change Detect GPIO */ Maybe Card detect GPIO is right. > + > 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"? Best Regards, Jaehoon Chung > COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"), > COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), > COMPAT(GENERIC_SPI_FLASH, "spi-flash"), >
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@samsung.com> > > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> > > Cc: Minkyu Kang <mk7.kang@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
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); + 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) { + 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"); + 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 */ + struct fdt_gpio_state cd_gpio; /* Change Detect GPIO */ + 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"), COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"), COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), COMPAT(GENERIC_SPI_FLASH, "spi-flash"),