From aeed96195bce4d0117143e7778c03b1d70b3fcd1 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Fri, 12 Jun 2026 20:36:03 +0200 Subject: [PATCH 01/28] power: supply: macsmc: Support macOS 27 SMC firmware The SMC firmware included in macOS 27 changed the size of BCF0 key from 4 to 1 bytes. This key is used for indicating that battery state is critically low. Reviewed-by: Sven Peter Signed-off-by: Sasha Finkelstein --- drivers/power/supply/macsmc-power.c | 35 ++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/macsmc-power.c b/drivers/power/supply/macsmc-power.c index d4a1f737ca6ba4..c2dc198ba2f588 100644 --- a/drivers/power/supply/macsmc-power.c +++ b/drivers/power/supply/macsmc-power.c @@ -86,6 +86,7 @@ struct macsmc_power { bool has_ch0i; /* Force discharge (Older firmware) */ bool has_ch0c; /* Inhibit charge (Older firmware) */ bool has_chte; /* Inhibit charge (Modern firmware) */ + bool bcf0_1byte; /* Battery critical key is 1 byte (Modern firmware) */ u8 num_cells; int nominal_voltage_mv; @@ -372,6 +373,19 @@ static int macsmc_battery_get_date(const char *s, int *out) return 0; } +static int macsmc_battery_read_bcf0(struct macsmc_power *power, u32 *val) +{ + u8 tval = 0; + int ret; + + if (!power->bcf0_1byte) + return apple_smc_read_u32(power->smc, SMC_KEY(BCF0), val); + + ret = apple_smc_read_u8(power->smc, SMC_KEY(BCF0), &tval); + *val = tval; + return ret; +} + static int macsmc_battery_get_capacity_level(struct macsmc_power *power) { bool flag; @@ -379,7 +393,7 @@ static int macsmc_battery_get_capacity_level(struct macsmc_power *power) int ret; /* Check for emergency shutdown condition */ - if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val) >= 0 && val) + if (macsmc_battery_read_bcf0(power, &val) >= 0 && val) return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; /* Check AC status for whether we could boot in this state */ @@ -700,7 +714,7 @@ static void macsmc_power_critical_work(struct work_struct *wrk) * Check if SMC flagged the battery as empty. * We trigger a graceful shutdown to let the OS save data. */ - if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &bcf0) == 0 && bcf0 != 0) { + if (macsmc_battery_read_bcf0(power, &bcf0) == 0 && bcf0 != 0) { power->orderly_shutdown_triggered = true; dev_crit(power->dev, "Battery critical (empty flag set). Triggering orderly shutdown.\n"); orderly_poweroff(true); @@ -744,6 +758,7 @@ static int macsmc_power_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); struct power_supply_config psy_cfg = {}; + struct apple_smc_key_info info; struct macsmc_power *power; bool has_battery = false; bool has_ac_adapter = false; @@ -842,6 +857,20 @@ static int macsmc_power_probe(struct platform_device *pdev) if (apple_smc_key_exists(smc, SMC_KEY(CH0I))) power->has_ch0i = true; + ret = apple_smc_get_key_info(power->smc, SMC_KEY(BCF0), &info); + if (ret) { + dev_err(&pdev->dev, "Failed to determine BCF0 key size\n"); + return ret; + } + if (info.size == 1) + power->bcf0_1byte = true; + else if (info.size == 4) + power->bcf0_1byte = false; + else { + dev_err(&pdev->dev, "Unexpected BCF0 key size %d\n", info.size); + return -EIO; + } + /* Reset "Optimised Battery Charging" flags to default state */ if (power->has_chte) apple_smc_write_u32(smc, SMC_KEY(CHTE), 0); @@ -894,7 +923,7 @@ static int macsmc_power_probe(struct platform_device *pdev) power->nominal_voltage_mv = MACSMC_NOMINAL_CELL_VOLTAGE_MV * power->num_cells; /* Enable critical shutdown notifications by reading status once */ - apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val32); + macsmc_battery_read_bcf0(power, &val32); psy_cfg.drv_data = power; power->batt = devm_power_supply_register(dev, &power->batt_desc, &psy_cfg); From f710fc6548a76bb429821eb04e14865d6d71e1ea Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Tue, 7 Apr 2026 13:33:46 +0200 Subject: [PATCH 02/28] Bluetooth: Add Broadcom channel priority commands Certain Broadcom bluetooth chips (bcm4377/bcm4378/bcm438) need ACL streams carrying audio to be set as "high priority" using a vendor specific command to prevent 10-ish second-long dropouts whenever something does a device scan. This patch sends the command when the socket priority is set to TC_PRIO_INTERACTIVE, as BlueZ does for audio. Signed-off-by: Sasha Finkelstein --- MAINTAINERS | 2 ++ drivers/bluetooth/hci_bcm4377.c | 2 ++ include/net/bluetooth/bluetooth.h | 4 ++++ include/net/bluetooth/hci_core.h | 11 +++++++++++ net/bluetooth/Kconfig | 7 +++++++ net/bluetooth/Makefile | 1 + net/bluetooth/brcm.c | 29 +++++++++++++++++++++++++++++ net/bluetooth/brcm.h | 17 +++++++++++++++++ net/bluetooth/hci_conn.c | 27 +++++++++++++++++++++++++++ net/bluetooth/l2cap_sock.c | 13 +++++++++++++ 10 files changed, 113 insertions(+) create mode 100644 net/bluetooth/brcm.c create mode 100644 net/bluetooth/brcm.h diff --git a/MAINTAINERS b/MAINTAINERS index a24c0cb47aa5b8..1fa5182c49ac4f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2593,6 +2593,8 @@ F: include/dt-bindings/pinctrl/apple.h F: include/linux/mfd/macsmc.h F: include/linux/soc/apple/* F: include/uapi/drm/asahi_drm.h +F: net/bluetooth/brcm.c +F: net/bluetooth/brcm.h ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c index 925d0a6359453e..5f79920c030681 100644 --- a/drivers/bluetooth/hci_bcm4377.c +++ b/drivers/bluetooth/hci_bcm4377.c @@ -2397,6 +2397,8 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (bcm4377->hw->broken_le_ext_adv_report_phy) hci_set_quirk(hdev, HCI_QUIRK_FIXUP_LE_EXT_ADV_REPORT_PHY); + hci_set_brcm_capable(hdev); + pci_set_drvdata(pdev, bcm4377); hci_set_drvdata(hdev, bcm4377); SET_HCIDEV_DEV(hdev, &pdev->dev); diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 3faea66b19799a..5d82944370e427 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -458,6 +458,7 @@ struct l2cap_ctrl { }; struct hci_dev; +struct hci_conn; typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode); typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status, @@ -470,6 +471,9 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status, int hci_ethtool_ts_info(unsigned int index, int sk_proto, struct kernel_ethtool_ts_info *ts_info); +int hci_conn_setsockopt(struct hci_conn *conn, struct sock *sk, int level, + int optname, sockptr_t optval, unsigned int optlen); + #define HCI_REQ_START BIT(0) #define HCI_REQ_SKB BIT(1) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index aa554c34f9ec35..a5f9251178cbf7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -642,6 +642,10 @@ struct hci_dev { bool aosp_quality_report; #endif +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + bool brcm_capable; +#endif + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); @@ -1792,6 +1796,13 @@ static inline void hci_set_aosp_capable(struct hci_dev *hdev) #endif } +static inline void hci_set_brcm_capable(struct hci_dev *hdev) +{ +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + hdev->brcm_capable = true; +#endif +} + static inline void hci_devcd_setup(struct hci_dev *hdev) { #ifdef CONFIG_DEV_COREDUMP diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index ee6457d1a5eed3..b611942c7b8ffd 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -107,6 +107,13 @@ config BT_AOSPEXT This options enables support for the Android Open Source Project defined HCI vendor extensions. +config BT_BRCMEXT + bool "Enable Broadcom extensions" + depends on BT + help + This option enables support for the Broadcom defined HCI + vendor extensions. + config BT_DEBUGFS bool "Export Bluetooth internals in debugfs" depends on BT && DEBUG_FS diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 41049b280887db..d402645dfb7da0 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -23,5 +23,6 @@ bluetooth-$(CONFIG_BT_LE) += iso.o bluetooth-$(CONFIG_BT_LEDS) += leds.o bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o +bluetooth-$(CONFIG_BT_BRCMEXT) += brcm.o bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o diff --git a/net/bluetooth/brcm.c b/net/bluetooth/brcm.c new file mode 100644 index 00000000000000..9aa0a265ab3d6b --- /dev/null +++ b/net/bluetooth/brcm.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 The Asahi Linux Contributors + */ + +#include +#include + +#include "brcm.h" + +int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable) +{ + struct sk_buff *skb; + u8 cmd[3]; + + if (!hdev->brcm_capable) + return 0; + + cmd[0] = handle; + cmd[1] = handle >> 8; + cmd[2] = !!enable; + + skb = hci_cmd_sync(hdev, 0xfc57, sizeof(cmd), cmd, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + return 0; +} diff --git a/net/bluetooth/brcm.h b/net/bluetooth/brcm.h new file mode 100644 index 00000000000000..fdaee63bd1d23c --- /dev/null +++ b/net/bluetooth/brcm.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 The Asahi Linux Contributors + */ + +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + +int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable); + +#else + +static inline int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable) +{ + return 0; +} + +#endif diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index eba4a548bef52a..f481c944061add 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -35,6 +35,7 @@ #include #include +#include "brcm.h" #include "smp.h" #include "eir.h" @@ -3156,6 +3157,32 @@ int hci_conn_set_phy(struct hci_conn *conn, u32 phys) } } +int hci_conn_setsockopt(struct hci_conn *conn, struct sock *sk, int level, + int optname, sockptr_t optval, unsigned int optlen) { + int val; + bool old_high, new_high, changed; + + if (level != SOL_SOCKET) + return 0; + + if (optname != SO_PRIORITY) + return 0; + + if (optlen < sizeof(int)) + return -EINVAL; + + if (copy_from_sockptr(&val, optval, sizeof(val))) + return -EFAULT; + + old_high = sk->sk_priority >= TC_PRIO_INTERACTIVE; + new_high = val >= TC_PRIO_INTERACTIVE; + changed = old_high != new_high; + if (!changed) + return 0; + + return brcm_set_high_priority(conn->hdev, conn->handle, new_high); +} + static int abort_conn_sync(struct hci_dev *hdev, void *data) { struct hci_conn *conn = data; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d8cbe278443779..0c86be41622e2b 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -897,6 +897,16 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, BT_DBG("sk %p", sk); + if (level == SOL_SOCKET) { + conn = chan->conn; + if (conn) + err = hci_conn_setsockopt(conn->hcon, sock->sk, level, + optname, optval, optlen); + if (err) + return err; + return sock_setsockopt(sock, level, optname, optval, optlen); + } + if (level == SOL_L2CAP) return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); @@ -1976,6 +1986,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy); + if (sock) + set_bit(SOCK_CUSTOM_SOCKOPT, &sock->flags); + /* The sock takes ownership of the caller's reference on chan. */ l2cap_pi(sk)->chan = chan; From 9c6f3ad0939b8e09bfccb8f444176806925b4027 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 21 May 2026 10:30:50 +0200 Subject: [PATCH 03/28] Fail the build on RUST=y and RUST_IS_AVAILABLE=n The current approach of silently disabling all rust drivers if the toolchain is missing results in users that try to compile their own kernels getting a "successful" build and then being confused about where did their drivers go. In comparison, missing openssl results in a build failure, not a disappearance of everything that depends on it. This also means that allyesconfig will depend on rust, but since the rust experiment concluded with "rust is here to stay", i believe that allyesconfig should be building rust drivers too. Signed-off-by: Sasha Finkelstein --- Documentation/rust/quick-start.rst | 6 +++--- init/Kconfig | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst index a6ec3fa94d3307..764c81d0dd5926 100644 --- a/Documentation/rust/quick-start.rst +++ b/Documentation/rust/quick-start.rst @@ -321,9 +321,9 @@ Configuration ------------- ``Rust support`` (``CONFIG_RUST``) needs to be enabled in the ``General setup`` -menu. The option is only shown if a suitable Rust toolchain is found (see -above), as long as the other requirements are met. In turn, this will make -visible the rest of options that depend on Rust. +menu. In turn, this will make visible the rest of options that depend on Rust. +You can check the value of ``RUST_IS_AVAILABLE`` to determine if your toolchain +is configured correctly. Afterwards, go to:: diff --git a/init/Kconfig b/init/Kconfig index 826a7d768ca368..7beb3f1753b206 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2190,7 +2190,6 @@ config PROFILING config RUST bool "Rust support" depends on HAVE_RUST - depends on RUST_IS_AVAILABLE select EXTENDED_MODVERSIONS if MODVERSIONS depends on !MODVERSIONS || GENDWARFKSYMS depends on !GCC_PLUGIN_RANDSTRUCT From 49e2583371803891bd2ad0764b5196989de3c346 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 9 May 2026 11:58:52 +0200 Subject: [PATCH 04/28] driver-core: Add error message to device_links_missing_supplier WARN() Signed-off-by: Janne Grunau --- drivers/base/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/base/core.c b/drivers/base/core.c index 3ee92a5b88c3a0..a9df82e5f6b5d9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1076,6 +1076,7 @@ static void device_links_missing_supplier(struct device *dev) if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } else { + dev_err(dev, "devices misses supplier %s\n", dev_name(link->supplier)); WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); WRITE_ONCE(link->status, DL_STATE_DORMANT); } From 073f2948a5f9970bb7f7f2a798c88cea74605a89 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 30 May 2026 12:16:44 +0200 Subject: [PATCH 05/28] dt-bindings: gpio: apple,smc: Add compatible for 'gp00' keys Apple M3 Pro and Max devices are using 'gp00' keys for GPIO in addition to 'gP00' keys. Add a second compatible to handle this keys with an additional macsmc-gpio instance. Signed-off-by: Janne Grunau --- Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml b/Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml index 42b1bc0a10c97a..b4063a9dd1248c 100644 --- a/Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml @@ -14,7 +14,9 @@ description: properties: compatible: - const: apple,smc-gpio + enum: + - apple,smc-gpio + - apple,smc-low-gpio gpio-controller: true From d02c8506e105ebae8cfb2dbf28867acaac245ad7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 29 May 2026 20:54:16 +0200 Subject: [PATCH 06/28] gpio: gpio-macsmc: Support 'gp00' GPIO keys Add support for SMC GPIO keys with a lower letter 'p' via the "apple,smc-low-gpio" compatible. This adds support for a second macsmc-gpio controller using 'gp00' keys. These keys are used on Apple M3 Pro and Max MacBooks in the controller for keyboard and trackpad and for the built-in DisplayPort to HDMI converter. Signed-off-by: Janne Grunau --- drivers/gpio/gpio-macsmc.c | 45 +++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpio-macsmc.c b/drivers/gpio/gpio-macsmc.c index b0952d066a9dd0..c3ca445a85ac9d 100644 --- a/drivers/gpio/gpio-macsmc.c +++ b/drivers/gpio/gpio-macsmc.c @@ -75,6 +75,7 @@ struct macsmc_gpio { struct gpio_chip gc; int first_index; + smc_key base_key; }; static int macsmc_gpio_nr(smc_key key) @@ -88,15 +89,15 @@ static int macsmc_gpio_nr(smc_key key) return low | (high << 4); } -static int macsmc_gpio_key(unsigned int offset) +static int macsmc_gpio_key(smc_key base_key, unsigned int offset) { - return _SMC_KEY("gP\0\0") | hex_asc_hi(offset) << 8 | hex_asc_lo(offset); + return base_key | hex_asc_hi(offset) << 8 | hex_asc_lo(offset); } static int macsmc_gpio_find_first_gpio_index(struct macsmc_gpio *smcgp) { struct apple_smc *smc = smcgp->smc; - smc_key key = macsmc_gpio_key(0); + smc_key key = macsmc_gpio_key(smcgp->base_key, 0); smc_key first_key, last_key; int start, count, ret; @@ -143,7 +144,7 @@ static int macsmc_gpio_find_first_gpio_index(struct macsmc_gpio *smcgp) static int macsmc_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) { struct macsmc_gpio *smcgp = gpiochip_get_data(gc); - smc_key key = macsmc_gpio_key(offset); + smc_key key = macsmc_gpio_key(smcgp->base_key, offset); u32 val; int ret; @@ -163,7 +164,7 @@ static int macsmc_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) static int macsmc_gpio_get(struct gpio_chip *gc, unsigned int offset) { struct macsmc_gpio *smcgp = gpiochip_get_data(gc); - smc_key key = macsmc_gpio_key(offset); + smc_key key = macsmc_gpio_key(smcgp->base_key, offset); u32 cmd, val; int ret; @@ -186,7 +187,7 @@ static int macsmc_gpio_get(struct gpio_chip *gc, unsigned int offset) static int macsmc_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) { struct macsmc_gpio *smcgp = gpiochip_get_data(gc); - smc_key key = macsmc_gpio_key(offset); + smc_key key = macsmc_gpio_key(smcgp->base_key, offset); int ret; value |= CMD_OUTPUT; @@ -217,7 +218,7 @@ static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc, if (ret < 0) return ret; - if (key > SMC_KEY(gPff)) + if (key > macsmc_gpio_key(smcgp->base_key, MAX_GPIO - 1)) break; gpio_nr = macsmc_gpio_nr(key); @@ -232,10 +233,15 @@ static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc, return 0; } +struct macsmc_gpio_of_match_data { + smc_key base_key; +}; + static int macsmc_gpio_probe(struct platform_device *pdev) { struct macsmc_gpio *smcgp; struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); + const struct macsmc_gpio_of_match_data *data = of_device_get_match_data(&pdev->dev); smc_key key; int ret; @@ -245,6 +251,7 @@ static int macsmc_gpio_probe(struct platform_device *pdev) smcgp->dev = &pdev->dev; smcgp->smc = smc; + smcgp->base_key = data ? data->base_key : _SMC_KEY("gP\0\0"); smcgp->first_index = macsmc_gpio_find_first_gpio_index(smcgp); if (smcgp->first_index < 0) @@ -254,12 +261,15 @@ static int macsmc_gpio_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (key > macsmc_gpio_key(MAX_GPIO - 1)) + if (key > macsmc_gpio_key(smcgp->base_key, MAX_GPIO - 1)) return -ENODEV; dev_info(smcgp->dev, "First GPIO key: %p4ch\n", &key); - smcgp->gc.label = "macsmc-pmu-gpio"; + if (device_is_compatible(&pdev->dev, "apple,smc-low-gpio")) + smcgp->gc.label = "macsmc-pmu-low-gpio"; + else + smcgp->gc.label = "macsmc-pmu-gpio"; smcgp->gc.owner = THIS_MODULE; smcgp->gc.get = macsmc_gpio_get; smcgp->gc.set = macsmc_gpio_set; @@ -273,8 +283,23 @@ static int macsmc_gpio_probe(struct platform_device *pdev) return devm_gpiochip_add_data(&pdev->dev, &smcgp->gc, smcgp); } +static const struct macsmc_gpio_of_match_data macsmc_gpio_up_data = { + .base_key = _SMC_KEY("gP\0\0"), +}; + +static const struct macsmc_gpio_of_match_data macsmc_gpio_low_data = { + .base_key = _SMC_KEY("gp\0\0"), +}; + static const struct of_device_id macsmc_gpio_of_table[] = { - { .compatible = "apple,smc-gpio", }, + { + .compatible = "apple,smc-gpio", + .data = &macsmc_gpio_up_data, + }, + { + .compatible = "apple,smc-low-gpio", + .data = &macsmc_gpio_low_data, + }, {} }; MODULE_DEVICE_TABLE(of, macsmc_gpio_of_table); From 0abb5959b930ceeab87659b86f484a95e2f4c134 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 30 May 2026 12:20:39 +0200 Subject: [PATCH 07/28] mfd: macsmc: Add second gpio subdevice for 'gp00' keys Apple M3 Pro and Max devices are using 'gp00' keys for GPIO in addition to 'gP00' keys. These keys are handled by an additional macsmc-gpio instance using the "apple,smc-low-gpio" compatible. Signed-off-by: Janne Grunau --- drivers/mfd/macsmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c index 514cba7dc897ae..31540f67ddbd8a 100644 --- a/drivers/mfd/macsmc.c +++ b/drivers/mfd/macsmc.c @@ -48,6 +48,7 @@ static const struct mfd_cell apple_smc_devs[] = { MFD_CELL_NAME("macsmc-input"), MFD_CELL_NAME("macsmc-power"), MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"), + MFD_CELL_OF("macsmc-low-gpio", NULL, NULL, 0, 0, "apple,smc-low-gpio"), MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"), MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"), MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"), From ffff3d16f6b2bd42e98d735421de216b24a30d17 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 14 Jun 2026 22:34:12 +0200 Subject: [PATCH 08/28] phy: apple: atc: Handle dummy pipehandler transisions Signed-off-by: Janne Grunau --- drivers/phy/apple/atc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c index 4156fabad742cc..6d8888732a83fb 100644 --- a/drivers/phy/apple/atc.c +++ b/drivers/phy/apple/atc.c @@ -1133,6 +1133,8 @@ static int atcphy_configure_pipehandler(struct apple_atcphy *atcphy, bool host) case ATCPHY_PIPEHANDLER_STATE_USB4: dev_warn(atcphy->dev, "ATCPHY_PIPEHANDLER_STATE_USB4 not implemented; falling back to USB2\n"); + fallthrough; + case ATCPHY_PIPEHANDLER_STATE_DUMMY: ret = atcphy_configure_pipehandler_dummy(atcphy); atcphy->pipehandler_up = false; break; From 28962a37ce0a0cd70d81781700f2bb2bddb38ec2 Mon Sep 17 00:00:00 2001 From: sofus Date: Sat, 18 Jul 2026 09:19:05 +0200 Subject: [PATCH 09/28] fixup! media: apple: avd: make get_ref_buf shared Signed-off-by: sofus --- drivers/media/platform/apple/avd/avd-drv.c | 2 +- drivers/media/platform/apple/avd/avd-hevc.c | 4 ++-- drivers/media/platform/apple/avd/avd-vp9.c | 6 +++--- drivers/media/platform/apple/avd/avd.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/apple/avd/avd-drv.c b/drivers/media/platform/apple/avd/avd-drv.c index 400cbe76cff8f7..2e826afb19b952 100644 --- a/drivers/media/platform/apple/avd/avd-drv.c +++ b/drivers/media/platform/apple/avd/avd-drv.c @@ -101,7 +101,7 @@ void avd_buf_free(struct avd_dev *avd, struct avd_buf *buf) } struct avd_decoded_buffer * -get_ref_buf(struct avd_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) +avd_get_ref_buf(struct avd_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) { struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; diff --git a/drivers/media/platform/apple/avd/avd-hevc.c b/drivers/media/platform/apple/avd/avd-hevc.c index af0a4eabaf9f16..e7dbe65f3bd6b2 100644 --- a/drivers/media/platform/apple/avd/avd-hevc.c +++ b/drivers/media/platform/apple/avd/avd-hevc.c @@ -91,7 +91,7 @@ static void stream_refs(struct avd_ctx *ctx, struct avd_hevc_run *run) for (int i = 0; i < decode->num_active_dpb_entries; i++) { dpb = &decode->dpb[i]; - ref_buf = get_ref_buf(ctx, &dst->base.vb, dpb->timestamp); + ref_buf = avd_get_ref_buf(ctx, &dst->base.vb, dpb->timestamp); dma_addr_t rvra_addr = vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0) @@ -503,7 +503,7 @@ static void stream_slice_mv(struct avd_ctx *ctx, struct avd_hevc_run *run, ? sl->ref_idx_l0 : sl->ref_idx_l1; dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf); - ref = get_ref_buf(ctx, &dst->base.vb, + ref = avd_get_ref_buf(ctx, &dst->base.vb, decode->dpb[ref_list[sl->collocated_ref_idx]].timestamp); ref_valid = diff --git a/drivers/media/platform/apple/avd/avd-vp9.c b/drivers/media/platform/apple/avd/avd-vp9.c index fb423616aa7726..77dd49de6cf140 100644 --- a/drivers/media/platform/apple/avd/avd-vp9.c +++ b/drivers/media/platform/apple/avd/avd-vp9.c @@ -163,9 +163,9 @@ static void set_refs(struct avd_ctx *ctx, struct avd_vp9_run *run) dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf); - ref_buf[0] = get_ref_buf(ctx, &dst->base.vb, frame->last_frame_ts); - ref_buf[1] = get_ref_buf(ctx, &dst->base.vb, frame->golden_frame_ts); - ref_buf[2] = get_ref_buf(ctx, &dst->base.vb, frame->alt_frame_ts); + ref_buf[0] = avd_get_ref_buf(ctx, &dst->base.vb, frame->last_frame_ts); + ref_buf[1] = avd_get_ref_buf(ctx, &dst->base.vb, frame->golden_frame_ts); + ref_buf[2] = avd_get_ref_buf(ctx, &dst->base.vb, frame->alt_frame_ts); push(INST_DMA3, "cm3_dma_config_7"); push(INST_DMA3, "cm3_dma_config_8"); diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h index a12b42e2a68461..82086ac3d9ca88 100644 --- a/drivers/media/platform/apple/avd/avd.h +++ b/drivers/media/platform/apple/avd/avd.h @@ -101,7 +101,7 @@ vb2_to_avd_decoded_buf(struct vb2_buffer *buf) return container_of(buf, struct avd_decoded_buffer, base.vb.vb2_buf); } struct avd_decoded_buffer * -get_ref_buf(struct avd_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp); +avd_get_ref_buf(struct avd_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp); struct avd_coded_fmt_ops { void (*adjust_decoded_fmt)(struct avd_ctx *ctx, From 6d9dfa12941509e7b256998cbcd3d2e16de15030 Mon Sep 17 00:00:00 2001 From: DesktopECHO <33142753+DesktopECHO@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:46:35 -0300 Subject: [PATCH 10/28] drm/asahi: Clean up deferred BOs when dropping a VM Since immediate mode was enabled, unmapping a GPU VA can defer drm_gpuvm_bo destruction until drm_gpuvm_bo_deferred_cleanup() is called. The GEM bind and unbind paths drain that list, but Vm::drop() unmaps the remaining user ranges without doing so. Drain the deferred list after both teardown unmaps. Otherwise a deferred drm_gpuvm_bo retains the imported GEM and dma-buf after its DRM file is closed, leaving its backing pages pinned. Fixes: 2aeee2dd4a79 ("drm/asahi: Switch gpuvm to DRM_GPUVM_IMMEDIATE_MODE") Signed-off-by: DesktopECHO <33142753+DesktopECHO@users.noreply.github.com> --- drivers/gpu/drm/asahi/file.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/asahi/file.rs b/drivers/gpu/drm/asahi/file.rs index 02a4ce874a92c8..061f289e40d933 100644 --- a/drivers/gpu/drm/asahi/file.rs +++ b/drivers/gpu/drm/asahi/file.rs @@ -87,6 +87,8 @@ impl Drop for Vm { { pr_err!("Vm::Drop: vm.unmap_range() failed\n"); } + + self.vm.bo_deferred_cleanup(); } } From a326e00f6d17ac093431a4a3aef75aa21cd95b36 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 25 Jul 2026 20:28:29 +0200 Subject: [PATCH 11/28] arm64: configs: asahi: Add new configs for v7.1 Add CONFIG_VIDEO_APPLE_AVD for AVD (Apple video decoder) support. Signed-off-by: Janne Grunau --- arch/arm64/configs/asahi.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/asahi.config b/arch/arm64/configs/asahi.config index c76f2c727fb0dd..b7ff1bbad24dcb 100644 --- a/arch/arm64/configs/asahi.config +++ b/arch/arm64/configs/asahi.config @@ -24,6 +24,7 @@ CONFIG_POWER_RESET_MACSMC=m CONFIG_CHARGER_MACSMC=m CONFIG_SENSORS_MACSMC_HWMON=m CONFIG_APPLE_WATCHDOG=m +CONFIG_VIDEO_APPLE_AVD=m CONFIG_VIDEO_APPLE_ISP=m CONFIG_DRM=y CONFIG_DRM_ASAHI=m From 42762d102d3a58f699a8fd46be1df89f8540f275 Mon Sep 17 00:00:00 2001 From: sofus Date: Sat, 25 Jul 2026 22:06:52 +0200 Subject: [PATCH 12/28] fixup! media: apple: avd: add hevc support Signed-off-by: sofus --- drivers/media/platform/apple/avd/avd-hevc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/avd/avd-hevc.c b/drivers/media/platform/apple/avd/avd-hevc.c index e7dbe65f3bd6b2..478db2d9eca076 100644 --- a/drivers/media/platform/apple/avd/avd-hevc.c +++ b/drivers/media/platform/apple/avd/avd-hevc.c @@ -311,7 +311,7 @@ static void set_header(struct avd_ctx *ctx, struct avd_hevc_run *run) push(0, "cm3_mark_end_section"); - if (avd->variant->revision != 3) + if (!(avd->variant->quirks & AVD_QUIRK_LSR)) push(0, "cm3_mark_end_section"); bytesperline = ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline; From e8efe09d4f378992c890d181d65e2ed8d8cb1194 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 8 Feb 2022 02:30:16 +0900 Subject: [PATCH 13/28] power: supply: macsmc_power: Add CHWA / CHLS charge thresholds This is a hardcoded charge threshold feature present in firmware 13.0 or newer. Userspace settings are rounded to one of the two possible behaviors. Since macOS Sequoia firmware, CHLS replaced CHWA and now allows an arbitrary end charge threshold to be configured. Prefer CHWA over CHLS since the SMC firmware from iBoot-10151.1.1 (macOS 14.0) is not compatible with our CHGLS usage. It was working with the SMC firmware from iBoot-10151.121.1 (macOS 14.5). Signed-off-by: Janne Grunau Co-developed-by: Janne Grunau Signed-off-by: Hector Martin --- drivers/power/supply/macsmc-power.c | 50 +++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/power/supply/macsmc-power.c b/drivers/power/supply/macsmc-power.c index c2dc198ba2f588..cfc57eb9a471b0 100644 --- a/drivers/power/supply/macsmc-power.c +++ b/drivers/power/supply/macsmc-power.c @@ -563,6 +563,24 @@ static int macsmc_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_MANUFACTURE_DAY: ret = macsmc_battery_get_date(&power->mfg_date[4], &val->intval); break; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: + if (power->has_chls) { + ret = apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16); + val->intval = vu16 & 0xff; + if (val->intval < CHLS_MIN_END_THRESHOLD || val->intval >= 100) + val->intval = 100; + } else if (power->has_chwa) { + flag = false; + ret = apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag); + val->intval = flag ? CHWA_FIXED_END_THRESHOLD : 100; + } else { + return -EINVAL; + } + if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD && + ret >= 0 && val->intval < 100 && val->intval >= CHLS_MIN_END_THRESHOLD) + val->intval -= CHWA_CHLS_FIXED_START_OFFSET; + break; default: return -EINVAL; } @@ -579,6 +597,28 @@ static int macsmc_battery_set_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: return macsmc_battery_set_charge_behaviour(power, val->intval); + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: + /* + * Ignore, we allow writes so userspace isn't confused but this is + * not configurable independently, it always is end - 5 or 100 depending + * on the end_threshold setting. + */ + return 0; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: + if (power->has_chls) { + u16 kval = 0; + /* TODO: Make CHLS_FORCE_DISCHARGE configurable */ + if (val->intval < CHLS_MIN_END_THRESHOLD) + kval = CHLS_FORCE_DISCHARGE | CHLS_MIN_END_THRESHOLD; + else if (val->intval < 100) + kval = CHLS_FORCE_DISCHARGE | (val->intval & 0xff); + return apple_smc_write_u16(power->smc, SMC_KEY(CHLS), kval); + } else if (power->has_chwa) { + return apple_smc_write_flag(power->smc, SMC_KEY(CHWA), + val->intval <= CHWA_PROP_WRITE_THRESHOLD); + } else { + return -EINVAL; + } default: return -EINVAL; } @@ -587,9 +627,14 @@ static int macsmc_battery_set_property(struct power_supply *psy, static int macsmc_battery_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { + struct macsmc_power *power = power_supply_get_drvdata(psy); + switch (psp) { case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: return true; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: + return power->has_chwa || power->has_chls; default: return false; } @@ -905,6 +950,11 @@ static int macsmc_power_probe(struct platform_device *pdev) else if (apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16) >= 0) power->has_chls = true; + if (power->has_chwa || power->has_chls) { + props[nprops++] = POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD; + props[nprops++] = POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD; + } + if (nprops > MACSMC_MAX_BATT_PROPS) return -ENOMEM; From e25660512a0361dee7dd300df3f2e4eb1f822790 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 26 Jul 2026 12:40:56 +0200 Subject: [PATCH 14/28] fixup! arm64: configs: asahi: Add new configs for v7.1 Signed-off-by: Janne Grunau --- arch/arm64/configs/asahi.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/configs/asahi.config b/arch/arm64/configs/asahi.config index b7ff1bbad24dcb..4aa7f499997e73 100644 --- a/arch/arm64/configs/asahi.config +++ b/arch/arm64/configs/asahi.config @@ -21,7 +21,7 @@ CONFIG_SPMI_APPLE=m CONFIG_PINCTRL_APPLE_GPIO=m CONFIG_GPIO_MACSMC=m CONFIG_POWER_RESET_MACSMC=m -CONFIG_CHARGER_MACSMC=m +CONFIG_MACSMC_POWER=m CONFIG_SENSORS_MACSMC_HWMON=m CONFIG_APPLE_WATCHDOG=m CONFIG_VIDEO_APPLE_AVD=m From 59462ad263bcc607a825aff73a17240616427a19 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 19 Jun 2026 20:20:35 +1000 Subject: [PATCH 15/28] 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 16/28] 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 17/28] 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 18/28] 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 19/28] 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 20/28] 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 21/28] 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 22/28] 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 23/28] 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 24/28] 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 25/28] 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 26/28] 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 27/28] 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 28/28] 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;