Hi Jaehoon, On 11/1/23 08:20, Jaehoon Chung wrote: > From: Jaehoon Chung <jh80.ch...@samsung.com> > Hi > > On 10/3/23 16:22, Kuan Lim Lee wrote: > > From: Kuan Lim Lee <kuanlim....@linux.starfivetech.com> > > > > 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> > > Reviewed-by: Alex Soo <yuklin....@starfivetech.com> > > Reviewed-by: Wei Liang Lim <weiliang....@starfivetech.com> > > I didn't see their Reviewed-by tag in mailing list. They are my colleagues who collaborated develop code with me. I think I should them in Signed-off-by, and put your name in Reviewed-by
> > > --- > > drivers/mmc/Kconfig | 13 ++ > > drivers/mmc/Makefile | 1 + > > drivers/mmc/sdhci-cadence.c | 63 ++----- > > drivers/mmc/sdhci-cadence.h | 68 +++++++ > > drivers/mmc/sdhci-cadence6-phy.c | 302 > > +++++++++++++++++++++++++++++++ > > 5 files changed, 396 insertions(+), 51 deletions(-) create mode > > 100644 drivers/mmc/sdhci-cadence.h create mode 100644 > > drivers/mmc/sdhci-cadence6-phy.c > > > > diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index > > de01b9687b..cec881d862 100644 > > --- a/drivers/mmc/Kconfig > > +++ b/drivers/mmc/Kconfig > > @@ -573,6 +573,19 @@ config MMC_SDHCI_CADENCE > > > > If unsure, say N. > > > > +config MMC_SDHCI_CADENCE_V6 > > + bool "SDHCI support for the Cadence SD/SDIO/eMMC controller & > driver version 6" > > + depends on BLK && DM_MMC > > + depends on MMC_SDHCI > > + depends on OF_CONTROL > > + select MMC_SDHCI_CADENCE > > + help > > + This selects the Cadence SD/SDIO/eMMC driver version 6. > > + > > + If you have a controller with this interface, say Y here. > > + > > + If unsure, say N. > > + > > config MMC_SDHCI_AM654 > > bool "SDHCI Controller on TI's Am654 devices" > > depends on ARCH_K3 > > diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index > > 2c65c4765a..cdcce55b8b 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_V6) += sdhci-cadence6-phy.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..d7a270e74c 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; > > @@ -112,8 +63,11 @@ static int sdhci_cdns_write_phy_reg(struct > > sdhci_cdns_plat *plat, } > > > > static int sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat, > > - const void *fdt, int nodeoffset) > > + const void *fdt, int nodeoffset) > > Is there any reason to touch this? I thought the space key is misaligned. I think I better not to touch it. > > > > { > > + if (IS_ENABLED(CONFIG_MMC_SDHCI_CADENCE_V6)) > > + return sdhci_cdns6_phy_init(plat, > SDHCI_CDNS_HRS06_MODE_SD); > > + > > const fdt32_t *prop; > > int ret, i; > > > > @@ -163,6 +117,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 (IS_ENABLED(CONFIG_MMC_SDHCI_CADENCE_V6)) > > + sdhci_cdns6_phy_init(plat, mode); > > } > > > > static const struct sdhci_ops sdhci_cdns_ops = { @@ -172,6 +129,9 @@ > > static const struct sdhci_ops sdhci_cdns_ops = { static int > > sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat, > > unsigned int val) > > { > > + if (IS_ENABLED(CONFIG_MMC_SDHCI_CADENCE_V6)) > > + return sdhci_cdns6_set_tune_val(plat, val); > > + > > void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS06; > > u32 tmp; > > int i, 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..2c42cff2f3 > > --- /dev/null > > +++ b/drivers/mmc/sdhci-cadence.h > > @@ -0,0 +1,68 @@ > > +/* SPDX-License-Identifier: GPL-2.0-only */ > > +/* > > + * Copyright (C) 2022 Starfive. > > + * Author: Kuan Lim Lee <kuanlim....@starfivetech.com> > > > Does it right Copyright and author? the below codes are taken from sdhci- > cadence.c. Some parts of #define are taken from sdchi-cadence.c, some parts of #define are written by me. I think I still better put back the original Copyright and author. > > > + */ > > + > > +#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_init(struct sdhci_cdns_plat *plat, u32 mode); int > > +sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int > > +val); > > + > > +#endif > > diff --git a/drivers/mmc/sdhci-cadence6-phy.c > > b/drivers/mmc/sdhci-cadence6-phy.c > > new file mode 100644 > > index 0000000000..dd3df27dc8 > > --- /dev/null > > +++ b/drivers/mmc/sdhci-cadence6-phy.c > > @@ -0,0 +1,302 @@ > > +// SPDX-License-Identifier: GPL-2.0-or-platform_driver > > +/* > > + * Copyright (C) 2022 Starfive. > > s/2022/2023? I will put 2023. > > > + * 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) > > + > > +#define SDHCI_CDNS_HRS09 0x24 /* PHY Control and > Status */ > > +#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) > > + > > +#define SDHCI_CDNS_HRS10 0x28 /* SDCLK adjustment > */ > > +#define SDHCI_CDNS_HRS10_HCSDCLKADJ GENMASK(19, 16) > > + > > +#define SDHCI_CDNS_HRS16 0x40 /* CMD/DAT output > delay */ > > + > > +/* PHY Special Function Registers */ > > +//#define DLL_PHY_REG_BASE 0x2000 > > + > > +/* 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) > > + > > +/* register to control the global settings for PHY */ > > +#define PHY_CTRL_REG_ADDR 0x2080 > > + > > +struct phy_reg { > > + u32 phy_dqs_timing; > > + u32 phy_gate_lpbk_ctrl; > > + //u32 phy_dll_master_ctrl; > > Remove unused code. Noted. > > > + u32 phy_dll_slave_ctrl; > > + //u32 phy_ctrl; > > ditto Noted. > > > + u32 phy_dq_timing; > > + //cp_sw_half_cycle_shift; ASIC > > Ditto Noted. > > > +}; > > + > > +struct controller_reg { > > + u32 hrs07; > > + u32 hrs09; > > + u32 hrs10; > > + u32 hrs16; > > +}; > > > As some reg values can be re-used. I don't know what its value means. > e.g) 0x00380004 is sued sd_ds/emmc_sdr/emmc_ddr/emmc_hs200. This value is generated by script provided by Cadence. e.g.) phy_dqs_timing_reg (0x2004) is a 32 bits register, inside the register has few component: use_ext_lpbk_dqs, use_lpbk_dqs, use_phony_dqs, use_phony_dqs_cmd, phony_dqs_sel, dqs_select_tsel_start and dqs_select_tsel_end. Each components value is generated by script and I combined the value in a 32 bits value, 0x00380004. > > I don't want to use a magic code. If you can add some macros, it's more > readable. Should I change the struct in way below, so that it is more reable? static struct sdhci_cdns_phy_reg_pairs sd_ds_mode_setting[] = { {0x00380000, PHY_DQS_TIMING_REG_ADDR}, {0x01A00040, PHY_GATE_LPBK_CTRL_REG_ADDR}, {0x00000000, PHY_DLL_SLAVE_CTRL_REG_ADDR}, {0x00000180, PHY_CTRL_REG_ADDR}, {0x00000001, PHY_DQ_TIMING_REG_ADDR}, }; Or I have to put each value of components and put a convertion function in the code to change this to 32 bits value and program inti register, phy_dqs_timing_reg (0x2004)? > > > + > > +static struct phy_reg sd_ds_phy_cfg = { > > + 0x00380004, > > + 0x01A00040, > > + 0x00000000, > > + 0x00000001, > > +}; > > + > > +static struct phy_reg emmc_sdr_phy_cfg = { > > + 0x00380004, > > + 0x01A00040, > > + 0x00000000, > > + 0x00000001, > > +}; > > + > > +static struct phy_reg emmc_ddr_phy_cfg = { > > + 0x00380004, > > + 0x01A00040, > > + 0x00000000, > > + 0x10000001, > > +}; > > + > > +static struct phy_reg emmc_hs200_phy_cfg = { > > + 0x00380004, > > + 0x01A00040, > > + 0x00DADA00, > > + 0x00000001, > > +}; > > + > > +static struct phy_reg emmc_hs400_phy_cfg = { > > + 0x00280004, > > + 0x01A00040, > > + 0x00DAD800, > > + 0x00000001, > > +}; > > + > > +static struct controller_reg sd_ds_ctrl_cfg = { > > + 0x00080000, > > + 0x0001800C, > > + 0x00020000, > > + 0x00000000, > > +}; > > + > > +static struct controller_reg emmc_sdr_ctrl_cfg = { > > + 0x00080000, > > + 0x0001800C, > > + 0x00030000, > > + 0x00000000, > > +}; > > + > > +static struct controller_reg emmc_ddr_ctrl_cfg = { > > + 0x00090001, > > + 0x0001800C, > > + 0x00020000, > > + 0x11000001, > > +}; > > + > > +static struct controller_reg emmc_hs200_ctrl_cfg = { > > + 0x00090000, > > + 0x00018000, > > + 0x00080000, > > + 0x00000000, > > +}; > > + > > +static struct controller_reg emmc_hs400_ctrl_cfg = { > > + 0x00080000, > > + 0x00018000, > > + 0x00080000, > > + 0x11000000, > > +}; > > + > > +static unsigned int sdhci_cdns6_read_phy_reg(struct sdhci_cdns_plat *plat, > > + u32 addr) > > +{ > > + u32 data = 0; > > + > > + writel(addr, plat->hrs_addr + SDHCI_CDNS_HRS04); > > + data = readl(plat->hrs_addr + SDHCI_CDNS_HRS05); > > + return data; > > +} > > + > > +static void sdhci_cdns6_write_phy_reg(struct sdhci_cdns_plat *plat, > > + u32 addr, u32 data) > > +{ > > + u32 readdat = 0; > > + > > + writel(addr, plat->hrs_addr + SDHCI_CDNS_HRS04); > > + writel(data, plat->hrs_addr + SDHCI_CDNS_HRS05); > > + readdat = readl(plat->hrs_addr + SDHCI_CDNS_HRS05); > > + > > + if (readdat != data) { > > + pr_err("Error, %s: Writing failed!: address: 0x%x, value : 0x%x, > > + readval: 0x%x\n", __func__, addr, data, readdat); > > > Doesn't need to return error value? Yes, I think it will be changed to return error value. > > > > + } > > +} > > + > > +static int sdhci_cdns6_reset_phy_dll(struct sdhci_cdns_plat *plat, > > + unsigned int reset) > > +{ > > + void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS09; > > + u32 tmp; > > + int ret; > > + > > + tmp = readl(reg); > > + tmp &= ~SDHCI_CDNS_HRS09_PHY_SW_RESET; > > + > > + if (reset) /* Switch On DLL Reset */ > > > /* Swithc On DLL Reset */ Noted, thanks for telling. > if (reset) > ... > else > ... > > > > + tmp |= FIELD_PREP(SDHCI_CDNS_HRS09_PHY_SW_RESET, 0); > > + else /* Switch Off DLL Reset */ > > + tmp |= FIELD_PREP(SDHCI_CDNS_HRS09_PHY_SW_RESET, 1); > > + > > + writel(tmp, reg); > > + > > + if (!reset) { > > + ret = readl_poll_timeout(reg, tmp, > > + (tmp & > SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE), > > + 3000); > > Add a comment why it needs to poll during 3000. Actually 3000 us is a safe range. User manual doesn’t specify, I put myself. Comment will be like below: /* After reset, wait for PHY_INIT_COMPLETE in HRS09 register until it is set to 1 within 3000us*/ > > > + } > > + > > + return ret; > > +} > > + > > +int sdhci_cdns6_phy_init(struct sdhci_cdns_plat *plat, u32 mode) { > > + struct phy_reg *phy_cfgs; > > + struct controller_reg *ctrl_cfgs; > > + void __iomem *reg = NULL; > > + u32 tmp; > > + int ret; > > + > > + switch (mode) { > > + case SDHCI_CDNS_HRS06_MODE_SD: > > + phy_cfgs = &sd_ds_phy_cfg; > > + ctrl_cfgs = &sd_ds_ctrl_cfg; > > + break; > > + > > + case SDHCI_CDNS_HRS06_MODE_MMC_SDR: > > + phy_cfgs = &emmc_sdr_phy_cfg; > > + ctrl_cfgs = &emmc_sdr_ctrl_cfg; > > + break; > > + > > + case SDHCI_CDNS_HRS06_MODE_MMC_DDR: > > + phy_cfgs = &emmc_ddr_phy_cfg; > > + ctrl_cfgs = &emmc_ddr_ctrl_cfg; > > + break; > > + > > + case SDHCI_CDNS_HRS06_MODE_MMC_HS200: > > + phy_cfgs = &emmc_hs200_phy_cfg; > > + ctrl_cfgs = &emmc_hs200_ctrl_cfg; > > + break; > > + > > + case SDHCI_CDNS_HRS06_MODE_MMC_HS400: > > + phy_cfgs = &emmc_hs400_phy_cfg; > > + ctrl_cfgs = &emmc_hs400_ctrl_cfg; > > + break; > > > If there is no matched mod, phy_cfgs and ctrl_cfgs should be NULL. Noted. > > > + } > > + > > + /* Switch On the DLL Reset */ > > + sdhci_cdns6_reset_phy_dll(plat, 1); > > + > > + sdhci_cdns6_write_phy_reg(plat, PHY_DQS_TIMING_REG_ADDR, > > + phy_cfgs->phy_dqs_timing); > > + sdhci_cdns6_write_phy_reg(plat, PHY_GATE_LPBK_CTRL_REG_ADDR, > > + phy_cfgs->phy_gate_lpbk_ctrl); > > + sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, > > + phy_cfgs->phy_dll_slave_ctrl); > > + > > + /* Switch Off the DLL Reset */ > > + ret = sdhci_cdns6_reset_phy_dll(plat, 0); > > + 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, > > + phy_cfgs->phy_dq_timing); > > + > > + /* Set HRS09 register */ > > + reg = plat->hrs_addr + SDHCI_CDNS_HRS09; > > + tmp = readl(reg); > > > I'm not suer why plat-hrs_addr assigned to reg. > How about using the below? > > hrs_base_addr = plat->hrs_addr; > > readl(hrs_base_addr + SDHCI_CDNS_HRS10); > > Then you can change the below code like > > readl(hrs_base_addr + SDHCI_CDNS_HRS16); readl(hrs_base_addr + > SDHCI_CDNS_HRS07); > > Otherwise, readl(plat->hrs_addr + SDHCI_xxx); Noted, this looked simpler. > > > > + tmp &= ~(SDHCI_CDNS_HRS09_EXTENDED_WR_MODE | > > + SDHCI_CDNS_HRS09_EXTENDED_RD_MODE | > > + SDHCI_CDNS_HRS09_RDDATA_EN | > > + SDHCI_CDNS_HRS09_RDCMD_EN); > > + tmp |= ctrl_cfgs->hrs09; > > + writel(tmp, reg); > > + > > + /* Set HRS10 register */ > > + reg = plat->hrs_addr + SDHCI_CDNS_HRS10; > > + tmp = readl(reg); > > + tmp &= ~SDHCI_CDNS_HRS10_HCSDCLKADJ; > > + tmp |= ctrl_cfgs->hrs10; > > + writel(tmp, reg); > > + > > + /* Set HRS16 register */ > > + reg = plat->hrs_addr + SDHCI_CDNS_HRS16; > > + tmp = ctrl_cfgs->hrs16; > > + writel(tmp, reg); > > + > > + /* Set HRS07 register */ > > + reg = plat->hrs_addr + SDHCI_CDNS_HRS07; > > + tmp = ctrl_cfgs->hrs07; > > + writel(tmp, reg); > > + > > + return 0; > > +} > > + > > +int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, > > + unsigned int val) > > +{ > > + u32 tmp, tuneval; > > Ditto. Any problem with this? I think current way looked simple. > > Best Regards, > Jaehoon Chung > > > + > > + 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; > > +} >