* [PATCH 2/4] mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume
From: ziniu.wang_1 @ 2026-06-23 7:35 UTC (permalink / raw)
To: adrian.hunter, ulf.hansson, haibo.chen
Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260623073515.2658205-1-ziniu.wang_1@oss.nxp.com>
From: Luke Wang <ziniu.wang_1@nxp.com>
sdhci_esdhc_imx_hwinit() unconditionally clears ESDHC_DLL_CTRL by
writing zero. For SDIO devices that keep power during system suspend
and operate in DDR mode, the card remains in DDR timing while the host
DLL override configuration is lost.
Extract the DLL override setup from esdhc_set_uhs_signaling() into
a helper esdhc_set_dll_override(), and call it on the resume path
when the card kept power and is using a DDR timing mode.
Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM logic")
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
drivers/mmc/host/sdhci-esdhc-imx.c | 38 ++++++++++++++++++++++--------
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 6526d65538de..a944351dbcdf 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1349,6 +1349,23 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
return pinctrl_select_state(imx_data->pinctrl, pinctrl);
}
+static void esdhc_set_dll_override(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+ struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+ u32 v;
+
+ if (!boarddata->delay_line)
+ return;
+
+ v = boarddata->delay_line << ESDHC_DLL_OVERRIDE_VAL_SHIFT |
+ (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
+ if (is_imx53_esdhc(imx_data))
+ v <<= 1;
+ writel(v, host->ioaddr + ESDHC_DLL_CTRL);
+}
+
/*
* For HS400 eMMC, there is a data_strobe line. This signal is generated
* by the device and used for data output and CRC status response output
@@ -1425,15 +1442,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
m |= ESDHC_MIX_CTRL_DDREN;
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
imx_data->is_ddr = 1;
- if (boarddata->delay_line) {
- u32 v;
- v = boarddata->delay_line <<
- ESDHC_DLL_OVERRIDE_VAL_SHIFT |
- (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
- if (is_imx53_esdhc(imx_data))
- v <<= 1;
- writel(v, host->ioaddr + ESDHC_DLL_CTRL);
- }
+ esdhc_set_dll_override(host);
break;
case MMC_TIMING_MMC_HS400:
m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
@@ -2123,9 +2132,18 @@ static int sdhci_esdhc_resume(struct device *dev)
* restore the saved tuning delay value for the device which keep
* power during system PM.
*/
- if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
+ if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data)) {
sdhc_esdhc_tuning_restore(host);
+ /*
+ * Restore DLL override for DDR modes. hwinit unconditionally
+ * clears ESDHC_DLL_CTRL, but the card is still in DDR mode.
+ */
+ if (host->timing == MMC_TIMING_UHS_DDR50 ||
+ host->timing == MMC_TIMING_MMC_DDR52)
+ esdhc_set_dll_override(host);
+ }
+
pm_runtime_put_autosuspend(dev);
return ret;
--
2.34.1
^ permalink raw reply related
* [PATCH 1/4] mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore
From: ziniu.wang_1 @ 2026-06-23 7:35 UTC (permalink / raw)
To: adrian.hunter, ulf.hansson, haibo.chen
Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260623073515.2658205-1-ziniu.wang_1@oss.nxp.com>
From: Luke Wang <ziniu.wang_1@nxp.com>
The tuning save/restore during system PM is conditioned on
mmc_card_wake_sdio_irq(), but this check is unrelated to whether
tuning values need to be preserved. The actual requirement is that
the card keeps power during suspend and the controller is a uSDHC.
SDIO devices using out-of-band GPIO wakeup maintain power during
suspend but do not set the SDIO IRQ wake flag. In this case the
tuning delay values are not saved/restored.
Remove the unnecessary mmc_card_wake_sdio_irq() condition from both
the suspend save and resume restore paths.
Fixes: c63d25cdc59a ("mmc: sdhci-esdhc-imx: Save tuning value when card stays powered in suspend")
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
---
drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 18ecddd6df6f..6526d65538de 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -2064,8 +2064,7 @@ static int sdhci_esdhc_suspend(struct device *dev)
* to save the tuning delay value just in case the usdhc
* lost power during system PM.
*/
- if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
- esdhc_is_usdhc(imx_data))
+ if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
sdhc_esdhc_tuning_save(host);
if (device_may_wakeup(dev)) {
@@ -2124,8 +2123,7 @@ static int sdhci_esdhc_resume(struct device *dev)
* restore the saved tuning delay value for the device which keep
* power during system PM.
*/
- if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
- esdhc_is_usdhc(imx_data))
+ if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
sdhc_esdhc_tuning_restore(host);
pm_runtime_put_autosuspend(dev);
--
2.34.1
^ permalink raw reply related
* [PATCH 0/4] mmc: sdhci-esdhc-imx: fix SDIO suspend/resume issues
From: ziniu.wang_1 @ 2026-06-23 7:35 UTC (permalink / raw)
To: adrian.hunter, ulf.hansson, haibo.chen
Cc: Frank.Li, s.hauer, kernel, festevam, imx, linux-mmc, s32,
linux-arm-kernel, linux-kernel
From: Luke Wang <ziniu.wang_1@nxp.com>
This series fixes several issues with SDIO devices that keep power
during system suspend on i.MX platforms.
Patch 1 removes unnecessary mmc_card_wake_sdio_irq() check from tuning
save/restore paths.
Patch 2 restores DLL override configuration for DDR modes on resume,
which is lost when sdhci_esdhc_imx_hwinit() clears ESDHC_DLL_CTRL.
Patch 3 restores pinctrl before pm_runtime_force_resume() to ensure
proper pin configuration before DDR_EN is set, avoiding CRC errors.
Patch 4 unconditionally disables usdhc interrupt during suspend to
prevent "irq xxx: nobody cared" warnings during resume.
Luke Wang (4):
mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check
for tuning save/restore
mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume
mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on
resume
mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled
interrupt
drivers/mmc/host/sdhci-esdhc-imx.c | 57 ++++++++++++++++++++----------
1 file changed, 39 insertions(+), 18 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v2] dt-bindings: clock: Replace bouncing emails
From: Krzysztof Kozlowski @ 2026-06-23 7:30 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sylwester Nawrocki, Chanwoo Choi, Peter Griffin, Alim Akhtar,
Barnabas Czeman, Tomasz Figa, linux-arm-msm, linux-clk,
devicetree, linux-kernel, linux-samsung-soc, linux-arm-kernel
Cc: Krzysztof Kozlowski
Replace permanently bouncing email addresses (550 5.1.1 Recipient address
rejected) of Adam Skladowski, Chanho Park, Anusha Rao and Sireesh
Kodali. There are no new messages from them via other email addresses,
so drop them permanently. Add Alim Akhtar to Samsung ExynosAutov9 SoC
clocks, because he looks at other Samsung clock hardware and drivers.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Stephen, can you take this directly?
Changes in v2:
1. Also Anusha Rao.
---
Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml | 2 --
Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml | 1 -
Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml | 1 -
.../devicetree/bindings/clock/samsung,exynosautov9-clock.yaml | 2 +-
4 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
index fc0360554f68..9f2b970bfb48 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
@@ -7,8 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Global Clock & Reset Controller on MSM8937, MSM8940, MSM8953 and SDM439
maintainers:
- - Adam Skladowski <a_skl39@protonmail.com>
- - Sireesh Kodali <sireeshkodali@protonmail.com>
- Barnabas Czeman <barnabas.czeman@mainlining.org>
description: |
diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
index 5b128fa841aa..1337bd87fddd 100644
--- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
@@ -8,7 +8,6 @@ title: Qualcomm Global Clock & Reset Controller on IPQ9574
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- - Anusha Rao <quic_anusha@quicinc.com>
description: |
Qualcomm global clock control module provides the clocks, resets and power
diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml
index 7ff4ff3587ca..a35bbc7b1924 100644
--- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-nsscc.yaml
@@ -8,7 +8,6 @@ title: Qualcomm Networking Sub System Clock & Reset Controller on IPQ9574 and IP
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- - Anusha Rao <quic_anusha@quicinc.com>
description: |
Qualcomm networking sub system clock control module provides the clocks,
diff --git a/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
index e9d17d48b4f3..3dcdfa7a8792 100644
--- a/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung Exynos Auto v9 SoC clock controller
maintainers:
- - Chanho Park <chanho61.park@samsung.com>
+ - Alim Akhtar <alim.akhtar@samsung.com>
- Chanwoo Choi <cw00.choi@samsung.com>
- Krzysztof Kozlowski <krzk@kernel.org>
- Sylwester Nawrocki <s.nawrocki@samsung.com>
--
2.53.0
^ permalink raw reply related
* [PATCH] ARM: OMAP2+: Fix a reference leak bug in omap_hwmod_fix_mpu_rt_idx()
From: Haoxiang Li @ 2026-06-23 7:25 UTC (permalink / raw)
To: paul, aaro.koskinen, andreas, khilman, rogerq, tony, linux
Cc: linux-omap, linux-arm-kernel, linux-kernel, Haoxiang Li, stable
omap_hwmod_fix_mpu_rt_idx() gets the first child node with
of_get_next_child(), which returns a node with its reference count
incremented. The function uses the child node to translate the MPU
runtime register resource, but never drops the reference afterwards.
Add the missing of_node_put() after of_address_to_resource().
Fixes: 1dbcb97c656e ("ARM: OMAP2+: Fix module address for modules using mpu_rt_idx")
Cc: stable@vger.kernel.org
Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
---
arch/arm/mach-omap2/omap_hwmod.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 974107ff18b4..1d7677ca3802 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2176,6 +2176,7 @@ static void omap_hwmod_fix_mpu_rt_idx(struct omap_hwmod *oh,
if (error)
pr_err("%s: error mapping mpu_rt_idx: %i\n",
__func__, error);
+ of_node_put(child);
}
/**
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v5 1/1] arm64: dts: add tqma9596la-mba95xxca
From: Alexander Stein @ 2026-06-23 7:14 UTC (permalink / raw)
To: Frank Li
Cc: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Markus Niebel, imx,
linux-arm-kernel, devicetree, linux-kernel, linux,
linux-renesas-soc
In-Reply-To: <ajVN4nbmOW-D_Ec9@SMW015318>
[-- Attachment #1: Type: text/plain, Size: 4206 bytes --]
Am Freitag, 19. Juni 2026, 16:10:42 CEST schrieb Frank Li:
> On Fri, Jun 19, 2026 at 01:24:30PM +0200, Alexander Stein wrote:
> > From: Markus Niebel <Markus.Niebel@ew.tq-group.com>
> >
> > This adds support for TQMa95xxLA modules, designed to be soldered
> > on a carrier board. MBa95xxCA is a carrier reference board / starter kit
> > design.
> >
> > There is a common device tree for all variants with e.g. reduced
> > CPU core / feature count.
> >
> > Enable the external accessible PCIe controllers as host,
> > add clocking and reset GPIO. While at it, add hogs for GPIO
> > lines from the M.2 slots until M.2 connector driver is available.
> >
> > Signed-off-by: Markus Niebel <Markus.Niebel@ew.tq-group.com>
> > Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
> > ---
> > Changes in v5:
> > * Limit LPSPI4 max frequency
> > * Replace PCIe M2 Key-E GPIO hogs with dedicated connector node
> > * Fix PCIe clock configuration
> >
> > Changes in v4:
> > * Fix LPSPI4 pad muxing and control
> >
> > Changes in v3:
> > * Moved reserved-memory to board-lebel
> > * Remove VPU reserved memory (unused for now)
> > * Fix typo in connector comment
> >
> > Changes in v2:
> > * removed useless regulator
> > * added USB PD source configuration
> > * Removed unused uart-has-rtscts properties (unused by LPUART)
> > * Fixed RTS/CTS pullups in pinctrl
> > * Added thermalzone on module
> >
> > arch/arm64/boot/dts/freescale/Makefile | 1 +
> > .../freescale/imx95-tqma9596la-mba95xxca.dts | 963 ++++++++++++++++++
> > .../boot/dts/freescale/imx95-tqma9596la.dtsi | 278 +++++
> > 3 files changed, 1242 insertions(+)
> > create mode 100644 arch/arm64/boot/dts/freescale/imx95-tqma9596la-mba95xxca.dts
> > create mode 100644 arch/arm64/boot/dts/freescale/imx95-tqma9596la.dtsi
> >
> > diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> > index 8ddaab127ab9c..43e1dc51b11d7 100644
> > --- a/arch/arm64/boot/dts/freescale/Makefile
> > +++ b/arch/arm64/boot/dts/freescale/Makefile
> > @@ -649,6 +649,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-frdm-pro.dtb
> > dtb-$(CONFIG_ARCH_MXC) += imx95-aquila-clover.dtb
> > dtb-$(CONFIG_ARCH_MXC) += imx95-aquila-dev.dtb
> > dtb-$(CONFIG_ARCH_MXC) += imx95-toradex-smarc-dev.dtb
> > +dtb-$(CONFIG_ARCH_MXC) += imx95-tqma9596la-mba95xxca.dtb
> > dtb-$(CONFIG_ARCH_MXC) += imx95-tqma9596sa-mb-smarc-2.dtb
> > dtb-$(CONFIG_ARCH_MXC) += imx95-var-dart-sonata.dtb
> > dtb-$(CONFIG_ARCH_MXC) += imx95-verdin-nonwifi-dahlia.dtb
> ...
> > +
> > + ptn5110: usb-typec@50 {
> > + compatible = "nxp,ptn5110", "tcpci";
> > + reg = <0x50>;
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_typec>;
> > + interrupt-parent = <&gpio2>;
> > + interrupts = <28 IRQ_TYPE_LEVEL_LOW>;
> > +
> > + typec_con: connector {
> > + compatible = "usb-c-connector";
> > + label = "X9";
> > + power-role = "source";
> > + data-role = "dual";
> > + source-pdos = <PDO_FIXED(5000, 500, PDO_FIXED_USB_COMM)>;
> > + self-powered;
> > +
> > + port {
> > + typec_con_hs: endpoint {
> > + remote-endpoint = <&typec_hs>;
> > + };
> > + };
> > + };
> > + };
> > +
> > + sensor_mb: temperature-sensor@1e {
>
> please order by hex address value
Ah, thanks for the catch.
> > + compatible = "nxp,se97b", "jedec,jc-42.4-temp";
> > + reg = <0x1e>;
> > + };
> > +
> ...
> > + m2-keye-dev_bt-wake-hog {
> > + gpio-hog;
> > + gpios = <4 GPIO_ACTIVE_LOW>;
> > + input;
> > + line-name = "M2_KEYE_DEV_BT_WAKE#";
> > + };
>
> Now Key E connector already be upstreamed.
>
> Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml,
> which already define these gpios.
Thanks for the hint. But these two wake signals are vendor specific
pins 40 and 42 on key-e. In this case these are for the default module
JODY-W3 module.
Thanks and best regards,
Alexander
--
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH] iommu/qcom: Remove sysfs device on probe failure path
From: Haoxiang Li @ 2026-06-23 7:12 UTC (permalink / raw)
To: robin.clark, will, robin.murphy, joro, jroedel
Cc: iommu, linux-arm-msm, linux-arm-kernel, linux-kernel, Haoxiang Li
In qcom_iommu_device_probe(), if iommu_device_register()
fails, the sysfs device created by iommu_device_sysfs_add()
is not released. Add a goto label to do the cleanup.
Fixes: 0ae349a0f33f ("iommu/qcom: Add qcom_iommu")
Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
---
drivers/iommu/arm/arm-smmu/qcom_iommu.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index a1e8cf29f594..32efef69e72d 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -855,7 +855,7 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
ret = iommu_device_register(&qcom_iommu->iommu, &qcom_iommu_ops, dev);
if (ret) {
dev_err(dev, "Failed to register iommu\n");
- goto err_pm_disable;
+ goto err_sysfs_remove;
}
if (qcom_iommu->local_base) {
@@ -866,6 +866,8 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
return 0;
+err_sysfs_remove:
+ iommu_device_sysfs_remove(&qcom_iommu->iommu);
err_pm_disable:
pm_runtime_disable(dev);
return ret;
--
2.25.1
^ permalink raw reply related
* [PATCH v6 2/4] clk: cix: add sky1 audss clock controller
From: joakim.zhang @ 2026-06-23 7:08 UTC (permalink / raw)
To: mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt, p.zabel,
gary.yang
Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Joakim Zhang
In-Reply-To: <20260623070805.211019-1-joakim.zhang@cixtech.com>
From: Joakim Zhang <joakim.zhang@cixtech.com>
Add a platform driver for the Cix Sky1 AUDSS CRU. The driver maps
the CRU registers and registers mux, divider and gate clocks for
DSP, SRAM, HDA, DMAC, I2S, mailbox, watchdog and timer blocks.
Four SoC-level audio reference clocks are enabled as inputs to the
internal clock tree. The driver releases the AUDSS NOC reset, enables
runtime PM and instantiates the auxiliary reset device.
Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
---
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/cix/Kconfig | 16 +
drivers/clk/cix/Makefile | 3 +
drivers/clk/cix/clk-sky1-audss.c | 1201 ++++++++++++++++++++++++++++++
5 files changed, 1222 insertions(+)
create mode 100644 drivers/clk/cix/Kconfig
create mode 100644 drivers/clk/cix/Makefile
create mode 100644 drivers/clk/cix/clk-sky1-audss.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1717ce75a907..cfcaab39068a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -509,6 +509,7 @@ source "drivers/clk/actions/Kconfig"
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/aspeed/Kconfig"
source "drivers/clk/bcm/Kconfig"
+source "drivers/clk/cix/Kconfig"
source "drivers/clk/eswin/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imgtec/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cc108a75a900..87c992f0df54 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -119,6 +119,7 @@ obj-$(CONFIG_ARCH_ARTPEC) += axis/
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
obj-y += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
+obj-y += cix/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
obj-$(CONFIG_COMMON_CLK_ESWIN) += eswin/
obj-$(CONFIG_ARCH_HISI) += hisilicon/
diff --git a/drivers/clk/cix/Kconfig b/drivers/clk/cix/Kconfig
new file mode 100644
index 000000000000..c92a9a873893
--- /dev/null
+++ b/drivers/clk/cix/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+# Audio subsystem clock support for Cixtech SoC family
+menu "Clock support for Cixtech audss"
+
+config CLK_SKY1_AUDSS
+ tristate "Cixtech Sky1 Audio Subsystem Clock Driver"
+ depends on ARCH_CIX || COMPILE_TEST
+ select AUXILIARY_BUS
+ select REGMAP_MMIO
+ select RESET_CONTROLLER
+ help
+ Support for the Audio Subsystem clock controller present on
+ Cixtech Sky1 SoC. This driver provides mux, divider and gate
+ clocks for DSP, I2S, HDA and related blocks in the audio
+ subsystem. Say M or Y here if you want to build this driver.
+endmenu
diff --git a/drivers/clk/cix/Makefile b/drivers/clk/cix/Makefile
new file mode 100644
index 000000000000..bc612f1d08b2
--- /dev/null
+++ b/drivers/clk/cix/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_CLK_SKY1_AUDSS) += clk-sky1-audss.o
diff --git a/drivers/clk/cix/clk-sky1-audss.c b/drivers/clk/cix/clk-sky1-audss.c
new file mode 100644
index 000000000000..25341be4f5bf
--- /dev/null
+++ b/drivers/clk/cix/clk-sky1-audss.c
@@ -0,0 +1,1201 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright 2026 Cix Technology Group Co., Ltd.
+
+#include <linux/auxiliary_bus.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <dt-bindings/clock/cix,sky1-audss-cru.h>
+
+#define INFO_HIFI0 0x00
+#define INFO_CLK_GATE 0x10
+#define INFO_CLK_DIV 0x14
+#define INFO_CLK_MUX 0x18
+#define INFO_MCLK 0x70
+
+#define SKY1_AUDSS_CLK_PARENTS_CNT 4
+#define SKY1_AUDSS_NUM_CLKS (CLK_MCLK4 + 1)
+
+static u32 sky1_reg_save[][2] = {
+ { INFO_HIFI0, 0 },
+ { INFO_CLK_GATE, 0 },
+ { INFO_CLK_DIV, 0 },
+ { INFO_CLK_MUX, 0 },
+ { INFO_MCLK, 0 },
+};
+
+static const char * const sky1_audss_clk_names[SKY1_AUDSS_CLK_PARENTS_CNT] = {
+ "x8k", "x11k", "sys", "48m",
+};
+
+static const u32 sky1_clk_rate_default[SKY1_AUDSS_CLK_PARENTS_CNT] = {
+ 294912000,
+ 270950400,
+ 800000000,
+ 48000000,
+};
+
+static const char * const dsp_clk_parent[] = {
+ "audio_clk4"
+};
+
+static const char * const dsp_bclk_parent[] = {
+ "audio_clk4_div2"
+};
+
+static const char * const dsp_pbclk_parent[] = {
+ "audio_clk4_div4"
+};
+
+static const char * const sram_axi_parent[] = {
+ "audio_clk4_div2"
+};
+
+static const char * const hda_sys_parent[] = {
+ "audio_clk4_div2"
+};
+
+static const char * const hda_hda_parent[] = {
+ "audio_clk5"
+};
+
+static const char * const dmac_axi_parent[] = {
+ "audio_clk4_div2"
+};
+
+static const char * const wdg_apb_parent[] = {
+ "audio_clk5_div2"
+};
+
+static const char * const wdg_wdg_parent[] = {
+ "audio_clk5_div2"
+};
+
+static const char * const timer_apb_parent[] = {
+ "audio_clk4_div4"
+};
+
+static const char * const timer_timer_parent[] = {
+ "audio_clk5_div2"
+};
+
+static const char * const mailbox_apb_parent[] = {
+ "audio_clk4_div4"
+};
+
+static const char * const i2s_apb_parent[] = {
+ "audio_clk4_div4"
+};
+
+static const char * const i2s0_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s1_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s2_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s3_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s4_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s5_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s6_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s7_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s8_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const i2s9_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const char * const mclk_parents[] = {
+ "audio_clk0", "audio_clk2"
+};
+
+static const u32 i2s3_mux_table[] = { 0, 2 };
+static const u32 i2s4_mux_table[] = { 0, 2 };
+
+/*
+ * audss composite clock definition
+ */
+struct muxdiv_cfg {
+ int offset;
+ u8 shift;
+ u8 width;
+ u8 flags;
+};
+
+struct gate_cfg {
+ int offset;
+ u8 shift;
+ u8 flags;
+};
+
+struct composite_clk_cfg {
+ u32 id;
+ const char * const name;
+ const char * const *parent_names;
+ int num_parents;
+ const u32 *mux_table;
+ struct muxdiv_cfg *mux_cfg;
+ struct muxdiv_cfg *div_cfg;
+ struct gate_cfg *gate_cfg;
+ unsigned long flags;
+};
+
+#define CFG(_id,\
+ _name,\
+ _parent_names,\
+ _mux_table,\
+ _mux_offset, _mux_shift, _mux_width, _mux_flags,\
+ _div_offset, _div_shift, _div_width, _div_flags,\
+ _gate_offset, _gate_shift, _gate_flags,\
+ _flags)\
+{\
+ .id = _id,\
+ .name = _name,\
+ .parent_names = _parent_names,\
+ .num_parents = ARRAY_SIZE(_parent_names),\
+ .mux_table = _mux_table,\
+ .mux_cfg = &(struct muxdiv_cfg) { _mux_offset, _mux_shift, _mux_width, _mux_flags },\
+ .div_cfg = &(struct muxdiv_cfg) { _div_offset, _div_shift, _div_width, _div_flags },\
+ .gate_cfg = &(struct gate_cfg) { _gate_offset, _gate_shift, _gate_flags },\
+ .flags = _flags,\
+}
+
+static const struct composite_clk_cfg sky1_audss_clks[] = {
+ /* dsp */
+ CFG(CLK_DSP_CLK,
+ "audss_dsp_clk",
+ dsp_clk_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_HIFI0, 0, 0,
+ 0),
+ CFG(CLK_DSP_BCLK,
+ "audss_dsp_bclk",
+ dsp_bclk_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ -1, 0, 0,
+ 0),
+ CFG(CLK_DSP_PBCLK,
+ "audss_dsp_pbclk",
+ dsp_pbclk_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ -1, 0, 0,
+ 0),
+ /* sram */
+ CFG(CLK_SRAM_AXI,
+ "audss_sram_axi",
+ sram_axi_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 16, 0,
+ 0),
+ /* hda */
+ CFG(CLK_HDA_SYS,
+ "audss_hda_sys",
+ hda_sys_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 14, 0,
+ 0),
+ CFG(CLK_HDA_HDA,
+ "audss_hda_hda",
+ hda_hda_parent,
+ NULL,
+ -1, 0, 0, 0,
+ -1, 0, 0, 0,
+ INFO_CLK_GATE, 14, 0,
+ 0),
+ /* dmac */
+ CFG(CLK_DMAC_AXI,
+ "audss_dmac_axi",
+ dmac_axi_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 15, 0,
+ 0),
+ /* wdg */
+ CFG(CLK_WDG_APB,
+ "audss_wdg_apb",
+ wdg_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ -1, 0, 0, 0,
+ INFO_CLK_GATE, 10, 0,
+ 0),
+ CFG(CLK_WDG_WDG,
+ "audss_wdg_wdg",
+ wdg_wdg_parent,
+ NULL,
+ -1, 0, 0, 0,
+ -1, 0, 0, 0,
+ INFO_CLK_GATE, 10, 0,
+ 0),
+ /* timer */
+ CFG(CLK_TIMER_APB,
+ "audss_timer_apb",
+ timer_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 11, 0,
+ 0),
+ CFG(CLK_TIMER_TIMER,
+ "audss_timer_timer",
+ timer_timer_parent,
+ NULL,
+ -1, 0, 0, 0,
+ -1, 0, 0, 0,
+ INFO_CLK_GATE, 11, 0,
+ 0),
+ /* mailbox: mb0(ap->dsp), mb1(dsp->ap) */
+ CFG(CLK_MB_0_APB,
+ "audss_mb_0_apb",
+ mailbox_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ -1, 0, 0, 0,
+ INFO_CLK_GATE, 12, 0,
+ 0),
+ CFG(CLK_MB_1_APB,
+ "audss_mb_1_apb",
+ mailbox_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ -1, 0, 0, 0,
+ INFO_CLK_GATE, 13, 0,
+ 0),
+ /* i2s */
+ CFG(CLK_I2S0_APB,
+ "audss_i2s0_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 0, 0,
+ 0),
+ CFG(CLK_I2S1_APB,
+ "audss_i2s1_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 1, 0,
+ 0),
+ CFG(CLK_I2S2_APB,
+ "audss_i2s2_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 2, 0,
+ 0),
+ CFG(CLK_I2S3_APB,
+ "audss_i2s3_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 3, 0,
+ 0),
+ CFG(CLK_I2S4_APB,
+ "audss_i2s4_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 4, 0,
+ 0),
+ CFG(CLK_I2S5_APB,
+ "audss_i2s5_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 5, 0,
+ 0),
+ CFG(CLK_I2S6_APB,
+ "audss_i2s6_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 6, 0,
+ 0),
+ CFG(CLK_I2S7_APB,
+ "audss_i2s7_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 7, 0,
+ 0),
+ CFG(CLK_I2S8_APB,
+ "audss_i2s8_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 8, 0,
+ 0),
+ CFG(CLK_I2S9_APB,
+ "audss_i2s9_apb",
+ i2s_apb_parent,
+ NULL,
+ -1, 0, 0, 0,
+ INFO_CLK_DIV, 0, 2, 0,
+ INFO_CLK_GATE, 9, 0,
+ 0),
+ CFG(CLK_I2S0,
+ "audss_i2s0",
+ i2s0_parents,
+ NULL,
+ INFO_CLK_MUX, 0, 2, 0,
+ INFO_CLK_DIV, 2, 2, 0,
+ INFO_CLK_GATE, 0, 0,
+ 0),
+ CFG(CLK_I2S1,
+ "audss_i2s1",
+ i2s1_parents,
+ NULL,
+ INFO_CLK_MUX, 2, 2, 0,
+ INFO_CLK_DIV, 4, 2, 0,
+ INFO_CLK_GATE, 1, 0,
+ 0),
+ CFG(CLK_I2S2,
+ "audss_i2s2",
+ i2s2_parents,
+ NULL,
+ INFO_CLK_MUX, 4, 2, 0,
+ INFO_CLK_DIV, 6, 2, 0,
+ INFO_CLK_GATE, 2, 0,
+ 0),
+ CFG(CLK_I2S3,
+ "audss_i2s3",
+ i2s3_parents,
+ i2s3_mux_table,
+ INFO_CLK_MUX, 6, 2, 0,
+ INFO_CLK_DIV, 8, 2, 0,
+ INFO_CLK_GATE, 3, 0,
+ 0),
+ CFG(CLK_I2S4,
+ "audss_i2s4",
+ i2s4_parents,
+ i2s4_mux_table,
+ INFO_CLK_MUX, 8, 2, 0,
+ INFO_CLK_DIV, 10, 2, 0,
+ INFO_CLK_GATE, 4, 0,
+ 0),
+ CFG(CLK_I2S5,
+ "audss_i2s5",
+ i2s5_parents,
+ NULL,
+ INFO_CLK_MUX, 10, 2, 0,
+ INFO_CLK_DIV, 12, 2, 0,
+ INFO_CLK_GATE, 5, 0,
+ 0),
+ CFG(CLK_I2S6,
+ "audss_i2s6",
+ i2s6_parents,
+ NULL,
+ INFO_CLK_MUX, 12, 2, 0,
+ INFO_CLK_DIV, 14, 2, 0,
+ INFO_CLK_GATE, 6, 0,
+ 0),
+ CFG(CLK_I2S7,
+ "audss_i2s7",
+ i2s7_parents,
+ NULL,
+ INFO_CLK_MUX, 14, 2, 0,
+ INFO_CLK_DIV, 16, 2, 0,
+ INFO_CLK_GATE, 7, 0,
+ 0),
+ CFG(CLK_I2S8,
+ "audss_i2s8",
+ i2s8_parents,
+ NULL,
+ INFO_CLK_MUX, 16, 2, 0,
+ INFO_CLK_DIV, 18, 2, 0,
+ INFO_CLK_GATE, 8, 0,
+ 0),
+ CFG(CLK_I2S9,
+ "audss_i2s9",
+ i2s9_parents,
+ NULL,
+ INFO_CLK_MUX, 18, 2, 0,
+ INFO_CLK_DIV, 20, 2, 0,
+ INFO_CLK_GATE, 9, 0,
+ 0),
+ /* mclk */
+ CFG(CLK_MCLK0,
+ "audss_mclk0",
+ mclk_parents,
+ NULL,
+ INFO_MCLK, 5, 1, 0,
+ -1, 0, 0, 0,
+ INFO_MCLK, 0, 0,
+ 0),
+ CFG(CLK_MCLK1,
+ "audss_mclk1",
+ mclk_parents,
+ NULL,
+ INFO_MCLK, 6, 1, 0,
+ -1, 0, 0, 0,
+ INFO_MCLK, 1, 0,
+ 0),
+ CFG(CLK_MCLK2,
+ "audss_mclk2",
+ mclk_parents,
+ NULL,
+ INFO_MCLK, 7, 1, 0,
+ -1, 0, 0, 0,
+ INFO_MCLK, 2, 0,
+ 0),
+ CFG(CLK_MCLK3,
+ "audss_mclk3",
+ mclk_parents,
+ NULL,
+ INFO_MCLK, 8, 1, 0,
+ -1, 0, 0, 0,
+ INFO_MCLK, 3, 0,
+ 0),
+ CFG(CLK_MCLK4,
+ "audss_mclk4",
+ mclk_parents,
+ NULL,
+ INFO_MCLK, 9, 1, 0,
+ -1, 0, 0, 0,
+ INFO_MCLK, 4, 0,
+ 0),
+};
+
+struct sky1_audss_clks_devtype_data {
+ u32 (*reg_save)[2];
+ size_t reg_save_size;
+ const char * const *clk_names;
+ size_t clk_num;
+ const u32 *clk_rate_default;
+ const struct composite_clk_cfg *clk_cfg;
+ size_t clk_cfg_size;
+};
+
+static const struct regmap_config sky1_audss_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+struct sky1_audss_clks_priv {
+ struct device *dev;
+ struct regmap *regmap_cru;
+ struct reset_control *rst_noc;
+ struct clk *clks[SKY1_AUDSS_CLK_PARENTS_CNT];
+ const struct sky1_audss_clks_devtype_data *devtype_data;
+ spinlock_t lock;
+ struct clk_hw_onecell_data *clk_data;
+};
+
+#if IS_ENABLED(CONFIG_RESET_SKY1_AUDSS)
+
+static int sky1_audss_reset_controller_register(struct device *dev)
+{
+ struct auxiliary_device *adev;
+
+ if (!of_property_present(dev->of_node, "#reset-cells"))
+ return 0;
+
+ adev = devm_auxiliary_device_create(dev, "reset", NULL);
+ if (!adev)
+ return -ENODEV;
+
+ return 0;
+}
+
+#else
+
+static int sky1_audss_reset_controller_register(struct device *dev)
+{
+ return 0;
+}
+
+#endif
+
+/*
+ * clk_ops for audss clock mux/divider/gate
+ */
+struct sky1_clk_divider {
+ struct clk_divider div;
+ struct regmap *regmap;
+ int offset;
+};
+
+struct sky1_clk_gate {
+ struct clk_gate gate;
+ struct regmap *regmap;
+ int offset;
+};
+
+struct sky1_clk_mux {
+ struct clk_mux mux;
+ struct regmap *regmap;
+ int offset;
+};
+
+static inline struct sky1_clk_mux *to_sky1_clk_mux(struct clk_mux *mux)
+{
+ return container_of(mux, struct sky1_clk_mux, mux);
+}
+
+static u8 sky1_audss_clk_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_mux *mux = to_clk_mux(hw);
+ struct sky1_clk_mux *sky1_mux = to_sky1_clk_mux(mux);
+ u32 val;
+
+ regmap_read(sky1_mux->regmap, sky1_mux->offset, &val);
+ val = val >> mux->shift;
+ val &= mux->mask;
+
+ return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
+}
+
+static int sky1_audss_clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_mux *mux = to_clk_mux(hw);
+ u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
+ struct sky1_clk_mux *sky1_mux = to_sky1_clk_mux(mux);
+ unsigned long flags = 0;
+ u32 reg;
+
+ if (mux->lock)
+ spin_lock_irqsave(mux->lock, flags);
+ else
+ __acquire(mux->lock);
+
+ if (mux->flags & CLK_MUX_HIWORD_MASK) {
+ reg = mux->mask << (mux->shift + 16);
+ } else {
+ regmap_read(sky1_mux->regmap, sky1_mux->offset, ®);
+ reg &= ~(mux->mask << mux->shift);
+ }
+ val = val << mux->shift;
+ reg |= val;
+ regmap_write(sky1_mux->regmap, sky1_mux->offset, reg);
+
+ if (mux->lock)
+ spin_unlock_irqrestore(mux->lock, flags);
+ else
+ __release(mux->lock);
+
+ return 0;
+}
+
+static int sky1_audss_clk_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_mux *mux = to_clk_mux(hw);
+
+ return clk_mux_determine_rate_flags(hw, req, mux->flags);
+}
+
+static const struct clk_ops sky1_audss_clk_mux_ops = {
+ .get_parent = sky1_audss_clk_mux_get_parent,
+ .set_parent = sky1_audss_clk_mux_set_parent,
+ .determine_rate = sky1_audss_clk_mux_determine_rate,
+};
+
+static inline struct sky1_clk_divider *to_sky1_clk_divider(struct clk_divider *div)
+{
+ return container_of(div, struct sky1_clk_divider, div);
+}
+
+static unsigned long sky1_audss_clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
+ unsigned int val;
+
+ regmap_read(sky1_div->regmap, sky1_div->offset, &val);
+ val = val >> divider->shift;
+ val &= clk_div_mask(divider->width);
+
+ return divider_recalc_rate(hw, parent_rate, val, divider->table,
+ divider->flags, divider->width);
+}
+
+static int sky1_audss_clk_divider_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
+
+ /* if read only, just return current value */
+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+ u32 val;
+
+ regmap_read(sky1_div->regmap, sky1_div->offset, &val);
+ val = val >> divider->shift;
+ val &= clk_div_mask(divider->width);
+
+ return divider_ro_determine_rate(hw, req, divider->table,
+ divider->width,
+ divider->flags, val);
+ }
+
+ return divider_determine_rate(hw, req, divider->table, divider->width,
+ divider->flags);
+}
+
+static int sky1_audss_clk_divider_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
+ int value;
+ unsigned long flags = 0;
+ u32 val;
+
+ value = divider_get_val(rate, parent_rate, divider->table,
+ divider->width, divider->flags);
+ if (value < 0)
+ return value;
+
+ if (divider->lock)
+ spin_lock_irqsave(divider->lock, flags);
+ else
+ __acquire(divider->lock);
+
+ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
+ val = clk_div_mask(divider->width) << (divider->shift + 16);
+ } else {
+ regmap_read(sky1_div->regmap, sky1_div->offset, &val);
+ val &= ~(clk_div_mask(divider->width) << divider->shift);
+ }
+ val |= (u32)value << divider->shift;
+ regmap_write(sky1_div->regmap, sky1_div->offset, val);
+
+ if (divider->lock)
+ spin_unlock_irqrestore(divider->lock, flags);
+ else
+ __release(divider->lock);
+
+ return 0;
+}
+
+static const struct clk_ops sky1_audss_clk_divider_ops = {
+ .recalc_rate = sky1_audss_clk_divider_recalc_rate,
+ .determine_rate = sky1_audss_clk_divider_determine_rate,
+ .set_rate = sky1_audss_clk_divider_set_rate,
+};
+
+static inline struct sky1_clk_gate *to_sky1_clk_gate(struct clk_gate *gate)
+{
+ return container_of(gate, struct sky1_clk_gate, gate);
+}
+
+static void sky1_audss_clk_gate_endisable(struct clk_hw *hw, int enable)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct sky1_clk_gate *sky1_gate = to_sky1_clk_gate(gate);
+ int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
+ unsigned long flags = 0;
+ u32 reg;
+
+ set ^= enable;
+
+ if (gate->lock)
+ spin_lock_irqsave(gate->lock, flags);
+ else
+ __acquire(gate->lock);
+
+ if (gate->flags & CLK_GATE_HIWORD_MASK) {
+ reg = BIT(gate->bit_idx + 16);
+ if (set)
+ reg |= BIT(gate->bit_idx);
+ } else {
+ regmap_read(sky1_gate->regmap, sky1_gate->offset, ®);
+
+ if (set)
+ reg |= BIT(gate->bit_idx);
+ else
+ reg &= ~BIT(gate->bit_idx);
+ }
+
+ regmap_write(sky1_gate->regmap, sky1_gate->offset, reg);
+
+ if (gate->lock)
+ spin_unlock_irqrestore(gate->lock, flags);
+ else
+ __release(gate->lock);
+}
+
+static int sky1_audss_clk_gate_enable(struct clk_hw *hw)
+{
+ sky1_audss_clk_gate_endisable(hw, 1);
+
+ return 0;
+}
+
+static void sky1_audss_clk_gate_disable(struct clk_hw *hw)
+{
+ sky1_audss_clk_gate_endisable(hw, 0);
+}
+
+static int sky1_audss_clk_gate_is_enabled(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct sky1_clk_gate *sky1_gate = to_sky1_clk_gate(gate);
+ u32 reg;
+
+ regmap_read(sky1_gate->regmap, sky1_gate->offset, ®);
+
+ /* if a set bit disables this clk, flip it before masking */
+ if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+ reg ^= BIT(gate->bit_idx);
+
+ reg &= BIT(gate->bit_idx);
+
+ return !!reg;
+}
+
+static const struct clk_ops sky1_audss_clk_gate_ops = {
+ .enable = sky1_audss_clk_gate_enable,
+ .disable = sky1_audss_clk_gate_disable,
+ .is_enabled = sky1_audss_clk_gate_is_enabled,
+};
+
+static struct clk_hw *sky1_audss_clk_register(struct device *dev,
+ const char *name,
+ const char * const *parent_names,
+ int num_parents,
+ struct regmap *regmap,
+ const u32 *mux_table,
+ struct muxdiv_cfg *mux_cfg,
+ struct muxdiv_cfg *div_cfg,
+ struct gate_cfg *gate_cfg,
+ unsigned long flags,
+ spinlock_t *lock)
+{
+ const struct clk_ops *sky1_mux_ops = NULL;
+ const struct clk_ops *sky1_div_ops = NULL;
+ const struct clk_ops *sky1_gate_ops = NULL;
+ struct clk_hw *hw = ERR_PTR(-ENOMEM);
+ struct sky1_clk_divider *sky1_div = NULL;
+ struct sky1_clk_gate *sky1_gate = NULL;
+ struct sky1_clk_mux *sky1_mux = NULL;
+
+ if (mux_cfg->offset >= 0) {
+ sky1_mux = devm_kzalloc(dev, sizeof(*sky1_mux), GFP_KERNEL);
+ if (!sky1_mux)
+ return ERR_PTR(-ENOMEM);
+
+ sky1_mux->mux.reg = NULL;
+ sky1_mux->mux.shift = mux_cfg->shift;
+ sky1_mux->mux.mask = BIT(mux_cfg->width) - 1;
+ sky1_mux->mux.flags = mux_cfg->flags;
+ sky1_mux->mux.table = mux_table;
+ sky1_mux->mux.lock = lock;
+ sky1_mux_ops = &sky1_audss_clk_mux_ops;
+ sky1_mux->regmap = regmap;
+ sky1_mux->offset = mux_cfg->offset;
+ }
+
+ if (div_cfg->offset >= 0) {
+ sky1_div = devm_kzalloc(dev, sizeof(*sky1_div), GFP_KERNEL);
+ if (!sky1_div)
+ return ERR_PTR(-ENOMEM);
+
+ sky1_div->div.reg = NULL;
+ sky1_div->div.shift = div_cfg->shift;
+ sky1_div->div.width = div_cfg->width;
+ sky1_div->div.flags = div_cfg->flags | CLK_DIVIDER_POWER_OF_TWO;
+ sky1_div->div.lock = lock;
+ sky1_div_ops = &sky1_audss_clk_divider_ops;
+ sky1_div->regmap = regmap;
+ sky1_div->offset = div_cfg->offset;
+ }
+
+ if (gate_cfg->offset >= 0) {
+ sky1_gate = devm_kzalloc(dev, sizeof(*sky1_gate), GFP_KERNEL);
+ if (!sky1_gate)
+ return ERR_PTR(-ENOMEM);
+
+ sky1_gate->gate.reg = NULL;
+ sky1_gate->gate.bit_idx = gate_cfg->shift;
+ sky1_gate->gate.flags = gate_cfg->flags;
+ sky1_gate->gate.lock = lock;
+ sky1_gate_ops = &sky1_audss_clk_gate_ops;
+ sky1_gate->regmap = regmap;
+ sky1_gate->offset = gate_cfg->offset;
+ }
+
+ hw = clk_hw_register_composite(dev, name, parent_names, num_parents,
+ sky1_mux ? &sky1_mux->mux.hw : NULL, sky1_mux_ops,
+ sky1_div ? &sky1_div->div.hw : NULL, sky1_div_ops,
+ sky1_gate ? &sky1_gate->gate.hw : NULL, sky1_gate_ops,
+ flags);
+ if (IS_ERR(hw)) {
+ dev_err(dev, "register %s clock failed with err = %ld\n",
+ name, PTR_ERR(hw));
+ return hw;
+ }
+
+ return hw;
+}
+
+static int sky1_audss_clks_get(struct sky1_audss_clks_priv *priv)
+{
+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
+ int i;
+
+ for (i = 0; i < devtype_data->clk_num; i++) {
+ priv->clks[i] = devm_clk_get(priv->dev, devtype_data->clk_names[i]);
+ if (IS_ERR(priv->clks[i]))
+ return dev_err_probe(priv->dev, PTR_ERR(priv->clks[i]),
+ "failed to get clock %s", devtype_data->clk_names[i]);
+ }
+
+ return 0;
+}
+
+static int sky1_audss_clks_enable(struct sky1_audss_clks_priv *priv)
+{
+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
+ int i, err;
+
+ for (i = 0; i < devtype_data->clk_num; i++) {
+ err = clk_prepare_enable(priv->clks[i]);
+ if (err) {
+ dev_err(priv->dev, "failed to enable clock %s\n",
+ devtype_data->clk_names[i]);
+ goto err_clks;
+ }
+ }
+
+ return 0;
+
+err_clks:
+ while (--i >= 0)
+ clk_disable_unprepare(priv->clks[i]);
+
+ return err;
+}
+
+static void sky1_audss_clks_disable(struct sky1_audss_clks_priv *priv)
+{
+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
+ int i;
+
+ for (i = 0; i < devtype_data->clk_num; i++)
+ clk_disable_unprepare(priv->clks[i]);
+}
+
+static int sky1_audss_clks_set_rate(struct sky1_audss_clks_priv *priv)
+{
+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
+ int i, err;
+
+ for (i = 0; i < devtype_data->clk_num; i++) {
+ err = clk_set_rate(priv->clks[i], devtype_data->clk_rate_default[i]);
+ if (err) {
+ dev_err(priv->dev, "failed to set clock rate %s\n",
+ devtype_data->clk_names[i]);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/* register sky1 audio subsystem clocks */
+static int sky1_audss_clk_probe(struct platform_device *pdev)
+{
+ const struct sky1_audss_clks_devtype_data *devtype_data;
+ struct sky1_audss_clks_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct clk_hw **clk_table;
+ void __iomem *base;
+ int i, ret;
+
+ devtype_data = device_get_match_data(dev);
+ if (!devtype_data)
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->lock);
+
+ priv->clk_data = devm_kzalloc(dev,
+ struct_size(priv->clk_data, hws, SKY1_AUDSS_NUM_CLKS),
+ GFP_KERNEL);
+ if (!priv->clk_data)
+ return -ENOMEM;
+
+ priv->clk_data->num = SKY1_AUDSS_NUM_CLKS;
+ clk_table = priv->clk_data->hws;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap_cru = devm_regmap_init_mmio(dev, base, &sky1_audss_regmap_config);
+ if (IS_ERR(priv->regmap_cru))
+ return dev_err_probe(dev, PTR_ERR(priv->regmap_cru),
+ "failed to initialize regmap\n");
+
+ priv->dev = dev;
+ priv->devtype_data = devtype_data;
+
+ priv->rst_noc = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(priv->rst_noc))
+ return dev_err_probe(dev, PTR_ERR(priv->rst_noc),
+ "failed to get audss noc reset");
+
+ reset_control_deassert(priv->rst_noc);
+
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ platform_set_drvdata(pdev, priv);
+
+ ret = sky1_audss_clks_get(priv);
+ if (ret)
+ goto err_pm;
+
+ ret = sky1_audss_clks_enable(priv);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks\n");
+ goto err_pm;
+ }
+
+ ret = sky1_audss_clks_set_rate(priv);
+ if (ret) {
+ dev_err(dev, "failed to set clocks rate\n");
+ goto fail_clks_set;
+ }
+
+ /* audio_clk4 clock fixed divider */
+ clk_table[CLK_AUD_CLK4_DIV2] =
+ devm_clk_hw_register_fixed_factor(dev,
+ "audio_clk4_div2",
+ "audio_clk4",
+ 0,
+ 1, 2);
+ if (IS_ERR(clk_table[CLK_AUD_CLK4_DIV2])) {
+ ret = PTR_ERR(clk_table[CLK_AUD_CLK4_DIV2]);
+ dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK4_DIV2, ret);
+ goto fail_fixed_clk;
+ }
+
+ clk_table[CLK_AUD_CLK4_DIV4] =
+ devm_clk_hw_register_fixed_factor(dev,
+ "audio_clk4_div4",
+ "audio_clk4",
+ 0,
+ 1, 4);
+ if (IS_ERR(clk_table[CLK_AUD_CLK4_DIV4])) {
+ ret = PTR_ERR(clk_table[CLK_AUD_CLK4_DIV4]);
+ dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK4_DIV4, ret);
+ goto fail_fixed_clk;
+ }
+
+ /* audio_clk5 clock fixed divider */
+ clk_table[CLK_AUD_CLK5_DIV2] =
+ devm_clk_hw_register_fixed_factor(dev,
+ "audio_clk5_div2",
+ "audio_clk5",
+ 0,
+ 1, 2);
+ if (IS_ERR(clk_table[CLK_AUD_CLK5_DIV2])) {
+ ret = PTR_ERR(clk_table[CLK_AUD_CLK5_DIV2]);
+ dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK5_DIV2, ret);
+ goto fail_fixed_clk;
+ }
+
+ for (i = 0; i < devtype_data->clk_cfg_size; i++) {
+ clk_table[devtype_data->clk_cfg[i].id] =
+ sky1_audss_clk_register(dev,
+ devtype_data->clk_cfg[i].name,
+ devtype_data->clk_cfg[i].parent_names,
+ devtype_data->clk_cfg[i].num_parents,
+ priv->regmap_cru,
+ devtype_data->clk_cfg[i].mux_table,
+ devtype_data->clk_cfg[i].mux_cfg,
+ devtype_data->clk_cfg[i].div_cfg,
+ devtype_data->clk_cfg[i].gate_cfg,
+ devtype_data->clk_cfg[i].flags,
+ &priv->lock);
+ if (IS_ERR(clk_table[devtype_data->clk_cfg[i].id])) {
+ ret = PTR_ERR(clk_table[devtype_data->clk_cfg[i].id]);
+ dev_err(dev, "failed to register clock %d, ret:%d\n",
+ devtype_data->clk_cfg[i].id, ret);
+ goto fail_array_clk;
+ }
+ }
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, priv->clk_data);
+ if (ret) {
+ dev_err(dev, "failed to add clock provider: %d\n", ret);
+ goto fail_register;
+ }
+
+ ret = sky1_audss_reset_controller_register(dev);
+ if (ret)
+ goto fail_register;
+
+ pm_runtime_put_sync(dev);
+
+ return 0;
+
+fail_register:
+fail_array_clk:
+ while (i--)
+ clk_hw_unregister_composite(clk_table[devtype_data->clk_cfg[i].id]);
+fail_fixed_clk:
+fail_clks_set:
+ pm_runtime_put_sync(dev);
+err_pm:
+ pm_runtime_disable(dev);
+ return ret;
+}
+
+static void sky1_audss_clk_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev);
+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
+ int i = 0;
+
+ for (i = 0; i < devtype_data->clk_cfg_size; i++)
+ clk_hw_unregister_composite(priv->clk_data->hws[devtype_data->clk_cfg[i].id]);
+
+ if (!pm_runtime_status_suspended(dev))
+ pm_runtime_force_suspend(dev);
+
+ pm_runtime_disable(dev);
+}
+
+static int __maybe_unused sky1_audss_clk_runtime_suspend(struct device *dev)
+{
+ struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev);
+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ for (i = 0; i < devtype_data->reg_save_size; i++)
+ regmap_read(priv->regmap_cru,
+ devtype_data->reg_save[i][0], &devtype_data->reg_save[i][1]);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ sky1_audss_clks_disable(priv);
+
+ return reset_control_assert(priv->rst_noc);
+}
+
+static int __maybe_unused sky1_audss_clk_runtime_resume(struct device *dev)
+{
+ struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev);
+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
+ unsigned long flags;
+ int i, ret;
+
+ ret = reset_control_deassert(priv->rst_noc);
+ if (ret)
+ return ret;
+
+ ret = sky1_audss_clks_enable(priv);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks\n");
+ return ret;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ for (i = 0; i < devtype_data->reg_save_size; i++)
+ regmap_write(priv->regmap_cru,
+ devtype_data->reg_save[i][0], devtype_data->reg_save[i][1]);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static const struct dev_pm_ops sky1_audss_clk_pm_ops = {
+ SET_RUNTIME_PM_OPS(sky1_audss_clk_runtime_suspend,
+ sky1_audss_clk_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static const struct sky1_audss_clks_devtype_data sky1_devtype_data = {
+ .reg_save = sky1_reg_save,
+ .reg_save_size = ARRAY_SIZE(sky1_reg_save),
+ .clk_names = sky1_audss_clk_names,
+ .clk_num = ARRAY_SIZE(sky1_audss_clk_names),
+ .clk_rate_default = sky1_clk_rate_default,
+ .clk_cfg = sky1_audss_clks,
+ .clk_cfg_size = ARRAY_SIZE(sky1_audss_clks),
+};
+
+static const struct of_device_id sky1_audss_clk_of_match[] = {
+ { .compatible = "cix,sky1-audss-cru", .data = &sky1_devtype_data, },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sky1_audss_clk_of_match);
+
+static struct platform_driver sky1_audss_clk_driver = {
+ .probe = sky1_audss_clk_probe,
+ .remove = sky1_audss_clk_remove,
+ .driver = {
+ .name = "sky1-audss-clk",
+ .suppress_bind_attrs = true,
+ .of_match_table = sky1_audss_clk_of_match,
+ .pm = &sky1_audss_clk_pm_ops,
+ },
+};
+module_platform_driver(sky1_audss_clk_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
+MODULE_DESCRIPTION("Cixtech Sky1 Audio Subsystem Clock Controller Driver");
--
2.50.1
^ permalink raw reply related
* [PATCH v6 1/4] dt-bindings: soc: cix: add sky1 audss cru controller
From: joakim.zhang @ 2026-06-23 7:08 UTC (permalink / raw)
To: mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt, p.zabel,
gary.yang
Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Joakim Zhang
In-Reply-To: <20260623070805.211019-1-joakim.zhang@cixtech.com>
From: Joakim Zhang <joakim.zhang@cixtech.com>
The Cix Sky1 Audio Subsystem (AUDSS) Clock and Reset Unit (CRU)
groups clock muxing, gating and block-level software reset control
in a single register block.
Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
---
.../bindings/soc/cix/cix,sky1-audss-cru.yaml | 92 +++++++++++++++++++
.../dt-bindings/clock/cix,sky1-audss-cru.h | 60 ++++++++++++
.../dt-bindings/reset/cix,sky1-audss-cru.h | 25 +++++
3 files changed, 177 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/cix/cix,sky1-audss-cru.yaml
create mode 100644 include/dt-bindings/clock/cix,sky1-audss-cru.h
create mode 100644 include/dt-bindings/reset/cix,sky1-audss-cru.h
diff --git a/Documentation/devicetree/bindings/soc/cix/cix,sky1-audss-cru.yaml b/Documentation/devicetree/bindings/soc/cix/cix,sky1-audss-cru.yaml
new file mode 100644
index 000000000000..50dd0593e1d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/cix/cix,sky1-audss-cru.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/cix/cix,sky1-audss-cru.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cix Sky1 audio subsystem clock and reset unit
+
+maintainers:
+ - Joakim Zhang <joakim.zhang@cixtech.com>
+
+description: |
+ The Cix Sky1 Audio Subsystem (AUDSS) Clock and Reset Unit (CRU) groups
+ audio-related clock muxing, gating and block-level software reset control
+ in a single register block.
+
+ A single device node exposes both the clock controller and software reset
+ lines. The clock driver registers as a platform driver; the reset controller
+ is registered by an auxiliary driver bound from the clock driver.
+
+ Four SoC-level reference clocks listed in clocks/clock-names feed the AUDSS
+ clock tree. Internal AUDSS clocks are exposed via #clock-cells; indices are
+ defined in include/dt-bindings/clock/cix,sky1-audss-cru.h.
+
+ Block-level software reset indices are exposed via #reset-cells; indices
+ are defined in include/dt-bindings/reset/cix,sky1-audss-cru.h.
+
+ The SoC syscon NoC (or bus) reset is described via resets. The audio
+ subsystem power domain is described via power-domains.
+
+properties:
+ compatible:
+ const: cix,sky1-audss-cru
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+ description:
+ Clock indices are defined in include/dt-bindings/clock/cix,sky1-audss-cru.h.
+
+ '#reset-cells':
+ const: 1
+ description:
+ Reset indices are defined in include/dt-bindings/reset/cix,sky1-audss-cru.h.
+
+ clocks:
+ items:
+ - description: I2S parent clock for sampling rates multiple of 8kHz.
+ - description: I2S parent clock for sampling rates multiple of 11.025kHz.
+ - description: Clock feeding most devices in AUDSS (NOC, DSP, SRAM, HDA, DMAC, I2S, and mailbox).
+ - description: Clock feeding HDA, timer and watchdog, which is a dedicated 48 MHz clock.
+
+ clock-names:
+ items:
+ - const: x8k
+ - const: x11k
+ - const: sys
+ - const: 48m
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+ - '#reset-cells'
+ - clocks
+ - clock-names
+ - power-domains
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ audss_cru: clock-controller@7110000 {
+ compatible = "cix,sky1-audss-cru";
+ reg = <0x7110000 0x10000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ clocks = <&scmi_clk 76>, <&scmi_clk 78>,
+ <&scmi_clk 70>, <&scmi_clk 71>;
+ clock-names = "x8k", "x11k", "sys", "48m";
+ power-domains = <&smc_devpd 0>;
+ resets = <&s5_syscon 31>;
+ };
diff --git a/include/dt-bindings/clock/cix,sky1-audss-cru.h b/include/dt-bindings/clock/cix,sky1-audss-cru.h
new file mode 100644
index 000000000000..8c58ef8bf682
--- /dev/null
+++ b/include/dt-bindings/clock/cix,sky1-audss-cru.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright 2026 Cix Technology Group Co., Ltd.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_CIX_SKY1_AUDSS_CRU_H
+#define _DT_BINDINGS_CLOCK_CIX_SKY1_AUDSS_CRU_H
+
+#define CLK_AUD_CLK4_DIV2 0
+#define CLK_AUD_CLK4_DIV4 1
+#define CLK_AUD_CLK5_DIV2 2
+
+#define CLK_DSP_CLK 3
+#define CLK_DSP_BCLK 4
+#define CLK_DSP_PBCLK 5
+
+#define CLK_SRAM_AXI 6
+
+#define CLK_HDA_SYS 7
+#define CLK_HDA_HDA 8
+
+#define CLK_DMAC_AXI 9
+
+#define CLK_WDG_APB 10
+#define CLK_WDG_WDG 11
+
+#define CLK_TIMER_APB 12
+#define CLK_TIMER_TIMER 13
+
+#define CLK_MB_0_APB 14 /* MB0: ap->dsp */
+#define CLK_MB_1_APB 15 /* MB1: dsp->ap */
+
+#define CLK_I2S0_APB 16
+#define CLK_I2S1_APB 17
+#define CLK_I2S2_APB 18
+#define CLK_I2S3_APB 19
+#define CLK_I2S4_APB 20
+#define CLK_I2S5_APB 21
+#define CLK_I2S6_APB 22
+#define CLK_I2S7_APB 23
+#define CLK_I2S8_APB 24
+#define CLK_I2S9_APB 25
+#define CLK_I2S0 26
+#define CLK_I2S1 27
+#define CLK_I2S2 28
+#define CLK_I2S3 29
+#define CLK_I2S4 30
+#define CLK_I2S5 31
+#define CLK_I2S6 32
+#define CLK_I2S7 33
+#define CLK_I2S8 34
+#define CLK_I2S9 35
+
+#define CLK_MCLK0 36
+#define CLK_MCLK1 37
+#define CLK_MCLK2 38
+#define CLK_MCLK3 39
+#define CLK_MCLK4 40
+
+#endif
diff --git a/include/dt-bindings/reset/cix,sky1-audss-cru.h b/include/dt-bindings/reset/cix,sky1-audss-cru.h
new file mode 100644
index 000000000000..55e9f3797b30
--- /dev/null
+++ b/include/dt-bindings/reset/cix,sky1-audss-cru.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright 2026 Cix Technology Group Co., Ltd.
+ */
+#ifndef DT_BINDINGS_RESET_CIX_SKY1_AUDSS_CRU_H
+#define DT_BINDINGS_RESET_CIX_SKY1_AUDSS_CRU_H
+
+#define AUDSS_I2S0_SW_RST 0
+#define AUDSS_I2S1_SW_RST 1
+#define AUDSS_I2S2_SW_RST 2
+#define AUDSS_I2S3_SW_RST 3
+#define AUDSS_I2S4_SW_RST 4
+#define AUDSS_I2S5_SW_RST 5
+#define AUDSS_I2S6_SW_RST 6
+#define AUDSS_I2S7_SW_RST 7
+#define AUDSS_I2S8_SW_RST 8
+#define AUDSS_I2S9_SW_RST 9
+#define AUDSS_WDT_SW_RST 10
+#define AUDSS_TIMER_SW_RST 11
+#define AUDSS_MB0_SW_RST 12
+#define AUDSS_MB1_SW_RST 13
+#define AUDSS_HDA_SW_RST 14
+#define AUDSS_DMAC_SW_RST 15
+
+#endif
--
2.50.1
^ permalink raw reply related
* [PATCH v6 3/4] reset: cix: add sky1 audss auxiliary reset driver
From: joakim.zhang @ 2026-06-23 7:08 UTC (permalink / raw)
To: mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt, p.zabel,
gary.yang
Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Joakim Zhang
In-Reply-To: <20260623070805.211019-1-joakim.zhang@cixtech.com>
From: Joakim Zhang <joakim.zhang@cixtech.com>
Add an auxiliary reset controller driver for the AUDSS CRU. Sixteen
software reset lines for audio subsystem peripherals are controlled
through one register in the CRU register map.
The driver is created by the AUDSS clock platform driver and registers
the reset controller on the CRU device node.
Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
---
drivers/reset/Kconfig | 14 +++
drivers/reset/Makefile | 1 +
drivers/reset/reset-sky1-audss.c | 192 +++++++++++++++++++++++++++++++
3 files changed, 207 insertions(+)
create mode 100644 drivers/reset/reset-sky1-audss.c
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index d009eb0849a3..f74859b292ae 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -300,6 +300,20 @@ config RESET_SKY1
help
This enables the reset controller for Cix Sky1.
+config RESET_SKY1_AUDSS
+ tristate "Cix Sky1 Audio Subsystem reset controller"
+ depends on ARCH_CIX || COMPILE_TEST
+ select AUXILIARY_BUS
+ select REGMAP_MMIO
+ default CLK_SKY1_AUDSS
+ help
+ Support for block-level software reset lines in the Cix Sky1
+ Audio Subsystem (AUDSS) Clock and Reset Unit. Sixteen reset
+ outputs for audio peripherals are controlled through the CRU
+ register map. The driver binds as an auxiliary device from
+ the AUDSS clock driver. Say M or Y here if you want to build
+ this driver.
+
config RESET_SOCFPGA
bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)
default ARM && ARCH_INTEL_SOCFPGA
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 3e52569bd276..e81407ea3e29 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_RESET_RZV2H_USB2PHY) += reset-rzv2h-usb2phy.o
obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
obj-$(CONFIG_RESET_SKY1) += reset-sky1.o
+obj-$(CONFIG_RESET_SKY1_AUDSS) += reset-sky1-audss.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
diff --git a/drivers/reset/reset-sky1-audss.c b/drivers/reset/reset-sky1-audss.c
new file mode 100644
index 000000000000..20870f37d7d7
--- /dev/null
+++ b/drivers/reset/reset-sky1-audss.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cix Sky1 Audio Subsystem reset controller driver
+ *
+ * Copyright 2026 Cix Technology Group Co., Ltd.
+ */
+
+#include <dt-bindings/reset/cix,sky1-audss-cru.h>
+
+#include <linux/auxiliary_bus.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#define SKY1_RESET_SLEEP_MIN_US 50
+#define SKY1_RESET_SLEEP_MAX_US 100
+
+#define AUDSS_SW_RST 0x78
+
+struct sky1_audss_reset_map {
+ unsigned int offset;
+ unsigned int mask;
+};
+
+struct sky1_audss_reset {
+ struct reset_controller_dev rcdev;
+ struct regmap *regmap;
+ const struct sky1_audss_reset_map *map;
+};
+
+static const struct sky1_audss_reset_map sky1_audss_reset_map[] = {
+ [AUDSS_I2S0_SW_RST] = { AUDSS_SW_RST, BIT(0) },
+ [AUDSS_I2S1_SW_RST] = { AUDSS_SW_RST, BIT(1) },
+ [AUDSS_I2S2_SW_RST] = { AUDSS_SW_RST, BIT(2) },
+ [AUDSS_I2S3_SW_RST] = { AUDSS_SW_RST, BIT(3) },
+ [AUDSS_I2S4_SW_RST] = { AUDSS_SW_RST, BIT(4) },
+ [AUDSS_I2S5_SW_RST] = { AUDSS_SW_RST, BIT(5) },
+ [AUDSS_I2S6_SW_RST] = { AUDSS_SW_RST, BIT(6) },
+ [AUDSS_I2S7_SW_RST] = { AUDSS_SW_RST, BIT(7) },
+ [AUDSS_I2S8_SW_RST] = { AUDSS_SW_RST, BIT(8) },
+ [AUDSS_I2S9_SW_RST] = { AUDSS_SW_RST, BIT(9) },
+ [AUDSS_WDT_SW_RST] = { AUDSS_SW_RST, BIT(10) },
+ [AUDSS_TIMER_SW_RST] = { AUDSS_SW_RST, BIT(11) },
+ [AUDSS_MB0_SW_RST] = { AUDSS_SW_RST, BIT(12) },
+ [AUDSS_MB1_SW_RST] = { AUDSS_SW_RST, BIT(13) },
+ [AUDSS_HDA_SW_RST] = { AUDSS_SW_RST, BIT(14) },
+ [AUDSS_DMAC_SW_RST] = { AUDSS_SW_RST, BIT(15) },
+};
+
+static struct sky1_audss_reset *to_sky1_audss_reset(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct sky1_audss_reset, rcdev);
+}
+
+static int sky1_audss_reset_set(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct sky1_audss_reset *priv = to_sky1_audss_reset(rcdev);
+ const struct sky1_audss_reset_map *signal = &priv->map[id];
+ unsigned int value = assert ? 0 : signal->mask;
+
+ return regmap_update_bits(priv->regmap, signal->offset, signal->mask, value);
+}
+
+static int sky1_audss_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ sky1_audss_reset_set(rcdev, id, true);
+ usleep_range(SKY1_RESET_SLEEP_MIN_US, SKY1_RESET_SLEEP_MAX_US);
+ return 0;
+}
+
+static int sky1_audss_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ sky1_audss_reset_set(rcdev, id, false);
+ usleep_range(SKY1_RESET_SLEEP_MIN_US, SKY1_RESET_SLEEP_MAX_US);
+ return 0;
+}
+
+static int sky1_audss_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ sky1_audss_reset_assert(rcdev, id);
+ sky1_audss_reset_deassert(rcdev, id);
+ return 0;
+}
+
+static int sky1_audss_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct sky1_audss_reset *priv = to_sky1_audss_reset(rcdev);
+ const struct sky1_audss_reset_map *signal = &priv->map[id];
+ unsigned int value;
+
+ regmap_read(priv->regmap, signal->offset, &value);
+ return !!(value & signal->mask);
+}
+
+static const struct reset_control_ops sky1_audss_reset_ops = {
+ .reset = sky1_audss_reset,
+ .assert = sky1_audss_reset_assert,
+ .deassert = sky1_audss_reset_deassert,
+ .status = sky1_audss_reset_status,
+};
+
+static const struct regmap_config sky1_audss_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static void sky1_audss_reset_iounmap(void *data)
+{
+ iounmap(data);
+}
+
+static int sky1_audss_reset_get_regmap(struct sky1_audss_reset *priv)
+{
+ struct device *dev = priv->rcdev.dev;
+ void __iomem *base;
+ int ret;
+
+ priv->regmap = dev_get_regmap(dev->parent, NULL);
+ if (priv->regmap)
+ return 0;
+
+ base = of_iomap(dev->parent->of_node, 0);
+ if (!base)
+ return dev_err_probe(dev, -ENOMEM, "failed to iomap address space\n");
+
+ ret = devm_add_action_or_reset(dev, sky1_audss_reset_iounmap, base);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register iounmap action\n");
+
+ priv->regmap = devm_regmap_init_mmio(dev, base, &sky1_audss_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->regmap),
+ "failed to initialize regmap\n");
+
+ return 0;
+}
+
+static int sky1_audss_reset_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct sky1_audss_reset *priv;
+ struct device *dev = &adev->dev;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->map = sky1_audss_reset_map;
+ priv->rcdev.owner = THIS_MODULE;
+ priv->rcdev.nr_resets = ARRAY_SIZE(sky1_audss_reset_map);
+ priv->rcdev.ops = &sky1_audss_reset_ops;
+ priv->rcdev.of_node = dev->parent->of_node;
+ priv->rcdev.dev = dev;
+ priv->rcdev.of_reset_n_cells = 1;
+
+ dev_set_drvdata(dev, priv);
+
+ ret = sky1_audss_reset_get_regmap(priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get regmap\n");
+
+ return devm_reset_controller_register(dev, &priv->rcdev);
+}
+
+static const struct auxiliary_device_id sky1_audss_reset_ids[] = {
+ { .name = "clk_sky1_audss.reset" },
+ { }
+};
+MODULE_DEVICE_TABLE(auxiliary, sky1_audss_reset_ids);
+
+static struct auxiliary_driver sky1_audss_reset_driver = {
+ .probe = sky1_audss_reset_probe,
+ .id_table = sky1_audss_reset_ids,
+};
+
+module_auxiliary_driver(sky1_audss_reset_driver);
+
+MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
+MODULE_DESCRIPTION("Cix Sky1 Audio Subsystem reset driver");
+MODULE_LICENSE("GPL");
--
2.50.1
^ permalink raw reply related
* [PATCH v6 0/4] Add Cix Sky1 AUDSS clock and reset support
From: joakim.zhang @ 2026-06-23 7:08 UTC (permalink / raw)
To: mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt, p.zabel,
gary.yang
Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Joakim Zhang
From: Joakim Zhang <joakim.zhang@cixtech.com>
The Cix Sky1 Audio Subsystem (AUDSS) groups audio-related blocks such as
HDA, I2S, DSP, DMA, mailboxes, watchdog and timer behind one Clock and
Reset Unit (CRU). The CRU is a single MMIO register block that provides
clock muxing, gating and block-level software reset lines for those
peripherals.
Clock and reset support are submitted in one series because they belong
to the same hardware block and share one devicetree node
(cix,sky1-audss-cru). The binding, clock indices and reset indices are
defined together; the clock driver maps the CRU and instantiates the
reset controller as an auxiliary driver on that node. Splitting clk and
reset across separate series would leave neither side self-contained: the
DTS node needs both providers, and the reset driver has no standalone
probe path without the clock driver.
---
ChangeLogs:
v5->v6:
* rename dt-bindings headers to cix,sky1-audss-cru.h to match compatible
* drop status = "okay" from audss_cru node in sky1.dtsi
v4->v5:
* refactor the driver, using platform_driver for clk and auxiliary_driver
for reset.
v3->v4:
* move both power domain and resets into parset node (audss_cru)
* remove "simple-mfd", and change to populate the child node
* cix,sky1-audss.h -> cix,sky1-audss-clock.h
v2->v3:
* clk part:
* devm_reset_control_get()->devm_reset_control_get_exclusive()
* assert noc reset from suspend
* clock parents changes from 6 to 4, and rename the clock names,
explain more about this: confirm with our designer, In fact,
there are 6 clock sources going into the audio subsystem. audio_clk1
and audio_clk3 are redundant in design and are not actually needed
in practice, so they are not shown here.
* refine clocks and clock-names property
* add detailed description of clocks
* drop parent node from clk binding
* drop define AUDSS_MAX_CLKS
* reset part:
* rename reset signal macro, remove _N
* drop SKY1_AUDSS_SW_RESET_NUM
* switching to compatible-style of defining subnodes in parent schema
v1->v2:
* remove audss_rst device node since it doesn't has resource, and
move to reset-sky1.c driver.
* remove hda related which would be sent after this patch set accepted
* soc componnet is okay by default from dtsi
* fix for audss clk driver:
* remove "comment "Clock options for Cixtech audss:""
* add select MFD_SYSCON
* move lock and clk_data into struct sky1_audss_clks_priv
* const char *name -> const char * const * name
* remove CLK_GET_RATE_NOCACHE
* divicer -> divider
* Reverse Christmas tree order
* return reg ? 1 : 0; -> return !!reg;
* return ERR_CAST(hw); -> return hw;
* of_device_get_match_data(dev) -> device_get_match_data()
* add lock from runtime_suspend/resume
* loop to more mailing lists
Joakim Zhang (4):
dt-bindings: soc: cix: add sky1 audss cru controller
clk: cix: add sky1 audss clock controller
reset: cix: add sky1 audss auxiliary reset driver
arm64: dts: cix: sky1: add audss cru
.../bindings/soc/cix/cix,sky1-audss-cru.yaml | 92 ++
arch/arm64/boot/dts/cix/sky1.dtsi | 18 +
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/cix/Kconfig | 16 +
drivers/clk/cix/Makefile | 3 +
drivers/clk/cix/clk-sky1-audss.c | 1201 +++++++++++++++++
drivers/reset/Kconfig | 14 +
drivers/reset/Makefile | 1 +
drivers/reset/reset-sky1-audss.c | 192 +++
.../dt-bindings/clock/cix,sky1-audss-cru.h | 60 +
.../dt-bindings/reset/cix,sky1-audss-cru.h | 25 +
12 files changed, 1624 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/cix/cix,sky1-audss-cru.yaml
create mode 100644 drivers/clk/cix/Kconfig
create mode 100644 drivers/clk/cix/Makefile
create mode 100644 drivers/clk/cix/clk-sky1-audss.c
create mode 100644 drivers/reset/reset-sky1-audss.c
create mode 100644 include/dt-bindings/clock/cix,sky1-audss-cru.h
create mode 100644 include/dt-bindings/reset/cix,sky1-audss-cru.h
--
2.50.1
^ permalink raw reply
* [PATCH v6 4/4] arm64: dts: cix: sky1: add audss cru
From: joakim.zhang @ 2026-06-23 7:08 UTC (permalink / raw)
To: mturquette, sboyd, bmasney, robh, krzk+dt, conor+dt, p.zabel,
gary.yang
Cc: cix-kernel-upstream, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Joakim Zhang
In-Reply-To: <20260623070805.211019-1-joakim.zhang@cixtech.com>
From: Joakim Zhang <joakim.zhang@cixtech.com>
Add the AUDSS CRU device node providing clocks and software resets
for audio subsystem peripherals.
Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
---
arch/arm64/boot/dts/cix/sky1.dtsi | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/arch/arm64/boot/dts/cix/sky1.dtsi b/arch/arm64/boot/dts/cix/sky1.dtsi
index bb5cfb1f2113..6d045d7216e6 100644
--- a/arch/arm64/boot/dts/cix/sky1.dtsi
+++ b/arch/arm64/boot/dts/cix/sky1.dtsi
@@ -6,6 +6,10 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/cix,sky1.h>
+#include <dt-bindings/clock/cix,sky1-audss-cru.h>
+#include <dt-bindings/reset/cix,sky1-system-control.h>
+#include <dt-bindings/reset/cix,sky1-s5-system-control.h>
+#include <dt-bindings/reset/cix,sky1-audss-cru.h>
#include "sky1-power.h"
/ {
@@ -488,6 +492,20 @@ mbox_pm2ap: mailbox@65a0080 {
cix,mbox-dir = "rx";
};
+ audss_cru: clock-controller@7110000 {
+ compatible = "cix,sky1-audss-cru";
+ reg = <0x0 0x07110000 0x0 0x10000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ clocks = <&scmi_clk CLK_TREE_AUDIO_CLK0>,
+ <&scmi_clk CLK_TREE_AUDIO_CLK2>,
+ <&scmi_clk CLK_TREE_AUDIO_CLK4>,
+ <&scmi_clk CLK_TREE_AUDIO_CLK5>;
+ clock-names = "x8k", "x11k", "sys", "48m";
+ power-domains = <&smc_devpd SKY1_PD_AUDIO>;
+ resets = <&s5_syscon SKY1_AUDIO_HIFI5_NOC_RESET_N>;
+ };
+
mbox_sfh2ap: mailbox@8090000 {
compatible = "cix,sky1-mbox";
reg = <0x0 0x08090000 0x0 0x10000>;
--
2.50.1
^ permalink raw reply related
* RE: [PATCH v5 4/4] arm64: dts: cix: sky1: add audss cru
From: Joakim Zhang @ 2026-06-23 7:07 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: mturquette@baylibre.com, sboyd@kernel.org, bmasney@redhat.com,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
p.zabel@pengutronix.de, Gary Yang, cix-kernel-upstream,
linux-clk@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20260622-dramatic-worm-of-radiance-adf731@quoll>
Hi,
> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Monday, June 22, 2026 5:03 PM
> To: Joakim Zhang <joakim.zhang@cixtech.com>
> Cc: mturquette@baylibre.com; sboyd@kernel.org; bmasney@redhat.com;
> robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> p.zabel@pengutronix.de; Gary Yang <gary.yang@cixtech.com>; cix-kernel-
> upstream <cix-kernel-upstream@cixtech.com>; linux-clk@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH v5 4/4] arm64: dts: cix: sky1: add audss cru
>
> EXTERNAL EMAIL
>
> On Mon, Jun 22, 2026 at 10:25:20AM +0800, joakim.zhang@cixtech.com wrote:
> >
> > + audss_cru: clock-controller@7110000 {
> > + compatible = "cix,sky1-audss-cru";
> > + reg = <0x0 0x07110000 0x0 0x10000>;
> > + #clock-cells = <1>;
> > + #reset-cells = <1>;
> > + clocks = <&scmi_clk CLK_TREE_AUDIO_CLK0>,
> > + <&scmi_clk CLK_TREE_AUDIO_CLK2>,
> > + <&scmi_clk CLK_TREE_AUDIO_CLK4>,
> > + <&scmi_clk CLK_TREE_AUDIO_CLK5>;
> > + clock-names = "x8k", "x11k", "sys", "48m";
> > + power-domains = <&smc_devpd SKY1_PD_AUDIO>;
> > + resets = <&s5_syscon SKY1_AUDIO_HIFI5_NOC_RESET_N>;
>
> > + status = "okay";
>
> Drop.
Ok.
Thanks,
Joakim
^ permalink raw reply
* RE: [PATCH v5 1/4] dt-bindings: soc: cix: add sky1 audss cru controller
From: Joakim Zhang @ 2026-06-23 7:07 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: mturquette@baylibre.com, sboyd@kernel.org, bmasney@redhat.com,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
p.zabel@pengutronix.de, Gary Yang, cix-kernel-upstream,
linux-clk@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20260622-handsome-kagu-from-jupiter-8ebe05@quoll>
Hi,
> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Monday, June 22, 2026 5:02 PM
> To: Joakim Zhang <joakim.zhang@cixtech.com>
> Cc: mturquette@baylibre.com; sboyd@kernel.org; bmasney@redhat.com;
> robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> p.zabel@pengutronix.de; Gary Yang <gary.yang@cixtech.com>; cix-kernel-
> upstream <cix-kernel-upstream@cixtech.com>; linux-clk@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH v5 1/4] dt-bindings: soc: cix: add sky1 audss cru controller
>
> EXTERNAL EMAIL
>
> On Mon, Jun 22, 2026 at 10:25:17AM +0800, joakim.zhang@cixtech.com wrote:
> > From: Joakim Zhang <joakim.zhang@cixtech.com>
> >
> > The Cix Sky1 Audio Subsystem (AUDSS) Clock and Reset Unit (CRU) groups
> > clock muxing, gating and block-level software reset control in a
> > single register block.
> >
> > Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
> > ---
> > .../bindings/soc/cix/cix,sky1-audss-cru.yaml | 92
> > +++++++++++++++++++ .../dt-bindings/clock/cix,sky1-audss-clock.h |
> > 60 ++++++++++++ .../dt-bindings/reset/cix,sky1-audss-reset.h | 25
> > +++++
> > 3 files changed, 177 insertions(+)
> > create mode 100644
> > Documentation/devicetree/bindings/soc/cix/cix,sky1-audss-cru.yaml
> > create mode 100644 include/dt-bindings/clock/cix,sky1-audss-clock.h
> > create mode 100644 include/dt-bindings/reset/cix,sky1-audss-reset.h
>
> Both headers should have the same name as the compatible. I already
> requested this some time ago, I think.
Sorry, will update.
Joakim
^ permalink raw reply
* Re: [PATCH v4 5/8] riscv/runtime-const: Introduce runtime_const_mask_32()
From: Charlie Jenkins @ 2026-06-23 7:01 UTC (permalink / raw)
To: K Prateek Nayak
Cc: Thomas Gleixner, Ingo Molnar, Peter Zijlstra,
Sebastian Andrzej Siewior, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Guo Ren, Darren Hart, Davidlohr Bueso,
André Almeida, linux-arch, linux-kernel, linux-s390,
linux-riscv, linux-arm-kernel, Alexandre Ghiti, Charlie Jenkins,
Jisheng Zhang, Charles Mirabile
In-Reply-To: <ff9678fb-4cca-4849-8ffb-7cb76db60e1a@amd.com>
On Tue, Jun 23, 2026 at 11:43:39AM +0530, K Prateek Nayak wrote:
> Hello Charlie,
>
> On 6/23/2026 10:54 AM, Charlie Jenkins wrote:
> > On Thu, 30 Apr 2026 09:47:27 +0000, K Prateek Nayak <kprateek.nayak@amd.com> wrote:
> >> Futex hash computation requires a mask operation with read-only after
> >> init data that will be converted to a runtime constant in the subsequent
> >> commit.
> >>
> >> Introduce runtime_const_mask_32 to further optimize the mask operation
> >> in the futex hash computation hot path. GCC generates a:
> >>
> >> lui a0, 0x12346 # upper; +0x800 then >>12 for correct rounding
> >> addi a0, a0, 0x678 # lower 12 bits
> >> and a1, a1, a0 # a1 = a1 & a0
> >>
> >> pattern to tackle arbitrary 32-bit masks and the same was also suggested
> >> by Claude which is implemented here. The final (__ret & val) operation
> >> is intentionally placed outside of asm block to allow compilers to
> >> further optimize it if possible.
> >
> > If the mask fits in 12 bits, we can nop the lui and the addi and just
> > patch an "andi" instruction with the 12 bits of the mask. We already do
> > this with the lui+addi block and nop the lui if val fits in 12 bits. I
> > would be happy to help draft that optimization.
> >
> > But I think the better solution would be to take the power of 2
> > assumption since that will also benefit arm. We should still only emit
> > an andi if val fits in 12 bits, but if it doesn't we can patch in
> > shifts:
> >
> > slli a0,a0,x
> > srli a0,a0,x
> >
> > Where x is the constant (arch_size - _futex_shift - 1)
>
> I can do that for the next version and use ubfx for ARM. I can just put
> in a BUG_ON() at the arch/ specific __runtime_fixup_mask() and if a
> new use case arises which hits that, we can perhaps move on the dynamic
> nop patching scheme that you mentioned earlier.
>
> Let me know if that works and I can pivot to that scheme in v5 and send
> it out post -rc1 after some testing.
That sounds like a great plan :)
- Charlie
>
> --
> Thanks and Regards,
> Prateek
>
^ permalink raw reply
* [PATCH] hwrng: xilinx-trng: propagate timeout before any data is read
From: Pengpeng Hou @ 2026-06-23 6:07 UTC (permalink / raw)
To: Mounika Botcha, Harsh Jain, Olivia Mackall, Herbert Xu,
Michal Simek, linux-crypto, linux-arm-kernel, linux-kernel
Cc: Pengpeng Hou
xtrng_readblock32() polls for 16-byte chunks but returns the number of
bytes read even when the first poll times out. Its caller then treats a
zero return as a short successful read, and partial reads for full
32-byte blocks can make the tail copy use a fixed block offset rather
than the amount already produced.
Return the poll error when no data has been read, preserve partial
positive returns after some data is available, stop the generator on all
collection exits, and append tail bytes at the current output count.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/char/hw_random/xilinx-trng.c | 32 +++++++++++++++++++++-------
1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/drivers/char/hw_random/xilinx-trng.c b/drivers/char/hw_random/xilinx-trng.c
index f615d5adddde..4a1a168bb46a 100644
--- a/drivers/char/hw_random/xilinx-trng.c
+++ b/drivers/char/hw_random/xilinx-trng.c
@@ -87,8 +87,8 @@ static void xtrng_softreset(struct xilinx_rng *rng)
xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, 0);
}
-/* Return no. of bytes read */
-static size_t xtrng_readblock32(void __iomem *rng_base, __be32 *buf, int blocks32, bool wait)
+/* Return no. of bytes read or a negative error before any data is read. */
+static int xtrng_readblock32(void __iomem *rng_base, __be32 *buf, int blocks32, bool wait)
{
int read = 0, ret;
int timeout = 1;
@@ -103,8 +103,11 @@ static size_t xtrng_readblock32(void __iomem *rng_base, __be32 *buf, int blocks3
ret = readl_poll_timeout(rng_base + TRNG_STATUS_OFFSET, val,
(val & TRNG_STATUS_QCNT_MASK) ==
TRNG_STATUS_QCNT_16_BYTES, !!wait, timeout);
- if (ret)
+ if (ret) {
+ if (!read)
+ return ret;
break;
+ }
for (idx = 0; idx < TRNG_READ_4_WORD; idx++) {
*(buf + read) = cpu_to_be32(ioread32(rng_base + TRNG_CORE_OUTPUT_OFFSET));
@@ -119,27 +122,40 @@ static int xtrng_collect_random_data(struct xilinx_rng *rng, u8 *rand_gen_buf,
{
u8 randbuf[TRNG_SEC_STRENGTH_BYTES];
int byteleft, blocks, count = 0;
+ int full_blocks_bytes;
int ret;
byteleft = no_of_random_bytes & (TRNG_SEC_STRENGTH_BYTES - 1);
blocks = no_of_random_bytes >> TRNG_SEC_STRENGTH_SHIFT;
+ full_blocks_bytes = blocks * TRNG_SEC_STRENGTH_BYTES;
xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK,
TRNG_CTRL_PRNGSTART_MASK);
if (blocks) {
ret = xtrng_readblock32(rng->rng_base, (__be32 *)rand_gen_buf, blocks, wait);
- if (!ret)
- return 0;
+ if (ret <= 0) {
+ count = ret;
+ goto out_stop;
+ }
count += ret;
+ if (ret < full_blocks_bytes)
+ goto out_stop;
}
if (byteleft) {
ret = xtrng_readblock32(rng->rng_base, (__be32 *)randbuf, 1, wait);
+ if (ret < 0) {
+ if (!count)
+ count = ret;
+ goto out_stop;
+ }
if (!ret)
- return count;
- memcpy(rand_gen_buf + (blocks * TRNG_SEC_STRENGTH_BYTES), randbuf, byteleft);
- count += byteleft;
+ goto out_stop;
+ ret = min(ret, no_of_random_bytes - count);
+ memcpy(rand_gen_buf + count, randbuf, ret);
+ count += ret;
}
+out_stop:
xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET,
TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGSTART_MASK, 0U);
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* Re: [PATCH] PCI: cadence: skip the link polling when endpoint not connected
From: Aksh Garg @ 2026-06-23 6:37 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: linux-pci, vigneshr, s-vadapalli, lpieralisi, kwilczynski, robh,
bhelgaas, mpillai, unicorn_wang, me, 18255117159,
linux-arm-kernel, linux-kernel, danishanwar
In-Reply-To: <pocwd4v7iqlixcpaikjo6vqmnwsb7rfjt42qvlmxsn6xnvtrpf@zgch2iwu7itw>
On 23/06/26 11:15, Manivannan Sadhasivam wrote:
> On Tue, Jun 23, 2026 at 10:53:48AM +0530, Aksh Garg wrote:
>>
>>
>> On 22/06/26 20:22, Manivannan Sadhasivam wrote:
>>> On Fri, Jun 05, 2026 at 12:49:22PM +0530, Aksh Garg wrote:
>>>> cdns_pcie_host_wait_for_link() polls on link-up for 10 retries with a
>>>> delay of 90-100ms each (~1 second). A call to cdns_pcie_host_link_setup()
>>>> during the resume operation blocks the resume operation unnecessarily for
>>>> ~1s even when no endpoint device is connected.
>>>>
>>>> Add skip_link_polling flag to track link state across suspend/resume
>>>> cycles. If link was down before suspend, skip the expensive polling
>>>> in resume since no endpoint was present.
>>>>
>>>
>>> Won't you need the delay if a device gets plugged while the host was suspended?
>>> We had this same concern with the DWC drivers and we left the delay as-is as
>>> nothing prevents an user to connect a device when the host was suspended.
>>
>> Yes, that is true. However, the platforms that do not support hot-plug can
>> skip the delay during resume since no device could have been connected while
>> suspended (only those platform's driver would be expected to set
>> 'rc->skip_link_polling) just like what Tegra264 PCIe driver tries to do at
>> [1], where the driver sets "pcie->link_up = false" if the link is down
>> during the probe and if the controller doesn't support hot-plug.
>>
>
> If the platform doesn't support hotplug, then it is perfectly fine to skip the
> delay. But you need to name the flag as like 'no_hotplug' or something
> relevant, not 'skip_link_polling'.
Sure, I will rename the flag to 'link_down_no_hotplug' to clarify that
it tracks the link state when there's no hotplug support.
>
>> Even if a user connects a device (when the host was suspended) to a platform
>> which doesn't support hotplug, the user is expected to run a bus rescan,
>> which doesn't call cdns_pcie_host_link_setup() anyway, hence the flag
>> 'skip_link_polling' is not taken into account in that case.
>>
>
> This is not about running the rescan, but about initializing the device. The 1s
> delay in cdns_pcie_host_wait_for_link() is mandated by the PCIe spec after
> starting LTSSM and before issuing the config read to the device. If this delay
> is skipped and if a config read is issued to the device, then the device may not
> respond and the failure may lead to PCI stack assuming that the device is dead.
Understood, thanks for the explanation.
>
> - Mani
>
^ permalink raw reply
* Re: [PATCH v1] arm64: dts: freescale: imx95-toradex-smarc: add alias for lpuart5
From: Peng Fan @ 2026-06-23 6:21 UTC (permalink / raw)
To: Francesco Dolcini
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Francesco Dolcini, devicetree, imx, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260622093507.44132-1-francesco@dolcini.it>
On Mon, Jun 22, 2026 at 11:35:06AM +0200, Francesco Dolcini wrote:
>From: Francesco Dolcini <francesco.dolcini@toradex.com>
>
>Add alias for lpuart5 so the UART gets a stable line number.
>Without this alias, the lpuart driver fails:
>
> fsl-lpuart 42590000.serial: failed to get alias id, errno -19
>
>This prevents the Bluetooth controller connected to this UART from
>working.
>
>Fixes: 104a391bb6ff ("arm64: dts: freescale: imx95-toradex-smarc: Enable bluetooth on lpuart5")
>Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
Acked-by: Peng Fan <peng.fan@nxp.com>
^ permalink raw reply
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
From: Peng Fan @ 2026-06-23 6:19 UTC (permalink / raw)
To: Frieder Schrempf
Cc: Frank Li, Pankaj Gupta, Frieder Schrempf, Srinivas Kandagatla,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Shawn Guo,
devicetree, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <4f4cc156-7534-4f11-8a45-e4caf083c865@kontron.de>
On Thu, Jun 18, 2026 at 07:52:16AM +0200, Frieder Schrempf wrote:
>On 17.06.26 21:56, Frank Li wrote:
>> On Wed, Jun 17, 2026 at 08:54:35AM +0200, Frieder Schrempf wrote:
>>> On 16.06.26 22:05, Frank Li wrote:
>>>> On Tue, Jun 16, 2026 at 07:59:54PM +0200, Frieder Schrempf wrote:
>>>>> On 16.06.26 17:36, Frank Li wrote:
>>>>>> On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
>>>>>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>>>>>
>>>>>>> The ELE S400 API provides read and write access to the OCOTP fuse
>>>>>>> registers. This adds the necessary API functions imx_se_read_fuse()
>>>>>>> and imx_se_write_fuse() to be used by other drivers such as the
>>>>>>> OCOTP S400 NVMEM driver.
>>>>>>>
>>>>>>> This is ported from the downstream vendor kernel.
>>>>>>>
>>>>>>> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>>>>> ---
>>>>>>> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
>>>>>>> drivers/firmware/imx/ele_base_msg.h | 6 ++
>>>>>>> include/linux/firmware/imx/se_api.h | 3 +
>>>>>>> 3 files changed, 131 insertions(+)
>>>>>>>
>>>>>> ...
>>>>>>> +++ b/include/linux/firmware/imx/se_api.h
>>>>>>> @@ -11,4 +11,7 @@
>>>>>>> #define SOC_ID_OF_IMX8ULP 0x084d
>>>>>>> #define SOC_ID_OF_IMX93 0x9300
>>>>>>>
>>>>>>> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
>>>>>>> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
>>>>>>> +
>>>>>>
>>>>>> This API should implement in fuse drivers. Other consume should use standard
>>>>>> fuse API to get value. If put here, it may bypass fuse driver.
>>>>>
>>>>> The reason this is here, is the downstream implementation in linux-imx
>>>>> and the current code organization.
>>>>
>>>> Downstream may not good enough, sometime, it is quick solution.
>>>
>>> Ok, but the code structure and API design has been upstreamed like this
>>> and the refactoring could have been done before, if downstream is known
>>> to not be well organized.
>>>
>>>>
>>>>> I thought there is some good reason
>>>>> to have shared functions and it looks like Pankaj structured it like
>>>>> this so all API functions live in ele_base_msg.c and the internal
>>>>> structs and defines in ele_base_msg.h and se_ctrl.h are not exposed to
>>>>> other drivers.
>>>>>
>>>>> If I would move this into imx-ocotp-ele.c, then I would also need to
>>>>> change how the code is organized and make the internal se_api functions
>>>>> exposed to other drivers. I don't know if that is really a good idea.
>>>>>
>>>>> I get your point but it looks like this contradicts the intention of
>>>>> having a clean API in the firmware driver.
>>>>
>>>> You can refer imx-ocotp-scu.c, structure should be similar, only difference
>>>> is that lower transfer APIs.
>>> Ok, this would mean that I expose the generic SE functions and structs
>>> required for fuse handling. In practice, I would remove
>>> imx_se_read_fuse() and imx_se_write_fuse() from se_api.h and instead add
>>> the following:
>>>
>>> struct se_msg_hdr { ... };
>>> struct se_api_msg { ... };
>>> struct se_if_priv;
>>> se_fill_cmd_msg_hdr( ... );
>>> se_msg_send_rcv( ... );
>>> se_val_rsp_hdr_n_status( ... );
>>>
>>> Then I would export the functions in ele_common.c and put the fuse
>>> read/write functions in the NVMEM driver.
>>>
>>> Is that what you want me to do?
>>
>> Yes, Idealy, it should be children device under ele, ELE like a bus, which
>> previous lower level data transfer, ocotp should be base on top then it.
>> like spi/i2c, which provide low level data transfer.
>
>Ok, please also see the discussion with Krzysztof on the bindings patch.
>The problem is that this driver uses both, MMIO and firmware interface.
>Therefore putting a child node in the ELE device node is probably not
>correct, either!?
>
>In general I think it's a good idea as the fuses actually live inside
>the ELE block so this would properly describe the hardware, but again
>this would create a hard dependency on the closed source ELE firmware
>which I don't like that much.
The current ele driver does not export API for others to fill the structure
as i.MX8 imx_scu_call_rpc(). Actually I agree with Frank's idea regarding
ELE firmware provides low level data transfer, such as ELE firmware driver
providing an API such as imx_se_call_rpc() or imx_ele_call_rpc().
Regards
Peng
^ permalink raw reply
* Re: [PATCH v4 5/8] riscv/runtime-const: Introduce runtime_const_mask_32()
From: K Prateek Nayak @ 2026-06-23 6:13 UTC (permalink / raw)
To: Charlie Jenkins
Cc: Thomas Gleixner, Ingo Molnar, Peter Zijlstra,
Sebastian Andrzej Siewior, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Guo Ren, Darren Hart, Davidlohr Bueso,
André Almeida, linux-arch, linux-kernel, linux-s390,
linux-riscv, linux-arm-kernel, Alexandre Ghiti, Charlie Jenkins,
Jisheng Zhang, Charles Mirabile
In-Reply-To: <178219229643.10927.7189200920480581019.b4-review@b4>
Hello Charlie,
On 6/23/2026 10:54 AM, Charlie Jenkins wrote:
> On Thu, 30 Apr 2026 09:47:27 +0000, K Prateek Nayak <kprateek.nayak@amd.com> wrote:
>> Futex hash computation requires a mask operation with read-only after
>> init data that will be converted to a runtime constant in the subsequent
>> commit.
>>
>> Introduce runtime_const_mask_32 to further optimize the mask operation
>> in the futex hash computation hot path. GCC generates a:
>>
>> lui a0, 0x12346 # upper; +0x800 then >>12 for correct rounding
>> addi a0, a0, 0x678 # lower 12 bits
>> and a1, a1, a0 # a1 = a1 & a0
>>
>> pattern to tackle arbitrary 32-bit masks and the same was also suggested
>> by Claude which is implemented here. The final (__ret & val) operation
>> is intentionally placed outside of asm block to allow compilers to
>> further optimize it if possible.
>
> If the mask fits in 12 bits, we can nop the lui and the addi and just
> patch an "andi" instruction with the 12 bits of the mask. We already do
> this with the lui+addi block and nop the lui if val fits in 12 bits. I
> would be happy to help draft that optimization.
>
> But I think the better solution would be to take the power of 2
> assumption since that will also benefit arm. We should still only emit
> an andi if val fits in 12 bits, but if it doesn't we can patch in
> shifts:
>
> slli a0,a0,x
> srli a0,a0,x
>
> Where x is the constant (arch_size - _futex_shift - 1)
I can do that for the next version and use ubfx for ARM. I can just put
in a BUG_ON() at the arch/ specific __runtime_fixup_mask() and if a
new use case arises which hits that, we can perhaps move on the dynamic
nop patching scheme that you mentioned earlier.
Let me know if that works and I can pivot to that scheme in v5 and send
it out post -rc1 after some testing.
--
Thanks and Regards,
Prateek
^ permalink raw reply
* [PATCH] dt-bindings: clock: Replace bouncing emails
From: Krzysztof Kozlowski @ 2026-06-23 5:56 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sylwester Nawrocki, Chanwoo Choi, Peter Griffin, Alim Akhtar,
Barnabas Czeman, Tomasz Figa, linux-arm-msm, linux-clk,
devicetree, linux-kernel, linux-samsung-soc, linux-arm-kernel
Cc: Krzysztof Kozlowski
Replace permanently bouncing email addresses (550 5.1.1 Recipient address
rejected) of Adam Skladowski, Sireesh Kodali and Chanho Park. There are
no new messages from them via other email addresses, so drop them
permanently. Add Alim Akhtar to Samsung ExynosAutov9 SoC clocks,
because he looks at other Samsung clock hardware and drivers.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Stephen, can you take this directly?
---
Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml | 2 --
.../devicetree/bindings/clock/samsung,exynosautov9-clock.yaml | 2 +-
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
index fc0360554f68..9f2b970bfb48 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml
@@ -7,8 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Global Clock & Reset Controller on MSM8937, MSM8940, MSM8953 and SDM439
maintainers:
- - Adam Skladowski <a_skl39@protonmail.com>
- - Sireesh Kodali <sireeshkodali@protonmail.com>
- Barnabas Czeman <barnabas.czeman@mainlining.org>
description: |
diff --git a/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
index e9d17d48b4f3..3dcdfa7a8792 100644
--- a/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/samsung,exynosautov9-clock.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung Exynos Auto v9 SoC clock controller
maintainers:
- - Chanho Park <chanho61.park@samsung.com>
+ - Alim Akhtar <alim.akhtar@samsung.com>
- Chanwoo Choi <cw00.choi@samsung.com>
- Krzysztof Kozlowski <krzk@kernel.org>
- Sylwester Nawrocki <s.nawrocki@samsung.com>
--
2.53.0
^ permalink raw reply related
* Re: [RFC PATCH 0/2] kasan: hw_tags: Add option to tag only at allocation time
From: Dev Jain @ 2026-06-23 5:02 UTC (permalink / raw)
To: Catalin Marinas, Harry Yoo
Cc: ryabinin.a.a, akpm, corbet, glider, andreyknvl, dvyukov,
vincenzo.frascino, kasan-dev, linux-mm, linux-kernel, skhan,
workflows, linux-doc, linux-arm-kernel, ryan.roberts,
anshuman.khandual, kaleshsingh, 21cnbao, david, will
In-Reply-To: <ajltLd6FQg1aMge_@arm.com>
On 22/06/26 10:43 pm, Catalin Marinas wrote:
> Hi Harry,
>
> On Mon, Jun 22, 2026 at 09:42:10PM +0900, Harry Yoo wrote:
>> On 6/19/26 10:19 PM, Catalin Marinas wrote:
>>> On Thu, Jun 18, 2026 at 10:35:15PM +0900, Harry Yoo wrote:
>>>> On 6/12/26 1:44 PM, Dev Jain wrote:
>>>>> Now, when a memory object will be freed, it will retain the random tag it
>>>>> had at allocation time. This compromises on catching UAF bugs, till the
>>>>> time the object is not reallocated, at which point it will have a new
>>>>> random tag.
>>>>>
>>>>> Hence, not catching "use-after-free-before-reallocation" and not catching
>>>>> "double-free" will be the compromise for reduced KASAN overhead.
>>>>
>>>> I doubt users who care about security enough to enable HW_TAGS KASAN
>>>> are willing to compromise on security just to save a few instructions
>>>> to store tags in the free path.
>>>>
>>>> To me, it looks like too much of a compromise on security for little
>>>> performance gain.
>>>
>>> I don't think there's much compromise on security for use-after-free.
>>
>> I think it depends... OH, WAIT! I see what you mean.
>>
>> You mean use-after-free before reallocation does not lead to much
>> compromise on security because objects are initialized after allocation?
>>
>> You're probably right.
>>
>> Hmm, but stores to e.g.) free pointer, fields initialized by
>> constructor or accessed by SLAB_TYPESAFE_BY_RCU semantics after free
>> will be undiscovered if they happen before reallocation.
>
> Even with SLAB_TYPESAFE_BY_RCU, the object isn't tagged on free either
> (or realloc, only if the actual slab page ends up freed). But we don't
> get type confusion for such slab.
>
> However, without tagging on free, one could argue that it reduces
> security for cases where the page is re-allocated as untagged - e.g. all
> user pages mapped without PROT_MTE. Currently we have a deterministic
> tag check fault if the page is coloured as KASAN_TAG_INVALID. I think
So you are saying that a stale kernel pointer can continue to use the
reallocated page, because for non-PROT_MTE case the page does not get
a new tag. Makes sense.
> for this patch, it might be better to only do such skip on free in
> kasan_poison_slab() rather than kasan_poison(). Freed pages would then
> be tagged.
I think you mean to say, "skip tag on free when freeing pages into buddy"?
So that would mean, kasan_poison() will do the poisoning also in the
case of value == KASAN_PAGE_FREE.
>
> An alternative would be tagging on free only with a new tag and skipping
> it on re-alloc. But we'd need to track when it's a completely new
> allocation or a reused object (I haven't looked I'm pretty sure it's
> doable).
That was our original approach, and IIRC we had concluded there was no
security compromise. However it is difficult to implement - it has cases
like, what happens when two differently tagged pages are coalesced by
buddy and someone gets that large page as an allocation.
>
^ permalink raw reply
* Re: [PATCH] PCI: cadence: skip the link polling when endpoint not connected
From: Manivannan Sadhasivam @ 2026-06-23 5:45 UTC (permalink / raw)
To: Aksh Garg
Cc: linux-pci, vigneshr, s-vadapalli, lpieralisi, kwilczynski, robh,
bhelgaas, mpillai, unicorn_wang, me, 18255117159,
linux-arm-kernel, linux-kernel, danishanwar
In-Reply-To: <1ad01870-e2f9-485c-9206-23ee6de1d1ba@ti.com>
On Tue, Jun 23, 2026 at 10:53:48AM +0530, Aksh Garg wrote:
>
>
> On 22/06/26 20:22, Manivannan Sadhasivam wrote:
> > On Fri, Jun 05, 2026 at 12:49:22PM +0530, Aksh Garg wrote:
> > > cdns_pcie_host_wait_for_link() polls on link-up for 10 retries with a
> > > delay of 90-100ms each (~1 second). A call to cdns_pcie_host_link_setup()
> > > during the resume operation blocks the resume operation unnecessarily for
> > > ~1s even when no endpoint device is connected.
> > >
> > > Add skip_link_polling flag to track link state across suspend/resume
> > > cycles. If link was down before suspend, skip the expensive polling
> > > in resume since no endpoint was present.
> > >
> >
> > Won't you need the delay if a device gets plugged while the host was suspended?
> > We had this same concern with the DWC drivers and we left the delay as-is as
> > nothing prevents an user to connect a device when the host was suspended.
>
> Yes, that is true. However, the platforms that do not support hot-plug can
> skip the delay during resume since no device could have been connected while
> suspended (only those platform's driver would be expected to set
> 'rc->skip_link_polling) just like what Tegra264 PCIe driver tries to do at
> [1], where the driver sets "pcie->link_up = false" if the link is down
> during the probe and if the controller doesn't support hot-plug.
>
If the platform doesn't support hotplug, then it is perfectly fine to skip the
delay. But you need to name the flag as like 'no_hotplug' or something
relevant, not 'skip_link_polling'.
> Even if a user connects a device (when the host was suspended) to a platform
> which doesn't support hotplug, the user is expected to run a bus rescan,
> which doesn't call cdns_pcie_host_link_setup() anyway, hence the flag
> 'skip_link_polling' is not taken into account in that case.
>
This is not about running the rescan, but about initializing the device. The 1s
delay in cdns_pcie_host_wait_for_link() is mandated by the PCIe spec after
starting LTSSM and before issuing the config read to the device. If this delay
is skipped and if a config read is issued to the device, then the device may not
respond and the failure may lead to PCI stack assuming that the device is dead.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v11 2/3] dt-bindings: clock: imx95-blk-ctl: Define formatter child node schema
From: Krzysztof Kozlowski @ 2026-06-23 5:41 UTC (permalink / raw)
To: guoniu.zhou
Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Laurent Pinchart, Frank Li, Abel Vesa, Peng Fan,
Michael Turquette, Stephen Boyd, imx, linux-media, devicetree,
linux-arm-kernel, linux-kernel, linux-clk, Guoniu Zhou
In-Reply-To: <20260623-csi_formatter-v11-2-a792fe9c1502@oss.nxp.com>
On Tue, Jun 23, 2026 at 11:56:32AM +0800, guoniu.zhou@oss.nxp.com wrote:
> From: Guoniu Zhou <guoniu.zhou@nxp.com>
>
> The Camera CSR contains control registers for multiple CSI formatter IPs
> at different register offsets. Each formatter is an independent hardware
> block with its own clock input and media pipeline connection.
>
> Define schema to allow formatter child nodes under nxp,imx95-camera-csr,
> with 'reg' property specifying the formatter's register offset within the
> CSR address space.
>
> Signed-off-by: Guoniu Zhou <guoniu.zhou@nxp.com>
> ---
> Changes in v11:
> - Move properties to top-level and use if:then:else (Krzysztof/Frank)
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 8/8] arm64: defconfig: Add SM8450 camcc
From: Krzysztof Kozlowski @ 2026-06-23 5:38 UTC (permalink / raw)
To: esteuwu, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-8-37e2ee8df9da@proton.me>
On 23/06/2026 02:54, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
>
> Add SM8450 camcc as a module since it's enabled in SM8450 dtsi.
This is not needed. I already sent such patch.
Best regards,
Krzysztof
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox