This is for new platform enablement for agilex5.
Add mmc and cadence host driver for new platform.

Signed-off-by: Jit Loon Lim <jit.loon....@intel.com>
---
 drivers/mmc/mmc.c           |  27 +++---
 drivers/mmc/sdhci-cadence.c | 164 ++++++++++++++++++++++++++++++++----
 2 files changed, 160 insertions(+), 31 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 1af6af82e6..88c674d44f 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -26,6 +26,7 @@
 #include <div64.h>
 #include "mmc_private.h"
 
+#define TIMEOUT_TEN_MS  10
 #define DEFAULT_CMD6_TIMEOUT_MS  500
 
 static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
@@ -247,7 +248,7 @@ static int mmc_send_cmd_retry(struct mmc *mmc, struct 
mmc_cmd *cmd,
 static int mmc_send_cmd_quirks(struct mmc *mmc, struct mmc_cmd *cmd,
                               struct mmc_data *data, u32 quirk, uint retries)
 {
-       if (IS_ENABLED(CONFIG_MMC_QUIRKS) && mmc->quirks & quirk)
+       if (CONFIG_IS_ENABLED(MMC_QUIRKS) && mmc->quirks & quirk)
                return mmc_send_cmd_retry(mmc, cmd, data, retries);
        else
                return mmc_send_cmd(mmc, cmd, data);
@@ -597,6 +598,11 @@ static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
        int err;
        struct mmc_cmd cmd;
 
+       /* lower timeout, to speed up mmc init since both uses same flow */
+       if (IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5_EMU) ||
+           IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5_SIMICS))
+               timeout = TIMEOUT_TEN_MS;
+
        while (1) {
                cmd.cmdidx = MMC_CMD_APP_CMD;
                cmd.resp_type = MMC_RSP_R1;
@@ -635,7 +641,7 @@ static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
                        break;
 
                if (timeout-- <= 0)
-                       return -EOPNOTSUPP;
+                       return -ETIMEDOUT;
 
                udelay(1000);
        }
@@ -2432,9 +2438,6 @@ static int mmc_startup_v4(struct mmc *mmc)
 
        mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
 
-       mmc->can_trim =
-               !!(ext_csd[EXT_CSD_SEC_FEATURE] & EXT_CSD_SEC_FEATURE_TRIM_EN);
-
        return 0;
 error:
        if (mmc->ext_csd) {
@@ -3130,10 +3133,9 @@ int mmc_init_device(int num)
 #endif
 
 #ifdef CONFIG_CMD_BKOPS_ENABLE
-int mmc_set_bkops_enable(struct mmc *mmc, bool autobkops, bool enable)
+int mmc_set_bkops_enable(struct mmc *mmc)
 {
        int err;
-       u32 bit = autobkops ? BIT(1) : BIT(0);
        ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
 
        err = mmc_send_ext_csd(mmc, ext_csd);
@@ -3147,21 +3149,18 @@ int mmc_set_bkops_enable(struct mmc *mmc, bool 
autobkops, bool enable)
                return -EMEDIUMTYPE;
        }
 
-       if (enable && (ext_csd[EXT_CSD_BKOPS_EN] & bit)) {
+       if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
                puts("Background operations already enabled\n");
                return 0;
        }
 
-       err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN,
-                        enable ? bit : 0);
+       err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
        if (err) {
-               printf("Failed to %sable manual background operations\n",
-                      enable ? "en" : "dis");
+               puts("Failed to enable manual background operations\n");
                return err;
        }
 
-       printf("%sabled %s background operations\n",
-              enable ? "En" : "Dis", autobkops ? "auto" : "manual");
+       puts("Enabled manual background operations\n");
 
        return 0;
 }
diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c
index 327a05ad11..4154fd33da 100644
--- a/drivers/mmc/sdhci-cadence.c
+++ b/drivers/mmc/sdhci-cadence.c
@@ -5,7 +5,10 @@
  */
 
 #include <common.h>
+#include <clk.h>
 #include <dm.h>
+#include <generic-phy.h>
+#include <asm/arch/clock_manager.h>
 #include <asm/global_data.h>
 #include <dm/device_compat.h>
 #include <linux/bitfield.h>
@@ -16,10 +19,15 @@
 #include <linux/sizes.h>
 #include <linux/libfdt.h>
 #include <mmc.h>
+#include <reset-uclass.h>
 #include <sdhci.h>
 
+/* General define */
+#define SD_MIN_CLK 400000
+
 /* HRS - Host Register Set (specific to Cadence) */
 #define SDHCI_CDNS_HRS04               0x10            /* PHY access port */
