Add support for Eswin EIC7700 SD/eMMC controller
Subsystems (3)
v3 cover Add support for Eswin EIC7700 SD/eMMC controller
From: Huan He <[email protected]>
Updates:
Changes in v3:
- Update snps,dwcmshc-sdhci.yaml
- Delete clock-output-names, '#clock-cells' and eswin,syscrg-csr
- Update description for eswin,hsp-sp-csr
- Update drive-impedance-ohm
- Update the item of reset-names
- Update sdhci-of-dwcmshc.c
- Add descriptions for PHY registers
- Simplify clock management(remove custom clock provider, use
standard clk API)
- Replace magic numbers with GENMASK() or FIELD_PREP() macros
- Add comments explaining HSP stability assertion writes
- Adjust line wrapping to fit within 100-column
- Delete forward declarations by moving function definitions
- Rename variable is_sdio to is_sd
- Replace unclear macros with meaningful alternatives
- Link to v2: https://lore.kernel.org/all/[email protected]/
Changes in v2:
- Delete the previous separate driver and yaml binding file
- Update snps,dwcmshc-sdhci.yaml to add support for Eswin EIC7700
- Add the new compautible string: "eswin,eic7700-dwcmshc"
- Add new properties: clock-output-names, '#clock-cells', drive-impedance-ohm, eswin,hsp-sp-csr and eswin,syscrg-csr
- Add customized reset-names for EIC7700 platform
- Update sdhci-of-dwcmshc.c to add support for Eswin EIC7700
- Add a new struct eic7700_priv to hold Eswin-specific data,
including clock phases, register mappings, and drive
impedance configuration
- Implement EIC7700-specific sdhci_ops
- set_clock: support core clock configuration with phase delay
- reset: add PHY reset and configuration
- set_uhs_signaling: support HS400 DLL lock
- platform_execute_tuning: implement delay line tuning and phase
code adjustment
- Add initialization routine (eic7700_init)
- Integrate the new platform data and ops into the driver's match table
- Link to v1: https://lore.kernel.org/all/[email protected]/
Huan He (2):
dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
.../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +- drivers/mmc/host/sdhci-of-dwcmshc.c | 526 +++++++++++++++++- 2 files changed, 555 insertions(+), 28 deletions(-)
Signature · 1 line
2.25.1
PATCH v3 1/2 dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
From: Huan He <[email protected]>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml.
--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-)
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +51 -6
@@ -30,6 +30,7 @@ properties: - sophgo,sg2002-dwcmshc - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc + - eswin,eic7700-dwcmshc reg: maxItems: 1
@@ -52,17 +53,30 @@ properties: maxItems: 5 reset-names: - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + maxItems: 5 rockchip,txclk-tapnum: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8 + eswin,hsp-sp-csr: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - description: Phandle to HSP(High-Speed Peripheral) device + - description: Offset of the stability status register for + internal clock + - description: Offset of the stability register for host regulator + voltage. + description: | + HSP CSR is to control and get status of different high-speed + peripherals (such as Ethernet, USB, SATA, etc.) via register, + which can close module's clock, reset module independently + and tune board-level's parameters of PHY, etc. + + eswin,drive-impedance-ohms: + description: Specifies the drive impedance in Ohm. + enum: [33, 40, 50, 66, 100] + required: - compatible - reg
@@ -110,6 +124,37 @@ allOf: - const: block - const: timer + - if: + properties: + compatible: + contains: + const: eswin,eic7700-dwcmshc + then: + properties: + resets: + minItems: 4 + maxItems: 4 + reset-names: + items: + - const: axi + - const: phy + - const: prstn + - const: txrx + required: + - eswin,hsp-sp-csr + - eswin,drive-impedance-ohms + else: + properties: + resets: + maxItems: 5 + reset-names: + items: + - const: core + - const: bus + - const: axi + - const: block + - const: timer + - if: properties: compatible:
Signature · 1 line
2.25.1
Re: [PATCH v3 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
Quoted 6 lines · On Fri, Oct 10, 2025 at 05:40:13PM +0800, [email protected] wrote:
From: Huan He <[email protected]>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in
sdhci-of-dwcmshc.yaml.Signed-off-by Huan He <[email protected]>
--
pw-bot: not-applicable
PATCH v3 2/2 mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
In reply to [email protected]From: Huan He <[email protected]>
Add support for the mmc controller in the Eswin EIC7700 with the new compatible "eswin,eic7700-dwcmshc". Implement custom sdhci_ops for set_clock, reset, set_uhs_signaling, platform_execute_tuning.
--- drivers/mmc/host/sdhci-of-dwcmshc.c | 526 ++++++++++++++++++++++++++-- 1 file changed, 504 insertions(+), 22 deletions(-)
drivers/mmc/host/sdhci-of-dwcmshc.c +504 -22
@@ -11,6 +11,7 @@#include <linux/arm-smccc.h> #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/dma-mapping.h> #include <linux/iopoll.h> #include <linux/kernel.h>
@@ -19,8 +20,11 @@#include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/reset.h> #include <linux/sizes.h> +#include <linux/mfd/syscon.h> +#include <linux/units.h> #include "sdhci-pltfm.h" #include "cqhci.h"
@@ -39,6 +43,7 @@#define DWCMSHC_CARD_IS_EMMC BIT(0)#define DWCMSHC_ENHANCED_STROBE BIT(8)#define DWCMSHC_EMMC_ATCTRL 0x40 +#define DWCMSHC_AT_STAT 0x44/* Tuning and auto-tuning fields in AT_CTRL_R control register */ #define AT_CTRL_AT_EN BIT(0)/* autotuning is enabled */ #define AT_CTRL_CI_SEL BIT(1)/* interval to drive center phase select */
@@ -194,6 +199,19 @@#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5)/* bits [6:5] */ #define PHY_DLLDL_CNFG_SLV_INPSEL 0x3/* clock source select for slave DL */ +/* PHY DLL offset setting register */ +#define PHY_DLL_OFFST_R (DWC_MSHC_PTR_PHY_R + 0x29) +/* DLL LBT setting register */ +#define PHY_DLLBT_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x2c) +/* DLL Status register */ +#define PHY_DLL_STATUS_R (DWC_MSHC_PTR_PHY_R + 0x2e) +#define DLL_LOCK_STS BIT(0)/* DLL is locked and ready */ +/* +* Captures the value of DLL's lock error status information. Value is valid +* only when LOCK_STS is set. +*/ +#define DLL_ERROR_STS BIT(1) +#define FLAG_IO_FIXED_1V8 BIT(0)#define BOUNDARY_OK (addr, len) \
@@ -206,6 +224,31 @@/* SMC call for BlueField-3 eMMC RST_N */ #define BLUEFIELD_SMC_SET_EMMC_RST_N 0x82000007 +/* Eswin specific Registers */ +#define EIC7700_CARD_CLK_STABLE BIT(28) +#define EIC7700_INT_BCLK_STABLE BIT(16) +#define EIC7700_INT_ACLK_STABLE BIT(8) +#define EIC7700_INT_TMCLK_STABLE BIT(0) +#define EIC7700_INT_CLK_STABLE (EIC7700_CARD_CLK_STABLE | \ + EIC7700_INT_ACLK_STABLE | \ + EIC7700_INT_BCLK_STABLE | \ + EIC7700_INT_TMCLK_STABLE) +#define EIC7700_HOST_VAL_STABLE BIT(0) + +/* strength definition */ +#define PHYCTRL_DR_33OHM 0xee +#define PHYCTRL_DR_40OHM 0xcc +#define PHYCTRL_DR_50OHM 0x88 +#define PHYCTRL_DR_66OHM 0x44 +#define PHYCTRL_DR_100OHM 0x00 + +#define MAX_PHASE_CODE 0xff +#define TUNING_RANGE_THRESHOLD 40 +#define PHY_CLK_MAX_DELAY_MASK 0x7f +#define PHY_DELAY_CODE_MAX 0x7f +#define PHY_DELAY_CODE_EMMC 0x17 +#define PHY_DELAY_CODE_SD 0x55 +enum dwcmshc_rk_type {DWCMSHC_RK3568 ,DWCMSHC_RK3588 ,
@@ -217,6 +260,11 @@ struct rk35xx_priv {u8 txclk_tapnum; }; +struct eic7700_priv { +struct reset_control *reset; +unsigned int drive_impedance; +}; +#define DWCMSHC_MAX_OTHER_CLKS 3struct dwcmshc_priv {
@@ -238,6 +286,28 @@ struct dwcmshc_pltfm_data {void (*postinit)(struct sdhci_host *host,struct dwcmshc_priv *dwc_priv); }; +static void dwcmshc_enable_card_clk (struct sdhci_host *host) +{ +u16 ctrl; + + ctrl =sdhci_readw (host,SDHCI_CLOCK_CONTROL ); +if ((ctrl &SDHCI_CLOCK_INT_EN ) && !(ctrl &SDHCI_CLOCK_CARD_EN )) { + ctrl |=SDHCI_CLOCK_CARD_EN ; +sdhci_writew (host, ctrl,SDHCI_CLOCK_CONTROL ); + } +} + +static void dwcmshc_enable_card_clk (struct sdhci_host *host) +{ +u16 ctrl; + + ctrl =sdhci_readw (host,SDHCI_CLOCK_CONTROL ); +if ((ctrl &SDHCI_CLOCK_INT_EN ) && !(ctrl &SDHCI_CLOCK_CARD_EN )) { + ctrl |=SDHCI_CLOCK_CARD_EN ; +sdhci_writew (host, ctrl,SDHCI_CLOCK_CONTROL ); + } +} + static int dwcmshc_get_enable_other_clks(struct device *dev, struct dwcmshc_priv *priv, int num_clks,
@@ -1095,6 +1165,413 @@ static int sg2042_init(struct device *dev, struct sdhci_host *host, ARRAY_SIZE(clk_ids), clk_ids); } +static void sdhci_eic7700_set_clock (struct sdhci_host *host,unsigned int clock) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +u16 clk; + + host->mmc->actual_clock = clock; + +if (clock ==0 ) { +sdhci_set_clock (host, clock); +return ; + } +dwcmshc_disable_card_clk (host); + +clk_disable_unprepare (pltfm_host->clk); +clk_set_rate (pltfm_host->clk, clock); +clk_prepare_enable (pltfm_host->clk); + + clk =sdhci_readw (host,SDHCI_CLOCK_CONTROL ); + clk |=SDHCI_CLOCK_INT_EN ; +sdhci_writew (host, clk,SDHCI_CLOCK_CONTROL ); + +dwcmshc_enable_card_clk (host); +} + +static void sdhci_eic7700_config_phy_delay (struct sdhci_host *host,int delay) +{ + delay &=PHY_CLK_MAX_DELAY_MASK ; + +/* phy clk delay line config */ +sdhci_writeb (host,PHY_SDCLKDL_CNFG_UPDATE ,PHY_SDCLKDL_CNFG_R ); +sdhci_writeb (host, delay,PHY_SDCLKDL_DC_R ); +sdhci_writeb (host,0x0 ,PHY_SDCLKDL_CNFG_R ); +} + +static void sdhci_eic7700_config_phy (struct sdhci_host *host) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct dwcmshc_priv *dwc_priv =sdhci_pltfm_priv (pltfm_host); +u32 emmc_caps =MMC_CAP2_NO_SD |MMC_CAP2_NO_SDIO ; +struct eic7700_priv *priv = dwc_priv->priv; +unsigned int val, drv; + + drv =FIELD_PREP (PHY_CNFG_PAD_SP_MASK , priv->drive_impedance &0xF ); + drv |=FIELD_PREP (PHY_CNFG_PAD_SN_MASK , (priv->drive_impedance >>4 ) &0xF ); + +if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { + val =sdhci_readw (host, dwc_priv->vendor_specific_area1 +DWCMSHC_EMMC_CONTROL ); + val |=DWCMSHC_CARD_IS_EMMC ; +sdhci_writew (host, val, dwc_priv->vendor_specific_area1 +DWCMSHC_EMMC_CONTROL ); + } + +/* reset phy, config phy's pad */ +sdhci_writel (host, drv | (~PHY_CNFG_RSTN_DEASSERT ),PHY_CNFG_R ); + +/* configure phy pads */ + val =FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); + val |=FIELD_PREP (PHY_PAD_WEAKPULL_MASK ,PHY_PAD_WEAKPULL_PULLUP ); + val |=PHY_PAD_RXSEL_1V8 ; +sdhci_writew (host, val,PHY_CMDPAD_CNFG_R ); +sdhci_writew (host, val,PHY_DATAPAD_CNFG_R ); +sdhci_writew (host, val,PHY_RSTNPAD_CNFG_R ); + +/* Clock PAD Setting */ + val =FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); +sdhci_writew (host, val,PHY_CLKPAD_CNFG_R ); + +/* PHY strobe PAD setting (EMMC only) */ +if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { + val =FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,PHY_PAD_TXSLEW_CTRL_N_SG2042 ); + val |=PHY_PAD_RXSEL_1V8 ; +sdhci_writew (host, val,PHY_STBPAD_CNFG_R ); + } +usleep_range (2000 ,3000 ); +sdhci_writel (host, drv |PHY_CNFG_RSTN_DEASSERT ,PHY_CNFG_R ); +sdhci_eic7700_config_phy_delay (host, dwc_priv->delay_line); +} + +static void sdhci_eic7700_reset (struct sdhci_host *host,u8 mask) +{ +sdhci_reset (host, mask); + +/* after reset all, the phy's config will be clear */ +if (mask ==SDHCI_RESET_ALL ) +sdhci_eic7700_config_phy (host); +} + +static int sdhci_eic7700_reset_init (struct device *dev,struct eic7700_priv *priv) +{ +int ret; + + priv->reset =devm_reset_control_array_get_optional_exclusive (dev); +if (IS_ERR (priv->reset)) { + ret =PTR_ERR (priv->reset); +dev_err (dev,"failed to get reset control %d\n" , ret); +return ret; + } + + ret =reset_control_assert (priv->reset); +if (ret) { +dev_err (dev,"Failed to assert reset signals: %d\n" , ret); +return ret; + } +usleep_range (2000 ,2100 ); + ret =reset_control_deassert (priv->reset); +if (ret) { +dev_err (dev,"Failed to deassert reset signals: %d\n" , ret); +return ret; + } + +return ret; +} + +static unsigned int eic7700_convert_drive_impedance_ohm (struct device *dev,unsigned int dr_ohm) +{ +switch (dr_ohm) { +case 100 : +return PHYCTRL_DR_100OHM ; +case 66 : +return PHYCTRL_DR_66OHM ; +case 50 : +return PHYCTRL_DR_50OHM ; +case 40 : +return PHYCTRL_DR_40OHM ; +case 33 : +return PHYCTRL_DR_33OHM ; + } + +dev_warn (dev,"Invalid value %u for drive-impedance-ohms.\n" , dr_ohm); +return PHYCTRL_DR_50OHM ; +} + +static int sdhci_eic7700_delay_tuning (struct sdhci_host *host,u32 opcode) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct dwcmshc_priv *dwc_priv =sdhci_pltfm_priv (pltfm_host); +int delay_min =-1 ; +int delay_max =-1 ; +int cmd_error =0 ; +int delay =0 ; +int i =0 ; +int ret; + +for (i =0 ; i <=PHY_DELAY_CODE_MAX ; i++) { +sdhci_eic7700_config_phy_delay (host, i); + ret =mmc_send_tuning (host->mmc, opcode, &cmd_error); +if (ret) { + host->ops->reset (host,SDHCI_RESET_CMD |SDHCI_RESET_DATA ); +usleep_range (200 ,210 ); +if (delay_min !=-1 && delay_max !=-1 ) +break ; + }else { +if (delay_min ==-1 ) { + delay_min = i; +continue ; + }else { + delay_max = i; +continue ; + } + } + } +if (delay_min ==-1 && delay_max ==-1 ) { +pr_err ("%s: delay code tuning failed!\n" ,mmc_hostname (host->mmc)); +sdhci_eic7700_config_phy_delay (host, dwc_priv->delay_line); +return ret; + } + + delay = (delay_min + delay_max) /2 ; +sdhci_eic7700_config_phy_delay (host, delay); + +return 0 ; +} + +static int sdhci_eic7700_phase_code_tuning (struct sdhci_host *host,u32 opcode) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); +u32 sd_caps =MMC_CAP2_NO_MMC |MMC_CAP2_NO_SDIO ; +int phase_code =-1 ; +int code_range =-1 ; +bool is_sd = false; +int code_min =-1 ; +int code_max =-1 ; +int cmd_error =0 ; +int ret =0 ; +int i =0 ; + +if ((host->mmc->caps2 & sd_caps) == sd_caps) + is_sd = true; + +for (i =0 ; i <=MAX_PHASE_CODE ; i++) { +/* Centered Phase code */ +sdhci_writew (host, i, priv->vendor_specific_area1 +DWCMSHC_AT_STAT ); + ret =mmc_send_tuning (host->mmc, opcode, &cmd_error); + host->ops->reset (host,SDHCI_RESET_CMD |SDHCI_RESET_DATA ); + +if (ret) { +/* SDIO specific range tracking */ +if (is_sd && code_min !=-1 && code_max !=-1 ) { +if (code_max - code_min > code_range) { + code_range = code_max - code_min; + phase_code = (code_min + code_max) /2 ; +if (code_range >TUNING_RANGE_THRESHOLD ) +break ; + } + code_min =-1 ; + code_max =-1 ; + } +/* EMMC breaks after first valid range */ +if (!is_sd && code_min !=-1 && code_max !=-1 ) +break ; + }else { +/* Track valid phase code range */ +if (code_min ==-1 ) { + code_min = i; +if (!is_sd) +continue ; + } + code_max = i; +if (is_sd && i ==MAX_PHASE_CODE ) { +if (code_max - code_min > code_range) { + code_range = code_max - code_min; + phase_code = (code_min + code_max) /2 ; + } + } + } + } + +/* Handle tuning failure case */ +if ((is_sd && phase_code ==-1 ) || + (!is_sd && code_min ==-1 && code_max ==-1 )) { +pr_err ("%s: phase code tuning failed!\n" ,mmc_hostname (host->mmc)); +sdhci_writew (host,0 , priv->vendor_specific_area1 +DWCMSHC_AT_STAT ); +return -EIO ; + } +if (!is_sd) + phase_code = (code_min + code_max) /2 ; + +sdhci_writew (host, phase_code, priv->vendor_specific_area1 +DWCMSHC_AT_STAT ); + +/* SDIO specific final verification */ +if (is_sd) { + ret =mmc_send_tuning (host->mmc, opcode, &cmd_error); + host->ops->reset (host,SDHCI_RESET_CMD |SDHCI_RESET_DATA ); +if (ret) { +pr_err ("%s: Final phase code 0x%x verification failed!\n" , +mmc_hostname (host->mmc), phase_code); +return ret; + } + } + +return 0 ; +} + +static int sdhci_eic7700_executing_tuning (struct sdhci_host *host,u32 opcode) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); +u32 emmc_caps =MMC_CAP2_NO_SD |MMC_CAP2_NO_SDIO ; +int ret =0 ; +u16 ctrl; +u32 val; + + ctrl =sdhci_readw (host,SDHCI_HOST_CONTROL2 ); + ctrl &= ~SDHCI_CTRL_TUNED_CLK ; +sdhci_writew (host, ctrl,SDHCI_HOST_CONTROL2 ); + + val =sdhci_readl (host, priv->vendor_specific_area1 +DWCMSHC_EMMC_ATCTRL ); + val |=AT_CTRL_SW_TUNE_EN ; +sdhci_writew (host, val, priv->vendor_specific_area1 +DWCMSHC_EMMC_ATCTRL ); + +sdhci_writew (host,0 , priv->vendor_specific_area1 +DWCMSHC_AT_STAT ); +sdhci_writew (host,0x0 ,SDHCI_CMD_DATA ); + +if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { + ret =sdhci_eic7700_delay_tuning (host, opcode); +if (ret) +return ret; + } + + ret =sdhci_eic7700_phase_code_tuning (host, opcode); +if (ret) +return ret; + +return 0 ; +} + +static void sdhci_eic7700_set_uhs_signaling (struct sdhci_host *host,unsigned int timing) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct dwcmshc_priv *priv =sdhci_pltfm_priv (pltfm_host); +u8 status; +u32 val; +int ret; + +dwcmshc_set_uhs_signaling (host, timing); + +/* here need make dll locked when in hs400 at 200MHz */ +if (timing ==MMC_TIMING_MMC_HS400 && host->clock ==200000000 ) { + val =sdhci_readl (host, priv->vendor_specific_area1 +DWCMSHC_EMMC_ATCTRL ); + val &= ~(FIELD_PREP (AT_CTRL_POST_CHANGE_DLY_MASK ,AT_CTRL_POST_CHANGE_DLY )); +/* 2-cycle latency */ + val |=FIELD_PREP (AT_CTRL_POST_CHANGE_DLY_MASK ,0x2 ); +sdhci_writew (host, val, priv->vendor_specific_area1 +DWCMSHC_EMMC_ATCTRL ); + +sdhci_writeb (host,FIELD_PREP (PHY_DLL_CNFG1_SLVDLY_MASK ,PHY_DLL_CNFG1_SLVDLY ) | +0x3 ,PHY_DLL_CNFG1_R );/* DLL wait cycle input */ +/* DLL jump step input */ +sdhci_writeb (host,0x02 ,PHY_DLL_CNFG2_R ); +sdhci_writeb (host,FIELD_PREP (PHY_DLLDL_CNFG_SLV_INPSEL_MASK , +PHY_DLLDL_CNFG_SLV_INPSEL ),PHY_DLLDL_CNFG_R ); +/* Sets the value of DLL's offset input */ +sdhci_writeb (host,0x00 ,PHY_DLL_OFFST_R ); +/* Sets the value of DLL's olbt loadval input. Controls the Ibt +* timer's timeout value at which DLL runs a revalidation cycle. +*/ +sdhci_writew (host,0xffff ,PHY_DLLBT_CNFG_R ); +sdhci_writeb (host,PHY_DLL_CTRL_ENABLE ,PHY_DLL_CTRL_R ); +usleep_range (100 ,110 ); + + ret =read_poll_timeout (sdhci_readb, status, status &DLL_LOCK_STS ,100 ,1000000 , + false, host,PHY_DLL_STATUS_R ); +if (ret) { +pr_err ("%s: DLL lock timeout! status: 0x%x\n" , +mmc_hostname (host->mmc), status); +return ; + } + + status =sdhci_readb (host,PHY_DLL_STATUS_R ); +if (status &DLL_ERROR_STS ) { +pr_err ("%s: DLL lock failed!err_status:0x%x\n" , +mmc_hostname (host->mmc), status); + } + } +} + +static void sdhci_eic7700_set_uhs_wrapper (struct sdhci_host *host,unsigned int timing) +{ +u32 sd_caps =MMC_CAP2_NO_MMC |MMC_CAP2_NO_SDIO ; + +if ((host->mmc->caps2 & sd_caps) == sd_caps) +sdhci_set_uhs_signaling (host, timing); +else +sdhci_eic7700_set_uhs_signaling (host, timing); +} + +static int eic7700_init (struct device *dev,struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) +{ +u32 emmc_caps =MMC_CAP2_NO_SD |MMC_CAP2_NO_SDIO ; +unsigned int val, hsp_int_status, hsp_pwr_ctrl; +struct of_phandle_args args; +struct eic7700_priv *priv; +struct regmap *hsp_regmap; +int ret; + + priv =devm_kzalloc (dev,sizeof (struct eic7700_priv ),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + + dwc_priv->priv = priv; + + ret =sdhci_eic7700_reset_init (dev, dwc_priv->priv); +if (ret) { +dev_err (dev,"failed to reset\n" ); +return ret; + } + + ret =of_parse_phandle_with_fixed_args (dev->of_node,"eswin,hsp-sp-csr" ,2 ,0 , &args); +if (ret) { +dev_err (dev,"Fail to parse 'eswin,hsp-sp-csr' phandle (%d)\n" , ret); +return ret; + } + + hsp_regmap =syscon_node_to_regmap (args.np); +if (IS_ERR (hsp_regmap)) { +dev_err (dev,"Failed to get regmap for 'eswin,hsp-sp-csr'\n" ); +of_node_put (args.np); +return ret; + } + hsp_int_status = args.args[0 ]; + hsp_pwr_ctrl = args.args[1 ]; +of_node_put (args.np); +/* +* Assert clock stability: write EIC7700_INT_CLK_STABLE to hsp_int_status. +* This signals to the eMMC controller that platform clocks (card, ACLK, +* BCLK, TMCLK) are enabled and stable. +*/ +regmap_write (hsp_regmap, hsp_int_status,EIC7700_INT_CLK_STABLE ); +/* +* Assert voltage stability: write EIC7700_HOST_VAL_STABLE to hsp_pwr_ctrl. +* This signals that VDD is stable and permits transition to high-speed +* modes (e.g., UHS-I). +*/ +regmap_write (hsp_regmap, hsp_pwr_ctrl,EIC7700_HOST_VAL_STABLE ); + +if ((host->mmc->caps2 & emmc_caps) == emmc_caps) + dwc_priv->delay_line =PHY_DELAY_CODE_EMMC ; +else + dwc_priv->delay_line =PHY_DELAY_CODE_SD ; + +if (!of_property_read_u32 (dev->of_node,"eswin,drive-impedance-ohms" , &val)) + priv->drive_impedance =eic7700_convert_drive_impedance_ohm (dev, val); +return 0 ; +} +static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width,
@@ -1169,6 +1646,18 @@ static const struct sdhci_ops sdhci_dwcmshc_sg2042_ops = { .platform_execute_tuning = th1520_execute_tuning, }; +static const struct sdhci_ops sdhci_dwcmshc_eic7700_ops = { + .set_clock = sdhci_eic7700_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_eic7700_reset, + .set_uhs_signaling = sdhci_eic7700_set_uhs_wrapper, + .set_power = sdhci_set_power_and_bus_voltage, + .irq = dwcmshc_cqe_irq_handler, + .platform_execute_tuning = sdhci_eic7700_executing_tuning, +}; +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_pdata = { .pdata = { .ops = &sdhci_dwcmshc_ops,
@@ -1238,6 +1727,17 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc_sg2042_pdata = { .init = sg2042_init, }; +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_eic7700_pdata = { + .pdata = { + .ops = &sdhci_dwcmshc_eic7700_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +SDHCI_QUIRK_BROKEN_TIMEOUT_VAL , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN , + }, + .init = eic7700_init, +}; +static const struct cqhci_host_ops dwcmshc_cqhci_ops = { .enable = dwcmshc_sdhci_cqe_enable, .disable = sdhci_cqe_disable,
@@ -1338,6 +1838,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .compatible = "sophgo,sg2042-dwcmshc", .data = &sdhci_dwcmshc_sg2042_pdata, }, + { + .compatible = "eswin,eic7700-dwcmshc", + .data = &sdhci_dwcmshc_eic7700_pdata, + }, {}, };MODULE_DEVICE_TABLE (of, sdhci_dwcmshc_dt_ids);
@@ -1469,17 +1973,6 @@ static int dwcmshc_probe(struct platform_device *pdev)return err; } -static void dwcmshc_disable_card_clk (struct sdhci_host *host) -{ -u16 ctrl; - - ctrl =sdhci_readw (host,SDHCI_CLOCK_CONTROL ); -if (ctrl &SDHCI_CLOCK_CARD_EN ) { - ctrl &= ~SDHCI_CLOCK_CARD_EN ; -sdhci_writew (host, ctrl,SDHCI_CLOCK_CONTROL ); - } -} -static void dwcmshc_remove (struct platform_device *pdev) {struct sdhci_host *host =platform_get_drvdata (pdev);
@@ -1570,17 +2063,6 @@ static int dwcmshc_resume(struct device *dev)return ret; } -static void dwcmshc_enable_card_clk (struct sdhci_host *host) -{ -u16 ctrl; - - ctrl =sdhci_readw (host,SDHCI_CLOCK_CONTROL ); -if ((ctrl &SDHCI_CLOCK_INT_EN ) && !(ctrl &SDHCI_CLOCK_CARD_EN )) { - ctrl |=SDHCI_CLOCK_CARD_EN ; -sdhci_writew (host, ctrl,SDHCI_CLOCK_CONTROL ); - } -} -static int dwcmshc_runtime_suspend (struct device *dev) {struct sdhci_host *host =dev_get_drvdata (dev);
Signature · 1 line
2.25.1
kernel test robot
build botRe: [PATCH v3 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
kernel test robot noticed the following build errors:
Hi,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on ulf-hansson-mmc-mirror/next v6.17 next-20251010] [cannot apply to robh/for-next pza/reset/next pza/imx-drm/next] [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/hehuan1-eswincomputing-com/dt-bindings-mmc-sdhci-of-dwcmshc-Add-Eswin-EIC7700/20251010-174323 base: linus/master patch link: https://lore.kernel.org/r/20251010094109.1613-1-hehuan1%40eswincomputing.com patch subject: [PATCH v3 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700 config: riscv-randconfig-001-20251011 (https://download.01.org/0day-ci/archive/20251011/[email protected]/config) compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251011/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
In file included from drivers/mmc/host/sdhci-of-dwcmshc.c:15:
In file included from include/linux/dma-mapping.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/riscv/include/asm/io.h:140:
include/asm-generic/io.h:838:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
838 | insb(addr, buffer, count);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
arch/riscv/include/asm/io.h:108:53: note: expanded from macro 'insb'
108 | #define insb(addr, buffer, count) __insb(PCI_IOBASE + (addr), buffer, count)
| ~~~~~~~~~~ ^
In file included from drivers/mmc/host/sdhci-of-dwcmshc.c:15:
In file included from include/linux/dma-mapping.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/riscv/include/asm/io.h:140:
include/asm-generic/io.h:846:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
846 | insw(addr, buffer, count);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
arch/riscv/include/asm/io.h:109:53: note: expanded from macro 'insw'
109 | #define insw(addr, buffer, count) __insw(PCI_IOBASE + (addr), buffer, count)
| ~~~~~~~~~~ ^
In file included from drivers/mmc/host/sdhci-of-dwcmshc.c:15:
In file included from include/linux/dma-mapping.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/riscv/include/asm/io.h:140:
include/asm-generic/io.h:854:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
854 | insl(addr, buffer, count);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
arch/riscv/include/asm/io.h:110:53: note: expanded from macro 'insl'
110 | #define insl(addr, buffer, count) __insl(PCI_IOBASE + (addr), buffer, count)
| ~~~~~~~~~~ ^
In file included from drivers/mmc/host/sdhci-of-dwcmshc.c:15:
In file included from include/linux/dma-mapping.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/riscv/include/asm/io.h:140:
include/asm-generic/io.h:863:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
863 | outsb(addr, buffer, count);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
arch/riscv/include/asm/io.h:122:55: note: expanded from macro 'outsb'
122 | #define outsb(addr, buffer, count) __outsb(PCI_IOBASE + (addr), buffer, count)
| ~~~~~~~~~~ ^
In file included from drivers/mmc/host/sdhci-of-dwcmshc.c:15:
In file included from include/linux/dma-mapping.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/riscv/include/asm/io.h:140:
include/asm-generic/io.h:872:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
872 | outsw(addr, buffer, count);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
arch/riscv/include/asm/io.h:123:55: note: expanded from macro 'outsw'
123 | #define outsw(addr, buffer, count) __outsw(PCI_IOBASE + (addr), buffer, count)
| ~~~~~~~~~~ ^
In file included from drivers/mmc/host/sdhci-of-dwcmshc.c:15:
In file included from include/linux/dma-mapping.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/riscv/include/asm/io.h:140:
include/asm-generic/io.h:881:2: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
881 | outsl(addr, buffer, count);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
arch/riscv/include/asm/io.h:124:55: note: expanded from macro 'outsl'
124 | #define outsl(addr, buffer, count) __outsl(PCI_IOBASE + (addr), buffer, count)
| ~~~~~~~~~~ ^
In file included from drivers/mmc/host/sdhci-of-dwcmshc.c:15:
In file included from include/linux/dma-mapping.h:8:
In file included from include/linux/scatterlist.h:9:
In file included from arch/riscv/include/asm/io.h:140:
include/asm-generic/io.h:1209:55: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
1209 | return (port > MMIO_UPPER_LIMIT) ? NULL : PCI_IOBASE + port;
| ~~~~~~~~~~ ^
>> drivers/mmc/host/sdhci-of-dwcmshc.c:300:13: error: redefinition of 'dwcmshc_enable_card_clk'
300 | static void dwcmshc_enable_card_clk(struct sdhci_host *host)
| ^
drivers/mmc/host/sdhci-of-dwcmshc.c:289:13: note: previous definition is here
289 | static void dwcmshc_enable_card_clk(struct sdhci_host *host)
| ^
>> drivers/mmc/host/sdhci-of-dwcmshc.c:1179:2: error: call to undeclared function 'dwcmshc_disable_card_clk'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1179 | dwcmshc_disable_card_clk(host);
| ^
drivers/mmc/host/sdhci-of-dwcmshc.c:1179:2: note: did you mean 'dwcmshc_enable_card_clk'?
drivers/mmc/host/sdhci-of-dwcmshc.c:300:13: note: 'dwcmshc_enable_card_clk' declared here
300 | static void dwcmshc_enable_card_clk(struct sdhci_host *host)
| ^
drivers/mmc/host/sdhci-of-dwcmshc.c:1988:2: error: call to undeclared function 'dwcmshc_disable_card_clk'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
1988 | dwcmshc_disable_card_clk(host);
| ^
drivers/mmc/host/sdhci-of-dwcmshc.c:2070:2: error: call to undeclared function 'dwcmshc_disable_card_clk'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2070 | dwcmshc_disable_card_clk(host);
| ^7 warnings and 4 errors generated.
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for ARCH_HAS_ELF_CORE_EFLAGS Depends on [n]: BINFMT_ELF [=n] && ELF_CORE [=y]
Selected by [y]:
- RISCV [=y]
vim +/dwcmshc_enable_card_clk +300 drivers/mmc/host/sdhci-of-dwcmshc.c
299
> 300 static void dwcmshc_enable_card_clk(struct sdhci_host *host)
301 {
302 u16 ctrl;
303
304 ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
305 if ((ctrl & SDHCI_CLOCK_INT_EN) && !(ctrl & SDHCI_CLOCK_CARD_EN)) {
306 ctrl |= SDHCI_CLOCK_CARD_EN;
307 sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
308 }
309 }
310
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [PATCH v3 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
In reply to [email protected]kernel test robot noticed the following build warnings:
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on ulf-hansson-mmc-mirror/next v6.17 next-20251010] [cannot apply to robh/for-next pza/reset/next pza/imx-drm/next] [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/hehuan1-eswincomputing-com/dt-bindings-mmc-sdhci-of-dwcmshc-Add-Eswin-EIC7700/20251010-174323 base: linus/master patch link: https://lore.kernel.org/r/20251010094109.1613-1-hehuan1%40eswincomputing.com patch subject: [PATCH v3 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700 config: x86_64-randconfig-005-20251011 (https://download.01.org/0day-ci/archive/20251011/[email protected]/config) compiler: gcc-14 (Debian 14.2.0-19) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251011/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
drivers/mmc/host/sdhci-of-dwcmshc.c:300:13: error: redefinition of 'dwcmshc_enable_card_clk'
300 | static void dwcmshc_enable_card_clk(struct sdhci_host *host)
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/mmc/host/sdhci-of-dwcmshc.c:289:13: note: previous definition of 'dwcmshc_enable_card_clk' with type 'void(struct sdhci_host *)'
289 | static void dwcmshc_enable_card_clk(struct sdhci_host *host)
| ^~~~~~~~~~~~~~~~~~~~~~~
drivers/mmc/host/sdhci-of-dwcmshc.c: In function 'sdhci_eic7700_set_clock':
drivers/mmc/host/sdhci-of-dwcmshc.c:1179:9: error: implicit declaration of function 'dwcmshc_disable_card_clk'; did you mean 'dwcmshc_enable_card_clk'? [-Wimplicit-function-declaration]
1179 | dwcmshc_disable_card_clk(host);
| ^~~~~~~~~~~~~~~~~~~~~~~~
| dwcmshc_enable_card_clk
drivers/mmc/host/sdhci-of-dwcmshc.c: At top level:
>> drivers/mmc/host/sdhci-of-dwcmshc.c:289:13: warning: 'dwcmshc_enable_card_clk' defined but not used [-Wunused-function] 289 | static void dwcmshc_enable_card_clk(struct sdhci_host *host)
| ^~~~~~~~~~~~~~~~~~~~~~~
vim +/dwcmshc_enable_card_clk +289 drivers/mmc/host/sdhci-of-dwcmshc.c
288
> 289 static void dwcmshc_enable_card_clk(struct sdhci_host *host)
290 {
291 u16 ctrl;
292
293 ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
294 if ((ctrl & SDHCI_CLOCK_INT_EN) && !(ctrl & SDHCI_CLOCK_CARD_EN)) {
295 ctrl |= SDHCI_CLOCK_CARD_EN;
296 sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
297 }
298 }
299
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki