1c5c1af21SChin Liang See /* 2c5c1af21SChin Liang See * (C) Copyright 2013 Altera Corporation <www.altera.com> 3c5c1af21SChin Liang See * 4c5c1af21SChin Liang See * SPDX-License-Identifier: GPL-2.0+ 5c5c1af21SChin Liang See */ 6c5c1af21SChin Liang See 7c5c1af21SChin Liang See #include <common.h> 8*c35ed77aSMarek Vasut #include <asm/arch/clock_manager.h> 9*c35ed77aSMarek Vasut #include <asm/arch/dwmmc.h> 10*c35ed77aSMarek Vasut #include <asm/arch/system_manager.h> 11*c35ed77aSMarek Vasut #include <dm.h> 12c5c1af21SChin Liang See #include <dwmmc.h> 13498d1a62SPavel Machek #include <errno.h> 14*c35ed77aSMarek Vasut #include <fdtdec.h> 15*c35ed77aSMarek Vasut #include <libfdt.h> 16*c35ed77aSMarek Vasut #include <linux/err.h> 17*c35ed77aSMarek Vasut #include <malloc.h> 18*c35ed77aSMarek Vasut 19*c35ed77aSMarek Vasut DECLARE_GLOBAL_DATA_PTR; 20c5c1af21SChin Liang See 21c5c1af21SChin Liang See static const struct socfpga_clock_manager *clock_manager_base = 22c5c1af21SChin Liang See (void *)SOCFPGA_CLKMGR_ADDRESS; 23c5c1af21SChin Liang See static const struct socfpga_system_manager *system_manager_base = 24c5c1af21SChin Liang See (void *)SOCFPGA_SYSMGR_ADDRESS; 25c5c1af21SChin Liang See 26*c35ed77aSMarek Vasut /* socfpga implmentation specific driver private data */ 279a41404dSChin Liang See struct dwmci_socfpga_priv_data { 28*c35ed77aSMarek Vasut struct dwmci_host host; 29c5c1af21SChin Liang See unsigned int drvsel; 30c5c1af21SChin Liang See unsigned int smplsel; 319a41404dSChin Liang See }; 329a41404dSChin Liang See 339a41404dSChin Liang See static void socfpga_dwmci_clksel(struct dwmci_host *host) 349a41404dSChin Liang See { 359a41404dSChin Liang See struct dwmci_socfpga_priv_data *priv = host->priv; 36c5c1af21SChin Liang See 37c5c1af21SChin Liang See /* Disable SDMMC clock. */ 3851fb455fSPavel Machek clrbits_le32(&clock_manager_base->per_pll.en, 39c5c1af21SChin Liang See CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); 40c5c1af21SChin Liang See 419a41404dSChin Liang See debug("%s: drvsel %d smplsel %d\n", __func__, 429a41404dSChin Liang See priv->drvsel, priv->smplsel); 439a41404dSChin Liang See writel(SYSMGR_SDMMC_CTRL_SET(priv->smplsel, priv->drvsel), 44c5c1af21SChin Liang See &system_manager_base->sdmmcgrp_ctrl); 45c5c1af21SChin Liang See 46c5c1af21SChin Liang See debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__, 47c5c1af21SChin Liang See readl(&system_manager_base->sdmmcgrp_ctrl)); 48c5c1af21SChin Liang See 49c5c1af21SChin Liang See /* Enable SDMMC clock */ 5051fb455fSPavel Machek setbits_le32(&clock_manager_base->per_pll.en, 51c5c1af21SChin Liang See CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); 52c5c1af21SChin Liang See } 53c5c1af21SChin Liang See 54*c35ed77aSMarek Vasut static int socfpga_dwmmc_ofdata_to_platdata(struct udevice *dev) 55c5c1af21SChin Liang See { 56129adf5bSMarek Vasut /* FIXME: probe from DT eventually too/ */ 57129adf5bSMarek Vasut const unsigned long clk = cm_get_mmc_controller_clk_hz(); 58129adf5bSMarek Vasut 59*c35ed77aSMarek Vasut struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); 60*c35ed77aSMarek Vasut struct dwmci_host *host = &priv->host; 61*c35ed77aSMarek Vasut int fifo_depth; 62498d1a62SPavel Machek 63498d1a62SPavel Machek if (clk == 0) { 64*c35ed77aSMarek Vasut printf("DWMMC: MMC clock is zero!"); 65498d1a62SPavel Machek return -EINVAL; 66498d1a62SPavel Machek } 6778606497SPavel Machek 68*c35ed77aSMarek Vasut fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 69*c35ed77aSMarek Vasut "fifo-depth", 0); 70129adf5bSMarek Vasut if (fifo_depth < 0) { 71*c35ed77aSMarek Vasut printf("DWMMC: Can't get FIFO depth\n"); 72129adf5bSMarek Vasut return -EINVAL; 73129adf5bSMarek Vasut } 74129adf5bSMarek Vasut 75*c35ed77aSMarek Vasut host->name = dev->name; 76*c35ed77aSMarek Vasut host->ioaddr = (void *)dev_get_addr(dev); 77*c35ed77aSMarek Vasut host->buswidth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 78*c35ed77aSMarek Vasut "bus-width", 4); 79c5c1af21SChin Liang See host->clksel = socfpga_dwmci_clksel; 80*c35ed77aSMarek Vasut 81*c35ed77aSMarek Vasut /* 82*c35ed77aSMarek Vasut * TODO(sjg@chromium.org): Remove the need for this hack. 83*c35ed77aSMarek Vasut * We only have one dwmmc block on gen5 SoCFPGA. 84*c35ed77aSMarek Vasut */ 85*c35ed77aSMarek Vasut host->dev_index = 0; 86129adf5bSMarek Vasut /* Fixed clock divide by 4 which due to the SDMMC wrapper */ 87498d1a62SPavel Machek host->bus_hz = clk; 88c5c1af21SChin Liang See host->fifoth_val = MSIZE(0x2) | 89129adf5bSMarek Vasut RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); 90*c35ed77aSMarek Vasut priv->drvsel = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, 91*c35ed77aSMarek Vasut "drvsel", 3); 92*c35ed77aSMarek Vasut priv->smplsel = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, 93*c35ed77aSMarek Vasut "smplsel", 0); 949a41404dSChin Liang See host->priv = priv; 95c5c1af21SChin Liang See 96129adf5bSMarek Vasut return 0; 97129adf5bSMarek Vasut } 98129adf5bSMarek Vasut 99*c35ed77aSMarek Vasut static int socfpga_dwmmc_probe(struct udevice *dev) 100129adf5bSMarek Vasut { 101*c35ed77aSMarek Vasut struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 102*c35ed77aSMarek Vasut struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); 103*c35ed77aSMarek Vasut struct dwmci_host *host = &priv->host; 104*c35ed77aSMarek Vasut int ret; 105129adf5bSMarek Vasut 106*c35ed77aSMarek Vasut ret = add_dwmci(host, host->bus_hz, 400000); 107*c35ed77aSMarek Vasut if (ret) 108129adf5bSMarek Vasut return ret; 109*c35ed77aSMarek Vasut 110*c35ed77aSMarek Vasut upriv->mmc = host->mmc; 111*c35ed77aSMarek Vasut 112*c35ed77aSMarek Vasut return 0; 113129adf5bSMarek Vasut } 114*c35ed77aSMarek Vasut 115*c35ed77aSMarek Vasut static const struct udevice_id socfpga_dwmmc_ids[] = { 116*c35ed77aSMarek Vasut { .compatible = "altr,socfpga-dw-mshc" }, 117*c35ed77aSMarek Vasut { } 118*c35ed77aSMarek Vasut }; 119*c35ed77aSMarek Vasut 120*c35ed77aSMarek Vasut U_BOOT_DRIVER(socfpga_dwmmc_drv) = { 121*c35ed77aSMarek Vasut .name = "socfpga_dwmmc", 122*c35ed77aSMarek Vasut .id = UCLASS_MMC, 123*c35ed77aSMarek Vasut .of_match = socfpga_dwmmc_ids, 124*c35ed77aSMarek Vasut .ofdata_to_platdata = socfpga_dwmmc_ofdata_to_platdata, 125*c35ed77aSMarek Vasut .probe = socfpga_dwmmc_probe, 126*c35ed77aSMarek Vasut .priv_auto_alloc_size = sizeof(struct dwmci_socfpga_priv_data), 127*c35ed77aSMarek Vasut }; 128