[U-Boot] [PATCHv2 04/10] mmc: exynos_dw_mmc: restore the property into host

Jaehoon Chung jh80.chung at samsung.com
Wed Apr 2 08:17:25 CEST 2014


Restore the platdata(property of dt) into host struct.
Then data's information is maintained and reused anywhere.

Signed-off-by: Jaehoon Chung <jh80.chung at samsung.com>
---
 drivers/mmc/exynos_dw_mmc.c |  220 +++++++++++++++++++++++++++----------------
 include/dwmmc.h             |    2 +
 2 files changed, 139 insertions(+), 83 deletions(-)

diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index b9d41d4..a2a4d75 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -14,6 +14,7 @@
 #include <asm/arch/clk.h>
 #include <asm/arch/pinmux.h>
 #include <asm/gpio.h>
+#include <asm-generic/errno.h>
 
 #define	DWMMC_MAX_CH_NUM		4
 #define	DWMMC_MAX_FREQ			52000000
@@ -45,6 +46,13 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host)
 			& DWMCI_DIVRATIO_MASK) + 1;
 	sclk = get_mmc_clk(host->dev_index);
 
+	/*
+	 * Assume to know divider value.
+	 * When clock unit is broken, need to set "host->div"
+	 */
+	if (host->div)
+		sclk /= (host->div + 1);
+
 	return sclk / clk_div;
 }
 
@@ -61,26 +69,17 @@ static void exynos_dwmci_board_init(struct dwmci_host *host)
 	}
 }
 
