* [PATCH v5 0/2] Add support for Eswin EIC7700 SD/eMMC controller
@ 2025-10-19 11:51 hehuan1
2025-10-19 11:52 ` [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700 hehuan1
2025-10-19 11:53 ` [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for " hehuan1
0 siblings, 2 replies; 11+ messages in thread
From: hehuan1 @ 2025-10-19 11:51 UTC (permalink / raw)
To: ulf.hansson, robh, krzk+dt, conor+dt, jszhang, adrian.hunter,
p.zabel, linux-mmc, devicetree, linux-kernel
Cc: ningyu, linmin, pinkesh.vaghela, xuxiang, luyulin, dongxuyang,
zhangsenchuan, weishangjuan, lizhi2, caohang, hehuan1
From: Huan He <hehuan1@eswincomputing.com>
Updates:
Changes in v5:
- Update snps,dwcmshc-sdhci.yaml
- Update description for eswin,hsp-sp-csr
- Fix eswin,hsp-sp-csr property structure to use nested items format
- Remove unnecessary '|' symbol from description field
- Wrap description lines to 80-chars
- Update sdhci-of-dwcmshc.c
- Remove inappropriate Reported-by and Closes tags, as the fixes are part
of this patch
- Fix error code return in eic7700_init() when syscon_node_to_regmap()
fails (return PTR_ERR(hsp_regmap))
- Remove unnecessary clock disable/enable operations when changing clock
rates
- Remove unnecessary parentheses around ~PHY_CNFG_RSTN_DEASSERT in
sdhci_eic7700_config_phy()
- Update misleading comments: change "SDIO specific" to "SD specific" in
tuning logic
- Fix multi-line comment format
- Link to v4: https://lore.kernel.org/all/20251011111039.533-1-hehuan1@eswincomputing.com/
Changes in v4:
- Update sdhci-of-dwcmshc.c
- Address the compile error from kernel test robot
- Remove duplicate implementation of dwcmshc_enable_card_clk()
- Add missing dwcmshc_disable_card_clk() function implementation
- Link to v3: https://lore.kernel.org/all/20251010093807.1579-1-hehuan1@eswincomputing.com/
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/20250912093451.125-1-hehuan1@eswincomputing.com/
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/20250516091259.774-1-dongxuyang@eswincomputing.com/
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 | 502 +++++++++++++++++-
2 files changed, 542 insertions(+), 17 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
2025-10-19 11:51 [PATCH v5 0/2] Add support for Eswin EIC7700 SD/eMMC controller hehuan1
@ 2025-10-19 11:52 ` hehuan1
2025-10-20 11:35 ` Rob Herring (Arm)
2025-10-24 13:57 ` Ulf Hansson
2025-10-19 11:53 ` [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for " hehuan1
1 sibling, 2 replies; 11+ messages in thread
From: hehuan1 @ 2025-10-19 11:52 UTC (permalink / raw)
To: ulf.hansson, robh, krzk+dt, conor+dt, jszhang, adrian.hunter,
p.zabel, linux-mmc, devicetree, linux-kernel
Cc: ningyu, linmin, pinkesh.vaghela, xuxiang, luyulin, dongxuyang,
zhangsenchuan, weishangjuan, lizhi2, caohang, hehuan1,
Conor Dooley
From: Huan He <hehuan1@eswincomputing.com>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers.
Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml.
Signed-off-by: Huan He <hehuan1@eswincomputing.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++--
1 file changed, 51 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
index f882219a0a26..7e7c55dc2440 100644
--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
@@ -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:
+ - 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 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:
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
2025-10-19 11:51 [PATCH v5 0/2] Add support for Eswin EIC7700 SD/eMMC controller hehuan1
2025-10-19 11:52 ` [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700 hehuan1
@ 2025-10-19 11:53 ` hehuan1
2025-10-23 11:08 ` Adrian Hunter
1 sibling, 1 reply; 11+ messages in thread
From: hehuan1 @ 2025-10-19 11:53 UTC (permalink / raw)
To: ulf.hansson, robh, krzk+dt, conor+dt, jszhang, adrian.hunter,
p.zabel, linux-mmc, devicetree, linux-kernel
Cc: ningyu, linmin, pinkesh.vaghela, xuxiang, luyulin, dongxuyang,
zhangsenchuan, weishangjuan, lizhi2, caohang, hehuan1
From: Huan He <hehuan1@eswincomputing.com>
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.
Signed-off-by: Huan He <hehuan1@eswincomputing.com>
---
drivers/mmc/host/sdhci-of-dwcmshc.c | 502 +++++++++++++++++++++++++++-
1 file changed, 491 insertions(+), 11 deletions(-)
diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index eebd45389956..c8726e6e0905 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -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 3
struct dwcmshc_priv {
@@ -238,6 +286,17 @@ 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 int dwcmshc_get_enable_other_clks(struct device *dev,
struct dwcmshc_priv *priv,
int num_clks,
@@ -1095,6 +1154,411 @@ 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;
+ }
+
+ clk_set_rate(pltfm_host->clk, clock);
+
+ 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) {
+ /* SD 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);
+
+ /* SD 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 PTR_ERR(hsp_regmap);
+ }
+ 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 +1633,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 +1714,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 +1825,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);
@@ -1570,17 +2061,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);
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
2025-10-19 11:52 ` [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700 hehuan1
@ 2025-10-20 11:35 ` Rob Herring (Arm)
2025-10-24 13:57 ` Ulf Hansson
1 sibling, 0 replies; 11+ messages in thread
From: Rob Herring (Arm) @ 2025-10-20 11:35 UTC (permalink / raw)
To: hehuan1
Cc: linmin, ulf.hansson, lizhi2, devicetree, pinkesh.vaghela,
weishangjuan, jszhang, linux-mmc, zhangsenchuan, conor+dt,
p.zabel, caohang, dongxuyang, luyulin, ningyu, Conor Dooley,
adrian.hunter, linux-kernel, xuxiang, krzk+dt
On Sun, 19 Oct 2025 19:52:38 +0800, hehuan1@eswincomputing.com wrote:
> From: Huan He <hehuan1@eswincomputing.com>
>
> EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers.
> Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml.
>
> Signed-off-by: Huan He <hehuan1@eswincomputing.com>
> Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
> ---
> .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++--
> 1 file changed, 51 insertions(+), 6 deletions(-)
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/eswin,eic7700-eth.example.dtb: ethernet@50400000 (eswin,eic7700-qos-eth): eswin,hsp-sp-csr: [[4294967295, 256], [264, 280]] is too short
from schema $id: http://devicetree.org/schemas/net/eswin,eic7700-eth.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/net/eswin,eic7700-eth.example.dtb: ethernet@50400000 (eswin,eic7700-qos-eth): Unevaluated properties are not allowed ('eswin,hsp-sp-csr' was unexpected)
from schema $id: http://devicetree.org/schemas/net/eswin,eic7700-eth.yaml#
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20251019115238.320-1-hehuan1@eswincomputing.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
2025-10-19 11:53 ` [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for " hehuan1
@ 2025-10-23 11:08 ` Adrian Hunter
2025-10-24 3:19 ` 何欢
0 siblings, 1 reply; 11+ messages in thread
From: Adrian Hunter @ 2025-10-23 11:08 UTC (permalink / raw)
To: hehuan1, ulf.hansson, robh, krzk+dt, conor+dt, jszhang, p.zabel,
linux-mmc, devicetree, linux-kernel
Cc: ningyu, linmin, pinkesh.vaghela, xuxiang, luyulin, dongxuyang,
zhangsenchuan, weishangjuan, lizhi2, caohang
On 19/10/2025 14:53, hehuan1@eswincomputing.com wrote:
> From: Huan He <hehuan1@eswincomputing.com>
>
> 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.
>
> Signed-off-by: Huan He <hehuan1@eswincomputing.com>
Noting that the dt-bindings patch still seems to have issues,
for this patch, anyway:
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> drivers/mmc/host/sdhci-of-dwcmshc.c | 502 +++++++++++++++++++++++++++-
> 1 file changed, 491 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
> index eebd45389956..c8726e6e0905 100644
> --- a/drivers/mmc/host/sdhci-of-dwcmshc.c
> +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
> @@ -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 3
>
> struct dwcmshc_priv {
> @@ -238,6 +286,17 @@ 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 int dwcmshc_get_enable_other_clks(struct device *dev,
> struct dwcmshc_priv *priv,
> int num_clks,
> @@ -1095,6 +1154,411 @@ 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;
> + }
> +
> + clk_set_rate(pltfm_host->clk, clock);
> +
> + 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) {
> + /* SD 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);
> +
> + /* SD 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 PTR_ERR(hsp_regmap);
> + }
> + 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 +1633,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 +1714,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 +1825,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);
> @@ -1570,17 +2061,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);
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Re: [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
2025-10-23 11:08 ` Adrian Hunter
@ 2025-10-24 3:19 ` 何欢
2025-10-24 6:36 ` Adrian Hunter
0 siblings, 1 reply; 11+ messages in thread
From: 何欢 @ 2025-10-24 3:19 UTC (permalink / raw)
To: Adrian Hunter
Cc: ulf.hansson, robh, krzk+dt, conor+dt, jszhang, p.zabel, linux-mmc,
devicetree, linux-kernel, ningyu, linmin, pinkesh.vaghela,
xuxiang, luyulin, dongxuyang, zhangsenchuan, weishangjuan, lizhi2,
caohang, 何欢
Hi Adrian,
Thank you very much for your Acked-by and the review!
> On 19/10/2025 14:53, hehuan1@eswincomputing.com wrote:
> > From: Huan He <hehuan1@eswincomputing.com>
> >
> > 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.
> >
> > Signed-off-by: Huan He <hehuan1@eswincomputing.com>
>
> Noting that the dt-bindings patch still seems to have issues,
> for this patch, anyway:
>
> Acked-by: Adrian Hunter <adrian.hunter@intel.com>
I recieved an dt_binding_check error report:
https://lore.kernel.org/all/176096011380.22917.1988679321096076522.robh@kernel.org/
It seems the error has nothing to do with MMC, but is related to the
Ethernet binding (eswin,eic7700-eth.yaml), that was pushed by us and
applied recently, link:
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=888bd0eca93c
We're fixing this issue for the Ethernet. The Ethernet patch with
this bug fix will be sent out later.
I would be grateful for your reply.
Regards,
Huan He
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
2025-10-24 3:19 ` 何欢
@ 2025-10-24 6:36 ` Adrian Hunter
0 siblings, 0 replies; 11+ messages in thread
From: Adrian Hunter @ 2025-10-24 6:36 UTC (permalink / raw)
To: 何欢, ulf.hansson
Cc: robh, krzk+dt, conor+dt, jszhang, p.zabel, linux-mmc, devicetree,
linux-kernel, ningyu, linmin, pinkesh.vaghela, xuxiang, luyulin,
dongxuyang, zhangsenchuan, weishangjuan, lizhi2, caohang
On 24/10/2025 06:19, 何欢 wrote:
> Hi Adrian,
>
> Thank you very much for your Acked-by and the review!
>
>> On 19/10/2025 14:53, hehuan1@eswincomputing.com wrote:
>>> From: Huan He <hehuan1@eswincomputing.com>
>>>
>>> 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.
>>>
>>> Signed-off-by: Huan He <hehuan1@eswincomputing.com>
>>
>> Noting that the dt-bindings patch still seems to have issues,
>> for this patch, anyway:
>>
>> Acked-by: Adrian Hunter <adrian.hunter@intel.com>
>
> I recieved an dt_binding_check error report:
> https://lore.kernel.org/all/176096011380.22917.1988679321096076522.robh@kernel.org/
>
> It seems the error has nothing to do with MMC, but is related to the
> Ethernet binding (eswin,eic7700-eth.yaml), that was pushed by us and
> applied recently, link:
> https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=888bd0eca93c
>
> We're fixing this issue for the Ethernet. The Ethernet patch with
> this bug fix will be sent out later.
That seems OK, but it is up to Ulf now.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
2025-10-19 11:52 ` [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700 hehuan1
2025-10-20 11:35 ` Rob Herring (Arm)
@ 2025-10-24 13:57 ` Ulf Hansson
2025-10-24 16:37 ` Conor Dooley
1 sibling, 1 reply; 11+ messages in thread
From: Ulf Hansson @ 2025-10-24 13:57 UTC (permalink / raw)
To: hehuan1, robh, krzk+dt
Cc: conor+dt, jszhang, adrian.hunter, p.zabel, linux-mmc, devicetree,
linux-kernel, ningyu, linmin, pinkesh.vaghela, xuxiang, luyulin,
dongxuyang, zhangsenchuan, weishangjuan, lizhi2, caohang,
Conor Dooley
On Sun, 19 Oct 2025 at 13:52, <hehuan1@eswincomputing.com> wrote:
>
> From: Huan He <hehuan1@eswincomputing.com>
>
> EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers.
> Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml.
>
> Signed-off-by: Huan He <hehuan1@eswincomputing.com>
> Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
> ---
> .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++--
> 1 file changed, 51 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> index f882219a0a26..7e7c55dc2440 100644
> --- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> +++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> @@ -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:
> + - 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 tune
> + board-level's parameters of PHY, etc.
I would like second confirmation from DT maintainers, to make sure
it's reasonable to model the HW like this.
In principle the phandle above gets translated into a regmap via a
call to syscon_node_to_regmap() in the driver, to allow some registers
to be written that are outside the controllers address space.
> +
> + 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:
> --
> 2.25.1
>
Kind regards
Uffe
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
2025-10-24 13:57 ` Ulf Hansson
@ 2025-10-24 16:37 ` Conor Dooley
2025-10-24 21:47 ` Conor Dooley
0 siblings, 1 reply; 11+ messages in thread
From: Conor Dooley @ 2025-10-24 16:37 UTC (permalink / raw)
To: Ulf Hansson
Cc: hehuan1, robh, krzk+dt, conor+dt, jszhang, adrian.hunter, p.zabel,
linux-mmc, devicetree, linux-kernel, ningyu, linmin,
pinkesh.vaghela, xuxiang, luyulin, dongxuyang, zhangsenchuan,
weishangjuan, lizhi2, caohang, Conor Dooley
[-- Attachment #1: Type: text/plain, Size: 4242 bytes --]
On Fri, Oct 24, 2025 at 03:57:33PM +0200, Ulf Hansson wrote:
> On Sun, 19 Oct 2025 at 13:52, <hehuan1@eswincomputing.com> wrote:
> >
> > From: Huan He <hehuan1@eswincomputing.com>
> >
> > EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers.
> > Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml.
> >
> > Signed-off-by: Huan He <hehuan1@eswincomputing.com>
> > Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
> > ---
> > .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++--
> > 1 file changed, 51 insertions(+), 6 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > index f882219a0a26..7e7c55dc2440 100644
> > --- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > +++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > @@ -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:
> > + - 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 tune
> > + board-level's parameters of PHY, etc.
>
> I would like second confirmation from DT maintainers, to make sure
> it's reasonable to model the HW like this.
If by second confirmation, you mean by someone other than me, obviously
ignore this, but I think this is "fine". It discussed on a previous
revision that all is being done with it is setting a handful bits that
signify that the peripheral has been configured correctly.
That said, I don't have a clue what's going on with the warning about
the dwmac device. That's definitely one for Rob.
>
> In principle the phandle above gets translated into a regmap via a
> call to syscon_node_to_regmap() in the driver, to allow some registers
> to be written that are outside the controllers address space.
>
> > +
> > + 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:
> > --
> > 2.25.1
> >
>
> Kind regards
> Uffe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
2025-10-24 16:37 ` Conor Dooley
@ 2025-10-24 21:47 ` Conor Dooley
2025-10-24 22:22 ` Rob Herring
0 siblings, 1 reply; 11+ messages in thread
From: Conor Dooley @ 2025-10-24 21:47 UTC (permalink / raw)
To: Ulf Hansson
Cc: hehuan1, robh, krzk+dt, conor+dt, jszhang, adrian.hunter, p.zabel,
linux-mmc, devicetree, linux-kernel, ningyu, linmin,
pinkesh.vaghela, xuxiang, luyulin, dongxuyang, zhangsenchuan,
weishangjuan, lizhi2, caohang, Conor Dooley
[-- Attachment #1: Type: text/plain, Size: 4813 bytes --]
On Fri, Oct 24, 2025 at 05:37:59PM +0100, Conor Dooley wrote:
> On Fri, Oct 24, 2025 at 03:57:33PM +0200, Ulf Hansson wrote:
> > On Sun, 19 Oct 2025 at 13:52, <hehuan1@eswincomputing.com> wrote:
> > >
> > > From: Huan He <hehuan1@eswincomputing.com>
> > >
> > > EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers.
> > > Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml.
> > >
> > > Signed-off-by: Huan He <hehuan1@eswincomputing.com>
> > > Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
> > > ---
> > > .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++--
> > > 1 file changed, 51 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > > index f882219a0a26..7e7c55dc2440 100644
> > > --- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > > +++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > > @@ -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:
> > > + - 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 tune
> > > + board-level's parameters of PHY, etc.
> >
> > I would like second confirmation from DT maintainers, to make sure
> > it's reasonable to model the HW like this.
>
> If by second confirmation, you mean by someone other than me, obviously
> ignore this, but I think this is "fine". It discussed on a previous
> revision that all is being done with it is setting a handful bits that
> signify that the peripheral has been configured correctly.
>
> That said, I don't have a clue what's going on with the warning about
> the dwmac device. That's definitely one for Rob.
Apparently it's just as simple as there being more than one definition
of the same property. I had it in my head that that was okay when only
one binding was applied to the node, but clearly not.
I'll have to un-review it until that error is sorted out.
> > In principle the phandle above gets translated into a regmap via a
> > call to syscon_node_to_regmap() in the driver, to allow some registers
> > to be written that are outside the controllers address space.
> >
> > > +
> > > + 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:
> > > --
> > > 2.25.1
> > >
> >
> > Kind regards
> > Uffe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
2025-10-24 21:47 ` Conor Dooley
@ 2025-10-24 22:22 ` Rob Herring
0 siblings, 0 replies; 11+ messages in thread
From: Rob Herring @ 2025-10-24 22:22 UTC (permalink / raw)
To: Conor Dooley
Cc: Ulf Hansson, hehuan1, krzk+dt, conor+dt, jszhang, adrian.hunter,
p.zabel, linux-mmc, devicetree, linux-kernel, ningyu, linmin,
pinkesh.vaghela, xuxiang, luyulin, dongxuyang, zhangsenchuan,
weishangjuan, lizhi2, caohang, Conor Dooley
On Fri, Oct 24, 2025 at 10:47:34PM +0100, Conor Dooley wrote:
> On Fri, Oct 24, 2025 at 05:37:59PM +0100, Conor Dooley wrote:
> > On Fri, Oct 24, 2025 at 03:57:33PM +0200, Ulf Hansson wrote:
> > > On Sun, 19 Oct 2025 at 13:52, <hehuan1@eswincomputing.com> wrote:
> > > >
> > > > From: Huan He <hehuan1@eswincomputing.com>
> > > >
> > > > EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers.
> > > > Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml.
> > > >
> > > > Signed-off-by: Huan He <hehuan1@eswincomputing.com>
> > > > Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
> > > > ---
> > > > .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++--
> > > > 1 file changed, 51 insertions(+), 6 deletions(-)
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > > > index f882219a0a26..7e7c55dc2440 100644
> > > > --- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > > > +++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
> > > > @@ -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:
> > > > + - 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 tune
> > > > + board-level's parameters of PHY, etc.
> > >
> > > I would like second confirmation from DT maintainers, to make sure
> > > it's reasonable to model the HW like this.
> >
> > If by second confirmation, you mean by someone other than me, obviously
> > ignore this, but I think this is "fine". It discussed on a previous
> > revision that all is being done with it is setting a handful bits that
> > signify that the peripheral has been configured correctly.
> >
> > That said, I don't have a clue what's going on with the warning about
> > the dwmac device. That's definitely one for Rob.
>
> Apparently it's just as simple as there being more than one definition
> of the same property. I had it in my head that that was okay when only
> one binding was applied to the node, but clearly not.
>
> I'll have to un-review it until that error is sorted out.
This binding is fine. The error is in the eswin,eic770-eth.yaml binding:
eswin,hsp-sp-csr:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- description: Phandle to HSP(High-Speed Peripheral) device
- description: Offset of phy control register for internal
or external clock selection
- description: Offset of AXI clock controller Low-Power request
register
- description: Offset of register controlling TX/RX clock delay
description: |
High-Speed Peripheral device needed to configure clock selection,
clock low-power mode and clock delay.
The issue here is phandle-array is really a matrix and an outer 'items'
is needed to say there is 1 entry with 4 cells. Like this:
items:
- items:
- description: ...
- description: ...
- description: ...
- description: ...
Please send a fix for that.
The tools could handle this case better, so I'll look into a fix for
them.
Rob
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-10-24 22:22 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-19 11:51 [PATCH v5 0/2] Add support for Eswin EIC7700 SD/eMMC controller hehuan1
2025-10-19 11:52 ` [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700 hehuan1
2025-10-20 11:35 ` Rob Herring (Arm)
2025-10-24 13:57 ` Ulf Hansson
2025-10-24 16:37 ` Conor Dooley
2025-10-24 21:47 ` Conor Dooley
2025-10-24 22:22 ` Rob Herring
2025-10-19 11:53 ` [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for " hehuan1
2025-10-23 11:08 ` Adrian Hunter
2025-10-24 3:19 ` 何欢
2025-10-24 6:36 ` Adrian Hunter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).