From: Chee Hong Ang <chee.hong....@intel.com>

MMC driver now access System Manager's SDMMC control register
to set SDMMC's clock phase shift via 'altera_sysmgr' driver.

Following entry need to be specified under MMC node in device tree:
altr,sysmgr-syscon = <&sysmgr 'x' 'y' 'z'>;

x = offset of the SDMCC control register in System Manager
y = start of drvsel's bit field
z = start of smplsel's bit field

Example:
altr,sysmgr-syscon = <&sysmgr 0x28 0 4>;

Signed-off-by: Chee Hong Ang <chee.hong....@intel.com>
---
 drivers/mmc/socfpga_dw_mmc.c | 63 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 58 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
index 786cdc7..4a9627b 100644
--- a/drivers/mmc/socfpga_dw_mmc.c
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -5,16 +5,17 @@
 
 #include <common.h>
 #include <asm/arch/clock_manager.h>
-#include <asm/arch/system_manager.h>
 #include <clk.h>
 #include <dm.h>
 #include <dwmmc.h>
 #include <errno.h>
 #include <fdtdec.h>
+#include <hang.h>
 #include <dm/device_compat.h>
 #include <linux/libfdt.h>
 #include <linux/err.h>
 #include <malloc.h>
+#include <misc.h>
 #include <reset.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -24,6 +25,13 @@ struct socfpga_dwmci_plat {
        struct mmc mmc;
 };
 
+/* System Manager's SDMMC CCLK phase shift register */
+struct sysmgr_sdmmc_reg {
+       u32 offset;
+       u32 drvsel_shift;
+       u32 smplsel_shift;
+};
+
 /* socfpga implmentation specific driver private data */
 struct dwmci_socfpga_priv_data {
        struct dwmci_host       host;
@@ -45,11 +53,54 @@ static void socfpga_dwmci_reset(struct udevice *dev)
        reset_deassert_bulk(&reset_bulk);
 }
 
+static int get_sysmgr_sdmmc_reg(struct udevice *dev,
+                               struct sysmgr_sdmmc_reg *reg)
+{
+       struct ofnode_phandle_args args;
+
+       int ret = dev_read_phandle_with_args(dev, "altr,sysmgr-syscon", NULL,
+                                       3, 0, &args);
+       if (ret) {
+               dev_err(dev, "Failed to get syscon: %d\n", ret);
+               return -EINVAL;
+       }
+
+       if (args.args_count != 3) {
+               dev_err(dev, "Invalid number of syscon args\n");
+               return -EINVAL;
+       }
+
+       reg->offset = args.args[0];
+       reg->drvsel_shift = args.args[1];
+       reg->smplsel_shift = args.args[2];
+
+       return 0;
+}
+
 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);
+       struct sysmgr_sdmmc_reg sdmmc_reg;
+       struct udevice *sysmgr;
+       u32 sdmmc_mask;
+
+       int ret = uclass_get_device_by_phandle(UCLASS_MISC, host->mmc->dev,
+                                              "altr,sysmgr-syscon", &sysmgr);
+
+       if (ret == -ENOENT) {
+               debug("%s: Could not find 'altr,sysmgr-syscon' phandle\n",
+                     host->mmc->dev->name);
+               hang();
+       }
+
+       if (get_sysmgr_sdmmc_reg(host->mmc->dev, &sdmmc_reg)) {
+               debug("%s: Error reading sysmgr sdmmc reg info\n",
+                     host->mmc->dev->name);
+               hang();
+       }
+
+       sdmmc_mask = ((priv->smplsel & 0x7) << sdmmc_reg.smplsel_shift) |
+                        ((priv->drvsel & 0x7) << sdmmc_reg.drvsel_shift);
 
        /* Disable SDMMC clock. */
        clrbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_PERPLL_EN,
@@ -57,10 +108,12 @@ static void socfpga_dwmci_clksel(struct dwmci_host *host)
 
        debug("%s: drvsel %d smplsel %d\n", __func__,
              priv->drvsel, priv->smplsel);
-       writel(sdmmc_mask, socfpga_get_sysmgr_addr() + SYSMGR_SDMMC);
+
+       misc_write(sysmgr, sdmmc_reg.offset, &sdmmc_mask, sizeof(sdmmc_mask));
+       misc_read(sysmgr, sdmmc_reg.offset, &sdmmc_mask, sizeof(sdmmc_mask));
 
        debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__,
-               readl(socfpga_get_sysmgr_addr() + SYSMGR_SDMMC));
+             sdmmc_mask);
 
        /* Enable SDMMC clock */
        setbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_PERPLL_EN,
-- 
2.7.4

Reply via email to