summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2015-07-25 10:48:14 +0200
committerMarek Vasut <marex@denx.de>2015-09-04 11:54:20 +0200
commit129adf5bf4769cd93f05e53e6aab724894c31036 (patch)
tree9b3ab9ecb98ca258ec029e90efec3f7d72795604 /drivers
parent6015f8f1b6fc30de7b4839bd691058583ec7f521 (diff)
downloadblackbird-obmc-uboot-129adf5bf4769cd93f05e53e6aab724894c31036.tar.gz
blackbird-obmc-uboot-129adf5bf4769cd93f05e53e6aab724894c31036.zip
mmc: dw_mmc: Probe the MMC from OF
Rework the driver to probe the MMC controller from Device Tree and make it mandatory. There is no longer support for probing from the ancient qts-generated header files. This patch now also removes previous temporary workaround. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Dinh Nguyen <dinguyen@opensource.altera.com> Cc: Pantelis Antoniou <panto@antoniou-consulting.com> Cc: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/socfpga_dw_mmc.c81
1 files changed, 68 insertions, 13 deletions
diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
index eb69aed9df..8076761e06 100644
--- a/drivers/mmc/socfpga_dw_mmc.c
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -6,6 +6,8 @@
#include <common.h>
#include <malloc.h>
+#include <fdtdec.h>
+#include <libfdt.h>
#include <dwmmc.h>
#include <errno.h>
#include <asm/arch/dwmmc.h>
@@ -42,34 +44,87 @@ static void socfpga_dwmci_clksel(struct dwmci_host *host)
CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
}
-int socfpga_dwmmc_init(u32 regbase, int bus_width, int index)
+static int socfpga_dwmci_of_probe(const void *blob, int node, const int idx)
{
+ /* FIXME: probe from DT eventually too/ */
+ const unsigned long clk = cm_get_mmc_controller_clk_hz();
+
struct dwmci_host *host;
- unsigned long clk = cm_get_mmc_controller_clk_hz();
+ fdt_addr_t reg_base;
+ int bus_width, fifo_depth;
if (clk == 0) {
- printf("%s: MMC clock is zero!", __func__);
+ printf("DWMMC%d: MMC clock is zero!", idx);
return -EINVAL;
}
- /* calloc for zero init */
- host = calloc(1, sizeof(struct dwmci_host));
- if (!host) {
- printf("%s: calloc() failed!\n", __func__);
- return -ENOMEM;
+ /* Get the register address from the device node */
+ reg_base = fdtdec_get_addr(blob, node, "reg");
+ if (!reg_base) {
+ printf("DWMMC%d: Can't get base address\n", idx);
+ return -EINVAL;
+ }
+
+ /* Get the bus width from the device node */
+ bus_width = fdtdec_get_int(blob, node, "bus-width", 0);
+ if (bus_width <= 0) {
+ printf("DWMMC%d: Can't get bus-width\n", idx);
+ return -EINVAL;
}
+ fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0);
+ if (fifo_depth < 0) {
+ printf("DWMMC%d: Can't get FIFO depth\n", idx);
+ return -EINVAL;
+ }
+
+ /* Allocate the host */
+ host = calloc(1, sizeof(*host));
+ if (!host)
+ return -ENOMEM;
+
host->name = "SOCFPGA DWMMC";
- host->ioaddr = (void *)regbase;
+ host->ioaddr = (void *)reg_base;
host->buswidth = bus_width;
host->clksel = socfpga_dwmci_clksel;
- host->dev_index = index;
- /* fixed clock divide by 4 which due to the SDMMC wrapper */
+ host->dev_index = idx;
+ /* Fixed clock divide by 4 which due to the SDMMC wrapper */
host->bus_hz = clk;
host->fifoth_val = MSIZE(0x2) |
- RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) |
- TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2);
+ RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2);
return add_dwmci(host, host->bus_hz, 400000);
}
+static int socfpga_dwmci_process_node(const void *blob, int nodes[],
+ int count)
+{
+ int i, node, ret;
+
+ for (i = 0; i < count; i++) {
+ node = nodes[i];
+ if (node <= 0)
+ continue;
+
+ ret = socfpga_dwmci_of_probe(blob, node, i);
+ if (ret) {
+ printf("%s: failed to decode dev %d\n", __func__, i);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+int socfpga_dwmmc_init(const void *blob)
+{
+ int nodes[2]; /* Max. two controllers. */
+ int ret, count;
+
+ count = fdtdec_find_aliases_for_id(blob, "mmc",
+ COMPAT_ALTERA_SOCFPGA_DWMMC,
+ nodes, ARRAY_SIZE(nodes));
+
+ ret = socfpga_dwmci_process_node(blob, nodes, count);
+
+ return ret;
+}
OpenPOWER on IntegriCloud