Add support for Eswin EIC7700 SD/eMMC controller
Subsystems (3)
v5 cover Add support for Eswin EIC7700 SD/eMMC controller
From: Huan He <[email protected]>
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/[email protected]/
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/[email protected]/
Changes in v3:
- Update snps,dwcmshc-sdhci.yaml
- Delete clock-output-names, '#clock-cells' and eswin,syscrg-csr
- Update description for eswin,hsp-sp-csr
- Update drive-impedance-ohm
- Update the item of reset-names
- Update sdhci-of-dwcmshc.c
- Add descriptions for PHY registers
- Simplify clock management(remove custom clock provider, use
standard clk API)
- Replace magic numbers with GENMASK() or FIELD_PREP() macros
- Add comments explaining HSP stability assertion writes
- Adjust line wrapping to fit within 100-column
- Delete forward declarations by moving function definitions
- Rename variable is_sdio to is_sd
- Replace unclear macros with meaningful alternatives
- Link to v2: https://lore.kernel.org/all/[email protected]/
Changes in v2:
- Delete the previous separate driver and yaml binding file
- Update snps,dwcmshc-sdhci.yaml to add support for Eswin EIC7700
- Add the new compautible string: "eswin,eic7700-dwcmshc"
- Add new properties: clock-output-names, '#clock-cells', drive-impedance-ohm, eswin,hsp-sp-csr and eswin,syscrg-csr
- Add customized reset-names for EIC7700 platform
- Update sdhci-of-dwcmshc.c to add support for Eswin EIC7700
- Add a new struct eic7700_priv to hold Eswin-specific data,
including clock phases, register mappings, and drive
impedance configuration
- Implement EIC7700-specific sdhci_ops
- set_clock: support core clock configuration with phase delay
- reset: add PHY reset and configuration
- set_uhs_signaling: support HS400 DLL lock
- platform_execute_tuning: implement delay line tuning and phase
code adjustment
- Add initialization routine (eic7700_init)
- Integrate the new platform data and ops into the driver's match table
- Link to v1: https://lore.kernel.org/all/[email protected]/
Huan He (2):
dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
.../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +- drivers/mmc/host/sdhci-of-dwcmshc.c | 502 +++++++++++++++++- 2 files changed, 542 insertions(+), 17 deletions(-)
Signature · 1 line
2.25.1
PATCH v5 1/2 dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
From: Huan He <[email protected]>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in sdhci-of-dwcmshc.yaml.
--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-)
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +51 -6
@@ -30,6 +30,7 @@ properties: - sophgo,sg2002-dwcmshc - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc + - eswin,eic7700-dwcmshc reg: maxItems: 1
@@ -52,17 +53,30 @@ properties: maxItems: 5 reset-names: - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + maxItems: 5 rockchip,txclk-tapnum: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8 + eswin,hsp-sp-csr: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - 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:
Signature · 1 line
2.25.1
Rob Herring (Arm)
maintainerRe: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
Quoted 11 lines · On Sun, 19 Oct 2025 19:52:38 +0800, [email protected] wrote:
From: Huan He <[email protected]>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in
sdhci-of-dwcmshc.yaml.Signed-off-by Huan He <[email protected]>Reviewed-by Conor Dooley <[email protected]>--- .../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/[email protected]
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.
Re: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
In reply to [email protected]Quoted 43 lines · On Sun, 19 Oct 2025 at 13:52, <[email protected]> wrote:
From: Huan He <[email protected]>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in
sdhci-of-dwcmshc.yaml.Signed-off-by Huan He <[email protected]>Reviewed-by Conor Dooley <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +5
-6@@ -30,6 +30,7 @@ properties: - sophgo,sg2002-dwcmshc - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc + - eswin,eic7700-dwcmshc reg: maxItems: 1@@ -52,17 +53,30 @@ properties: maxItems: 5 reset-names: - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + maxItems: 5 rockchip,txclk-tapnum: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8 + eswin,hsp-sp-csr: + $ref: /schemas/types.yaml#/definitions/phandle-array + items:
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 74
Quoted 10 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +10
-0+ - 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.
Quoted 47 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +36
-1+ + 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: --
Quoted 2 lines
2.25.1
Kind regards
Uffe
Re: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
Quoted 41 lines · Ulf Hansson
Quoted 40 lines · On Sun, 19 Oct 2025 at 13:52, <[email protected]> wrote:
From: Huan He <[email protected]>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in
sdhci-of-dwcmshc.yaml.Signed-off-by Huan He <[email protected]>Reviewed-by Conor Dooley <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +2
-6@@ -30,6 +30,7 @@ properties: - sophgo,sg2002-dwcmshc - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc + - eswin,eic7700-dwcmshc reg: maxItems: 1@@ -52,17 +53,30 @@ properties: maxItems: 5 reset-names: - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + maxItems: 5 rockchip,txclk-tapnum: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8
Quoted 16 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 74
Quoted 13 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +13
-0+ 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.
Quoted 57 lines
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.Quoted 47 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +36
-1+ + 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: --Quoted 2 lines
2.25.1
Kind regards
Uffe
Re: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
Quoted 59 lines · Conor Dooley
Quoted 41 lines · Ulf Hansson
Quoted 40 lines · On Sun, 19 Oct 2025 at 13:52, <[email protected]> wrote:
From: Huan He <[email protected]>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in
sdhci-of-dwcmshc.yaml.Signed-off-by Huan He <[email protected]>Reviewed-by Conor Dooley <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +2
-6@@ -30,6 +30,7 @@ properties: - sophgo,sg2002-dwcmshc - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc + - eswin,eic7700-dwcmshc reg: maxItems: 1@@ -52,17 +53,30 @@ properties: maxItems: 5 reset-names: - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + maxItems: 5 rockchip,txclk-tapnum: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8Quoted 16 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 74
Quoted 13 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +13
-0+ 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.
Quoted 7 lines
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.
Quoted 56 lines
Quoted 56 lines
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.Quoted 47 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +36
-1+ + 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: --Quoted 2 lines
2.25.1
Kind regards
Uffe
Rob Herring
maintainerRe: [PATCH v5 1/2] dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
Quoted 65 lines · Conor Dooley
Quoted 64 lines · Conor Dooley
Quoted 41 lines · Ulf Hansson
Quoted 40 lines · On Sun, 19 Oct 2025 at 13:52, <[email protected]> wrote:
From: Huan He <[email protected]>
EIC7700 use Synopsys dwcmshc IP for SD/eMMC controllers. Add Eswin EIC7700 support in
sdhci-of-dwcmshc.yaml.Signed-off-by Huan He <[email protected]>Reviewed-by Conor Dooley <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +2
-6@@ -30,6 +30,7 @@ properties: - sophgo,sg2002-dwcmshc - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc + - eswin,eic7700-dwcmshc reg: maxItems: 1@@ -52,17 +53,30 @@ properties: maxItems: 5 reset-names: - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + maxItems: 5 rockchip,txclk-tapnum: description: Specify the number of delay for tx sampling. $ref: /schemas/types.yaml#/definitions/uint8Quoted 16 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 74
Quoted 13 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +13
-0+ 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.
Quoted 8 lines
Quoted 2 lines
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
PATCH v5 2/2 mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
In reply to [email protected]From: Huan He <[email protected]>
Add support for the mmc controller in the Eswin EIC7700 with the new compatible "eswin,eic7700-dwcmshc". Implement custom sdhci_ops for set_clock, reset, set_uhs_signaling, platform_execute_tuning.
--- drivers/mmc/host/sdhci-of-dwcmshc.c | 502 +++++++++++++++++++++++++++- 1 file changed, 491 insertions(+), 11 deletions(-)
drivers/mmc/host/sdhci-of-dwcmshc.c +491 -11
@@ -11,6 +11,7 @@#include <linux/arm-smccc.h> #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/dma-mapping.h> #include <linux/iopoll.h> #include <linux/kernel.h>
@@ -19,8 +20,11 @@#include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/reset.h> #include <linux/sizes.h> +#include <linux/mfd/syscon.h> +#include <linux/units.h> #include "sdhci-pltfm.h" #include "cqhci.h"
@@ -39,6 +43,7 @@#define DWCMSHC_CARD_IS_EMMC BIT(0)#define DWCMSHC_ENHANCED_STROBE BIT(8)#define DWCMSHC_EMMC_ATCTRL 0x40 +#define DWCMSHC_AT_STAT 0x44/* Tuning and auto-tuning fields in AT_CTRL_R control register */ #define AT_CTRL_AT_EN BIT(0)/* autotuning is enabled */ #define AT_CTRL_CI_SEL BIT(1)/* interval to drive center phase select */
@@ -194,6 +199,19 @@#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5)/* bits [6:5] */ #define PHY_DLLDL_CNFG_SLV_INPSEL 0x3/* clock source select for slave DL */ +/* PHY DLL offset setting register */ +#define PHY_DLL_OFFST_R (DWC_MSHC_PTR_PHY_R + 0x29) +/* DLL LBT setting register */ +#define PHY_DLLBT_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x2c) +/* DLL Status register */ +#define PHY_DLL_STATUS_R (DWC_MSHC_PTR_PHY_R + 0x2e) +#define DLL_LOCK_STS BIT(0)/* DLL is locked and ready */ +/* +* Captures the value of DLL's lock error status information. Value is valid +* only when LOCK_STS is set. +*/ +#define DLL_ERROR_STS BIT(1) +#define FLAG_IO_FIXED_1V8 BIT(0)#define BOUNDARY_OK (addr, len) \
@@ -206,6 +224,31 @@/* SMC call for BlueField-3 eMMC RST_N */ #define BLUEFIELD_SMC_SET_EMMC_RST_N 0x82000007 +/* Eswin specific Registers */ +#define EIC7700_CARD_CLK_STABLE BIT(28) +#define EIC7700_INT_BCLK_STABLE BIT(16) +#define EIC7700_INT_ACLK_STABLE BIT(8) +#define EIC7700_INT_TMCLK_STABLE BIT(0) +#define EIC7700_INT_CLK_STABLE (EIC7700_CARD_CLK_STABLE | \ + EIC7700_INT_ACLK_STABLE | \ + EIC7700_INT_BCLK_STABLE | \ + EIC7700_INT_TMCLK_STABLE) +#define EIC7700_HOST_VAL_STABLE BIT(0) + +/* strength definition */ +#define PHYCTRL_DR_33OHM 0xee +#define PHYCTRL_DR_40OHM 0xcc +#define PHYCTRL_DR_50OHM 0x88 +#define PHYCTRL_DR_66OHM 0x44 +#define PHYCTRL_DR_100OHM 0x00 + +#define MAX_PHASE_CODE 0xff +#define TUNING_RANGE_THRESHOLD 40 +#define PHY_CLK_MAX_DELAY_MASK 0x7f +#define PHY_DELAY_CODE_MAX 0x7f +#define PHY_DELAY_CODE_EMMC 0x17 +#define PHY_DELAY_CODE_SD 0x55 +enum dwcmshc_rk_type {DWCMSHC_RK3568 ,DWCMSHC_RK3588 ,
@@ -217,6 +260,11 @@ struct rk35xx_priv {u8 txclk_tapnum; }; +struct eic7700_priv { +struct reset_control *reset; +unsigned int drive_impedance; +}; +#define DWCMSHC_MAX_OTHER_CLKS 3struct dwcmshc_priv {
@@ -238,6 +286,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);
Signature · 1 line
2.25.1
Re: [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
Quoted 7 lines · On 19/10/2025 14:53, [email protected] wrote:
From: Huan He <[email protected]>
Add support for the mmc controller in the Eswin EIC7700 with the new compatible "eswin,eic7700-dwcmshc". Implement custom
sdhci_opsforset_clock, reset,set_uhs_signaling,platform_execute_tuning.Signed-off-by Huan He <[email protected]>
Noting that the dt-bindings patch still seems to have issues, for this patch, anyway:
Quoted 596 lines
--- drivers/mmc/host/sdhci-of-dwcmshc.c | 502 +++++++++++++++++++++++++++- 1 file changed, 491 insertions(+), 11 deletions(-)drivers/mmc/host/sdhci-of-dwcmshc.c +491
-11@@ -11,6 +11,7 @@#include <linux/arm-smccc.h> #include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/dma-mapping.h> #include <linux/iopoll.h> #include <linux/kernel.h> @@ -19,8 +20,11 @@#include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/reset.h> #include <linux/sizes.h> +#include <linux/mfd/syscon.h> +#include <linux/units.h> #include "sdhci-pltfm.h" #include "cqhci.h" @@ -39,6 +43,7 @@#define DWCMSHC_CARD_IS_EMMC BIT(0)#define DWCMSHC_ENHANCED_STROBE BIT(8)#define DWCMSHC_EMMC_ATCTRL 0x40 +#define DWCMSHC_AT_STAT 0x44/* Tuning and auto-tuning fields in AT_CTRL_R control register */ #define AT_CTRL_AT_EN BIT(0)/* autotuning is enabled */ #define AT_CTRL_CI_SEL BIT(1)/* interval to drive center phase select */ @@ -194,6 +199,19 @@#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5)/* bits [6:5] */ #define PHY_DLLDL_CNFG_SLV_INPSEL 0x3/* clock source select for slave DL */ +/* PHY DLL offset setting register */ +#define PHY_DLL_OFFST_R (DWC_MSHC_PTR_PHY_R + 0x29) +/* DLL LBT setting register */ +#define PHY_DLLBT_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x2c) +/* DLL Status register */ +#define PHY_DLL_STATUS_R (DWC_MSHC_PTR_PHY_R + 0x2e) +#define DLL_LOCK_STS BIT(0)/* DLL is locked and ready */ +/* +* Captures the value of DLL's lock error status information. Value is valid +* only when LOCK_STS is set. +*/ +#define DLL_ERROR_STS BIT(1) +#define FLAG_IO_FIXED_1V8 BIT(0)#define BOUNDARY_OK (addr, len) \@@ -206,6 +224,31 @@/* SMC call for BlueField-3 eMMC RST_N */ #define BLUEFIELD_SMC_SET_EMMC_RST_N 0x82000007 +/* Eswin specific Registers */ +#define EIC7700_CARD_CLK_STABLE BIT(28) +#define EIC7700_INT_BCLK_STABLE BIT(16) +#define EIC7700_INT_ACLK_STABLE BIT(8) +#define EIC7700_INT_TMCLK_STABLE BIT(0) +#define EIC7700_INT_CLK_STABLE (EIC7700_CARD_CLK_STABLE | \ + EIC7700_INT_ACLK_STABLE | \ + EIC7700_INT_BCLK_STABLE | \ + EIC7700_INT_TMCLK_STABLE) +#define EIC7700_HOST_VAL_STABLE BIT(0) + +/* strength definition */ +#define PHYCTRL_DR_33OHM 0xee +#define PHYCTRL_DR_40OHM 0xcc +#define PHYCTRL_DR_50OHM 0x88 +#define PHYCTRL_DR_66OHM 0x44 +#define PHYCTRL_DR_100OHM 0x00 + +#define MAX_PHASE_CODE 0xff +#define TUNING_RANGE_THRESHOLD 40 +#define PHY_CLK_MAX_DELAY_MASK 0x7f +#define PHY_DELAY_CODE_MAX 0x7f +#define PHY_DELAY_CODE_EMMC 0x17 +#define PHY_DELAY_CODE_SD 0x55 +enum dwcmshc_rk_type {DWCMSHC_RK3568 ,DWCMSHC_RK3588 ,@@ -217,6 +260,11 @@ struct rk35xx_priv {u8 txclk_tapnum; }; +struct eic7700_priv { +struct reset_control *reset; +unsigned int drive_impedance; +}; +#define DWCMSHC_MAX_OTHER_CLKS 3struct dwcmshc_priv {@@ -238,6 +286,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);
Re: Re: [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
Hi Adrian,
Thank you very much for your Acked-by and the review!
Quoted 7 lines · On 19/10/2025 14:53, [email protected] wrote:
Quoted 6 lines
From: Huan He <[email protected]>
Add support for the mmc controller in the Eswin EIC7700 with the new compatible "eswin,eic7700-dwcmshc". Implement custom
sdhci_opsforset_clock, reset,set_uhs_signaling,platform_execute_tuning.
Quoted 6 lines
Quoted 1 line
Signed-off-by Huan He <[email protected]>Noting that the dt-bindings patch still seems to have issues, for this patch, anyway:
Acked-by Adrian Hunter <[email protected]>
I recieved an dt_binding_check error report:
https://lore.kernel.org/all/[email protected]/
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
Adrian Hunter
maintainerRe: [PATCH v5 2/2] mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
Quoted 21 lines · 何欢
Hi Adrian,
Thank you very much for your Acked-by and the review!
Quoted 7 lines · On 19/10/2025 14:53, [email protected] wrote:
Quoted 6 lines
From: Huan He <[email protected]>
Add support for the mmc controller in the Eswin EIC7700 with the new compatible "eswin,eic7700-dwcmshc". Implement custom
sdhci_opsforset_clock, reset,set_uhs_signaling,platform_execute_tuning.Quoted 6 lines
Quoted 1 line
Signed-off-by Huan He <[email protected]>Noting that the dt-bindings patch still seems to have issues, for this patch, anyway:
Acked-by Adrian Hunter <[email protected]>I recieved an
dt_binding_checkerror report:
https://lore.kernel.org/all/[email protected]/
Quoted 7 lines
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=888bd0eca93cWe'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.
Quoted 68 lines
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
- Updatesdhci-of-dwcmshc.c
- Remove inappropriate Reported-by and Closes tags, as the fixes are part of this patch
- Fix error code return ineic7700_init()whensyscon_node_to_regmap()fails (returnPTR_ERR(hsp_regmap))
- Remove unnecessary clock disable/enable operations when changing clock rates
- Remove unnecessary parentheses around ~PHY_CNFG_RSTN_DEASSERT insdhci_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/[email protected]/Changes in v4:
- Updatesdhci-of-dwcmshc.c
- Address the compile error from kernel test robot
- Remove duplicate implementation ofdwcmshc_enable_card_clk()
- Add missingdwcmshc_disable_card_clk()function implementation
- Link to v3: https://lore.kernel.org/all/[email protected]/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
- Updatesdhci-of-dwcmshc.c
- Add descriptions for PHY registers
- Simplify clock management(remove custom clock provider, use
standard clk API)
- Replace magic numbers withGENMASK()orFIELD_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 variableis_sdiotois_sd
- Replace unclear macros with meaningful alternatives
- Link to v2: https://lore.kernel.org/all/[email protected]/Changes in v2:
- Delete the previous separate driver and yaml binding file
- Update snps,dwcmshc-sdhci.yaml to add support for Eswin EIC7700
- Add the new compautible string: "eswin,eic7700-dwcmshc"
- Add new properties: clock-output-names, '#clock-cells', drive-impedance-ohm, eswin,hsp-sp-csr and eswin,syscrg-csr
- Add customized reset-names for EIC7700 platform
- Updatesdhci-of-dwcmshc.cto add support for Eswin EIC7700
- Add a new structeic7700_privto hold Eswin-specific data,
including clock phases, register mappings, and drive
impedance configuration
- Implement EIC7700-specificsdhci_ops
-set_clock: support core clock configuration with phase delay
- reset: add PHY reset and configuration
-set_uhs_signaling: support HS400 DLL lock
-platform_execute_tuning: implement delay line tuning and phase
code adjustment
- Add initialization routine (eic7700_init)
- Integrate the new platform data and ops into the driver's match table
- Link to v1: https://lore.kernel.org/all/[email protected]/
Quoted 8 lines
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(-)
Hi Ulf, Rob, all,
Thank you for the discussion and feedback.
Regarding the dt_binding_check error previously reported for the eswin,hsp-sp-csr property in the eswin,eic7700-eth.yaml binding, we have submitted a fix patch that has now been applied:
https://git.kernel.org/netdev/net-next/c/0567c84d683d
Could you please review the mmc-related changes? Thanks in advance for your time and consideration.
Best regards,
Huan He
Quoted 75 lines · On Sun, 19 Oct 2025 at 13:51, <[email protected]> wrote:
From: Huan He <[email protected]>
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
- Updatesdhci-of-dwcmshc.c
- Remove inappropriate Reported-by and Closes tags, as the fixes are part of this patch
- Fix error code return ineic7700_init()whensyscon_node_to_regmap()fails (returnPTR_ERR(hsp_regmap))
- Remove unnecessary clock disable/enable operations when changing clock rates
- Remove unnecessary parentheses around ~PHY_CNFG_RSTN_DEASSERT insdhci_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/[email protected]/Changes in v4:
- Updatesdhci-of-dwcmshc.c
- Address the compile error from kernel test robot
- Remove duplicate implementation ofdwcmshc_enable_card_clk()
- Add missingdwcmshc_disable_card_clk()function implementation
- Link to v3: https://lore.kernel.org/all/[email protected]/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
- Updatesdhci-of-dwcmshc.c
- Add descriptions for PHY registers
- Simplify clock management(remove custom clock provider, use
standard clk API)
- Replace magic numbers withGENMASK()orFIELD_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 variableis_sdiotois_sd
- Replace unclear macros with meaningful alternatives
- Link to v2: https://lore.kernel.org/all/[email protected]/Changes in v2:
- Delete the previous separate driver and yaml binding file
- Update snps,dwcmshc-sdhci.yaml to add support for Eswin EIC7700
- Add the new compautible string: "eswin,eic7700-dwcmshc"
- Add new properties: clock-output-names, '#clock-cells', drive-impedance-ohm, eswin,hsp-sp-csr and eswin,syscrg-csr
- Add customized reset-names for EIC7700 platform
- Updatesdhci-of-dwcmshc.cto add support for Eswin EIC7700
- Add a new structeic7700_privto hold Eswin-specific data,
including clock phases, register mappings, and drive
impedance configuration
- Implement EIC7700-specificsdhci_ops
-set_clock: support core clock configuration with phase delay
- reset: add PHY reset and configuration
-set_uhs_signaling: support HS400 DLL lock
-platform_execute_tuning: implement delay line tuning and phase
code adjustment
- Add initialization routine (eic7700_init)
- Integrate the new platform data and ops into the driver's match table
- Link to v1: https://lore.kernel.org/all/[email protected]/Huan He (2):
dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700
mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700
Quoted 7 lines
.../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
The v5 series applied for next, thanks!
Kind regards
Uffe