+#define SDHCI_CDNS_HRS05               0x14            /* PHY data access port 
*/
 #define   SDHCI_CDNS_HRS04_ACK                 BIT(26)
 #define   SDHCI_CDNS_HRS04_RD                  BIT(25)
 #define   SDHCI_CDNS_HRS04_WR                  BIT(24)
@@ -66,6 +74,16 @@ struct sdhci_cdns_plat {
        struct mmc_config cfg;
        struct mmc mmc;
        void __iomem *hrs_addr;
+       struct udevice *udev;
+       struct phy phy_dev;
+       bool phy_enabled;
+       struct reset_ctl softreset_ctl;
+};
+
+/* socfpga implementation specific driver private data */
+struct sdhci_socfpga_priv_data {
+       struct sdhci_host host;
+       struct phy phy;
 };
 
 struct sdhci_cdns_phy_cfg {
@@ -94,25 +112,45 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_plat 
*plat,
        u32 tmp;
        int ret;
 
-       tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
-             FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
-       writel(tmp, reg);
+       if (plat->phy_enabled) {
+               /* retrieve reg. addr */
+               tmp = FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
 
-       tmp |= SDHCI_CDNS_HRS04_WR;
-       writel(tmp, reg);
+               ret = writel(tmp, reg);
+               debug("%s: register = 0x%08x\n", __func__, readl(reg));
 
-       ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 10);
-       if (ret)
-               return ret;
+               /* read existing value, mask it */
+               reg = plat->hrs_addr + SDHCI_CDNS_HRS05;
+               tmp = readl(reg);
+               debug("%s: register = 0x%08x\n", __func__, readl(reg));
 
-       tmp &= ~SDHCI_CDNS_HRS04_WR;
-       writel(tmp, reg);
+               tmp &= ~data;
+               tmp |= data;
+
+               /* write operation */
+               ret = writel(tmp, reg);
+               debug("%s: register = 0x%08x\n", __func__, readl(reg));
+       } else {
+               tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
+                         FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
+               writel(tmp, reg);
+
+               tmp |= SDHCI_CDNS_HRS04_WR;
+               writel(tmp, reg);
+
+               ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 
10);
+               if (ret)
+                       return ret;
+
+               tmp &= ~SDHCI_CDNS_HRS04_WR;
+               writel(tmp, reg);
+       }
 
        return 0;
 }
 
 static int sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat,
-                               const void *fdt, int nodeoffset)
+                              const void *fdt, int nodeoffset)
 {
        const fdt32_t *prop;
        int ret, i;
@@ -126,6 +164,7 @@ static int sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat,
                ret = sdhci_cdns_write_phy_reg(plat,
                                               sdhci_cdns_phy_cfgs[i].addr,
                                               fdt32_to_cpu(*prop));
+
                if (ret)
                        return ret;
        }
@@ -162,7 +201,14 @@ static void sdhci_cdns_set_control_reg(struct sdhci_host 
*host)
        tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS06);
        tmp &= ~SDHCI_CDNS_HRS06_MODE;
        tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode);
+
        writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS06);
+       debug("%s: register = 0x%x\n", __func__,
+             readl(plat->hrs_addr + SDHCI_CDNS_HRS06));
+
+       /* program phy based on generated settings, input through device tree */
+       if (plat->phy_enabled)
+               generic_phy_configure(&plat->phy_dev, NULL);
 }
 
 static const struct sdhci_ops sdhci_cdns_ops = {
@@ -192,6 +238,8 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat 
*plat,
                tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
                writel(tmp, reg);
 
+               debug("%s: register = 0x%08x\n", __func__, readl(reg));
+
                ret = readl_poll_timeout(reg, tmp,
                                         !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), 1);
                if (ret)
@@ -252,15 +300,49 @@ static int sdhci_cdns_bind(struct udevice *dev)
        return sdhci_bind(dev, &plat->mmc, &plat->cfg);
 }
 
