From 723c3cc37dcd583ecd052be140b66c085700842e Mon Sep 17 00:00:00 2001 From: Satya Benson Date: Sun, 1 Nov 2026 19:04:19 -0500 Subject: [PATCH 1/4] iommu: apple-dart: preserve the live J613 MTP bypass stream Keep the boot loader DMA context for a running J613 MTP session. Admit only the T8122 MTP DART at 0x2fa808000, exactly stream 1, and verify that its control register still selects bypass before skipping reset. Select an identity domain and reject paging, blocked-domain attachment and runtime suspend while the inherited session runs. Retain the clock and bypass state at removal. This permits the existing mtp-live-v1 RTKit adoption path to keep serving input without another INIT. The C-diag11 implementation passed owner input testing on J613 with firmware 26.6.2. The rebased series requires a separate owner boot test. Signed-off-by: Satya Benson --- drivers/iommu/apple-dart.c | 42 ++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index c34aa47b9833f..b7c8fb6ce8a4b 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -354,6 +354,8 @@ struct apple_dart { u32 pgsize; u32 num_streams; u32 supports_bypass : 1; + /* J613 MTP keeps issuing DMA in the boot loader identity domain. */ + bool live_mtp; u32 four_level : 1; u32 locked : 1; u32 tunneled : 1; @@ -3087,6 +3089,10 @@ static int apple_dart_attach_dev_paging(struct iommu_domain *domain, struct apple_dart_domain *dart_domain = to_dart_domain(domain); bool streams_added = false; + for_each_stream_map(i, cfg, stream_map) + if (stream_map->dart->live_mtp) + return -EBUSY; + for_each_stream_map(i, cfg, stream_map) WARN_ON(pm_runtime_get_sync(stream_map->dart->dev) < 0); @@ -3180,6 +3186,10 @@ static int apple_dart_attach_dev_blocked(struct iommu_domain *domain, struct apple_dart_stream_map *stream_map; int i; + for_each_stream_map(i, cfg, stream_map) + if (stream_map->dart->live_mtp) + return -EBUSY; + if (cfg->locked) return -EINVAL; @@ -3918,7 +3928,8 @@ static int apple_dart_def_domain_type(struct device *dev) if (cfg->stream_maps[0].dart->managed_sids || apple_dart_has_borrowed(cfg->stream_maps[0].dart)) return IOMMU_DOMAIN_DMA; - if (cfg->stream_maps[0].dart->retained_mtp) + if (cfg->stream_maps[0].dart->retained_mtp || + cfg->stream_maps[0].dart->live_mtp) return IOMMU_DOMAIN_IDENTITY; if (cfg->stream_maps[0].dart->pgsize > PAGE_SIZE) return IOMMU_DOMAIN_IDENTITY; @@ -5095,6 +5106,25 @@ static int apple_dart_probe(struct platform_device *pdev) goto err_clk_disable; } + /* A live MTP epoch must never lose its firmware DMA addresses. */ + if (of_property_present(dev->of_node, "apple,bypass-handoff-streams")) { + u32 stream; + + if (!of_machine_is_compatible("apple,j613") || + !of_device_is_compatible(dev->of_node, "apple,t8122-dart") || + res->start != 0x2fa808000ULL || !dart->supports_bypass || + of_property_count_u32_elems(dev->of_node, + "apple,bypass-handoff-streams") != 1 || + of_property_read_u32(dev->of_node, "apple,bypass-handoff-streams", + &stream) || + stream != 1 || stream >= dart->num_streams || + apple_dart_readl(dart, DART_TCR(dart, stream)) != dart->hw->tcr_bypass) { + ret = -EINVAL; + goto err_clk_disable; + } + dart->live_mtp = true; + } + ret = apple_dart_read_remaps(dart); if (ret) goto err_clk_disable; @@ -5233,7 +5263,7 @@ static int apple_dart_probe(struct platform_device *pdev) } /* ENABLE is write-one-to-set; no foreign stream changes state. */ apple_dart_writel(dart, dart->managed_sids, dart->hw->enable_streams); - } else if (!dart->locked && !dart->retained_mtp && !dart->preserve_display) { + } else if (!dart->locked && !dart->retained_mtp && !dart->live_mtp && !dart->preserve_display) { ret = apple_dart_hw_reset(dart); if (ret) goto err_clk_disable; @@ -5469,7 +5499,7 @@ static void apple_dart_remove(struct platform_device *pdev) * A command issued then never completes. The next probe resets the * block after that clock is running again. */ - if (!dart->locked && !dart->retained_mtp && + if (!dart->locked && !dart->retained_mtp && !dart->live_mtp && !READ_ONCE(dart->commands_gated)) apple_dart_hw_reset(dart); @@ -5479,7 +5509,8 @@ static void apple_dart_remove(struct platform_device *pdev) iommu_device_unregister(&dart->iommu); iommu_device_sysfs_remove(&dart->iommu); - clk_bulk_disable_unprepare(dart->num_clks, dart->clks); + if (!dart->live_mtp) + clk_bulk_disable_unprepare(dart->num_clks, dart->clks); } static void apple_dart_shutdown(struct platform_device *pdev) @@ -5623,6 +5654,9 @@ static __maybe_unused int apple_dart_suspend(struct device *dev) { struct apple_dart *dart = dev_get_drvdata(dev); + if (dart->live_mtp) + return -EBUSY; + dart->tunnel_state_restored = false; if (READ_ONCE(dart->commands_gated)) return 0; From c53dd9f590a64cadad3ba27355615fe39a0849d3 Mon Sep 17 00:00:00 2001 From: Satya Benson Date: Mon, 2 Nov 2026 12:56:58 -0500 Subject: [PATCH 2/4] soc: apple: rtkit-helper: match the T8122 helper compatible The J613 and J615 25G83 device trees list the MTP as "apple,t8122-mtp", "apple,t8122-rtk-helper-asc4", "apple,mtp" without the generic "apple,rtk-helper-asc4" fallback, and say that Linux binds the SoC-specific compatible. The helper only matches the generic one, so on those boards it never probes, DockChannel HID defers forever and the built-in keyboard and trackpad stay absent. Match "apple,t8122-rtk-helper-asc4" as well. Signed-off-by: Satya Benson --- drivers/soc/apple/rtkit-helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/apple/rtkit-helper.c b/drivers/soc/apple/rtkit-helper.c index 07b5840da8fde..df2f5334ac6b6 100644 --- a/drivers/soc/apple/rtkit-helper.c +++ b/drivers/soc/apple/rtkit-helper.c @@ -406,6 +406,8 @@ static const struct dev_pm_ops apple_rtkit_helper_pm_ops = { static const struct of_device_id apple_rtkit_helper_of_match[] = { { .compatible = "apple,rtk-helper-asc4" }, + /* J613/J615 25G83 DTs omit the generic fallback (see t8122-j613-25g83.dts). */ + { .compatible = "apple,t8122-rtk-helper-asc4" }, {}, }; MODULE_DEVICE_TABLE(of, apple_rtkit_helper_of_match); From f891a957fc26e8c9e6b1823f25e1cfd4f37b2c59 Mon Sep 17 00:00:00 2001 From: Satya Benson Date: Tue, 10 Nov 2026 14:38:20 -0500 Subject: [PATCH 3/4] iommu: apple-dart: treat zero bypass handoff as inactive J700 advertises apple,bypass-handoff-streams with value zero. Skip the live MTP admission checks in that case, as for an absent property, so the ordinary probe path remains available. Nonzero handoffs retain the J613 identity and bypass checks. Signed-off-by: Satya Benson Assisted-by: LLM --- drivers/iommu/apple-dart.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index b7c8fb6ce8a4b..c7752478b4a2f 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -5110,19 +5110,23 @@ static int apple_dart_probe(struct platform_device *pdev) if (of_property_present(dev->of_node, "apple,bypass-handoff-streams")) { u32 stream; - if (!of_machine_is_compatible("apple,j613") || - !of_device_is_compatible(dev->of_node, "apple,t8122-dart") || - res->start != 0x2fa808000ULL || !dart->supports_bypass || - of_property_count_u32_elems(dev->of_node, + /* A zero stream value advertises no live handoff (e.g. J700). */ + if (of_property_count_u32_elems(dev->of_node, "apple,bypass-handoff-streams") != 1 || of_property_read_u32(dev->of_node, "apple,bypass-handoff-streams", - &stream) || + &stream)) { + ret = -EINVAL; + goto err_clk_disable; + } + if (stream && (!of_machine_is_compatible("apple,j613") || + !of_device_is_compatible(dev->of_node, "apple,t8122-dart") || + res->start != 0x2fa808000ULL || !dart->supports_bypass || stream != 1 || stream >= dart->num_streams || - apple_dart_readl(dart, DART_TCR(dart, stream)) != dart->hw->tcr_bypass) { + apple_dart_readl(dart, DART_TCR(dart, stream)) != dart->hw->tcr_bypass)) { ret = -EINVAL; goto err_clk_disable; } - dart->live_mtp = true; + dart->live_mtp = stream != 0; } ret = apple_dart_read_remaps(dart); From 6debb6f76b5c797e0a6eb6e257929ded0e55100a Mon Sep 17 00:00:00 2001 From: Satya Benson Date: Tue, 10 Nov 2026 21:41:23 -0500 Subject: [PATCH 4/4] iommu: apple-dart: retain live MTP bypass across s2idle The live J613 MTP session is adopted without resetting its DART. Its RTKit helper admits suspend-to-idle with firmware kept running, but the DART rejects every suspend with EBUSY. Allow only that retained-power state and skip resume reset as well; deeper sleep remains refused. Matched 30.6 devices/platform pm_test passes; the current PR971 composition fails at 2fa808000.iommu. Hardware retest of this change is pending. Signed-off-by: Satya Benson --- drivers/iommu/apple-dart.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index c7752478b4a2f..f2549b1fb12a5 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -5658,8 +5658,13 @@ static __maybe_unused int apple_dart_suspend(struct device *dev) { struct apple_dart *dart = dev_get_drvdata(dev); + /* + * The adopted MTP keeps issuing DMA through its firmware bypass. + * Like its RTKit helper, admit only suspend-to-idle: leave the DART + * untouched while that live session and its power domain stay on. + */ if (dart->live_mtp) - return -EBUSY; + return pm_suspend_target_state == PM_SUSPEND_TO_IDLE ? 0 : -EBUSY; dart->tunnel_state_restored = false; if (READ_ONCE(dart->commands_gated)) @@ -5797,7 +5802,7 @@ static __maybe_unused int apple_dart_resume(struct device *dev) int ret; /* No reset or restore: see apple_dart_suspend(). */ - if (dart->cold_ane) + if (dart->cold_ane || dart->live_mtp) return 0; /* Powered down by its DCP, which restores it at power-up. */ if (READ_ONCE(dart->host_off))