2022-12-19 14:31:02

by Piyush Malgujar

[permalink] [raw]
Subject: [PATCH 0/5] drivers: mmc: sdhci-cadence: SD6 controller support

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


2022-12-19 14:31:12

by Piyush Malgujar

[permalink] [raw]
Subject: [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support

From: Dhananjay Kangude <[email protected]>

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 <[email protected]>
Co-developed-by: Jayanthi Annadurai <[email protected]>
Signed-off-by: Jayanthi Annadurai <[email protected]>
Signed-off-by: Piyush Malgujar <[email protected]>
---
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

2022-12-19 14:33:29

by Piyush Malgujar

[permalink] [raw]
Subject: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support

From: Jayanthi Annadurai <[email protected]>

Add support for SD6 controller support

Signed-off-by: Jayanthi Annadurai <[email protected]>
Signed-off-by: Piyush Malgujar <[email protected]>
---
.../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 <[email protected]>
@@ -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

2022-12-19 14:33:33

by Piyush Malgujar

[permalink] [raw]
Subject: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS

From: Jayanthi Annadurai <[email protected]>

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

Signed-off-by: Jayanthi Annadurai <[email protected]>
Signed-off-by: Piyush Malgujar <[email protected]>
---
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

2022-12-19 14:34:16

by Piyush Malgujar

[permalink] [raw]
Subject: [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout

From: Jayanthi Annadurai <[email protected]>

Add config option to choose the sdhci timeout in seconds.

Signed-off-by: Jayanthi Annadurai <[email protected]>
Signed-off-by: Piyush Malgujar <[email protected]>
---
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

2022-12-19 14:40:23

by Piyush Malgujar

[permalink] [raw]
Subject: [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver.

From: Jayanthi Annadurai <[email protected]>

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

Signed-off-by: Jayanthi Annadurai <[email protected]>
Signed-off-by: Piyush Malgujar <[email protected]>
---
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

2022-12-19 15:56:43

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support

On 19/12/2022 15:24, Piyush Malgujar wrote:
> From: Dhananjay Kangude <[email protected]>
>
> 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

2022-12-19 15:58:47

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support

On 19/12/2022 15:24, Piyush Malgujar wrote:
> From: Jayanthi Annadurai <[email protected]>
>

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

> Add support for SD6 controller support

Full stop.

>
> Signed-off-by: Jayanthi Annadurai <[email protected]>
> Signed-off-by: Piyush Malgujar <[email protected]>
> ---
> .../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 <[email protected]>
> @@ -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

2022-12-19 17:44:39

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver.

Hi Piyush,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.1 next-20221219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
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-6-pmalgujar%40marvell.com
patch subject: [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver.
config: sh-allmodconfig
compiler: sh4-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/2f50d93c62815502509f88632801e0d3e68600d1
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Piyush-Malgujar/drivers-mmc-sdhci-cadence-SD6-controller-support/20221219-222703
git checkout 2f50d93c62815502509f88632801e0d3e68600d1
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sh olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sh SHELL=/bin/bash drivers/mmc/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> drivers/mmc/host/sdhci-cadence.c:1026:6: warning: no previous prototype for 'sdhci_cdns_sd6_dump' [-Wmissing-prototypes]
1026 | void sdhci_cdns_sd6_dump(struct sdhci_cdns_priv *priv)
| ^~~~~~~~~~~~~~~~~~~

Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for MMC_SDHCI_IO_ACCESSORS
Depends on [n]: MMC [=m] && MMC_SDHCI [=n]
Selected by [m]:
- MMC_SDHCI_CN10K [=m] && MMC [=m]
WARNING: unmet direct dependencies detected for MMC_SDHCI_CADENCE
Depends on [n]: MMC [=m] && MMC_SDHCI_PLTFM [=n] && OF [=y]
Selected by [m]:
- MMC_SDHCI_CN10K [=m] && MMC [=m]


vim +/sdhci_cdns_sd6_dump +1026 drivers/mmc/host/sdhci-cadence.c

1025
> 1026 void sdhci_cdns_sd6_dump(struct sdhci_cdns_priv *priv)
1027 {
1028 struct sdhci_cdns_sd6_phy *phy = priv->phy;
1029 int id;
1030
1031 sdhci_cdns_sd6_phy_dump(phy);
1032
1033 DEBUG_DRV("Host controller Register Dump\n");
1034 for (id = 0; id < 14; id++)
1035 DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
1036
1037 id = 29;
1038 DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
1039 id = 30;
1040 DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
1041
1042 for (id = 0; id < 27; id++)
1043 DEBUG_DRV("SRS%d 0x%x\n", id, readl(priv->hrs_addr + 0x200 + (id * 4)));
1044
1045 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DQS_TIMING 0x%x\n",
1046 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQS_TIMING));
1047 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_GATE_LPBK 0x%x\n",
1048 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GATE_LPBK));
1049 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_MASTER 0x%x\n",
1050 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_MASTER));
1051 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_SLAVE 0x%x\n",
1052 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_SLAVE));
1053 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_CTRL 0x%x\n",
1054 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_CTRL));
1055 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_GPIO_CTRL0 0x%x\n",
1056 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GPIO_CTRL0));
1057 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DQ_TIMING 0x%x\n",
1058 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQ_TIMING));
1059 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0 0x%x\n",
1060 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0));
1061 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1 0x%x\n",
1062 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1));
1063 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2 0x%x\n",
1064 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2));
1065 }
1066 #endif
1067

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


