X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmmc%2Fsocfpga_dw_mmc.c;h=8076761e06e0d44bcc0924864d94c40c450a434e;hb=6b75d35949968ea2083d5778de6882e175ecc3d0;hp=bc53a5da272582429a833e79653f2a7632458da7;hpb=c5c1af21764d9423b45c1d03e835c4547a8bc5cb;p=oweals%2Fu-boot.git diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index bc53a5da27..8076761e06 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -6,7 +6,10 @@ #include #include +#include +#include #include +#include #include #include #include @@ -16,15 +19,13 @@ static const struct socfpga_clock_manager *clock_manager_base = static const struct socfpga_system_manager *system_manager_base = (void *)SOCFPGA_SYSMGR_ADDRESS; -static char *SOCFPGA_NAME = "SOCFPGA DWMMC"; - static void socfpga_dwmci_clksel(struct dwmci_host *host) { unsigned int drvsel; unsigned int smplsel; /* Disable SDMMC clock. */ - clrbits_le32(&clock_manager_base->per_pll_en, + clrbits_le32(&clock_manager_base->per_pll.en, CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); /* Configures drv_sel and smpl_sel */ @@ -39,30 +40,91 @@ static void socfpga_dwmci_clksel(struct dwmci_host *host) readl(&system_manager_base->sdmmcgrp_ctrl)); /* Enable SDMMC clock */ - setbits_le32(&clock_manager_base->per_pll_en, + setbits_le32(&clock_manager_base->per_pll.en, 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) { - struct dwmci_host *host = NULL; - host = calloc(sizeof(struct dwmci_host), 1); - if (!host) { - printf("dwmci_host calloc fail!\n"); - return -1; + /* FIXME: probe from DT eventually too/ */ + const unsigned long clk = cm_get_mmc_controller_clk_hz(); + + struct dwmci_host *host; + fdt_addr_t reg_base; + int bus_width, fifo_depth; + + if (clk == 0) { + printf("DWMMC%d: MMC clock is zero!", idx); + return -EINVAL; } - host->name = SOCFPGA_NAME; - host->ioaddr = (void *)regbase; + /* 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 *)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->bus_hz = CONFIG_SOCFPGA_DWMMC_BUS_HZ; + 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; +}