[PATCH] mmc: sdhci-cadence: Add support for Cadence sdmmc v6

Jaehoon Chung jh80.chung at samsung.com
Wed Nov 1 01:19:48 CET 2023


Hi

On 10/3/23 16:22, Kuan Lim Lee wrote:
> From: Kuan Lim Lee <kuanlim.lee at 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.lee at starfivetech.com>
> Reviewed-by: Alex Soo <yuklin.soo at starfivetech.com>
> Reviewed-by: Wei Liang Lim <weiliang.lim at starfivetech.com>

I didn't see their Reviewed-by tag in mailing list.

> ---
>  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?


>  {
> +	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.lee at starfivetech.com>


Does it right Copyright and author? the below codes are taken from sdhci-cadence.c.

> + */
> +
> +#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?

> + *   Author: Kuan Lim Lee <kuanlim.lee at 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.

> +	u32 phy_dll_slave_ctrl;
> +	//u32 phy_ctrl;

ditto

> +	u32 phy_dq_timing;
> +	//cp_sw_half_cycle_shift; ASIC

Ditto

> +};
> +
> +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.

I don't want to use a magic code. If you can add some macros, it's more readable.

> +
> +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? 


> +	}
> +}
> +
> +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 */
	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.

> +	}
> +
> +	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.

> +	}
> +
> +	/* 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);


> +	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.

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;
> +}




More information about the U-Boot mailing list