-/*
- * This function adds the mmc channel to be registered with mmc core.
- * index -	mmc channel number.
- * regbase -	register base address of mmc channel specified in 'index'.
- * bus_width -	operating bus width of mmc channel specified in 'index'.
- * clksel -	value to be written into CLKSEL register in case of FDT.
- *		NULL in case od non-FDT.
- */
-int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
+static int exynos_dwmci_core_init(struct dwmci_host *host, int index)
 {
-	struct dwmci_host *host = NULL;
 	unsigned int div;
 	unsigned long freq, sclk;
-	host = malloc(sizeof(struct dwmci_host));
-	if (!host) {
-		printf("dwmci_host malloc fail!\n");
-		return 1;
-	}
+
+	if (host->bus_hz)
+		freq = host->bus_hz;
+	else
+		freq = DWMMC_MAX_FREQ;
+
 	/* request mmc clock vlaue of 52MHz.  */
-	freq = 52000000;
 	sclk = get_mmc_clk(index);
 	div = DIV_ROUND_UP(sclk, freq);
 	div -= 1;
@@ -88,19 +87,15 @@ int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
 	set_mmc_clk(index, div);
 
 	host->name = "EXYNOS DWMMC";
-	host->ioaddr = (void *)regbase;
-	host->buswidth = bus_width;
 #ifdef CONFIG_EXYNOS5420
 	host->quirks = DWMCI_QUIRK_DISABLE_SMU;
 #endif
 	host->board_init = exynos_dwmci_board_init;
 
-	if (clksel) {
-		host->clksel_val = clksel;
-	} else {
-		if (0 == index)
+	if (!host->clksel_val) {
+		if (index == 0)
 			host->clksel_val = DWMMC_MMC0_CLKSEL_VAL;
-		if (2 == index)
+		if (index == 2)
 			host->clksel_val = DWMMC_MMC2_CLKSEL_VAL;
 	}
 
@@ -115,80 +110,139 @@ int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
 	return 0;
 }
 
+/*
+ * This function adds the mmc channel to be registered with mmc core.
+ * index -	mmc channel number.
+ * regbase -	register base address of mmc channel specified in 'index'.
+ * bus_width -	operating bus width of mmc channel specified in 'index'.
+ * clksel -	value to be written into CLKSEL register in case of FDT.
+ *		NULL in case od non-FDT.
+ */
+int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
+{
+	struct dwmci_host *host = NULL;
+
+	host = malloc(sizeof(struct dwmci_host));
+	if (!host) {
+		error("dwmci_host malloc fail!\n");
+		return -ENOMEM;
+	}
+
+	host->ioaddr = (void *)regbase;
+	host->buswidth = bus_width;
+
+	if (clksel)
+		host->clksel_val = clksel;
+
+	return exynos_dwmci_core_init(host, index);
+}
+
 #ifdef CONFIG_OF_CONTROL
-int exynos_dwmmc_init(const void *blob)
+struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM];
+
+static int do_dwmci_init(struct dwmci_host *host)
 {
-	int index, bus_width;
-	int node_list[DWMMC_MAX_CH_NUM];
-	int err = 0, dev_id, flag, count, i, compat_id;
-	u32 clksel_val, base, timing[3];
+	int index, flag = 0, err = 0;
 
-#ifdef CONFIG_EXYNOS4
-	compat_id = COMPAT_SAMSUNG_EXYNOS4_DWMMC;
-#else
-	compat_id = COMPAT_SAMSUNG_EXYNOS5_DWMMC;
-#endif
+	index = host->dev_index;
 
-	count = fdtdec_find_aliases_for_id(blob, "mmc",
-				compat_id, node_list, DWMMC_MAX_CH_NUM);
+	flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
+	err = exynos_pinmux_config(host->dev_id, flag);
+	if (err) {
+		debug("DWMMC not configure\n");
+		return err;
+	}
 
-	for (i = 0; i < count; i++) {
-		int node = node_list[i];
-		struct fdt_gpio_state pwr_gpio;
+	return exynos_dwmci_core_init(host, index);
+}
 
-		if (node <= 0)
-			continue;
+static int exynos_dwmci_get_config(const void *blob, int node,
+					struct dwmci_host *host)
+{
+	int err = 0;
+	u32 base, clksel_val, timing[3];
 
-		/* Extract device id for each mmc channel */
-		dev_id = pinmux_decode_periph_id(blob, node);
+	/* Extract device id for each mmc channel */
+	host->dev_id = pinmux_decode_periph_id(blob, node);
 
-		/* Get the bus width from the device node */
-		bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
-		if (bus_width <= 0) {
-			debug("DWMMC: Can't get bus-width\n");
-			return -1;
-		}
-		if (8 == bus_width)
-			flag = PINMUX_FLAG_8BIT_MODE;
-		else
-			flag = PINMUX_FLAG_NONE;
-
-		fdtdec_decode_gpio(blob, node, "pwr-gpios", &pwr_gpio);
-		if (fdt_gpio_isvalid(&pwr_gpio))
-			gpio_direction_output(pwr_gpio.gpio, 1);
-		/* config pinmux for each mmc channel */
-		err = exynos_pinmux_config(dev_id, flag);
-		if (err) {
-			debug("DWMMC not configured\n");
-			return err;
-		}
+	/* Get the bus width from the device node */
+	host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
+	if (host->buswidth <= 0) {
+		debug("DWMMC: Can't get bus-width\n");
+		return -EINVAL;
+	}
 
-		index = fdtdec_get_int(blob, node, "index", dev_id);
-		if (index == dev_id)
-			index = dev_id - PERIPH_ID_SDMMC0;
+	host->dev_index = fdtdec_get_int(blob, node, "index", host->dev_id);
+	if (host->dev_index == host->dev_id)
+		host->dev_index = host->dev_id - PERIPH_ID_SDMMC0;
 
-		/* 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;
-		}
-		/* Extract the timing info from the node */
-		err = fdtdec_get_int_array(blob, node, "samsung,timing",
-					timing, 3);
+	/* Set 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 -EINVAL;
+	}
+	host->ioaddr = (void *)base;
+
+	/* Extract the timing info from the node */
+	err =  fdtdec_get_int_array(blob, node, "samsung,timing", timing, 3);
+	if (err) {
+		debug("Can't get sdr-timings for devider\n");
+		return -EINVAL;
+	}
+
+	clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
+			DWMCI_SET_DRV_CLK(timing[1]) |
+			DWMCI_SET_DIV_RATIO(timing[2]));
+	if (clksel_val)
+		host->clksel_val = clksel_val;
+
+	host->fifoth_val = fdtdec_get_int(blob, node, "fifoth_val", 0);
+	host->bus_hz = fdtdec_get_int(blob, node, "bus_hz", 0);
+	host->div = fdtdec_get_int(blob, node, "div", 0);
+
+	return 0;
+}
+
+static int exynos_dwmci_process_node(const void *blob,
+					int node_list[], int count)
+{
+	struct dwmci_host *host;
+	int i, node, err;
+
+	for (i = 0; i < count; i++) {
+		node = node_list[i];
+		if (node <= 0)
+			continue;
+		host = &dwmci_host[i];
+		err = exynos_dwmci_get_config(blob, node, host);
 		if (err) {
-			debug("Can't get sdr-timings for divider\n");
-			return -1;
+			debug("%s: failed to decode dev %d\n", __func__, i);
+			return err;
 		}
 
-		clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
-				DWMCI_SET_DRV_CLK(timing[1]) |
-				DWMCI_SET_DIV_RATIO(timing[2]));
-		/* Initialise each mmc channel */
-		err = exynos_dwmci_add_port(index, base, bus_width, clksel_val);
-		if (err)
-			debug("dwmmc Channel-%d init failed\n", index);
+		do_dwmci_init(host);
 	}
 	return 0;
 }
+
+int exynos_dwmmc_init(const void *blob)
+{
+	int compat_id;
+	int node_list[DWMMC_MAX_CH_NUM];
+	int err = 0, count;
+
+	if (cpu_is_exynos4())
+		compat_id = COMPAT_SAMSUNG_EXYNOS4_DWMMC;
+	else if (cpu_is_exynos5())
+		compat_id = COMPAT_SAMSUNG_EXYNOS5_DWMMC;
+	else
+		compat_id = COMPAT_UNKNOWN;
+
+	count = fdtdec_find_aliases_for_id(blob, "mmc",
+				compat_id, node_list, DWMMC_MAX_CH_NUM);
+	err = exynos_dwmci_process_node(blob, node_list, count);
+
+	return err;
+}
 #endif
diff --git a/include/dwmmc.h b/include/dwmmc.h
index b641558..f391b63 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -134,7 +134,9 @@ struct dwmci_host {
 	unsigned int version;
 	unsigned int clock;
 	unsigned int bus_hz;
+	unsigned int div;
 	int dev_index;
+	int dev_id;
 	int buswidth;
 	u32 clksel_val;
 	u32 fifoth_val;
-- 
1.7.9.5



More information about the U-Boot mailing list