Linux MultiMedia Card development
 help / color / mirror / Atom feed
* [PATCH 0/5] drivers: mmc: sdhci-cadence: SD6 controller support
@ 2022-12-19 14:24 Piyush Malgujar
  2022-12-19 14:24 ` [PATCH 1/5] " Piyush Malgujar
                   ` (4 more replies)
  0 siblings, 5 replies; 19+ messages in thread
From: Piyush Malgujar @ 2022-12-19 14:24 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva, Piyush Malgujar

This patch series includes the following changes:

- Added support for SD6 controller
- Support for MMC_SDHCI_IO_ACCESSORS
- Related changes done in dt bindings
- Introduce config option for sdhci timeout
- Support for debug option

Dhananjay Kangude (1):
  drivers: mmc: sdhci-cadence: SD6 controller support

Jayanthi Annadurai (4):
  drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS
  dt-bindings: mmc: sdhci-cadence: SD6 support
  drivers: mmc: sdhci: Add option to configure sdhci timeout
  drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence
    driver.

 .../devicetree/bindings/mmc/cdns,sdhci.yaml   |   33 +-
 drivers/mmc/host/Kconfig                      |   20 +
 drivers/mmc/host/sdhci-cadence.c              | 1665 ++++++++++++++++-
 drivers/mmc/host/sdhci.c                      |    3 +-
 4 files changed, 1619 insertions(+), 102 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support
  2022-12-19 14:24 [PATCH 0/5] drivers: mmc: sdhci-cadence: SD6 controller support Piyush Malgujar
@ 2022-12-19 14:24 ` Piyush Malgujar
  2022-12-19 15:41   ` Krzysztof Kozlowski
                     ` (2 more replies)
  2022-12-19 14:24 ` [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS Piyush Malgujar
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 19+ messages in thread
From: Piyush Malgujar @ 2022-12-19 14:24 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva, Dhananjay Kangude, Piyush Malgujar

From: Dhananjay Kangude <dkangude@cadence.com>

This patch includes changes done to support SD6 controller:
- Added SD6 related ops which are isolated from SD4
- changes to support HS400, HS400ES emmc mode
- Updated HS200 tuning values and support to read tune configuration
  from FDT.
- Support to configure host side drive strength and slew
  and read it from device tree

Signed-off-by: Dhananjay Kangude <dkangude@cadence.com>
Co-developed-by: Jayanthi Annadurai <jannadurai@marvell.com>
Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
---
 drivers/mmc/host/sdhci-cadence.c | 1502 ++++++++++++++++++++++++++++--
 1 file changed, 1403 insertions(+), 99 deletions(-)

diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 6f2de54a598773879bf339aae8450f63e1251509..5332d19e489be936d6814feba4f0fc046f5e130e 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -15,30 +15,119 @@
 
 #include "sdhci-pltfm.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
+#define SDMCLK_MAX_FREQ		200000000
+
+#define DEFAULT_CMD_DELAY		16
+#define SDHCI_CDNS_TUNE_START		16
+#define SDHCI_CDNS_TUNE_STEP		6
+#define SDHCI_CDNS_TUNE_ITERATIONS	40
+
+#define SDHCI_CDNS_HRS00			0x00
+#define SDHCI_CDNS_HRS00_SWR			BIT(0)
+
+#define SDHCI_CDNS_HRS02			0x08		/* PHY access port */
+#define SDHCI_CDNS_HRS04			0x10		/* PHY access port */
+
+/* SD 4.0 Controller HRS - Host Register Set (specific to Cadence) */
+#define SDHCI_CDNS_SD4_HRS04_ACK		BIT(26)
+#define SDHCI_CDNS_SD4_HRS04_RD			BIT(25)
+#define SDHCI_CDNS_SD4_HRS04_WR			BIT(24)
+#define SDHCI_CDNS_SD4_HRS04_RDATA		GENMASK(23, 16)
+#define SDHCI_CDNS_SD4_HRS04_WDATA		GENMASK(15, 8)
+#define SDHCI_CDNS_SD4_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_LEGACY		0x1
+#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
+
+/* SD 6.0 Controller HRS - Host Register Set (Specific to Cadence) */
+#define SDHCI_CDNS_SD6_HRS04_ADDR		GENMASK(15, 0)
+
+#define SDHCI_CDNS_HRS05			0x14
+
+#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
+#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
+#define	SDHCI_CDNS_HRS10_HCSDCLKADJ		GENMASK(19, 16)
+
+#define SDHCI_CDNS_HRS11			0x2c
+/*Reset related*/
+#define SDHCI_CDNS_SRS11_SW_RESET_ALL		BIT(24)
+#define SDHCI_CDNS_SRS11_SW_RESET_CMD		BIT(25)
+#define SDHCI_CDNS_SRS11_SW_RESET_DAT		BIT(26)
+
+#define SDHCI_CDNS_HRS16			0x40
+#define SDHCI_CDNS_HRS16_WRDATA1_SDCLK_DLY	GENMASK(31, 28)
+#define SDHCI_CDNS_HRS16_WRDATA0_SDCLK_DLY	GENMASK(27, 24)
+#define SDHCI_CDNS_HRS16_WRCMD1_SDCLK_DLY	GENMASK(23, 20)
+#define SDHCI_CDNS_HRS16_WRCMD0_SDCLK_DLY	GENMASK(19, 16)
+#define SDHCI_CDNS_HRS16_WRDATA1_DLY		GENMASK(15, 12)
+#define SDHCI_CDNS_HRS16_WRDATA0_DLY		GENMASK(11, 8)
+#define SDHCI_CDNS_HRS16_WRCMD1_DLY		GENMASK(7, 4)
+#define SDHCI_CDNS_HRS16_WRCMD0_DLY		GENMASK(3, 0)
+
+/* PHY registers for SD6 controller */
+#define SDHCI_CDNS_SD6_PHY_DQ_TIMING				0x2000
+#define	SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_ALWAYS_ON		BIT(31)
+#define	SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_END		GENMASK(29, 27)
+#define	SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_START		GENMASK(26, 24)
+#define	SDHCI_CDNS_SD6_PHY_DQ_TIMING_DATA_SELECT_OE_END		GENMASK(2, 0)
+
+#define SDHCI_CDNS_SD6_PHY_DQS_TIMING				0x2004
+#define	SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_EXT_LPBK_DQS		BIT(22)
+#define	SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_LPBK_DQS		BIT(21)
+#define	SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS		BIT(20)
+#define	SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS_CMD		BIT(19)
+
+#define SDHCI_CDNS_SD6_PHY_GATE_LPBK				0x2008
+#define	SDHCI_CDNS_SD6_PHY_GATE_LPBK_SYNC_METHOD		BIT(31)
+#define	SDHCI_CDNS_SD6_PHY_GATE_LPBK_SW_HALF_CYCLE_SHIFT	BIT(28)
+#define	SDHCI_CDNS_SD6_PHY_GATE_LPBK_RD_DEL_SEL			GENMASK(24, 19)
+#define	SDHCI_CDNS_SD6_PHY_GATE_LPBK_GATE_CFG_ALWAYS_ON		BIT(6)
+
+#define SDHCI_CDNS_SD6_PHY_DLL_MASTER				0x200C
+#define	SDHCI_CDNS_SD6_PHY_DLL_MASTER_BYPASS_MODE		BIT(23)
+#define	SDHCI_CDNS_SD6_PHY_DLL_MASTER_PHASE_DETECT_SEL		GENMASK(22, 20)
+#define	SDHCI_CDNS_SD6_PHY_DLL_MASTER_DLL_LOCK_NUM		GENMASK(18, 16)
+#define	SDHCI_CDNS_SD6_PHY_DLL_MASTER_DLL_START_POINT		GENMASK(7, 0)
+
+#define SDHCI_CDNS_SD6_PHY_DLL_SLAVE				0x2010
+#define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_CMD_DELAY		GENMASK(31, 24)
+#define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WRDQS_DELAY		GENMASK(23, 16)
+#define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WR_DELAY		GENMASK(15, 8)
+#define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_DELAY		GENMASK(7, 0)
+
+#define SDHCI_CDNS_SD6_PHY_CTRL					0x2080
+#define	SDHCI_CDNS_SD6_PHY_CTRL_PHONY_DQS_TIMING		GENMASK(9, 4)
+
+#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0				0x2088
+#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_DRV			GENMASK(6, 5)
+#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_DRV_OVR_EN		BIT(4)
+#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_SLEW			GENMASK(2, 1)
+#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_SLEW_OVR_EN		BIT(0)
 
 /* SRS - Slot Register Set (SDHCI-compatible) */
 #define SDHCI_CDNS_SRS_BASE		0x200
 
-/* PHY */
+/* PHY registers for SD4 controller */
 #define SDHCI_CDNS_PHY_DLY_SD_HS	0x00
 #define SDHCI_CDNS_PHY_DLY_SD_DEFAULT	0x01
 #define SDHCI_CDNS_PHY_DLY_UHS_SDR12	0x02
@@ -59,24 +148,47 @@
  */
 #define SDHCI_CDNS_MAX_TUNING_LOOP	40
 
-struct sdhci_cdns_phy_param {
+static int tune_val_start = SDHCI_CDNS_TUNE_START;
+static int tune_val_step = SDHCI_CDNS_TUNE_STEP;
+static int max_tune_iter = SDHCI_CDNS_TUNE_ITERATIONS;
+
+struct sdhci_cdns_priv;
+
+struct sdhci_cdns_sd4_phy_param {
 	u8 addr;
 	u8 data;
 };
 
+struct sdhci_cdns_data {
+	int (*phy_init)(struct sdhci_cdns_priv *priv);
+	int (*set_tune_val)(struct sdhci_host *host, unsigned int val);
+};
+
+struct sdhci_cdns_sd4_phy {
+	unsigned int nr_phy_params;
+	struct sdhci_cdns_sd4_phy_param phy_params[];
+};
+
 struct sdhci_cdns_priv {
 	void __iomem *hrs_addr;
 	bool enhanced_strobe;
-	unsigned int nr_phy_params;
-	struct sdhci_cdns_phy_param phy_params[];
+	const struct sdhci_cdns_data *cdns_data;
+	void *phy;
 };
 
-struct sdhci_cdns_phy_cfg {
+struct sdhci_cdns_sd4_phy_cfg {
 	const char *property;
 	u8 addr;
 };
 
-static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
+struct sdhci_cdns_of_data {
+	const struct sdhci_pltfm_data *pltfm_data;
+	const struct sdhci_cdns_data *cdns_data;
+	int (*phy_probe)(struct platform_device *pdev,
+			 struct sdhci_cdns_priv *priv);
+};
+
+static const struct sdhci_cdns_sd4_phy_cfg sdhci_cdns_sd4_phy_cfgs[] = {
 	{ "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, },
 	{ "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, },
 	{ "cdns,phy-input-delay-sd-uhs-sdr12", SDHCI_CDNS_PHY_DLY_UHS_SDR12, },
@@ -90,80 +202,900 @@ static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
 	{ "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, },
 };
 
-static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
-				    u8 addr, u8 data)
+enum sdhci_cdns_sd6_phy_lock_mode {
+	SDHCI_CDNS_SD6_PHY_LOCK_MODE_FULL_CLK = 0,
+	SDHCI_CDNS_SD6_PHY_LOCK_MODE_HALF_CLK = 2,
+	SDHCI_CDNS_SD6_PHY_LOCK_MODE_SATURATION = 3,
+};
+
+struct sdhci_cdns_sd6_phy_timings {
+	u32 t_cmd_output_min;
+	u32 t_cmd_output_max;
+	u32 t_dat_output_min;
+	u32 t_dat_output_max;
+	u32 t_cmd_input_min;
+	u32 t_cmd_input_max;
+	u32 t_dat_input_min;
+	u32 t_dat_input_max;
+	u32 t_sdclk_min;
+	u32 t_sdclk_max;
+};
+
+struct sdhci_cdns_sd6_phy_delays {
+	u32 phy_sdclk_delay;
+	u32 phy_cmd_o_delay;
+	u32 phy_dat_o_delay;
+	u32 iocell_input_delay;
+	u32 iocell_output_delay;
+	u32 delay_element_org;
+	u32 delay_element;
+};
+
+struct sdhci_cdns_sd6_phy_settings {
+	/* SDHCI_CDNS_SD6_PHY_DLL_SLAVE */
+	u32 cp_read_dqs_cmd_delay;
+	u32 cp_read_dqs_delay;
+	u32 cp_clk_wr_delay;
+	u32 cp_clk_wrdqs_delay;
+
+	/* SDHCI_CDNS_SD6_PHY_DLL_MASTER */
+	u32 cp_dll_bypass_mode;
+	u32 cp_dll_start_point;
+
+	/* SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0 */
+	u32 cp_dll_locked_mode;
+
+	/* SDHCI_CDNS_SD6_PHY_GATE_LPBK */
+	u32 cp_gate_cfg_always_on;
+	u32 cp_sync_method;
+	u32 cp_rd_del_sel;
+	u32 cp_sw_half_cycle_shift;
+	u32 cp_underrun_suppress;
+
+	/* SDHCI_CDNS_SD6_PHY_DQ_TIMING */
+	u32 cp_io_mask_always_on;
+	u32 cp_io_mask_end;
+	u32 cp_io_mask_start;
+	u32 cp_data_select_oe_end;
+
+	/* SDHCI_CDNS_SD6_PHY_DQS_TIMING */
+	u32 cp_use_ext_lpbk_dqs;
+	u32 cp_use_lpbk_dqs;
+	u8 cp_use_phony_dqs;
+	u8 cp_use_phony_dqs_cmd;
+
+	/* HRS 09 */
+	u8 sdhc_extended_rd_mode;
+	u8 sdhc_extended_wr_mode;
+	u32 sdhc_rdcmd_en;
+	u32 sdhc_rddata_en;
+
+	/* HRS10 */
+	u32 sdhc_hcsdclkadj;
+
+	/* HRS 07 */
+	u32 sdhc_idelay_val;
+	u32 sdhc_rw_compensate;
+
+	/* SRS 11 */
+	u32 sdhc_sdcfsh;
+	u32 sdhc_sdcfsl;
+
+	/* HRS 16 */
+	u32 sdhc_wrcmd0_dly;
+	u32 sdhc_wrcmd0_sdclk_dly;
+	u32 sdhc_wrcmd1_dly;
+	u32 sdhc_wrcmd1_sdclk_dly;
+	u32 sdhc_wrdata0_dly;
+	u32 sdhc_wrdata0_sdclk_dly;
+	u32 sdhc_wrdata1_dly;
+	u32 sdhc_wrdata1_sdclk_dly;
+
+	u32 hs200_tune_val;
+	u32 drive;
+	u32 slew;
+};
+
+struct sdhci_cdns_sd6_phy_intermediate_results {
+	u32 t_sdmclk_calc;
+	u32 dll_max_value;
+};
+
+struct sdhci_cdns_sd6_phy {
+	struct sdhci_cdns_sd6_phy_timings t;
+	struct sdhci_cdns_sd6_phy_delays d;
+	u32 t_sdmclk;
+	struct sdhci_cdns_sd6_phy_settings settings;
+	struct sdhci_cdns_sd6_phy_intermediate_results vars;
+	bool ddr;
+	bool tune_cmd;
+	bool tune_dat;
+	bool strobe_cmd;
+	bool strobe_dat;
+	int mode;
+	int t_sdclk;
+};
+
+static void init_hs(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 2000, .t_cmd_output_max = t_sdclk - 6000,
+		.t_dat_output_min = 2000, .t_dat_output_max = t_sdclk - 6000,
+		.t_cmd_input_min = 14000, .t_cmd_input_max = t_sdclk + 2500,
+		.t_dat_input_min = 14000, .t_dat_input_max = t_sdclk + 2500,
+		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
+	};
+}
+
+static void init_uhs_sdr12(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 3000,
+		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 3000,
+		.t_cmd_input_min = 14000, .t_cmd_input_max = t_sdclk + 1500,
+		.t_dat_input_min = 14000, .t_dat_input_max = t_sdclk + 1500,
+		.t_sdclk_min = 1000000 / 25, .t_sdclk_max = 1000000 / 0.4
+	};
+}
+
+static void init_uhs_sdr25(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 3000,
+		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 3000,
+		.t_cmd_input_min = 14000, .t_cmd_input_max = t_sdclk + 1500,
+		.t_dat_input_min = 14000, .t_dat_input_max = t_sdclk + 1500,
+		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
+	};
+}
+
+static void init_uhs_sdr50(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 3000,
+		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 3000,
+		.t_cmd_input_min = 7500, .t_cmd_input_max = t_sdclk + 1500,
+		.t_dat_input_min = 7500, .t_dat_input_max = t_sdclk + 1500,
+		.t_sdclk_min = 1000000 / 100, .t_sdclk_max = 1000000 / 0.4
+	};
+}
+
+static void init_uhs_sdr104(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 1400,
+		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 1400,
+		.t_cmd_input_min = 1000, .t_cmd_input_max = t_sdclk + 1000,
+		.t_dat_input_min = 1000, .t_dat_input_max = t_sdclk + 1000,
+		.t_sdclk_min = 1000000 / 200, .t_sdclk_max = 1000000 / 100
+	};
+}
+
+static void init_uhs_ddr50(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 3000,
+		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 3000,
+		.t_cmd_input_min = 13700, .t_cmd_input_max = t_sdclk + 1500,
+		.t_dat_input_min = 7000, .t_dat_input_max = t_sdclk + 1500,
+		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
+	};
+}
+
+static void init_emmc_legacy(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 3000, .t_cmd_output_max = t_sdclk - 3000,
+		.t_dat_output_min = 3000, .t_dat_output_max = t_sdclk - 3000,
+		.t_cmd_input_min = 11700, .t_cmd_input_max = t_sdclk + 8300,
+		.t_dat_input_min = 11700, .t_dat_input_max = t_sdclk + 8300,
+		.t_sdclk_min = 1000000 / 25, .t_sdclk_max = 1000000 / 0.4
+	};
+}
+
+static void init_emmc_sdr(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 3000, .t_cmd_output_max = t_sdclk - 3000,
+		.t_dat_output_min = 3000, .t_dat_output_max = t_sdclk - 3000,
+		.t_cmd_input_min = 13700, .t_cmd_input_max = t_sdclk + 2500,
+		.t_dat_input_min = 13700, .t_dat_input_max = t_sdclk + 2500,
+		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
+	};
+}
+
+static void init_emmc_ddr(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 3000, .t_cmd_output_max = t_sdclk - 3000,
+		.t_dat_output_min = 2500, .t_dat_output_max = t_sdclk - 2500,
+		.t_cmd_input_min = 13700, .t_cmd_input_max = t_sdclk + 2500,
+		.t_dat_input_min = 7000, .t_dat_input_max = t_sdclk + 1500,
+		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
+	};
+}
+
+static void init_emmc_hs200(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 1400,
+		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 1400,
+		.t_cmd_input_min = 1000, .t_cmd_input_max = t_sdclk + 1000,
+		.t_dat_input_min = 1000, .t_dat_input_max = t_sdclk + 1000,
+		.t_sdclk_min = 1000000 / 200, .t_sdclk_max = 1000000 / 100
+	};
+}
+
+/* HS400 and HS400ES */
+static void init_emmc_hs400(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
+{
+	*t = (struct sdhci_cdns_sd6_phy_timings){
+		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 1400,
+		.t_dat_output_min = 400, .t_dat_output_max = t_sdclk - 400,
+		.t_cmd_input_min = 1000, .t_cmd_input_max = t_sdclk + 1000,
+		.t_dat_input_min = 1000, .t_dat_input_max = t_sdclk + 1000,
+		.t_sdclk_min = 1000000 / 200, .t_sdclk_max = 1000000 / 100
+	};
+}
+
+static void (*init_timings[])(struct sdhci_cdns_sd6_phy_timings*, int) = {
+	&init_hs, &init_emmc_legacy, &init_emmc_sdr,
+	&init_emmc_ddr, &init_emmc_hs200, &init_emmc_hs400,
+	&init_uhs_sdr12, &init_uhs_sdr25, &init_uhs_sdr50,
+	&init_uhs_sdr104, &init_uhs_ddr50
+};
+
+static u32 read_dqs_cmd_delay, clk_wrdqs_delay, clk_wr_delay, read_dqs_delay;
+
+static u32 sdhci_cdns_sd6_get_mode(struct sdhci_host *host, unsigned int timing);
+
+static int sdhci_cdns_sd6_phy_lock_dll(struct sdhci_cdns_sd6_phy *phy)
+{
+	u32 delay_element = phy->d.delay_element_org;
+	u32 delay_elements_in_sdmclk;
+	enum sdhci_cdns_sd6_phy_lock_mode mode;
+
+	delay_elements_in_sdmclk = DIV_ROUND_UP(phy->t_sdmclk, delay_element);
+	if (delay_elements_in_sdmclk > 256) {
+		delay_element *= 2;
+		delay_elements_in_sdmclk = DIV_ROUND_UP(phy->t_sdmclk,
+							delay_element);
+
+		if (delay_elements_in_sdmclk > 256)
+			return -1;
+
+		mode = SDHCI_CDNS_SD6_PHY_LOCK_MODE_HALF_CLK;
+		phy->vars.dll_max_value = 127;
+	} else {
+		mode = SDHCI_CDNS_SD6_PHY_LOCK_MODE_FULL_CLK;
+		phy->vars.dll_max_value = 255;
+	}
+
+	phy->vars.t_sdmclk_calc = delay_element * delay_elements_in_sdmclk;
+	phy->d.delay_element = delay_element;
+	phy->settings.cp_dll_locked_mode = mode;
+	phy->settings.cp_dll_bypass_mode = 0;
+
+	return 0;
+}
+
+static void sdhci_cdns_sd6_phy_dll_bypass(struct sdhci_cdns_sd6_phy *phy)
+{
+	phy->vars.dll_max_value = 256;
+	phy->settings.cp_dll_bypass_mode = 1;
+	phy->settings.cp_dll_locked_mode =
+		SDHCI_CDNS_SD6_PHY_LOCK_MODE_SATURATION;
+}
+
+static void sdhci_cdns_sd6_phy_configure_dll(struct sdhci_cdns_sd6_phy *phy)
+{
+	if (phy->settings.sdhc_extended_wr_mode == 0) {
+		if (sdhci_cdns_sd6_phy_lock_dll(phy) == 0)
+			return;
+	}
+	sdhci_cdns_sd6_phy_dll_bypass(phy);
+}
+
+static void sdhci_cdns_sd6_phy_calc_out(struct sdhci_cdns_sd6_phy *phy,
+					bool cmd_not_dat)
+{
+	u32 wr0_dly = 0, wr1_dly = 0, output_min, output_max, phy_o_delay,
+	    clk_wr_delay = 0, wr0_sdclk_dly = 0, wr1_sdclk_dly = 0;
+	bool data_ddr = phy->ddr && !cmd_not_dat;
+	int t;
+
+	if (cmd_not_dat) {
+		output_min = phy->t.t_cmd_output_min;
+		output_max = phy->t.t_cmd_output_max;
+		phy_o_delay = phy->d.phy_cmd_o_delay;
+	} else {
+		output_min = phy->t.t_dat_output_min;
+		output_max = phy->t.t_dat_output_max;
+		phy_o_delay = phy->d.phy_dat_o_delay;
+	}
+
+	clk_wr_delay = 0;
+	if (data_ddr) {
+		wr0_sdclk_dly = 1;
+		wr1_sdclk_dly = 1;
+	}
+
+	t = phy_o_delay - phy->d.phy_sdclk_delay - output_min;
+	if (t < 0 && phy->settings.sdhc_extended_wr_mode == 1) {
+		u32 n_half_cycle = DIV_ROUND_UP(-t * 2, phy->t_sdmclk);
+
+		wr0_dly = (n_half_cycle + 1) / 2;
+		if (data_ddr)
+			wr1_dly = (n_half_cycle + 1) / 2;
+		else
+			wr1_dly = (n_half_cycle + 1) % 2 + wr0_dly - 1;
+	}
+
+	if (phy->settings.sdhc_extended_wr_mode == 0) {
+		u32 out_hold, out_setup, out_hold_margin;
+		u32 n;
+
+		if (!data_ddr)
+			wr0_dly = 1;
+
+		out_setup = output_max;
+		out_hold = output_min;
+		out_hold_margin = DIV_ROUND_UP(out_setup - out_hold, 4);
+		out_hold += out_hold_margin;
+
+		if (phy->settings.cp_dll_bypass_mode == 0)
+			n = DIV_ROUND_UP(256 * out_hold, phy->vars.t_sdmclk_calc);
+		else
+			n = DIV_ROUND_UP(out_hold, phy->d.delay_element) - 1;
+
+		if (n <= phy->vars.dll_max_value)
+			clk_wr_delay = n;
+		else
+			clk_wr_delay = 255;
+	} else {
+		/*  sdhc_extended_wr_mode = 1 - PHY IO cell work in SDR mode */
+		clk_wr_delay = 0;
+	}
+
+	if (cmd_not_dat) {
+		phy->settings.sdhc_wrcmd0_dly = wr0_dly;
+		phy->settings.sdhc_wrcmd1_dly = wr1_dly;
+		phy->settings.cp_clk_wrdqs_delay = clk_wr_delay;
+		phy->settings.sdhc_wrcmd0_sdclk_dly = wr0_sdclk_dly;
+		phy->settings.sdhc_wrcmd1_sdclk_dly = wr1_sdclk_dly;
+	} else {
+		phy->settings.sdhc_wrdata0_dly = wr0_dly;
+		phy->settings.sdhc_wrdata1_dly = wr1_dly;
+		phy->settings.cp_clk_wr_delay = clk_wr_delay;
+		phy->settings.sdhc_wrdata0_sdclk_dly = wr0_sdclk_dly;
+		phy->settings.sdhc_wrdata1_sdclk_dly = wr1_sdclk_dly;
+	}
+}
+
+static void sdhci_cdns_sd6_phy_calc_cmd_out(struct sdhci_cdns_sd6_phy *phy)
+{
+	sdhci_cdns_sd6_phy_calc_out(phy, true);
+}
+
+static void sdhci_cdns_sd6_phy_calc_cmd_in(struct sdhci_cdns_sd6_phy *phy)
+{
+	phy->settings.cp_io_mask_end =
+		((phy->d.iocell_output_delay + phy->d.iocell_input_delay) * 2)
+		/ phy->t_sdmclk;
+
+	if (phy->settings.cp_io_mask_end >= 8)
+		phy->settings.cp_io_mask_end = 7;
+
+	if (phy->strobe_cmd && phy->settings.cp_io_mask_end > 0)
+		phy->settings.cp_io_mask_end--;
+
+	if (phy->strobe_cmd) {
+		phy->settings.cp_use_phony_dqs_cmd = 0;
+		phy->settings.cp_read_dqs_cmd_delay = 64;
+	} else {
+		phy->settings.cp_use_phony_dqs_cmd = 1;
+		phy->settings.cp_read_dqs_cmd_delay = 0;
+	}
+
+	if ((phy->mode == MMC_TIMING_MMC_HS400 && !phy->strobe_cmd) ||
+	    phy->mode == MMC_TIMING_MMC_HS200)
+		phy->settings.cp_read_dqs_cmd_delay =
+			phy->settings.hs200_tune_val;
+}
+
+static void sdhci_cdns_sd6_phy_calc_dat_in(struct sdhci_cdns_sd6_phy *phy)
+{
+	u32 hcsdclkadj = 0;
+
+	if (phy->strobe_dat) {
+		phy->settings.cp_use_phony_dqs = 0;
+		phy->settings.cp_read_dqs_delay = 64;
+	} else {
+		phy->settings.cp_use_phony_dqs = 1;
+		phy->settings.cp_read_dqs_delay = 0;
+	}
+
+	if (phy->mode == MMC_TIMING_MMC_HS200)
+		phy->settings.cp_read_dqs_delay =
+			phy->settings.hs200_tune_val;
+
+	if (phy->strobe_dat) {
+		/* dqs loopback input via IO cell */
+		hcsdclkadj += phy->d.iocell_input_delay;
+		/* dfi_dqs_in: mem_dqs -> clean_dqs_mod; delay of hic_dll_dqs_nand2 */
+		hcsdclkadj += phy->d.delay_element / 2;
+		/* delay line */
+		hcsdclkadj += phy->t_sdclk / 2;
+		/* PHY FIFO write pointer */
+		hcsdclkadj += phy->t_sdclk / 2 + phy->d.delay_element;
+		/* 1st synchronizer */
+		hcsdclkadj += DIV_ROUND_UP(hcsdclkadj, phy->t_sdmclk)
+			* phy->t_sdmclk - hcsdclkadj;
+		/*
+		 * 2nd synchronizer + PHY FIFO read pointer + PHY rddata
+		 * + PHY rddata registered, + FIFO 1st ciu_en
+		 */
+		hcsdclkadj += 5 * phy->t_sdmclk;
+		/* FIFO 2st ciu_en */
+		hcsdclkadj += phy->t_sdclk;
+
+		hcsdclkadj /= phy->t_sdclk;
+	} else {
+		u32 n;
+
+		/* rebar PHY delay */
+		hcsdclkadj += 2 * phy->t_sdmclk;
+		/* rebar output via IO cell */
+		hcsdclkadj += phy->d.iocell_output_delay;
+		/* dqs loopback input via IO cell */
+		hcsdclkadj += phy->d.iocell_input_delay;
+		/* dfi_dqs_in: mem_dqs -> clean_dqs_mod delay of hic_dll_dqs_nand2 */
+		hcsdclkadj += phy->d.delay_element / 2;
+		/* dll: one delay element between SIGI_0 and SIGO_0 */
+		hcsdclkadj += phy->d.delay_element;
+		/* dfi_dqs_in: mem_dqs_delayed -> clk_dqs delay of hic_dll_dqs_nand2 */
+		hcsdclkadj += phy->d.delay_element / 2;
+		/* deskew DLL: clk_dqs -> clk_dqN: one delay element */
+		hcsdclkadj += phy->d.delay_element;
+
+		if (phy->t_sdclk == phy->t_sdmclk)
+			n = (hcsdclkadj - 2 * phy->t_sdmclk) / phy->t_sdclk;
+		else
+			n = hcsdclkadj / phy->t_sdclk;
+
+		/* phase shift within one t_sdclk clock cycle caused by rebar - lbk dqs delay */
+		hcsdclkadj = hcsdclkadj % phy->t_sdclk;
+		/* PHY FIFO write pointer */
+		hcsdclkadj += phy->t_sdclk / 2;
+		/* 1st synchronizer */
+		hcsdclkadj += DIV_ROUND_UP(hcsdclkadj, phy->t_sdmclk)
+			* phy->t_sdmclk - hcsdclkadj;
+		/*
+		 * 2nd synchronizer + PHY FIFO read pointer + PHY rddata
+		 * + PHY rddata registered
+		 */
+		hcsdclkadj += 4 * phy->t_sdmclk;
+
+		if ((phy->t_sdclk / phy->t_sdmclk) > 1) {
+			u32 tmp1, tmp2;
+
+			tmp1 = hcsdclkadj;
+			tmp2 = (hcsdclkadj / phy->t_sdclk) * phy->t_sdclk
+				+ phy->t_sdclk - phy->t_sdmclk;
+			if (tmp1 == tmp2)
+				tmp2 += phy->t_sdclk;
+
+			/* FIFO aligns to clock cycle before ciu_en */
+			hcsdclkadj += tmp2 - tmp1;
+		}
+
+		/* FIFO 1st ciu_en */
+		hcsdclkadj += phy->t_sdmclk;
+		/* FIFO 2nd ciu_en */
+		hcsdclkadj += phy->t_sdclk;
+
+		hcsdclkadj /= phy->t_sdclk;
+
+		hcsdclkadj += n;
+
+		if ((phy->t_sdclk / phy->t_sdmclk) >= 2) {
+			if (phy->mode == MMC_TIMING_UHS_DDR50 ||
+			    phy->mode == MMC_TIMING_MMC_DDR52)
+				hcsdclkadj -= 2;
+			else
+				hcsdclkadj -= 1;
+		} else if ((phy->t_sdclk / phy->t_sdmclk) == 1) {
+			hcsdclkadj += 2;
+		}
+
+		if (phy->tune_dat)
+			hcsdclkadj -= 1;
+	}
+
+	if (hcsdclkadj > 15)
+		hcsdclkadj = 15;
+
+	phy->settings.sdhc_hcsdclkadj = hcsdclkadj;
+}
+
+static void sdhci_cdns_sd6_phy_calc_dat_out(struct sdhci_cdns_sd6_phy *phy)
+{
+	sdhci_cdns_sd6_phy_calc_out(phy, false);
+}
+
+static void sdhci_cdns_sd6_phy_calc_io(struct sdhci_cdns_sd6_phy *phy)
+{
+	u32 rw_compensate;
+
+	rw_compensate = (phy->d.iocell_input_delay + phy->d.iocell_output_delay)
+		/ phy->t_sdmclk + phy->settings.sdhc_wrdata0_dly + 5 + 3;
+
+	phy->settings.sdhc_idelay_val = (2 * phy->d.iocell_input_delay)
+		/ phy->t_sdmclk;
+
+	phy->settings.cp_io_mask_start = 0;
+	if (phy->t_sdclk == phy->t_sdmclk && rw_compensate > 10)
+		phy->settings.cp_io_mask_start = 2 * (rw_compensate - 10);
+
+	if (phy->mode == MMC_TIMING_UHS_SDR104)
+		phy->settings.cp_io_mask_start++;
+
+	if (phy->t_sdclk == phy->t_sdmclk && phy->mode == MMC_TIMING_UHS_SDR50)
+		phy->settings.cp_io_mask_start++;
+
+	phy->settings.sdhc_rw_compensate = rw_compensate;
+}
+
+static void sdhci_cdns_sd6_phy_calc_settings(struct sdhci_cdns_sd6_phy *phy)
+{
+	sdhci_cdns_sd6_phy_calc_cmd_out(phy);
+	sdhci_cdns_sd6_phy_calc_cmd_in(phy);
+	sdhci_cdns_sd6_phy_calc_dat_out(phy);
+	sdhci_cdns_sd6_phy_calc_dat_in(phy);
+	sdhci_cdns_sd6_phy_calc_io(phy);
+}
+
+static int sdhci_cdns_sd4_write_phy_reg(struct sdhci_cdns_priv *priv,
+					u8 addr, u8 data)
 {
 	void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS04;
 	u32 tmp;
 	int ret;
 
-	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK),
+	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_SD4_HRS04_ACK),
 				 0, 10);
 	if (ret)
 		return ret;
 
-	tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
-	      FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
+	tmp = FIELD_PREP(SDHCI_CDNS_SD4_HRS04_WDATA, data) |
+	      FIELD_PREP(SDHCI_CDNS_SD4_HRS04_ADDR, addr);
 	writel(tmp, reg);
 
-	tmp |= SDHCI_CDNS_HRS04_WR;
+	tmp |= SDHCI_CDNS_SD4_HRS04_WR;
 	writel(tmp, reg);
 
-	ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 0, 10);
+	ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_SD4_HRS04_ACK, 0, 10);
 	if (ret)
 		return ret;
 
-	tmp &= ~SDHCI_CDNS_HRS04_WR;
+	tmp &= ~SDHCI_CDNS_SD4_HRS04_WR;
 	writel(tmp, reg);
 
-	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK),
+	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_SD4_HRS04_ACK),
 				 0, 10);
 
 	return ret;
 }
 
-static unsigned int sdhci_cdns_phy_param_count(struct device_node *np)
+static unsigned int sdhci_cdns_sd4_phy_param_count(struct device_node *np)
 {
 	unsigned int count = 0;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++)
-		if (of_property_read_bool(np, sdhci_cdns_phy_cfgs[i].property))
+	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_sd4_phy_cfgs); i++)
+		if (of_property_read_bool(np, sdhci_cdns_sd4_phy_cfgs[i].property))
 			count++;
 
 	return count;
 }
 
-static void sdhci_cdns_phy_param_parse(struct device_node *np,
-				       struct sdhci_cdns_priv *priv)
+static void sdhci_cdns_sd4_phy_param_parse(struct device_node *np,
+					   struct sdhci_cdns_sd4_phy *phy)
 {
-	struct sdhci_cdns_phy_param *p = priv->phy_params;
+	struct sdhci_cdns_sd4_phy_param *p = phy->phy_params;
 	u32 val;
 	int ret, i;
 
-	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) {
-		ret = of_property_read_u32(np, sdhci_cdns_phy_cfgs[i].property,
+	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_sd4_phy_cfgs); i++) {
+		ret = of_property_read_u32(np, sdhci_cdns_sd4_phy_cfgs[i].property,
 					   &val);
 		if (ret)
 			continue;
 
-		p->addr = sdhci_cdns_phy_cfgs[i].addr;
+		p->addr = sdhci_cdns_sd4_phy_cfgs[i].addr;
 		p->data = val;
 		p++;
 	}
 }
 
-static int sdhci_cdns_phy_init(struct sdhci_cdns_priv *priv)
+static int sdhci_cdns_sd4_phy_init(struct sdhci_cdns_priv *priv)
 {
 	int ret, i;
+	struct sdhci_cdns_sd4_phy *phy = priv->phy;
 
-	for (i = 0; i < priv->nr_phy_params; i++) {
-		ret = sdhci_cdns_write_phy_reg(priv, priv->phy_params[i].addr,
-					       priv->phy_params[i].data);
+	for (i = 0; i < phy->nr_phy_params; i++) {
+		ret = sdhci_cdns_sd4_write_phy_reg(priv, phy->phy_params[i].addr,
+						   phy->phy_params[i].data);
 		if (ret)
 			return ret;
 	}
+	return 0;
+}
+
+static u32 sdhci_cdns_sd6_read_phy_reg(struct sdhci_cdns_priv *priv,
+				       u32 addr)
+{
+	writel(FIELD_PREP(SDHCI_CDNS_SD6_HRS04_ADDR, addr),
+	       priv->hrs_addr + SDHCI_CDNS_HRS04);
+	return readl(priv->hrs_addr + SDHCI_CDNS_HRS05);
+}
+
+static void sdhci_cdns_sd6_write_phy_reg(struct sdhci_cdns_priv *priv,
+					 u32 addr, u32 data)
+{
+	writel(FIELD_PREP(SDHCI_CDNS_SD6_HRS04_ADDR, addr),
+	       priv->hrs_addr + SDHCI_CDNS_HRS04);
+	writel(data, priv->hrs_addr + SDHCI_CDNS_HRS05);
+}
+
+static int sdhci_cdns_sd6_dll_reset(struct sdhci_cdns_priv *priv, bool reset)
+{
+	u32 reg;
+	int ret = 0;
+
+	reg = readl(priv->hrs_addr + SDHCI_CDNS_HRS09);
+	if (reset)
+		reg &= ~SDHCI_CDNS_HRS09_PHY_SW_RESET;
+	else
+		reg |= SDHCI_CDNS_HRS09_PHY_SW_RESET;
+
+	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS09);
+
+	if (!reset)
+		ret = readl_poll_timeout(priv->hrs_addr + SDHCI_CDNS_HRS09,
+					 reg,
+					 (reg &
+					  SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE),
+					 0, 0);
+
+	return ret;
+}
+
+static void sdhci_cdns_sd6_calc_phy(struct sdhci_cdns_sd6_phy *phy)
+{
+	if (phy->mode == MMC_TIMING_MMC_HS) {
+		phy->settings.cp_clk_wr_delay = 0;
+		phy->settings.cp_clk_wrdqs_delay = 0;
+		phy->settings.cp_data_select_oe_end = 1;
+		phy->settings.cp_dll_bypass_mode = 1;
+		phy->settings.cp_dll_locked_mode = 3;
+		phy->settings.cp_dll_start_point = 4;
+		phy->settings.cp_gate_cfg_always_on = 1;
+		phy->settings.cp_io_mask_always_on = 0;
+		phy->settings.cp_io_mask_end = 0;
+		phy->settings.cp_io_mask_start = 0;
+		phy->settings.cp_rd_del_sel = 52;
+		phy->settings.cp_read_dqs_cmd_delay = 0;
+		phy->settings.cp_read_dqs_delay = 0;
+		phy->settings.cp_sw_half_cycle_shift = 0;
+		phy->settings.cp_sync_method = 1;
+		phy->settings.cp_underrun_suppress = 1;
+		phy->settings.cp_use_ext_lpbk_dqs = 1;
+		phy->settings.cp_use_lpbk_dqs = 1;
+		phy->settings.cp_use_phony_dqs = 1;
+		phy->settings.cp_use_phony_dqs_cmd = 1;
+		phy->settings.sdhc_extended_rd_mode = 1;
+		phy->settings.sdhc_extended_wr_mode = 1;
+		phy->settings.sdhc_hcsdclkadj = 2;
+		phy->settings.sdhc_idelay_val = 0;
+		phy->settings.sdhc_rdcmd_en = 1;
+		phy->settings.sdhc_rddata_en = 1;
+		phy->settings.sdhc_rw_compensate = 9;
+		phy->settings.sdhc_sdcfsh = 0;
+		phy->settings.sdhc_sdcfsl = 4;
+		phy->settings.sdhc_wrcmd0_dly = 1;
+		phy->settings.sdhc_wrcmd0_sdclk_dly = 0;
+		phy->settings.sdhc_wrcmd1_dly = 0;
+		phy->settings.sdhc_wrcmd1_sdclk_dly = 0;
+		phy->settings.sdhc_wrdata0_dly = 1;
+		phy->settings.sdhc_wrdata0_sdclk_dly = 0;
+		phy->settings.sdhc_wrdata1_dly = 0;
+		phy->settings.sdhc_wrdata1_sdclk_dly = 0;
+	}
+}
+
+static int sdhci_cdns_sd6_get_delay_params(struct device *dev, struct sdhci_cdns_priv *priv)
+{
+	struct sdhci_cdns_sd6_phy *phy = priv->phy;
+	int ret;
+
+	of_property_read_u32(dev->of_node, "cdns,iocell_input_delay", &phy->d.iocell_input_delay);
+	of_property_read_u32(dev->of_node, "cdns,iocell_output_delay", &phy->d.iocell_output_delay);
+	of_property_read_u32(dev->of_node, "cdns,delay_element", &phy->d.delay_element);
+	ret = of_property_read_u32(dev->of_node, "cdns,read_dqs_cmd_delay",
+				   &phy->settings.cp_read_dqs_cmd_delay);
+	if (ret)
+		phy->settings.cp_read_dqs_cmd_delay = DEFAULT_CMD_DELAY;
+
+	ret = of_property_read_u32(dev->of_node, "cdns,tune_val_start", &tune_val_start);
+	if (ret)
+		tune_val_start = SDHCI_CDNS_TUNE_START;
+
+	ret = of_property_read_u32(dev->of_node, "cdns,tune_val_step", &tune_val_step);
+	if (ret)
+		tune_val_step = SDHCI_CDNS_TUNE_STEP;
+
+	ret = of_property_read_u32(dev->of_node, "cdns,max_tune_iter", &max_tune_iter);
+	if (ret)
+		max_tune_iter = SDHCI_CDNS_TUNE_ITERATIONS;
+
+	read_dqs_cmd_delay = phy->settings.cp_read_dqs_cmd_delay;
+	clk_wrdqs_delay = phy->settings.cp_clk_wrdqs_delay;
+	clk_wr_delay = phy->settings.cp_clk_wr_delay;
+	read_dqs_delay = phy->settings.cp_read_dqs_delay;
+	return 0;
+}
+
+static int sdhci_cdns_sd6_phy_init(struct sdhci_cdns_priv *priv)
+{
+	int ret;
+	u32 reg;
+	struct sdhci_cdns_sd6_phy *phy = priv->phy;
+
+	sdhci_cdns_sd6_dll_reset(priv, true);
+
+	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQS_TIMING);
+	reg &= ~SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_EXT_LPBK_DQS;
+	reg &= ~SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_LPBK_DQS;
+	reg &= ~SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS;
+	reg &= ~SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS_CMD;
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_EXT_LPBK_DQS,
+			phy->settings.cp_use_ext_lpbk_dqs);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_LPBK_DQS,
+			phy->settings.cp_use_lpbk_dqs);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS,
+			  phy->settings.cp_use_phony_dqs);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS_CMD,
+			  phy->settings.cp_use_phony_dqs_cmd);
+	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQS_TIMING, reg);
+
+	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GATE_LPBK);
+	reg &= ~SDHCI_CDNS_SD6_PHY_GATE_LPBK_SYNC_METHOD;
+	reg &= ~SDHCI_CDNS_SD6_PHY_GATE_LPBK_SW_HALF_CYCLE_SHIFT;
+	reg &= ~SDHCI_CDNS_SD6_PHY_GATE_LPBK_RD_DEL_SEL;
+	reg &= ~SDHCI_CDNS_SD6_PHY_GATE_LPBK_GATE_CFG_ALWAYS_ON;
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GATE_LPBK_SYNC_METHOD,
+			phy->settings.cp_sync_method);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GATE_LPBK_SW_HALF_CYCLE_SHIFT,
+			phy->settings.cp_sw_half_cycle_shift);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GATE_LPBK_RD_DEL_SEL,
+			phy->settings.cp_rd_del_sel);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GATE_LPBK_GATE_CFG_ALWAYS_ON,
+			phy->settings.cp_gate_cfg_always_on);
+	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GATE_LPBK, reg);
+
+	reg = 0x0;
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_MASTER_BYPASS_MODE,
+			 phy->settings.cp_dll_bypass_mode);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_MASTER_PHASE_DETECT_SEL, 2);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_MASTER_DLL_LOCK_NUM, 0);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_MASTER_DLL_START_POINT,
+			phy->settings.cp_dll_start_point);
+	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_MASTER, reg);
+
+	reg = 0x0;
+	reg = FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_CMD_DELAY,
+			 phy->settings.cp_read_dqs_cmd_delay);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WRDQS_DELAY,
+			  phy->settings.cp_clk_wrdqs_delay);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WR_DELAY,
+			  phy->settings.cp_clk_wr_delay);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_DELAY,
+			  phy->settings.cp_read_dqs_delay);
+	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_SLAVE, reg);
+
+	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_CTRL);
+	reg &= ~SDHCI_CDNS_SD6_PHY_CTRL_PHONY_DQS_TIMING;
+	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_CTRL, reg);
+
+	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GPIO_CTRL0);
+	reg &= ~0x77;
+	reg |= SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_DRV_OVR_EN |
+		SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_SLEW_OVR_EN;
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_DRV,
+		phy->settings.drive);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_SLEW,
+		phy->settings.slew);
+	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GPIO_CTRL0, reg);
+
+	ret = sdhci_cdns_sd6_dll_reset(priv, false);
+	if (ret)
+		return ret;
+
+	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQ_TIMING);
+	reg &= ~SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_ALWAYS_ON;
+	reg &= ~SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_END;
+	reg &= ~SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_START;
+	reg &= ~SDHCI_CDNS_SD6_PHY_DQ_TIMING_DATA_SELECT_OE_END;
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_ALWAYS_ON,
+			phy->settings.cp_io_mask_always_on);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_END,
+			  phy->settings.cp_io_mask_end);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_START,
+			  phy->settings.cp_io_mask_start);
+	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQ_TIMING_DATA_SELECT_OE_END,
+			phy->settings.cp_data_select_oe_end);
+	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQ_TIMING, reg);
+
+	reg = readl(priv->hrs_addr + SDHCI_CDNS_HRS09);
+	if (phy->settings.sdhc_extended_wr_mode)
+		reg |= SDHCI_CDNS_HRS09_EXTENDED_WR_MODE;
+	else
+		reg &= ~SDHCI_CDNS_HRS09_EXTENDED_WR_MODE;
+
+	if (phy->settings.sdhc_extended_rd_mode)
+		reg |= SDHCI_CDNS_HRS09_EXTENDED_RD_MODE;
+	else
+		reg &= ~SDHCI_CDNS_HRS09_EXTENDED_RD_MODE;
+
+	if (phy->settings.sdhc_rddata_en)
+		reg |= SDHCI_CDNS_HRS09_RDDATA_EN;
+	else
+		reg &= ~SDHCI_CDNS_HRS09_RDDATA_EN;
+
+	if (phy->settings.sdhc_rdcmd_en)
+		reg |= SDHCI_CDNS_HRS09_RDCMD_EN;
+	else
+		reg &= ~SDHCI_CDNS_HRS09_RDCMD_EN;
+
+	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS09);
+
+	writel(0x30004, priv->hrs_addr + SDHCI_CDNS_HRS02);
+
+	reg = 0x0;
+	reg = FIELD_PREP(SDHCI_CDNS_HRS10_HCSDCLKADJ, phy->settings.sdhc_hcsdclkadj);
+	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS10);
+
+	if (phy->mode != MMC_TIMING_MMC_HS && phy->mode != MMC_TIMING_MMC_DDR52) {
+		reg = 0x0;
+		reg = FIELD_PREP(SDHCI_CDNS_HRS16_WRDATA1_SDCLK_DLY,
+				 phy->settings.sdhc_wrdata1_sdclk_dly);
+		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRDATA0_SDCLK_DLY,
+				  phy->settings.sdhc_wrdata0_sdclk_dly);
+		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRCMD1_SDCLK_DLY,
+				  phy->settings.sdhc_wrcmd1_sdclk_dly);
+		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRCMD0_SDCLK_DLY,
+				  phy->settings.sdhc_wrcmd0_sdclk_dly);
+		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRDATA1_DLY,
+				  phy->settings.sdhc_wrdata1_dly);
+		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRDATA0_DLY,
+				  phy->settings.sdhc_wrdata0_dly);
+		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRCMD1_DLY,
+				  phy->settings.sdhc_wrcmd1_dly);
+		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRCMD0_DLY,
+				  phy->settings.sdhc_wrcmd0_dly);
+	} else {
+		reg = 0x202;
+	}
 
+	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS16);
+
+	reg = 0x0;
+	reg = FIELD_PREP(SDHCI_CDNS_HRS07_RW_COMPENSATE,
+			 phy->settings.sdhc_rw_compensate);
+	reg |= FIELD_PREP(SDHCI_CDNS_HRS07_IDELAY_VAL,
+			 phy->settings.sdhc_idelay_val);
+	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS07);
 	return 0;
 }
 
@@ -174,6 +1106,19 @@ static void *sdhci_cdns_priv(struct sdhci_host *host)
 	return sdhci_pltfm_priv(pltfm_host);
 }
 
