From nobody Thu Oct 2 19:00:58 2025 Received: from zg8tmja5ljk3lje4mi4ymjia.icoremail.net (zg8tmja5ljk3lje4mi4ymjia.icoremail.net [209.97.182.222]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7CF92211A09; Fri, 12 Sep 2025 09:37:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.97.182.222 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757669860; cv=none; b=WPBchnoaEEE/bOoXPyKiKHXkBnZidVvNLgsya7ZbXAAvoNlleKqyAuKmHLEN2Lr5wggJnc4Pl2HNaZXOD/X3Rf8nNRg49q22mIrLgByXJhpdqyHp/DroQAdaCvAynIF5FCsX/XioI1Bla0IQJZX+czoHB364Gy9mvv7dPKuZHck= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757669860; c=relaxed/simple; bh=d3Xz5EpHIWdV7OLbNRXvXBeYGZWMR4ewhEs6jhMcR7o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CSZ0hSQM8JVXXIaNaokGfvFkUNqKVfgbS9bsKepJ1YmZpcBspgzleDcWqeOBFZAhbOOUv4dxbQ/TFSvFdS3P2XWhrc6trfsYAvn5fEBbdITolMV0tWu7pu5QU0BhME2e4h/ePCoGSstmqxeqfba8xByb4QZCp97XkjzZWhxgsS8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com; spf=pass smtp.mailfrom=eswincomputing.com; arc=none smtp.client-ip=209.97.182.222 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=eswincomputing.com Received: from E0005154LT.eswin.cn (unknown [10.12.96.103]) by app1 (Coremail) with SMTP id TAJkCgDnCxLM6cNoRM7OAA--.64219S2; Fri, 12 Sep 2025 17:37:18 +0800 (CST) From: hehuan1@eswincomputing.com To: ulf.hansson@linaro.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, jszhang@kernel.org, adrian.hunter@intel.com, p.zabel@pengutronix.de, linux-mmc@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: ningyu@eswincomputing.com, linmin@eswincomputing.com, pinkesh.vaghela@einfochips.com, xuxiang@eswincomputing.com, luyulin@eswincomputing.com, dongxuyang@eswincomputing.com, zhangsenchuan@eswincomputing.com, weishangjuan@eswincomputing.com, lizhi2@eswincomputing.com, caohang@eswincomputing.com, hehuan1@eswincomputing.com Subject: [PATCH v2 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700 Date: Fri, 12 Sep 2025 17:37:13 +0800 Message-ID: <20250912093713.142-1-hehuan1@eswincomputing.com> X-Mailer: git-send-email 2.49.0.windows.1 In-Reply-To: <20250912093451.125-1-hehuan1@eswincomputing.com> References: <20250912093451.125-1-hehuan1@eswincomputing.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: TAJkCgDnCxLM6cNoRM7OAA--.64219S2 X-Coremail-Antispam: 1UD129KBjvJXoWxAw15CF17XF1kXr15Zr1UKFg_yoW5Cr17pa ykJ3y7Gr1fJF1fZw4Ut3WkC3W3Kan7Jr1Yyr17Jr13Jan0qFy8tFWak3Z8Ka45CF1xZaya gayUuryfAw12vr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBv14x267AKxVW5JVWrJwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26w1j6s0DM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4U JVWxJr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_Gc CE3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E 2Ix0cI8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJV W8JwACjcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2 Y2ka0xkIwI1lw4CEc2x0rVAKj4xxMxkF7I0En4kS14v26r4a6rW5MxkIecxEwVCm-wCF04 k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18 MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr4 1lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l IxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0xvEx4 A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x0pRuHqcUUUUU= X-CM-SenderInfo: 5khk3tzqr6v25zlqu0xpsx3x1qjou0bp/ Content-Type: text/plain; charset="utf-8" From: Huan He EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml. Signed-off-by: Huan He --- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 81 +++++++++++++++++-- 1 file changed, 75 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..e0f34bc28e0c 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 =20 reg: maxItems: 1 @@ -52,17 +53,51 @@ properties: maxItems: 5 =20 reset-names: - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + maxItems: 5 =20 rockchip,txclk-tapnum: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8 =20 + clock-output-names: + maxItems: 1 + description: + The name of the clock output representing the card clock, + consumed by the PHY. + + '#clock-cells': + enum: [0] + description: + Specifies how many cells are used when referencing the + exported clock from another node. This property indicates + that the clock output has no extra parameters and represents + the card clock. + + 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: | + High-Speed Peripheral device needed to configure internal + clocks, and the power. + + eswin,syscrg-csr: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - description: Phandle to system CRG(System Clock and Reset + Generator) device + - description: Offset of core clock control register + description: | + System Clock and Reset Generator device needed to configure + core clock. + + drive-impedance-ohm: + description: Specifies the drive impedance in Ohm. + enum: [33, 40, 50, 66, 100] + required: - compatible - reg @@ -110,6 +145,40 @@ allOf: - const: block - const: timer =20 + - if: + properties: + compatible: + contains: + const: eswin,eic7700-dwcmshc + then: + properties: + resets: + minItems: 4 + maxItems: 4 + reset-names: + items: + - const: arstn + - const: phy_rst + - const: prstn + - const: txrx_rst + required: + - clock-output-names + - '#clock-cells' + - eswin,hsp-sp-csr + - eswin,syscrg-csr + - drive-impedance-ohm + else: + properties: + resets: + maxItems: 5 + reset-names: + items: + - const: core + - const: bus + - const: axi + - const: block + - const: timer + - if: properties: compatible: --=20 2.25.1 From nobody Thu Oct 2 19:00:58 2025 Received: from zg8tmja2lje4os4yms4ymjma.icoremail.net (zg8tmja2lje4os4yms4ymjma.icoremail.net [206.189.21.223]) by smtp.subspace.kernel.org (Postfix) with ESMTP id CAA0026057F; Fri, 12 Sep 2025 09:38:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=206.189.21.223 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757669902; cv=none; b=ppgWtU3APux4VHuxHt/uy1kGL9eX6qCcUMyO89a4cUxyomXURcg9g18WJ8xjLga47DTmUjqEqZOkdcaJkOsoYhSiRbL+AlH1mMH0uVGe7pNvsy5ogPf8IuYkwscSEJhK6wc/izPUm4cWzkoiF1LtoCTW4g5xb2ZgJjpXgqx+0p4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757669902; c=relaxed/simple; bh=6lgxMzhWeAabD9ywOkCxncjWr5+amPuAa6I4uovX2tQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=En/G3B8qnTHlAZo8GuiG5Z3J9xkyYspJ/1l+YCaiv39SeCwlBJO9Zs9fkXmo+80GDkSdU/RK+Bp1makPXdRtF5P7uj8NzviXw2mHxKmNujjOCElgS9jNzIBeI3ika5hUmqmvTzg3nkR2+Lkya+2ECQ0E6vqXgxjcKkHTxkD73SU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com; spf=pass smtp.mailfrom=eswincomputing.com; arc=none smtp.client-ip=206.189.21.223 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=eswincomputing.com Received: from E0005154LT.eswin.cn (unknown [10.12.96.103]) by app1 (Coremail) with SMTP id TAJkCgAXLg_+6cNoY87OAA--.52852S2; Fri, 12 Sep 2025 17:38:08 +0800 (CST) From: hehuan1@eswincomputing.com To: ulf.hansson@linaro.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, jszhang@kernel.org, adrian.hunter@intel.com, p.zabel@pengutronix.de, linux-mmc@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: ningyu@eswincomputing.com, linmin@eswincomputing.com, pinkesh.vaghela@einfochips.com, xuxiang@eswincomputing.com, luyulin@eswincomputing.com, dongxuyang@eswincomputing.com, zhangsenchuan@eswincomputing.com, weishangjuan@eswincomputing.com, lizhi2@eswincomputing.com, caohang@eswincomputing.com, hehuan1@eswincomputing.com Subject: [PATCH v2 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700 Date: Fri, 12 Sep 2025 17:38:03 +0800 Message-ID: <20250912093803.159-1-hehuan1@eswincomputing.com> X-Mailer: git-send-email 2.49.0.windows.1 In-Reply-To: <20250912093451.125-1-hehuan1@eswincomputing.com> References: <20250912093451.125-1-hehuan1@eswincomputing.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: TAJkCgAXLg_+6cNoY87OAA--.52852S2 X-Coremail-Antispam: 1UD129KBjvAXoWfZry7tryxXr13Ww1rXr1DKFg_yoW5GF43Zo WfWFnxWw4rJ3yxWFWYkr97GF1Uuws7Aayagw4furnru3WkA3W5Wr4SkF43Jw1fXryFyrWk XrZ7JrW3XrWfAFn5n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYN7AC8VAFwI0_Xr0_Wr1l1xkIjI8I6I8E6xAIw20EY4v20xva j40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxSw2 x7M28EF7xvwVC0I7IYx2IY67AKxVWDJVCq3wA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxVW8 Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v26r xl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj 6xIIjxv20xvE14v26r1Y6r17McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr 0_Gr1lF7xvr2IYc2Ij64vIr41lF7I21c0EjII2zVCS5cI20VAGYxC7M4IIrI8v6xkF7I0E 8cxan2IY04v7M4kE6xkIj40Ew7xC0wCY1x0262kKe7AKxVW8ZVWrXwCY02Avz4vE-syl42 xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWU GwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6rW5MIIYrxkI7VAKI4 8JMIIF0xvE2Ix0cI8IcVAFwI0_Jr0_JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26F4j6r4U JwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcV C2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7sRiBT5PUUUUU== X-CM-SenderInfo: 5khk3tzqr6v25zlqu0xpsx3x1qjou0bp/ Content-Type: text/plain; charset="utf-8" From: Huan He 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 --- drivers/mmc/host/sdhci-of-dwcmshc.c | 770 ++++++++++++++++++++++++++++ 1 file changed, 770 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-o= f-dwcmshc.c index ee6b1096f709..dd16c7a3bda7 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,8 +20,11 @@ #include #include #include +#include #include #include +#include +#include =20 #include "sdhci-pltfm.h" #include "cqhci.h" @@ -194,6 +198,10 @@ #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 = */ =20 +#define PHY_DLL_OFFST_R (DWC_MSHC_PTR_PHY_R + 0x29) +#define PHY_DLLBT_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x2c) +#define PHY_DLL_STATUS_R (DWC_MSHC_PTR_PHY_R + 0x2e) + #define FLAG_IO_FIXED_1V8 BIT(0) =20 #define BOUNDARY_OK(addr, len) \ @@ -206,6 +214,48 @@ /* SMC call for BlueField-3 eMMC RST_N */ #define BLUEFIELD_SMC_SET_EMMC_RST_N 0x82000007 =20 +/* 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) +#define EIC7700_CORE_CLK_ENABLE BIT(16) +#define EIC7700_CORE_CLK_FREQ_SHIFT 4 +#define EIC7700_CORE_CLK_FREQ_MASK 0xfffu +#define EIC7700_CORE_CLK_SEL_BIT 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 LATENCY_LT_BIT_OFFSET 19 +#define LATENCY_LT_MASK 0x3 +#define LATENCY_LT_3 0x2 +#define VENDOR_AT_SATA_R 0x544 + +#define MAX_PHASE_CODE 0xff +#define TUNING_RANGE_THRESHOLD 40 + +#define PHY_CLK_MAX_DELAY_MASK 0x7f +#define PHY_PAD_SP_DRIVE_SHIF 16 + +#define EIC7700_CORE_CLK_SRC_208MHZ (208 * HZ_PER_MHZ) +#define EIC7700_CORE_CLK_SRC_200MHZ (200 * HZ_PER_MHZ) +#define MAX_CORE_CLK_DIV 0xfff +#define DLL_LOCK_STS BIT(0) +#define DLL_ERROR_STS BIT(1) +#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 +267,18 @@ struct rk35xx_priv { u8 txclk_tapnum; }; =20 +struct eic7700_priv { + struct sdhci_host *host; + struct clk_hw sdcardclk_hw; + struct clk *sdcardclk; + int clk_phase_out[MMC_TIMING_MMC_HS400 + 1]; + void (*set_clk_delays)(struct sdhci_host *host); + struct reset_control *reset; + struct regmap *crg_regmap; + unsigned int crg_core_clk; + unsigned int drive_impedance; +}; + #define DWCMSHC_MAX_OTHER_CLKS 3 =20 struct dwcmshc_priv { @@ -238,6 +300,8 @@ struct dwcmshc_pltfm_data { void (*postinit)(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv); }; =20 +static void dwcmshc_disable_card_clk(struct sdhci_host *host); + static int dwcmshc_get_enable_other_clks(struct device *dev, struct dwcmshc_priv *priv, int num_clks, @@ -1095,6 +1159,685 @@ static int sg2042_init(struct device *dev, struct s= dhci_host *host, ARRAY_SIZE(clk_ids), clk_ids); } =20 +static void sdhci_eic7700_enable_card_clk(struct sdhci_host *host) +{ + u16 clk; + int ret; + + clk =3D sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |=3D SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + /* Wait max 150 ms */ + ret =3D read_poll_timeout(sdhci_readw, clk, clk & SDHCI_CLOCK_INT_STABLE, + 10, 150000, false, host, SDHCI_CLOCK_CONTROL); + if (ret) { + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); + return; + } + + clk |=3D SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + usleep_range(1000, 2000); +} + +static void eic7700_mshc_coreclk_disable(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host =3D sdhci_priv(host); + struct dwcmshc_priv *dwc_priv =3D sdhci_pltfm_priv(pltfm_host); + struct eic7700_priv *priv =3D dwc_priv->priv; + u32 val; + + regmap_read(priv->crg_regmap, priv->crg_core_clk, &val); + val &=3D ~EIC7700_CORE_CLK_ENABLE; + regmap_write(priv->crg_regmap, priv->crg_core_clk, val); +} + +static void eic7700_mshc_coreclk_config(struct sdhci_host *host, + u16 divisor, unsigned int flag_sel) +{ + struct sdhci_pltfm_host *pltfm_host =3D sdhci_priv(host); + struct dwcmshc_priv *dwc_priv =3D sdhci_pltfm_priv(pltfm_host); + struct eic7700_priv *priv =3D dwc_priv->priv; + u32 val; + + regmap_read(priv->crg_regmap, priv->crg_core_clk, &val); + val &=3D ~EIC7700_CORE_CLK_ENABLE; + regmap_write(priv->crg_regmap, priv->crg_core_clk, val); + usleep_range(10, 20); + + val &=3D ~(EIC7700_CORE_CLK_FREQ_MASK << EIC7700_CORE_CLK_FREQ_SHIFT); + val |=3D (divisor & EIC7700_CORE_CLK_FREQ_MASK) << + EIC7700_CORE_CLK_FREQ_SHIFT; + val &=3D ~(EIC7700_CORE_CLK_SEL_BIT); + val |=3D flag_sel; + regmap_write(priv->crg_regmap, priv->crg_core_clk, val); + + usleep_range(50, 60); + val |=3D EIC7700_CORE_CLK_ENABLE; + regmap_write(priv->crg_regmap, priv->crg_core_clk, val); + usleep_range(1000, 1100); +} + +static void sdhci_eic7700_set_core_clock(struct sdhci_host *host, + unsigned int clock) +{ + unsigned int flag_sel, max_clk; + unsigned int div, divide; + + host->mmc->actual_clock =3D clock; + + if (clock =3D=3D 0) { + eic7700_mshc_coreclk_disable(host); + return; + } + + if (EIC7700_CORE_CLK_SRC_208MHZ % clock =3D=3D 0) { + flag_sel =3D 1; + max_clk =3D EIC7700_CORE_CLK_SRC_208MHZ; + } else { + flag_sel =3D 0; + max_clk =3D EIC7700_CORE_CLK_SRC_200MHZ; + } + + for (div =3D 1; div <=3D MAX_CORE_CLK_DIV; div++) { + if ((max_clk / div) <=3D clock) + break; + } + div--; + + if (div =3D=3D 0 || div =3D=3D 1) + divide =3D 2; + else + divide =3D (div + 1) * 2; + + dwcmshc_disable_card_clk(host); + eic7700_mshc_coreclk_config(host, divide, flag_sel); + sdhci_eic7700_enable_card_clk(host); + usleep_range(2000, 3000); +} + +static void sdhci_eic7700_set_clock(struct sdhci_host *host, unsigned int = clock) +{ + struct sdhci_pltfm_host *pltfm_host =3D sdhci_priv(host); + struct dwcmshc_priv *dwc_priv =3D sdhci_pltfm_priv(pltfm_host); + struct eic7700_priv *priv =3D dwc_priv->priv; + + /* Set the Input and Output Clock Phase Delays */ + if (priv->set_clk_delays) + priv->set_clk_delays(host); + + sdhci_eic7700_set_core_clock(host, clock); +} + +static void sdhci_eic7700_config_phy_delay(struct sdhci_host *host, int de= lay) +{ + delay &=3D 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 =3D sdhci_priv(host); + struct dwcmshc_priv *dwc_priv =3D sdhci_pltfm_priv(pltfm_host); + u32 emmc_caps =3D MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; + struct eic7700_priv *priv =3D dwc_priv->priv; + unsigned int val, drv; + + drv =3D priv->drive_impedance << PHY_PAD_SP_DRIVE_SHIF; + + if ((host->mmc->caps2 & emmc_caps) =3D=3D emmc_caps) { + val =3D sdhci_readw(host, dwc_priv->vendor_specific_area1 + + DWCMSHC_EMMC_CONTROL); + val |=3D DWCMSHC_CARD_IS_EMMC; + sdhci_writew(host, val, dwc_priv->vendor_specific_area1 + + DWCMSHC_EMMC_CONTROL); + } + + dwcmshc_disable_card_clk(host); + + /* reset phy, config phy's pad */ + sdhci_writel(host, drv | (~PHY_CNFG_RSTN_DEASSERT), PHY_CNFG_R); + + /* configure phy pads */ + val =3D FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, + PHY_PAD_TXSLEW_CTRL_N_SG2042); + val |=3D FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, + PHY_PAD_TXSLEW_CTRL_N_SG2042); + val |=3D FIELD_PREP(PHY_PAD_WEAKPULL_MASK, + PHY_PAD_WEAKPULL_PULLUP); + val |=3D 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 =3D FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, + PHY_PAD_TXSLEW_CTRL_N_SG2042); + val |=3D 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) =3D=3D emmc_caps) { + val =3D FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, + PHY_PAD_TXSLEW_CTRL_N_SG2042); + val |=3D FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, + PHY_PAD_TXSLEW_CTRL_N_SG2042); + val |=3D 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); + sdhci_eic7700_enable_card_clk(host); +} + +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 =3D=3D SDHCI_RESET_ALL) + sdhci_eic7700_config_phy(host); +} + +static unsigned long +sdhci_eic7700_sdcardclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct eic7700_priv *priv =3D + container_of(hw, struct eic7700_priv, sdcardclk_hw); + + return priv->host->mmc->actual_clock; +} + +static const struct clk_ops eic7700_sdcardclk_ops =3D { + .recalc_rate =3D sdhci_eic7700_sdcardclk_recalc_rate, +}; + +static int sdhci_eic7700_register_sdcardclk(struct eic7700_priv *priv, + struct clk *clk, struct device *dev) +{ + struct device_node *np =3D dev->of_node; + struct clk_init_data sdcardclk_init; + const char *parent_clk_name; + int ret; + + ret =3D of_property_read_string_index(np, "clock-output-names", 0, + &sdcardclk_init.name); + if (ret) { + dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); + return ret; + } + + parent_clk_name =3D __clk_get_name(clk); + sdcardclk_init.parent_names =3D &parent_clk_name; + sdcardclk_init.num_parents =3D 1; + sdcardclk_init.flags =3D CLK_GET_RATE_NOCACHE; + sdcardclk_init.ops =3D &eic7700_sdcardclk_ops; + + priv->sdcardclk_hw.init =3D &sdcardclk_init; + priv->sdcardclk =3D devm_clk_register(dev, &priv->sdcardclk_hw); + if (IS_ERR(priv->sdcardclk)) + return PTR_ERR(priv->sdcardclk); + priv->sdcardclk_hw.init =3D NULL; + + ret =3D of_clk_add_provider(np, of_clk_src_simple_get, + priv->sdcardclk); + if (ret) + dev_err(dev, "Failed to add sdcard clock provider\n"); + + return ret; +} + +static int sdhci_eic7700_register_sdclk(struct dwcmshc_priv *dwc_priv, + struct clk *clk, struct device *dev) +{ + struct device_node *np =3D dev->of_node; + int ret; + + /* Providing a clock to the PHY is optional; no error if missing */ + if (!of_property_present(np, "#clock-cells")) + return 0; + + ret =3D sdhci_eic7700_register_sdcardclk(dwc_priv->priv, clk, dev); + + return ret; +} + +static int sdhci_eic7700_reset_init(struct device *dev, + struct eic7700_priv *priv) +{ + int ret; + + priv->reset =3D devm_reset_control_array_get_optional_exclusive(dev); + if (IS_ERR(priv->reset)) { + ret =3D PTR_ERR(priv->reset); + dev_err(dev, "failed to get reset control %d\n", ret); + return ret; + } + + ret =3D 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 =3D reset_control_deassert(priv->reset); + if (ret) { + dev_err(dev, "Failed to deassert reset signals: %d\n", ret); + return ret; + } + + return ret; +} + +static void sdhci_eic7700_set_clk_delays(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host =3D sdhci_priv(host); + struct dwcmshc_priv *dwc_priv =3D sdhci_pltfm_priv(pltfm_host); + struct eic7700_priv *priv =3D dwc_priv->priv; + + clk_set_phase(priv->sdcardclk, + priv->clk_phase_out[host->timing]); +} + +static void sdhci_eic7700_dt_read_clk_phase(struct device *dev, + struct eic7700_priv *priv, + unsigned int timing, + const char *prop) +{ + struct device_node *np =3D dev->of_node; + int clk_phase[2] =3D {0}; + + /* + * Read Tap Delay values from DT, if the DT does not contain the Tap + * Values then use the pre-defined values. + */ + if (of_property_read_variable_u32_array(np, prop, &clk_phase[0], 2, + 0)) { + dev_dbg(dev, "Using predefined clock phase for %s =3D %d\n", + prop, priv->clk_phase_out[timing]); + return; + } + + /* Only use the output clock delays in order */ + priv->clk_phase_out[timing] =3D clk_phase[1]; +} + +static void sdhci_eic7700_dt_parse_clk_phases(struct device *dev, + struct dwcmshc_priv *dwc_priv) +{ + struct eic7700_priv *priv =3D dwc_priv->priv; + + priv->set_clk_delays =3D sdhci_eic7700_set_clk_delays; + + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_LEGACY, + "clk-phase-legacy"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_MMC_HS, + "clk-phase-mmc-hs"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_SD_HS, + "clk-phase-sd-hs"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_UHS_SDR12, + "clk-phase-uhs-sdr12"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_UHS_SDR25, + "clk-phase-uhs-sdr25"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_UHS_SDR50, + "clk-phase-uhs-sdr50"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_UHS_SDR104, + "clk-phase-uhs-sdr104"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_UHS_DDR50, + "clk-phase-uhs-ddr50"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_MMC_DDR52, + "clk-phase-mmc-ddr52"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_MMC_HS200, + "clk-phase-mmc-hs200"); + sdhci_eic7700_dt_read_clk_phase(dev, priv, MMC_TIMING_MMC_HS400, + "clk-phase-mmc-hs400"); +} + +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-ohm.\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 =3D sdhci_priv(host); + struct dwcmshc_priv *dwc_priv =3D sdhci_pltfm_priv(pltfm_host); + int cmd_error, delay, ret, i; + int delay_min =3D -1; + int delay_max =3D -1; + + for (i =3D 0; i <=3D PHY_DELAY_CODE_MAX; i++) { + dwcmshc_disable_card_clk(host); + sdhci_eic7700_config_phy_delay(host, i); + sdhci_eic7700_enable_card_clk(host); + ret =3D 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 !=3D -1 && delay_max !=3D -1) + break; + } else { + if (delay_min =3D=3D -1) { + delay_min =3D i; + continue; + } else { + delay_max =3D i; + continue; + } + } + } + if (delay_min =3D=3D -1 && delay_max =3D=3D -1) { + pr_err("%s: delay code tuning failed!\n", + mmc_hostname(host->mmc)); + dwcmshc_disable_card_clk(host); + sdhci_eic7700_config_phy_delay(host, dwc_priv->delay_line); + sdhci_eic7700_enable_card_clk(host); + + return ret; + } + + delay =3D (delay_min + delay_max) / 2; + dwcmshc_disable_card_clk(host); + sdhci_eic7700_config_phy_delay(host, delay); + sdhci_eic7700_enable_card_clk(host); + + return 0; +} + +static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 op= code) +{ + u32 sd_caps =3D MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO; + int cmd_error, ret, i; + bool is_sdio =3D false; + int phase_code =3D -1; + int code_range =3D -1; + int code_min =3D -1; + int code_max =3D -1; + + if ((host->mmc->caps2 & sd_caps) =3D=3D sd_caps) + is_sdio =3D true; + + for (i =3D 0; i <=3D MAX_PHASE_CODE; i++) { + dwcmshc_disable_card_clk(host); + sdhci_writew(host, i, VENDOR_AT_SATA_R); + sdhci_eic7700_enable_card_clk(host); + + ret =3D 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_sdio && code_min !=3D -1 && code_max !=3D -1) { + if (code_max - code_min > code_range) { + code_range =3D code_max - code_min; + phase_code =3D (code_min + code_max) / 2; + if (code_range > TUNING_RANGE_THRESHOLD) + break; + } + code_min =3D -1; + code_max =3D -1; + } + /* EMMC breaks after first valid range */ + if (!is_sdio && code_min !=3D -1 && code_max !=3D -1) + break; + } else { + /* Track valid phase code range */ + if (code_min =3D=3D -1) { + code_min =3D i; + if (!is_sdio) + continue; + } + code_max =3D i; + if (is_sdio && i =3D=3D MAX_PHASE_CODE) { + if (code_max - code_min > code_range) { + code_range =3D code_max - code_min; + phase_code =3D (code_min + code_max) / 2; + } + } + } + } + + /* Handle tuning failure case */ + if ((is_sdio && phase_code =3D=3D -1) || + (!is_sdio && code_min =3D=3D -1 && code_max =3D=3D -1)) { + pr_err("%s: phase code tuning failed!\n", + mmc_hostname(host->mmc)); + dwcmshc_disable_card_clk(host); + sdhci_writew(host, 0, VENDOR_AT_SATA_R); + sdhci_eic7700_enable_card_clk(host); + return -EIO; + } + if (!is_sdio) + phase_code =3D (code_min + code_max) / 2; + + dwcmshc_disable_card_clk(host); + sdhci_writew(host, phase_code, VENDOR_AT_SATA_R); + sdhci_eic7700_enable_card_clk(host); + + /* SDIO specific final verification */ + if (is_sdio) { + ret =3D 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 opc= ode) +{ + struct sdhci_pltfm_host *pltfm_host =3D sdhci_priv(host); + struct dwcmshc_priv *priv =3D sdhci_pltfm_priv(pltfm_host); + u32 emmc_caps =3D MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; + u16 ctrl; + u32 val; + int ret; + + dwcmshc_disable_card_clk(host); + + ctrl =3D sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl &=3D ~SDHCI_CTRL_TUNED_CLK; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + + val =3D sdhci_readl(host, priv->vendor_specific_area1 + + DWCMSHC_EMMC_ATCTRL); + val |=3D AT_CTRL_SW_TUNE_EN; + sdhci_writew(host, val, priv->vendor_specific_area1 + + DWCMSHC_EMMC_ATCTRL); + + sdhci_writew(host, 0, VENDOR_AT_SATA_R); + + sdhci_eic7700_enable_card_clk(host); + + sdhci_writew(host, 0x0, SDHCI_CMD_DATA); + + if ((host->mmc->caps2 & emmc_caps) =3D=3D emmc_caps) { + ret =3D sdhci_eic7700_delay_tuning(host, opcode); + if (ret) + return ret; + } + + ret =3D 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 =3D sdhci_priv(host); + struct dwcmshc_priv *priv =3D 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 =3D=3D MMC_TIMING_MMC_HS400 && host->clock =3D=3D 200000000) { + dwcmshc_disable_card_clk(host); + + val =3D sdhci_readl(host, priv->vendor_specific_area1 + + DWCMSHC_EMMC_ATCTRL); + val &=3D ~(LATENCY_LT_MASK << LATENCY_LT_BIT_OFFSET); + val |=3D (LATENCY_LT_3 << LATENCY_LT_MASK); + sdhci_writew(host, val, priv->vendor_specific_area1 + + DWCMSHC_EMMC_ATCTRL); + + sdhci_writeb(host, 0x23, PHY_DLL_CNFG1_R); + sdhci_writeb(host, 0x02, PHY_DLL_CNFG2_R); + sdhci_writeb(host, 0x60, PHY_DLLDL_CNFG_R); + sdhci_writeb(host, 0x00, PHY_DLL_OFFST_R); + sdhci_writew(host, 0xffff, PHY_DLLBT_CNFG_R); + + sdhci_eic7700_enable_card_clk(host); + sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); + usleep_range(100, 110); + + ret =3D 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 =3D 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 =3D MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO; + + if ((host->mmc->caps2 & sd_caps) =3D=3D 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) +{ + struct sdhci_pltfm_host *pltfm_host =3D sdhci_priv(host); + u32 emmc_caps =3D 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 =3D devm_kzalloc(dev, sizeof(struct eic7700_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->host =3D host; + dwc_priv->priv =3D priv; + + ret =3D sdhci_eic7700_register_sdclk(dwc_priv, pltfm_host->clk, dev); + if (ret) + return ret; + + ret =3D sdhci_eic7700_reset_init(dev, dwc_priv->priv); + if (ret) { + dev_err(dev, "failed to reset\n"); + return ret; + } + + ret =3D of_parse_phandle_with_fixed_args(dev->of_node, + "eswin,syscrg-csr", 1, 0, &args); + if (ret) { + dev_err(dev, "Fail to parse 'eswin,syscrg-csr' phandle (%d)\n", + ret); + return ret; + } + priv->crg_regmap =3D syscon_node_to_regmap(args.np); + if (IS_ERR(priv->crg_regmap)) { + dev_err(dev, "Failed to get regmap for 'eswin,syscrg-csr'\n"); + of_node_put(args.np); + return ret; + } + + priv->crg_core_clk =3D args.args[0]; + of_node_put(args.np); + + ret =3D 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 =3D 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 =3D args.args[0]; + hsp_pwr_ctrl =3D args.args[1]; + of_node_put(args.np); + regmap_write(hsp_regmap, hsp_int_status, + EIC7700_INT_CLK_STABLE); + regmap_write(hsp_regmap, hsp_pwr_ctrl, + EIC7700_HOST_VAL_STABLE); + + if ((host->mmc->caps2 & emmc_caps) =3D=3D emmc_caps) + dwc_priv->delay_line =3D PHY_DELAY_CODE_EMMC; + else + dwc_priv->delay_line =3D PHY_DELAY_CODE_SD; + + if (!of_property_read_u32(dev->of_node, "drive-impedance-ohm", &val)) + priv->drive_impedance =3D + eic7700_convert_drive_impedance_ohm(dev, val); + + sdhci_eic7700_dt_parse_clk_phases(dev, dwc_priv); + return 0; +} + static const struct sdhci_ops sdhci_dwcmshc_ops =3D { .set_clock =3D sdhci_set_clock, .set_bus_width =3D sdhci_set_bus_width, @@ -1169,6 +1912,18 @@ static const struct sdhci_ops sdhci_dwcmshc_sg2042_o= ps =3D { .platform_execute_tuning =3D th1520_execute_tuning, }; =20 +static const struct sdhci_ops sdhci_dwcmshc_eic7700_ops =3D { + .set_clock =3D sdhci_eic7700_set_clock, + .get_max_clock =3D sdhci_pltfm_clk_get_max_clock, + .get_timeout_clock =3D sdhci_pltfm_clk_get_max_clock, + .set_bus_width =3D sdhci_set_bus_width, + .reset =3D sdhci_eic7700_reset, + .set_uhs_signaling =3D sdhci_eic7700_set_uhs_wrapper, + .set_power =3D sdhci_set_power_and_bus_voltage, + .irq =3D dwcmshc_cqe_irq_handler, + .platform_execute_tuning =3D sdhci_eic7700_executing_tuning, +}; + static const struct dwcmshc_pltfm_data sdhci_dwcmshc_pdata =3D { .pdata =3D { .ops =3D &sdhci_dwcmshc_ops, @@ -1238,6 +1993,17 @@ static const struct dwcmshc_pltfm_data sdhci_dwcmshc= _sg2042_pdata =3D { .init =3D sg2042_init, }; =20 +static const struct dwcmshc_pltfm_data sdhci_dwcmshc_eic7700_pdata =3D { + .pdata =3D { + .ops =3D &sdhci_dwcmshc_eic7700_ops, + .quirks =3D SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, + .quirks2 =3D SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, + }, + .init =3D eic7700_init, +}; + static const struct cqhci_host_ops dwcmshc_cqhci_ops =3D { .enable =3D dwcmshc_sdhci_cqe_enable, .disable =3D sdhci_cqe_disable, @@ -1338,6 +2104,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_id= s[] =3D { .compatible =3D "sophgo,sg2042-dwcmshc", .data =3D &sdhci_dwcmshc_sg2042_pdata, }, + { + .compatible =3D "eswin,eic7700-dwcmshc", + .data =3D &sdhci_dwcmshc_eic7700_pdata, + }, {}, }; MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); --=20 2.25.1