From: KuanLim.Lee <kuanlim.lee@starfivetech.com>
To: Jaehoon Chung <jh80.chung@samsung.com>,
"u-boot@lists.denx.de" <u-boot@lists.denx.de>
Cc: Yuklin Soo <yuklin.soo@starfivetech.com>,
WeiLiang Lim <weiliang.lim@starfivetech.com>,
Kuan Lim Lee <kuanlim.lee@linux.starfivetech.com>,
"cpgs@samsung.com" <cpgs@samsung.com>
Subject: RE: [PATCH] mmc: sdhci-cadence: Add support for Cadence sdmmc v6
Date: Wed, 15 Nov 2023 03:36:36 +0000 [thread overview]
Message-ID: <4a9aa7b7ce6243b68623ef4ee1bca822@EXMBX066.cuchost.com> (raw)
In-Reply-To: <2e47818072d74a8cac1c55888543a947@EXMBX066.cuchost.com>
Hi Jaehoon,
If there are no more feedback, I will send out version2 patch soon.
On 11/7/23 14:24, Kuan Lim Lee wrote:
>
> Hi Jaehoon,
>
> On 11/1/23 08:20, Jaehoon Chung wrote:
> > From: Jaehoon Chung <jh80.chung@samsung.com> Hi
> >
> > On 10/3/23 16:22, Kuan Lim Lee wrote:
> > > From: Kuan Lim Lee <kuanlim.lee@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@starfivetech.com>
> > > Reviewed-by: Alex Soo <yuklin.soo@starfivetech.com>
> > > Reviewed-by: Wei Liang Lim <weiliang.lim@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.lee@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.lee@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;
> > > +}
> >
next prev parent reply other threads:[~2023-11-15 3:36 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20231101001948epcas1p21f7980fd9ab6a99e884eeb08409b1f48@epcas1p2.samsung.com>
2023-10-03 7:22 ` [PATCH] mmc: sdhci-cadence: Add support for Cadence sdmmc v6 Kuan Lim Lee
2023-10-10 8:18 ` KuanLim.Lee
2023-10-17 4:53 ` KuanLim.Lee
2023-11-01 0:19 ` Jaehoon Chung
2023-11-07 6:23 ` KuanLim.Lee
2023-11-15 3:36 ` KuanLim.Lee [this message]
2023-11-15 12:16 ` Jaehoon Chung
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4a9aa7b7ce6243b68623ef4ee1bca822@EXMBX066.cuchost.com \
--to=kuanlim.lee@starfivetech.com \
--cc=cpgs@samsung.com \
--cc=jh80.chung@samsung.com \
--cc=kuanlim.lee@linux.starfivetech.com \
--cc=u-boot@lists.denx.de \
--cc=weiliang.lim@starfivetech.com \
--cc=yuklin.soo@starfivetech.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.