2 * (C) Copyright 2013 Altera Corporation <www.altera.com>
4 * SPDX-License-Identifier: GPL-2.0+
8 #include <asm/arch/clock_manager.h>
9 #include <asm/arch/system_manager.h>
15 #include <linux/err.h>
18 DECLARE_GLOBAL_DATA_PTR
;
20 static const struct socfpga_clock_manager
*clock_manager_base
=
21 (void *)SOCFPGA_CLKMGR_ADDRESS
;
22 static const struct socfpga_system_manager
*system_manager_base
=
23 (void *)SOCFPGA_SYSMGR_ADDRESS
;
25 struct socfpga_dwmci_plat
{
26 struct mmc_config cfg
;
30 /* socfpga implmentation specific driver private data */
31 struct dwmci_socfpga_priv_data
{
32 struct dwmci_host host
;
37 static void socfpga_dwmci_clksel(struct dwmci_host
*host
)
39 struct dwmci_socfpga_priv_data
*priv
= host
->priv
;
40 u32 sdmmc_mask
= ((priv
->smplsel
& 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT
) |
41 ((priv
->drvsel
& 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT
);
43 /* Disable SDMMC clock. */
44 clrbits_le32(&clock_manager_base
->per_pll
.en
,
45 CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK
);
47 debug("%s: drvsel %d smplsel %d\n", __func__
,
48 priv
->drvsel
, priv
->smplsel
);
49 writel(sdmmc_mask
, &system_manager_base
->sdmmcgrp_ctrl
);
51 debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__
,
52 readl(&system_manager_base
->sdmmcgrp_ctrl
));
54 /* Enable SDMMC clock */
55 setbits_le32(&clock_manager_base
->per_pll
.en
,
56 CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK
);
59 static int socfpga_dwmmc_ofdata_to_platdata(struct udevice
*dev
)
61 /* FIXME: probe from DT eventually too/ */
62 const unsigned long clk
= cm_get_mmc_controller_clk_hz();
64 struct dwmci_socfpga_priv_data
*priv
= dev_get_priv(dev
);
65 struct dwmci_host
*host
= &priv
->host
;
69 printf("DWMMC: MMC clock is zero!");
73 fifo_depth
= fdtdec_get_int(gd
->fdt_blob
, dev_of_offset(dev
),
76 printf("DWMMC: Can't get FIFO depth\n");
80 host
->name
= dev
->name
;
81 host
->ioaddr
= (void *)devfdt_get_addr(dev
);
82 host
->buswidth
= fdtdec_get_int(gd
->fdt_blob
, dev_of_offset(dev
),
84 host
->clksel
= socfpga_dwmci_clksel
;
87 * TODO(sjg@chromium.org): Remove the need for this hack.
88 * We only have one dwmmc block on gen5 SoCFPGA.
91 /* Fixed clock divide by 4 which due to the SDMMC wrapper */
93 host
->fifoth_val
= MSIZE(0x2) |
94 RX_WMARK(fifo_depth
/ 2 - 1) | TX_WMARK(fifo_depth
/ 2);
95 priv
->drvsel
= fdtdec_get_uint(gd
->fdt_blob
, dev_of_offset(dev
),
97 priv
->smplsel
= fdtdec_get_uint(gd
->fdt_blob
, dev_of_offset(dev
),
104 static int socfpga_dwmmc_probe(struct udevice
*dev
)
107 struct socfpga_dwmci_plat
*plat
= dev_get_platdata(dev
);
109 struct mmc_uclass_priv
*upriv
= dev_get_uclass_priv(dev
);
110 struct dwmci_socfpga_priv_data
*priv
= dev_get_priv(dev
);
111 struct dwmci_host
*host
= &priv
->host
;
114 dwmci_setup_cfg(&plat
->cfg
, host
, host
->bus_hz
, 400000);
115 host
->mmc
= &plat
->mmc
;
119 ret
= add_dwmci(host
, host
->bus_hz
, 400000);
123 host
->mmc
->priv
= &priv
->host
;
124 upriv
->mmc
= host
->mmc
;
125 host
->mmc
->dev
= dev
;
130 static int socfpga_dwmmc_bind(struct udevice
*dev
)
133 struct socfpga_dwmci_plat
*plat
= dev_get_platdata(dev
);
136 ret
= dwmci_bind(dev
, &plat
->mmc
, &plat
->cfg
);
144 static const struct udevice_id socfpga_dwmmc_ids
[] = {
145 { .compatible
= "altr,socfpga-dw-mshc" },
149 U_BOOT_DRIVER(socfpga_dwmmc_drv
) = {
150 .name
= "socfpga_dwmmc",
152 .of_match
= socfpga_dwmmc_ids
,
153 .ofdata_to_platdata
= socfpga_dwmmc_ofdata_to_platdata
,
154 .ops
= &dm_dwmci_ops
,
155 .bind
= socfpga_dwmmc_bind
,
156 .probe
= socfpga_dwmmc_probe
,
157 .priv_auto_alloc_size
= sizeof(struct dwmci_socfpga_priv_data
),
158 .platdata_auto_alloc_size
= sizeof(struct socfpga_dwmci_plat
),