* [PATCH 1/3] dt-bindings: reset: Add Apple SoC CIO reset
2026-08-09 12:16 [PATCH 0/3] Apple SoC CIO (USB4/Thunderbolt) reset controller Sven Peter
@ 2026-08-09 12:16 ` Sven Peter
2026-08-09 12:26 ` sashiko-bot
2026-08-09 12:16 ` [PATCH 2/3] reset: Add Apple SoC CIO reset driver Sven Peter
2026-08-09 12:16 ` [PATCH 3/3] arm64: dts: apple: Add CIO reset controllers Sven Peter
2 siblings, 1 reply; 9+ messages in thread
From: Sven Peter @ 2026-08-09 12:16 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel
The CIO (USB4/Thunderbolt) blocks on Apple Silicon SoCs have a reset
inside the power manager that has to be deasserted before their
co-processor can be booted. On t8103 each port comes with a dedicated
register page, represented as a standalone node. On t600x a single
register shared by all ports of a die is located in the middle of the
PMGR MMIO region instead, represented as a sub-node of the PMGR syscon.
Signed-off-by: Sven Peter <sven@kernel.org>
---
.../devicetree/bindings/arm/apple/apple,pmgr.yaml | 6 ++
.../bindings/reset/apple,t8103-cio-reset.yaml | 74 ++++++++++++++++++++++
MAINTAINERS | 1 +
3 files changed, 81 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml b/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml
index c67b67ba065a..2cdecc2c2cea 100644
--- a/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml
+++ b/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml
@@ -59,6 +59,12 @@ patternProperties:
type: object
$ref: /schemas/power/apple,pmgr-pwrstate.yaml#
+ "reset-controller@[0-9a-f]+$":
+ description:
+ Reset controller for the CIO (USB4/Thunderbolt) blocks
+ type: object
+ $ref: /schemas/reset/apple,t8103-cio-reset.yaml#
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/reset/apple,t8103-cio-reset.yaml b/Documentation/devicetree/bindings/reset/apple,t8103-cio-reset.yaml
new file mode 100644
index 000000000000..5f5be0636b36
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/apple,t8103-cio-reset.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reset/apple,t8103-cio-reset.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple SoC CIO (USB4/Thunderbolt) block reset controller
+
+maintainers:
+ - Sven Peter <sven@kernel.org>
+
+description: |
+ The CIO (Converged I/O) blocks on Apple Silicon SoCs have a reset
+ inside the power manager (PMGR) that has to be deasserted before
+ their co-processor can be booted. On t8103 each port comes with a
+ dedicated register page, represented as a standalone node. On t600x a
+ single register shared by all ports of a die with one request bit per
+ port is used instead. Since this register is located in the middle of
+ the PMGR MMIO region it is represented as a sub-node of the PMGR
+ syscon with reg used as an offset into it.
+
+ In both cases the reset id is the CIO port index on the die.
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - apple,t8103-cio-reset
+ - apple,t6000-cio-reset
+ - items:
+ - const: apple,t8112-cio-reset
+ - const: apple,t8103-cio-reset
+ - items:
+ - const: apple,t6020-cio-reset
+ - const: apple,t6000-cio-reset
+
+ reg:
+ maxItems: 1
+
+ '#reset-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ reset-controller@23b784000 {
+ compatible = "apple,t8103-cio-reset";
+ reg = <0x2 0x3b784000 0x0 0x8000>;
+ #reset-cells = <1>;
+ };
+ };
+ - |
+ power-management@28e080000 {
+ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd";
+ reg = <0x8e080000 0x1c000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ reset-controller@1a034 {
+ compatible = "apple,t6000-cio-reset";
+ reg = <0x1a034 0x4>;
+ #reset-cells = <1>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 15011f5752a9..4b78528324c8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2606,6 +2606,7 @@ F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
F: Documentation/devicetree/bindings/power/apple*
F: Documentation/devicetree/bindings/power/reset/apple,smc-reboot.yaml
F: Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml
+F: Documentation/devicetree/bindings/reset/apple,t8103-cio-reset.yaml
F: Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml
F: Documentation/devicetree/bindings/spi/apple,spi.yaml
F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 1/3] dt-bindings: reset: Add Apple SoC CIO reset
2026-08-09 12:16 ` [PATCH 1/3] dt-bindings: reset: Add Apple SoC CIO reset Sven Peter
@ 2026-08-09 12:26 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-08-09 12:26 UTC (permalink / raw)
To: Sven Peter; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Unit address and reg mismatch in the dt-schema example causes `dt_binding_check` to fail.
--
--- Patch [1]: [PATCH 1/3] dt-bindings: reset: Add Apple SoC CIO reset ---
commit 97bcf50ad89703c7219aea4998995a3a045920b5
Author: Sven Peter <sven@kernel.org>
dt-bindings: reset: Add Apple SoC CIO reset
This commit introduces device tree bindings for the CIO (USB4/Thunderbolt)
reset controller on Apple Silicon SoCs. It defines both a standalone node
representation for t8103 and a syscon sub-node representation for t600x.
> diff --git a/Documentation/devicetree/bindings/reset/apple,t8103-cio-reset.yaml b/Documentation/devicetree/bindings/reset/apple,t8103-cio-reset.yaml
> new file mode 100644
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/apple,t8103-cio-reset.yaml
[ ... ]
> +examples:
> + - |
[ ... ]
> + - |
> + power-management@28e080000 {
> + compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd";
> + reg = <0x8e080000 0x1c000>;
[Severity: Low]
Does this unit address mismatch the reg property base address? The node's
unit address is @28e080000, but the reg property uses 0x8e080000. This
typically causes make dt_binding_check to fail due to a unit_address_vs_reg
warning from dtc.
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + reset-controller@1a034 {
> + compatible = "apple,t6000-cio-reset";
> + reg = <0x1a034 0x4>;
> + #reset-cells = <1>;
> + };
> + };
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260809-b4-cio-reset-v1-0-4f33777d9b4b@kernel.org?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/3] reset: Add Apple SoC CIO reset driver
2026-08-09 12:16 [PATCH 0/3] Apple SoC CIO (USB4/Thunderbolt) reset controller Sven Peter
2026-08-09 12:16 ` [PATCH 1/3] dt-bindings: reset: Add Apple SoC CIO reset Sven Peter
@ 2026-08-09 12:16 ` Sven Peter
2026-08-09 12:28 ` sashiko-bot
2026-08-09 14:30 ` Joshua Peisach
2026-08-09 12:16 ` [PATCH 3/3] arm64: dts: apple: Add CIO reset controllers Sven Peter
2 siblings, 2 replies; 9+ messages in thread
From: Sven Peter @ 2026-08-09 12:16 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel
Add a driver for the reset of the CIO (USB4/Thunderbolt) blocks on
Apple Silicon SoCs which has to be deasserted before their
co-processor can be booted. On t8103 each port comes with a dedicated
register page while t600x uses a single register with one request bit
per port shared by all ports of a die inside the PMGR MMIO region.
Signed-off-by: Sven Peter <sven@kernel.org>
---
MAINTAINERS | 1 +
drivers/reset/Kconfig | 10 +++
drivers/reset/Makefile | 1 +
drivers/reset/reset-apple-cio.c | 182 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 194 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 4b78528324c8..5425051c0f99 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2636,6 +2636,7 @@ F: drivers/pinctrl/pinctrl-apple-gpio.c
F: drivers/power/reset/macsmc-reboot.c
F: drivers/power/supply/macsmc-power.c
F: drivers/pwm/pwm-apple.c
+F: drivers/reset/reset-apple-cio.c
F: drivers/rtc/rtc-macsmc.c
F: drivers/soc/apple/*
F: drivers/spi/spi-apple.c
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index d009eb0849a3..1e83cb5c68ce 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -22,6 +22,16 @@ config RESET_A10SR
This option enables support for the external reset functions for
peripheral PHYs on the Altera Arria10 System Resource Chip.
+config RESET_APPLE_CIO
+ tristate "Apple SoC CIO block reset driver"
+ depends on ARCH_APPLE || COMPILE_TEST
+ select MFD_SYSCON
+ help
+ This enables the reset driver for the CIO (USB4/Thunderbolt) blocks
+ found on Apple Silicon SoCs. It is required to start the blocks
+ before the USB4/Thunderbolt host routers inside them can be brought
+ up by the thunderbolt driver.
+
config RESET_ASPEED
tristate "ASPEED Reset Driver"
depends on ARCH_ASPEED || COMPILE_TEST
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 3e52569bd276..6554649bc139 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -7,6 +7,7 @@ obj-y += starfive/
obj-y += sti/
obj-y += tegra/
obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o
+obj-$(CONFIG_RESET_APPLE_CIO) += reset-apple-cio.o
obj-$(CONFIG_RESET_ASPEED) += reset-aspeed.o
obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
obj-$(CONFIG_RESET_AXS10X) += reset-axs10x.o
diff --git a/drivers/reset/reset-apple-cio.c b/drivers/reset/reset-apple-cio.c
new file mode 100644
index 000000000000..951340455468
--- /dev/null
+++ b/drivers/reset/reset-apple-cio.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple SoC CIO (USB4/Thunderbolt) block reset driver
+ *
+ * Copyright The Asahi Linux Contributors
+ *
+ * The CIO blocks have a reset inside the power manager (PMGR) that
+ * has to be deasserted before their co-processor can be booted. On
+ * t8103 each port comes with a dedicated register page while t600x
+ * uses a single register shared by all ports of a die inside the PMGR
+ * MMIO region.
+ */
+
+#include <linux/bits.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#define APPLE_CIO_RESET_POLL_US 100
+#define APPLE_CIO_RESET_TIMEOUT_US 100000
+
+#define T8103_CIO_CTRL_STRIDE 0x4000
+#define T8103_CIO_CTRL_INIT_REQ BIT(0)
+#define T8103_CIO_CTRL_INIT_DONE BIT(2)
+
+#define T6000_CIO_CTRL_INIT_REQ(port) BIT(port)
+#define T6000_CIO_CTRL_INIT_BUSY(port) BIT(16 + (port))
+
+struct apple_cio_reset;
+
+struct apple_cio_reset_variant {
+ unsigned int nr_resets;
+ bool pmgr_child;
+ int (*deassert)(struct apple_cio_reset *priv, unsigned long id);
+};
+
+struct apple_cio_reset {
+ struct reset_controller_dev rcdev;
+ const struct apple_cio_reset_variant *variant;
+ struct regmap *regmap;
+ u32 offset;
+ struct mutex lock; /* serializes access to the shared t600x register */
+};
+
+static int t8103_cio_deassert(struct apple_cio_reset *priv, unsigned long id)
+{
+ u32 offset = priv->offset + id * T8103_CIO_CTRL_STRIDE;
+ u32 val;
+ int ret;
+
+ ret = regmap_write(priv->regmap, offset, T8103_CIO_CTRL_INIT_REQ);
+ if (ret)
+ return ret;
+
+ return regmap_read_poll_timeout(priv->regmap, offset, val,
+ val == T8103_CIO_CTRL_INIT_DONE,
+ APPLE_CIO_RESET_POLL_US,
+ APPLE_CIO_RESET_TIMEOUT_US);
+}
+
+static int t6000_cio_deassert(struct apple_cio_reset *priv, unsigned long id)
+{
+ u32 val;
+ int ret;
+
+ guard(mutex)(&priv->lock);
+
+ ret = regmap_write(priv->regmap, priv->offset, T6000_CIO_CTRL_INIT_REQ(id));
+ if (ret)
+ return ret;
+
+ return regmap_read_poll_timeout(priv->regmap, priv->offset, val,
+ !(val & T6000_CIO_CTRL_INIT_BUSY(id)),
+ APPLE_CIO_RESET_POLL_US,
+ APPLE_CIO_RESET_TIMEOUT_US);
+}
+
+static const struct apple_cio_reset_variant apple_t8103_cio_reset = {
+ .nr_resets = 2,
+ .deassert = t8103_cio_deassert,
+};
+
+static const struct apple_cio_reset_variant apple_t6000_cio_reset = {
+ .nr_resets = 4,
+ .pmgr_child = true,
+ .deassert = t6000_cio_deassert,
+};
+
+static int apple_cio_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct apple_cio_reset *priv =
+ container_of(rcdev, struct apple_cio_reset, rcdev);
+
+ return priv->variant->deassert(priv, id);
+}
+
+static const struct reset_control_ops apple_cio_reset_ops = {
+ .deassert = apple_cio_reset_deassert,
+};
+
+static const struct regmap_config apple_cio_reset_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+};
+
+static int apple_cio_reset_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct apple_cio_reset *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->variant = of_device_get_match_data(dev);
+
+ ret = devm_mutex_init(dev, &priv->lock);
+ if (ret)
+ return ret;
+
+ if (priv->variant->pmgr_child) {
+ priv->regmap = syscon_node_to_regmap(dev->of_node->parent);
+ if (IS_ERR(priv->regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->regmap),
+ "Failed to get parent regmap");
+
+ ret = of_property_read_u32(dev->of_node, "reg", &priv->offset);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read reg offset");
+ } else {
+ void __iomem *base;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(dev, base,
+ &apple_cio_reset_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->regmap),
+ "Failed to init MMIO regmap");
+ }
+
+ priv->rcdev.owner = THIS_MODULE;
+ priv->rcdev.ops = &apple_cio_reset_ops;
+ priv->rcdev.of_node = dev->of_node;
+ priv->rcdev.nr_resets = priv->variant->nr_resets;
+
+ return devm_reset_controller_register(dev, &priv->rcdev);
+}
+
+static const struct of_device_id apple_cio_reset_match[] = {
+ {
+ .compatible = "apple,t8103-cio-reset",
+ .data = &apple_t8103_cio_reset,
+ },
+ {
+ .compatible = "apple,t6000-cio-reset",
+ .data = &apple_t6000_cio_reset,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, apple_cio_reset_match);
+
+static struct platform_driver apple_cio_reset_driver = {
+ .driver = {
+ .name = "apple-cio-reset",
+ .of_match_table = apple_cio_reset_match,
+ },
+ .probe = apple_cio_reset_probe,
+};
+module_platform_driver(apple_cio_reset_driver);
+
+MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
+MODULE_DESCRIPTION("Apple SoC CIO block reset driver");
+MODULE_LICENSE("Dual MIT/GPL");
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 2/3] reset: Add Apple SoC CIO reset driver
2026-08-09 12:16 ` [PATCH 2/3] reset: Add Apple SoC CIO reset driver Sven Peter
@ 2026-08-09 12:28 ` sashiko-bot
2026-08-09 14:30 ` Joshua Peisach
1 sibling, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-08-09 12:28 UTC (permalink / raw)
To: Sven Peter; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Race condition in `t6000_cio_deassert()` polling logic allows premature success before hardware busy assertion.
- [Medium] Unchecked return value of `of_device_get_match_data()` leads to NULL pointer dereference on manual sysfs bind.
- [Medium] Shared register overwrite in `t6000_cio_deassert()` via `regmap_write()`.
--
--- Patch [2]: [PATCH 2/3] reset: Add Apple SoC CIO reset driver ---
commit b460799e8ebb76e6526aa8a4370ed4331dbda4b0
Author: Sven Peter <sven@kernel.org>
reset: Add Apple SoC CIO reset driver
Adds a driver for the reset of the CIO (USB4/Thunderbolt) blocks on
Apple Silicon SoCs which has to be deasserted before their co-processor
can be booted.
> --- /dev/null
> +++ b/drivers/reset/reset-apple-cio.c
[ ... ]
> +static int t6000_cio_deassert(struct apple_cio_reset *priv, unsigned long id)
> +{
> + u32 val;
> + int ret;
> +
> + guard(mutex)(&priv->lock);
> +
> + ret = regmap_write(priv->regmap, priv->offset, T6000_CIO_CTRL_INIT_REQ(id));
[Severity: Medium]
Will this regmap_write() overwrite the state bits of all sibling ports?
Because the t600x variant uses a single shared register for all ports,
writing the entire 32-bit register might write 0 to the INIT_REQ bits
of previously initialized ports. Should this use regmap_update_bits()
instead to preserve active state?
> + if (ret)
> + return ret;
> +
> + return regmap_read_poll_timeout(priv->regmap, priv->offset, val,
> + !(val & T6000_CIO_CTRL_INIT_BUSY(id)),
> + APPLE_CIO_RESET_POLL_US,
> + APPLE_CIO_RESET_TIMEOUT_US);
> +}
[Severity: High]
Could this polling loop exit prematurely before the hardware begins
initialization?
Since regmap_read_poll_timeout() (without sleep_before_read) performs
its first read instantly, any hardware synchronization delay might cause
the first read to see the INIT_BUSY bit as 0 (its pre-assertion state).
This would cause the driver to report success before the hardware actually
starts the reset process. Is it possible to ensure the BUSY bit is
asserted first, or add a preliminary read delay?
[ ... ]
> +static int apple_cio_reset_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct apple_cio_reset *priv;
> + int ret;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->variant = of_device_get_match_data(dev);
> +
> + ret = devm_mutex_init(dev, &priv->lock);
> + if (ret)
> + return ret;
> +
> + if (priv->variant->pmgr_child) {
[Severity: Medium]
Can priv->variant be NULL here if the driver is bound manually via sysfs?
If a user writes "apple-cio-reset" to the driver's bind file without an
associated Device Tree node, of_device_get_match_data() will return NULL.
The probe function then immediately dereferences it for pmgr_child, causing
a kernel oops. Should we add a check for !priv->variant before continuing?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260809-b4-cio-reset-v1-0-4f33777d9b4b@kernel.org?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 2/3] reset: Add Apple SoC CIO reset driver
2026-08-09 12:16 ` [PATCH 2/3] reset: Add Apple SoC CIO reset driver Sven Peter
2026-08-09 12:28 ` sashiko-bot
@ 2026-08-09 14:30 ` Joshua Peisach
2026-08-09 15:20 ` Sven Peter
1 sibling, 1 reply; 9+ messages in thread
From: Joshua Peisach @ 2026-08-09 14:30 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel
On Sun Aug 9, 2026 at 8:16 AM EDT, Sven Peter wrote:
> Add a driver for the reset of the CIO (USB4/Thunderbolt) blocks on
> Apple Silicon SoCs which has to be deasserted before their
> co-processor can be booted. On t8103 each port comes with a dedicated
> register page while t600x uses a single register with one request bit
> per port shared by all ports of a die inside the PMGR MMIO region.
>
> Signed-off-by: Sven Peter <sven@kernel.org>
> ---
> MAINTAINERS | 1 +
> drivers/reset/Kconfig | 10 +++
> drivers/reset/Makefile | 1 +
> drivers/reset/reset-apple-cio.c | 182 ++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 194 insertions(+)
> +
> +static int apple_cio_reset_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct apple_cio_reset *priv;
> + int ret;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->variant = of_device_get_match_data(dev);
Might be a dumb question, but does priv->variant also need to be
checked? Because later priv->variant->pmgr_child is and I *think*
it could return NULL.
(Or is this not necessary since in theory the device should only run
this if detected... so this should never be an issue?)
> +
> + ret = devm_mutex_init(dev, &priv->lock);
> + if (ret)
> + return ret;
> +
> + if (priv->variant->pmgr_child) {
> + priv->regmap = syscon_node_to_regmap(dev->of_node->parent);
> + if (IS_ERR(priv->regmap))
> + return dev_err_probe(dev, PTR_ERR(priv->regmap),
> + "Failed to get parent regmap");
> +
> + ret = of_property_read_u32(dev->of_node, "reg", &priv->offset);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to read reg offset");
> + } else {
> + void __iomem *base;
> +
> + base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + priv->regmap = devm_regmap_init_mmio(dev, base,
> + &apple_cio_reset_regmap_config);
> + if (IS_ERR(priv->regmap))
> + return dev_err_probe(dev, PTR_ERR(priv->regmap),
> + "Failed to init MMIO regmap");
> + }
> +
> + priv->rcdev.owner = THIS_MODULE;
> + priv->rcdev.ops = &apple_cio_reset_ops;
> + priv->rcdev.of_node = dev->of_node;
> + priv->rcdev.nr_resets = priv->variant->nr_resets;
> +
> + return devm_reset_controller_register(dev, &priv->rcdev);
> +}
> +
> +static const struct of_device_id apple_cio_reset_match[] = {
> + {
> + .compatible = "apple,t8103-cio-reset",
> + .data = &apple_t8103_cio_reset,
> + },
> + {
> + .compatible = "apple,t6000-cio-reset",
> + .data = &apple_t6000_cio_reset,
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, apple_cio_reset_match);
> +
> +static struct platform_driver apple_cio_reset_driver = {
> + .driver = {
> + .name = "apple-cio-reset",
> + .of_match_table = apple_cio_reset_match,
> + },
> + .probe = apple_cio_reset_probe,
> +};
> +module_platform_driver(apple_cio_reset_driver);
> +
> +MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
> +MODULE_DESCRIPTION("Apple SoC CIO block reset driver");
> +MODULE_LICENSE("Dual MIT/GPL");
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 2/3] reset: Add Apple SoC CIO reset driver
2026-08-09 14:30 ` Joshua Peisach
@ 2026-08-09 15:20 ` Sven Peter
2026-08-09 17:13 ` Joshua Peisach
0 siblings, 1 reply; 9+ messages in thread
From: Sven Peter @ 2026-08-09 15:20 UTC (permalink / raw)
To: Joshua Peisach
Cc: asahi, Philipp Zabel, Rob Herring, Conor Dooley, linux-arm-kernel,
Neal Gompa, devicetree, linux-kernel, Janne Grunau,
Krzysztof Kozlowski
On 09.08.26 16:30, Joshua Peisach wrote:
> On Sun Aug 9, 2026 at 8:16 AM EDT, Sven Peter wrote:
>> Add a driver for the reset of the CIO (USB4/Thunderbolt) blocks on
>> Apple Silicon SoCs which has to be deasserted before their
>> co-processor can be booted. On t8103 each port comes with a dedicated
>> register page while t600x uses a single register with one request bit
>> per port shared by all ports of a die inside the PMGR MMIO region.
>>
>> Signed-off-by: Sven Peter <sven@kernel.org>
>> ---
>> MAINTAINERS | 1 +
>> drivers/reset/Kconfig | 10 +++
>> drivers/reset/Makefile | 1 +
>> drivers/reset/reset-apple-cio.c | 182 +++++++++++++++++++++++++++++++
>> +++++++++
>> 4 files changed, 194 insertions(+)
>
>> +
>> +static int apple_cio_reset_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct apple_cio_reset *priv;
>> + int ret;
>> +
>> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> + if (!priv)
>> + return -ENOMEM;
>> +
>> + priv->variant = of_device_get_match_data(dev);
>
> Might be a dumb question, but does priv->variant also need to be
> checked? Because later priv->variant->pmgr_child is and I *think*
> it could return NULL.
>
> (Or is this not necessary since in theory the device should only run
> this if detected... so this should never be an issue?)
You might be able to get this driver to probe without a device tree node
by manually forcing it with sysfs but well... play stupid games, win
stupid prizes.
Adding the check is just two lines and doesn't hurt though.
Best,
Sven
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 2/3] reset: Add Apple SoC CIO reset driver
2026-08-09 15:20 ` Sven Peter
@ 2026-08-09 17:13 ` Joshua Peisach
0 siblings, 0 replies; 9+ messages in thread
From: Joshua Peisach @ 2026-08-09 17:13 UTC (permalink / raw)
To: Sven Peter, Joshua Peisach
Cc: asahi, Philipp Zabel, Rob Herring, Conor Dooley, linux-arm-kernel,
Neal Gompa, devicetree, linux-kernel, Janne Grunau,
Krzysztof Kozlowski
On Sun Aug 9, 2026 at 11:20 AM EDT, Sven Peter wrote:
> On 09.08.26 16:30, Joshua Peisach wrote:
>> On Sun Aug 9, 2026 at 8:16 AM EDT, Sven Peter wrote:
>>> Add a driver for the reset of the CIO (USB4/Thunderbolt) blocks on
>>> Apple Silicon SoCs which has to be deasserted before their
>>> co-processor can be booted. On t8103 each port comes with a dedicated
>>> register page while t600x uses a single register with one request bit
>>> per port shared by all ports of a die inside the PMGR MMIO region.
>>>
>>> Signed-off-by: Sven Peter <sven@kernel.org>
>>> ---
>>> MAINTAINERS | 1 +
>>> drivers/reset/Kconfig | 10 +++
>>> drivers/reset/Makefile | 1 +
>>> drivers/reset/reset-apple-cio.c | 182 +++++++++++++++++++++++++++++++
>>> +++++++++
>>> 4 files changed, 194 insertions(+)
>>
>>> +
>>> +static int apple_cio_reset_probe(struct platform_device *pdev)
>>> +{
>>> + struct device *dev = &pdev->dev;
>>> + struct apple_cio_reset *priv;
>>> + int ret;
>>> +
>>> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>>> + if (!priv)
>>> + return -ENOMEM;
>>> +
>>> + priv->variant = of_device_get_match_data(dev);
>>
>> Might be a dumb question, but does priv->variant also need to be
>> checked? Because later priv->variant->pmgr_child is and I *think*
>> it could return NULL.
>>
>> (Or is this not necessary since in theory the device should only run
>> this if detected... so this should never be an issue?)
>
> You might be able to get this driver to probe without a device tree node
> by manually forcing it with sysfs but well... play stupid games, win
> stupid prizes.
> Adding the check is just two lines and doesn't hurt though.
Meh, not worth the extra lines of instruction. FAFO for the curious.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/3] arm64: dts: apple: Add CIO reset controllers
2026-08-09 12:16 [PATCH 0/3] Apple SoC CIO (USB4/Thunderbolt) reset controller Sven Peter
2026-08-09 12:16 ` [PATCH 1/3] dt-bindings: reset: Add Apple SoC CIO reset Sven Peter
2026-08-09 12:16 ` [PATCH 2/3] reset: Add Apple SoC CIO reset driver Sven Peter
@ 2026-08-09 12:16 ` Sven Peter
2 siblings, 0 replies; 9+ messages in thread
From: Sven Peter @ 2026-08-09 12:16 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel
Add the reset controllers used to start the CIO (USB4/Thunderbolt)
blocks on t8103 and t600x. On t8103 each port comes with a dedicated
register page represented as a standalone node. On t600x a single
register shared by all ports of a die is located in the middle of the
PMGR MMIO region and represented as a sub-node of its syscon.
Signed-off-by: Sven Peter <sven@kernel.org>
---
arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 8 +++++++-
arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 8 +++++++-
arch/arm64/boot/dts/apple/t8103.dtsi | 6 ++++++
arch/arm64/boot/dts/apple/t8112.dtsi | 6 ++++++
4 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi
index 9676d5127039..5e163d756a7f 100644
--- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi
@@ -28,7 +28,13 @@ DIE_NODE(pmgr): power-management@28e080000 {
compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
- reg = <0x2 0x8e080000 0 0x4000>;
+ reg = <0x2 0x8e080000 0 0x1c000>;
+
+ DIE_NODE(cio_reset): reset-controller@1a034 {
+ compatible = "apple,t6000-cio-reset";
+ reg = <0x1a034 0x4>;
+ #reset-cells = <1>;
+ };
};
DIE_NODE(pmgr_east): power-management@28e580000 {
diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi
index ae3d535c5acb..fd4d572a04e7 100644
--- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi
@@ -27,7 +27,13 @@ DIE_NODE(pmgr): power-management@28e080000 {
compatible = "apple,t6020-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
- reg = <0x2 0x8e080000 0 0x8000>;
+ reg = <0x2 0x8e080000 0 0xc000>;
+
+ DIE_NODE(cio_reset): reset-controller@a02c {
+ compatible = "apple,t6020-cio-reset", "apple,t6000-cio-reset";
+ reg = <0xa02c 0x4>;
+ #reset-cells = <1>;
+ };
};
DIE_NODE(pmgr_south): power-management@28e680000 {
diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
index da774096b667..83f6f1003424 100644
--- a/arch/arm64/boot/dts/apple/t8103.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103.dtsi
@@ -730,6 +730,12 @@ pmgr: power-management@23b700000 {
reg = <0x2 0x3b700000 0 0x14000>;
};
+ cio_reset: reset-controller@23b784000 {
+ compatible = "apple,t8103-cio-reset";
+ reg = <0x2 0x3b784000 0x0 0x8000>;
+ #reset-cells = <1>;
+ };
+
pinctrl_ap: pinctrl@23c100000 {
compatible = "apple,t8103-pinctrl", "apple,pinctrl";
reg = <0x2 0x3c100000 0x0 0x100000>;
diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi
index 85c47422d4e8..d0637c0384b2 100644
--- a/arch/arm64/boot/dts/apple/t8112.dtsi
+++ b/arch/arm64/boot/dts/apple/t8112.dtsi
@@ -737,6 +737,12 @@ pmgr: power-management@23b700000 {
/* child nodes are added in t8103-pmgr.dtsi */
};
+ cio_reset: reset-controller@23b784000 {
+ compatible = "apple,t8112-cio-reset", "apple,t8103-cio-reset";
+ reg = <0x2 0x3b784000 0x0 0x8000>;
+ #reset-cells = <1>;
+ };
+
pinctrl_ap: pinctrl@23c100000 {
compatible = "apple,t8112-pinctrl", "apple,pinctrl";
reg = <0x2 0x3c100000 0x0 0x100000>;
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread