From patchwork Mon Mar 9 09:07:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ang, Chee Hong" X-Patchwork-Id: 243432 List-Id: U-Boot discussion From: chee.hong.ang at intel.com (chee.hong.ang at intel.com) Date: Mon, 9 Mar 2020 02:07:14 -0700 Subject: [PATCH v4 13/21] mmc: dwmmc: socfpga: MMC driver access System Manager via 'altera_sysmgr' In-Reply-To: <1583744842-24632-1-git-send-email-chee.hong.ang@intel.com> References: <1583744842-24632-1-git-send-email-chee.hong.ang@intel.com> Message-ID: <1583744842-24632-14-git-send-email-chee.hong.ang@intel.com> From: Chee Hong Ang 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 --- 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 #include -#include #include #include #include #include #include +#include #include #include #include #include +#include #include 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,