+static int socfpga_sdhci_get_clk_rate(struct udevice *dev)
+{
+       struct sdhci_socfpga_priv_data *priv = dev_get_priv(dev);
+       struct sdhci_host *host = &priv->host;
+
+#if (IS_ENABLED(CONFIG_CLK))
+       struct clk clk;
+       int ret;
+
+       ret = clk_get_by_index(dev, 1, &clk);
+       if (ret)
+               return ret;
+
+       host->max_clk = clk_get_rate(&clk);
+
+       clk_free(&clk);
+#else
+       /* Fixed clock divide by 4 which due to the SDMMC wrapper */
+       host->max_clk = cm_get_mmc_controller_clk_hz();
+#endif
+
+       if (!host->max_clk) {
+               debug("SDHCI: MMC clock is zero!");
+               return -EINVAL;
+       }
+       debug("max_clk: %d\n", host->max_clk);
+
+       return 0;
+}
+
 static int sdhci_cdns_probe(struct udevice *dev)
 {
        DECLARE_GLOBAL_DATA_PTR;
        struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
        struct sdhci_cdns_plat *plat = dev_get_plat(dev);
-       struct sdhci_host *host = dev_get_priv(dev);
+       struct sdhci_socfpga_priv_data *priv = dev_get_priv(dev);
+       struct sdhci_host *host = &priv->host;
+       const char *phy_name = dev_read_string(dev, "phy-names");
        fdt_addr_t base;
        int ret;
 
+       plat->phy_enabled = false;
+
        base = dev_read_addr(dev);
        if (base == FDT_ADDR_T_NONE)
                return -EINVAL;
@@ -269,6 +351,43 @@ static int sdhci_cdns_probe(struct udevice *dev)
        if (!plat->hrs_addr)
                return -ENOMEM;
 
+       if (!phy_name)
+               return -EINVAL;
+
+       /* get SDMMC softreset */
+       ret = reset_get_by_name(dev, "reset", &plat->softreset_ctl);
+       if (ret)
+               pr_err("can't get soft reset for %s (%d)", dev->name, ret);
+
+       /* assert & deassert softreset */
+       ret = reset_assert(&plat->softreset_ctl);
+       if (ret < 0) {
+               pr_err("SDMMC soft reset deassert failed: %d", ret);
+               return ret;
+       }
+
+       ret = reset_deassert(&plat->softreset_ctl);
+       if (ret < 0) {
+               pr_err("SDMMC soft reset deassert failed: %d", ret);
+               return ret;
+       }
+
+       /* probe ComboPHY */
+       ret = generic_phy_get_by_name(dev, "combo-phy", &plat->phy_dev);
+       if (ret) {
+               printf("ComboPHY probe failed: %d\n", ret);
+               return ret;
+       }
+       debug("ComboPHY probe success\n");
+
+       ret = generic_phy_init(&plat->phy_dev);
+       if (ret) {
+               printf("ComboPHY init failed: %d\n", ret);
+               return ret;
+       }
+       debug("ComboPHY init success\n");
+
+       plat->phy_enabled = true;
        host->name = dev->name;
        host->ioaddr = plat->hrs_addr + SDHCI_CDNS_SRS_BASE;
        host->ops = &sdhci_cdns_ops;
@@ -282,18 +401,29 @@ static int sdhci_cdns_probe(struct udevice *dev)
        if (ret)
                return ret;
 
-       ret = sdhci_cdns_phy_init(plat, gd->fdt_blob, dev_of_offset(dev));
+       /* get max clk */
+       ret = socfpga_sdhci_get_clk_rate(dev);
        if (ret)
                return ret;
 
-       host->mmc = &plat->mmc;
-       host->mmc->dev = dev;
-       ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
+       ret = sdhci_cdns_phy_init(plat, gd->fdt_blob, dev_of_offset(dev));
        if (ret)
                return ret;
 
+       host->mmc = &plat->mmc;
        upriv->mmc = &plat->mmc;
        host->mmc->priv = host;
+       host->mmc->dev = dev;
+
+#if (IS_ENABLED(CONFIG_BLK))
+       ret = sdhci_setup_cfg(&plat->cfg, host, host->max_clk, SD_MIN_CLK);
+       if (ret)
+               return ret;
+#else
+       ret = add_sdhci(host, host->max_clk, SD_MIN_CLK);
+       if (ret)
+               return ret;
+#endif
 
        return sdhci_probe(dev);
 }
@@ -310,7 +440,7 @@ U_BOOT_DRIVER(sdhci_cdns) = {
        .of_match = sdhci_cdns_match,
        .bind = sdhci_cdns_bind,
        .probe = sdhci_cdns_probe,
-       .priv_auto      = sizeof(struct sdhci_host),
+       .priv_auto      = sizeof(struct sdhci_socfpga_priv_data),
        .plat_auto      = sizeof(struct sdhci_cdns_plat),
        .ops = &sdhci_cdns_mmc_ops,
 };
-- 
2.26.2

Reply via email to