[PATCH v4 13/21] mmc: dwmmc: socfpga: MMC driver access System Manager via 'altera_sysmgr'

chee.hong.ang at intel.com chee.hong.ang at intel.com
Mon Mar 9 10:07:14 CET 2020


From: Chee Hong Ang <chee.hong.ang at 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.ang at 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



More information about the U-Boot mailing list