From 59462ad263bcc607a825aff73a17240616427a19 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 19 Jun 2026 20:20:35 +1000 Subject: [PATCH 01/14] drm: apple: Handle differences in surface positions between SoCs DCP is an interesting little bit of hardware. Each variant has quite different scanout capabilities, including which hardware planes are actually present. The firmware interface will always accept four IOSurface structs, however the hardware will fail in weird and wonderful ways if the firmware then tries to program the corresponding scanout planes when they do not actually work. We need a way to declare to KMS which hardware planes actually work on which SoCs. Add an array to the Devicetree node representing the working hardware surfaces (relative to the four possible IOSurfaces), and use this to decide which KMS planes get created at driver init. Since we now guarantee that every instantiated DRM plane corresponds to a valid hardware surface, we can remove some superfluous sanity checks in crtc_atomic_check too. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/apple_drv.c | 36 +++++++++++--------------- drivers/gpu/drm/apple/dcp-internal.h | 2 ++ drivers/gpu/drm/apple/dcp.c | 21 ++++----------- drivers/gpu/drm/apple/iomfb.h | 2 -- drivers/gpu/drm/apple/iomfb_template.c | 33 +++++++---------------- drivers/gpu/drm/apple/plane.c | 8 ++---- drivers/gpu/drm/apple/plane.h | 9 ++++++- 7 files changed, 42 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 0f36dad6f96351..f4a1a06a98f622 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -272,31 +272,25 @@ static int apple_probe_per_dcp(struct device *dev, struct apple_crtc *crtc; struct apple_connector *connector; struct apple_encoder *enc; - struct drm_plane *planes[DCP_MAX_PLANES]; + struct apple_plane *planes[DCP_MAX_PLANES]; + struct apple_dcp *drv = platform_get_drvdata(dcp); int ret, i; - int immutable_zpos = 0; + int zpos = 0; bool supports_l10r = !dcp_fw_compat_is_12_x(dcp); - planes[0] = apple_plane_init(drm, 1U << num, supports_l10r, - DRM_PLANE_TYPE_PRIMARY); - if (IS_ERR(planes[0])) - return PTR_ERR(planes[0]); - ret = drm_plane_create_zpos_immutable_property(planes[0], immutable_zpos); - if (ret) { - return ret; - } + for (i = 0; i < DCP_MAX_PLANES; i++) { + if (drv->iomfb_surfaces[i]) { + planes[zpos] = apple_plane_init(drm, 1U << num, supports_l10r, + zpos ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY); + if (IS_ERR(planes[zpos])) + return PTR_ERR(planes[zpos]); + ret = drm_plane_create_zpos_immutable_property(&planes[zpos]->base, zpos); + if (ret) + return ret; - /* Set up our other planes */ - for (i = 1; i < DCP_MAX_PLANES; i++) { - planes[i] = apple_plane_init(drm, 1U << num, supports_l10r, - DRM_PLANE_TYPE_OVERLAY); - if (IS_ERR(planes[i])) - return PTR_ERR(planes[i]); - immutable_zpos++; - ret = drm_plane_create_zpos_immutable_property(planes[i], immutable_zpos); - if (ret) { - return ret; + planes[zpos]->iomfb_surf = i; + zpos++; } } @@ -307,7 +301,7 @@ static int apple_probe_per_dcp(struct device *dev, * knows what to do with overlays. */ crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); - ret = drm_crtc_init_with_planes(drm, &crtc->base, planes[0], NULL, + ret = drm_crtc_init_with_planes(drm, &crtc->base, &planes[0]->base, NULL, &apple_crtc_funcs, NULL); if (ret) return ret; diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index f2eb2483c9a880..04ec57bd570fb2 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -138,6 +138,8 @@ struct apple_dcp { * sense to keep some of the members in apple_dcp. * **********************************************************************/ + u32 iomfb_surfaces[DCP_MAX_PLANES]; + /* clock rate request by dcp in */ struct clk *clk; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 9dfc3fd002f530..27a544a3ce3519 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -331,10 +331,7 @@ int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct platform_device *pdev = to_apple_crtc(crtc)->dcp; struct apple_dcp *dcp = platform_get_drvdata(pdev); - struct drm_plane_state *new_state; - struct drm_plane *plane; struct drm_crtc_state *crtc_state; - int plane_idx, plane_count = 0; bool needs_modeset; if (dcp->crashed) @@ -348,19 +345,6 @@ int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) return -EINVAL; } - for_each_new_plane_in_state(state, plane, new_state, plane_idx) { - /* skip planes not for this crtc */ - if (new_state->crtc != crtc) - continue; - - plane_count += 1; - } - - if (plane_count > DCP_MAX_PLANES) { - dev_err(dcp->dev, "crtc_atomic_check: Blend supports only 2 layers!\n"); - return -EINVAL; - } - return 0; } @@ -1194,6 +1178,11 @@ static int dcp_platform_probe(struct platform_device *pdev) dev_err(dev, "Failed to get dp-phy: %ld\n", PTR_ERR(dcp->phy)); return PTR_ERR(dcp->phy); } + + if (of_property_read_u32_array(dev->of_node, "apple,iomfb-surfaces", + (u32 *)&dcp->iomfb_surfaces, DCP_MAX_PLANES)) + dcp->iomfb_surfaces[0] = 1; + if (dcp->phy) { int ret; /* diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index 8a871db0b94a70..7903fad4040677 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -86,8 +86,6 @@ enum iomfb_property_id { /* Structures used in v12.0 firmware */ #define SWAP_SURFACES 4 -/* We have 4 surfaces, but we can only ever blend two */ -#define MAX_BLEND_SURFACES 2 struct dcp_iouserclient { /* Handle for the IOUserClient. macOS sets this to a kernel VA. */ diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 553134aad80c9c..61d8b0c4e8c2b5 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1311,26 +1311,13 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru for_each_oldnew_plane_in_state(state, plane, old_state, new_state, plane_idx) { struct apple_plane_state *apple_state = to_apple_plane_state(new_state); + struct apple_plane *apl_plane = to_apple_plane(plane); /* skip planes not for this crtc */ if (old_state->crtc != crtc && new_state->crtc != crtc) continue; - /* - * Plane order is nondeterministic for this iterator. DCP will - * almost always crash at some point if the z order of planes - * flip-flops around. Make sure we are always blending them - * in the correct order. - * - * Despite having 4 surfaces, we can only blend two. Surface 0 is - * also unusable on some machines, so ignore it. - */ - - l = MAX_BLEND_SURFACES - new_state->normalized_zpos; - - WARN_ON(l > MAX_BLEND_SURFACES); - - req->swap.swap_enabled |= BIT(l); + req->swap.swap_enabled |= BIT(apl_plane->iomfb_surf); if (old_state->fb && new_state->fb != old_state->fb) { /* @@ -1356,17 +1343,17 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru if (!new_state->fb || !new_state->visible) { continue; } - req->surf_null[l] = false; + req->surf_null[apl_plane->iomfb_surf] = false; has_surface = 1; - req->swap.src_rect[l] = apple_state->src_rect; - req->swap.dst_rect[l] = apple_state->dst_rect; + req->swap.src_rect[apl_plane->iomfb_surf] = apple_state->src_rect; + req->swap.dst_rect[apl_plane->iomfb_surf] = apple_state->dst_rect; if (dcp->notch_height > 0) - req->swap.dst_rect[l].y += dcp->notch_height; + req->swap.dst_rect[apl_plane->iomfb_surf].y += dcp->notch_height; - req->surf_iova[l] = apple_state->iova; - req->surf[l].base = apple_state->surf; + req->surf_iova[apl_plane->iomfb_surf] = apple_state->iova; + req->surf[apl_plane->iomfb_surf].base = apple_state->surf; /* Use sRGB colorspace only for internal panels. External * displays are expected to have EDID and user space can use @@ -1374,8 +1361,8 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru * colors. */ if (dcp->connector_type == DRM_MODE_CONNECTOR_eDP && - req->surf[l].base.colorspace == DCP_COLORSPACE_BG_SRGB) - req->surf[l].base.colorspace = DCP_COLORSPACE_NATIVE; + req->surf[apl_plane->iomfb_surf].base.colorspace == DCP_COLORSPACE_BG_SRGB) + req->surf[apl_plane->iomfb_surf].base.colorspace = DCP_COLORSPACE_NATIVE; } if (!has_surface && !crtc_state->color_mgmt_changed) { diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index 2f0b76ad84ad65..8654532f4afa30 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -430,11 +430,7 @@ u64 apple_format_modifiers[] = { DRM_FORMAT_MOD_INVALID }; -struct apple_plane { - struct drm_plane base; -}; - -struct drm_plane *apple_plane_init(struct drm_device *dev, +struct apple_plane *apple_plane_init(struct drm_device *dev, unsigned long possible_crtcs, bool supports_l10r, enum drm_plane_type type) @@ -487,5 +483,5 @@ struct drm_plane *apple_plane_init(struct drm_device *dev, else drm_plane_helper_add(&plane->base, &apple_plane_helper_funcs); - return &plane->base; + return plane; } diff --git a/drivers/gpu/drm/apple/plane.h b/drivers/gpu/drm/apple/plane.h index 67d15938cf0dcb..c0c28627a61042 100644 --- a/drivers/gpu/drm/apple/plane.h +++ b/drivers/gpu/drm/apple/plane.h @@ -12,6 +12,13 @@ #include "iomfb_plane.h" +struct apple_plane { + struct drm_plane base; + u8 iomfb_surf; +}; + +#define to_apple_plane(x) container_of(x, struct apple_plane, base) + struct apple_plane_state { struct drm_plane_state base; struct dcp_surface surf; @@ -22,7 +29,7 @@ struct apple_plane_state { #define to_apple_plane_state(x) container_of(x, struct apple_plane_state, base) -struct drm_plane *apple_plane_init(struct drm_device *dev, +struct apple_plane *apple_plane_init(struct drm_device *dev, unsigned long possible_crtcs, bool supports_l10r, enum drm_plane_type type); From 94ce18ca4e2918aaf9698712aee4efe2d340cb36 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 19 Jun 2026 20:27:17 +1000 Subject: [PATCH 02/14] arm64: dts: apple: t602x: add apple,iomfb-surfaces to DCP nodes All T602x DCPs support simultaneous scanout on surfaces 0, 1, and 3. Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/t602x-die0.dtsi | 1 + arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 8938dd90693c4d..852b33a88b8136 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -624,6 +624,7 @@ <0x3 0x89344000 0x0 0x4000>, <0x3 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1208>; + apple,iomfb-surfaces = <1 1 0 1>; #ifdef APPLE_USE_PMP power-domains = <&pmp_report_disp0>; #else diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi index d916c0b106d109..13eb09067c4109 100644 --- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi @@ -102,6 +102,7 @@ <0x2 0x89344000 0x0 0x4000>, <0x2 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1210>; + apple,iomfb-surfaces = <1 1 0 1>; #ifdef APPLE_USE_PMP power-domains = <&DIE_NODE(pmp_report_dispext0)>; #else @@ -254,6 +255,7 @@ <0x3 0x15344000 0x0 0x4000>, <0x3 0x15800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1218>; + apple,iomfb-surfaces = <1 1 0 1>; #ifdef APPLE_USE_PMP power-domains = <&DIE_NODE(pmp_report_dispext1)>; #else From de20724c91177a2336ddc829a461e32b7c1a9173 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 19 Jun 2026 20:30:08 +1000 Subject: [PATCH 03/14] arm64: dts: apple: t600x: Add apple,iomfb-surfaces to DCP nodes All T600x DCPs support simultaneous scanout on surfaces 0 and 1. Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 1 + arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 637e052e5db3c3..1be41d6ff5fca7 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -525,6 +525,7 @@ <0x3 0x8b344000 0x0 0x4000>, <0x3 0x8b800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x988>; + apple,iomfb-surfaces = <1 1 0 0>; #ifdef APPLE_USE_PMP power-domains = <&pmp_report_disp0>; #else diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi index e222d63b37d320..e48065b70e0b97 100644 --- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi @@ -103,6 +103,7 @@ <0x2 0x89344000 0x0 0x4000>, <0x2 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x990>; + apple,iomfb-surfaces = <1 1 0 0>; #ifdef APPLE_USE_PMP power-domains = <&DIE_NODE(pmp_report_dispext0)>; #else @@ -184,6 +185,7 @@ <0x2 0x8c344000 0x0 0x4000>, <0x2 0x8c800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x998>; + apple,iomfb-surfaces = <1 1 0 0>; #ifdef APPLE_USE_PMP power-domains = <&DIE_NODE(pmp_report_dispext1)>; #else From 7457f7d0b50b5d6ea69c413cf98da8bb094ef652 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 19 Jun 2026 20:32:02 +1000 Subject: [PATCH 04/14] arm64: dts: apple: t8103: Add apple,iomfb-surfaces to DCP nodes All T8103 DCPs support simultaneous scanout on surfaces 0 and 1. Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/t8103.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index dfb5f737a420b3..58c59075f2d2b7 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -659,6 +659,7 @@ <0x2 0x3b3d0000 0x0 0x4000>; apple,bw-scratch = <&pmgr_dcp 0 5 0x14>; apple,bw-doorbell = <&pmgr_dcp 1 6>; + apple,iomfb-surfaces = <1 1 0 0>; power-domains = <&ps_disp0_cpu0>; resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; @@ -1485,6 +1486,7 @@ <0x2 0x3b3d0000 0x0 0x4000>; apple,bw-scratch = <&pmgr_dcp 0 5 0x18>; apple,bw-doorbell = <&pmgr_dcp 1 6>; + apple,iomfb-surfaces = <1 1 0 0>; power-domains = <&ps_dispext_cpu0>; resets = <&ps_dispext_cpu0>; clocks = <&clk_dispext0>; From 3de5796e7b654ca86d0535ff8dbfc013208be877 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 19 Jun 2026 20:33:31 +1000 Subject: [PATCH 05/14] arm64: dts: apple: t8112: Add apple,iomfb-surfaces to DCP nodes All T8112 DCPs support simultaneous scanout on surfaces 0, 1, and 3. Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/t8112.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index b19b94305e47c1..1215de82221d5d 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -748,6 +748,7 @@ <0x2 0x31344000 0x0 0x4000>, <0x2 0x31800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x5d8>; + apple,iomfb-surfaces = <1 1 0 1>; #ifdef APPLE_USE_PMP power-domains = <&pmp_report_disp0>; #else @@ -1745,6 +1746,7 @@ <0x2 0x71344000 0x0 0x4000>, <0x2 0x71800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x5e0>; + apple,iomfb-surfaces = <1 1 0 1>; #ifdef APPLE_USE_PMP power-domains = <&pmp_report_dispext>; #else From 13db32daf3f8df27d511bd0ff5acdb1a42a1de2d Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 19 Jun 2026 20:34:19 +1000 Subject: [PATCH 06/14] drm: apple: Max out DCP_MAX_PLANES Now that we can safely declare the working hardware surfaces on each SoC, let the driver test all possible positions for a working surface. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/dcp-internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 04ec57bd570fb2..c3f8eb77797b7c 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -20,7 +20,7 @@ #include "iomfb_v13_3.h" #include "epic/dpavservep.h" -#define DCP_MAX_PLANES 2 +#define DCP_MAX_PLANES 4 struct apple_dcp; struct apple_dcp_afkep; From 71031b0fce628500d8a7b576bf56fb420b516ea4 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 10 Jul 2026 17:47:46 +1000 Subject: [PATCH 07/14] drm: apple: move fw version enum to version_utils.h Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/dcp-internal.h | 7 +------ drivers/gpu/drm/apple/version_utils.h | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index c3f8eb77797b7c..6df99e7d65d954 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -19,6 +19,7 @@ #include "iomfb_v12_3.h" #include "iomfb_v13_3.h" #include "epic/dpavservep.h" +#include "version_utils.h" #define DCP_MAX_PLANES 4 @@ -27,12 +28,6 @@ struct apple_dcp_afkep; struct dcpav_service_epic; -enum dcp_firmware_version { - DCP_FIRMWARE_UNKNOWN, - DCP_FIRMWARE_V_12_3, - DCP_FIRMWARE_V_13_5, -}; - enum { SYSTEM_ENDPOINT = 0x20, TEST_ENDPOINT = 0x21, diff --git a/drivers/gpu/drm/apple/version_utils.h b/drivers/gpu/drm/apple/version_utils.h index 5a33ce1db61c47..35f82e6ad56c01 100644 --- a/drivers/gpu/drm/apple/version_utils.h +++ b/drivers/gpu/drm/apple/version_utils.h @@ -12,4 +12,10 @@ #define DCP_FW_NAME(name) CONCATENATE(name, DCP_FW_SUFFIX) #define DCP_FW_VERSION(x, y, z) ( ((x) << 16) | ((y) << 8) | (z) ) +enum dcp_firmware_version { + DCP_FIRMWARE_UNKNOWN, + DCP_FIRMWARE_V_12_3, + DCP_FIRMWARE_V_13_5, +}; + #endif /*__APPLE_VERSION_UTILS_H__*/ From 53432b6e25510b6dff97ffaf61d3e0b0d39b2e27 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 10 Jul 2026 17:55:37 +1000 Subject: [PATCH 08/14] drm: apple: Remove support for firmware version 12.3 This firmware version was only ever used for extremely early alpha installs based on ALARM (so basically just for developers testing things). Remove support for it to make way for a new target ABI for M3 machines. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/Makefile | 1 - drivers/gpu/drm/apple/apple_drv.c | 2 +- drivers/gpu/drm/apple/av.c | 14 ---- drivers/gpu/drm/apple/dcp-internal.h | 2 - drivers/gpu/drm/apple/dcp.c | 19 ----- drivers/gpu/drm/apple/iomfb.c | 12 --- drivers/gpu/drm/apple/iomfb_v12_3.c | 108 -------------------------- drivers/gpu/drm/apple/iomfb_v12_3.h | 17 ---- drivers/gpu/drm/apple/iomfb_v13_3.c | 1 - drivers/gpu/drm/apple/version_utils.h | 1 - 10 files changed, 1 insertion(+), 176 deletions(-) delete mode 100644 drivers/gpu/drm/apple/iomfb_v12_3.c delete mode 100644 drivers/gpu/drm/apple/iomfb_v12_3.h diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index b22839bdd611a7..a050e1292186ec 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -8,7 +8,6 @@ appledrm-$(CONFIG_DRM_APPLE_AUDIO) += audio.o appledrm-$(CONFIG_DRM_APPLE_AUDIO) += av.o appledrm-y += connector.o appledrm-y += ibootep.o -appledrm-y += iomfb_v12_3.o appledrm-y += iomfb_v13_3.o appledrm-y += epic/dpavservep.o appledrm-y += plane.o diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index f4a1a06a98f622..ddaa4415fde0b0 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -276,7 +276,7 @@ static int apple_probe_per_dcp(struct device *dev, struct apple_dcp *drv = platform_get_drvdata(dcp); int ret, i; int zpos = 0; - bool supports_l10r = !dcp_fw_compat_is_12_x(dcp); + bool supports_l10r = true; for (i = 0; i < DCP_MAX_PLANES; i++) { if (drv->iomfb_surfaces[i]) { diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index 0d3c752f62d5f5..2734cdf8a6cb1d 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -30,17 +30,6 @@ struct dcp_av_audio_cmds { u32 get_product_attrs; }; -static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v12_3 = { - .open = 6, - .close = 7, - .prepare = 8, - .start_link = 9, - .stop_link = 12, - .unprepare = 13, - .get_elements = 18, - .get_product_attrs = 20, -}; - static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v13_5 = { .open = 4, .close = 5, @@ -389,9 +378,6 @@ int avep_init(struct apple_dcp *dcp) mutex_init(&audiosrv_data->plug_lock); switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - audiosrv_data->cmds = dcp_av_audio_cmds_v12_3; - break; case DCP_FIRMWARE_V_13_5: audiosrv_data->cmds = dcp_av_audio_cmds_v13_5; break; diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 6df99e7d65d954..1458928fc1813f 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -16,7 +16,6 @@ #include "dptxep.h" #include "iomfb.h" -#include "iomfb_v12_3.h" #include "iomfb_v13_3.h" #include "epic/dpavservep.h" #include "version_utils.h" @@ -171,7 +170,6 @@ struct apple_dcp { /* Queued swap. Owned by the DCP to avoid per-swap memory allocation */ union { - struct dcp_swap_submit_req_v12_3 v12_3; struct dcp_swap_submit_req_v13_3 v13_3; } swap; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 27a544a3ce3519..89a5ef883fa257 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -485,14 +485,6 @@ void dcp_link(struct platform_device *pdev, struct apple_crtc *crtc, dcp->connector = connector; } - -bool dcp_fw_compat_is_12_x(struct platform_device *pdev) -{ - struct apple_dcp *dcp = platform_get_drvdata(pdev); - - return dcp->fw_compat == DCP_FIRMWARE_V_12_3; -} - int dcp_start(struct platform_device *pdev) { struct apple_dcp *dcp = platform_get_drvdata(pdev); @@ -568,9 +560,6 @@ int dcp_start(struct platform_device *pdev) static void _dcp_poweroff(struct apple_dcp *dcp) { switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_poweroff_v12_3(dcp); - break; case DCP_FIRMWARE_V_13_5: iomfb_poweroff_v13_3(dcp); break; @@ -627,9 +616,6 @@ int dcp_wait_ready(struct platform_device *pdev, u64 timeout) static void __maybe_unused dcp_sleep(struct apple_dcp *dcp) { switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_sleep_v12_3(dcp); - break; case DCP_FIRMWARE_V_13_5: iomfb_sleep_v13_3(dcp); break; @@ -652,9 +638,6 @@ void dcp_poweron(struct platform_device *pdev) } switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_poweron_v12_3(dcp); - break; case DCP_FIRMWARE_V_13_5: iomfb_poweron_v13_3(dcp); break; @@ -943,8 +926,6 @@ static enum dcp_firmware_version dcp_check_firmware_version(struct device *dev) return DCP_FIRMWARE_UNKNOWN; } - if (strncmp(compat_str, "12.3.0", sizeof(compat_str)) == 0) - return DCP_FIRMWARE_V_12_3; /* * m1n1 reports firmware version 13.5 as compatible with 13.3. This is * only true for the iomfb endpoint. The interface for the dptx-port diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 1d9448f0f4dc47..18a35cd7077065 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -430,9 +430,6 @@ int dcp_crtc_atomic_modeset(struct drm_crtc *crtc, return 0; switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - ret = iomfb_modeset_v12_3(dcp, crtc_state); - break; case DCP_FIRMWARE_V_13_5: ret = iomfb_modeset_v13_3(dcp, crtc_state); break; @@ -479,9 +476,6 @@ void dcp_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) } switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_flush_v12_3(dcp, crtc, state); - break; case DCP_FIRMWARE_V_13_5: iomfb_flush_v13_3(dcp, crtc, state); break; @@ -494,9 +488,6 @@ void dcp_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) static void iomfb_start(struct apple_dcp *dcp) { switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_start_v12_3(dcp); - break; case DCP_FIRMWARE_V_13_5: iomfb_start_v13_3(dcp); break; @@ -545,9 +536,6 @@ void iomfb_shutdown(struct apple_dcp *dcp) dcp->valid_mode = false; switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_shutdown_v12_3(dcp); - break; case DCP_FIRMWARE_V_13_5: iomfb_shutdown_v13_3(dcp); break; diff --git a/drivers/gpu/drm/apple/iomfb_v12_3.c b/drivers/gpu/drm/apple/iomfb_v12_3.c deleted file mode 100644 index 0fe08c42d64659..00000000000000 --- a/drivers/gpu/drm/apple/iomfb_v12_3.c +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT -/* Copyright The Asahi Linux Contributors */ - -#include "iomfb_v12_3.h" -#include "iomfb_v13_3.h" -#include "version_utils.h" - -static const struct dcp_method_entry dcp_methods[dcpep_num_methods] = { - IOMFB_METHOD("A000", dcpep_late_init_signal), - IOMFB_METHOD("A029", dcpep_setup_video_limits), - IOMFB_METHOD("A131", iomfbep_a131_pmu_service_matched), - IOMFB_METHOD("A132", iomfbep_a132_backlight_service_matched), - IOMFB_METHOD("A357", dcpep_set_create_dfb), - IOMFB_METHOD("A358", iomfbep_a358_vi_set_temperature_hint), - IOMFB_METHOD("A401", dcpep_start_signal), - IOMFB_METHOD("A407", dcpep_swap_start), - IOMFB_METHOD("A408", dcpep_swap_submit), - IOMFB_METHOD("A410", dcpep_set_display_device), - IOMFB_METHOD("A411", dcpep_is_main_display), - IOMFB_METHOD("A412", dcpep_set_digital_out_mode), - IOMFB_METHOD("A422", iomfbep_set_matrix), - IOMFB_METHOD("A426", iomfbep_get_color_remap_mode), - IOMFB_METHOD("A439", dcpep_set_parameter_dcp), - IOMFB_METHOD("A443", dcpep_create_default_fb), - IOMFB_METHOD("A447", dcpep_enable_disable_video_power_savings), - IOMFB_METHOD("A454", dcpep_first_client_open), - IOMFB_METHOD("A455", iomfbep_last_client_close), - IOMFB_METHOD("A460", dcpep_set_display_refresh_properties), - IOMFB_METHOD("A463", dcpep_flush_supports_power), - IOMFB_METHOD("A464", iomfbep_abort_swaps_dcp), - IOMFB_METHOD("A468", dcpep_set_power_state), -}; - -#define DCP_FW v12_3 -#define DCP_FW_VER DCP_FW_VERSION(12, 3, 0) - -#include "iomfb_template.c" - -static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { - [0] = trampoline_true, /* did_boot_signal */ - [1] = trampoline_true, /* did_power_on_signal */ - [2] = trampoline_nop, /* will_power_off_signal */ - [3] = trampoline_rt_bandwidth, - [100] = iomfbep_cb_match_pmu_service, - [101] = trampoline_zero, /* get_display_default_stride */ - [102] = trampoline_nop, /* set_number_property */ - [103] = trampoline_nop, /* set_boolean_property */ - [106] = trampoline_nop, /* remove_property */ - [107] = trampoline_true, /* create_provider_service */ - [108] = trampoline_true, /* create_product_service */ - [109] = trampoline_true, /* create_pmu_service */ - [110] = trampoline_true, /* create_iomfb_service */ - [111] = trampoline_create_backlight_service, - [116] = dcpep_cb_boot_1, - [117] = trampoline_false, /* is_dark_boot */ - [118] = trampoline_false, /* is_dark_boot / is_waking_from_hibernate*/ - [120] = trampoline_read_edt_data, - [122] = trampoline_prop_start, - [123] = trampoline_prop_chunk, - [124] = trampoline_prop_end, - [201] = trampoline_map_piodma, - [202] = trampoline_unmap_piodma, - [206] = iomfbep_cb_match_pmu_service_2, - [207] = iomfbep_cb_match_backlight_service, - [208] = trampoline_get_time, - [211] = trampoline_nop, /* update_backlight_factor_prop */ - [300] = trampoline_pr_publish, - [401] = trampoline_get_uint_prop, - [404] = trampoline_nop, /* sr_set_uint_prop */ - [406] = trampoline_set_fx_prop, - [408] = trampoline_get_frequency, - [411] = trampoline_map_reg, - [413] = trampoline_true, /* sr_set_property_dict */ - [414] = trampoline_sr_set_property_int, - [415] = trampoline_true, /* sr_set_property_bool */ - [451] = trampoline_allocate_buffer, - [452] = trampoline_map_physical, - [456] = trampoline_release_mem_desc, - [552] = trampoline_true, /* set_property_dict_0 */ - [561] = trampoline_true, /* set_property_dict */ - [563] = trampoline_true, /* set_property_int */ - [565] = trampoline_true, /* set_property_bool */ - [567] = trampoline_true, /* set_property_str */ - [574] = trampoline_zero, /* power_up_dart */ - [576] = trampoline_hotplug, - [577] = trampoline_nop, /* powerstate_notify */ - [582] = trampoline_true, /* create_default_fb_surface */ - [584] = trampoline_nop, /* IOMobileFramebufferAP::clear_default_surface */ - [588] = trampoline_nop, /* resize_default_fb_surface_gated */ - [589] = trampoline_swap_complete, - [591] = trampoline_swap_complete_intent_gated, - [592] = trampoline_abort_swap_ap_gated, - [593] = trampoline_enable_backlight_message_ap_gated, - [594] = trampoline_nop, /* IOMobileFramebufferAP::setSystemConsoleMode */ - [596] = trampoline_false, /* IOMobileFramebufferAP::isDFBAllocated */ - [597] = trampoline_false, /* IOMobileFramebufferAP::preserveContents */ - [598] = trampoline_nop, /* find_swap_function_gated */ -}; - -void DCP_FW_NAME(iomfb_start)(struct apple_dcp *dcp) -{ - dcp->cb_handlers = cb_handlers; - - dcp_start_signal(dcp, false, dcp_started, NULL); -} - -#undef DCP_FW_VER -#undef DCP_FW diff --git a/drivers/gpu/drm/apple/iomfb_v12_3.h b/drivers/gpu/drm/apple/iomfb_v12_3.h deleted file mode 100644 index 7359685d981fe5..00000000000000 --- a/drivers/gpu/drm/apple/iomfb_v12_3.h +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT -/* Copyright The Asahi Linux Contributors */ - -#ifndef __APPLE_IOMFB_V12_3_H__ -#define __APPLE_IOMFB_V12_3_H__ - -#include "version_utils.h" - -#define DCP_FW v12_3 -#define DCP_FW_VER DCP_FW_VERSION(12, 3, 0) - -#include "iomfb_template.h" - -#undef DCP_FW_VER -#undef DCP_FW - -#endif /* __APPLE_IOMFB_V12_3_H__ */ diff --git a/drivers/gpu/drm/apple/iomfb_v13_3.c b/drivers/gpu/drm/apple/iomfb_v13_3.c index 0ac869d24eb01b..ceac3fe03bbb0c 100644 --- a/drivers/gpu/drm/apple/iomfb_v13_3.c +++ b/drivers/gpu/drm/apple/iomfb_v13_3.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only OR MIT /* Copyright The Asahi Linux Contributors */ -#include "iomfb_v12_3.h" #include "iomfb_v13_3.h" #include "version_utils.h" diff --git a/drivers/gpu/drm/apple/version_utils.h b/drivers/gpu/drm/apple/version_utils.h index 35f82e6ad56c01..dfa4fff589a269 100644 --- a/drivers/gpu/drm/apple/version_utils.h +++ b/drivers/gpu/drm/apple/version_utils.h @@ -14,7 +14,6 @@ enum dcp_firmware_version { DCP_FIRMWARE_UNKNOWN, - DCP_FIRMWARE_V_12_3, DCP_FIRMWARE_V_13_5, }; From fd6115573ee73c18ee422ee7e5875670b1864cdd Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 12 Jul 2026 23:40:24 +1000 Subject: [PATCH 09/14] drm: apple: Add 14.8.3 FW ABI WIP This currently breaks with overlays and on machines that do not use surface 0 by default. I am also not 100% sure about some of the new fields and offsets. There seems to be some data at the bottom of the blob that gets sent to swap_submit, but it's all garbage. Also not sure why overlay surfaces now crash DCP. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/Makefile | 1 + drivers/gpu/drm/apple/av.c | 1 + drivers/gpu/drm/apple/dcp-internal.h | 2 + drivers/gpu/drm/apple/dcp.c | 12 +++ drivers/gpu/drm/apple/iomfb.c | 12 +++ drivers/gpu/drm/apple/iomfb.h | 3 +- drivers/gpu/drm/apple/iomfb_template.c | 11 ++- drivers/gpu/drm/apple/iomfb_template.h | 30 ++++++- drivers/gpu/drm/apple/iomfb_v13_3.c | 1 + drivers/gpu/drm/apple/iomfb_v14_8_3.c | 116 +++++++++++++++++++++++++ drivers/gpu/drm/apple/iomfb_v14_8_3.h | 17 ++++ drivers/gpu/drm/apple/version_utils.h | 1 + 12 files changed, 201 insertions(+), 6 deletions(-) create mode 100644 drivers/gpu/drm/apple/iomfb_v14_8_3.c create mode 100644 drivers/gpu/drm/apple/iomfb_v14_8_3.h diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index a050e1292186ec..c64f8ee2071db3 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -9,6 +9,7 @@ appledrm-$(CONFIG_DRM_APPLE_AUDIO) += av.o appledrm-y += connector.o appledrm-y += ibootep.o appledrm-y += iomfb_v13_3.o +appledrm-y += iomfb_v14_8_3.o appledrm-y += epic/dpavservep.o appledrm-y += plane.o diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index 2734cdf8a6cb1d..4a951d5800d708 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -379,6 +379,7 @@ int avep_init(struct apple_dcp *dcp) switch (dcp->fw_compat) { case DCP_FIRMWARE_V_13_5: + case DCP_FIRMWARE_V_14_7: audiosrv_data->cmds = dcp_av_audio_cmds_v13_5; break; default: diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 1458928fc1813f..f89758a9964920 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -17,6 +17,7 @@ #include "dptxep.h" #include "iomfb.h" #include "iomfb_v13_3.h" +#include "iomfb_v14_8_3.h" #include "epic/dpavservep.h" #include "version_utils.h" @@ -171,6 +172,7 @@ struct apple_dcp { /* Queued swap. Owned by the DCP to avoid per-swap memory allocation */ union { struct dcp_swap_submit_req_v13_3 v13_3; + struct dcp_swap_submit_req_v14_7_0 v14_7_0; } swap; /* swap id of the last completed swap */ diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 89a5ef883fa257..8ce6b7d403e822 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -563,6 +563,9 @@ static void _dcp_poweroff(struct apple_dcp *dcp) case DCP_FIRMWARE_V_13_5: iomfb_poweroff_v13_3(dcp); break; + case DCP_FIRMWARE_V_14_7: + iomfb_poweroff_v14_7_0(dcp); + break; default: WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); break; @@ -619,6 +622,9 @@ static void __maybe_unused dcp_sleep(struct apple_dcp *dcp) case DCP_FIRMWARE_V_13_5: iomfb_sleep_v13_3(dcp); break; + case DCP_FIRMWARE_V_14_7: + iomfb_sleep_v14_7_0(dcp); + break; default: WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); break; @@ -641,6 +647,9 @@ void dcp_poweron(struct platform_device *pdev) case DCP_FIRMWARE_V_13_5: iomfb_poweron_v13_3(dcp); break; + case DCP_FIRMWARE_V_14_7: + iomfb_poweron_v14_7_0(dcp); + break; default: WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); break; @@ -938,6 +947,9 @@ static enum dcp_firmware_version dcp_check_firmware_version(struct device *dev) return DCP_FIRMWARE_V_13_5; else if (strncmp(compat_str, "13.5.0", sizeof(compat_str)) == 0) return DCP_FIRMWARE_V_13_5; + else if (strncmp(compat_str, "14.7.0", sizeof(compat_str)) == 0 && + (strncmp(fw_str, "14.7.0", sizeof(compat_str)) == 0)) + return DCP_FIRMWARE_V_14_7; dev_err(dev, "DCP firmware-compat %s (FW: %s) is not supported\n", compat_str, fw_str); diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 18a35cd7077065..1eb71c1d85eaaf 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -433,6 +433,9 @@ int dcp_crtc_atomic_modeset(struct drm_crtc *crtc, case DCP_FIRMWARE_V_13_5: ret = iomfb_modeset_v13_3(dcp, crtc_state); break; + case DCP_FIRMWARE_V_14_7: + ret = iomfb_modeset_v14_7_0(dcp, crtc_state); + break; default: WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); @@ -479,6 +482,9 @@ void dcp_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) case DCP_FIRMWARE_V_13_5: iomfb_flush_v13_3(dcp, crtc, state); break; + case DCP_FIRMWARE_V_14_7: + iomfb_flush_v14_7_0(dcp, crtc, state); + break; default: WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); break; @@ -491,6 +497,9 @@ static void iomfb_start(struct apple_dcp *dcp) case DCP_FIRMWARE_V_13_5: iomfb_start_v13_3(dcp); break; + case DCP_FIRMWARE_V_14_7: + iomfb_start_v14_7_0(dcp); + break; default: WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); break; @@ -539,6 +548,9 @@ void iomfb_shutdown(struct apple_dcp *dcp) case DCP_FIRMWARE_V_13_5: iomfb_shutdown_v13_3(dcp); break; + case DCP_FIRMWARE_V_14_7: + iomfb_shutdown_v14_7_0(dcp); + break; default: WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); break; diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index 7903fad4040677..531089dab63134 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -78,7 +78,8 @@ struct dcp_packet_header { #define DCP_PACKET_ALIGNMENT (0x40) enum iomfb_property_id { - IOMFB_PROPERTY_NITS = 15, // divide by Brightness_Scale + IOMFB_PROPERTY_NITS_V13_3 = 15, // divide by Brightness_Scale + IOMFB_PROPERTY_NITS_V14_7 = 19, }; #define IOMFB_BRIGHTNESS_MIN 0x10000000 diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 61d8b0c4e8c2b5..bf1dbf8f15795e 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -200,7 +200,8 @@ static bool iomfbep_cb_match_backlight_service(struct apple_dcp *dcp, int tag, v static void iomfb_cb_pr_publish(struct apple_dcp *dcp, struct iomfb_property *prop) { switch (prop->id) { - case IOMFB_PROPERTY_NITS: + case IOMFB_PROPERTY_NITS_V13_3: + case IOMFB_PROPERTY_NITS_V14_7: { if (dcp_has_panel(dcp)) { dcp->brightness.nits = prop->value / dcp->brightness.scale; @@ -909,7 +910,11 @@ void DCP_FW_NAME(iomfb_poweroff)(struct apple_dcp *dcp) * brightness. */ if (dcp_has_panel(dcp)) { +#if DCP_FW_VER < DCP_FW_VERSION(14, 7, 0) swap->swap.bl_unk = 1; +#else + swap->swap.bl_update = 1; +#endif swap->swap.bl_value = 0; swap->swap.bl_power = 0; } @@ -1393,7 +1398,11 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru /* update brightness if changed */ if (dcp_has_panel(dcp) && dcp->brightness.update) { +#if DCP_FW_VER >= DCP_FW_VERSION(14, 7, 0) + req->swap.bl_update = 1; +#else req->swap.bl_unk = 1; +#endif req->swap.bl_value = dcp->brightness.dac; req->swap.bl_power = 0x40; dcp->brightness.update = false; diff --git a/drivers/gpu/drm/apple/iomfb_template.h b/drivers/gpu/drm/apple/iomfb_template.h index 8efab49cc53d08..49bab7c53c6e23 100644 --- a/drivers/gpu/drm/apple/iomfb_template.h +++ b/drivers/gpu/drm/apple/iomfb_template.h @@ -30,7 +30,9 @@ struct DCP_FW_NAME(dcp_swap) { u64 flags1; u64 flags2; - +#if DCP_FW_VER >= DCP_FW_VERSION(14, 7, 0) + u8 unk_v14_7[0x48]; +#endif u32 swap_id; u32 surf_ids[SWAP_SURFACES]; @@ -42,22 +44,39 @@ struct DCP_FW_NAME(dcp_swap) { u32 swap_completed; u32 bg_color; - u8 unk_110[0x1b8]; + u8 unk_110[0x30]; + u32 active_region_en[SWAP_SURFACES]; + struct dcp_rect active_regions[SWAP_SURFACES]; + u8 unk_190[0x138]; u32 unk_2c8; +#if DCP_FW_VER < DCP_FW_VERSION(14, 7, 0) u8 unk_2cc[0x14]; +#else + u8 unk_2cc[0x40]; +#endif +#if DCP_FW_VER < DCP_FW_VERSION(14, 7, 0) u32 unk_2e0; +#else + u32 bl_update; +#endif #if DCP_FW_VER < DCP_FW_VERSION(13, 2, 0) u16 unk_2e2; #else u8 unk_2e2[3]; #endif +#if DCP_FW_VER < DCP_FW_VERSION(14, 7 ,0) u64 bl_unk; +#else + u32 bl_unk; +#endif u32 bl_value; // min value is 0x10000000 u8 bl_power; // constant 0x40 for on u8 unk_2f3[0x2d]; #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) - u8 unk_320[0x13f]; - u64 unk_1; + u8 unk_320[0x147]; +#if DCP_FW_VER >= DCP_FW_VERSION(14, 7, 0) + u8 unk_14_7_2[0x30]; +#endif #endif } __packed; @@ -103,6 +122,9 @@ struct DCP_FW_NAME(dcp_swap_submit_req) { u8 unkU32out_null; #endif u8 padding[1]; +#if DCP_FW_VER >= DCP_FW_VERSION(14, 7, 0) + u8 padding_14_7[0x234]; +#endif } __packed; struct DCP_FW_NAME(dcp_swap_submit_resp) { diff --git a/drivers/gpu/drm/apple/iomfb_v13_3.c b/drivers/gpu/drm/apple/iomfb_v13_3.c index ceac3fe03bbb0c..a74350b8c930dd 100644 --- a/drivers/gpu/drm/apple/iomfb_v13_3.c +++ b/drivers/gpu/drm/apple/iomfb_v13_3.c @@ -2,6 +2,7 @@ /* Copyright The Asahi Linux Contributors */ #include "iomfb_v13_3.h" +#include "iomfb_v14_8_3.h" #include "version_utils.h" static const struct dcp_method_entry dcp_methods[dcpep_num_methods] = { diff --git a/drivers/gpu/drm/apple/iomfb_v14_8_3.c b/drivers/gpu/drm/apple/iomfb_v14_8_3.c new file mode 100644 index 00000000000000..8e0efbcfbba3b7 --- /dev/null +++ b/drivers/gpu/drm/apple/iomfb_v14_8_3.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright The Asahi Linux Contributors */ + +#include "iomfb_v13_3.h" +#include "iomfb_v14_8_3.h" +#include "version_utils.h" + +static const struct dcp_method_entry dcp_methods[dcpep_num_methods] = { + IOMFB_METHOD("A000", dcpep_late_init_signal), + IOMFB_METHOD("A029", dcpep_setup_video_limits), + IOMFB_METHOD("A131", iomfbep_a131_pmu_service_matched), + IOMFB_METHOD("A132", iomfbep_a132_backlight_service_matched), + IOMFB_METHOD("A377", dcpep_set_create_dfb), + IOMFB_METHOD("A378", iomfbep_a358_vi_set_temperature_hint), + IOMFB_METHOD("A401", dcpep_start_signal), + IOMFB_METHOD("A406", dcpep_swap_start), + IOMFB_METHOD("A407", dcpep_swap_submit), + IOMFB_METHOD("A409", dcpep_set_display_device), + IOMFB_METHOD("A410", dcpep_is_main_display), + IOMFB_METHOD("A411", dcpep_set_digital_out_mode), + IOMFB_METHOD("A421", iomfbep_set_matrix), + IOMFB_METHOD("A425", iomfbep_get_color_remap_mode), + IOMFB_METHOD("A440", dcpep_set_parameter_dcp), + IOMFB_METHOD("A444", dcpep_create_default_fb), + IOMFB_METHOD("A443", dcpep_enable_disable_video_power_savings), + IOMFB_METHOD("A455", dcpep_first_client_open), + IOMFB_METHOD("A457", iomfbep_last_client_close), + IOMFB_METHOD("A463", dcpep_set_display_refresh_properties), + IOMFB_METHOD("A466", dcpep_flush_supports_power), + IOMFB_METHOD("A467", iomfbep_abort_swaps_dcp), + //IOMFB_METHOD("A471", dcpep_update_dfb_surface), + IOMFB_METHOD("A472", dcpep_set_power_state), +}; + +#define DCP_FW v14_7_0 +#define DCP_FW_VER DCP_FW_VERSION(14, 7, 0) + +#include "iomfb_template.c" + +static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { + [0] = trampoline_true, /* did_boot_signal */ + [1] = trampoline_true, /* did_power_on_signal */ + [2] = trampoline_nop, /* will_power_off_signal */ + [3] = trampoline_rt_bandwidth, + // [6] = trampoline_set_frame_sync_props, + [6] = trampoline_nop, + [100] = iomfbep_cb_match_pmu_service, + [101] = trampoline_zero, /* get_display_default_stride */ + [102] = trampoline_nop, /* set_number_property */ + [103] = trampoline_nop, /* trigger_user_cal_loader */ + [104] = trampoline_nop, /* set_boolean_property */ + [107] = trampoline_nop, /* remove_property */ + [108] = trampoline_true, /* create_provider_service */ + [109] = trampoline_true, /* create_product_service */ + [110] = trampoline_true, /* create_pmu_service */ + [111] = trampoline_true, /* create_iomfb_service */ + [112] = trampoline_create_backlight_service, + [113] = trampoline_true, /* create_nvram_service? */ + //[114] = trampoline_get_tiling_state, + //[115] = trampoline_false, /* set_tiling_state */ + [121] = dcpep_cb_boot_1, /* is_dark_boot */ + [122] = trampoline_false, /* is_dark_boot / is_waking_from_hibernate*/ + [123] = trampoline_false, + [125] = trampoline_read_edt_data, + [127] = trampoline_prop_start, + [128] = trampoline_prop_chunk, + [129] = trampoline_prop_end, + // [129] = trampoline_allocate_bandwidth, + [201] = trampoline_map_piodma, + [202] = trampoline_unmap_piodma, + [206] = iomfbep_cb_match_pmu_service_2, + [207] = iomfbep_cb_match_backlight_service, + [208] = trampoline_nop, /* update_backlight_factor_prop */ + [209] = trampoline_get_time, + [300] = trampoline_pr_publish, + [401] = trampoline_get_uint_prop, + [404] = trampoline_nop, /* sr_set_uint_prop */ + [406] = trampoline_set_fx_prop, + [408] = trampoline_get_frequency, + [411] = trampoline_map_reg, + [413] = trampoline_true, /* sr_set_property_dict */ + [414] = trampoline_sr_set_property_int, + [415] = trampoline_true, /* sr_set_property_bool */ + [451] = trampoline_allocate_buffer, + [452] = trampoline_map_physical, + [454] = trampoline_release_mem_desc, + [552] = trampoline_true, /* set_property_dict_0 */ + [561] = trampoline_true, /* set_property_dict */ + [563] = trampoline_true, /* set_property_int */ + [565] = trampoline_true, /* set_property_bool */ + [567] = trampoline_true, /* set_property_str */ + [574] = trampoline_zero, /* power_up_dart */ + [576] = trampoline_hotplug, + [577] = trampoline_nop, /* powerstate_notify */ + //[582] = trampoline_create_dfb_surface, /* create_default_fb_surface */ + [582] = trampoline_true, + [584] = trampoline_nop, /* IOMobileFramebufferAP::clear_default_surface */ + [588] = trampoline_nop, /* resize_default_fb_surface_gated */ + [589] = trampoline_swap_complete, + [591] = trampoline_swap_complete_intent_gated, + [592] = trampoline_abort_swap_ap_gated, + [593] = trampoline_enable_backlight_message_ap_gated, + [594] = trampoline_nop, /* IOMobileFramebufferAP::setSystemConsoleMode */ + [596] = trampoline_false, /* IOMobileFramebufferAP::isDFBAllocated */ + [597] = trampoline_false, /* IOMobileFramebufferAP::preserveContents */ + [598] = trampoline_nop, /* find_swap_function_gated */ +}; +void DCP_FW_NAME(iomfb_start)(struct apple_dcp *dcp) +{ + dcp->cb_handlers = cb_handlers; + + dcp_start_signal(dcp, false, dcp_started, NULL); +} + +#undef DCP_FW_VER +#undef DCP_FW diff --git a/drivers/gpu/drm/apple/iomfb_v14_8_3.h b/drivers/gpu/drm/apple/iomfb_v14_8_3.h new file mode 100644 index 00000000000000..9db803b9dc8090 --- /dev/null +++ b/drivers/gpu/drm/apple/iomfb_v14_8_3.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright The Asahi Linux Contributors */ + +#ifndef __APPLE_IOMFB_V14_8_3_H__ +#define __APPLE_IOMFB_V14_8_3_H__ + +#include "version_utils.h" + +#define DCP_FW v14_7_0 +#define DCP_FW_VER DCP_FW_VERSION(14, 7, 0) + +#include "iomfb_template.h" + +#undef DCP_FW_VER +#undef DCP_FW + +#endif /* __APPLE_IOMFB_V14_8_3_H__ */ diff --git a/drivers/gpu/drm/apple/version_utils.h b/drivers/gpu/drm/apple/version_utils.h index dfa4fff589a269..542a5e9570866b 100644 --- a/drivers/gpu/drm/apple/version_utils.h +++ b/drivers/gpu/drm/apple/version_utils.h @@ -15,6 +15,7 @@ enum dcp_firmware_version { DCP_FIRMWARE_UNKNOWN, DCP_FIRMWARE_V_13_5, + DCP_FIRMWARE_V_14_7, }; #endif /*__APPLE_VERSION_UTILS_H__*/ From 607b5cf397651ecbde0b3b3173ebf8999a8a70d0 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 19 Jul 2026 20:24:58 +1000 Subject: [PATCH 10/14] drm: apple: properly define plane and compression parameters Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_plane.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_plane.h b/drivers/gpu/drm/apple/iomfb_plane.h index 0701978200311a..73f104059d29cc 100644 --- a/drivers/gpu/drm/apple/iomfb_plane.h +++ b/drivers/gpu/drm/apple/iomfb_plane.h @@ -67,7 +67,9 @@ struct dcp_plane_info { u16 tile_size; u8 tile_w; u8 tile_h; - u32 unk[13]; + u8 unk[0xd]; + u8 unk2; + u8 unk3[0x26]; } __packed; struct dcp_component_types { @@ -75,6 +77,23 @@ struct dcp_component_types { u8 types[7]; } __packed; +struct dcp_compression_info { + u32 tile_w; + u32 tile_h; + u32 metadata_offset; + u32 data_offset; + u32 meta_bytes; + u32 tiles_w; + u32 tiles_h; + u32 unk_1; + u32 compression_type; + u32 unk3; + u8 padding[3]; + u32 tile_bytes; + u32 row_stride; + u8 pad2; +} __packed; + /* Information describing a surface */ struct dcp_surface { u8 is_tiled; @@ -100,7 +119,7 @@ struct dcp_surface { u64 has_comp; struct dcp_plane_info planes[DCP_SURF_MAX_PLANES]; u64 has_planes; - u32 compression_info[DCP_SURF_MAX_PLANES][13]; + struct dcp_compression_info compression_info[DCP_SURF_MAX_PLANES]; u64 has_compr_info; u32 unk_num; u32 unk_denom; From 7ea152d53989fa864653fb5dc3b537c118ec16ea Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 26 Jul 2026 09:06:39 +1000 Subject: [PATCH 11/14] drm: apple: Expose two flag fields at the end of IOMFBSwapRec Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_template.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.h b/drivers/gpu/drm/apple/iomfb_template.h index 49bab7c53c6e23..c08d31b177c822 100644 --- a/drivers/gpu/drm/apple/iomfb_template.h +++ b/drivers/gpu/drm/apple/iomfb_template.h @@ -73,10 +73,12 @@ struct DCP_FW_NAME(dcp_swap) { u8 bl_power; // constant 0x40 for on u8 unk_2f3[0x2d]; #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) - u8 unk_320[0x147]; + u8 unk_320[0x13f]; #if DCP_FW_VER >= DCP_FW_VERSION(14, 7, 0) u8 unk_14_7_2[0x30]; #endif + u32 unk_flags; + u32 unk_flags2; #endif } __packed; From 0e4b3579d9e310ebb54c88c100e879c2c872ef2f Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 26 Jul 2026 09:09:52 +1000 Subject: [PATCH 12/14] drm: apple: Pass plane ID as IOSurface ID Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_template.c | 2 ++ drivers/gpu/drm/apple/plane.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index bf1dbf8f15795e..c4efa41a16926e 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1354,6 +1354,8 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru req->swap.src_rect[apl_plane->iomfb_surf] = apple_state->src_rect; req->swap.dst_rect[apl_plane->iomfb_surf] = apple_state->dst_rect; + req->swap.surf_ids[apl_plane->iomfb_surf] = plane->base.id; + if (dcp->notch_height > 0) req->swap.dst_rect[apl_plane->iomfb_surf].y += dcp->notch_height; diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index 8654532f4afa30..643af649086c1b 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -249,7 +249,7 @@ static void apple_plane_atomic_update(struct drm_plane *plane, .width = fb->width, .height = fb->height, .buf_size = fb->height * fb->pitches[0], - // .surface_id = req->swap.surf_ids[l], + .surface_id = plane->base.id, /* Only used for compressed or multiplanar surfaces */ .pix_size = 1, From 14971a2eb0425bf3771dfe377bea21d1fa9a11de Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 26 Jul 2026 20:04:50 +1000 Subject: [PATCH 13/14] HACK: drm: apple: do not destroy stale framebuffer references Because we have not yet figured out how to clear surfaces, freeing old framebuffer references crashes DCP with IOVA errors. Don't destroy them for now so that we can continue working. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_template.c | 44 +++++++++++++------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index c4efa41a16926e..252f1310870b53 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -739,17 +739,17 @@ static void dcp_swap_cleared(struct apple_dcp *dcp, void *data, void *cookie) return; } - while (!list_empty(&dcp->swapped_out_fbs)) { - struct dcp_fb_reference *entry; - entry = list_first_entry(&dcp->swapped_out_fbs, - struct dcp_fb_reference, head); - if (entry->swap_id == dcp->last_swap_id) - break; - if (entry->fb) - drm_framebuffer_put(entry->fb); - list_del(&entry->head); - kfree(entry); - } + // while (!list_empty(&dcp->swapped_out_fbs)) { + // struct dcp_fb_reference *entry; + // entry = list_first_entry(&dcp->swapped_out_fbs, + // struct dcp_fb_reference, head); + // if (entry->swap_id == dcp->last_swap_id) + // break; + // if (entry->fb) + // drm_framebuffer_put(entry->fb); + // list_del(&entry->head); + // kfree(entry); + // } } static void dcp_swap_clear_started(struct apple_dcp *dcp, void *data, @@ -1150,17 +1150,17 @@ static void dcp_swapped(struct apple_dcp *dcp, void *data, void *cookie) } dcp->swap_start = ktime_get(); - while (!list_empty(&dcp->swapped_out_fbs)) { - struct dcp_fb_reference *entry; - entry = list_first_entry(&dcp->swapped_out_fbs, - struct dcp_fb_reference, head); - if (entry->swap_id == dcp->last_swap_id) - break; - if (entry->fb) - drm_framebuffer_put(entry->fb); - list_del(&entry->head); - kfree(entry); - } + // while (!list_empty(&dcp->swapped_out_fbs)) { + // struct dcp_fb_reference *entry; + // entry = list_first_entry(&dcp->swapped_out_fbs, + // struct dcp_fb_reference, head); + // if (entry->swap_id == dcp->last_swap_id) + // break; + // if (entry->fb) + // drm_framebuffer_put(entry->fb); + // list_del(&entry->head); + // kfree(entry); + // } } static void dcp_swap_started(struct apple_dcp *dcp, void *data, void *cookie) From 00ad585322c90c01a80bccb365405a5bf025f42d Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sat, 1 Aug 2026 23:34:22 +1000 Subject: [PATCH 14/14] drm: apple: split out unknown 14.7 region Some of this is 0xaa padding, some of it is zeroes, and there is a conspicuous empty byte at the end. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_template.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.h b/drivers/gpu/drm/apple/iomfb_template.h index c08d31b177c822..3e1ee3b58ae32b 100644 --- a/drivers/gpu/drm/apple/iomfb_template.h +++ b/drivers/gpu/drm/apple/iomfb_template.h @@ -125,7 +125,10 @@ struct DCP_FW_NAME(dcp_swap_submit_req) { #endif u8 padding[1]; #if DCP_FW_VER >= DCP_FW_VERSION(14, 7, 0) - u8 padding_14_7[0x234]; + u8 padding_14_7[0x1e9]; + u8 unk_14_7_zero[0x46] + u32 unk_14_7_u32; + u8 unk_bool; #endif } __packed;