+static int sdhci_cdns_sd6_set_tune_val(struct sdhci_host *host,
+				       unsigned int val)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	struct sdhci_cdns_sd6_phy *phy = priv->phy;
+
+	phy->settings.hs200_tune_val = val;
+	phy->settings.cp_read_dqs_cmd_delay = val;
+	phy->settings.cp_read_dqs_delay = val;
+
+	return sdhci_cdns_sd6_phy_init(priv);
+}
+
 static unsigned int sdhci_cdns_get_timeout_clock(struct sdhci_host *host)
 {
 	/*
@@ -183,6 +1128,11 @@ static unsigned int sdhci_cdns_get_timeout_clock(struct sdhci_host *host)
 	return host->max_clk;
 }
 
+static unsigned int sdhci_cdns_get_max_clock(struct sdhci_host *host)
+{
+	return SDMCLK_MAX_FREQ;
+}
+
 static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode)
 {
 	u32 tmp;
@@ -202,7 +1152,296 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
 	return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
 }
 
-static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
+static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
+					 unsigned int timing)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	u32 mode;
+
+	switch (timing) {
+	case MMC_TIMING_MMC_HS:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
+		break;
+	case MMC_TIMING_MMC_DDR52:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
+		break;
+	case MMC_TIMING_MMC_HS400:
+		if (priv->enhanced_strobe)
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
+		else
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
+		break;
+	case MMC_TIMING_SD_HS:
+		mode = SDHCI_CDNS_HRS06_MODE_SD;
+		break;
+	default:
+		mode = SDHCI_CDNS_HRS06_MODE_LEGACY;
+		break;
+	}
+
+	pr_debug("%s mode %d timing %d\n", __func__, mode, timing);
+	sdhci_cdns_set_emmc_mode(priv, mode);
+
+	/* For SD, fall back to the default handler */
+	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
+		sdhci_set_uhs_signaling(host, timing);
+}
+
+static int sdhci_cdns_sd6_phy_update_timings(struct sdhci_host *host)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	struct sdhci_cdns_sd6_phy *phy = priv->phy;
+	int t_sdmclk = phy->t_sdmclk;
+	int mode;
+
+	mode = sdhci_cdns_sd6_get_mode(host, host->mmc->ios.timing);
+	/* initialize input */
+	init_timings[mode](&phy->t, phy->t_sdclk);
+
+	phy->mode = host->mmc->ios.timing;
+	phy->strobe_dat = false;
+
+	switch (phy->mode) {
+	case MMC_TIMING_UHS_SDR104:
+		phy->tune_cmd = true;
+		phy->tune_dat = true;
+		break;
+	case MMC_TIMING_UHS_DDR50:
+		phy->ddr = true;
+		break;
+	case MMC_TIMING_MMC_DDR52:
+		phy->ddr = true;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		phy->tune_dat = true;
+		phy->tune_cmd = true;
+		break;
+	case MMC_TIMING_MMC_HS400:
+		phy->tune_cmd = true;
+		phy->ddr = true;
+		phy->strobe_dat = true;
+		break;
+	}
+
+	if (priv->enhanced_strobe)
+		phy->strobe_cmd = true;
+
+	phy->d.phy_sdclk_delay = 2 * t_sdmclk;
+	phy->d.phy_cmd_o_delay = 2 * t_sdmclk + t_sdmclk / 2;
+	phy->d.phy_dat_o_delay = 2 * t_sdmclk + t_sdmclk / 2;
+
+	if (phy->t_sdclk == phy->t_sdmclk) {
+		phy->settings.sdhc_extended_wr_mode = 0;
+		phy->settings.sdhc_extended_rd_mode = 0;
+	} else {
+		phy->settings.sdhc_extended_wr_mode = 1;
+		phy->settings.sdhc_extended_rd_mode = 1;
+	}
+
+	phy->settings.cp_gate_cfg_always_on = 1;
+
+	sdhci_cdns_sd6_phy_configure_dll(phy);
+
+	sdhci_cdns_sd6_phy_calc_settings(phy);
+
+	return 0;
+}
+
+static u32 sdhci_cdns_sd6_get_mode(struct sdhci_host *host,
+				   unsigned int timing)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	u32 mode;
+
+	switch (timing) {
+	case MMC_TIMING_MMC_HS:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
+		break;
+	case MMC_TIMING_MMC_DDR52:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
+		break;
+	case MMC_TIMING_MMC_HS400:
+		if (priv->enhanced_strobe)
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
+		else
+			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
+		break;
+	case MMC_TIMING_SD_HS:
+		mode = SDHCI_CDNS_HRS06_MODE_SD;
+		break;
+	default:
+		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
+		break;
+	}
+
+	return mode;
+}
+
+static void sdhci_cdns_sd6_set_uhs_signaling(struct sdhci_host *host,
+					     unsigned int timing)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	struct sdhci_cdns_sd6_phy *phy = priv->phy;
+
+	sdhci_cdns_set_uhs_signaling(host, timing);
+
+	if ((phy->mode == -1) || (phy->t_sdclk == -1))
+		return;
+
+	if (sdhci_cdns_sd6_phy_update_timings(host))
+		pr_debug("%s: update timings failed\n", __func__);
+
+	if (sdhci_cdns_sd6_phy_init(priv))
+		pr_debug("%s: phy init failed\n", __func__);
+}
+
+static void sdhci_cdns_sd6_set_clock(struct sdhci_host *host,
+				     unsigned int clock)
+{
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
+	struct sdhci_cdns_sd6_phy *phy = priv->phy;
+
+	phy->t_sdclk = DIV_ROUND_DOWN_ULL(1e12, clock);
+
+	pr_debug("%s %d %d\n", __func__, phy->mode, clock);
+
+	if (sdhci_cdns_sd6_phy_update_timings(host))
+		pr_debug("%s: update timings failed\n", __func__);
+
+	if (sdhci_cdns_sd6_phy_init(priv))
+		pr_debug("%s: phy init failed\n", __func__);
+
+	sdhci_set_clock(host, clock);
+}
+
+static int sdhci_cdns_sd4_phy_probe(struct platform_device *pdev,
+				    struct sdhci_cdns_priv *priv)
+{
+	unsigned int nr_phy_params;
+	struct sdhci_cdns_sd4_phy *phy;
+	struct device *dev = &pdev->dev;
+
+	nr_phy_params = sdhci_cdns_sd4_phy_param_count(dev->of_node);
+	phy = devm_kzalloc(dev, struct_size(phy, phy_params, nr_phy_params),
+			   GFP_KERNEL);
+	if (!phy)
+		return -ENOMEM;
+
+	phy->nr_phy_params = nr_phy_params;
+
+	sdhci_cdns_sd4_phy_param_parse(dev->of_node, phy);
+	priv->phy = phy;
+
+	return 0;
+}
+
+static int sdhci_cdns_sd6_phy_probe(struct platform_device *pdev,
+				    struct sdhci_cdns_priv *priv)
+{
+	struct device *dev = &pdev->dev;
+	struct sdhci_cdns_sd6_phy *phy;
+	u32 val;
+	struct clk *clk;
+	int ret;
+	const char *mode_name;
+
+	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+	if (!phy)
+		return -ENOMEM;
+
+	clk = devm_clk_get(dev, "sdmclk");
+	if (IS_ERR(clk)) {
+		dev_err(dev, "sdmclk get error\n");
+		return PTR_ERR(clk);
+	}
+
+	val = clk_get_rate(clk);
+	phy->t_sdmclk = DIV_ROUND_DOWN_ULL(1e12, val);
+
+	ret = of_property_read_u32(dev->of_node, "cdns,host_slew",
+				   &phy->settings.slew);
+	if (ret)
+		phy->settings.slew = 3;
+
+	ret = of_property_read_u32(dev->of_node, "cdns,host_drive",
+				   &phy->settings.drive);
+	if (ret)
+		phy->settings.drive = 2;
+
+	ret = of_property_read_u32(dev->of_node, "cdns,iocell_input_delay",
+				   &phy->d.iocell_input_delay);
+	if (ret)
+		phy->d.iocell_input_delay = 2500;
+
+	ret = of_property_read_u32(dev->of_node, "cdns,iocell_output_delay",
+				   &phy->d.iocell_output_delay);
+	if (ret)
+		phy->d.iocell_output_delay = 2500;
+
+	ret = of_property_read_u32(dev->of_node, "cdns,delay_element",
+				   &phy->d.delay_element);
+	if (ret)
+		phy->d.delay_element = 24;
+
+	ret = of_property_read_string_index(dev->of_node, "cdns,mode", 0,
+					    &mode_name);
+	if (!ret) {
+		if (!strcmp("emmc_sdr", mode_name))
+			phy->mode = MMC_TIMING_MMC_HS;
+		else if (!strcmp("emmc_ddr", mode_name))
+			phy->mode = MMC_TIMING_MMC_DDR52;
+		else if (!strcmp("emmc_hs200", mode_name))
+			phy->mode = MMC_TIMING_MMC_HS200;
+		else if (!strcmp("emmc_hs400", mode_name))
+			phy->mode = MMC_TIMING_MMC_HS400;
+		else if (!strcmp("sd_hs", mode_name))
+			phy->mode = MMC_TIMING_SD_HS;
+		else
+			phy->mode = MMC_TIMING_MMC_HS;
+	} else {
+		phy->mode = MMC_TIMING_MMC_HS;
+	}
+
+	phy->d.delay_element_org = phy->d.delay_element;
+	phy->d.iocell_input_delay = 650;
+	phy->d.iocell_output_delay = 1800;
+
+	switch (phy->mode) {
+	case MMC_TIMING_MMC_HS:
+		phy->t_sdclk =  10000;
+		break;
+	case MMC_TIMING_MMC_DDR52:
+		phy->t_sdclk = 10000;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		phy->t_sdclk = 5000;
+		break;
+	case MMC_TIMING_MMC_HS400:
+		phy->t_sdclk = 5000;
+		break;
+	case MMC_TIMING_SD_HS:
+		phy->t_sdclk = 100000;
+		break;
+	default:
+		phy->t_sdclk = 10000;
+		break;
+	}
+
+	priv->phy = phy;
+
+	sdhci_cdns_sd6_get_delay_params(dev, priv);
+
+	sdhci_cdns_sd6_calc_phy(phy);
+	return 0;
+}
+
+static int sdhci_cdns_sd4_set_tune_val(struct sdhci_host *host, unsigned int val)
 {
 	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
 	void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
@@ -239,12 +1478,13 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
  * In SD mode, software must not use the hardware tuning and instead perform
  * an almost identical procedure to eMMC.
  */
-static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
+static int sdhci_cdns_sd6_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
+	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
 	int cur_streak = 0;
 	int max_streak = 0;
 	int end_of_streak = 0;
-	int i;
+	int i, midpoint, iter = 0;
 
 	/*
 	 * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
@@ -254,8 +1494,8 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 	    host->timing != MMC_TIMING_UHS_SDR104)
 		return 0;
 
-	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
-		if (sdhci_cdns_set_tune_val(host, i) ||
+	for (i = tune_val_start; iter < max_tune_iter; iter++, i += tune_val_step) {
+		if (priv->cdns_data->set_tune_val(host, i) ||
 		    mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
 			cur_streak = 0;
 		} else { /* good */
@@ -263,6 +1503,12 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 			if (cur_streak > max_streak) {
 				max_streak = cur_streak;
 				end_of_streak = i;
+				pr_debug("%s (%d-%d = %d)", __func__,
+					 end_of_streak - ((cur_streak - 1) * tune_val_step),
+					 end_of_streak, cur_streak);
+			} else {
+				pr_debug("%s (%d-%d)", __func__,
+					 i - ((cur_streak - 1) * tune_val_step), i);
 			}
 		}
 	}
@@ -272,44 +1518,55 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 		return -EIO;
 	}
 
-	return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
+	pr_debug("max_streak: %d-%d", end_of_streak - ((max_streak - 1) * tune_val_step),
+		 end_of_streak);
+
+	midpoint = end_of_streak - (((max_streak - 1) * tune_val_step) / 2);
+
+	return priv->cdns_data->set_tune_val(host, midpoint);
 }
 
-static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
-					 unsigned int timing)
+/*
+ * In SD mode, software must not use the hardware tuning and instead perform
+ * an almost identical procedure to eMMC.
+ */
+static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
-	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
-	u32 mode;
+	int cur_streak = 0;
+	int max_streak = 0;
+	int end_of_streak = 0;
+	int i;
 
-	switch (timing) {
-	case MMC_TIMING_MMC_HS:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
-		break;
-	case MMC_TIMING_MMC_DDR52:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
-		break;
-	case MMC_TIMING_MMC_HS200:
-		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
-		break;
-	case MMC_TIMING_MMC_HS400:
-		if (priv->enhanced_strobe)
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
-		else
-			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
-		break;
-	default:
-		mode = SDHCI_CDNS_HRS06_MODE_SD;
-		break;
+	/*
+	 * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
+	 * The delay is set by probe, based on the DT properties.
+	 */
+	if (host->timing != MMC_TIMING_MMC_HS200 &&
+	    host->timing != MMC_TIMING_UHS_SDR104)
+		return 0;
+
+	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
+		if (sdhci_cdns_sd4_set_tune_val(host, i) ||
+		    mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
+			cur_streak = 0;
+		} else { /* good */
+			cur_streak++;
+			if (cur_streak > max_streak) {
+				max_streak = cur_streak;
+				end_of_streak = i;
+			}
+		}
 	}
 
-	sdhci_cdns_set_emmc_mode(priv, mode);
+	if (!max_streak) {
+		dev_err(mmc_dev(host->mmc), "no tuning point found\n");
+		return -EIO;
+	}
 
-	/* For SD, fall back to the default handler */
-	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
-		sdhci_set_uhs_signaling(host, timing);
+	return sdhci_cdns_sd4_set_tune_val(host, end_of_streak - max_streak / 2);
 }
 
