mmc: sdhci-of-dwcmshc: support Sophgo SG2042
Subsystems (5)
cover mmc: sdhci-of-dwcmshc: support Sophgo SG2042
From: Chen Wang <[email protected]>
Add support for the mmc controller for Sophgo SG2042. Adding corresponding new compatible strings, and implement custom sdhci_ops.
This patchset is based on v6.9-rc1 and depends on following pathsets:
- [PATCH 0/1] mmc: sdhci-of-dwcmshc: enhance framework [1]
- [PATCH v14 0/5] riscv: sophgo: add clock support for sg2042 [2]
- [PATCH v1] mmc: sdhci-of-dwcmshc: th1520: Increase tuning loop count to 128 [3]
---
Chen Wang (3):
dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
mmc: sdhci-of-dwcmshc: Add support for Sophgo SG2042
riscv: dts: add mmc controllers for Sophgo SG2042 SoC
.../bindings/mmc/snps,dwcmshc-sdhci.yaml | 67 +++++-- .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 15 ++ arch/riscv/boot/dts/sophgo/sg2042.dtsi | 32 ++++ drivers/mmc/host/sdhci-of-dwcmshc.c | 173 +++++++++++++++++- 4 files changed, 264 insertions(+), 23 deletions(-)
Signature · 1 line
2.25.1
PATCH 1/3 dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
From: Chen Wang <[email protected]>
SG2042 use Synopsys dwcnshc IP for SD/eMMC controllers.
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks in DWC_mshc) and blck(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".
- 100K_EMMC/100K_SD for cqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.
- EMMC_100M/SD_100M for cclk(Card clocks in DWC_mshc), add new "card".
Adding some examples.
--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-)
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +51 -16
@@ -21,6 +21,7 @@ properties: - snps,dwcmshc-sdhci - sophgo,cv1800b-dwcmshc - sophgo,sg2002-dwcmshc + - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc reg:
@@ -30,23 +31,36 @@ properties: maxItems: 1 clocks: - minItems: 1 - items: - - description: core clock - - description: bus clock for optional - - description: axi clock for rockchip specified - - description: block clock for rockchip specified - - description: timer clock for rockchip specified - + anyOf: + - minItems: 1 + items: + - description: core clock + - description: bus clock for optional + - description: axi clock for rockchip specified + - description: block clock for rockchip specified + - description: timer clock for rockchip specified + + - minItems: 1 + items: + - description: core clock + - description: timer clock + - description: card clock clock-names: - minItems: 1 - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + anyOf: + - minItems: 1 + items: + - const: core + - const: bus + - const: axi + - const: block + - const: timer + + - minItems: 1 + items: + - const: core + - const: timer + - const: card resets: maxItems: 5
@@ -96,5 +110,26 @@ examples: #address-cells = <1>; #size-cells = <0>; }; - + - | + mmc@bb0000 { + compatible = "snps,dwcmshc-sdhci"; + reg = <0xbb000 0x1000>; + interrupts = <0 25 0x4>; + clocks = <&cru 17>; + clock-names = "core"; + bus-width = <8>; + #address-cells = <1>; + #size-cells = <0>; + }; + - | + mmc@cc0000 { + compatible = "snps,dwcmshc-sdhci"; + reg = <0xcc000 0x1000>; + interrupts = <0 25 0x4>; + clocks = <&cru 17>, <&cru 18>, <&cru 19>; + clock-names = "core", "timer", "card"; + bus-width = <8>; + #address-cells = <1>; + #size-cells = <0>; + }; ...
Signature · 1 line
2.25.1
Re: [PATCH 1/3] dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
Quoted 43 lines · Chen Wang
From: Chen Wang <[email protected]>
SG2042 use Synopsys dwcnshc IP for SD/eMMC controllers.
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks inDWC_mshc) andblck(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".
- 100K_EMMC/100K_SD forcqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.
- EMMC_100M/SD_100M forcclk(Card clocks in DWC_mshc), add new "card".Adding some examples.
Signed-off-by Chen Wang <[email protected]>--- .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-)Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +1
-8@@ -21,6 +21,7 @@ properties: - snps,dwcmshc-sdhci - sophgo,cv1800b-dwcmshc - sophgo,sg2002-dwcmshc + - sophgo,sg2042-dwcmshc - thead,th1520-dwcmshc reg:@@ -30,23 +31,36 @@ properties: maxItems: 1 clocks: - minItems: 1 - items: - - description: core clock - - description: bus clock for optional - - description: axi clock for rockchip specified - - description: block clock for rockchip specified - - description: timer clock for rockchip specified -
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 43
Quoted 10 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +10
-0+ anyOf: + - minItems: 1 + items: + - description: core clock + - description: bus clock for optional + - description: axi clock for rockchip specified + - description: block clock for rockchip specified + - description: timer clock for rockchip specified + + - minItems: 1
I don't think this minItems is needed, this is for one device which has all 3, no?
I also think this combination should only be permitted for the sg2042, since it is not valid for the existing devices.
Cheers,
Conor.
Quoted 61 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +40
-8+ items: + - description: core clock + - description: timer clock + - description: card clock clock-names: - minItems: 1 - items: - - const: core - - const: bus - - const: axi - - const: block - - const: timer + anyOf: + - minItems: 1 + items: + - const: core + - const: bus + - const: axi + - const: block + - const: timer + + - minItems: 1 + items: + - const: core + - const: timer + - const: card resets: maxItems: 5@@ -96,5 +110,26 @@ examples: #address-cells = <1>; #size-cells = <0>; }; - + - | + mmc@bb0000 { + compatible = "snps,dwcmshc-sdhci"; + reg = <0xbb000 0x1000>; + interrupts = <0 25 0x4>; + clocks = <&cru 17>; + clock-names = "core"; + bus-width = <8>; + #address-cells = <1>; + #size-cells = <0>; + }; + - | + mmc@cc0000 { + compatible = "snps,dwcmshc-sdhci"; + reg = <0xcc000 0x1000>; + interrupts = <0 25 0x4>; + clocks = <&cru 17>, <&cru 18>, <&cru 19>; + clock-names = "core", "timer", "card"; + bus-width = <8>; + #address-cells = <1>; + #size-cells = <0>; + };Signature · 1 line
2.25.1
Re: [PATCH 1/3] dt-bindings: mmc: sdhci-of-dwcmhsc: Add Sophgo SG2042 support
Quoted 1 line · Conor Dooley
On Tue, Apr 16, 2024 at 05:50:37PM +0800, Chen Wang wrote:
[......]
Quoted 10 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml properties: · line 43
Quoted 10 lines
Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +10
-0+ anyOf: + - minItems: 1 + items: + - description: core clock + - description: bus clock for optional + - description: axi clock for rockchip specified + - description: block clock for rockchip specified + - description: timer clock for rockchip specified + + - minItems: 1
Quoted 2 lines
I don't think this minItems is needed, this is for one device which has all 3, no?
Yes, SG2042 requires all the 3 clocks presented, I will remove this minItems.
Quoted 2 lines
I also think this combination should only be permitted for the sg2042, since it is not valid for the existing devices.
Yes, I will add condition to allow this combination only for sg2042, thanks.
Quoted 2 lines
Cheers,
Conor.
[......]
PATCH 2/3 mmc: sdhci-of-dwcmshc: Add support for Sophgo SG2042
In reply to Chen WangFrom: Chen Wang <[email protected]>
Add support for the mmc controller of Sophgo SG2042.
SG2042 uses Synopsys PHY the same as TH1520 so we reuse the tuning logic from TH1520. Besides this, this patch implement some SG2042 specific work, such as clocks and reset ops.
--- drivers/mmc/host/sdhci-of-dwcmshc.c | 173 ++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 7 deletions(-)
drivers/mmc/host/sdhci-of-dwcmshc.c +166 -7
@@ -106,12 +106,13 @@#define DWC_MSHC_PTR_PHY_R 0x300/* PHY general configuration */ -#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) -#define PHY_CNFG_RSTN_DEASSERT 0x1/* Deassert PHY reset */ -#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16)/* bits [19:16] */ -#define PHY_CNFG_PAD_SP 0x0c/* PMOS TX drive strength */ -#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20)/* bits [23:20] */ -#define PHY_CNFG_PAD_SN 0x0c/* NMOS TX drive strength */ +#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) +#define PHY_CNFG_RSTN_DEASSERT 0x1/* Deassert PHY reset */ +#define PHY_CNFG_PHY_PWRGOOD_MASK BIT_MASK(1)/* bit [1] */ +#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16)/* bits [19:16] */ +#define PHY_CNFG_PAD_SP 0x0c/* PMOS TX drive strength */ +#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20)/* bits [23:20] */ +#define PHY_CNFG_PAD_SN 0x0c/* NMOS TX drive strength */ /* PHY command/response pad settings */ #define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04)
@@ -143,7 +144,8 @@/* PHY CLK delay line settings */ #define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d) -#define PHY_SDCLKDL_CNFG_UPDATE BIT(4)/* set before writing to SDCLKDL_DC */ +#define PHY_SDCLKDL_CNFG_EXTDLY_EN BIT(0) +#define PHY_SDCLKDL_CNFG_UPDATE BIT(4)/* set before writing to SDCLKDL_DC */ /* PHY CLK delay line delay code */ #define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e)
@@ -151,6 +153,9 @@#define PHY_SDCLKDL_DC_DEFAULT 0x32/* default delay code */ #define PHY_SDCLKDL_DC_HS400 0x18/* delay code for HS400 mode */ +#define PHY_SMPLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x20) +#define PHY_SMPLDL_CNFG_BYPASS_EN BIT(1) +/* PHY drift_cclk_rx delay line configuration setting */ #define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21)#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2)/* bits [3:2] */
@@ -194,6 +199,11 @@ struct rk35xx_priv {u8 txclk_tapnum; }; +#define SG2042_MAX_CLKS 2 +struct sg2042_priv { +struct clk_bulk_data clks[SG2042_MAX_CLKS ]; +}; +struct dwcmshc_priv {struct clk *bus_clk;int vendor_specific_area1;/* P_VENDOR_SPECIFIC_AREA reg */
@@ -690,6 +700,76 @@ static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask)sdhci_writel (host, val, priv->vendor_specific_area1 +CV18XX_SDHCI_PHY_TX_RX_DLY ); } +static inline void sg2042_sdhci_phy_init (struct sdhci_host *host) +{ +u32 val; + +/* Asset phy reset & set tx drive strength */ + val =sdhci_readl (host,PHY_CNFG_R ); + val &= ~PHY_CNFG_RSTN_DEASSERT ; + val |=FIELD_PREP (PHY_CNFG_PHY_PWRGOOD_MASK ,1 ); + val |=FIELD_PREP (PHY_CNFG_PAD_SP_MASK ,9 ); + val |=FIELD_PREP (PHY_CNFG_PAD_SN_MASK ,8 ); +sdhci_writel (host, val,PHY_CNFG_R ); + +/* Configure phy pads */ + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_WEAKPULL_MASK ,PHY_PAD_WEAKPULL_PULLUP ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,3 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,2 ); +sdhci_writew (host, val,PHY_CMDPAD_CNFG_R ); +sdhci_writew (host, val,PHY_DATAPAD_CNFG_R ); +sdhci_writew (host, val,PHY_RSTNPAD_CNFG_R ); + + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,3 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,2 ); +sdhci_writew (host, val,PHY_CLKPAD_CNFG_R ); + + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_WEAKPULL_MASK ,PHY_PAD_WEAKPULL_PULLDOWN ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,3 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,2 ); +sdhci_writew (host, val,PHY_STBPAD_CNFG_R ); + +/* Configure delay line */ +/* Enable fixed delay */ +sdhci_writeb (host,PHY_SDCLKDL_CNFG_EXTDLY_EN ,PHY_SDCLKDL_CNFG_R ); +/* +* Set delay line. +* Its recommended that bit UPDATE_DC[4] is 1 when SDCLKDL_DC is being written. +* Ensure UPDATE_DC[4] is '0' when not updating code. +*/ + val =sdhci_readb (host,PHY_SDCLKDL_CNFG_R ); + val |=PHY_SDCLKDL_CNFG_UPDATE ; +sdhci_writeb (host, val,PHY_SDCLKDL_CNFG_R ); +/* Add 10 * 70ps = 0.7ns for output delay */ +sdhci_writeb (host,10 ,PHY_SDCLKDL_DC_R ); + val =sdhci_readb (host,PHY_SDCLKDL_CNFG_R ); + val &= ~(PHY_SDCLKDL_CNFG_UPDATE ); +sdhci_writeb (host, val,PHY_SDCLKDL_CNFG_R ); + +/* Set SMPLDL_CNFG, Bypass */ +sdhci_writeb (host,PHY_SMPLDL_CNFG_BYPASS_EN ,PHY_SMPLDL_CNFG_R ); + +/* Set ATDL_CNFG, tuning clk not use for init */ + val =FIELD_PREP (PHY_ATDL_CNFG_INPSEL_MASK ,2 ); +sdhci_writeb (host, val,PHY_ATDL_CNFG_R ); + +/* Deasset phy reset */ + val =sdhci_readl (host,PHY_CNFG_R ); + val |=PHY_CNFG_RSTN_DEASSERT ; +sdhci_writel (host, val,PHY_CNFG_R ); +} + +static void sg2042_sdhci_reset (struct sdhci_host *host,u8 mask) +{ +sdhci_reset (host, mask); + +if (mask &SDHCI_RESET_ALL ) +sg2042_sdhci_phy_init (host); +} +static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width,
@@ -728,6 +808,16 @@ static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { .adma_write_desc = dwcmshc_adma_write_desc, }; +static const struct sdhci_ops sdhci_dwcmshc_sg2042_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, + .platform_execute_tuning = th1520_execute_tuning, + .reset = sg2042_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, +}; +static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { .ops = &sdhci_dwcmshc_ops, .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
@@ -763,6 +853,13 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, }; +static const struct sdhci_pltfm_data sdhci_dwcmshc_sg2042_pdata = { + .ops = &sdhci_dwcmshc_sg2042_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +SDHCI_QUIRK_INVERTED_WRITE_PROTECT , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , +}; +static void dwcmshc_rk35xx_postinit (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) {/*
@@ -882,6 +979,58 @@ static int dwcmshc_th1520_init(struct device *dev,return 0 ; } +static int dwcmshc_sg2042_clks_enable (struct dwcmshc_priv *dwc_priv) +{ +int ret =0 ; +struct sg2042_priv *soc = dwc_priv->priv; + +if (soc) + ret =clk_bulk_prepare_enable (SG2042_MAX_CLKS , soc->clks); +return ret; +} + +static void dwcmshc_sg2042_clks_disable (struct dwcmshc_priv *dwc_priv) +{ +struct sg2042_priv *soc = dwc_priv->priv; + +if (soc) +clk_bulk_disable_unprepare (SG2042_MAX_CLKS , + soc->clks); +} + +static int dwcmshc_sg2042_init (struct device *dev, +struct sdhci_host *host, +struct dwcmshc_priv *dwc_priv) +{ +int err; +struct sg2042_priv *soc =NULL ; + + soc =devm_kzalloc (dev,sizeof (struct sg2042_priv ),GFP_KERNEL ); +if (!soc) +return -ENOMEM ; + + soc->clks[0 ].id ="card" ; + soc->clks[1 ].id ="timer" ; + err =devm_clk_bulk_get_optional (mmc_dev (host->mmc),SG2042_MAX_CLKS , + soc->clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to get clocks %d\n" , err); +return err; + } + + err =clk_bulk_prepare_enable (SG2042_MAX_CLKS , soc->clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to enable clocks %d\n" , err); +return err; + } + + dwc_priv->priv = soc; + dwc_priv->soc_clks_enable = dwcmshc_sg2042_clks_enable; + dwc_priv->soc_clks_disable = dwcmshc_sg2042_clks_disable; + +return 0 ; +} +static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { { .compatible ="rockchip,rk3588-dwcmshc" ,
@@ -907,6 +1056,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .compatible = "thead,th1520-dwcmshc", .data = &sdhci_dwcmshc_th1520_pdata, }, + { + .compatible = "sophgo,sg2042-dwcmshc", + .data = &sdhci_dwcmshc_sg2042_pdata, + }, {}, };MODULE_DEVICE_TABLE (of, sdhci_dwcmshc_dt_ids);
@@ -994,6 +1147,12 @@ static int dwcmshc_probe(struct platform_device *pdev) goto err_clk; } +if (pltfm_data == &sdhci_dwcmshc_sg2042_pdata) { + err =dwcmshc_sg2042_init (dev, host, priv); +if (err) + goto err_clk; + } +#ifdef CONFIG_ACPI if (pltfm_data == &sdhci_dwcmshc_bf3_pdata)sdhci_enable_v4_mode (host);
Signature · 1 line
2.25.1
Re: [PATCH 2/3] mmc: sdhci-of-dwcmshc: Add support for Sophgo SG2042
Quoted 58 lines · Chen Wang
From: Chen Wang <[email protected]>
Add support for the mmc controller of Sophgo SG2042.
SG2042 uses Synopsys PHY the same as TH1520 so we reuse the tuning logic from TH1520. Besides this, this patch implement some SG2042 specific work, such as clocks and reset ops.
Signed-off-by Chen Wang <[email protected]>--- drivers/mmc/host/sdhci-of-dwcmshc.c | 173 ++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 7 deletions(-)drivers/mmc/host/sdhci-of-dwcmshc.c +12
-7@@ -106,12 +106,13 @@#define DWC_MSHC_PTR_PHY_R 0x300/* PHY general configuration */ -#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) -#define PHY_CNFG_RSTN_DEASSERT 0x1/* Deassert PHY reset */ -#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16)/* bits [19:16] */ -#define PHY_CNFG_PAD_SP 0x0c/* PMOS TX drive strength */ -#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20)/* bits [23:20] */ -#define PHY_CNFG_PAD_SN 0x0c/* NMOS TX drive strength */ +#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) +#define PHY_CNFG_RSTN_DEASSERT 0x1/* Deassert PHY reset */ +#define PHY_CNFG_PHY_PWRGOOD_MASK BIT_MASK(1)/* bit [1] */ +#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16)/* bits [19:16] */ +#define PHY_CNFG_PAD_SP 0x0c/* PMOS TX drive strength */ +#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20)/* bits [23:20] */ +#define PHY_CNFG_PAD_SN 0x0c/* NMOS TX drive strength */ /* PHY command/response pad settings */ #define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04)@@ -143,7 +144,8 @@/* PHY CLK delay line settings */ #define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d) -#define PHY_SDCLKDL_CNFG_UPDATE BIT(4)/* set before writing to SDCLKDL_DC */ +#define PHY_SDCLKDL_CNFG_EXTDLY_EN BIT(0) +#define PHY_SDCLKDL_CNFG_UPDATE BIT(4)/* set before writing to SDCLKDL_DC */ /* PHY CLK delay line delay code */ #define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e)@@ -151,6 +153,9 @@#define PHY_SDCLKDL_DC_DEFAULT 0x32/* default delay code */ #define PHY_SDCLKDL_DC_HS400 0x18/* delay code for HS400 mode */ +#define PHY_SMPLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x20) +#define PHY_SMPLDL_CNFG_BYPASS_EN BIT(1) +/* PHY drift_cclk_rx delay line configuration setting */ #define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21)#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2)/* bits [3:2] */
drivers/mmc/host/sdhci-of-dwcmshc.c struct rk35xx_priv { · line 202
Quoted 4 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +1
-0@@ -194,6 +199,11 @@ struct rk35xx_priv {u8 txclk_tapnum; }; +#define SG2042_MAX_CLKS 2
I don't think "bulk" is suitable here for max 2 clks, no?
drivers/mmc/host/sdhci-of-dwcmshc.c struct rk35xx_priv { · line 204
Quoted 2 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +2
-0+struct sg2042_priv { +struct clk_bulk_data clks[SG2042_MAX_CLKS ];
useless either
Quoted 53 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +46
-0+}; +struct dwcmshc_priv {struct clk *bus_clk;int vendor_specific_area1;/* P_VENDOR_SPECIFIC_AREA reg */ @@ -690,6 +700,76 @@ static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask)sdhci_writel (host, val, priv->vendor_specific_area1 +CV18XX_SDHCI_PHY_TX_RX_DLY ); } +static inline void sg2042_sdhci_phy_init (struct sdhci_host *host) +{ +u32 val; + +/* Asset phy reset & set tx drive strength */ + val =sdhci_readl (host,PHY_CNFG_R ); + val &= ~PHY_CNFG_RSTN_DEASSERT ; + val |=FIELD_PREP (PHY_CNFG_PHY_PWRGOOD_MASK ,1 ); + val |=FIELD_PREP (PHY_CNFG_PAD_SP_MASK ,9 ); + val |=FIELD_PREP (PHY_CNFG_PAD_SN_MASK ,8 ); +sdhci_writel (host, val,PHY_CNFG_R ); + +/* Configure phy pads */ + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_WEAKPULL_MASK ,PHY_PAD_WEAKPULL_PULLUP ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,3 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,2 ); +sdhci_writew (host, val,PHY_CMDPAD_CNFG_R ); +sdhci_writew (host, val,PHY_DATAPAD_CNFG_R ); +sdhci_writew (host, val,PHY_RSTNPAD_CNFG_R ); + + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,3 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,2 ); +sdhci_writew (host, val,PHY_CLKPAD_CNFG_R ); + + val =PHY_PAD_RXSEL_3V3 ; + val |=FIELD_PREP (PHY_PAD_WEAKPULL_MASK ,PHY_PAD_WEAKPULL_PULLDOWN ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_P_MASK ,3 ); + val |=FIELD_PREP (PHY_PAD_TXSLEW_CTRL_N_MASK ,2 ); +sdhci_writew (host, val,PHY_STBPAD_CNFG_R ); + +/* Configure delay line */ +/* Enable fixed delay */ +sdhci_writeb (host,PHY_SDCLKDL_CNFG_EXTDLY_EN ,PHY_SDCLKDL_CNFG_R ); +/* +* Set delay line. +* Its recommended that bit UPDATE_DC[4] is 1 when SDCLKDL_DC is being written. +* Ensure UPDATE_DC[4] is '0' when not updating code. +*/ + val =sdhci_readb (host,PHY_SDCLKDL_CNFG_R ); + val |=PHY_SDCLKDL_CNFG_UPDATE ; +sdhci_writeb (host, val,PHY_SDCLKDL_CNFG_R ); +/* Add 10 * 70ps = 0.7ns for output delay */
drivers/mmc/host/sdhci-of-dwcmshc.c static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask) · line 756
Quoted 10 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +10
-0+sdhci_writeb (host,10 ,PHY_SDCLKDL_DC_R ); + val =sdhci_readb (host,PHY_SDCLKDL_CNFG_R ); + val &= ~(PHY_SDCLKDL_CNFG_UPDATE ); +sdhci_writeb (host, val,PHY_SDCLKDL_CNFG_R ); + +/* Set SMPLDL_CNFG, Bypass */ +sdhci_writeb (host,PHY_SMPLDL_CNFG_BYPASS_EN ,PHY_SMPLDL_CNFG_R ); + +/* Set ATDL_CNFG, tuning clk not use for init */ + val =FIELD_PREP (PHY_ATDL_CNFG_INPSEL_MASK ,2 );
magic "2" needs a meaningful macro definition.
Quoted 37 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +26
-0+sdhci_writeb (host, val,PHY_ATDL_CNFG_R ); + +/* Deasset phy reset */ + val =sdhci_readl (host,PHY_CNFG_R ); + val |=PHY_CNFG_RSTN_DEASSERT ; +sdhci_writel (host, val,PHY_CNFG_R ); +} + +static void sg2042_sdhci_reset (struct sdhci_host *host,u8 mask) +{ +sdhci_reset (host, mask); + +if (mask &SDHCI_RESET_ALL ) +sg2042_sdhci_phy_init (host); +} +static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width,@@ -728,6 +808,16 @@ static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { .adma_write_desc = dwcmshc_adma_write_desc, }; +static const struct sdhci_ops sdhci_dwcmshc_sg2042_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = dwcmshc_get_max_clock, + .platform_execute_tuning = th1520_execute_tuning, + .reset = sg2042_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, +}; +static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { .ops = &sdhci_dwcmshc_ops, .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
drivers/mmc/host/sdhci-of-dwcmshc.c static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { · line 859
Quoted 7 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +4
-0@@ -763,6 +853,13 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, }; +static const struct sdhci_pltfm_data sdhci_dwcmshc_sg2042_pdata = { + .ops = &sdhci_dwcmshc_sg2042_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +SDHCI_QUIRK_INVERTED_WRITE_PROTECT ,
is "wp-inverted" property better?
Quoted 32 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +25
-0+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +}; +static void dwcmshc_rk35xx_postinit (struct sdhci_host *host,struct dwcmshc_priv *dwc_priv) {/* @@ -882,6 +979,58 @@ static int dwcmshc_th1520_init(struct device *dev,return 0 ; } +static int dwcmshc_sg2042_clks_enable (struct dwcmshc_priv *dwc_priv) +{ +int ret =0 ; +struct sg2042_priv *soc = dwc_priv->priv; + +if (soc) + ret =clk_bulk_prepare_enable (SG2042_MAX_CLKS , soc->clks); +return ret; +} + +static void dwcmshc_sg2042_clks_disable (struct dwcmshc_priv *dwc_priv) +{ +struct sg2042_priv *soc = dwc_priv->priv; + +if (soc) +clk_bulk_disable_unprepare (SG2042_MAX_CLKS , + soc->clks); +} + +static int dwcmshc_sg2042_init (struct device *dev, +struct sdhci_host *host, +struct dwcmshc_priv *dwc_priv)
drivers/mmc/host/sdhci-of-dwcmshc.c static int dwcmshc_th1520_init(struct device *dev, · line 1013
Quoted 10 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +10
-0+{ +int err; +struct sg2042_priv *soc =NULL ; + + soc =devm_kzalloc (dev,sizeof (struct sg2042_priv ),GFP_KERNEL ); +if (!soc) +return -ENOMEM ; + + soc->clks[0 ].id ="card" ; + soc->clks[1 ].id ="timer" ;
Interesting, only "card" and "timer", so which clk is for clk input of the ip?
Quoted 50 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +30
-0+ err =devm_clk_bulk_get_optional (mmc_dev (host->mmc),SG2042_MAX_CLKS , + soc->clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to get clocks %d\n" , err); +return err; + } + + err =clk_bulk_prepare_enable (SG2042_MAX_CLKS , soc->clks); +if (err) { +dev_err (mmc_dev (host->mmc),"failed to enable clocks %d\n" , err); +return err; + } + + dwc_priv->priv = soc; + dwc_priv->soc_clks_enable = dwcmshc_sg2042_clks_enable; + dwc_priv->soc_clks_disable = dwcmshc_sg2042_clks_disable; + +return 0 ; +} +static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { { .compatible ="rockchip,rk3588-dwcmshc" ,@@ -907,6 +1056,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .compatible = "thead,th1520-dwcmshc", .data = &sdhci_dwcmshc_th1520_pdata, }, + { + .compatible = "sophgo,sg2042-dwcmshc", + .data = &sdhci_dwcmshc_sg2042_pdata, + }, {}, };MODULE_DEVICE_TABLE (of, sdhci_dwcmshc_dt_ids);@@ -994,6 +1147,12 @@ static int dwcmshc_probe(struct platform_device *pdev) goto err_clk; } +if (pltfm_data == &sdhci_dwcmshc_sg2042_pdata) { + err =dwcmshc_sg2042_init (dev, host, priv); +if (err) + goto err_clk; + } +#ifdef CONFIG_ACPI if (pltfm_data == &sdhci_dwcmshc_bf3_pdata)sdhci_enable_v4_mode (host);Signature · 1 line
2.25.1
Re: [PATCH 2/3] mmc: sdhci-of-dwcmshc: Add support for Sophgo SG2042
Quoted 1 line · Jisheng Zhang
On Tue, Apr 16, 2024 at 05:50:57PM +0800, Chen Wang wrote:
[......]
Quoted 3 lines
Quoted 2 lines
+#define
SG2042_MAX_CLKS2I don't think "bulk" is suitable here for max 2 clks, no?
Without "bulk", I have to prepare/disable two times for each of clocks and handle the exception if first one failed etc. I learn this from rockchip, it has 3. Why you think it is not suitable, please advise me, thanks.
Quoted 3 lines
drivers/mmc/host/sdhci-of-dwcmshc.c struct rk35xx_priv { · line 204
Quoted 2 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +2
-0+struct sg2042_priv { +struct clk_bulk_data clks[SG2042_MAX_CLKS ];useless either
Sorry, what's this mean?
[......]
Quoted 4 lines
drivers/mmc/host/sdhci-of-dwcmshc.c static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask) · line 756
Quoted 3 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +3
-0+ +/* Set ATDL_CNFG, tuning clk not use for init */ + val =FIELD_PREP (PHY_ATDL_CNFG_INPSEL_MASK ,2 );magic "2" needs a meaningful macro definition.
Agree, will improve this in next version.
[......]
Quoted 6 lines
drivers/mmc/host/sdhci-of-dwcmshc.c static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { · line 859
Quoted 5 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +4
-0+static const struct sdhci_pltfm_data sdhci_dwcmshc_sg2042_pdata = { + .ops = &sdhci_dwcmshc_sg2042_ops, + .quirks =SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +SDHCI_QUIRK_INVERTED_WRITE_PROTECT ,is "wp-inverted" property better?
Yes, l will use this in next revision, thanks.
[......]
Quoted 7 lines
Quoted 7 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +7
-0+ +static int dwcmshc_sg2042_init (struct device *dev, +struct sdhci_host *host, +struct dwcmshc_priv *dwc_priv) +{ +int err; +struct sg2042_priv *soc =NULL ;
Quoted 8 lines
drivers/mmc/host/sdhci-of-dwcmshc.c static int dwcmshc_th1520_init(struct device *dev, · line 1013
Quoted 7 lines
drivers/mmc/host/sdhci-of-dwcmshc.c +7
-0+ + soc =devm_kzalloc (dev,sizeof (struct sg2042_priv ),GFP_KERNEL ); +if (!soc) +return -ENOMEM ; + + soc->clks[0 ].id ="card" ; + soc->clks[1 ].id ="timer" ;Interesting, only "card" and "timer", so which clk is for clk input of the ip?
Copy my comments from bindings patch here for quick reference:
Quoted 9 lines
SG2042 defines 3 clocks for SD/eMMC controllers.
- AXI_EMMC/AXI_SD for aclk/hclk(Bus interface clocks in
DWC_mshc) andbclk(Core Base Clock in DWC_mshc), these 3 clocks share one source, so reuse existing "core".
- 100K_EMMC/100K_SD forcqetmclk(Timer clocks in DWC_mshc), so reuse existing "timer" which was added for rockchip specified.- EMMC_100M/SD_100M for
cclk(Card clocks in DWC_mshc), add new "card".
What you meant "clk input of the ip" is "core", right?
[......]
PATCH 3/3 riscv: dts: add mmc controllers for Sophgo SG2042 SoC
In reply to Chen WangFrom: Chen Wang <[email protected]>
SG2042 has two MMC controller, one for emmc, another for sd-card.
--- .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 15 +++++++++ arch/riscv/boot/dts/sophgo/sg2042.dtsi | 32 +++++++++++++++++++ 2 files changed, 47 insertions(+)
arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +15 -0
@@ -26,6 +26,21 @@ &cgi_dpll1 { clock-frequency = <25000000>; }; +&emmc { + bus-width = <4>; + no-sdio; + no-sd; + non-removable; + status = "okay"; +}; + +&sd { + bus-width = <4>; + no-sdio; + no-mmc; + status = "okay"; +}; + &uart0 { status = "okay"; };
arch/riscv/boot/dts/sophgo/sg2042.dtsi +32 -0
@@ -393,5 +393,37 @@ uart0: serial@7040000000 { resets = <&rstgen RST_UART0>; status = "disabled"; }; + + emmc: mmc@704002a000 { + compatible = "sophgo,sg2042-dwcmshc"; + reg = <0x70 0x4002A000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <134 IRQ_TYPE_LEVEL_HIGH>; + clocks = + <&clkgen GATE_CLK_AXI_EMMC>, + <&clkgen GATE_CLK_100K_EMMC>, + <&clkgen GATE_CLK_EMMC_100M>; + clock-names = + "core", + "timer", + "card"; + status = "disabled"; + }; + + sd: mmc@704002b000 { + compatible = "sophgo,sg2042-dwcmshc"; + reg = <0x70 0x4002B000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <136 IRQ_TYPE_LEVEL_HIGH>; + clocks = + <&clkgen GATE_CLK_AXI_SD>, + <&clkgen GATE_CLK_100K_SD>, + <&clkgen GATE_CLK_SD_100M>; + clock-names = + "core", + "timer", + "card"; + status = "disabled"; + }; }; };
Signature · 1 line
2.25.1