Blame view
drivers/mmc/socfpga_dw_mmc.c
4.02 KB
d41ce506b Initial Release, ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
/* * (C) Copyright 2013 Altera Corporation <www.altera.com> * * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> #include <asm/arch/clock_manager.h> #include <asm/arch/system_manager.h> #include <dm.h> #include <dwmmc.h> #include <errno.h> #include <fdtdec.h> #include <linux/libfdt.h> #include <linux/err.h> #include <malloc.h> DECLARE_GLOBAL_DATA_PTR; static const struct socfpga_clock_manager *clock_manager_base = (void *)SOCFPGA_CLKMGR_ADDRESS; static const struct socfpga_system_manager *system_manager_base = (void *)SOCFPGA_SYSMGR_ADDRESS; struct socfpga_dwmci_plat { struct mmc_config cfg; struct mmc mmc; }; /* socfpga implmentation specific driver private data */ struct dwmci_socfpga_priv_data { struct dwmci_host host; unsigned int drvsel; unsigned int smplsel; }; static void socfpga_dwmci_clksel(struct dwmci_host *host) { struct dwmci_socfpga_priv_data *priv = host->priv; u32 sdmmc_mask = ((priv->smplsel & 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT) | ((priv->drvsel & 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT); /* Disable SDMMC clock. */ clrbits_le32(&clock_manager_base->per_pll.en, CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); debug("%s: drvsel %d smplsel %d ", __func__, priv->drvsel, priv->smplsel); writel(sdmmc_mask, &system_manager_base->sdmmcgrp_ctrl); debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x ", __func__, readl(&system_manager_base->sdmmcgrp_ctrl)); /* Enable SDMMC clock */ setbits_le32(&clock_manager_base->per_pll.en, CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); } static int socfpga_dwmmc_ofdata_to_platdata(struct udevice *dev) { /* FIXME: probe from DT eventually too/ */ const unsigned long clk = cm_get_mmc_controller_clk_hz(); struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; int fifo_depth; if (clk == 0) { printf("DWMMC: MMC clock is zero!"); return -EINVAL; } fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "fifo-depth", 0); if (fifo_depth < 0) { printf("DWMMC: Can't get FIFO depth "); return -EINVAL; } host->name = dev->name; host->ioaddr = (void *)devfdt_get_addr(dev); host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 4); host->clksel = socfpga_dwmci_clksel; /* * TODO(sjg@chromium.org): Remove the need for this hack. * We only have one dwmmc block on gen5 SoCFPGA. */ host->dev_index = 0; /* Fixed clock divide by 4 which due to the SDMMC wrapper */ host->bus_hz = clk; host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); priv->drvsel = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "drvsel", 3); priv->smplsel = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "smplsel", 0); host->priv = priv; return 0; } static int socfpga_dwmmc_probe(struct udevice *dev) { #ifdef CONFIG_BLK struct socfpga_dwmci_plat *plat = dev_get_platdata(dev); #endif struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; #ifdef CONFIG_BLK dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 400000); host->mmc = &plat->mmc; #else int ret; ret = add_dwmci(host, host->bus_hz, 400000); if (ret) return ret; #endif host->mmc->priv = &priv->host; upriv->mmc = host->mmc; host->mmc->dev = dev; return 0; } static int socfpga_dwmmc_bind(struct udevice *dev) { #ifdef CONFIG_BLK struct socfpga_dwmci_plat *plat = dev_get_platdata(dev); int ret; ret = dwmci_bind(dev, &plat->mmc, &plat->cfg); if (ret) return ret; #endif return 0; } static const struct udevice_id socfpga_dwmmc_ids[] = { { .compatible = "altr,socfpga-dw-mshc" }, { } }; U_BOOT_DRIVER(socfpga_dwmmc_drv) = { .name = "socfpga_dwmmc", .id = UCLASS_MMC, .of_match = socfpga_dwmmc_ids, .ofdata_to_platdata = socfpga_dwmmc_ofdata_to_platdata, .ops = &dm_dwmci_ops, .bind = socfpga_dwmmc_bind, .probe = socfpga_dwmmc_probe, .priv_auto_alloc_size = sizeof(struct dwmci_socfpga_priv_data), .platdata_auto_alloc_size = sizeof(struct socfpga_dwmci_plat), }; |