-static const struct sdhci_ops sdhci_cdns_ops = {
+static const struct sdhci_ops sdhci_cdns_sd4_ops = {
 	.set_clock = sdhci_set_clock,
 	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
 	.set_bus_width = sdhci_set_bus_width,
@@ -318,13 +1575,49 @@ static const struct sdhci_ops sdhci_cdns_ops = {
 	.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
 };
 
+static const struct sdhci_ops sdhci_cdns_sd6_ops = {
+	.get_max_clock = sdhci_cdns_get_max_clock,
+	.set_clock = sdhci_cdns_sd6_set_clock,
+	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
+	.set_bus_width = sdhci_set_bus_width,
+	.reset = sdhci_reset,
+	.platform_execute_tuning = sdhci_cdns_sd6_execute_tuning,
+	.set_uhs_signaling = sdhci_cdns_sd6_set_uhs_signaling,
+};
+
 static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
-	.ops = &sdhci_cdns_ops,
+	.ops = &sdhci_cdns_sd4_ops,
 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 };
 
-static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
-	.ops = &sdhci_cdns_ops,
+static const struct sdhci_pltfm_data sdhci_cdns_sd4_pltfm_data = {
+	.ops = &sdhci_cdns_sd4_ops,
+};
+
+static const struct sdhci_pltfm_data sdhci_cdns_sd6_pltfm_data = {
+	.ops = &sdhci_cdns_sd6_ops,
+};
+
+static const struct sdhci_cdns_data sdhci_cdns_sd4_data = {
+	.phy_init = sdhci_cdns_sd4_phy_init,
+	.set_tune_val = sdhci_cdns_sd4_set_tune_val,
+};
+
+static const struct sdhci_cdns_data sdhci_cdns_sd6_data = {
+	.phy_init = sdhci_cdns_sd6_phy_init,
+	.set_tune_val = sdhci_cdns_sd6_set_tune_val,
+};
+
+static const struct sdhci_cdns_of_data sdhci_cdns_sd4_of_data = {
+	.pltfm_data = &sdhci_cdns_sd4_pltfm_data,
+	.cdns_data = &sdhci_cdns_sd4_data,
+	.phy_probe = sdhci_cdns_sd4_phy_probe,
+};
+
+static const struct sdhci_cdns_of_data sdhci_cdns_sd6_of_data = {
+	.pltfm_data = &sdhci_cdns_sd6_pltfm_data,
+	.cdns_data = &sdhci_cdns_sd6_data,
+	.phy_probe = sdhci_cdns_sd6_phy_probe,
 };
 
 static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
@@ -350,14 +1643,12 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
 static int sdhci_cdns_probe(struct platform_device *pdev)
 {
 	struct sdhci_host *host;
-	const struct sdhci_pltfm_data *data;
+	const struct sdhci_cdns_of_data *data;
 	struct sdhci_pltfm_host *pltfm_host;
 	struct sdhci_cdns_priv *priv;
 	struct clk *clk;
-	unsigned int nr_phy_params;
 	int ret;
 	struct device *dev = &pdev->dev;
-	static const u16 version = SDHCI_SPEC_400 << SDHCI_SPEC_VER_SHIFT;
 
 	clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(clk))
@@ -368,12 +1659,12 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
 		return ret;
 
 	data = of_device_get_match_data(dev);
-	if (!data)
-		data = &sdhci_cdns_pltfm_data;
+	if (!data) {
+		return PTR_ERR(clk);
+		goto disable_clk;
+	}
 
-	nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
-	host = sdhci_pltfm_init(pdev, data,
-				struct_size(priv, phy_params, nr_phy_params));
+	host = sdhci_pltfm_init(pdev, data->pltfm_data, sizeof(*priv));
 	if (IS_ERR(host)) {
 		ret = PTR_ERR(host);
 		goto disable_clk;
@@ -382,15 +1673,17 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
 	pltfm_host = sdhci_priv(host);
 	pltfm_host->clk = clk;
 
+	host->clk_mul = 0;
+	host->max_clk = SDMCLK_MAX_FREQ;
+	host->quirks |=  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
+	host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
 	priv = sdhci_pltfm_priv(pltfm_host);
-	priv->nr_phy_params = nr_phy_params;
 	priv->hrs_addr = host->ioaddr;
 	priv->enhanced_strobe = false;
+	priv->cdns_data = data->cdns_data;
 	host->ioaddr += SDHCI_CDNS_SRS_BASE;
 	host->mmc_host_ops.hs400_enhanced_strobe =
 				sdhci_cdns_hs400_enhanced_strobe;
-	sdhci_enable_v4_mode(host);
-	__sdhci_read_caps(host, &version, NULL, NULL);
 
 	sdhci_get_of_property(pdev);
 
@@ -398,12 +1691,16 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
 	if (ret)
 		goto free;
 
-	sdhci_cdns_phy_param_parse(dev->of_node, priv);
+	ret = data->phy_probe(pdev, priv);
+	if (ret)
+		goto free;
 
-	ret = sdhci_cdns_phy_init(priv);
+	ret = priv->cdns_data->phy_init(priv);
 	if (ret)
 		goto free;
 
+	sdhci_enable_v4_mode(host);
+	__sdhci_read_caps(host, NULL, NULL, NULL);
 	ret = sdhci_add_host(host);
 	if (ret)
 		goto free;
@@ -429,7 +1726,7 @@ static int sdhci_cdns_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	ret = sdhci_cdns_phy_init(priv);
+	ret = priv->cdns_data->phy_init(priv);
 	if (ret)
 		goto disable_clk;
 
@@ -455,7 +1752,14 @@ static const struct of_device_id sdhci_cdns_match[] = {
 		.compatible = "socionext,uniphier-sd4hc",
 		.data = &sdhci_cdns_uniphier_pltfm_data,
 	},
-	{ .compatible = "cdns,sd4hc" },
+	{
+		.compatible = "cdns,sd4hc",
+		.data = &sdhci_cdns_sd4_of_data,
+	},
+	{
+		.compatible = "cdns,sd6hc",
+		.data = &sdhci_cdns_sd6_of_data,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sdhci_cdns_match);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS
  2022-12-19 14:24 [PATCH 0/5] drivers: mmc: sdhci-cadence: SD6 controller support Piyush Malgujar
  2022-12-19 14:24 ` [PATCH 1/5] " Piyush Malgujar
@ 2022-12-19 14:24 ` Piyush Malgujar
  2023-01-11  8:23   ` Adrian Hunter
  2022-12-19 14:24 ` [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support Piyush Malgujar
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 19+ messages in thread
From: Piyush Malgujar @ 2022-12-19 14:24 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva, Piyush Malgujar

From: Jayanthi Annadurai <jannadurai@marvell.com>

Add support for CONFIG_MMC_SDHCI_IO_ACCESSORS for controller
specific register read and write APIs.

Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
---
 drivers/mmc/host/Kconfig         | 12 ++++++
 drivers/mmc/host/sdhci-cadence.c | 63 ++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5e19a961c34d7b5664ab2fd43cfba82dc90913ac..b5b2ae0bb4625bdb9d17acdbb1887c9caa3a1f32 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -262,6 +262,18 @@ config MMC_SDHCI_CADENCE
 
 	  If unsure, say N.
 
+config MMC_SDHCI_CN10K
+	tristate "SDHCI Cadence support for Marvell CN10K platforms"
+	select MMC_SDHCI_CADENCE
+	select MMC_SDHCI_IO_ACCESSORS
+	help
+	  This selects the SDHCI cadence driver and IO Accessors
+	  for Marvell CN10K platforms
+
+	  If you have Marvell CN10K platform, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_SDHCI_CNS3XXX
 	tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
 	depends on ARCH_CNS3XXX || COMPILE_TEST
diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 5332d19e489be936d6814feba4f0fc046f5e130e..6bf703f15bc5be7e3be4cb1144b78ec3585ec540 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -449,6 +449,61 @@ static u32 read_dqs_cmd_delay, clk_wrdqs_delay, clk_wr_delay, read_dqs_delay;
 
 static u32 sdhci_cdns_sd6_get_mode(struct sdhci_host *host, unsigned int timing);
 
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+static u32 sdhci_cdns_sd6_readl(struct sdhci_host *host, int reg)
+{
+	return readl(host->ioaddr + reg);
+}
+
+static void sdhci_cdns_sd6_writel(struct sdhci_host *host, u32 val, int reg)
+{
+	writel(val, host->ioaddr + reg);
+}
+
+static u16 sdhci_cdns_sd6_readw(struct sdhci_host *host, int reg)
+{
+	u32 val, regoff;
+
+	regoff = reg & ~3;
+
+	val = readl(host->ioaddr + regoff);
+	if ((reg & 0x3) == 0)
+		return (val & 0xFFFF);
+	else
+		return ((val >> 16) & 0xFFFF);
+}
+
+static void sdhci_cdns_sd6_writew(struct sdhci_host *host, u16 val, int reg)
+{
+	writew(val, host->ioaddr + reg);
+}
+
+static u8 sdhci_cdns_sd6_readb(struct sdhci_host *host, int reg)
+{
+	u32 val, regoff;
+
+	regoff = reg & ~3;
+
+	val = readl(host->ioaddr + regoff);
+	switch (reg & 3) {
+	case 0:
+		return (val & 0xFF);
+	case 1:
+		return ((val >> 8) & 0xFF);
+	case 2:
+		return ((val >> 16) & 0xFF);
+	case 3:
+		return ((val >> 24) & 0xFF);
+	}
+	return 0;
+}
+
+static void sdhci_cdns_sd6_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+	writeb(val, host->ioaddr + reg);
+}
+#endif
+
 static int sdhci_cdns_sd6_phy_lock_dll(struct sdhci_cdns_sd6_phy *phy)
 {
 	u32 delay_element = phy->d.delay_element_org;
@@ -1576,6 +1631,14 @@ static const struct sdhci_ops sdhci_cdns_sd4_ops = {
 };
 
 static const struct sdhci_ops sdhci_cdns_sd6_ops = {
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+	.read_l = sdhci_cdns_sd6_readl,
+	.write_l = sdhci_cdns_sd6_writel,
+	.read_w = sdhci_cdns_sd6_readw,
+	.write_w = sdhci_cdns_sd6_writew,
+	.read_b = sdhci_cdns_sd6_readb,
+	.write_b = sdhci_cdns_sd6_writeb,
+#endif
 	.get_max_clock = sdhci_cdns_get_max_clock,
 	.set_clock = sdhci_cdns_sd6_set_clock,
 	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support
  2022-12-19 14:24 [PATCH 0/5] drivers: mmc: sdhci-cadence: SD6 controller support Piyush Malgujar
  2022-12-19 14:24 ` [PATCH 1/5] " Piyush Malgujar
  2022-12-19 14:24 ` [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS Piyush Malgujar
@ 2022-12-19 14:24 ` Piyush Malgujar
  2022-12-19 15:40   ` Krzysztof Kozlowski
  2022-12-19 14:24 ` [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout Piyush Malgujar
  2022-12-19 14:24 ` [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver Piyush Malgujar
  4 siblings, 1 reply; 19+ messages in thread
From: Piyush Malgujar @ 2022-12-19 14:24 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva, Piyush Malgujar

From: Jayanthi Annadurai <jannadurai@marvell.com>

Add support for SD6 controller support

Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
---
 .../devicetree/bindings/mmc/cdns,sdhci.yaml   | 33 +++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
index 8b1a0fdcb5e3e2e8b87d8d7678e37f3dad447fc1..2043e78ccd5f708a01e87fd96ec410418fcd539f 100644
--- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/mmc/cdns,sdhci.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Cadence SD/SDIO/eMMC Host Controller (SD4HC)
+title: Cadence SD/SDIO/eMMC Host Controller (SD4HC, SD6HC)
 
 maintainers:
   - Masahiro Yamada <yamada.masahiro@socionext.com>
@@ -19,6 +19,7 @@ properties:
           - microchip,mpfs-sd4hc
           - socionext,uniphier-sd4hc
       - const: cdns,sd4hc
+      - const: cdns,sd6hc
 
   reg:
     maxItems: 1
@@ -111,6 +112,34 @@ properties:
     minimum: 0
     maximum: 0x7f
 
+  cdns,iocell_input_delay:
+    description: Delay in ps across the input IO cells
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
+  cdns,iocell_output_delay:
+    description: Delay in ps across the output IO cells
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
+  cdns,delay_element:
+    description: Delay element in ps used for calculating phy timings
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
+  cdns,read_dqs_cmd_delay:
+    description: Command delay used in HS200 tuning
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
+  cdns,tune_val_start:
+    description: Staring value of data delay used in HS200 tuning
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
+  cdns,tune_val_step:
+    description: Incremental value of data delay used in HS200 tuning
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
+  cdns,max_tune_iter:
+    description: Maximum number of iterations to complete the HS200 tuning process
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
 required:
   - compatible
   - reg
@@ -122,7 +151,7 @@ unevaluatedProperties: false
 examples:
   - |
     emmc: mmc@5a000000 {
-        compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc";
+        compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc", "cdns,sd6hc";
         reg = <0x5a000000 0x400>;
         interrupts = <0 78 4>;
         clocks = <&clk 4>;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout
  2022-12-19 14:24 [PATCH 0/5] drivers: mmc: sdhci-cadence: SD6 controller support Piyush Malgujar
                   ` (2 preceding siblings ...)
  2022-12-19 14:24 ` [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support Piyush Malgujar
@ 2022-12-19 14:24 ` Piyush Malgujar
  2023-01-11  8:08   ` Adrian Hunter
  2022-12-19 14:24 ` [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver Piyush Malgujar
  4 siblings, 1 reply; 19+ messages in thread
From: Piyush Malgujar @ 2022-12-19 14:24 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva, Piyush Malgujar

From: Jayanthi Annadurai <jannadurai@marvell.com>

Add config option to choose the sdhci timeout in seconds.

Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
---
 drivers/mmc/host/Kconfig | 8 ++++++++
 drivers/mmc/host/sdhci.c | 3 ++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index b5b2ae0bb4625bdb9d17acdbb1887c9caa3a1f32..ab48f2bc4cff73d1aad8d7da542d761cf0346d9f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -1132,3 +1132,11 @@ config MMC_LITEX
 	  module will be called litex_mmc.
 
 	  If unsure, say N.
+
+config MMC_SDHCI_TIMEOUT
+	int
+	default 1 if MMC_SDHCI_CADENCE
+	default 10
+	depends on MMC_SDHCI
+	help
+	  Default timeout value for command and data.
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f3af1bd0f7b955272fbd8b034ecb591860b89aed..e9bc24258746834ec9c8f13fe24456587a2b758d 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1707,7 +1707,8 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 	else if (!cmd->data && cmd->busy_timeout > 9000)
 		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
 	else
-		timeout += 10 * HZ;
+		timeout += CONFIG_MMC_SDHCI_TIMEOUT * HZ;
+
 	sdhci_mod_timer(host, cmd->mrq, timeout);
 
 	if (host->use_external_dma)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver.
  2022-12-19 14:24 [PATCH 0/5] drivers: mmc: sdhci-cadence: SD6 controller support Piyush Malgujar
                   ` (3 preceding siblings ...)
  2022-12-19 14:24 ` [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout Piyush Malgujar
@ 2022-12-19 14:24 ` Piyush Malgujar
  2023-01-11  8:29   ` Adrian Hunter
  4 siblings, 1 reply; 19+ messages in thread
From: Piyush Malgujar @ 2022-12-19 14:24 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva, Piyush Malgujar

From: Jayanthi Annadurai <jannadurai@marvell.com>

Use Kernel config CONFIG_MMC_DEBUG to support dumping PHY and host
controller register configuration for debug.

Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
---
 drivers/mmc/host/sdhci-cadence.c | 100 +++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 6bf703f15bc5be7e3be4cb1144b78ec3585ec540..75363aabce9228755c4abed08fe17e57d1a44b23 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -15,6 +15,10 @@
 
 #include "sdhci-pltfm.h"
 
+#ifdef CONFIG_MMC_DEBUG
+#define DEBUG_DRV	pr_info
+#endif
+
 #define SDMCLK_MAX_FREQ		200000000
 
 #define DEFAULT_CMD_DELAY		16
@@ -115,6 +119,10 @@
 #define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WR_DELAY		GENMASK(15, 8)
 #define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_DELAY		GENMASK(7, 0)
 
+#define SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0				0x201C
+#define SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1				0x2020
+#define SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2				0x2024
+
 #define SDHCI_CDNS_SD6_PHY_CTRL					0x2080
 #define	SDHCI_CDNS_SD6_PHY_CTRL_PHONY_DQS_TIMING		GENMASK(9, 4)
 
@@ -969,6 +977,94 @@ static void sdhci_cdns_sd6_calc_phy(struct sdhci_cdns_sd6_phy *phy)
 	}
 }
 
+#ifdef CONFIG_MMC_DEBUG
+static void sdhci_cdns_sd6_phy_dump(struct sdhci_cdns_sd6_phy *phy)
+{
+	DEBUG_DRV("PHY Timings\n");
+	DEBUG_DRV("mode %d t_sdclk %d\n", phy->mode, phy->t_sdclk);
+
+	DEBUG_DRV("cp_clk_wr_delay %d\n", phy->settings.cp_clk_wr_delay);
+	DEBUG_DRV("cp_clk_wrdqs_delay %d\n", phy->settings.cp_clk_wrdqs_delay);
+	DEBUG_DRV("cp_data_select_oe_end %d\n", phy->settings.cp_data_select_oe_end);
+	DEBUG_DRV("cp_dll_bypass_mode %d\n", phy->settings.cp_dll_bypass_mode);
+	DEBUG_DRV("cp_dll_locked_mode %d\n", phy->settings.cp_dll_locked_mode);
+	DEBUG_DRV("cp_dll_start_point %d\n", phy->settings.cp_dll_start_point);
+	DEBUG_DRV("cp_io_mask_always_on %d\n", phy->settings.cp_io_mask_always_on);
+	DEBUG_DRV("cp_io_mask_end %d\n", phy->settings.cp_io_mask_end);
+	DEBUG_DRV("cp_io_mask_start %d\n", phy->settings.cp_io_mask_start);
+	DEBUG_DRV("cp_rd_del_sel %d\n", phy->settings.cp_rd_del_sel);
+	DEBUG_DRV("cp_read_dqs_cmd_delay %d\n", phy->settings.cp_read_dqs_cmd_delay);
+	DEBUG_DRV("cp_read_dqs_delay %d\n", phy->settings.cp_read_dqs_delay);
+	DEBUG_DRV("cp_sw_half_cycle_shift %d\n", phy->settings.cp_sw_half_cycle_shift);
+	DEBUG_DRV("cp_sync_method %d\n", phy->settings.cp_sync_method);
+	DEBUG_DRV("cp_use_ext_lpbk_dqs %d\n", phy->settings.cp_use_ext_lpbk_dqs);
+	DEBUG_DRV("cp_use_lpbk_dqs %d\n", phy->settings.cp_use_lpbk_dqs);
+	DEBUG_DRV("cp_use_phony_dqs %d\n", phy->settings.cp_use_phony_dqs);
+	DEBUG_DRV("cp_use_phony_dqs_cmd %d\n", phy->settings.cp_use_phony_dqs_cmd);
+	DEBUG_DRV("sdhc_extended_rd_mode %d\n", phy->settings.sdhc_extended_rd_mode);
+	DEBUG_DRV("sdhc_extended_wr_mode %d\n", phy->settings.sdhc_extended_wr_mode);
+
+	DEBUG_DRV("sdhc_hcsdclkadj %d\n", phy->settings.sdhc_hcsdclkadj);
+	DEBUG_DRV("sdhc_idelay_val %d\n", phy->settings.sdhc_idelay_val);
+	DEBUG_DRV("sdhc_rdcmd_en %d\n", phy->settings.sdhc_rdcmd_en);
+	DEBUG_DRV("sdhc_rddata_en %d\n", phy->settings.sdhc_rddata_en);
+	DEBUG_DRV("sdhc_rw_compensate %d\n", phy->settings.sdhc_rw_compensate);
+	DEBUG_DRV("sdhc_sdcfsh %d\n", phy->settings.sdhc_sdcfsh);
+	DEBUG_DRV("sdhc_sdcfsl %d\n", phy->settings.sdhc_sdcfsl);
+	DEBUG_DRV("sdhc_wrcmd0_dly %d %d\n",
+		  phy->settings.sdhc_wrcmd0_dly, phy->settings.sdhc_wrcmd0_sdclk_dly);
+	DEBUG_DRV("sdhc_wrcmd1_dly %d %d\n",
+		  phy->settings.sdhc_wrcmd1_dly, phy->settings.sdhc_wrcmd1_sdclk_dly);
+	DEBUG_DRV("sdhc_wrdata0_dly %d %d\n",
+		  phy->settings.sdhc_wrdata0_dly, phy->settings.sdhc_wrdata0_sdclk_dly);
+
+	DEBUG_DRV("sdhc_wrdata1_dly %d %d\n",
+		  phy->settings.sdhc_wrdata1_dly, phy->settings.sdhc_wrdata1_sdclk_dly);
+	DEBUG_DRV("hs200_tune_val %d\n", phy->settings.hs200_tune_val);
+}
+
+void sdhci_cdns_sd6_dump(struct sdhci_cdns_priv *priv)
+{
+	struct sdhci_cdns_sd6_phy *phy = priv->phy;
+	int id;
+
+	sdhci_cdns_sd6_phy_dump(phy);
+
+	DEBUG_DRV("Host controller Register Dump\n");
+	for (id = 0; id < 14; id++)
+		DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
+
+	id = 29;
+	DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
+	id = 30;
+	DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
+
+	for (id = 0; id < 27; id++)
+		DEBUG_DRV("SRS%d 0x%x\n", id, readl(priv->hrs_addr + 0x200 + (id * 4)));
+
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DQS_TIMING 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQS_TIMING));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_GATE_LPBK 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GATE_LPBK));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_MASTER 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_MASTER));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_SLAVE 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_SLAVE));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_CTRL 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_CTRL));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_GPIO_CTRL0 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GPIO_CTRL0));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DQ_TIMING 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQ_TIMING));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1));
+	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2 0x%x\n",
+		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2));
+}
+#endif
+
 static int sdhci_cdns_sd6_get_delay_params(struct device *dev, struct sdhci_cdns_priv *priv)
 {
 	struct sdhci_cdns_sd6_phy *phy = priv->phy;
@@ -1373,6 +1469,10 @@ static void sdhci_cdns_sd6_set_clock(struct sdhci_host *host,
 		pr_debug("%s: phy init failed\n", __func__);
 
 	sdhci_set_clock(host, clock);
+
+#ifdef CONFIG_MMC_DEBUG
+	sdhci_cdns_sd6_dump(priv);
+#endif
 }
 
 static int sdhci_cdns_sd4_phy_probe(struct platform_device *pdev,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support
  2022-12-19 14:24 ` [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support Piyush Malgujar
@ 2022-12-19 15:40   ` Krzysztof Kozlowski
  2023-01-06 16:48     ` Piyush Malgujar
  0 siblings, 1 reply; 19+ messages in thread
From: Krzysztof Kozlowski @ 2022-12-19 15:40 UTC (permalink / raw)
  To: Piyush Malgujar, linux-mmc, linux-kernel, adrian.hunter,
	ulf.hansson, robh+dt, krzysztof.kozlowski+dt, yamada.masahiro,
	devicetree
  Cc: jannadurai, cchavva

On 19/12/2022 15:24, Piyush Malgujar wrote:
> From: Jayanthi Annadurai <jannadurai@marvell.com>
> 

Subject: use final prefix matching the file, so "cdns,sdhci:"

> Add support for SD6 controller support

Full stop.

> 
> Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> ---
>  .../devicetree/bindings/mmc/cdns,sdhci.yaml   | 33 +++++++++++++++++--
>  1 file changed, 31 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> index 8b1a0fdcb5e3e2e8b87d8d7678e37f3dad447fc1..2043e78ccd5f708a01e87fd96ec410418fcd539f 100644
> --- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> +++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> @@ -4,7 +4,7 @@
>  $id: http://devicetree.org/schemas/mmc/cdns,sdhci.yaml#
>  $schema: http://devicetree.org/meta-schemas/core.yaml#
>  
> -title: Cadence SD/SDIO/eMMC Host Controller (SD4HC)
> +title: Cadence SD/SDIO/eMMC Host Controller (SD4HC, SD6HC)
>  
>  maintainers:
>    - Masahiro Yamada <yamada.masahiro@socionext.com>
> @@ -19,6 +19,7 @@ properties:
>            - microchip,mpfs-sd4hc
>            - socionext,uniphier-sd4hc
>        - const: cdns,sd4hc
> +      - const: cdns,sd6hc

Does not look like you tested the DTS against bindings. Please run `make
dtbs_check` (see Documentation/devicetree/bindings/writing-schema.rst
for instructions).

... because it does not really make sense. Why do you require SD6HC as
fallback? I think you meant enum.

>  
>    reg:
>      maxItems: 1
> @@ -111,6 +112,34 @@ properties:
>      minimum: 0
>      maximum: 0x7f
>  
> +  cdns,iocell_input_delay:

No underscores. Use proper units in name suffix:
https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/property-units.yaml


> +    description: Delay in ps across the input IO cells
> +    $ref: "/schemas/types.yaml#/definitions/uint32"

Ditto... and so on - all of the fields.

> +
> +  cdns,iocell_output_delay:
> +    description: Delay in ps across the output IO cells
> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> +
> +  cdns,delay_element:
> +    description: Delay element in ps used for calculating phy timings
> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> +
> +  cdns,read_dqs_cmd_delay:
> +    description: Command delay used in HS200 tuning
> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> +
> +  cdns,tune_val_start:
> +    description: Staring value of data delay used in HS200 tuning
> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> +
> +  cdns,tune_val_step:
> +    description: Incremental value of data delay used in HS200 tuning
> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> +
> +  cdns,max_tune_iter:
> +    description: Maximum number of iterations to complete the HS200 tuning process
> +    $ref: "/schemas/types.yaml#/definitions/uint32"

Why these three are properties of DT?

> +
>  required:
>    - compatible
>    - reg
> @@ -122,7 +151,7 @@ unevaluatedProperties: false
>  examples:
>    - |
>      emmc: mmc@5a000000 {
> -        compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc";
> +        compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc", "cdns,sd6hc";

This is confusing. I don't understand it. It requires much more
explanation in your commit msg.

>          reg = <0x5a000000 0x400>;
>          interrupts = <0 78 4>;
>          clocks = <&clk 4>;

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support
  2022-12-19 14:24 ` [PATCH 1/5] " Piyush Malgujar
@ 2022-12-19 15:41   ` Krzysztof Kozlowski
  2022-12-23 11:07   ` Dan Carpenter
  2023-01-11  8:19   ` Adrian Hunter
  2 siblings, 0 replies; 19+ messages in thread
From: Krzysztof Kozlowski @ 2022-12-19 15:41 UTC (permalink / raw)
  To: Piyush Malgujar, linux-mmc, linux-kernel, adrian.hunter,
	ulf.hansson, robh+dt, krzysztof.kozlowski+dt, yamada.masahiro,
	devicetree
  Cc: jannadurai, cchavva, Dhananjay Kangude

On 19/12/2022 15:24, Piyush Malgujar wrote:
> From: Dhananjay Kangude <dkangude@cadence.com>
> 
> This patch includes changes done to support SD6 controller:

Do not use "This commit/patch".
https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95

> - Added SD6 related ops which are isolated from SD4
> - changes to support HS400, HS400ES emmc mode
> - Updated HS200 tuning values and support to read tune configuration
>   from FDT.
> - Support to configure host side drive strength and slew
>   and read it from device tree
> 


(...)

>  
> @@ -455,7 +1752,14 @@ static const struct of_device_id sdhci_cdns_match[] = {
>  		.compatible = "socionext,uniphier-sd4hc",
>  		.data = &sdhci_cdns_uniphier_pltfm_data,
>  	},
> -	{ .compatible = "cdns,sd4hc" },
> +	{
> +		.compatible = "cdns,sd4hc",
> +		.data = &sdhci_cdns_sd4_of_data,
> +	},
> +	{
> +		.compatible = "cdns,sd6hc",
> +		.data = &sdhci_cdns_sd6_of_data,
> +	},

Your bindings said something different - every sd4hc is compatible with
sd6hc.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support
  2022-12-19 14:24 ` [PATCH 1/5] " Piyush Malgujar
  2022-12-19 15:41   ` Krzysztof Kozlowski
@ 2022-12-23 11:07   ` Dan Carpenter
  2023-01-11  8:19   ` Adrian Hunter
  2 siblings, 0 replies; 19+ messages in thread
From: Dan Carpenter @ 2022-12-23 11:07 UTC (permalink / raw)
  To: oe-kbuild, Piyush Malgujar, linux-mmc, linux-kernel,
	adrian.hunter, ulf.hansson, robh+dt, krzysztof.kozlowski+dt,
	yamada.masahiro, devicetree
  Cc: lkp, oe-kbuild-all, jannadurai, cchavva, Dhananjay Kangude,
	Piyush Malgujar

Hi Piyush,

https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Piyush-Malgujar/drivers-mmc-sdhci-cadence-SD6-controller-support/20221219-222703
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20221219142418.27949-2-pmalgujar%40marvell.com
patch subject: [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support
config: m68k-randconfig-m041-20221218
compiler: m68k-linux-gcc (GCC) 12.1.0

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>

smatch warnings:
drivers/mmc/host/sdhci-cadence.c:1663 sdhci_cdns_probe() warn: passing zero to 'PTR_ERR'
drivers/mmc/host/sdhci-cadence.c:1664 sdhci_cdns_probe() warn: ignoring unreachable code.

vim +/PTR_ERR +1663 drivers/mmc/host/sdhci-cadence.c

d12990f9900f49 Piotr Sroka       2017-03-06  1642  
ff6af28faff53a Masahiro Yamada   2016-12-08  1643  static int sdhci_cdns_probe(struct platform_device *pdev)
ff6af28faff53a Masahiro Yamada   2016-12-08  1644  {
ff6af28faff53a Masahiro Yamada   2016-12-08  1645  	struct sdhci_host *host;
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1646  	const struct sdhci_cdns_of_data *data;
ff6af28faff53a Masahiro Yamada   2016-12-08  1647  	struct sdhci_pltfm_host *pltfm_host;
ff6af28faff53a Masahiro Yamada   2016-12-08  1648  	struct sdhci_cdns_priv *priv;
ff6af28faff53a Masahiro Yamada   2016-12-08  1649  	struct clk *clk;
ff6af28faff53a Masahiro Yamada   2016-12-08  1650  	int ret;
a89c472d8b55c5 Piotr Sroka       2017-03-21  1651  	struct device *dev = &pdev->dev;
ff6af28faff53a Masahiro Yamada   2016-12-08  1652  
edf98579065950 Piotr Sroka       2017-03-21  1653  	clk = devm_clk_get(dev, NULL);
ff6af28faff53a Masahiro Yamada   2016-12-08  1654  	if (IS_ERR(clk))
ff6af28faff53a Masahiro Yamada   2016-12-08  1655  		return PTR_ERR(clk);
ff6af28faff53a Masahiro Yamada   2016-12-08  1656  
ff6af28faff53a Masahiro Yamada   2016-12-08  1657  	ret = clk_prepare_enable(clk);
ff6af28faff53a Masahiro Yamada   2016-12-08  1658  	if (ret)
ff6af28faff53a Masahiro Yamada   2016-12-08  1659  		return ret;
ff6af28faff53a Masahiro Yamada   2016-12-08  1660  
18b587b45c13bb Masahiro Yamada   2020-03-12  1661  	data = of_device_get_match_data(dev);
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1662  	if (!data) {
8bcfc23a884699 Dhananjay Kangude 2022-12-19 @1663  		return PTR_ERR(clk);

ret = -EINVAL?

8bcfc23a884699 Dhananjay Kangude 2022-12-19 @1664  		goto disable_clk;

Dead code.

8bcfc23a884699 Dhananjay Kangude 2022-12-19  1665  	}
18b587b45c13bb Masahiro Yamada   2020-03-12  1666  
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1667  	host = sdhci_pltfm_init(pdev, data->pltfm_data, sizeof(*priv));
ff6af28faff53a Masahiro Yamada   2016-12-08  1668  	if (IS_ERR(host)) {
ff6af28faff53a Masahiro Yamada   2016-12-08  1669  		ret = PTR_ERR(host);
ff6af28faff53a Masahiro Yamada   2016-12-08  1670  		goto disable_clk;
ff6af28faff53a Masahiro Yamada   2016-12-08  1671  	}
ff6af28faff53a Masahiro Yamada   2016-12-08  1672  
ff6af28faff53a Masahiro Yamada   2016-12-08  1673  	pltfm_host = sdhci_priv(host);
ff6af28faff53a Masahiro Yamada   2016-12-08  1674  	pltfm_host->clk = clk;
ff6af28faff53a Masahiro Yamada   2016-12-08  1675  
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1676  	host->clk_mul = 0;
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1677  	host->max_clk = SDMCLK_MAX_FREQ;
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1678  	host->quirks |=  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1679  	host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
a232a8f2d10750 Masahiro Yamada   2017-08-23  1680  	priv = sdhci_pltfm_priv(pltfm_host);
ff6af28faff53a Masahiro Yamada   2016-12-08  1681  	priv->hrs_addr = host->ioaddr;
d12990f9900f49 Piotr Sroka       2017-03-06  1682  	priv->enhanced_strobe = false;
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1683  	priv->cdns_data = data->cdns_data;
ff6af28faff53a Masahiro Yamada   2016-12-08  1684  	host->ioaddr += SDHCI_CDNS_SRS_BASE;
d12990f9900f49 Piotr Sroka       2017-03-06  1685  	host->mmc_host_ops.hs400_enhanced_strobe =
d12990f9900f49 Piotr Sroka       2017-03-06  1686  				sdhci_cdns_hs400_enhanced_strobe;
ff6af28faff53a Masahiro Yamada   2016-12-08  1687  
861183f115cd80 Piotr Sroka       2017-04-11  1688  	sdhci_get_of_property(pdev);
861183f115cd80 Piotr Sroka       2017-04-11  1689  
ff6af28faff53a Masahiro Yamada   2016-12-08  1690  	ret = mmc_of_parse(host->mmc);
ff6af28faff53a Masahiro Yamada   2016-12-08  1691  	if (ret)
ff6af28faff53a Masahiro Yamada   2016-12-08  1692  		goto free;
ff6af28faff53a Masahiro Yamada   2016-12-08  1693  
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1694  	ret = data->phy_probe(pdev, priv);
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1695  	if (ret)
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1696  		goto free;
a232a8f2d10750 Masahiro Yamada   2017-08-23  1697  
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1698  	ret = priv->cdns_data->phy_init(priv);
a89c472d8b55c5 Piotr Sroka       2017-03-21  1699  	if (ret)
a89c472d8b55c5 Piotr Sroka       2017-03-21  1700  		goto free;
ff6af28faff53a Masahiro Yamada   2016-12-08  1701  
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1702  	sdhci_enable_v4_mode(host);
8bcfc23a884699 Dhananjay Kangude 2022-12-19  1703  	__sdhci_read_caps(host, NULL, NULL, NULL);
ff6af28faff53a Masahiro Yamada   2016-12-08  1704  	ret = sdhci_add_host(host);
ff6af28faff53a Masahiro Yamada   2016-12-08  1705  	if (ret)
ff6af28faff53a Masahiro Yamada   2016-12-08  1706  		goto free;
ff6af28faff53a Masahiro Yamada   2016-12-08  1707  
ff6af28faff53a Masahiro Yamada   2016-12-08  1708  	return 0;
ff6af28faff53a Masahiro Yamada   2016-12-08  1709  free:
ff6af28faff53a Masahiro Yamada   2016-12-08  1710  	sdhci_pltfm_free(pdev);
ff6af28faff53a Masahiro Yamada   2016-12-08  1711  disable_clk:
ff6af28faff53a Masahiro Yamada   2016-12-08  1712  	clk_disable_unprepare(clk);
ff6af28faff53a Masahiro Yamada   2016-12-08  1713  
ff6af28faff53a Masahiro Yamada   2016-12-08  1714  	return ret;
ff6af28faff53a Masahiro Yamada   2016-12-08  1715  }

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support
  2022-12-19 15:40   ` Krzysztof Kozlowski
@ 2023-01-06 16:48     ` Piyush Malgujar
  2023-01-07 13:25       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 19+ messages in thread
From: Piyush Malgujar @ 2023-01-06 16:48 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree, jannadurai,
	cchavva

Hi Krzysztof,

Thank you the review comments.

On Mon, Dec 19, 2022 at 04:40:35PM +0100, Krzysztof Kozlowski wrote:
> On 19/12/2022 15:24, Piyush Malgujar wrote:
> > From: Jayanthi Annadurai <jannadurai@marvell.com>
> > 
> 
> Subject: use final prefix matching the file, so "cdns,sdhci:"
> 
> > Add support for SD6 controller support
> 
> Full stop.
> 
> > 
> > Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> > Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> > ---
> >  .../devicetree/bindings/mmc/cdns,sdhci.yaml   | 33 +++++++++++++++++--
> >  1 file changed, 31 insertions(+), 2 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> > index 8b1a0fdcb5e3e2e8b87d8d7678e37f3dad447fc1..2043e78ccd5f708a01e87fd96ec410418fcd539f 100644
> > --- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> > +++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> > @@ -4,7 +4,7 @@
> >  $id: http://devicetree.org/schemas/mmc/cdns,sdhci.yaml#
> >  $schema: http://devicetree.org/meta-schemas/core.yaml#
> >  
> > -title: Cadence SD/SDIO/eMMC Host Controller (SD4HC)
> > +title: Cadence SD/SDIO/eMMC Host Controller (SD4HC, SD6HC)
> >  
> >  maintainers:
> >    - Masahiro Yamada <yamada.masahiro@socionext.com>
> > @@ -19,6 +19,7 @@ properties:
> >            - microchip,mpfs-sd4hc
> >            - socionext,uniphier-sd4hc
> >        - const: cdns,sd4hc
> > +      - const: cdns,sd6hc
> 
> Does not look like you tested the DTS against bindings. Please run `make
> dtbs_check` (see Documentation/devicetree/bindings/writing-schema.rst
> for instructions).
> 
> ... because it does not really make sense. Why do you require SD6HC as
> fallback? I think you meant enum.
> 

Yes, that's correct. I will change it to enum.

> >  
> >    reg:
> >      maxItems: 1
> > @@ -111,6 +112,34 @@ properties:
> >      minimum: 0
> >      maximum: 0x7f
> >  
> > +  cdns,iocell_input_delay:
> 
> No underscores. Use proper units in name suffix:
> https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/property-units.yaml
> 
> 
> > +    description: Delay in ps across the input IO cells
> > +    $ref: "/schemas/types.yaml#/definitions/uint32"
> 
> Ditto... and so on - all of the fields.
> 
> > +
> > +  cdns,iocell_output_delay:
> > +    description: Delay in ps across the output IO cells
> > +    $ref: "/schemas/types.yaml#/definitions/uint32"
> > +
> > +  cdns,delay_element:
> > +    description: Delay element in ps used for calculating phy timings
> > +    $ref: "/schemas/types.yaml#/definitions/uint32"
> > +
> > +  cdns,read_dqs_cmd_delay:
> > +    description: Command delay used in HS200 tuning
> > +    $ref: "/schemas/types.yaml#/definitions/uint32"
> > +
> > +  cdns,tune_val_start:
> > +    description: Staring value of data delay used in HS200 tuning
> > +    $ref: "/schemas/types.yaml#/definitions/uint32"
> > +
> > +  cdns,tune_val_step:
> > +    description: Incremental value of data delay used in HS200 tuning
> > +    $ref: "/schemas/types.yaml#/definitions/uint32"
> > +
> > +  cdns,max_tune_iter:
> > +    description: Maximum number of iterations to complete the HS200 tuning process
> > +    $ref: "/schemas/types.yaml#/definitions/uint32"
> 
> Why these three are properties of DT?
> 

These tuning parameters are added here so to make them custom configurable for different
boards.

> > +
> >  required:
> >    - compatible
> >    - reg
> > @@ -122,7 +151,7 @@ unevaluatedProperties: false
> >  examples:
> >    - |
> >      emmc: mmc@5a000000 {
> > -        compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc";
> > +        compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc", "cdns,sd6hc";
> 
> This is confusing. I don't understand it. It requires much more
> explanation in your commit msg.
> 
> >          reg = <0x5a000000 0x400>;
> >          interrupts = <0 78 4>;
> >          clocks = <&clk 4>;
> 
> Best regards,
> Krzysztof
> 

Rest of the comments will be taken care in V2.

Thanks,
Piyush

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support
  2023-01-06 16:48     ` Piyush Malgujar
@ 2023-01-07 13:25       ` Krzysztof Kozlowski
  2023-01-18 16:02         ` Piyush Malgujar
  0 siblings, 1 reply; 19+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-07 13:25 UTC (permalink / raw)
  To: Piyush Malgujar
  Cc: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree, jannadurai,
	cchavva

On 06/01/2023 17:48, Piyush Malgujar wrote:
> Hi Krzysztof,
> 
> Thank you the review comments.
> 
> On Mon, Dec 19, 2022 at 04:40:35PM +0100, Krzysztof Kozlowski wrote:
>> On 19/12/2022 15:24, Piyush Malgujar wrote:
>>> From: Jayanthi Annadurai <jannadurai@marvell.com>
>>>
>>
>> Subject: use final prefix matching the file, so "cdns,sdhci:"
>>
>>> Add support for SD6 controller support
>>
>> Full stop.
>>
>>>
>>> Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
>>> Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
>>> ---
>>>  .../devicetree/bindings/mmc/cdns,sdhci.yaml   | 33 +++++++++++++++++--
>>>  1 file changed, 31 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
>>> index 8b1a0fdcb5e3e2e8b87d8d7678e37f3dad447fc1..2043e78ccd5f708a01e87fd96ec410418fcd539f 100644
>>> --- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
>>> +++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
>>> @@ -4,7 +4,7 @@
>>>  $id: http://devicetree.org/schemas/mmc/cdns,sdhci.yaml#
>>>  $schema: http://devicetree.org/meta-schemas/core.yaml#
>>>  
>>> -title: Cadence SD/SDIO/eMMC Host Controller (SD4HC)
>>> +title: Cadence SD/SDIO/eMMC Host Controller (SD4HC, SD6HC)
>>>  
>>>  maintainers:
>>>    - Masahiro Yamada <yamada.masahiro@socionext.com>
>>> @@ -19,6 +19,7 @@ properties:
>>>            - microchip,mpfs-sd4hc
>>>            - socionext,uniphier-sd4hc
>>>        - const: cdns,sd4hc
>>> +      - const: cdns,sd6hc
>>
>> Does not look like you tested the DTS against bindings. Please run `make
>> dtbs_check` (see Documentation/devicetree/bindings/writing-schema.rst
>> for instructions).
>>
>> ... because it does not really make sense. Why do you require SD6HC as
>> fallback? I think you meant enum.
>>
> 
> Yes, that's correct. I will change it to enum.
> 
>>>  
>>>    reg:
>>>      maxItems: 1
>>> @@ -111,6 +112,34 @@ properties:
>>>      minimum: 0
>>>      maximum: 0x7f
>>>  
>>> +  cdns,iocell_input_delay:
>>
>> No underscores. Use proper units in name suffix:
>> https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/property-units.yaml
>>
>>
>>> +    description: Delay in ps across the input IO cells
>>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
>>
>> Ditto... and so on - all of the fields.
>>
>>> +
>>> +  cdns,iocell_output_delay:
>>> +    description: Delay in ps across the output IO cells
>>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
>>> +
>>> +  cdns,delay_element:
>>> +    description: Delay element in ps used for calculating phy timings
>>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
>>> +
>>> +  cdns,read_dqs_cmd_delay:
>>> +    description: Command delay used in HS200 tuning
>>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
>>> +
>>> +  cdns,tune_val_start:
>>> +    description: Staring value of data delay used in HS200 tuning
>>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
>>> +
>>> +  cdns,tune_val_step:
>>> +    description: Incremental value of data delay used in HS200 tuning
>>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
>>> +
>>> +  cdns,max_tune_iter:
>>> +    description: Maximum number of iterations to complete the HS200 tuning process
>>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
>>
>> Why these three are properties of DT?
>>
> 
> These tuning parameters are added here so to make them custom configurable for different
> boards.

I understand why do you wanted to add them, but I am asking why these
are suitable for DT? DT  describes hardware, so what is here specific to
hardware which requires DT property?


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout
  2022-12-19 14:24 ` [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout Piyush Malgujar
@ 2023-01-11  8:08   ` Adrian Hunter
  2023-01-12 13:44     ` Piyush Malgujar
  0 siblings, 1 reply; 19+ messages in thread
From: Adrian Hunter @ 2023-01-11  8:08 UTC (permalink / raw)
  To: Piyush Malgujar, linux-mmc, linux-kernel, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva

On 19/12/22 16:24, Piyush Malgujar wrote:
> From: Jayanthi Annadurai <jannadurai@marvell.com>
> 
> Add config option to choose the sdhci timeout in seconds.

This approach is not ok, but why is the change wanted?

> 
> Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> ---
>  drivers/mmc/host/Kconfig | 8 ++++++++
>  drivers/mmc/host/sdhci.c | 3 ++-
>  2 files changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index b5b2ae0bb4625bdb9d17acdbb1887c9caa3a1f32..ab48f2bc4cff73d1aad8d7da542d761cf0346d9f 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -1132,3 +1132,11 @@ config MMC_LITEX
>  	  module will be called litex_mmc.
>  
>  	  If unsure, say N.
> +
> +config MMC_SDHCI_TIMEOUT
> +	int
> +	default 1 if MMC_SDHCI_CADENCE
> +	default 10
> +	depends on MMC_SDHCI
> +	help
> +	  Default timeout value for command and data.
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index f3af1bd0f7b955272fbd8b034ecb591860b89aed..e9bc24258746834ec9c8f13fe24456587a2b758d 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -1707,7 +1707,8 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>  	else if (!cmd->data && cmd->busy_timeout > 9000)
>  		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>  	else
> -		timeout += 10 * HZ;
> +		timeout += CONFIG_MMC_SDHCI_TIMEOUT * HZ;
> +
>  	sdhci_mod_timer(host, cmd->mrq, timeout);
>  
>  	if (host->use_external_dma)


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support
  2022-12-19 14:24 ` [PATCH 1/5] " Piyush Malgujar
  2022-12-19 15:41   ` Krzysztof Kozlowski
  2022-12-23 11:07   ` Dan Carpenter
@ 2023-01-11  8:19   ` Adrian Hunter
  2 siblings, 0 replies; 19+ messages in thread
From: Adrian Hunter @ 2023-01-11  8:19 UTC (permalink / raw)
  To: Piyush Malgujar, linux-mmc, linux-kernel, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva, Dhananjay Kangude

On 19/12/22 16:24, Piyush Malgujar wrote:
> From: Dhananjay Kangude <dkangude@cadence.com>
> 
> This patch includes changes done to support SD6 controller:
> - Added SD6 related ops which are isolated from SD4
> - changes to support HS400, HS400ES emmc mode
> - Updated HS200 tuning values and support to read tune configuration
>   from FDT.
> - Support to configure host side drive strength and slew
>   and read it from device tree

There is a certain amount of renaming and reformating of code
in this patch.  Please move that to a separate "preparation"
patch.

> 
> Signed-off-by: Dhananjay Kangude <dkangude@cadence.com>
> Co-developed-by: Jayanthi Annadurai <jannadurai@marvell.com>
> Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> ---
>  drivers/mmc/host/sdhci-cadence.c | 1502 ++++++++++++++++++++++++++++--
>  1 file changed, 1403 insertions(+), 99 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
> index 6f2de54a598773879bf339aae8450f63e1251509..5332d19e489be936d6814feba4f0fc046f5e130e 100644
> --- a/drivers/mmc/host/sdhci-cadence.c
> +++ b/drivers/mmc/host/sdhci-cadence.c
> @@ -15,30 +15,119 @@
>  
>  #include "sdhci-pltfm.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
> +#define SDMCLK_MAX_FREQ		200000000
> +
> +#define DEFAULT_CMD_DELAY		16
> +#define SDHCI_CDNS_TUNE_START		16
> +#define SDHCI_CDNS_TUNE_STEP		6
> +#define SDHCI_CDNS_TUNE_ITERATIONS	40
> +
> +#define SDHCI_CDNS_HRS00			0x00
> +#define SDHCI_CDNS_HRS00_SWR			BIT(0)
> +
> +#define SDHCI_CDNS_HRS02			0x08		/* PHY access port */
> +#define SDHCI_CDNS_HRS04			0x10		/* PHY access port */
> +
> +/* SD 4.0 Controller HRS - Host Register Set (specific to Cadence) */
> +#define SDHCI_CDNS_SD4_HRS04_ACK		BIT(26)
> +#define SDHCI_CDNS_SD4_HRS04_RD			BIT(25)
> +#define SDHCI_CDNS_SD4_HRS04_WR			BIT(24)
> +#define SDHCI_CDNS_SD4_HRS04_RDATA		GENMASK(23, 16)
> +#define SDHCI_CDNS_SD4_HRS04_WDATA		GENMASK(15, 8)
> +#define SDHCI_CDNS_SD4_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_LEGACY		0x1
> +#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
> +
> +/* SD 6.0 Controller HRS - Host Register Set (Specific to Cadence) */
> +#define SDHCI_CDNS_SD6_HRS04_ADDR		GENMASK(15, 0)
> +
> +#define SDHCI_CDNS_HRS05			0x14
> +
> +#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
> +#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
> +#define	SDHCI_CDNS_HRS10_HCSDCLKADJ		GENMASK(19, 16)
> +
> +#define SDHCI_CDNS_HRS11			0x2c
> +/*Reset related*/
> +#define SDHCI_CDNS_SRS11_SW_RESET_ALL		BIT(24)
> +#define SDHCI_CDNS_SRS11_SW_RESET_CMD		BIT(25)
> +#define SDHCI_CDNS_SRS11_SW_RESET_DAT		BIT(26)
> +
> +#define SDHCI_CDNS_HRS16			0x40
> +#define SDHCI_CDNS_HRS16_WRDATA1_SDCLK_DLY	GENMASK(31, 28)
> +#define SDHCI_CDNS_HRS16_WRDATA0_SDCLK_DLY	GENMASK(27, 24)
> +#define SDHCI_CDNS_HRS16_WRCMD1_SDCLK_DLY	GENMASK(23, 20)
> +#define SDHCI_CDNS_HRS16_WRCMD0_SDCLK_DLY	GENMASK(19, 16)
> +#define SDHCI_CDNS_HRS16_WRDATA1_DLY		GENMASK(15, 12)
> +#define SDHCI_CDNS_HRS16_WRDATA0_DLY		GENMASK(11, 8)
> +#define SDHCI_CDNS_HRS16_WRCMD1_DLY		GENMASK(7, 4)
> +#define SDHCI_CDNS_HRS16_WRCMD0_DLY		GENMASK(3, 0)
> +
> +/* PHY registers for SD6 controller */
> +#define SDHCI_CDNS_SD6_PHY_DQ_TIMING				0x2000
> +#define	SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_ALWAYS_ON		BIT(31)
> +#define	SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_END		GENMASK(29, 27)
> +#define	SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_START		GENMASK(26, 24)
> +#define	SDHCI_CDNS_SD6_PHY_DQ_TIMING_DATA_SELECT_OE_END		GENMASK(2, 0)
> +
> +#define SDHCI_CDNS_SD6_PHY_DQS_TIMING				0x2004
> +#define	SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_EXT_LPBK_DQS		BIT(22)
> +#define	SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_LPBK_DQS		BIT(21)
> +#define	SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS		BIT(20)
> +#define	SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS_CMD		BIT(19)
> +
> +#define SDHCI_CDNS_SD6_PHY_GATE_LPBK				0x2008
> +#define	SDHCI_CDNS_SD6_PHY_GATE_LPBK_SYNC_METHOD		BIT(31)
> +#define	SDHCI_CDNS_SD6_PHY_GATE_LPBK_SW_HALF_CYCLE_SHIFT	BIT(28)
> +#define	SDHCI_CDNS_SD6_PHY_GATE_LPBK_RD_DEL_SEL			GENMASK(24, 19)
> +#define	SDHCI_CDNS_SD6_PHY_GATE_LPBK_GATE_CFG_ALWAYS_ON		BIT(6)
> +
> +#define SDHCI_CDNS_SD6_PHY_DLL_MASTER				0x200C
> +#define	SDHCI_CDNS_SD6_PHY_DLL_MASTER_BYPASS_MODE		BIT(23)
> +#define	SDHCI_CDNS_SD6_PHY_DLL_MASTER_PHASE_DETECT_SEL		GENMASK(22, 20)
> +#define	SDHCI_CDNS_SD6_PHY_DLL_MASTER_DLL_LOCK_NUM		GENMASK(18, 16)
> +#define	SDHCI_CDNS_SD6_PHY_DLL_MASTER_DLL_START_POINT		GENMASK(7, 0)
> +
> +#define SDHCI_CDNS_SD6_PHY_DLL_SLAVE				0x2010
> +#define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_CMD_DELAY		GENMASK(31, 24)
> +#define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WRDQS_DELAY		GENMASK(23, 16)
> +#define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WR_DELAY		GENMASK(15, 8)
> +#define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_DELAY		GENMASK(7, 0)
> +
> +#define SDHCI_CDNS_SD6_PHY_CTRL					0x2080
> +#define	SDHCI_CDNS_SD6_PHY_CTRL_PHONY_DQS_TIMING		GENMASK(9, 4)
> +
> +#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0				0x2088
> +#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_DRV			GENMASK(6, 5)
> +#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_DRV_OVR_EN		BIT(4)
> +#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_SLEW			GENMASK(2, 1)
> +#define SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_SLEW_OVR_EN		BIT(0)
>  
>  /* SRS - Slot Register Set (SDHCI-compatible) */
>  #define SDHCI_CDNS_SRS_BASE		0x200
>  
> -/* PHY */
> +/* PHY registers for SD4 controller */
>  #define SDHCI_CDNS_PHY_DLY_SD_HS	0x00
>  #define SDHCI_CDNS_PHY_DLY_SD_DEFAULT	0x01
>  #define SDHCI_CDNS_PHY_DLY_UHS_SDR12	0x02
> @@ -59,24 +148,47 @@
>   */
>  #define SDHCI_CDNS_MAX_TUNING_LOOP	40
>  
> -struct sdhci_cdns_phy_param {
> +static int tune_val_start = SDHCI_CDNS_TUNE_START;
> +static int tune_val_step = SDHCI_CDNS_TUNE_STEP;
> +static int max_tune_iter = SDHCI_CDNS_TUNE_ITERATIONS;
> +
> +struct sdhci_cdns_priv;
> +
> +struct sdhci_cdns_sd4_phy_param {
>  	u8 addr;
>  	u8 data;
>  };
>  
> +struct sdhci_cdns_data {
> +	int (*phy_init)(struct sdhci_cdns_priv *priv);
> +	int (*set_tune_val)(struct sdhci_host *host, unsigned int val);
> +};
> +
> +struct sdhci_cdns_sd4_phy {
> +	unsigned int nr_phy_params;
> +	struct sdhci_cdns_sd4_phy_param phy_params[];
> +};
> +
>  struct sdhci_cdns_priv {
>  	void __iomem *hrs_addr;
>  	bool enhanced_strobe;
> -	unsigned int nr_phy_params;
> -	struct sdhci_cdns_phy_param phy_params[];
> +	const struct sdhci_cdns_data *cdns_data;
> +	void *phy;
>  };
>  
> -struct sdhci_cdns_phy_cfg {
> +struct sdhci_cdns_sd4_phy_cfg {
>  	const char *property;
>  	u8 addr;
>  };
>  
> -static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
> +struct sdhci_cdns_of_data {
> +	const struct sdhci_pltfm_data *pltfm_data;
> +	const struct sdhci_cdns_data *cdns_data;
> +	int (*phy_probe)(struct platform_device *pdev,
> +			 struct sdhci_cdns_priv *priv);
> +};
> +
> +static const struct sdhci_cdns_sd4_phy_cfg sdhci_cdns_sd4_phy_cfgs[] = {
>  	{ "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, },
>  	{ "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, },
>  	{ "cdns,phy-input-delay-sd-uhs-sdr12", SDHCI_CDNS_PHY_DLY_UHS_SDR12, },
> @@ -90,80 +202,900 @@ static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
>  	{ "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, },
>  };
>  
> -static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
> -				    u8 addr, u8 data)
> +enum sdhci_cdns_sd6_phy_lock_mode {
> +	SDHCI_CDNS_SD6_PHY_LOCK_MODE_FULL_CLK = 0,
> +	SDHCI_CDNS_SD6_PHY_LOCK_MODE_HALF_CLK = 2,
> +	SDHCI_CDNS_SD6_PHY_LOCK_MODE_SATURATION = 3,
> +};
> +
> +struct sdhci_cdns_sd6_phy_timings {
> +	u32 t_cmd_output_min;
> +	u32 t_cmd_output_max;
> +	u32 t_dat_output_min;
> +	u32 t_dat_output_max;
> +	u32 t_cmd_input_min;
> +	u32 t_cmd_input_max;
> +	u32 t_dat_input_min;
> +	u32 t_dat_input_max;
> +	u32 t_sdclk_min;
> +	u32 t_sdclk_max;
> +};
> +
> +struct sdhci_cdns_sd6_phy_delays {
> +	u32 phy_sdclk_delay;
> +	u32 phy_cmd_o_delay;
> +	u32 phy_dat_o_delay;
> +	u32 iocell_input_delay;
> +	u32 iocell_output_delay;
> +	u32 delay_element_org;
> +	u32 delay_element;
> +};
> +
> +struct sdhci_cdns_sd6_phy_settings {
> +	/* SDHCI_CDNS_SD6_PHY_DLL_SLAVE */
> +	u32 cp_read_dqs_cmd_delay;
> +	u32 cp_read_dqs_delay;
> +	u32 cp_clk_wr_delay;
> +	u32 cp_clk_wrdqs_delay;
> +
> +	/* SDHCI_CDNS_SD6_PHY_DLL_MASTER */
> +	u32 cp_dll_bypass_mode;
> +	u32 cp_dll_start_point;
> +
> +	/* SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0 */
> +	u32 cp_dll_locked_mode;
> +
> +	/* SDHCI_CDNS_SD6_PHY_GATE_LPBK */
> +	u32 cp_gate_cfg_always_on;
> +	u32 cp_sync_method;
> +	u32 cp_rd_del_sel;
> +	u32 cp_sw_half_cycle_shift;
> +	u32 cp_underrun_suppress;
> +
> +	/* SDHCI_CDNS_SD6_PHY_DQ_TIMING */
> +	u32 cp_io_mask_always_on;
> +	u32 cp_io_mask_end;
> +	u32 cp_io_mask_start;
> +	u32 cp_data_select_oe_end;
> +
> +	/* SDHCI_CDNS_SD6_PHY_DQS_TIMING */
> +	u32 cp_use_ext_lpbk_dqs;
> +	u32 cp_use_lpbk_dqs;
> +	u8 cp_use_phony_dqs;
> +	u8 cp_use_phony_dqs_cmd;
> +
> +	/* HRS 09 */
> +	u8 sdhc_extended_rd_mode;
> +	u8 sdhc_extended_wr_mode;
> +	u32 sdhc_rdcmd_en;
> +	u32 sdhc_rddata_en;
> +
> +	/* HRS10 */
> +	u32 sdhc_hcsdclkadj;
> +
> +	/* HRS 07 */
> +	u32 sdhc_idelay_val;
> +	u32 sdhc_rw_compensate;
> +
> +	/* SRS 11 */
> +	u32 sdhc_sdcfsh;
> +	u32 sdhc_sdcfsl;
> +
> +	/* HRS 16 */
> +	u32 sdhc_wrcmd0_dly;
> +	u32 sdhc_wrcmd0_sdclk_dly;
> +	u32 sdhc_wrcmd1_dly;
> +	u32 sdhc_wrcmd1_sdclk_dly;
> +	u32 sdhc_wrdata0_dly;
> +	u32 sdhc_wrdata0_sdclk_dly;
> +	u32 sdhc_wrdata1_dly;
> +	u32 sdhc_wrdata1_sdclk_dly;
> +
> +	u32 hs200_tune_val;
> +	u32 drive;
> +	u32 slew;
> +};
> +
> +struct sdhci_cdns_sd6_phy_intermediate_results {
> +	u32 t_sdmclk_calc;
> +	u32 dll_max_value;
> +};
> +
> +struct sdhci_cdns_sd6_phy {
> +	struct sdhci_cdns_sd6_phy_timings t;
> +	struct sdhci_cdns_sd6_phy_delays d;
> +	u32 t_sdmclk;
> +	struct sdhci_cdns_sd6_phy_settings settings;
> +	struct sdhci_cdns_sd6_phy_intermediate_results vars;
> +	bool ddr;
> +	bool tune_cmd;
> +	bool tune_dat;
> +	bool strobe_cmd;
> +	bool strobe_dat;
> +	int mode;
> +	int t_sdclk;
> +};
> +
> +static void init_hs(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 2000, .t_cmd_output_max = t_sdclk - 6000,
> +		.t_dat_output_min = 2000, .t_dat_output_max = t_sdclk - 6000,
> +		.t_cmd_input_min = 14000, .t_cmd_input_max = t_sdclk + 2500,
> +		.t_dat_input_min = 14000, .t_dat_input_max = t_sdclk + 2500,
> +		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
> +	};
> +}
> +
> +static void init_uhs_sdr12(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 3000,
> +		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 3000,
> +		.t_cmd_input_min = 14000, .t_cmd_input_max = t_sdclk + 1500,
> +		.t_dat_input_min = 14000, .t_dat_input_max = t_sdclk + 1500,
> +		.t_sdclk_min = 1000000 / 25, .t_sdclk_max = 1000000 / 0.4
> +	};
> +}
> +
> +static void init_uhs_sdr25(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 3000,
> +		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 3000,
> +		.t_cmd_input_min = 14000, .t_cmd_input_max = t_sdclk + 1500,
> +		.t_dat_input_min = 14000, .t_dat_input_max = t_sdclk + 1500,
> +		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
> +	};
> +}
> +
> +static void init_uhs_sdr50(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 3000,
> +		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 3000,
> +		.t_cmd_input_min = 7500, .t_cmd_input_max = t_sdclk + 1500,
> +		.t_dat_input_min = 7500, .t_dat_input_max = t_sdclk + 1500,
> +		.t_sdclk_min = 1000000 / 100, .t_sdclk_max = 1000000 / 0.4
> +	};
> +}
> +
> +static void init_uhs_sdr104(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 1400,
> +		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 1400,
> +		.t_cmd_input_min = 1000, .t_cmd_input_max = t_sdclk + 1000,
> +		.t_dat_input_min = 1000, .t_dat_input_max = t_sdclk + 1000,
> +		.t_sdclk_min = 1000000 / 200, .t_sdclk_max = 1000000 / 100
> +	};
> +}
> +
> +static void init_uhs_ddr50(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 3000,
> +		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 3000,
> +		.t_cmd_input_min = 13700, .t_cmd_input_max = t_sdclk + 1500,
> +		.t_dat_input_min = 7000, .t_dat_input_max = t_sdclk + 1500,
> +		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
> +	};
> +}
> +
> +static void init_emmc_legacy(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 3000, .t_cmd_output_max = t_sdclk - 3000,
> +		.t_dat_output_min = 3000, .t_dat_output_max = t_sdclk - 3000,
> +		.t_cmd_input_min = 11700, .t_cmd_input_max = t_sdclk + 8300,
> +		.t_dat_input_min = 11700, .t_dat_input_max = t_sdclk + 8300,
> +		.t_sdclk_min = 1000000 / 25, .t_sdclk_max = 1000000 / 0.4
> +	};
> +}
> +
> +static void init_emmc_sdr(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 3000, .t_cmd_output_max = t_sdclk - 3000,
> +		.t_dat_output_min = 3000, .t_dat_output_max = t_sdclk - 3000,
> +		.t_cmd_input_min = 13700, .t_cmd_input_max = t_sdclk + 2500,
> +		.t_dat_input_min = 13700, .t_dat_input_max = t_sdclk + 2500,
> +		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
> +	};
> +}
> +
> +static void init_emmc_ddr(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 3000, .t_cmd_output_max = t_sdclk - 3000,
> +		.t_dat_output_min = 2500, .t_dat_output_max = t_sdclk - 2500,
> +		.t_cmd_input_min = 13700, .t_cmd_input_max = t_sdclk + 2500,
> +		.t_dat_input_min = 7000, .t_dat_input_max = t_sdclk + 1500,
> +		.t_sdclk_min = 1000000 / 50, .t_sdclk_max = 1000000 / 0.4
> +	};
> +}
> +
> +static void init_emmc_hs200(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 1400,
> +		.t_dat_output_min = 800, .t_dat_output_max = t_sdclk - 1400,
> +		.t_cmd_input_min = 1000, .t_cmd_input_max = t_sdclk + 1000,
> +		.t_dat_input_min = 1000, .t_dat_input_max = t_sdclk + 1000,
> +		.t_sdclk_min = 1000000 / 200, .t_sdclk_max = 1000000 / 100
> +	};
> +}
> +
> +/* HS400 and HS400ES */
> +static void init_emmc_hs400(struct sdhci_cdns_sd6_phy_timings *t, int t_sdclk)
> +{
> +	*t = (struct sdhci_cdns_sd6_phy_timings){
> +		.t_cmd_output_min = 800, .t_cmd_output_max = t_sdclk - 1400,
> +		.t_dat_output_min = 400, .t_dat_output_max = t_sdclk - 400,
> +		.t_cmd_input_min = 1000, .t_cmd_input_max = t_sdclk + 1000,
> +		.t_dat_input_min = 1000, .t_dat_input_max = t_sdclk + 1000,
> +		.t_sdclk_min = 1000000 / 200, .t_sdclk_max = 1000000 / 100
> +	};
> +}
> +
> +static void (*init_timings[])(struct sdhci_cdns_sd6_phy_timings*, int) = {
> +	&init_hs, &init_emmc_legacy, &init_emmc_sdr,
> +	&init_emmc_ddr, &init_emmc_hs200, &init_emmc_hs400,
> +	&init_uhs_sdr12, &init_uhs_sdr25, &init_uhs_sdr50,
> +	&init_uhs_sdr104, &init_uhs_ddr50
> +};
> +
> +static u32 read_dqs_cmd_delay, clk_wrdqs_delay, clk_wr_delay, read_dqs_delay;
> +
> +static u32 sdhci_cdns_sd6_get_mode(struct sdhci_host *host, unsigned int timing);
> +
> +static int sdhci_cdns_sd6_phy_lock_dll(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	u32 delay_element = phy->d.delay_element_org;
> +	u32 delay_elements_in_sdmclk;
> +	enum sdhci_cdns_sd6_phy_lock_mode mode;
> +
> +	delay_elements_in_sdmclk = DIV_ROUND_UP(phy->t_sdmclk, delay_element);
> +	if (delay_elements_in_sdmclk > 256) {
> +		delay_element *= 2;
> +		delay_elements_in_sdmclk = DIV_ROUND_UP(phy->t_sdmclk,
> +							delay_element);
> +
> +		if (delay_elements_in_sdmclk > 256)
> +			return -1;
> +
> +		mode = SDHCI_CDNS_SD6_PHY_LOCK_MODE_HALF_CLK;
> +		phy->vars.dll_max_value = 127;
> +	} else {
> +		mode = SDHCI_CDNS_SD6_PHY_LOCK_MODE_FULL_CLK;
> +		phy->vars.dll_max_value = 255;
> +	}
> +
> +	phy->vars.t_sdmclk_calc = delay_element * delay_elements_in_sdmclk;
> +	phy->d.delay_element = delay_element;
> +	phy->settings.cp_dll_locked_mode = mode;
> +	phy->settings.cp_dll_bypass_mode = 0;
> +
> +	return 0;
> +}
> +
> +static void sdhci_cdns_sd6_phy_dll_bypass(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	phy->vars.dll_max_value = 256;
> +	phy->settings.cp_dll_bypass_mode = 1;
> +	phy->settings.cp_dll_locked_mode =
> +		SDHCI_CDNS_SD6_PHY_LOCK_MODE_SATURATION;
> +}
> +
> +static void sdhci_cdns_sd6_phy_configure_dll(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	if (phy->settings.sdhc_extended_wr_mode == 0) {
> +		if (sdhci_cdns_sd6_phy_lock_dll(phy) == 0)
> +			return;
> +	}
> +	sdhci_cdns_sd6_phy_dll_bypass(phy);
> +}
> +
> +static void sdhci_cdns_sd6_phy_calc_out(struct sdhci_cdns_sd6_phy *phy,
> +					bool cmd_not_dat)
> +{
> +	u32 wr0_dly = 0, wr1_dly = 0, output_min, output_max, phy_o_delay,
> +	    clk_wr_delay = 0, wr0_sdclk_dly = 0, wr1_sdclk_dly = 0;
> +	bool data_ddr = phy->ddr && !cmd_not_dat;
> +	int t;
> +
> +	if (cmd_not_dat) {
> +		output_min = phy->t.t_cmd_output_min;
> +		output_max = phy->t.t_cmd_output_max;
> +		phy_o_delay = phy->d.phy_cmd_o_delay;
> +	} else {
> +		output_min = phy->t.t_dat_output_min;
> +		output_max = phy->t.t_dat_output_max;
> +		phy_o_delay = phy->d.phy_dat_o_delay;
> +	}
> +
> +	clk_wr_delay = 0;
> +	if (data_ddr) {
> +		wr0_sdclk_dly = 1;
> +		wr1_sdclk_dly = 1;
> +	}
> +
> +	t = phy_o_delay - phy->d.phy_sdclk_delay - output_min;
> +	if (t < 0 && phy->settings.sdhc_extended_wr_mode == 1) {
> +		u32 n_half_cycle = DIV_ROUND_UP(-t * 2, phy->t_sdmclk);
> +
> +		wr0_dly = (n_half_cycle + 1) / 2;
> +		if (data_ddr)
> +			wr1_dly = (n_half_cycle + 1) / 2;
> +		else
> +			wr1_dly = (n_half_cycle + 1) % 2 + wr0_dly - 1;
> +	}
> +
> +	if (phy->settings.sdhc_extended_wr_mode == 0) {
> +		u32 out_hold, out_setup, out_hold_margin;
> +		u32 n;
> +
> +		if (!data_ddr)
> +			wr0_dly = 1;
> +
> +		out_setup = output_max;
> +		out_hold = output_min;
> +		out_hold_margin = DIV_ROUND_UP(out_setup - out_hold, 4);
> +		out_hold += out_hold_margin;
> +
> +		if (phy->settings.cp_dll_bypass_mode == 0)
> +			n = DIV_ROUND_UP(256 * out_hold, phy->vars.t_sdmclk_calc);
> +		else
> +			n = DIV_ROUND_UP(out_hold, phy->d.delay_element) - 1;
> +
> +		if (n <= phy->vars.dll_max_value)
> +			clk_wr_delay = n;
> +		else
> +			clk_wr_delay = 255;
> +	} else {
> +		/*  sdhc_extended_wr_mode = 1 - PHY IO cell work in SDR mode */
> +		clk_wr_delay = 0;
> +	}
> +
> +	if (cmd_not_dat) {
> +		phy->settings.sdhc_wrcmd0_dly = wr0_dly;
> +		phy->settings.sdhc_wrcmd1_dly = wr1_dly;
> +		phy->settings.cp_clk_wrdqs_delay = clk_wr_delay;
> +		phy->settings.sdhc_wrcmd0_sdclk_dly = wr0_sdclk_dly;
> +		phy->settings.sdhc_wrcmd1_sdclk_dly = wr1_sdclk_dly;
> +	} else {
> +		phy->settings.sdhc_wrdata0_dly = wr0_dly;
> +		phy->settings.sdhc_wrdata1_dly = wr1_dly;
> +		phy->settings.cp_clk_wr_delay = clk_wr_delay;
> +		phy->settings.sdhc_wrdata0_sdclk_dly = wr0_sdclk_dly;
> +		phy->settings.sdhc_wrdata1_sdclk_dly = wr1_sdclk_dly;
> +	}
> +}
> +
> +static void sdhci_cdns_sd6_phy_calc_cmd_out(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	sdhci_cdns_sd6_phy_calc_out(phy, true);
> +}
> +
> +static void sdhci_cdns_sd6_phy_calc_cmd_in(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	phy->settings.cp_io_mask_end =
> +		((phy->d.iocell_output_delay + phy->d.iocell_input_delay) * 2)
> +		/ phy->t_sdmclk;
> +
> +	if (phy->settings.cp_io_mask_end >= 8)
> +		phy->settings.cp_io_mask_end = 7;
> +
> +	if (phy->strobe_cmd && phy->settings.cp_io_mask_end > 0)
> +		phy->settings.cp_io_mask_end--;
> +
> +	if (phy->strobe_cmd) {
> +		phy->settings.cp_use_phony_dqs_cmd = 0;
> +		phy->settings.cp_read_dqs_cmd_delay = 64;
> +	} else {
> +		phy->settings.cp_use_phony_dqs_cmd = 1;
> +		phy->settings.cp_read_dqs_cmd_delay = 0;
> +	}
> +
> +	if ((phy->mode == MMC_TIMING_MMC_HS400 && !phy->strobe_cmd) ||
> +	    phy->mode == MMC_TIMING_MMC_HS200)
> +		phy->settings.cp_read_dqs_cmd_delay =
> +			phy->settings.hs200_tune_val;
> +}
> +
> +static void sdhci_cdns_sd6_phy_calc_dat_in(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	u32 hcsdclkadj = 0;
> +
> +	if (phy->strobe_dat) {
> +		phy->settings.cp_use_phony_dqs = 0;
> +		phy->settings.cp_read_dqs_delay = 64;
> +	} else {
> +		phy->settings.cp_use_phony_dqs = 1;
> +		phy->settings.cp_read_dqs_delay = 0;
> +	}
> +
> +	if (phy->mode == MMC_TIMING_MMC_HS200)
> +		phy->settings.cp_read_dqs_delay =
> +			phy->settings.hs200_tune_val;
> +
> +	if (phy->strobe_dat) {
> +		/* dqs loopback input via IO cell */
> +		hcsdclkadj += phy->d.iocell_input_delay;
> +		/* dfi_dqs_in: mem_dqs -> clean_dqs_mod; delay of hic_dll_dqs_nand2 */
> +		hcsdclkadj += phy->d.delay_element / 2;
> +		/* delay line */
> +		hcsdclkadj += phy->t_sdclk / 2;
> +		/* PHY FIFO write pointer */
> +		hcsdclkadj += phy->t_sdclk / 2 + phy->d.delay_element;
> +		/* 1st synchronizer */
> +		hcsdclkadj += DIV_ROUND_UP(hcsdclkadj, phy->t_sdmclk)
> +			* phy->t_sdmclk - hcsdclkadj;
> +		/*
> +		 * 2nd synchronizer + PHY FIFO read pointer + PHY rddata
> +		 * + PHY rddata registered, + FIFO 1st ciu_en
> +		 */
> +		hcsdclkadj += 5 * phy->t_sdmclk;
> +		/* FIFO 2st ciu_en */
> +		hcsdclkadj += phy->t_sdclk;
> +
> +		hcsdclkadj /= phy->t_sdclk;
> +	} else {
> +		u32 n;
> +
> +		/* rebar PHY delay */
> +		hcsdclkadj += 2 * phy->t_sdmclk;
> +		/* rebar output via IO cell */
> +		hcsdclkadj += phy->d.iocell_output_delay;
> +		/* dqs loopback input via IO cell */
> +		hcsdclkadj += phy->d.iocell_input_delay;
> +		/* dfi_dqs_in: mem_dqs -> clean_dqs_mod delay of hic_dll_dqs_nand2 */
> +		hcsdclkadj += phy->d.delay_element / 2;
> +		/* dll: one delay element between SIGI_0 and SIGO_0 */
> +		hcsdclkadj += phy->d.delay_element;
> +		/* dfi_dqs_in: mem_dqs_delayed -> clk_dqs delay of hic_dll_dqs_nand2 */
> +		hcsdclkadj += phy->d.delay_element / 2;
> +		/* deskew DLL: clk_dqs -> clk_dqN: one delay element */
> +		hcsdclkadj += phy->d.delay_element;
> +
> +		if (phy->t_sdclk == phy->t_sdmclk)
> +			n = (hcsdclkadj - 2 * phy->t_sdmclk) / phy->t_sdclk;
> +		else
> +			n = hcsdclkadj / phy->t_sdclk;
> +
> +		/* phase shift within one t_sdclk clock cycle caused by rebar - lbk dqs delay */
> +		hcsdclkadj = hcsdclkadj % phy->t_sdclk;
> +		/* PHY FIFO write pointer */
> +		hcsdclkadj += phy->t_sdclk / 2;
> +		/* 1st synchronizer */
> +		hcsdclkadj += DIV_ROUND_UP(hcsdclkadj, phy->t_sdmclk)
> +			* phy->t_sdmclk - hcsdclkadj;
> +		/*
> +		 * 2nd synchronizer + PHY FIFO read pointer + PHY rddata
> +		 * + PHY rddata registered
> +		 */
> +		hcsdclkadj += 4 * phy->t_sdmclk;
> +
> +		if ((phy->t_sdclk / phy->t_sdmclk) > 1) {
> +			u32 tmp1, tmp2;
> +
> +			tmp1 = hcsdclkadj;
> +			tmp2 = (hcsdclkadj / phy->t_sdclk) * phy->t_sdclk
> +				+ phy->t_sdclk - phy->t_sdmclk;
> +			if (tmp1 == tmp2)
> +				tmp2 += phy->t_sdclk;
> +
> +			/* FIFO aligns to clock cycle before ciu_en */
> +			hcsdclkadj += tmp2 - tmp1;
> +		}
> +
> +		/* FIFO 1st ciu_en */
> +		hcsdclkadj += phy->t_sdmclk;
> +		/* FIFO 2nd ciu_en */
> +		hcsdclkadj += phy->t_sdclk;
> +
> +		hcsdclkadj /= phy->t_sdclk;
> +
> +		hcsdclkadj += n;
> +
> +		if ((phy->t_sdclk / phy->t_sdmclk) >= 2) {
> +			if (phy->mode == MMC_TIMING_UHS_DDR50 ||
> +			    phy->mode == MMC_TIMING_MMC_DDR52)
> +				hcsdclkadj -= 2;
> +			else
> +				hcsdclkadj -= 1;
> +		} else if ((phy->t_sdclk / phy->t_sdmclk) == 1) {
> +			hcsdclkadj += 2;
> +		}
> +
> +		if (phy->tune_dat)
> +			hcsdclkadj -= 1;
> +	}
> +
> +	if (hcsdclkadj > 15)
> +		hcsdclkadj = 15;
> +
> +	phy->settings.sdhc_hcsdclkadj = hcsdclkadj;
> +}
> +
> +static void sdhci_cdns_sd6_phy_calc_dat_out(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	sdhci_cdns_sd6_phy_calc_out(phy, false);
> +}
> +
> +static void sdhci_cdns_sd6_phy_calc_io(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	u32 rw_compensate;
> +
> +	rw_compensate = (phy->d.iocell_input_delay + phy->d.iocell_output_delay)
> +		/ phy->t_sdmclk + phy->settings.sdhc_wrdata0_dly + 5 + 3;
> +
> +	phy->settings.sdhc_idelay_val = (2 * phy->d.iocell_input_delay)
> +		/ phy->t_sdmclk;
> +
> +	phy->settings.cp_io_mask_start = 0;
> +	if (phy->t_sdclk == phy->t_sdmclk && rw_compensate > 10)
> +		phy->settings.cp_io_mask_start = 2 * (rw_compensate - 10);
> +
> +	if (phy->mode == MMC_TIMING_UHS_SDR104)
> +		phy->settings.cp_io_mask_start++;
> +
> +	if (phy->t_sdclk == phy->t_sdmclk && phy->mode == MMC_TIMING_UHS_SDR50)
> +		phy->settings.cp_io_mask_start++;
> +
> +	phy->settings.sdhc_rw_compensate = rw_compensate;
> +}
> +
> +static void sdhci_cdns_sd6_phy_calc_settings(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	sdhci_cdns_sd6_phy_calc_cmd_out(phy);
> +	sdhci_cdns_sd6_phy_calc_cmd_in(phy);
> +	sdhci_cdns_sd6_phy_calc_dat_out(phy);
> +	sdhci_cdns_sd6_phy_calc_dat_in(phy);
> +	sdhci_cdns_sd6_phy_calc_io(phy);
> +}
> +
> +static int sdhci_cdns_sd4_write_phy_reg(struct sdhci_cdns_priv *priv,
> +					u8 addr, u8 data)
>  {
>  	void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS04;
>  	u32 tmp;
>  	int ret;
>  
> -	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK),
> +	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_SD4_HRS04_ACK),
>  				 0, 10);
>  	if (ret)
>  		return ret;
>  
> -	tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
> -	      FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
> +	tmp = FIELD_PREP(SDHCI_CDNS_SD4_HRS04_WDATA, data) |
> +	      FIELD_PREP(SDHCI_CDNS_SD4_HRS04_ADDR, addr);
>  	writel(tmp, reg);
>  
> -	tmp |= SDHCI_CDNS_HRS04_WR;
> +	tmp |= SDHCI_CDNS_SD4_HRS04_WR;
>  	writel(tmp, reg);
>  
> -	ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 0, 10);
> +	ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_SD4_HRS04_ACK, 0, 10);
>  	if (ret)
>  		return ret;
>  
> -	tmp &= ~SDHCI_CDNS_HRS04_WR;
> +	tmp &= ~SDHCI_CDNS_SD4_HRS04_WR;
>  	writel(tmp, reg);
>  
> -	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK),
> +	ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_SD4_HRS04_ACK),
>  				 0, 10);
>  
>  	return ret;
>  }
>  
> -static unsigned int sdhci_cdns_phy_param_count(struct device_node *np)
> +static unsigned int sdhci_cdns_sd4_phy_param_count(struct device_node *np)
>  {
>  	unsigned int count = 0;
>  	int i;
>  
> -	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++)
> -		if (of_property_read_bool(np, sdhci_cdns_phy_cfgs[i].property))
> +	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_sd4_phy_cfgs); i++)
> +		if (of_property_read_bool(np, sdhci_cdns_sd4_phy_cfgs[i].property))
>  			count++;
>  
>  	return count;
>  }
>  
> -static void sdhci_cdns_phy_param_parse(struct device_node *np,
> -				       struct sdhci_cdns_priv *priv)
> +static void sdhci_cdns_sd4_phy_param_parse(struct device_node *np,
> +					   struct sdhci_cdns_sd4_phy *phy)
>  {
> -	struct sdhci_cdns_phy_param *p = priv->phy_params;
> +	struct sdhci_cdns_sd4_phy_param *p = phy->phy_params;
>  	u32 val;
>  	int ret, i;
>  
> -	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) {
> -		ret = of_property_read_u32(np, sdhci_cdns_phy_cfgs[i].property,
> +	for (i = 0; i < ARRAY_SIZE(sdhci_cdns_sd4_phy_cfgs); i++) {
> +		ret = of_property_read_u32(np, sdhci_cdns_sd4_phy_cfgs[i].property,
>  					   &val);
>  		if (ret)
>  			continue;
>  
> -		p->addr = sdhci_cdns_phy_cfgs[i].addr;
> +		p->addr = sdhci_cdns_sd4_phy_cfgs[i].addr;
>  		p->data = val;
>  		p++;
>  	}
>  }
>  
> -static int sdhci_cdns_phy_init(struct sdhci_cdns_priv *priv)
> +static int sdhci_cdns_sd4_phy_init(struct sdhci_cdns_priv *priv)
>  {
>  	int ret, i;
> +	struct sdhci_cdns_sd4_phy *phy = priv->phy;
>  
> -	for (i = 0; i < priv->nr_phy_params; i++) {
> -		ret = sdhci_cdns_write_phy_reg(priv, priv->phy_params[i].addr,
> -					       priv->phy_params[i].data);
> +	for (i = 0; i < phy->nr_phy_params; i++) {
> +		ret = sdhci_cdns_sd4_write_phy_reg(priv, phy->phy_params[i].addr,
> +						   phy->phy_params[i].data);
>  		if (ret)
>  			return ret;
>  	}
> +	return 0;
> +}
> +
> +static u32 sdhci_cdns_sd6_read_phy_reg(struct sdhci_cdns_priv *priv,
> +				       u32 addr)
> +{
> +	writel(FIELD_PREP(SDHCI_CDNS_SD6_HRS04_ADDR, addr),
> +	       priv->hrs_addr + SDHCI_CDNS_HRS04);
> +	return readl(priv->hrs_addr + SDHCI_CDNS_HRS05);
> +}
> +
> +static void sdhci_cdns_sd6_write_phy_reg(struct sdhci_cdns_priv *priv,
> +					 u32 addr, u32 data)
> +{
> +	writel(FIELD_PREP(SDHCI_CDNS_SD6_HRS04_ADDR, addr),
> +	       priv->hrs_addr + SDHCI_CDNS_HRS04);
> +	writel(data, priv->hrs_addr + SDHCI_CDNS_HRS05);
> +}
> +
> +static int sdhci_cdns_sd6_dll_reset(struct sdhci_cdns_priv *priv, bool reset)
> +{
> +	u32 reg;
> +	int ret = 0;
> +
> +	reg = readl(priv->hrs_addr + SDHCI_CDNS_HRS09);
> +	if (reset)
> +		reg &= ~SDHCI_CDNS_HRS09_PHY_SW_RESET;
> +	else
> +		reg |= SDHCI_CDNS_HRS09_PHY_SW_RESET;
> +
> +	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS09);
> +
> +	if (!reset)
> +		ret = readl_poll_timeout(priv->hrs_addr + SDHCI_CDNS_HRS09,
> +					 reg,
> +					 (reg &
> +					  SDHCI_CDNS_HRS09_PHY_INIT_COMPLETE),
> +					 0, 0);
> +
> +	return ret;
> +}
> +
> +static void sdhci_cdns_sd6_calc_phy(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	if (phy->mode == MMC_TIMING_MMC_HS) {
> +		phy->settings.cp_clk_wr_delay = 0;
> +		phy->settings.cp_clk_wrdqs_delay = 0;
> +		phy->settings.cp_data_select_oe_end = 1;
> +		phy->settings.cp_dll_bypass_mode = 1;
> +		phy->settings.cp_dll_locked_mode = 3;
> +		phy->settings.cp_dll_start_point = 4;
> +		phy->settings.cp_gate_cfg_always_on = 1;
> +		phy->settings.cp_io_mask_always_on = 0;
> +		phy->settings.cp_io_mask_end = 0;
> +		phy->settings.cp_io_mask_start = 0;
> +		phy->settings.cp_rd_del_sel = 52;
> +		phy->settings.cp_read_dqs_cmd_delay = 0;
> +		phy->settings.cp_read_dqs_delay = 0;
> +		phy->settings.cp_sw_half_cycle_shift = 0;
> +		phy->settings.cp_sync_method = 1;
> +		phy->settings.cp_underrun_suppress = 1;
> +		phy->settings.cp_use_ext_lpbk_dqs = 1;
> +		phy->settings.cp_use_lpbk_dqs = 1;
> +		phy->settings.cp_use_phony_dqs = 1;
> +		phy->settings.cp_use_phony_dqs_cmd = 1;
> +		phy->settings.sdhc_extended_rd_mode = 1;
> +		phy->settings.sdhc_extended_wr_mode = 1;
> +		phy->settings.sdhc_hcsdclkadj = 2;
> +		phy->settings.sdhc_idelay_val = 0;
> +		phy->settings.sdhc_rdcmd_en = 1;
> +		phy->settings.sdhc_rddata_en = 1;
> +		phy->settings.sdhc_rw_compensate = 9;
> +		phy->settings.sdhc_sdcfsh = 0;
> +		phy->settings.sdhc_sdcfsl = 4;
> +		phy->settings.sdhc_wrcmd0_dly = 1;
> +		phy->settings.sdhc_wrcmd0_sdclk_dly = 0;
> +		phy->settings.sdhc_wrcmd1_dly = 0;
> +		phy->settings.sdhc_wrcmd1_sdclk_dly = 0;
> +		phy->settings.sdhc_wrdata0_dly = 1;
> +		phy->settings.sdhc_wrdata0_sdclk_dly = 0;
> +		phy->settings.sdhc_wrdata1_dly = 0;
> +		phy->settings.sdhc_wrdata1_sdclk_dly = 0;
> +	}
> +}
> +
> +static int sdhci_cdns_sd6_get_delay_params(struct device *dev, struct sdhci_cdns_priv *priv)
> +{
> +	struct sdhci_cdns_sd6_phy *phy = priv->phy;
> +	int ret;
> +
> +	of_property_read_u32(dev->of_node, "cdns,iocell_input_delay", &phy->d.iocell_input_delay);
> +	of_property_read_u32(dev->of_node, "cdns,iocell_output_delay", &phy->d.iocell_output_delay);
> +	of_property_read_u32(dev->of_node, "cdns,delay_element", &phy->d.delay_element);
> +	ret = of_property_read_u32(dev->of_node, "cdns,read_dqs_cmd_delay",
> +				   &phy->settings.cp_read_dqs_cmd_delay);
> +	if (ret)
> +		phy->settings.cp_read_dqs_cmd_delay = DEFAULT_CMD_DELAY;
> +
> +	ret = of_property_read_u32(dev->of_node, "cdns,tune_val_start", &tune_val_start);
> +	if (ret)
> +		tune_val_start = SDHCI_CDNS_TUNE_START;
> +
> +	ret = of_property_read_u32(dev->of_node, "cdns,tune_val_step", &tune_val_step);
> +	if (ret)
> +		tune_val_step = SDHCI_CDNS_TUNE_STEP;
> +
> +	ret = of_property_read_u32(dev->of_node, "cdns,max_tune_iter", &max_tune_iter);
> +	if (ret)
> +		max_tune_iter = SDHCI_CDNS_TUNE_ITERATIONS;
> +
> +	read_dqs_cmd_delay = phy->settings.cp_read_dqs_cmd_delay;
> +	clk_wrdqs_delay = phy->settings.cp_clk_wrdqs_delay;
> +	clk_wr_delay = phy->settings.cp_clk_wr_delay;
> +	read_dqs_delay = phy->settings.cp_read_dqs_delay;
> +	return 0;
> +}
> +
> +static int sdhci_cdns_sd6_phy_init(struct sdhci_cdns_priv *priv)
> +{
> +	int ret;
> +	u32 reg;
> +	struct sdhci_cdns_sd6_phy *phy = priv->phy;
> +
> +	sdhci_cdns_sd6_dll_reset(priv, true);
> +
> +	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQS_TIMING);
> +	reg &= ~SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_EXT_LPBK_DQS;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_LPBK_DQS;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS_CMD;
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_EXT_LPBK_DQS,
> +			phy->settings.cp_use_ext_lpbk_dqs);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_LPBK_DQS,
> +			phy->settings.cp_use_lpbk_dqs);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS,
> +			  phy->settings.cp_use_phony_dqs);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQS_TIMING_USE_PHONY_DQS_CMD,
> +			  phy->settings.cp_use_phony_dqs_cmd);
> +	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQS_TIMING, reg);
> +
> +	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GATE_LPBK);
> +	reg &= ~SDHCI_CDNS_SD6_PHY_GATE_LPBK_SYNC_METHOD;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_GATE_LPBK_SW_HALF_CYCLE_SHIFT;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_GATE_LPBK_RD_DEL_SEL;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_GATE_LPBK_GATE_CFG_ALWAYS_ON;
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GATE_LPBK_SYNC_METHOD,
> +			phy->settings.cp_sync_method);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GATE_LPBK_SW_HALF_CYCLE_SHIFT,
> +			phy->settings.cp_sw_half_cycle_shift);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GATE_LPBK_RD_DEL_SEL,
> +			phy->settings.cp_rd_del_sel);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GATE_LPBK_GATE_CFG_ALWAYS_ON,
> +			phy->settings.cp_gate_cfg_always_on);
> +	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GATE_LPBK, reg);
> +
> +	reg = 0x0;
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_MASTER_BYPASS_MODE,
> +			 phy->settings.cp_dll_bypass_mode);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_MASTER_PHASE_DETECT_SEL, 2);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_MASTER_DLL_LOCK_NUM, 0);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_MASTER_DLL_START_POINT,
> +			phy->settings.cp_dll_start_point);
> +	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_MASTER, reg);
> +
> +	reg = 0x0;
> +	reg = FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_CMD_DELAY,
> +			 phy->settings.cp_read_dqs_cmd_delay);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WRDQS_DELAY,
> +			  phy->settings.cp_clk_wrdqs_delay);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WR_DELAY,
> +			  phy->settings.cp_clk_wr_delay);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_DELAY,
> +			  phy->settings.cp_read_dqs_delay);
> +	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_SLAVE, reg);
> +
> +	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_CTRL);
> +	reg &= ~SDHCI_CDNS_SD6_PHY_CTRL_PHONY_DQS_TIMING;
> +	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_CTRL, reg);
> +
> +	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GPIO_CTRL0);
> +	reg &= ~0x77;
> +	reg |= SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_DRV_OVR_EN |
> +		SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_SLEW_OVR_EN;
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_DRV,
> +		phy->settings.drive);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_GPIO_CTRL0_SLEW,
> +		phy->settings.slew);
> +	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GPIO_CTRL0, reg);
> +
> +	ret = sdhci_cdns_sd6_dll_reset(priv, false);
> +	if (ret)
> +		return ret;
> +
> +	reg = sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQ_TIMING);
> +	reg &= ~SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_ALWAYS_ON;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_END;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_START;
> +	reg &= ~SDHCI_CDNS_SD6_PHY_DQ_TIMING_DATA_SELECT_OE_END;
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_ALWAYS_ON,
> +			phy->settings.cp_io_mask_always_on);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_END,
> +			  phy->settings.cp_io_mask_end);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQ_TIMING_IO_MASK_START,
> +			  phy->settings.cp_io_mask_start);
> +	reg |= FIELD_PREP(SDHCI_CDNS_SD6_PHY_DQ_TIMING_DATA_SELECT_OE_END,
> +			phy->settings.cp_data_select_oe_end);
> +	sdhci_cdns_sd6_write_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQ_TIMING, reg);
> +
> +	reg = readl(priv->hrs_addr + SDHCI_CDNS_HRS09);
> +	if (phy->settings.sdhc_extended_wr_mode)
> +		reg |= SDHCI_CDNS_HRS09_EXTENDED_WR_MODE;
> +	else
> +		reg &= ~SDHCI_CDNS_HRS09_EXTENDED_WR_MODE;
> +
> +	if (phy->settings.sdhc_extended_rd_mode)
> +		reg |= SDHCI_CDNS_HRS09_EXTENDED_RD_MODE;
> +	else
> +		reg &= ~SDHCI_CDNS_HRS09_EXTENDED_RD_MODE;
> +
> +	if (phy->settings.sdhc_rddata_en)
> +		reg |= SDHCI_CDNS_HRS09_RDDATA_EN;
> +	else
> +		reg &= ~SDHCI_CDNS_HRS09_RDDATA_EN;
> +
> +	if (phy->settings.sdhc_rdcmd_en)
> +		reg |= SDHCI_CDNS_HRS09_RDCMD_EN;
> +	else
> +		reg &= ~SDHCI_CDNS_HRS09_RDCMD_EN;
> +
> +	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS09);
> +
> +	writel(0x30004, priv->hrs_addr + SDHCI_CDNS_HRS02);
> +
> +	reg = 0x0;
> +	reg = FIELD_PREP(SDHCI_CDNS_HRS10_HCSDCLKADJ, phy->settings.sdhc_hcsdclkadj);
> +	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS10);
> +
> +	if (phy->mode != MMC_TIMING_MMC_HS && phy->mode != MMC_TIMING_MMC_DDR52) {
> +		reg = 0x0;
> +		reg = FIELD_PREP(SDHCI_CDNS_HRS16_WRDATA1_SDCLK_DLY,
> +				 phy->settings.sdhc_wrdata1_sdclk_dly);
> +		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRDATA0_SDCLK_DLY,
> +				  phy->settings.sdhc_wrdata0_sdclk_dly);
> +		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRCMD1_SDCLK_DLY,
> +				  phy->settings.sdhc_wrcmd1_sdclk_dly);
> +		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRCMD0_SDCLK_DLY,
> +				  phy->settings.sdhc_wrcmd0_sdclk_dly);
> +		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRDATA1_DLY,
> +				  phy->settings.sdhc_wrdata1_dly);
> +		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRDATA0_DLY,
> +				  phy->settings.sdhc_wrdata0_dly);
> +		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRCMD1_DLY,
> +				  phy->settings.sdhc_wrcmd1_dly);
> +		reg |= FIELD_PREP(SDHCI_CDNS_HRS16_WRCMD0_DLY,
> +				  phy->settings.sdhc_wrcmd0_dly);
> +	} else {
> +		reg = 0x202;
> +	}
>  
> +	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS16);
> +
> +	reg = 0x0;
> +	reg = FIELD_PREP(SDHCI_CDNS_HRS07_RW_COMPENSATE,
> +			 phy->settings.sdhc_rw_compensate);
> +	reg |= FIELD_PREP(SDHCI_CDNS_HRS07_IDELAY_VAL,
> +			 phy->settings.sdhc_idelay_val);
> +	writel(reg, priv->hrs_addr + SDHCI_CDNS_HRS07);
>  	return 0;
>  }
>  
> @@ -174,6 +1106,19 @@ static void *sdhci_cdns_priv(struct sdhci_host *host)
>  	return sdhci_pltfm_priv(pltfm_host);
>  }
>  
> +static int sdhci_cdns_sd6_set_tune_val(struct sdhci_host *host,
> +				       unsigned int val)
> +{
> +	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> +	struct sdhci_cdns_sd6_phy *phy = priv->phy;
> +
> +	phy->settings.hs200_tune_val = val;
> +	phy->settings.cp_read_dqs_cmd_delay = val;
> +	phy->settings.cp_read_dqs_delay = val;
> +
> +	return sdhci_cdns_sd6_phy_init(priv);
> +}
> +
>  static unsigned int sdhci_cdns_get_timeout_clock(struct sdhci_host *host)
>  {
>  	/*
> @@ -183,6 +1128,11 @@ static unsigned int sdhci_cdns_get_timeout_clock(struct sdhci_host *host)
>  	return host->max_clk;
>  }
>  
> +static unsigned int sdhci_cdns_get_max_clock(struct sdhci_host *host)
> +{
> +	return SDMCLK_MAX_FREQ;
> +}
> +
>  static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode)
>  {
>  	u32 tmp;
> @@ -202,7 +1152,296 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
>  	return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
>  }
>  
> -static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
> +static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
> +					 unsigned int timing)
> +{
> +	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> +	u32 mode;
> +
> +	switch (timing) {
> +	case MMC_TIMING_MMC_HS:
> +		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
> +		break;
> +	case MMC_TIMING_MMC_DDR52:
> +		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
> +		break;
> +	case MMC_TIMING_MMC_HS200:
> +		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
> +		break;
> +	case MMC_TIMING_MMC_HS400:
> +		if (priv->enhanced_strobe)
> +			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
> +		else
> +			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
> +		break;
> +	case MMC_TIMING_SD_HS:
> +		mode = SDHCI_CDNS_HRS06_MODE_SD;
> +		break;
> +	default:
> +		mode = SDHCI_CDNS_HRS06_MODE_LEGACY;
> +		break;
> +	}
> +
> +	pr_debug("%s mode %d timing %d\n", __func__, mode, timing);
> +	sdhci_cdns_set_emmc_mode(priv, mode);
> +
> +	/* For SD, fall back to the default handler */
> +	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
> +		sdhci_set_uhs_signaling(host, timing);
> +}
> +
> +static int sdhci_cdns_sd6_phy_update_timings(struct sdhci_host *host)
> +{
> +	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> +	struct sdhci_cdns_sd6_phy *phy = priv->phy;
> +	int t_sdmclk = phy->t_sdmclk;
> +	int mode;
> +
> +	mode = sdhci_cdns_sd6_get_mode(host, host->mmc->ios.timing);
> +	/* initialize input */
> +	init_timings[mode](&phy->t, phy->t_sdclk);
> +
> +	phy->mode = host->mmc->ios.timing;
> +	phy->strobe_dat = false;
> +
> +	switch (phy->mode) {
> +	case MMC_TIMING_UHS_SDR104:
> +		phy->tune_cmd = true;
> +		phy->tune_dat = true;
> +		break;
> +	case MMC_TIMING_UHS_DDR50:
> +		phy->ddr = true;
> +		break;
> +	case MMC_TIMING_MMC_DDR52:
> +		phy->ddr = true;
> +		break;
> +	case MMC_TIMING_MMC_HS200:
> +		phy->tune_dat = true;
> +		phy->tune_cmd = true;
> +		break;
> +	case MMC_TIMING_MMC_HS400:
> +		phy->tune_cmd = true;
> +		phy->ddr = true;
> +		phy->strobe_dat = true;
> +		break;
> +	}
> +
> +	if (priv->enhanced_strobe)
> +		phy->strobe_cmd = true;
> +
> +	phy->d.phy_sdclk_delay = 2 * t_sdmclk;
> +	phy->d.phy_cmd_o_delay = 2 * t_sdmclk + t_sdmclk / 2;
> +	phy->d.phy_dat_o_delay = 2 * t_sdmclk + t_sdmclk / 2;
> +
> +	if (phy->t_sdclk == phy->t_sdmclk) {
> +		phy->settings.sdhc_extended_wr_mode = 0;
> +		phy->settings.sdhc_extended_rd_mode = 0;
> +	} else {
> +		phy->settings.sdhc_extended_wr_mode = 1;
> +		phy->settings.sdhc_extended_rd_mode = 1;
> +	}
> +
> +	phy->settings.cp_gate_cfg_always_on = 1;
> +
> +	sdhci_cdns_sd6_phy_configure_dll(phy);
> +
> +	sdhci_cdns_sd6_phy_calc_settings(phy);
> +
> +	return 0;
> +}
> +
> +static u32 sdhci_cdns_sd6_get_mode(struct sdhci_host *host,
> +				   unsigned int timing)
> +{
> +	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> +	u32 mode;
> +
> +	switch (timing) {
> +	case MMC_TIMING_MMC_HS:
> +		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
> +		break;
> +	case MMC_TIMING_MMC_DDR52:
> +		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
> +		break;
> +	case MMC_TIMING_MMC_HS200:
> +		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
> +		break;
> +	case MMC_TIMING_MMC_HS400:
> +		if (priv->enhanced_strobe)
> +			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
> +		else
> +			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
> +		break;
> +	case MMC_TIMING_SD_HS:
> +		mode = SDHCI_CDNS_HRS06_MODE_SD;
> +		break;
> +	default:
> +		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
> +		break;
> +	}
> +
> +	return mode;
> +}
> +
> +static void sdhci_cdns_sd6_set_uhs_signaling(struct sdhci_host *host,
> +					     unsigned int timing)
> +{
> +	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> +	struct sdhci_cdns_sd6_phy *phy = priv->phy;
> +
> +	sdhci_cdns_set_uhs_signaling(host, timing);
> +
> +	if ((phy->mode == -1) || (phy->t_sdclk == -1))
> +		return;
> +
> +	if (sdhci_cdns_sd6_phy_update_timings(host))
> +		pr_debug("%s: update timings failed\n", __func__);
> +
> +	if (sdhci_cdns_sd6_phy_init(priv))
> +		pr_debug("%s: phy init failed\n", __func__);
> +}
> +
> +static void sdhci_cdns_sd6_set_clock(struct sdhci_host *host,
> +				     unsigned int clock)
> +{
> +	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> +	struct sdhci_cdns_sd6_phy *phy = priv->phy;
> +
> +	phy->t_sdclk = DIV_ROUND_DOWN_ULL(1e12, clock);
> +
> +	pr_debug("%s %d %d\n", __func__, phy->mode, clock);
> +
> +	if (sdhci_cdns_sd6_phy_update_timings(host))
> +		pr_debug("%s: update timings failed\n", __func__);
> +
> +	if (sdhci_cdns_sd6_phy_init(priv))
> +		pr_debug("%s: phy init failed\n", __func__);
> +
> +	sdhci_set_clock(host, clock);
> +}
> +
> +static int sdhci_cdns_sd4_phy_probe(struct platform_device *pdev,
> +				    struct sdhci_cdns_priv *priv)
> +{
> +	unsigned int nr_phy_params;
> +	struct sdhci_cdns_sd4_phy *phy;
> +	struct device *dev = &pdev->dev;
> +
> +	nr_phy_params = sdhci_cdns_sd4_phy_param_count(dev->of_node);
> +	phy = devm_kzalloc(dev, struct_size(phy, phy_params, nr_phy_params),
> +			   GFP_KERNEL);
> +	if (!phy)
> +		return -ENOMEM;
> +
> +	phy->nr_phy_params = nr_phy_params;
> +
> +	sdhci_cdns_sd4_phy_param_parse(dev->of_node, phy);
> +	priv->phy = phy;
> +
> +	return 0;
> +}
> +
> +static int sdhci_cdns_sd6_phy_probe(struct platform_device *pdev,
> +				    struct sdhci_cdns_priv *priv)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct sdhci_cdns_sd6_phy *phy;
> +	u32 val;
> +	struct clk *clk;
> +	int ret;
> +	const char *mode_name;
> +
> +	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
> +	if (!phy)
> +		return -ENOMEM;
> +
> +	clk = devm_clk_get(dev, "sdmclk");
> +	if (IS_ERR(clk)) {
> +		dev_err(dev, "sdmclk get error\n");
> +		return PTR_ERR(clk);
> +	}
> +
> +	val = clk_get_rate(clk);
> +	phy->t_sdmclk = DIV_ROUND_DOWN_ULL(1e12, val);
> +
> +	ret = of_property_read_u32(dev->of_node, "cdns,host_slew",
> +				   &phy->settings.slew);
> +	if (ret)
> +		phy->settings.slew = 3;
> +
> +	ret = of_property_read_u32(dev->of_node, "cdns,host_drive",
> +				   &phy->settings.drive);
> +	if (ret)
> +		phy->settings.drive = 2;
> +
> +	ret = of_property_read_u32(dev->of_node, "cdns,iocell_input_delay",
> +				   &phy->d.iocell_input_delay);
> +	if (ret)
> +		phy->d.iocell_input_delay = 2500;
> +
> +	ret = of_property_read_u32(dev->of_node, "cdns,iocell_output_delay",
> +				   &phy->d.iocell_output_delay);
> +	if (ret)
> +		phy->d.iocell_output_delay = 2500;
> +
> +	ret = of_property_read_u32(dev->of_node, "cdns,delay_element",
> +				   &phy->d.delay_element);
> +	if (ret)
> +		phy->d.delay_element = 24;
> +
> +	ret = of_property_read_string_index(dev->of_node, "cdns,mode", 0,
> +					    &mode_name);
> +	if (!ret) {
> +		if (!strcmp("emmc_sdr", mode_name))
> +			phy->mode = MMC_TIMING_MMC_HS;
> +		else if (!strcmp("emmc_ddr", mode_name))
> +			phy->mode = MMC_TIMING_MMC_DDR52;
> +		else if (!strcmp("emmc_hs200", mode_name))
> +			phy->mode = MMC_TIMING_MMC_HS200;
> +		else if (!strcmp("emmc_hs400", mode_name))
> +			phy->mode = MMC_TIMING_MMC_HS400;
> +		else if (!strcmp("sd_hs", mode_name))
> +			phy->mode = MMC_TIMING_SD_HS;
> +		else
> +			phy->mode = MMC_TIMING_MMC_HS;
> +	} else {
> +		phy->mode = MMC_TIMING_MMC_HS;
> +	}
> +
> +	phy->d.delay_element_org = phy->d.delay_element;
> +	phy->d.iocell_input_delay = 650;
> +	phy->d.iocell_output_delay = 1800;
> +
> +	switch (phy->mode) {
> +	case MMC_TIMING_MMC_HS:
> +		phy->t_sdclk =  10000;
> +		break;
> +	case MMC_TIMING_MMC_DDR52:
> +		phy->t_sdclk = 10000;
> +		break;
> +	case MMC_TIMING_MMC_HS200:
> +		phy->t_sdclk = 5000;
> +		break;
> +	case MMC_TIMING_MMC_HS400:
> +		phy->t_sdclk = 5000;
> +		break;
> +	case MMC_TIMING_SD_HS:
> +		phy->t_sdclk = 100000;
> +		break;
> +	default:
> +		phy->t_sdclk = 10000;
> +		break;
> +	}
> +
> +	priv->phy = phy;
> +
> +	sdhci_cdns_sd6_get_delay_params(dev, priv);
> +
> +	sdhci_cdns_sd6_calc_phy(phy);
> +	return 0;
> +}
> +
> +static int sdhci_cdns_sd4_set_tune_val(struct sdhci_host *host, unsigned int val)
>  {
>  	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
>  	void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
> @@ -239,12 +1478,13 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
>   * In SD mode, software must not use the hardware tuning and instead perform
>   * an almost identical procedure to eMMC.
>   */
> -static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
> +static int sdhci_cdns_sd6_execute_tuning(struct sdhci_host *host, u32 opcode)
>  {
> +	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
>  	int cur_streak = 0;
>  	int max_streak = 0;
>  	int end_of_streak = 0;
> -	int i;
> +	int i, midpoint, iter = 0;
>  
>  	/*
>  	 * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
> @@ -254,8 +1494,8 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
>  	    host->timing != MMC_TIMING_UHS_SDR104)
>  		return 0;
>  
> -	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
> -		if (sdhci_cdns_set_tune_val(host, i) ||
> +	for (i = tune_val_start; iter < max_tune_iter; iter++, i += tune_val_step) {
> +		if (priv->cdns_data->set_tune_val(host, i) ||
>  		    mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
>  			cur_streak = 0;
>  		} else { /* good */
> @@ -263,6 +1503,12 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
>  			if (cur_streak > max_streak) {
>  				max_streak = cur_streak;
>  				end_of_streak = i;
> +				pr_debug("%s (%d-%d = %d)", __func__,
> +					 end_of_streak - ((cur_streak - 1) * tune_val_step),
> +					 end_of_streak, cur_streak);
> +			} else {
> +				pr_debug("%s (%d-%d)", __func__,
> +					 i - ((cur_streak - 1) * tune_val_step), i);
>  			}
>  		}
>  	}
> @@ -272,44 +1518,55 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
>  		return -EIO;
>  	}
>  
> -	return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
> +	pr_debug("max_streak: %d-%d", end_of_streak - ((max_streak - 1) * tune_val_step),
> +		 end_of_streak);
> +
> +	midpoint = end_of_streak - (((max_streak - 1) * tune_val_step) / 2);
> +
> +	return priv->cdns_data->set_tune_val(host, midpoint);
>  }
>  
> -static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
> -					 unsigned int timing)
> +/*
> + * In SD mode, software must not use the hardware tuning and instead perform
> + * an almost identical procedure to eMMC.
> + */
> +static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
>  {
> -	struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
> -	u32 mode;
> +	int cur_streak = 0;
> +	int max_streak = 0;
> +	int end_of_streak = 0;
> +	int i;
>  
> -	switch (timing) {
> -	case MMC_TIMING_MMC_HS:
> -		mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
> -		break;
> -	case MMC_TIMING_MMC_DDR52:
> -		mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
> -		break;
> -	case MMC_TIMING_MMC_HS200:
> -		mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
> -		break;
> -	case MMC_TIMING_MMC_HS400:
> -		if (priv->enhanced_strobe)
> -			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
> -		else
> -			mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
> -		break;
> -	default:
> -		mode = SDHCI_CDNS_HRS06_MODE_SD;
> -		break;
> +	/*
> +	 * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
> +	 * The delay is set by probe, based on the DT properties.
> +	 */
> +	if (host->timing != MMC_TIMING_MMC_HS200 &&
> +	    host->timing != MMC_TIMING_UHS_SDR104)
> +		return 0;
> +
> +	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
> +		if (sdhci_cdns_sd4_set_tune_val(host, i) ||
> +		    mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
> +			cur_streak = 0;
> +		} else { /* good */
> +			cur_streak++;
> +			if (cur_streak > max_streak) {
> +				max_streak = cur_streak;
> +				end_of_streak = i;
> +			}
> +		}
>  	}
>  
> -	sdhci_cdns_set_emmc_mode(priv, mode);
> +	if (!max_streak) {
> +		dev_err(mmc_dev(host->mmc), "no tuning point found\n");
> +		return -EIO;
> +	}
>  
> -	/* For SD, fall back to the default handler */
> -	if (mode == SDHCI_CDNS_HRS06_MODE_SD)
> -		sdhci_set_uhs_signaling(host, timing);
> +	return sdhci_cdns_sd4_set_tune_val(host, end_of_streak - max_streak / 2);
>  }
>  
> -static const struct sdhci_ops sdhci_cdns_ops = {
> +static const struct sdhci_ops sdhci_cdns_sd4_ops = {
>  	.set_clock = sdhci_set_clock,
>  	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
>  	.set_bus_width = sdhci_set_bus_width,
> @@ -318,13 +1575,49 @@ static const struct sdhci_ops sdhci_cdns_ops = {
>  	.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
>  };
>  
> +static const struct sdhci_ops sdhci_cdns_sd6_ops = {
> +	.get_max_clock = sdhci_cdns_get_max_clock,
> +	.set_clock = sdhci_cdns_sd6_set_clock,
> +	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
> +	.set_bus_width = sdhci_set_bus_width,
> +	.reset = sdhci_reset,
> +	.platform_execute_tuning = sdhci_cdns_sd6_execute_tuning,
> +	.set_uhs_signaling = sdhci_cdns_sd6_set_uhs_signaling,
> +};
> +
>  static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
> -	.ops = &sdhci_cdns_ops,
> +	.ops = &sdhci_cdns_sd4_ops,
>  	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
>  };
>  
> -static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
> -	.ops = &sdhci_cdns_ops,
> +static const struct sdhci_pltfm_data sdhci_cdns_sd4_pltfm_data = {
> +	.ops = &sdhci_cdns_sd4_ops,
> +};
> +
> +static const struct sdhci_pltfm_data sdhci_cdns_sd6_pltfm_data = {
> +	.ops = &sdhci_cdns_sd6_ops,
> +};
> +
> +static const struct sdhci_cdns_data sdhci_cdns_sd4_data = {
> +	.phy_init = sdhci_cdns_sd4_phy_init,
> +	.set_tune_val = sdhci_cdns_sd4_set_tune_val,
> +};
> +
> +static const struct sdhci_cdns_data sdhci_cdns_sd6_data = {
> +	.phy_init = sdhci_cdns_sd6_phy_init,
> +	.set_tune_val = sdhci_cdns_sd6_set_tune_val,
> +};
> +
> +static const struct sdhci_cdns_of_data sdhci_cdns_sd4_of_data = {
> +	.pltfm_data = &sdhci_cdns_sd4_pltfm_data,
> +	.cdns_data = &sdhci_cdns_sd4_data,
> +	.phy_probe = sdhci_cdns_sd4_phy_probe,
> +};
> +
> +static const struct sdhci_cdns_of_data sdhci_cdns_sd6_of_data = {
> +	.pltfm_data = &sdhci_cdns_sd6_pltfm_data,
> +	.cdns_data = &sdhci_cdns_sd6_data,
> +	.phy_probe = sdhci_cdns_sd6_phy_probe,
>  };
>  
>  static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
> @@ -350,14 +1643,12 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
>  static int sdhci_cdns_probe(struct platform_device *pdev)
>  {
>  	struct sdhci_host *host;
> -	const struct sdhci_pltfm_data *data;
> +	const struct sdhci_cdns_of_data *data;
>  	struct sdhci_pltfm_host *pltfm_host;
>  	struct sdhci_cdns_priv *priv;
>  	struct clk *clk;
> -	unsigned int nr_phy_params;
>  	int ret;
>  	struct device *dev = &pdev->dev;
> -	static const u16 version = SDHCI_SPEC_400 << SDHCI_SPEC_VER_SHIFT;
>  
>  	clk = devm_clk_get(dev, NULL);
>  	if (IS_ERR(clk))
> @@ -368,12 +1659,12 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	data = of_device_get_match_data(dev);
> -	if (!data)
> -		data = &sdhci_cdns_pltfm_data;
> +	if (!data) {
> +		return PTR_ERR(clk);
> +		goto disable_clk;
> +	}
>  
> -	nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
> -	host = sdhci_pltfm_init(pdev, data,
> -				struct_size(priv, phy_params, nr_phy_params));
> +	host = sdhci_pltfm_init(pdev, data->pltfm_data, sizeof(*priv));
>  	if (IS_ERR(host)) {
>  		ret = PTR_ERR(host);
>  		goto disable_clk;
> @@ -382,15 +1673,17 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
>  	pltfm_host = sdhci_priv(host);
>  	pltfm_host->clk = clk;
>  
> +	host->clk_mul = 0;
> +	host->max_clk = SDMCLK_MAX_FREQ;
> +	host->quirks |=  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
> +	host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
>  	priv = sdhci_pltfm_priv(pltfm_host);
> -	priv->nr_phy_params = nr_phy_params;
>  	priv->hrs_addr = host->ioaddr;
>  	priv->enhanced_strobe = false;
> +	priv->cdns_data = data->cdns_data;
>  	host->ioaddr += SDHCI_CDNS_SRS_BASE;
>  	host->mmc_host_ops.hs400_enhanced_strobe =
>  				sdhci_cdns_hs400_enhanced_strobe;
> -	sdhci_enable_v4_mode(host);
> -	__sdhci_read_caps(host, &version, NULL, NULL);
>  
>  	sdhci_get_of_property(pdev);
>  
> @@ -398,12 +1691,16 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto free;
>  
> -	sdhci_cdns_phy_param_parse(dev->of_node, priv);
> +	ret = data->phy_probe(pdev, priv);
> +	if (ret)
> +		goto free;
>  
> -	ret = sdhci_cdns_phy_init(priv);
> +	ret = priv->cdns_data->phy_init(priv);
>  	if (ret)
>  		goto free;
>  
> +	sdhci_enable_v4_mode(host);
> +	__sdhci_read_caps(host, NULL, NULL, NULL);
>  	ret = sdhci_add_host(host);
>  	if (ret)
>  		goto free;
> @@ -429,7 +1726,7 @@ static int sdhci_cdns_resume(struct device *dev)
>  	if (ret)
>  		return ret;
>  
> -	ret = sdhci_cdns_phy_init(priv);
> +	ret = priv->cdns_data->phy_init(priv);
>  	if (ret)
>  		goto disable_clk;
>  
> @@ -455,7 +1752,14 @@ static const struct of_device_id sdhci_cdns_match[] = {
>  		.compatible = "socionext,uniphier-sd4hc",
>  		.data = &sdhci_cdns_uniphier_pltfm_data,
>  	},
> -	{ .compatible = "cdns,sd4hc" },
> +	{
> +		.compatible = "cdns,sd4hc",
> +		.data = &sdhci_cdns_sd4_of_data,
> +	},
> +	{
> +		.compatible = "cdns,sd6hc",
> +		.data = &sdhci_cdns_sd6_of_data,
> +	},
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, sdhci_cdns_match);


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS
  2022-12-19 14:24 ` [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS Piyush Malgujar
@ 2023-01-11  8:23   ` Adrian Hunter
  2023-01-12 14:12     ` Piyush Malgujar
  0 siblings, 1 reply; 19+ messages in thread
From: Adrian Hunter @ 2023-01-11  8:23 UTC (permalink / raw)
  To: Piyush Malgujar, linux-mmc, linux-kernel, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva

On 19/12/22 16:24, Piyush Malgujar wrote:
> From: Jayanthi Annadurai <jannadurai@marvell.com>
> 
> Add support for CONFIG_MMC_SDHCI_IO_ACCESSORS for controller
> specific register read and write APIs.
> 
> Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> ---
>  drivers/mmc/host/Kconfig         | 12 ++++++
>  drivers/mmc/host/sdhci-cadence.c | 63 ++++++++++++++++++++++++++++++++
>  2 files changed, 75 insertions(+)
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 5e19a961c34d7b5664ab2fd43cfba82dc90913ac..b5b2ae0bb4625bdb9d17acdbb1887c9caa3a1f32 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -262,6 +262,18 @@ config MMC_SDHCI_CADENCE
>  
>  	  If unsure, say N.
>  
> +config MMC_SDHCI_CN10K
> +	tristate "SDHCI Cadence support for Marvell CN10K platforms"
> +	select MMC_SDHCI_CADENCE
> +	select MMC_SDHCI_IO_ACCESSORS

Probably better to just add MMC_SDHCI_IO_ACCESSORS to 
config MMC_SDHCI_CADENCE and drop MMC_SDHCI_CN10K

> +	help
> +	  This selects the SDHCI cadence driver and IO Accessors
> +	  for Marvell CN10K platforms
> +
> +	  If you have Marvell CN10K platform, say Y or M here.
> +
> +	  If unsure, say N.
> +
>  config MMC_SDHCI_CNS3XXX
>  	tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
>  	depends on ARCH_CNS3XXX || COMPILE_TEST
> diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
> index 5332d19e489be936d6814feba4f0fc046f5e130e..6bf703f15bc5be7e3be4cb1144b78ec3585ec540 100644
> --- a/drivers/mmc/host/sdhci-cadence.c
> +++ b/drivers/mmc/host/sdhci-cadence.c
> @@ -449,6 +449,61 @@ static u32 read_dqs_cmd_delay, clk_wrdqs_delay, clk_wr_delay, read_dqs_delay;
>  
>  static u32 sdhci_cdns_sd6_get_mode(struct sdhci_host *host, unsigned int timing);
>  
> +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> +static u32 sdhci_cdns_sd6_readl(struct sdhci_host *host, int reg)
> +{
> +	return readl(host->ioaddr + reg);
> +}
> +
> +static void sdhci_cdns_sd6_writel(struct sdhci_host *host, u32 val, int reg)
> +{
> +	writel(val, host->ioaddr + reg);
> +}
> +
> +static u16 sdhci_cdns_sd6_readw(struct sdhci_host *host, int reg)
> +{
> +	u32 val, regoff;
> +
> +	regoff = reg & ~3;
> +
> +	val = readl(host->ioaddr + regoff);
> +	if ((reg & 0x3) == 0)
> +		return (val & 0xFFFF);
> +	else
> +		return ((val >> 16) & 0xFFFF);
> +}
> +
> +static void sdhci_cdns_sd6_writew(struct sdhci_host *host, u16 val, int reg)
> +{
> +	writew(val, host->ioaddr + reg);
> +}
> +
> +static u8 sdhci_cdns_sd6_readb(struct sdhci_host *host, int reg)
> +{
> +	u32 val, regoff;
> +
> +	regoff = reg & ~3;
> +
> +	val = readl(host->ioaddr + regoff);
> +	switch (reg & 3) {
> +	case 0:
> +		return (val & 0xFF);
> +	case 1:
> +		return ((val >> 8) & 0xFF);
> +	case 2:
> +		return ((val >> 16) & 0xFF);
> +	case 3:
> +		return ((val >> 24) & 0xFF);
> +	}
> +	return 0;
> +}
> +
> +static void sdhci_cdns_sd6_writeb(struct sdhci_host *host, u8 val, int reg)
> +{
> +	writeb(val, host->ioaddr + reg);
> +}
> +#endif
> +
>  static int sdhci_cdns_sd6_phy_lock_dll(struct sdhci_cdns_sd6_phy *phy)
>  {
>  	u32 delay_element = phy->d.delay_element_org;
> @@ -1576,6 +1631,14 @@ static const struct sdhci_ops sdhci_cdns_sd4_ops = {
>  };
>  
>  static const struct sdhci_ops sdhci_cdns_sd6_ops = {
> +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> +	.read_l = sdhci_cdns_sd6_readl,
> +	.write_l = sdhci_cdns_sd6_writel,
> +	.read_w = sdhci_cdns_sd6_readw,
> +	.write_w = sdhci_cdns_sd6_writew,
> +	.read_b = sdhci_cdns_sd6_readb,
> +	.write_b = sdhci_cdns_sd6_writeb,
> +#endif
>  	.get_max_clock = sdhci_cdns_get_max_clock,
>  	.set_clock = sdhci_cdns_sd6_set_clock,
>  	.get_timeout_clock = sdhci_cdns_get_timeout_clock,


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver.
  2022-12-19 14:24 ` [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver Piyush Malgujar
@ 2023-01-11  8:29   ` Adrian Hunter
  0 siblings, 0 replies; 19+ messages in thread
From: Adrian Hunter @ 2023-01-11  8:29 UTC (permalink / raw)
  To: Piyush Malgujar, linux-mmc, linux-kernel, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree
  Cc: jannadurai, cchavva

On 19/12/22 16:24, Piyush Malgujar wrote:
> From: Jayanthi Annadurai <jannadurai@marvell.com>
> 
> Use Kernel config CONFIG_MMC_DEBUG to support dumping PHY and host
> controller register configuration for debug.
> 
> Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> ---
>  drivers/mmc/host/sdhci-cadence.c | 100 +++++++++++++++++++++++++++++++
>  1 file changed, 100 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
> index 6bf703f15bc5be7e3be4cb1144b78ec3585ec540..75363aabce9228755c4abed08fe17e57d1a44b23 100644
> --- a/drivers/mmc/host/sdhci-cadence.c
> +++ b/drivers/mmc/host/sdhci-cadence.c
> @@ -15,6 +15,10 @@
>  
>  #include "sdhci-pltfm.h"
>  
> +#ifdef CONFIG_MMC_DEBUG
> +#define DEBUG_DRV	pr_info

Not sure what the point of that is

> +#endif
> +
>  #define SDMCLK_MAX_FREQ		200000000
>  
>  #define DEFAULT_CMD_DELAY		16
> @@ -115,6 +119,10 @@
>  #define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_CLK_WR_DELAY		GENMASK(15, 8)
>  #define	SDHCI_CDNS_SD6_PHY_DLL_SLAVE_READ_DQS_DELAY		GENMASK(7, 0)
>  
> +#define SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0				0x201C
> +#define SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1				0x2020
> +#define SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2				0x2024
> +
>  #define SDHCI_CDNS_SD6_PHY_CTRL					0x2080
>  #define	SDHCI_CDNS_SD6_PHY_CTRL_PHONY_DQS_TIMING		GENMASK(9, 4)
>  
> @@ -969,6 +977,94 @@ static void sdhci_cdns_sd6_calc_phy(struct sdhci_cdns_sd6_phy *phy)
>  	}
>  }
>  
> +#ifdef CONFIG_MMC_DEBUG

Put the DEBUG_DRV definition here instead of above i.e.

#define DEBUG_DRV	pr_info

> +static void sdhci_cdns_sd6_phy_dump(struct sdhci_cdns_sd6_phy *phy)
> +{
> +	DEBUG_DRV("PHY Timings\n");
> +	DEBUG_DRV("mode %d t_sdclk %d\n", phy->mode, phy->t_sdclk);
> +
> +	DEBUG_DRV("cp_clk_wr_delay %d\n", phy->settings.cp_clk_wr_delay);
> +	DEBUG_DRV("cp_clk_wrdqs_delay %d\n", phy->settings.cp_clk_wrdqs_delay);
> +	DEBUG_DRV("cp_data_select_oe_end %d\n", phy->settings.cp_data_select_oe_end);
> +	DEBUG_DRV("cp_dll_bypass_mode %d\n", phy->settings.cp_dll_bypass_mode);
> +	DEBUG_DRV("cp_dll_locked_mode %d\n", phy->settings.cp_dll_locked_mode);
> +	DEBUG_DRV("cp_dll_start_point %d\n", phy->settings.cp_dll_start_point);
> +	DEBUG_DRV("cp_io_mask_always_on %d\n", phy->settings.cp_io_mask_always_on);
> +	DEBUG_DRV("cp_io_mask_end %d\n", phy->settings.cp_io_mask_end);
> +	DEBUG_DRV("cp_io_mask_start %d\n", phy->settings.cp_io_mask_start);
> +	DEBUG_DRV("cp_rd_del_sel %d\n", phy->settings.cp_rd_del_sel);
> +	DEBUG_DRV("cp_read_dqs_cmd_delay %d\n", phy->settings.cp_read_dqs_cmd_delay);
> +	DEBUG_DRV("cp_read_dqs_delay %d\n", phy->settings.cp_read_dqs_delay);
> +	DEBUG_DRV("cp_sw_half_cycle_shift %d\n", phy->settings.cp_sw_half_cycle_shift);
> +	DEBUG_DRV("cp_sync_method %d\n", phy->settings.cp_sync_method);
> +	DEBUG_DRV("cp_use_ext_lpbk_dqs %d\n", phy->settings.cp_use_ext_lpbk_dqs);
> +	DEBUG_DRV("cp_use_lpbk_dqs %d\n", phy->settings.cp_use_lpbk_dqs);
> +	DEBUG_DRV("cp_use_phony_dqs %d\n", phy->settings.cp_use_phony_dqs);
> +	DEBUG_DRV("cp_use_phony_dqs_cmd %d\n", phy->settings.cp_use_phony_dqs_cmd);
> +	DEBUG_DRV("sdhc_extended_rd_mode %d\n", phy->settings.sdhc_extended_rd_mode);
> +	DEBUG_DRV("sdhc_extended_wr_mode %d\n", phy->settings.sdhc_extended_wr_mode);
> +
> +	DEBUG_DRV("sdhc_hcsdclkadj %d\n", phy->settings.sdhc_hcsdclkadj);
> +	DEBUG_DRV("sdhc_idelay_val %d\n", phy->settings.sdhc_idelay_val);
> +	DEBUG_DRV("sdhc_rdcmd_en %d\n", phy->settings.sdhc_rdcmd_en);
> +	DEBUG_DRV("sdhc_rddata_en %d\n", phy->settings.sdhc_rddata_en);
> +	DEBUG_DRV("sdhc_rw_compensate %d\n", phy->settings.sdhc_rw_compensate);
> +	DEBUG_DRV("sdhc_sdcfsh %d\n", phy->settings.sdhc_sdcfsh);
> +	DEBUG_DRV("sdhc_sdcfsl %d\n", phy->settings.sdhc_sdcfsl);
> +	DEBUG_DRV("sdhc_wrcmd0_dly %d %d\n",
> +		  phy->settings.sdhc_wrcmd0_dly, phy->settings.sdhc_wrcmd0_sdclk_dly);
> +	DEBUG_DRV("sdhc_wrcmd1_dly %d %d\n",
> +		  phy->settings.sdhc_wrcmd1_dly, phy->settings.sdhc_wrcmd1_sdclk_dly);
> +	DEBUG_DRV("sdhc_wrdata0_dly %d %d\n",
> +		  phy->settings.sdhc_wrdata0_dly, phy->settings.sdhc_wrdata0_sdclk_dly);
> +
> +	DEBUG_DRV("sdhc_wrdata1_dly %d %d\n",
> +		  phy->settings.sdhc_wrdata1_dly, phy->settings.sdhc_wrdata1_sdclk_dly);
> +	DEBUG_DRV("hs200_tune_val %d\n", phy->settings.hs200_tune_val);
> +}
> +
> +void sdhci_cdns_sd6_dump(struct sdhci_cdns_priv *priv)

static

> +{
> +	struct sdhci_cdns_sd6_phy *phy = priv->phy;
> +	int id;
> +
> +	sdhci_cdns_sd6_phy_dump(phy);
> +
> +	DEBUG_DRV("Host controller Register Dump\n");
> +	for (id = 0; id < 14; id++)
> +		DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
> +
> +	id = 29;
> +	DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
> +	id = 30;
> +	DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
> +
> +	for (id = 0; id < 27; id++)
> +		DEBUG_DRV("SRS%d 0x%x\n", id, readl(priv->hrs_addr + 0x200 + (id * 4)));
> +
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DQS_TIMING 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQS_TIMING));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_GATE_LPBK 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GATE_LPBK));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_MASTER 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_MASTER));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_SLAVE 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_SLAVE));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_CTRL 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_CTRL));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_GPIO_CTRL0 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GPIO_CTRL0));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DQ_TIMING 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQ_TIMING));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1));
> +	DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2 0x%x\n",
> +		  sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2));
> +}

Make a stub for sdhci_cdns_sd6_dump() i.e.

#else

static inline void sdhci_cdns_sd6_dump(struct sdhci_cdns_priv *priv)
{
}

> +#endif
> +
>  static int sdhci_cdns_sd6_get_delay_params(struct device *dev, struct sdhci_cdns_priv *priv)
>  {
>  	struct sdhci_cdns_sd6_phy *phy = priv->phy;
> @@ -1373,6 +1469,10 @@ static void sdhci_cdns_sd6_set_clock(struct sdhci_host *host,
>  		pr_debug("%s: phy init failed\n", __func__);
>  
>  	sdhci_set_clock(host, clock);
> +
> +#ifdef CONFIG_MMC_DEBUG
> +	sdhci_cdns_sd6_dump(priv);
> +#endif

With the stub above, #ifdef CONFIG_MMC_DEBUG / #endif
is no longer needed here.

>  }
>  
>  static int sdhci_cdns_sd4_phy_probe(struct platform_device *pdev,


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout
  2023-01-11  8:08   ` Adrian Hunter
@ 2023-01-12 13:44     ` Piyush Malgujar
  0 siblings, 0 replies; 19+ messages in thread
From: Piyush Malgujar @ 2023-01-12 13:44 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: linux-mmc, linux-kernel, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree, jannadurai,
	cchavva

Hi Adrian,

Thanks for the review comments.

On Wed, Jan 11, 2023 at 10:08:26AM +0200, Adrian Hunter wrote:
> On 19/12/22 16:24, Piyush Malgujar wrote:
> > From: Jayanthi Annadurai <jannadurai@marvell.com>
> > 
> > Add config option to choose the sdhci timeout in seconds.
> 
> This approach is not ok, but why is the change wanted?
> 

This option was just to give flexibility to opt for a different timeout value based
on requirement, for instance, to decrease the time of tuning process. 
Although it is not a mandatory change, we can remove this option and go with the
default one.

> > 
> > Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> > Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> > ---
> >  drivers/mmc/host/Kconfig | 8 ++++++++
> >  drivers/mmc/host/sdhci.c | 3 ++-
> >  2 files changed, 10 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> > index b5b2ae0bb4625bdb9d17acdbb1887c9caa3a1f32..ab48f2bc4cff73d1aad8d7da542d761cf0346d9f 100644
> > --- a/drivers/mmc/host/Kconfig
> > +++ b/drivers/mmc/host/Kconfig
> > @@ -1132,3 +1132,11 @@ config MMC_LITEX
> >  	  module will be called litex_mmc.
> >  
> >  	  If unsure, say N.
> > +
> > +config MMC_SDHCI_TIMEOUT
> > +	int
> > +	default 1 if MMC_SDHCI_CADENCE
> > +	default 10
> > +	depends on MMC_SDHCI
> > +	help
> > +	  Default timeout value for command and data.
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index f3af1bd0f7b955272fbd8b034ecb591860b89aed..e9bc24258746834ec9c8f13fe24456587a2b758d 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -1707,7 +1707,8 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
> >  	else if (!cmd->data && cmd->busy_timeout > 9000)
> >  		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
> >  	else
> > -		timeout += 10 * HZ;
> > +		timeout += CONFIG_MMC_SDHCI_TIMEOUT * HZ;
> > +
> >  	sdhci_mod_timer(host, cmd->mrq, timeout);
> >  
> >  	if (host->use_external_dma)
>

Thanks,
Piyush 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS
  2023-01-11  8:23   ` Adrian Hunter
@ 2023-01-12 14:12     ` Piyush Malgujar
  2023-01-13  7:20       ` Adrian Hunter
  0 siblings, 1 reply; 19+ messages in thread
From: Piyush Malgujar @ 2023-01-12 14:12 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: linux-mmc, linux-kernel, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree, jannadurai,
	cchavva

Hi Adrian, 

Thank you for the review comments.

On Wed, Jan 11, 2023 at 10:23:43AM +0200, Adrian Hunter wrote:
> On 19/12/22 16:24, Piyush Malgujar wrote:
> > From: Jayanthi Annadurai <jannadurai@marvell.com>
> > 
> > Add support for CONFIG_MMC_SDHCI_IO_ACCESSORS for controller
> > specific register read and write APIs.
> > 
> > Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> > Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> > ---
> >  drivers/mmc/host/Kconfig         | 12 ++++++
> >  drivers/mmc/host/sdhci-cadence.c | 63 ++++++++++++++++++++++++++++++++
> >  2 files changed, 75 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> > index 5e19a961c34d7b5664ab2fd43cfba82dc90913ac..b5b2ae0bb4625bdb9d17acdbb1887c9caa3a1f32 100644
> > --- a/drivers/mmc/host/Kconfig
> > +++ b/drivers/mmc/host/Kconfig
> > @@ -262,6 +262,18 @@ config MMC_SDHCI_CADENCE
> >  
> >  	  If unsure, say N.
> >  
> > +config MMC_SDHCI_CN10K
> > +	tristate "SDHCI Cadence support for Marvell CN10K platforms"
> > +	select MMC_SDHCI_CADENCE
> > +	select MMC_SDHCI_IO_ACCESSORS
> 
> Probably better to just add MMC_SDHCI_IO_ACCESSORS to 
> config MMC_SDHCI_CADENCE and drop MMC_SDHCI_CN10K
> 

This reason behind this was to not force SDHCI_IO_ACCESSORS upon cadence users as some may not
require it owing to how cadence ip is integrated to soc.

> > +	help
> > +	  This selects the SDHCI cadence driver and IO Accessors
> > +	  for Marvell CN10K platforms
> > +
> > +	  If you have Marvell CN10K platform, say Y or M here.
> > +
> > +	  If unsure, say N.
> > +
> >  config MMC_SDHCI_CNS3XXX
> >  	tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
> >  	depends on ARCH_CNS3XXX || COMPILE_TEST
> > diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
> > index 5332d19e489be936d6814feba4f0fc046f5e130e..6bf703f15bc5be7e3be4cb1144b78ec3585ec540 100644
> > --- a/drivers/mmc/host/sdhci-cadence.c
> > +++ b/drivers/mmc/host/sdhci-cadence.c
> > @@ -449,6 +449,61 @@ static u32 read_dqs_cmd_delay, clk_wrdqs_delay, clk_wr_delay, read_dqs_delay;
> >  
> >  static u32 sdhci_cdns_sd6_get_mode(struct sdhci_host *host, unsigned int timing);
> >  
> > +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> > +static u32 sdhci_cdns_sd6_readl(struct sdhci_host *host, int reg)
> > +{
> > +	return readl(host->ioaddr + reg);
> > +}
> > +
> > +static void sdhci_cdns_sd6_writel(struct sdhci_host *host, u32 val, int reg)
> > +{
> > +	writel(val, host->ioaddr + reg);
> > +}
> > +
> > +static u16 sdhci_cdns_sd6_readw(struct sdhci_host *host, int reg)
> > +{
> > +	u32 val, regoff;
> > +
> > +	regoff = reg & ~3;
> > +
> > +	val = readl(host->ioaddr + regoff);
> > +	if ((reg & 0x3) == 0)
> > +		return (val & 0xFFFF);
> > +	else
> > +		return ((val >> 16) & 0xFFFF);
> > +}
> > +
> > +static void sdhci_cdns_sd6_writew(struct sdhci_host *host, u16 val, int reg)
> > +{
> > +	writew(val, host->ioaddr + reg);
> > +}
> > +
> > +static u8 sdhci_cdns_sd6_readb(struct sdhci_host *host, int reg)
> > +{
> > +	u32 val, regoff;
> > +
> > +	regoff = reg & ~3;
> > +
> > +	val = readl(host->ioaddr + regoff);
> > +	switch (reg & 3) {
> > +	case 0:
> > +		return (val & 0xFF);
> > +	case 1:
> > +		return ((val >> 8) & 0xFF);
> > +	case 2:
> > +		return ((val >> 16) & 0xFF);
> > +	case 3:
> > +		return ((val >> 24) & 0xFF);
> > +	}
> > +	return 0;
> > +}
> > +
> > +static void sdhci_cdns_sd6_writeb(struct sdhci_host *host, u8 val, int reg)
> > +{
> > +	writeb(val, host->ioaddr + reg);
> > +}
> > +#endif
> > +
> >  static int sdhci_cdns_sd6_phy_lock_dll(struct sdhci_cdns_sd6_phy *phy)
> >  {
> >  	u32 delay_element = phy->d.delay_element_org;
> > @@ -1576,6 +1631,14 @@ static const struct sdhci_ops sdhci_cdns_sd4_ops = {
> >  };
> >  
> >  static const struct sdhci_ops sdhci_cdns_sd6_ops = {
> > +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> > +	.read_l = sdhci_cdns_sd6_readl,
> > +	.write_l = sdhci_cdns_sd6_writel,
> > +	.read_w = sdhci_cdns_sd6_readw,
> > +	.write_w = sdhci_cdns_sd6_writew,
> > +	.read_b = sdhci_cdns_sd6_readb,
> > +	.write_b = sdhci_cdns_sd6_writeb,
> > +#endif
> >  	.get_max_clock = sdhci_cdns_get_max_clock,
> >  	.set_clock = sdhci_cdns_sd6_set_clock,
> >  	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
> 

Rest of the comments will be taken care in v2.

Thanks,
Piyush

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS
  2023-01-12 14:12     ` Piyush Malgujar
@ 2023-01-13  7:20       ` Adrian Hunter
  0 siblings, 0 replies; 19+ messages in thread
From: Adrian Hunter @ 2023-01-13  7:20 UTC (permalink / raw)
  To: Piyush Malgujar
  Cc: linux-mmc, linux-kernel, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree, jannadurai,
	cchavva

On 12/01/23 16:12, Piyush Malgujar wrote:
> Hi Adrian, 
> 
> Thank you for the review comments.
> 
> On Wed, Jan 11, 2023 at 10:23:43AM +0200, Adrian Hunter wrote:
>> On 19/12/22 16:24, Piyush Malgujar wrote:
>>> From: Jayanthi Annadurai <jannadurai@marvell.com>
>>>
>>> Add support for CONFIG_MMC_SDHCI_IO_ACCESSORS for controller
>>> specific register read and write APIs.
>>>
>>> Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
>>> Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
>>> ---
>>>  drivers/mmc/host/Kconfig         | 12 ++++++
>>>  drivers/mmc/host/sdhci-cadence.c | 63 ++++++++++++++++++++++++++++++++
>>>  2 files changed, 75 insertions(+)
>>>
>>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
>>> index 5e19a961c34d7b5664ab2fd43cfba82dc90913ac..b5b2ae0bb4625bdb9d17acdbb1887c9caa3a1f32 100644
>>> --- a/drivers/mmc/host/Kconfig
>>> +++ b/drivers/mmc/host/Kconfig
>>> @@ -262,6 +262,18 @@ config MMC_SDHCI_CADENCE
>>>  
>>>  	  If unsure, say N.
>>>  
>>> +config MMC_SDHCI_CN10K
>>> +	tristate "SDHCI Cadence support for Marvell CN10K platforms"
>>> +	select MMC_SDHCI_CADENCE
>>> +	select MMC_SDHCI_IO_ACCESSORS
>>
>> Probably better to just add MMC_SDHCI_IO_ACCESSORS to 
>> config MMC_SDHCI_CADENCE and drop MMC_SDHCI_CN10K
>>
> 
> This reason behind this was to not force SDHCI_IO_ACCESSORS upon cadence users as some may not
> require it owing to how cadence ip is integrated to soc.

In practice, it makes no difference to performance and adds a
negligible amount of code, so it is not worth the extra complexity
to make it conditional.

> 
>>> +	help
>>> +	  This selects the SDHCI cadence driver and IO Accessors
>>> +	  for Marvell CN10K platforms
>>> +
>>> +	  If you have Marvell CN10K platform, say Y or M here.
>>> +
>>> +	  If unsure, say N.
>>> +
>>>  config MMC_SDHCI_CNS3XXX
>>>  	tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
>>>  	depends on ARCH_CNS3XXX || COMPILE_TEST
>>> diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
>>> index 5332d19e489be936d6814feba4f0fc046f5e130e..6bf703f15bc5be7e3be4cb1144b78ec3585ec540 100644
>>> --- a/drivers/mmc/host/sdhci-cadence.c
>>> +++ b/drivers/mmc/host/sdhci-cadence.c
>>> @@ -449,6 +449,61 @@ static u32 read_dqs_cmd_delay, clk_wrdqs_delay, clk_wr_delay, read_dqs_delay;
>>>  
>>>  static u32 sdhci_cdns_sd6_get_mode(struct sdhci_host *host, unsigned int timing);
>>>  
>>> +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
>>> +static u32 sdhci_cdns_sd6_readl(struct sdhci_host *host, int reg)
>>> +{
>>> +	return readl(host->ioaddr + reg);
>>> +}
>>> +
>>> +static void sdhci_cdns_sd6_writel(struct sdhci_host *host, u32 val, int reg)
>>> +{
>>> +	writel(val, host->ioaddr + reg);
>>> +}
>>> +
>>> +static u16 sdhci_cdns_sd6_readw(struct sdhci_host *host, int reg)
>>> +{
>>> +	u32 val, regoff;
>>> +
>>> +	regoff = reg & ~3;
>>> +
>>> +	val = readl(host->ioaddr + regoff);
>>> +	if ((reg & 0x3) == 0)
>>> +		return (val & 0xFFFF);
>>> +	else
>>> +		return ((val >> 16) & 0xFFFF);
>>> +}
>>> +
>>> +static void sdhci_cdns_sd6_writew(struct sdhci_host *host, u16 val, int reg)
>>> +{
>>> +	writew(val, host->ioaddr + reg);
>>> +}
>>> +
>>> +static u8 sdhci_cdns_sd6_readb(struct sdhci_host *host, int reg)
>>> +{
>>> +	u32 val, regoff;
>>> +
>>> +	regoff = reg & ~3;
>>> +
>>> +	val = readl(host->ioaddr + regoff);
>>> +	switch (reg & 3) {
>>> +	case 0:
>>> +		return (val & 0xFF);
>>> +	case 1:
>>> +		return ((val >> 8) & 0xFF);
>>> +	case 2:
>>> +		return ((val >> 16) & 0xFF);
>>> +	case 3:
>>> +		return ((val >> 24) & 0xFF);
>>> +	}
>>> +	return 0;
>>> +}
>>> +
>>> +static void sdhci_cdns_sd6_writeb(struct sdhci_host *host, u8 val, int reg)
>>> +{
>>> +	writeb(val, host->ioaddr + reg);
>>> +}
>>> +#endif
>>> +
>>>  static int sdhci_cdns_sd6_phy_lock_dll(struct sdhci_cdns_sd6_phy *phy)
>>>  {
>>>  	u32 delay_element = phy->d.delay_element_org;
>>> @@ -1576,6 +1631,14 @@ static const struct sdhci_ops sdhci_cdns_sd4_ops = {
>>>  };
>>>  
>>>  static const struct sdhci_ops sdhci_cdns_sd6_ops = {
>>> +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
>>> +	.read_l = sdhci_cdns_sd6_readl,
>>> +	.write_l = sdhci_cdns_sd6_writel,
>>> +	.read_w = sdhci_cdns_sd6_readw,
>>> +	.write_w = sdhci_cdns_sd6_writew,
>>> +	.read_b = sdhci_cdns_sd6_readb,
>>> +	.write_b = sdhci_cdns_sd6_writeb,
>>> +#endif
>>>  	.get_max_clock = sdhci_cdns_get_max_clock,
>>>  	.set_clock = sdhci_cdns_sd6_set_clock,
>>>  	.get_timeout_clock = sdhci_cdns_get_timeout_clock,
>>
> 
> Rest of the comments will be taken care in v2.
> 
> Thanks,
> Piyush


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support
  2023-01-07 13:25       ` Krzysztof Kozlowski
@ 2023-01-18 16:02         ` Piyush Malgujar
  0 siblings, 0 replies; 19+ messages in thread
From: Piyush Malgujar @ 2023-01-18 16:02 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linux-mmc, linux-kernel, adrian.hunter, ulf.hansson, robh+dt,
	krzysztof.kozlowski+dt, yamada.masahiro, devicetree, jannadurai,
	cchavva

Hi Krzysztof,

On Sat, Jan 07, 2023 at 02:25:02PM +0100, Krzysztof Kozlowski wrote:
> On 06/01/2023 17:48, Piyush Malgujar wrote:
> > Hi Krzysztof,
> > 
> > Thank you the review comments.
> > 
> > On Mon, Dec 19, 2022 at 04:40:35PM +0100, Krzysztof Kozlowski wrote:
> >> On 19/12/2022 15:24, Piyush Malgujar wrote:
> >>> From: Jayanthi Annadurai <jannadurai@marvell.com>
> >>>
> >>
> >> Subject: use final prefix matching the file, so "cdns,sdhci:"
> >>
> >>> Add support for SD6 controller support
> >>
> >> Full stop.
> >>
> >>>
> >>> Signed-off-by: Jayanthi Annadurai <jannadurai@marvell.com>
> >>> Signed-off-by: Piyush Malgujar <pmalgujar@marvell.com>
> >>> ---
> >>>  .../devicetree/bindings/mmc/cdns,sdhci.yaml   | 33 +++++++++++++++++--
> >>>  1 file changed, 31 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> >>> index 8b1a0fdcb5e3e2e8b87d8d7678e37f3dad447fc1..2043e78ccd5f708a01e87fd96ec410418fcd539f 100644
> >>> --- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> >>> +++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml
> >>> @@ -4,7 +4,7 @@
> >>>  $id: http://devicetree.org/schemas/mmc/cdns,sdhci.yaml#
> >>>  $schema: http://devicetree.org/meta-schemas/core.yaml#
> >>>  
> >>> -title: Cadence SD/SDIO/eMMC Host Controller (SD4HC)
> >>> +title: Cadence SD/SDIO/eMMC Host Controller (SD4HC, SD6HC)
> >>>  
> >>>  maintainers:
> >>>    - Masahiro Yamada <yamada.masahiro@socionext.com>
> >>> @@ -19,6 +19,7 @@ properties:
> >>>            - microchip,mpfs-sd4hc
> >>>            - socionext,uniphier-sd4hc
> >>>        - const: cdns,sd4hc
> >>> +      - const: cdns,sd6hc
> >>
> >> Does not look like you tested the DTS against bindings. Please run `make
> >> dtbs_check` (see Documentation/devicetree/bindings/writing-schema.rst
> >> for instructions).
> >>
> >> ... because it does not really make sense. Why do you require SD6HC as
> >> fallback? I think you meant enum.
> >>
> > 
> > Yes, that's correct. I will change it to enum.
> > 
> >>>  
> >>>    reg:
> >>>      maxItems: 1
> >>> @@ -111,6 +112,34 @@ properties:
> >>>      minimum: 0
> >>>      maximum: 0x7f
> >>>  
> >>> +  cdns,iocell_input_delay:
> >>
> >> No underscores. Use proper units in name suffix:
> >> https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/property-units.yaml
> >>
> >>
> >>> +    description: Delay in ps across the input IO cells
> >>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> >>
> >> Ditto... and so on - all of the fields.
> >>
> >>> +
> >>> +  cdns,iocell_output_delay:
> >>> +    description: Delay in ps across the output IO cells
> >>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> >>> +
> >>> +  cdns,delay_element:
> >>> +    description: Delay element in ps used for calculating phy timings
> >>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> >>> +
> >>> +  cdns,read_dqs_cmd_delay:
> >>> +    description: Command delay used in HS200 tuning
> >>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> >>> +
> >>> +  cdns,tune_val_start:
> >>> +    description: Staring value of data delay used in HS200 tuning
> >>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> >>> +
> >>> +  cdns,tune_val_step:
> >>> +    description: Incremental value of data delay used in HS200 tuning
> >>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> >>> +
> >>> +  cdns,max_tune_iter:
> >>> +    description: Maximum number of iterations to complete the HS200 tuning process
> >>> +    $ref: "/schemas/types.yaml#/definitions/uint32"
> >>
> >> Why these three are properties of DT?
> >>
> > 
> > These tuning parameters are added here so to make them custom configurable for different
> > boards.
> 
> I understand why do you wanted to add them, but I am asking why these
> are suitable for DT? DT  describes hardware, so what is here specific to
> hardware which requires DT property?
> 
> 

We have different values based on emmc devices populated on different boards and these
tuning parameters are used to program phy registers accordingly.

> Best regards,
> Krzysztof

Thanks,
Piyush> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2023-01-18 16:06 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-12-19 14:24 [PATCH 0/5] drivers: mmc: sdhci-cadence: SD6 controller support Piyush Malgujar
2022-12-19 14:24 ` [PATCH 1/5] " Piyush Malgujar
2022-12-19 15:41   ` Krzysztof Kozlowski
2022-12-23 11:07   ` Dan Carpenter
2023-01-11  8:19   ` Adrian Hunter
2022-12-19 14:24 ` [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS Piyush Malgujar
2023-01-11  8:23   ` Adrian Hunter
2023-01-12 14:12     ` Piyush Malgujar
2023-01-13  7:20       ` Adrian Hunter
2022-12-19 14:24 ` [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support Piyush Malgujar
2022-12-19 15:40   ` Krzysztof Kozlowski
2023-01-06 16:48     ` Piyush Malgujar
2023-01-07 13:25       ` Krzysztof Kozlowski
2023-01-18 16:02         ` Piyush Malgujar
2022-12-19 14:24 ` [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout Piyush Malgujar
2023-01-11  8:08   ` Adrian Hunter
2023-01-12 13:44     ` Piyush Malgujar
2022-12-19 14:24 ` [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver Piyush Malgujar
2023-01-11  8:29   ` Adrian Hunter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox