From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-07 13:26:45
This series adds support for the two SDMMC controllers in the Microchip
LAN969x family. It also enables the onboard QSPI NOR and eMMC storage on
the EV23X71A evaluation board.
The LAN969x SDMMC controller uses the same internally generated base clock
layout as SAM9X60. However, gating its clocks during runtime suspend leaves
the controller unable to complete software resets or stabilise its internal
clock. Add a generic SoC data option for keeping clocks enabled, while
keeping capability and preset restoration independent from clock
enablement. LAN969x then selects this option through its match data.
Describe both controllers using the fabric clock for the bus interface and
their respective generated clocks for the controller core. Use clock rates
suitable for the supported SD and eMMC modes, including 8-bit eMMC DDR on
the EV23X71A.
The QSPI enablement is retained from v1 so both onboard non-volatile
storage devices are described by this series.
Tested on LAN969x hardware with an 8-bit eMMC operating in DDR mode.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Changes in v2:
* Add driver support for the LAN969x SDMMC controller.
* Add a preparatory option for controllers that must keep clocks enabled.
* Restore capabilities and presets without unbalancing clock enable counts.
* Use the fabric clock for the SDMMC bus interface clock.
* Configure SDMMC1 with an exact 50 MHz generated clock.
* Keep the SDMMC nodes ordered by unit address.
* Remove the unnecessary maximum-frequency property.
* Retain Conor Dooley's Acked-by on the binding patch.
* Rebase onto next-20260904.
Robert Marko (6):
dt-bindings: mmc: atmel,sama5d2-sdhci: add LAN969x compatible
mmc: sdhci-of-at91: add option to keep clocks enabled
mmc: sdhci-of-at91: add LAN969x support
arm64: dts: microchip: lan969x: add SDMMC nodes
arm64: dts: microchip: ev23x71a: enable QSPI
arm64: dts: microchip: ev23x71a: enable eMMC
.../bindings/mmc/atmel,sama5d2-sdhci.yaml | 1 +
arch/arm64/boot/dts/microchip/lan9691.dtsi | 24 ++++++++++
.../boot/dts/microchip/lan9696-ev23x71a.dts | 25 ++++++++++
drivers/mmc/host/sdhci-of-at91.c | 47 ++++++++++++-------
4 files changed, 81 insertions(+), 16 deletions(-)
--
2.55.0
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-07 13:26:41
The SDHCI controller in the LAN969x family uses the same register layout
as the SAM9X60 implementation. Add the microchip,lan9691-sdhci compatible
with microchip,sam9x60-sdhci as its fallback.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
Changes in v2:
* Clarify the relationship between the LAN969x and SAM9X60 controllers.
* Add Conor Dooley's Acked-by.
Documentation/devicetree/bindings/mmc/atmel,sama5d2-sdhci.yaml | 1 +
1 file changed, 1 insertion(+)
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-07 13:26:48
sdhci_at91_set_clks_presets() both enables the controller clocks and
programs its capabilities and preset registers. This prevents callers from
restoring the registers without changing the clock enable counts.
Move clock enablement to callers and add a SoC data flag for controllers
that must keep their clocks enabled. Use it in the runtime PM paths while
keeping register restoration separate from clock enablement.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
drivers/mmc/host/sdhci-of-at91.c | 39 +++++++++++++++++++-------------
1 file changed, 23 insertions(+), 16 deletions(-)
@@ -344,9 +350,10 @@ static int sdhci_at91_probe(struct platform_device *pdev)returndev_err_probe(&pdev->dev,PTR_ERR(priv->gck),"failed to get multclk\n");-ret=sdhci_at91_set_clks_presets(&pdev->dev);-if(ret)-returnret;+clk_prepare_enable(priv->hclock);+sdhci_at91_set_clks_presets(&pdev->dev);+clk_prepare_enable(priv->mainck);+clk_prepare_enable(priv->gck);priv->restore_needed=false;
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-07 13:26:49
LAN969x uses the same internally generated base clock layout as SAM9X60,
but its SDMMC controller stops responding when runtime PM gates its clocks.
Software resets then fail to complete and the internal SDHCI clock never
stabilises, causing subsequent I/O requests to time out.
Add LAN969x-specific SoC data using the SAM9X60 clock layout and select the
option to leave its clocks enabled across runtime suspend.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
drivers/mmc/host/sdhci-of-at91.c | 8 ++++++++
1 file changed, 8 insertions(+)
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-07 13:26:54
Enable the QSPI controller and describe the onboard SPI NOR flash.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
.../arm64/boot/dts/microchip/lan9696-ev23x71a.dts | 15 +++++++++++++++
1 file changed, 15 insertions(+)
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-07 13:26:54
Add nodes for both SDMMC controllers. Connect their bus interface clock to
the fabric clock and their core clock to the corresponding generated clock.
Configure SDMMC0 with a 100 MHz generated clock for 50 MHz eMMC DDR
operation. Configure SDMMC1 with an exact 50 MHz generated clock so the
integer base clock encoded in the SDHCI capabilities remains accurate and
the identification clock does not exceed 400 kHz.
Keep both nodes ordered by unit address.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
Changes in v2:
* Use the fabric clock for the SDMMC bus interface clock.
* Configure SDMMC1 with an exact 50 MHz generated clock.
* Move the SDMMC1 node to preserve unit-address ordering.
* Explain the selected clock rates in the commit description.
arch/arm64/boot/dts/microchip/lan9691.dtsi | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-07 13:27:00
Enable the non-removable eMMC connected to SDMMC0. Configure its 8-bit bus
for 1.8 V DDR operation.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
Changes in v2:
* Remove the unnecessary maximum-frequency property.
* Expand the commit description.
arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts | 10 ++++++++++
1 file changed, 10 insertions(+)
Add nodes for both SDMMC controllers. Connect their bus interface clock to
the fabric clock and their core clock to the corresponding generated clock.
Configure SDMMC0 with a 100 MHz generated clock for 50 MHz eMMC DDR
operation. Configure SDMMC1 with an exact 50 MHz generated clock so the
integer base clock encoded in the SDHCI capabilities remains accurate and
the identification clock does not exceed 400 kHz.
Keep both nodes ordered by unit address.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
Changes in v2:
* Use the fabric clock for the SDMMC bus interface clock.
* Configure SDMMC1 with an exact 50 MHz generated clock.
* Move the SDMMC1 node to preserve unit-address ordering.
* Explain the selected clock rates in the commit description.
arch/arm64/boot/dts/microchip/lan9691.dtsi | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
From: Adrian Hunter <adrian.hunter@intel.com> Date: 2026-09-09 10:31:33
On 07/09/2026 16:25, Robert Marko wrote:
quoted hunk
sdhci_at91_set_clks_presets() both enables the controller clocks and
programs its capabilities and preset registers. This prevents callers from
restoring the registers without changing the clock enable counts.
Move clock enablement to callers and add a SoC data flag for controllers
that must keep their clocks enabled. Use it in the runtime PM paths while
keeping register restoration separate from clock enablement.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
drivers/mmc/host/sdhci-of-at91.c | 39 +++++++++++++++++++-------------
1 file changed, 23 insertions(+), 16 deletions(-)
It can be a bit easier to read when conditions do not have to be
inverted, like
if (priv->soc_data->suspend_clks)
instead of:
if (!priv->soc_data->keep_clks_on)
-
- return 0;
}
static int sdhci_at91_suspend(struct device *dev)
@@ -254,9 +249,11 @@ static int sdhci_at91_runtime_suspend(struct device *dev) if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc);- clk_disable_unprepare(priv->gck);- clk_disable_unprepare(priv->hclock);- clk_disable_unprepare(priv->mainck);+ if (!priv->soc_data->keep_clks_on) {+ clk_disable_unprepare(priv->gck);+ clk_disable_unprepare(priv->hclock);+ clk_disable_unprepare(priv->mainck);+ } return 0; }
@@ -269,14 +266,23 @@ static int sdhci_at91_runtime_resume(struct device *dev) int ret; if (priv->restore_needed) {- ret = sdhci_at91_set_clks_presets(dev);- if (ret)- return ret;+ if (!priv->soc_data->keep_clks_on)+ clk_prepare_enable(priv->hclock);++ sdhci_at91_set_clks_presets(dev);++ if (!priv->soc_data->keep_clks_on) {+ clk_prepare_enable(priv->mainck);+ clk_prepare_enable(priv->gck);+ }
Then that all becomes just:
sdhci_at91_set_clks_presets(dev, !priv->soc_data->keep_clks_on);
quoted hunk
priv->restore_needed = false;
goto out;
}
+ if (priv->soc_data->keep_clks_on)
+ goto out;
+
ret = clk_prepare_enable(priv->mainck);
if (ret) {
dev_err(dev, "can't enable mainck\n");
@@ -344,9 +350,10 @@ static int sdhci_at91_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(priv->gck), "failed to get multclk\n");- ret = sdhci_at91_set_clks_presets(&pdev->dev);- if (ret)- return ret;+ clk_prepare_enable(priv->hclock);+ sdhci_at91_set_clks_presets(&pdev->dev);+ clk_prepare_enable(priv->mainck);+ clk_prepare_enable(priv->gck);
And that all becomes just:
sdhci_at91_set_clks_presets(&pdev->dev, true);
From: Adrian Hunter <adrian.hunter@intel.com> Date: 2026-09-09 10:42:15
On 07/09/2026 16:25, Robert Marko wrote:
LAN969x uses the same internally generated base clock layout as SAM9X60,
but its SDMMC controller stops responding when runtime PM gates its clocks.
Software resets then fail to complete and the internal SDHCI clock never
stabilises, causing subsequent I/O requests to time out.
Is this a known issue of the SoC? Is there perhaps a hardware reset
for the controller that would bring it back to life?
Does that mean unbind and rebind of the device from the driver
also does not work?
quoted hunk
Add LAN969x-specific SoC data using the SAM9X60 clock layout and select the
option to leave its clocks enabled across runtime suspend.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
drivers/mmc/host/sdhci-of-at91.c | 8 ++++++++
1 file changed, 8 insertions(+)
Hi Robert,
On 07/09/2026 15:25, Robert Marko wrote:
sdhci_at91_set_clks_presets() both enables the controller clocks and
programs its capabilities and preset registers. This prevents callers from
restoring the registers without changing the clock enable counts.
Move clock enablement to callers and add a SoC data flag for controllers
that must keep their clocks enabled. Use it in the runtime PM paths while
keeping register restoration separate from clock enablement.
@@ -344,9 +350,10 @@ static int sdhci_at91_probe(struct platform_device *pdev)returndev_err_probe(&pdev->dev,PTR_ERR(priv->gck),"failed to get multclk\n");-ret=sdhci_at91_set_clks_presets(&pdev->dev);-if(ret)-returnret;+clk_prepare_enable(priv->hclock);+sdhci_at91_set_clks_presets(&pdev->dev);+clk_prepare_enable(priv->mainck);+clk_prepare_enable(priv->gck);priv->restore_needed=false;--
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-15 11:32:18
On Mon, Sep 14, 2026 at 3:46 PM Aubin Constans
[off-list ref] wrote:
Hi Robert,
On 07/09/2026 15:25, Robert Marko wrote:
quoted
sdhci_at91_set_clks_presets() both enables the controller clocks and
programs its capabilities and preset registers. This prevents callers from
restoring the registers without changing the clock enable counts.
Move clock enablement to callers and add a SoC data flag for controllers
that must keep their clocks enabled. Use it in the runtime PM paths while
keeping register restoration separate from clock enablement.
@@ -344,9 +350,10 @@ static int sdhci_at91_probe(struct platform_device *pdev)returndev_err_probe(&pdev->dev,PTR_ERR(priv->gck),"failed to get multclk\n");-ret=sdhci_at91_set_clks_presets(&pdev->dev);-if(ret)-returnret;+clk_prepare_enable(priv->hclock);+sdhci_at91_set_clks_presets(&pdev->dev);+clk_prepare_enable(priv->mainck);+clk_prepare_enable(priv->gck);priv->restore_needed=false;--
2.55.0
--
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko@sartura.hr
Web: www.sartura.hr
On Mon, Sep 14, 2026 at 3:46 PM Aubin Constans
[off-list ref] wrote:
quoted
Hi Robert,
On 07/09/2026 15:25, Robert Marko wrote:
quoted
sdhci_at91_set_clks_presets() both enables the controller clocks and
programs its capabilities and preset registers. This prevents callers from
restoring the registers without changing the clock enable counts.
Move clock enablement to callers and add a SoC data flag for controllers
that must keep their clocks enabled. Use it in the runtime PM paths while
keeping register restoration separate from clock enablement.
@@ -344,9 +350,10 @@ static int sdhci_at91_probe(struct platform_device *pdev)returndev_err_probe(&pdev->dev,PTR_ERR(priv->gck),"failed to get multclk\n");-ret=sdhci_at91_set_clks_presets(&pdev->dev);-if(ret)-returnret;+clk_prepare_enable(priv->hclock);+sdhci_at91_set_clks_presets(&pdev->dev);+clk_prepare_enable(priv->mainck);+clk_prepare_enable(priv->gck);priv->restore_needed=false;--
2.55.0
--
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko@sartura.hr
Web: www.sartura.hr
Add nodes for both SDMMC controllers. Connect their bus interface clock to
the fabric clock and their core clock to the corresponding generated clock.
Configure SDMMC0 with a 100 MHz generated clock for 50 MHz eMMC DDR
operation. Configure SDMMC1 with an exact 50 MHz generated clock so the
integer base clock encoded in the SDHCI capabilities remains accurate and
the identification clock does not exceed 400 kHz.
Keep both nodes ordered by unit address.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
Changes in v2:
* Use the fabric clock for the SDMMC bus interface clock.
* Configure SDMMC1 with an exact 50 MHz generated clock.
* Move the SDMMC1 node to preserve unit-address ordering.
* Explain the selected clock rates in the commit description.
arch/arm64/boot/dts/microchip/lan9691.dtsi | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
Enable the non-removable eMMC connected to SDMMC0. Configure its 8-bit bus
for 1.8 V DDR operation.
Signed-off-by: Robert Marko<robert.marko@sartura.hr>
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-22 12:10:17
On Wed, Sep 9, 2026 at 12:42 PM Adrian Hunter [off-list ref] wrote:
On 07/09/2026 16:25, Robert Marko wrote:
quoted
LAN969x uses the same internally generated base clock layout as SAM9X60,
but its SDMMC controller stops responding when runtime PM gates its clocks.
Software resets then fail to complete and the internal SDHCI clock never
stabilises, causing subsequent I/O requests to time out.
Is this a known issue of the SoC? Is there perhaps a hardware reset
for the controller that would bring it back to life?
Hi Adrian,
It seems like the controller was reused from SAMA7G5, which shares the
same behaviour.
Unfortunately, there is no HW reset for the controller.
Does that mean unbind and rebind of the device from the driver
also does not work?
It works as long as we avoid disabling the clocks.
Regards,
Robert
quoted
Add LAN969x-specific SoC data using the SAM9X60 clock layout and select the
option to leave its clocks enabled across runtime suspend.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
drivers/mmc/host/sdhci-of-at91.c | 8 ++++++++
1 file changed, 8 insertions(+)
--
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko@sartura.hr
Web: www.sartura.hr
From: Robert Marko <robert.marko@sartura.hr> Date: 2026-09-22 12:11:18
On Fri, Sep 18, 2026 at 6:02 PM Aubin Constans
[off-list ref] wrote:
On 15/09/2026 13:31, Robert Marko wrote:
quoted
On Mon, Sep 14, 2026 at 3:46 PM Aubin Constans
[off-list ref] wrote:
quoted
Hi Robert,
On 07/09/2026 15:25, Robert Marko wrote:
quoted
sdhci_at91_set_clks_presets() both enables the controller clocks and
programs its capabilities and preset registers. This prevents callers from
restoring the registers without changing the clock enable counts.
Move clock enablement to callers and add a SoC data flag for controllers
that must keep their clocks enabled. Use it in the runtime PM paths while
keeping register restoration separate from clock enablement.
Hi Aubin,
As long as that is merged, then LAN969x support is really simple.
I tested it locally and it works, so I am waiting on that getting
merged before sending v3 for LAN969x.
Regards,
Robert
Regards,
Aubin
quoted
quoted
quoted
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
drivers/mmc/host/sdhci-of-at91.c | 39 +++++++++++++++++++-------------
1 file changed, 23 insertions(+), 16 deletions(-)
@@ -344,9 +350,10 @@ static int sdhci_at91_probe(struct platform_device *pdev)returndev_err_probe(&pdev->dev,PTR_ERR(priv->gck),"failed to get multclk\n");-ret=sdhci_at91_set_clks_presets(&pdev->dev);-if(ret)-returnret;+clk_prepare_enable(priv->hclock);+sdhci_at91_set_clks_presets(&pdev->dev);+clk_prepare_enable(priv->mainck);+clk_prepare_enable(priv->gck);priv->restore_needed=false;--
2.55.0
--
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko@sartura.hr
Web: www.sartura.hr
--
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko@sartura.hr
Web: www.sartura.hr
As sashiko pointed out, #address-cells, #size-cells, should not be
necessary here. I dropped them and applied to microchip-dt64.
Thanks,
Will drop it from future v3 then.
Regards,
Robert
Thank you,
Claudiu
--
Robert Marko
Staff Embedded Linux Engineer
Sartura d.d.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko@sartura.hr
Web: www.sartura.hr