Attachments:
(No filename) (4.66 kB)
config (249.08 kB)
Download all attachments

2022-12-20 05:11:37

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver.

Hi Piyush,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.1 next-20221219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
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-6-pmalgujar%40marvell.com
patch subject: [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver.
config: hexagon-allyesconfig
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 98b13979fb05f3ed288a900deb843e7b27589e58)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/2f50d93c62815502509f88632801e0d3e68600d1
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Piyush-Malgujar/drivers-mmc-sdhci-cadence-SD6-controller-support/20221219-222703
git checkout 2f50d93c62815502509f88632801e0d3e68600d1
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/mmc/host/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

In file included from drivers/mmc/host/sdhci-cadence.c:9:
In file included from include/linux/iopoll.h:14:
In file included from include/linux/io.h:13:
In file included from arch/hexagon/include/asm/io.h:334:
include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __raw_readb(PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
#define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
^
In file included from drivers/mmc/host/sdhci-cadence.c:9:
In file included from include/linux/iopoll.h:14:
In file included from include/linux/io.h:13:
In file included from arch/hexagon/include/asm/io.h:334:
include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
#define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
^
In file included from drivers/mmc/host/sdhci-cadence.c:9:
In file included from include/linux/iopoll.h:14:
In file included from include/linux/io.h:13:
In file included from arch/hexagon/include/asm/io.h:334:
include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writeb(value, PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
~~~~~~~~~~ ^
include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
__raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
~~~~~~~~~~ ^
>> drivers/mmc/host/sdhci-cadence.c:1026:6: warning: no previous prototype for function 'sdhci_cdns_sd6_dump' [-Wmissing-prototypes]
void sdhci_cdns_sd6_dump(struct sdhci_cdns_priv *priv)
^
drivers/mmc/host/sdhci-cadence.c:1026:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void sdhci_cdns_sd6_dump(struct sdhci_cdns_priv *priv)
^
static
7 warnings generated.


vim +/sdhci_cdns_sd6_dump +1026 drivers/mmc/host/sdhci-cadence.c

1025
> 1026 void sdhci_cdns_sd6_dump(struct sdhci_cdns_priv *priv)
1027 {
1028 struct sdhci_cdns_sd6_phy *phy = priv->phy;
1029 int id;
1030
1031 sdhci_cdns_sd6_phy_dump(phy);
1032
1033 DEBUG_DRV("Host controller Register Dump\n");
1034 for (id = 0; id < 14; id++)
1035 DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
1036
1037 id = 29;
1038 DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
1039 id = 30;
1040 DEBUG_DRV("HRS%d 0x%x\n", id, readl(priv->hrs_addr + (id * 4)));
1041
1042 for (id = 0; id < 27; id++)
1043 DEBUG_DRV("SRS%d 0x%x\n", id, readl(priv->hrs_addr + 0x200 + (id * 4)));
1044
1045 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DQS_TIMING 0x%x\n",
1046 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQS_TIMING));
1047 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_GATE_LPBK 0x%x\n",
1048 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GATE_LPBK));
1049 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_MASTER 0x%x\n",
1050 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_MASTER));
1051 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_SLAVE 0x%x\n",
1052 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_SLAVE));
1053 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_CTRL 0x%x\n",
1054 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_CTRL));
1055 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_GPIO_CTRL0 0x%x\n",
1056 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_GPIO_CTRL0));
1057 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DQ_TIMING 0x%x\n",
1058 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DQ_TIMING));
1059 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0 0x%x\n",
1060 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG0));
1061 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1 0x%x\n",
1062 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG1));
1063 DEBUG_DRV("SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2 0x%x\n",
1064 sdhci_cdns_sd6_read_phy_reg(priv, SDHCI_CDNS_SD6_PHY_DLL_OBS_REG2));
1065 }
1066 #endif
1067

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


Attachments:
(No filename) (7.25 kB)
config (286.68 kB)
Download all attachments

2022-12-23 11:51:56

by Dan Carpenter

[permalink] [raw]
Subject: Re: [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support

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 <[email protected]>
| Reported-by: Dan Carpenter <[email protected]>

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


2023-01-01 02:20:08

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS

Hi Piyush,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on linus/master v6.2-rc1 next-20221226]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
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-3-pmalgujar%40marvell.com
patch subject: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS
config: ia64-randconfig-c004-20230101
compiler: ia64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/b087f4c6ad3997c952f7cfa57fb1fc5c4d1816ec
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Piyush-Malgujar/drivers-mmc-sdhci-cadence-SD6-controller-support/20221219-222703
git checkout b087f4c6ad3997c952f7cfa57fb1fc5c4d1816ec
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o: in function `sdhci_cdns_probe':
>> drivers/mmc/host/sdhci-cadence.c:1730: undefined reference to `sdhci_pltfm_init'
ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o: in function `sdhci_get_of_property':
>> drivers/mmc/host/sdhci-pltfm.h:94: undefined reference to `sdhci_get_property'
ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o: in function `sdhci_cdns_probe':
>> drivers/mmc/host/sdhci-cadence.c:1765: undefined reference to `sdhci_enable_v4_mode'
>> ia64-linux-ld: drivers/mmc/host/sdhci-cadence.c:1767: undefined reference to `__sdhci_read_caps'
>> ia64-linux-ld: drivers/mmc/host/sdhci-cadence.c:1767: undefined reference to `sdhci_add_host'
>> ia64-linux-ld: drivers/mmc/host/sdhci-cadence.c:1773: undefined reference to `sdhci_pltfm_free'
ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o: in function `sdhci_cdns_sd6_set_clock':
>> drivers/mmc/host/sdhci-cadence.c:1375: undefined reference to `sdhci_set_clock'
ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o: in function `sdhci_cdns_set_uhs_signaling':
>> drivers/mmc/host/sdhci-cadence.c:1245: undefined reference to `sdhci_set_uhs_signaling'
ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o:(.data.rel+0x8): undefined reference to `sdhci_pltfm_unregister'
>> ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o:(.data.rel.ro+0x80): undefined reference to `sdhci_set_bus_width'
>> ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o:(.data.rel.ro+0x98): undefined reference to `sdhci_reset'
>> ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o:(.data.rel.ro+0x120): undefined reference to `sdhci_set_clock'
ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o:(.data.rel.ro+0x170): undefined reference to `sdhci_set_bus_width'
ia64-linux-ld: drivers/mmc/host/sdhci-cadence.o:(.data.rel.ro+0x188): undefined reference to `sdhci_reset'

Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for MMC_SDHCI_IO_ACCESSORS
Depends on [n]: MMC [=y] && MMC_SDHCI [=n]
Selected by [y]:
- MMC_SDHCI_CN10K [=y] && MMC [=y]
WARNING: unmet direct dependencies detected for MMC_SDHCI_CADENCE
Depends on [n]: MMC [=y] && MMC_SDHCI_PLTFM [=n] && OF [=y]
Selected by [y]:
- MMC_SDHCI_CN10K [=y] && MMC [=y]


vim +1730 drivers/mmc/host/sdhci-cadence.c

d12990f9900f49 Piotr Sroka 2017-03-06 1705
ff6af28faff53a Masahiro Yamada 2016-12-08 1706 static int sdhci_cdns_probe(struct platform_device *pdev)
ff6af28faff53a Masahiro Yamada 2016-12-08 1707 {
ff6af28faff53a Masahiro Yamada 2016-12-08 1708 struct sdhci_host *host;
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1709 const struct sdhci_cdns_of_data *data;
ff6af28faff53a Masahiro Yamada 2016-12-08 1710 struct sdhci_pltfm_host *pltfm_host;
ff6af28faff53a Masahiro Yamada 2016-12-08 1711 struct sdhci_cdns_priv *priv;
ff6af28faff53a Masahiro Yamada 2016-12-08 1712 struct clk *clk;
ff6af28faff53a Masahiro Yamada 2016-12-08 1713 int ret;
a89c472d8b55c5 Piotr Sroka 2017-03-21 1714 struct device *dev = &pdev->dev;
ff6af28faff53a Masahiro Yamada 2016-12-08 1715
edf98579065950 Piotr Sroka 2017-03-21 1716 clk = devm_clk_get(dev, NULL);
ff6af28faff53a Masahiro Yamada 2016-12-08 1717 if (IS_ERR(clk))
ff6af28faff53a Masahiro Yamada 2016-12-08 1718 return PTR_ERR(clk);
ff6af28faff53a Masahiro Yamada 2016-12-08 1719
ff6af28faff53a Masahiro Yamada 2016-12-08 1720 ret = clk_prepare_enable(clk);
ff6af28faff53a Masahiro Yamada 2016-12-08 1721 if (ret)
ff6af28faff53a Masahiro Yamada 2016-12-08 1722 return ret;
ff6af28faff53a Masahiro Yamada 2016-12-08 1723
18b587b45c13bb Masahiro Yamada 2020-03-12 1724 data = of_device_get_match_data(dev);
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1725 if (!data) {
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1726 return PTR_ERR(clk);
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1727 goto disable_clk;
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1728 }
18b587b45c13bb Masahiro Yamada 2020-03-12 1729
8bcfc23a884699 Dhananjay Kangude 2022-12-19 @1730 host = sdhci_pltfm_init(pdev, data->pltfm_data, sizeof(*priv));
ff6af28faff53a Masahiro Yamada 2016-12-08 1731 if (IS_ERR(host)) {
ff6af28faff53a Masahiro Yamada 2016-12-08 1732 ret = PTR_ERR(host);
ff6af28faff53a Masahiro Yamada 2016-12-08 1733 goto disable_clk;
ff6af28faff53a Masahiro Yamada 2016-12-08 1734 }
ff6af28faff53a Masahiro Yamada 2016-12-08 1735
ff6af28faff53a Masahiro Yamada 2016-12-08 1736 pltfm_host = sdhci_priv(host);
ff6af28faff53a Masahiro Yamada 2016-12-08 1737 pltfm_host->clk = clk;
ff6af28faff53a Masahiro Yamada 2016-12-08 1738
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1739 host->clk_mul = 0;
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1740 host->max_clk = SDMCLK_MAX_FREQ;
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1741 host->quirks |= SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1742 host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
a232a8f2d10750 Masahiro Yamada 2017-08-23 1743 priv = sdhci_pltfm_priv(pltfm_host);
ff6af28faff53a Masahiro Yamada 2016-12-08 1744 priv->hrs_addr = host->ioaddr;
d12990f9900f49 Piotr Sroka 2017-03-06 1745 priv->enhanced_strobe = false;
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1746 priv->cdns_data = data->cdns_data;
ff6af28faff53a Masahiro Yamada 2016-12-08 1747 host->ioaddr += SDHCI_CDNS_SRS_BASE;
d12990f9900f49 Piotr Sroka 2017-03-06 1748 host->mmc_host_ops.hs400_enhanced_strobe =
d12990f9900f49 Piotr Sroka 2017-03-06 1749 sdhci_cdns_hs400_enhanced_strobe;
ff6af28faff53a Masahiro Yamada 2016-12-08 1750
861183f115cd80 Piotr Sroka 2017-04-11 1751 sdhci_get_of_property(pdev);
861183f115cd80 Piotr Sroka 2017-04-11 1752
ff6af28faff53a Masahiro Yamada 2016-12-08 1753 ret = mmc_of_parse(host->mmc);
ff6af28faff53a Masahiro Yamada 2016-12-08 1754 if (ret)
ff6af28faff53a Masahiro Yamada 2016-12-08 1755 goto free;
ff6af28faff53a Masahiro Yamada 2016-12-08 1756
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1757 ret = data->phy_probe(pdev, priv);
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1758 if (ret)
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1759 goto free;
a232a8f2d10750 Masahiro Yamada 2017-08-23 1760
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1761 ret = priv->cdns_data->phy_init(priv);
a89c472d8b55c5 Piotr Sroka 2017-03-21 1762 if (ret)
a89c472d8b55c5 Piotr Sroka 2017-03-21 1763 goto free;
ff6af28faff53a Masahiro Yamada 2016-12-08 1764
8bcfc23a884699 Dhananjay Kangude 2022-12-19 @1765 sdhci_enable_v4_mode(host);
8bcfc23a884699 Dhananjay Kangude 2022-12-19 1766 __sdhci_read_caps(host, NULL, NULL, NULL);
ff6af28faff53a Masahiro Yamada 2016-12-08 @1767 ret = sdhci_add_host(host);
ff6af28faff53a Masahiro Yamada 2016-12-08 1768 if (ret)
ff6af28faff53a Masahiro Yamada 2016-12-08 1769 goto free;
ff6af28faff53a Masahiro Yamada 2016-12-08 1770
ff6af28faff53a Masahiro Yamada 2016-12-08 1771 return 0;
ff6af28faff53a Masahiro Yamada 2016-12-08 1772 free:
ff6af28faff53a Masahiro Yamada 2016-12-08 @1773 sdhci_pltfm_free(pdev);
ff6af28faff53a Masahiro Yamada 2016-12-08 1774 disable_clk:
ff6af28faff53a Masahiro Yamada 2016-12-08 1775 clk_disable_unprepare(clk);
ff6af28faff53a Masahiro Yamada 2016-12-08 1776
ff6af28faff53a Masahiro Yamada 2016-12-08 1777 return ret;
ff6af28faff53a Masahiro Yamada 2016-12-08 1778 }
ff6af28faff53a Masahiro Yamada 2016-12-08 1779

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


Attachments:
(No filename) (9.48 kB)
config (169.17 kB)
Download all attachments

2023-01-06 17:06:45

by Piyush Malgujar

[permalink] [raw]
Subject: Re: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support

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 <[email protected]>
> >
>
> Subject: use final prefix matching the file, so "cdns,sdhci:"
>
> > Add support for SD6 controller support
>
> Full stop.
>
> >
> > Signed-off-by: Jayanthi Annadurai <[email protected]>
> > Signed-off-by: Piyush Malgujar <[email protected]>
> > ---
> > .../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 <[email protected]>
> > @@ -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

2023-01-07 14:01:17

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support

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 <[email protected]>
>>>
>>
>> Subject: use final prefix matching the file, so "cdns,sdhci:"
>>
>>> Add support for SD6 controller support
>>
>> Full stop.
>>
>>>
>>> Signed-off-by: Jayanthi Annadurai <[email protected]>
>>> Signed-off-by: Piyush Malgujar <[email protected]>
>>> ---
>>> .../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 <[email protected]>
>>> @@ -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

2023-01-11 08:24:36

by Adrian Hunter

[permalink] [raw]
Subject: Re: [PATCH 1/5] drivers: mmc: sdhci-cadence: SD6 controller support

On 19/12/22 16:24, Piyush Malgujar wrote:
> From: Dhananjay Kangude <[email protected]>
>
> 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 <[email protected]>
> Co-developed-by: Jayanthi Annadurai <[email protected]>
> Signed-off-by: Jayanthi Annadurai <[email protected]>
> Signed-off-by: Piyush Malgujar <[email protected]>
> ---
> 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);

2023-01-11 08:32:39

by Adrian Hunter

[permalink] [raw]
Subject: Re: [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout

On 19/12/22 16:24, Piyush Malgujar wrote:
> From: Jayanthi Annadurai <[email protected]>
>
> 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 <[email protected]>
> Signed-off-by: Piyush Malgujar <[email protected]>
> ---
> 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)

2023-01-11 08:40:57

by Adrian Hunter

[permalink] [raw]
Subject: Re: [PATCH 5/5] drivers: mmc: sdhci-cadence: Add debug option for sdhci-cadence driver.

On 19/12/22 16:24, Piyush Malgujar wrote:
> From: Jayanthi Annadurai <[email protected]>
>
> Use Kernel config CONFIG_MMC_DEBUG to support dumping PHY and host
> controller register configuration for debug.
>
> Signed-off-by: Jayanthi Annadurai <[email protected]>
> Signed-off-by: Piyush Malgujar <[email protected]>
> ---
> 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,

2023-01-11 08:42:16

by Adrian Hunter

[permalink] [raw]
Subject: Re: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS

On 19/12/22 16:24, Piyush Malgujar wrote:
> From: Jayanthi Annadurai <[email protected]>
>
> Add support for CONFIG_MMC_SDHCI_IO_ACCESSORS for controller
> specific register read and write APIs.
>
> Signed-off-by: Jayanthi Annadurai <[email protected]>
> Signed-off-by: Piyush Malgujar <[email protected]>
> ---
> 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,

2023-01-12 15:12:38

by Piyush Malgujar

[permalink] [raw]
Subject: Re: [PATCH 4/5] drivers: mmc: sdhci: Add option to configure sdhci timeout

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 <[email protected]>
> >
> > 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 <[email protected]>
> > Signed-off-by: Piyush Malgujar <[email protected]>
> > ---
> > 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

2023-01-12 15:12:51

by Piyush Malgujar

[permalink] [raw]
Subject: Re: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS

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 <[email protected]>
> >
> > Add support for CONFIG_MMC_SDHCI_IO_ACCESSORS for controller
> > specific register read and write APIs.
> >
> > Signed-off-by: Jayanthi Annadurai <[email protected]>
> > Signed-off-by: Piyush Malgujar <[email protected]>
> > ---
> > 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

2023-01-13 07:34:50

by Adrian Hunter

[permalink] [raw]
Subject: Re: [PATCH 2/5] drivers: mmc: sdhci-cadence: enable MMC_SDHCI_IO_ACCESSORS

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 <[email protected]>
>>>
>>> Add support for CONFIG_MMC_SDHCI_IO_ACCESSORS for controller
>>> specific register read and write APIs.
>>>
>>> Signed-off-by: Jayanthi Annadurai <[email protected]>
>>> Signed-off-by: Piyush Malgujar <[email protected]>
>>> ---
>>> 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

2023-01-18 17:08:14

by Piyush Malgujar

[permalink] [raw]
Subject: Re: [PATCH 3/5] dt-bindings: mmc: sdhci-cadence: SD6 support

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 <[email protected]>
> >>>
> >>
> >> Subject: use final prefix matching the file, so "cdns,sdhci:"
> >>
> >>> Add support for SD6 controller support
> >>
> >> Full stop.
> >>
> >>>
> >>> Signed-off-by: Jayanthi Annadurai <[email protected]>
> >>> Signed-off-by: Piyush Malgujar <[email protected]>
> >>> ---
> >>> .../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 <[email protected]>
> >>> @@ -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>