Cadence SDMMC v6 controller has a lot of changes on initialize
compared to v4 controller. PHY is needed by v6 controller.

Signed-off-by: Kuan Lim Lee <kuanlim....@starfivetech.com>
Co-developed-by: Alex Soo <yuklin....@starfivetech.com>
Signed-off-by: Wei Liang Lim <weiliang....@starfivetech.com>
---
Changes in v2
- Rename file sdhci-cadence6-phy.c to sdhci-cadence6.c
- Remove CONFIG_MMC_SDHCI_CADENCE_V6
- Rewrite code of v6 configuration part
- Add sdhci_cdns6_phy_init() function
---
 drivers/mmc/Makefile         |   1 +
 drivers/mmc/sdhci-cadence.c  |  63 ++------
 drivers/mmc/sdhci-cadence.h  |  69 ++++++++
 drivers/mmc/sdhci-cadence6.c | 294 +++++++++++++++++++++++++++++++++++
 4 files changed, 376 insertions(+), 51 deletions(-)
 create mode 100644 drivers/mmc/sdhci-cadence.h
 create mode 100644 drivers/mmc/sdhci-cadence6.c

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 2c65c4765a..136f06600a 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_MMC_SDHCI_ATMEL)         += atmel_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)                += bcm2835_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_BCMSTB)         += bcmstb_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_CADENCE)                += sdhci-cadence.o
+obj-$(CONFIG_MMC_SDHCI_CADENCE)                += sdhci-cadence6.o
 obj-$(CONFIG_MMC_SDHCI_AM654)          += am654_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_IPROC)          += iproc_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_KONA)           += kona_sdhci.o
diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c
index 327a05ad11..a5533af045 100644
--- a/drivers/mmc/sdhci-cadence.c
+++ b/drivers/mmc/sdhci-cadence.c
@@ -17,56 +17,7 @@
 #include <linux/libfdt.h>
 #include <mmc.h>
 #include <sdhci.h>
-
-/* HRS - Host Register Set (specific to Cadence) */
-#define SDHCI_CDNS_HRS04               0x10            /* PHY access port */
-#define   SDHCI_CDNS_HRS04_ACK                 BIT(26)
-#define   SDHCI_CDNS_HRS04_RD                  BIT(25)
-#define   SDHCI_CDNS_HRS04_WR                  BIT(24)
-#define   SDHCI_CDNS_HRS04_RDATA               GENMASK(23, 16)
-#define   SDHCI_CDNS_HRS04_WDATA               GENMASK(15, 8)
-#define   SDHCI_CDNS_HRS04_ADDR                        GENMASK(5, 0)
-
-#define SDHCI_CDNS_HRS06               0x18            /* eMMC control */
-#define   SDHCI_CDNS_HRS06_TUNE_UP             BIT(15)
-#define   SDHCI_CDNS_HRS06_TUNE                        GENMASK(13, 8)
-#define   SDHCI_CDNS_HRS06_MODE                        GENMASK(2, 0)
-#define   SDHCI_CDNS_HRS06_MODE_SD             0x0
-#define   SDHCI_CDNS_HRS06_MODE_MMC_SDR                0x2
-#define   SDHCI_CDNS_HRS06_MODE_MMC_DDR                0x3
-#define   SDHCI_CDNS_HRS06_MODE_MMC_HS200      0x4
-#define   SDHCI_CDNS_HRS06_MODE_MMC_HS400      0x5
-#define   SDHCI_CDNS_HRS06_MODE_MMC_HS400ES    0x6
-
-/* SRS - Slot Register Set (SDHCI-compatible) */
-#define SDHCI_CDNS_SRS_BASE            0x200
-
-/* PHY */
-#define SDHCI_CDNS_PHY_DLY_SD_HS       0x00
-#define SDHCI_CDNS_PHY_DLY_SD_DEFAULT  0x01
-#define SDHCI_CDNS_PHY_DLY_UHS_SDR12   0x02
-#define SDHCI_CDNS_PHY_DLY_UHS_SDR25   0x03
-#define SDHCI_CDNS_PHY_DLY_UHS_SDR50   0x04
-#define SDHCI_CDNS_PHY_DLY_UHS_DDR50   0x05
-#define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY 0x06
-#define SDHCI_CDNS_PHY_DLY_EMMC_SDR    0x07
-#define SDHCI_CDNS_PHY_DLY_EMMC_DDR    0x08
-#define SDHCI_CDNS_PHY_DLY_SDCLK       0x0b
-#define SDHCI_CDNS_PHY_DLY_HSMMC       0x0c
-#define SDHCI_CDNS_PHY_DLY_STROBE      0x0d
-
-/*
- * The tuned val register is 6 bit-wide, but not the whole of the range is
- * available.  The range 0-42 seems to be available (then 43 wraps around to 0)
- * but I am not quite sure if it is official.  Use only 0 to 39 for safety.
- */
-#define SDHCI_CDNS_MAX_TUNING_LOOP     40
-
-struct sdhci_cdns_plat {
-       struct mmc_config cfg;
-       struct mmc mmc;
-       void __iomem *hrs_addr;
-};
+#include "sdhci-cadence.h"
 
 struct sdhci_cdns_phy_cfg {
        const char *property;
@@ -163,6 +114,9 @@ static void sdhci_cdns_set_control_reg(struct sdhci_host 
*host)
        tmp &= ~SDHCI_CDNS_HRS06_MODE;
        tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode);
        writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS06);
+
+       if (device_is_compatible(mmc->dev, "cdns,sd6hc"))
+               sdhci_cdns6_phy_adj(mmc->dev, plat, mode);
 }
 
 static const struct sdhci_ops sdhci_cdns_ops = {
@@ -176,6 +130,9 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat 
*plat,
        u32 tmp;
        int i, ret;
 
+       if (device_is_compatible(plat->mmc.dev, "cdns,sd6hc"))
+               return sdhci_cdns6_set_tune_val(plat, val);
+
        if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
                return -EINVAL;
 
@@ -282,7 +239,10 @@ 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));
+       if (device_is_compatible(dev, "cdns,sd6hc"))
+               ret = sdhci_cdns6_phy_init(dev, plat);
+       else
+               ret = sdhci_cdns_phy_init(plat, gd->fdt_blob, 
dev_of_offset(dev));
        if (ret)
                return ret;
 
@@ -301,6 +261,7 @@ static int sdhci_cdns_probe(struct udevice *dev)
 static const struct udevice_id sdhci_cdns_match[] = {
        { .compatible = "socionext,uniphier-sd4hc" },
        { .compatible = "cdns,sd4hc" },
+       { .compatible = "cdns,sd6hc" },
        { /* sentinel */ }
 };
 
diff --git a/drivers/mmc/sdhci-cadence.h b/drivers/mmc/sdhci-cadence.h
new file mode 100644
index 0000000000..c20efd899a
--- /dev/null
+++ b/drivers/mmc/sdhci-cadence.h
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Socionext Inc.
+ *   Author: Masahiro Yamada <yamada.masah...@socionext.com>
+ */
+
+#ifndef SDHCI_CADENCE_H_
+#define SDHCI_CADENCE_H_
+
+/* HRS - Host Register Set (specific to Cadence) */
+/* PHY access port */
+#define SDHCI_CDNS_HRS04               0x10
+/* Cadence V4 HRS04 Description*/
+#define   SDHCI_CDNS_HRS04_ACK                 BIT(26)
+#define   SDHCI_CDNS_HRS04_RD                  BIT(25)
+#define   SDHCI_CDNS_HRS04_WR                  BIT(24)
+#define   SDHCI_CDNS_HRS04_RDATA               GENMASK(23, 16)
+#define   SDHCI_CDNS_HRS04_WDATA               GENMASK(15, 8)
+#define   SDHCI_CDNS_HRS04_ADDR                        GENMASK(5, 0)
+
+#define SDHCI_CDNS_HRS05               0x14
+
+/* eMMC control */
+#define SDHCI_CDNS_HRS06               0x18
+#define   SDHCI_CDNS_HRS06_TUNE_UP             BIT(15)
+#define   SDHCI_CDNS_HRS06_TUNE                        GENMASK(13, 8)
+#define   SDHCI_CDNS_HRS06_MODE                        GENMASK(2, 0)
+#define   SDHCI_CDNS_HRS06_MODE_SD             0x0
+#define   SDHCI_CDNS_HRS06_MODE_MMC_SDR                0x2
+#define   SDHCI_CDNS_HRS06_MODE_MMC_DDR                0x3
+#define   SDHCI_CDNS_HRS06_MODE_MMC_HS200      0x4
+#define   SDHCI_CDNS_HRS06_MODE_MMC_HS400      0x5
+#define   SDHCI_CDNS_HRS06_MODE_MMC_HS400ES    0x6
+
+/* SRS - Slot Register Set (SDHCI-compatible) */
+#define SDHCI_CDNS_SRS_BASE            0x200
+
+/* Cadence V4 PHY Setting*/
+#define SDHCI_CDNS_PHY_DLY_SD_HS       0x00
+#define SDHCI_CDNS_PHY_DLY_SD_DEFAULT  0x01
+#define SDHCI_CDNS_PHY_DLY_UHS_SDR12   0x02
+#define SDHCI_CDNS_PHY_DLY_UHS_SDR25   0x03
+#define SDHCI_CDNS_PHY_DLY_UHS_SDR50   0x04
+#define SDHCI_CDNS_PHY_DLY_UHS_DDR50   0x05
+#define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY 0x06
+#define SDHCI_CDNS_PHY_DLY_EMMC_SDR    0x07
+#define SDHCI_CDNS_PHY_DLY_EMMC_DDR    0x08
+#define SDHCI_CDNS_PHY_DLY_SDCLK       0x0b
+#define SDHCI_CDNS_PHY_DLY_HSMMC       0x0c
+#define SDHCI_CDNS_PHY_DLY_STROBE      0x0d
+
+/*
+ * The tuned val register is 6 bit-wide, but not the whole of the range is
+ * available.  The range 0-42 seems to be available (then 43 wraps around to 0)
+ * but I am not quite sure if it is official.  Use only 0 to 39 for safety.
+ */
+#define SDHCI_CDNS_MAX_TUNING_LOOP     40
+
+struct sdhci_cdns_plat {
+       struct mmc_config cfg;
+       struct mmc mmc;
+       void __iomem *hrs_addr;
+};
+
+int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 
mode);
+int sdhci_cdns6_phy_init(struct udevice *dev, struct sdhci_cdns_plat *plat);
+int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val);
+
+#endif
diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c
new file mode 100644
index 0000000000..ea0857e655
--- /dev/null
+++ b/drivers/mmc/sdhci-cadence6.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-or-platform_driver
+/*
+ * Copyright (C) 2023 Starfive.
+ *   Author: Kuan Lim Lee <kuanlim....@starfivetech.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/global_data.h>
+#include <dm/device_compat.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/sizes.h>
+#include <linux/libfdt.h>
+#include <mmc.h>
+#include <sdhci.h>
+#include "sdhci-cadence.h"
+
+/* IO Delay Information */
+#define SDHCI_CDNS_HRS07               0X1C
+#define   SDHCI_CDNS_HRS07_RW_COMPENSATE       GENMASK(20, 16)
+#define   SDHCI_CDNS_HRS07_IDELAY_VAL          GENMASK(4, 0)
+
+/* PHY Control and Status */
+#define SDHCI_CDNS_HRS09               0x24
+#define   SDHCI_CDNS_HRS09_RDDATA_EN           BIT(16)
+#define   SDHCI_CDNS_HRS09_RDCMD_EN            BIT(15)
+#define   SDHCI_CDNS_HRS09_EXTENDED_WR_MODE    BIT(3)
+#define   SDHCI_CDNS_HRS09_EXTENDED_RD_MODE    BIT(2)
+#define   SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE   BIT(1)
+#define   SDHCI_CDNS_HRS09_PHY_SW_RESET                BIT(0)
+
+/* SDCLK adjustment */
+#define SDHCI_CDNS_HRS10               0x28
+#define   SDHCI_CDNS_HRS10_HCSDCLKADJ          GENMASK(19, 16)
+
+/* CMD/DAT output delay */
+#define SDHCI_CDNS_HRS16               0x40
+
+/* PHY Special Function Registers */
+/* register to control the DQ related timing */
+#define PHY_DQ_TIMING_REG_ADDR         0x2000
+
+/* register to control the DQS related timing */
+#define PHY_DQS_TIMING_REG_ADDR                0x2004
+
+/* register to control the gate and loopback control related timing */
+#define PHY_GATE_LPBK_CTRL_REG_ADDR    0x2008
+
+/* register to control the Master DLL logic */
+#define PHY_DLL_MASTER_CTRL_REG_ADDR   0x200C
+
+/* register to control the Slave DLL logic */
+#define PHY_DLL_SLAVE_CTRL_REG_ADDR    0x2010
+#define PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY      GENMASK(31, 24)
+#define PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY          GENMASK(7, 0)
+
+#define SDHCI_CDNS6_PHY_CFG_NUM                4
+#define SDHCI_CDNS6_CTRL_CFG_NUM       4
+
+struct sdhci_cdns6_phy_cfg {
+       const char *property;
+       u32 val;
+};
+
+struct sdhci_cdns6_ctrl_cfg {
+       const char *property;
+       u32 val;
+};
+
+static struct sdhci_cdns6_phy_cfg sd_ds_phy_cfgs[] = {
+       { "cdns,phy-dqs-timing-delay-sd-ds", 0x00380004, },
+       { "cdns,phy-gate-lpbk_ctrl-delay-sd-ds", 0x01A00040, },
+       { "cdns,phy-dll-slave-ctrl-sd-ds", 0x00000000, },
+       { "cdns,phy-dq-timing-delay-sd-ds", 0x00000001, },
+};
+
+static struct sdhci_cdns6_phy_cfg emmc_sdr_phy_cfgs[] = {
+       { "cdns,phy-dqs-timing-delay-semmc-sdr", 0x00380004, },
+       { "cdns,phy-gate-lpbk_ctrl-delay-emmc-sdr", 0x01A00040, },
+       { "cdns,phy-dll-slave-ctrl-emmc-sdr", 0x00000000, },
+       { "cdns,phy-dq-timing-delay-emmc-sdr", 0x00000001, },
+};
+
+static struct sdhci_cdns6_phy_cfg emmc_ddr_phy_cfgs[] = {
+       { "cdns,phy-dqs-timing-delay-emmc-ddr", 0x00380004, },
+       { "cdns,phy-gate-lpbk_ctrl-delay-emmc-ddr", 0x01A00040, },
+       { "cdns,phy-dll-slave-ctrl-emmc-ddr", 0x00000000, },
+       { "cdns,phy-dq-timing-delay-emmc-ddr", 0x10000001, },
+};
+
+static struct sdhci_cdns6_phy_cfg emmc_hs200_phy_cfgs[] = {
+       { "cdns,phy-dqs-timing-delay-emmc-hs200", 0x00380004, },
+       { "cdns,phy-gate-lpbk_ctrl-delay-emmc-hs200", 0x01A00040, },
+       { "cdns,phy-dll-slave-ctrl-emmc-hs200", 0x00DADA00, },
+       { "cdns,phy-dq-timing-delay-emmc-hs200", 0x00000001, },
+};
+
+static struct sdhci_cdns6_phy_cfg emmc_hs400_phy_cfgs[] = {
+       { "cdns,phy-dqs-timing-delay-emmc-hs400", 0x00280004, },
+       { "cdns,phy-gate-lpbk_ctrl-delay-emmc-hs400", 0x01A00040, },
+       { "cdns,phy-dll-slave-ctrl-emmc-hs400", 0x00DAD800, },
+       { "cdns,phy-dq-timing-delay-emmc-hs400", 0x00000001, },
+};
+
+static struct sdhci_cdns6_ctrl_cfg sd_ds_ctrl_cfgs[] = {
+       { "cdns,ctrl-hrs09-timing-delay-sd-ds", 0x0001800C, },
+       { "cdns,ctrl-hrs10-lpbk_ctrl-delay-sd-ds", 0x00020000, },
+       { "cdns,ctrl-hrs16-slave-ctrl-sd-ds", 0x00000000, },
+       { "cdns,ctrl-hrs07-timing-delay-sd-ds", 0x00080000, },
+};
+
+static struct sdhci_cdns6_ctrl_cfg emmc_sdr_ctrl_cfgs[] = {
+       { "cdns,ctrl-hrs09-timing-delay-emmc-sdr", 0x0001800C, },
+       { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-sdr", 0x00030000, },
+       { "cdns,ctrl-hrs16-slave-ctrl-emmc-sdr", 0x00000000, },
+       { "cdns,ctrl-hrs07-timing-delay-emmc-sdr", 0x00080000, },
+};
+
+static struct sdhci_cdns6_ctrl_cfg emmc_ddr_ctrl_cfgs[] = {
+       { "cdns,ctrl-hrs09-timing-delay-emmc-ddr", 0x0001800C, },
+       { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-ddr", 0x00020000, },
+       { "cdns,ctrl-hrs16-slave-ctrl-emmc-ddr", 0x11000001, },
+       { "cdns,ctrl-hrs07-timing-delay-emmc-ddr", 0x00090001, },
+};
+
+static struct sdhci_cdns6_ctrl_cfg emmc_hs200_ctrl_cfgs[] = {
+       { "cdns,ctrl-hrs09-timing-delay-emmc-hs200", 0x00018000, },
+       { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-hs200", 0x00080000, },
+       { "cdns,ctrl-hrs16-slave-ctrl-emmc-hs200", 0x00000000, },
+       { "cdns,ctrl-hrs07-timing-delay-emmc-hs200", 0x00090000, },
+};
+
+static struct sdhci_cdns6_ctrl_cfg emmc_hs400_ctrl_cfgs[] = {
+       { "cdns,ctrl-hrs09-timing-delay-emmc-hs400", 0x00018000, },
+       { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-hs400", 0x00080000, },
+       { "cdns,ctrl-hrs16-slave-ctrl-emmc-hs400", 0x11000000, },
+       { "cdns,ctrl-hrs07-timing-delay-emmc-hs400", 0x00080000, },
+};
+
+static u32 sdhci_cdns6_read_phy_reg(struct sdhci_cdns_plat *plat, u32 addr)
+{
+       writel(addr, plat->hrs_addr + SDHCI_CDNS_HRS04);
+       return readl(plat->hrs_addr + SDHCI_CDNS_HRS05);
+}
+
+static void sdhci_cdns6_write_phy_reg(struct sdhci_cdns_plat *plat, u32 addr, 
u32 val)
+{
+       writel(addr, plat->hrs_addr + SDHCI_CDNS_HRS04);
+       writel(val, plat->hrs_addr + SDHCI_CDNS_HRS05);
+}
+
+static int sdhci_cdns6_reset_phy_dll(struct sdhci_cdns_plat *plat, bool reset)
+{
+       void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS09;
+       u32 tmp;
+       int ret;
+
+       tmp = readl(reg);
+       tmp &= ~SDHCI_CDNS_HRS09_PHY_SW_RESET;
+
+       /* Switch On DLL Reset */
+       if (reset)
+               tmp |= FIELD_PREP(SDHCI_CDNS_HRS09_PHY_SW_RESET, 0);
+       else
+               tmp |= FIELD_PREP(SDHCI_CDNS_HRS09_PHY_SW_RESET, 1);
+
+       writel(tmp, reg);
+
+       /* After reset, wait until HRS09.PHY_INIT_COMPLETE is set to 1 within 
3000us*/
+       if (!reset) {
+               ret = readl_poll_timeout(reg, tmp, (tmp & 
SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE),
+                                        3000);
+       }
+
+       return ret;
+}
+
+int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 
mode)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+       struct sdhci_cdns6_phy_cfg *sdhci_cdns6_phy_cfgs;
+       struct sdhci_cdns6_ctrl_cfg *sdhci_cdns6_ctrl_cfgs;
+       const fdt32_t *prop;
+       u32 tmp;
+       int i, ret;
+
+       switch (mode) {
+       case SDHCI_CDNS_HRS06_MODE_SD:
+               sdhci_cdns6_phy_cfgs = sd_ds_phy_cfgs;
+               sdhci_cdns6_ctrl_cfgs = sd_ds_ctrl_cfgs;
+               break;
+
+       case SDHCI_CDNS_HRS06_MODE_MMC_SDR:
+               sdhci_cdns6_phy_cfgs = emmc_sdr_phy_cfgs;
+               sdhci_cdns6_ctrl_cfgs = emmc_sdr_ctrl_cfgs;
+               break;
+
+       case SDHCI_CDNS_HRS06_MODE_MMC_DDR:
+               sdhci_cdns6_phy_cfgs = emmc_ddr_phy_cfgs;
+               sdhci_cdns6_ctrl_cfgs = emmc_ddr_ctrl_cfgs;
+               break;
+
+       case SDHCI_CDNS_HRS06_MODE_MMC_HS200:
+               sdhci_cdns6_phy_cfgs = emmc_hs200_phy_cfgs;
+               sdhci_cdns6_ctrl_cfgs = emmc_hs200_ctrl_cfgs;
+               break;
+
+       case SDHCI_CDNS_HRS06_MODE_MMC_HS400:
+               sdhci_cdns6_phy_cfgs = emmc_hs400_phy_cfgs;
+               sdhci_cdns6_ctrl_cfgs = emmc_hs400_ctrl_cfgs;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < SDHCI_CDNS6_PHY_CFG_NUM; i++) {
+               prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+                                  sdhci_cdns6_phy_cfgs[i].property, NULL);
+               if (prop)
+                       sdhci_cdns6_phy_cfgs[i].val = *prop;
+       }
+
+       for (i = 0; i < SDHCI_CDNS6_CTRL_CFG_NUM; i++) {
+               prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+                                  sdhci_cdns6_ctrl_cfgs[i].property, NULL);
+               if (prop)
+                       sdhci_cdns6_ctrl_cfgs[i].val = *prop;
+       }
+
+       /* Switch On the DLL Reset */
+       sdhci_cdns6_reset_phy_dll(plat, true);
+
+       sdhci_cdns6_write_phy_reg(plat, PHY_DQS_TIMING_REG_ADDR, 
sdhci_cdns6_phy_cfgs[0].val);
+       sdhci_cdns6_write_phy_reg(plat, PHY_GATE_LPBK_CTRL_REG_ADDR, 
sdhci_cdns6_phy_cfgs[1].val);
+       sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, 
sdhci_cdns6_phy_cfgs[2].val);
+
+       /* Switch Off the DLL Reset */
+       ret = sdhci_cdns6_reset_phy_dll(plat, false);
+       if (ret) {
+               printf("sdhci_cdns6_reset_phy is not completed\n");
+               return ret;
+       }
+
+       /* Set PHY DQ TIMING control register */
+       sdhci_cdns6_write_phy_reg(plat, PHY_DQ_TIMING_REG_ADDR, 
sdhci_cdns6_phy_cfgs[3].val);
+
+       /* Set HRS09 register */
+       tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS09);
+       tmp &= ~(SDHCI_CDNS_HRS09_EXTENDED_WR_MODE |
+                SDHCI_CDNS_HRS09_EXTENDED_RD_MODE |
+                SDHCI_CDNS_HRS09_RDDATA_EN |
+                SDHCI_CDNS_HRS09_RDCMD_EN);
+       tmp |= sdhci_cdns6_ctrl_cfgs[0].val;
+       writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS09);
+
+       /* Set HRS10 register */
+       tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS10);
+       tmp &= ~SDHCI_CDNS_HRS10_HCSDCLKADJ;
+       tmp |= sdhci_cdns6_ctrl_cfgs[1].val;
+       writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS10);
+
+       /* Set HRS16 register */
+       writel(sdhci_cdns6_ctrl_cfgs[2].val, plat->hrs_addr + SDHCI_CDNS_HRS16);
+
+       /* Set HRS07 register */
+       writel(sdhci_cdns6_ctrl_cfgs[3].val, plat->hrs_addr + SDHCI_CDNS_HRS07);
+
+       return 0;
+}
+
+int sdhci_cdns6_phy_init(struct udevice *dev, struct sdhci_cdns_plat *plat)
+{
+       return sdhci_cdns6_phy_adj(dev, plat, SDHCI_CDNS_HRS06_MODE_SD);
+}
+
+int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val)
+{
+       u32 tmp, tuneval;
+
+       tuneval = (val * 256) / SDHCI_CDNS_MAX_TUNING_LOOP;
+
+       tmp = sdhci_cdns6_read_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR);
+       tmp &= ~(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY |
+                PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY);
+       tmp |= FIELD_PREP(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY, tuneval) |
+               FIELD_PREP(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY, tuneval);
+       sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, tmp);
+
+       return 0;
+}
-- 
2.34.1

Reply via email to