From aeed96195bce4d0117143e7778c03b1d70b3fcd1 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Fri, 12 Jun 2026 20:36:03 +0200 Subject: [PATCH 01/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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 1668fc68de431a7c635c7ef801c29ffd330373db Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:07:59 +0200 Subject: [PATCH 15/23] dt-bindings: dma: apple,admac: Add M3 generation ADMACs The admacs seen in M3-generation SoCs (t603x, t8122) need additional configuration writes and so are getting a new compatible chain. Signed-off-by: Sasha Finkelstein --- Documentation/devicetree/bindings/dma/apple,admac.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml index 6a200cbd7d0280..560fd19a4c6f1f 100644 --- a/Documentation/devicetree/bindings/dma/apple,admac.yaml +++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml @@ -10,7 +10,7 @@ description: | Apple's Audio DMA Controller (ADMAC) is used to fetch and store audio samples on SoCs from the "Apple Silicon" family. - The controller has been seen with up to 24 channels. Even-numbered channels + The controller has been seen with up to 32 channels. Even-numbered channels are TX-only, odd-numbered are RX-only. Individual channels are coupled to fixed device endpoints. @@ -24,6 +24,7 @@ properties: compatible: oneOf: - items: + - const: apple,t8122-admac - const: apple,t6020-admac - const: apple,t8103-admac - items: @@ -33,6 +34,11 @@ properties: - apple,t8103-admac - apple,t8112-admac - const: apple,admac + - items: + - enum: + - apple,t6030-admac + - apple,t6031-admac + - const: apple,t8122-admac reg: maxItems: 1 @@ -43,7 +49,7 @@ properties: Clients specify a single cell with channel number. dma-channels: - maximum: 24 + maximum: 32 interrupts: minItems: 4 From 972c782db8bc107933d19937766ac232ee9a6ae1 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:58:25 +0200 Subject: [PATCH 16/23] arm64: dts: apple: t8122: Add aop/admac nodes Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t8122-j504.dts | 21 ++++++++ arch/arm64/boot/dts/apple/t8122-j613.dts | 21 ++++++++ arch/arm64/boot/dts/apple/t8122-j615.dts | 21 ++++++++ arch/arm64/boot/dts/apple/t8122.dtsi | 64 +++++++++++++++++++++++- 4 files changed, 126 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t8122-j504.dts b/arch/arm64/boot/dts/apple/t8122-j504.dts index ef241ed635f7e3..d76a5d79437289 100644 --- a/arch/arm64/boot/dts/apple/t8122-j504.dts +++ b/arch/arm64/boot/dts/apple/t8122-j504.dts @@ -101,6 +101,27 @@ }; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&aop_audio { + apple,chassis-name = "J504"; + apple,machine-kind = "MacBook Pro"; +}; + / { speaker_sdz: fixed-regulator-sn012776-sdz { compatible = "regulator-fixed"; diff --git a/arch/arm64/boot/dts/apple/t8122-j613.dts b/arch/arm64/boot/dts/apple/t8122-j613.dts index ec8eeebfdce40c..1a02bb7c97bd2c 100644 --- a/arch/arm64/boot/dts/apple/t8122-j613.dts +++ b/arch/arm64/boot/dts/apple/t8122-j613.dts @@ -38,6 +38,27 @@ brcm,board-type = "apple,dnieper"; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&aop_audio { + apple,chassis-name = "J613"; + apple,machine-kind = "MacBook Air"; +}; + /* Virtual regulator representing the shared shutdown GPIO */ / { speaker_sdz: fixed-regulator-sn012776-sdz { diff --git a/arch/arm64/boot/dts/apple/t8122-j615.dts b/arch/arm64/boot/dts/apple/t8122-j615.dts index 9914c34055025d..e10e31bb2b5cda 100644 --- a/arch/arm64/boot/dts/apple/t8122-j615.dts +++ b/arch/arm64/boot/dts/apple/t8122-j615.dts @@ -30,6 +30,27 @@ }; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&aop_audio { + apple,chassis-name = "J615"; + apple,machine-kind = "MacBook Air"; +}; + &wifi0 { brcm,board-type = "apple,tuzla"; }; diff --git a/arch/arm64/boot/dts/apple/t8122.dtsi b/arch/arm64/boot/dts/apple/t8122.dtsi index 50b39bfe521952..a657784b8bea51 100644 --- a/arch/arm64/boot/dts/apple/t8122.dtsi +++ b/arch/arm64/boot/dts/apple/t8122.dtsi @@ -529,7 +529,7 @@ }; admac: dma-controller@2a3200000 { - compatible = "apple,t8122-admac", "apple,t8103-admac"; + compatible = "apple,t8122-admac"; reg = <0x2 0xa3200000 0x0 0x34000>; dma-channels = <24>; interrupts-extended = <0>, @@ -830,6 +830,68 @@ ; }; + aop_mbox: mbox@2f4408000 { + compatible = "apple,t8122-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0xf4408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@2f4818000 { + compatible = "apple,t8122-dart", "apple,t8110-dart"; + reg = <0x2 0xf4818000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + aop_admac: dma-controller@2f4980000 { + compatible = "apple,t8122-admac"; + reg = <0x2 0xf4980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 412 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 10>; + status = "disabled"; + }; + + aop: aop@2f4c00000 { + compatible = "apple,t8122-aop", "apple,t6020-aop"; + reg = <0x2 0xf4c00000 0x0 0x1e0000>, + <0x2 0xf4400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t8122-aop-audio", "apple,t6030-aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t8122-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t8122-aop-las", "apple,aop-las"; + }; + }; + pinctrl_aop: pinctrl@2f4824000 { compatible = "apple,t8122-pinctrl", "apple,t8103-pinctrl"; reg = <0x2 0xf4824000 0x0 0x4000>; From e2bfaf79016888a9c79b1005037c218957676250 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:59:34 +0200 Subject: [PATCH 17/23] dts: apple: t603x: Add aop/admac nodes Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t6030-j514s.dts | 5 ++ arch/arm64/boot/dts/apple/t6030-j516s.dts | 5 ++ arch/arm64/boot/dts/apple/t6030.dtsi | 65 ++++++++++++++++++- arch/arm64/boot/dts/apple/t6031-die0.dtsi | 65 ++++++++++++++++++- arch/arm64/boot/dts/apple/t6031-j514c.dts | 5 ++ arch/arm64/boot/dts/apple/t6031-j516c.dts | 5 ++ arch/arm64/boot/dts/apple/t6034-j514m.dts | 5 ++ arch/arm64/boot/dts/apple/t6034-j516m.dts | 5 ++ .../arm64/boot/dts/apple/t603x-j514-j516.dtsi | 16 +++++ 9 files changed, 174 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6030-j514s.dts b/arch/arm64/boot/dts/apple/t6030-j514s.dts index 4ba49debe47d78..106df3e83bb908 100644 --- a/arch/arm64/boot/dts/apple/t6030-j514s.dts +++ b/arch/arm64/boot/dts/apple/t6030-j514s.dts @@ -66,6 +66,11 @@ interrupts-extended = <&pinctrl_ap 100 IRQ_TYPE_LEVEL_LOW>; }; +&aop_audio { + apple,chassis-name = "J514"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j514-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J514"; diff --git a/arch/arm64/boot/dts/apple/t6030-j516s.dts b/arch/arm64/boot/dts/apple/t6030-j516s.dts index c679e21ade96da..838c2003419baa 100644 --- a/arch/arm64/boot/dts/apple/t6030-j516s.dts +++ b/arch/arm64/boot/dts/apple/t6030-j516s.dts @@ -66,6 +66,11 @@ interrupts-extended = <&pinctrl_ap 100 IRQ_TYPE_LEVEL_LOW>; }; +&aop_audio { + apple,chassis-name = "J516"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j516-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J516"; diff --git a/arch/arm64/boot/dts/apple/t6030.dtsi b/arch/arm64/boot/dts/apple/t6030.dtsi index 2c2c388524317d..20a93f25b885fc 100644 --- a/arch/arm64/boot/dts/apple/t6030.dtsi +++ b/arch/arm64/boot/dts/apple/t6030.dtsi @@ -582,7 +582,7 @@ }; admac: dma-controller@28b200000 { - compatible = "apple,t6030-admac", "apple,t8103-admac"; + compatible = "apple,t6030-admac", "apple,t8122-admac"; reg = <0x2 0x8b200000 0x0 0x34000>; #dma-cells = <1>; dma-channels = <24>; @@ -932,6 +932,69 @@ ; }; + aop_mbox: mbox@374408000 { + compatible = "apple,t6030-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x74408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@374818000 { + compatible = "apple,t6030-dart", "apple,t8110-dart"; + reg = <0x3 0x74818000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + // apple,dma-range = <0x100 0x0 0x300 0x0>; + }; + + aop_admac: dma-controller@374980000 { + compatible = "apple,t6030-admac", "apple,t8122-admac"; + reg = <0x3 0x74980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 460 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 10>; + status = "disabled"; + }; + + aop: aop@374c00000 { + compatible = "apple,t6030-aop", "apple,t6020-aop"; + reg = <0x3 0x74c00000 0x0 0x1e0000>, + <0x3 0x74400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t6030-aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t6030-aop-als", "apple,t6020-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t6030-aop-las", "apple,t6020-aop-las", "apple,aop-las"; + }; + }; + pinctrl_aop: pinctrl@374824000 { compatible = "apple,t6030-pinctrl", "apple,t8103-pinctrl"; reg = <0x3 0x74824000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t6031-die0.dtsi b/arch/arm64/boot/dts/apple/t6031-die0.dtsi index 9591bace819be7..0ffe0dfdd113d9 100644 --- a/arch/arm64/boot/dts/apple/t6031-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t6031-die0.dtsi @@ -161,6 +161,69 @@ ; }; + aop_mbox: mbox@2a8408000 { + compatible = "apple,t6031-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0xa8408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@2a8818000 { + compatible = "apple,t6031-dart", "apple,t8110-dart"; + reg = <0x2 0xa8818000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + // apple,dma-range = <0x100 0x0 0x300 0x0>; + }; + + aop_admac: dma-controller@2a8980000 { + compatible = "apple,t6031-admac", "apple,t8122-admac"; + reg = <0x2 0xa8980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 0 630 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 10>; + status = "disabled"; + }; + + aop: aop@2a8c00000 { + compatible = "apple,t6031-aop", "apple,t6020-aop"; + reg = <0x2 0xa8c00000 0x0 0x2a0000>, + <0x2 0xa8400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t6031-aop-audio", "apple,t6030-aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t6031-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t6031-aop-las", "apple,aop-las"; + }; + }; + mtp: mtp@2ac400000 { compatible = "apple,t6031-mtp", "apple,t8122-rtk-helper-asc4", "apple,mtp", "apple,rtk-helper-asc4"; reg = <0x2 0xac400000 0x0 0x4000>, @@ -457,7 +520,7 @@ }; admac: dma-controller@393200000 { - compatible = "apple,t6031-admac", "apple,t8103-admac"; + compatible = "apple,t6031-admac", "apple,t8122-admac"; reg = <0x3 0x93200000 0x0 0x34000>; #dma-cells = <1>; dma-channels = <24>; diff --git a/arch/arm64/boot/dts/apple/t6031-j514c.dts b/arch/arm64/boot/dts/apple/t6031-j514c.dts index 1bfb9f2c63923a..ec53b88aebc985 100644 --- a/arch/arm64/boot/dts/apple/t6031-j514c.dts +++ b/arch/arm64/boot/dts/apple/t6031-j514c.dts @@ -29,6 +29,11 @@ brcm,board-type = "apple,texa"; }; +&aop_audio { + apple,chassis-name = "J514"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j514-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J514"; diff --git a/arch/arm64/boot/dts/apple/t6031-j516c.dts b/arch/arm64/boot/dts/apple/t6031-j516c.dts index a199b0b11814f2..9e447741cba718 100644 --- a/arch/arm64/boot/dts/apple/t6031-j516c.dts +++ b/arch/arm64/boot/dts/apple/t6031-j516c.dts @@ -29,6 +29,11 @@ brcm,board-type = "apple,jura"; }; +&aop_audio { + apple,chassis-name = "J516"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j516-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J516"; diff --git a/arch/arm64/boot/dts/apple/t6034-j514m.dts b/arch/arm64/boot/dts/apple/t6034-j514m.dts index 7ef946c9ea27cc..f9c2b6241c9551 100644 --- a/arch/arm64/boot/dts/apple/t6034-j514m.dts +++ b/arch/arm64/boot/dts/apple/t6034-j514m.dts @@ -29,6 +29,11 @@ brcm,board-type = "apple,texa"; }; +&aop_audio { + apple,chassis-name = "J514"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j514-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J514"; diff --git a/arch/arm64/boot/dts/apple/t6034-j516m.dts b/arch/arm64/boot/dts/apple/t6034-j516m.dts index a2b5abed07473a..22ad5251eaecef 100644 --- a/arch/arm64/boot/dts/apple/t6034-j516m.dts +++ b/arch/arm64/boot/dts/apple/t6034-j516m.dts @@ -29,6 +29,11 @@ brcm,board-type = "apple,jura"; }; +&aop_audio { + apple,chassis-name = "J516"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j516-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J516"; diff --git a/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi b/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi index f868eeb8ace8d9..0adfe50b78e788 100644 --- a/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi +++ b/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi @@ -251,6 +251,22 @@ status = "okay"; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + / { sound: sound { /* compatible is set per machine */ From 12c43f3ddf89e8387a44d51c9945d345d6257633 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:10:05 +0200 Subject: [PATCH 18/23] dmaengine: apple-admac: Add M3 generation ADMACs The admacs present on t8122 and t603x SoCs need additional writes in order to operate correctly. The exact purpose of this register is unknown Signed-off-by: Sasha Finkelstein --- drivers/dma/apple-admac.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index 14a5ee14a48156..75b75081bccfef 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -39,10 +39,14 @@ #define FLAG_DESC_NOTIFY BIT(16) +#define T603X_UNK_28_VAL 0x200000 + #define REG_TX_START 0x0000 #define REG_TX_STOP 0x0004 #define REG_RX_START 0x0008 #define REG_RX_STOP 0x000c +#define REG_UNK_28 0x0028 +#define REG_UNK_2C 0x002c #define REG_IMPRINT 0x0090 #define REG_TX_SRAM_SIZE 0x0094 #define REG_RX_SRAM_SIZE 0x0098 @@ -127,6 +131,7 @@ struct admac_data { struct mutex cache_alloc_lock; struct admac_sram txcache, rxcache; + bool set_unk28; int irq; int irq_index; int nchannels; @@ -147,6 +152,10 @@ struct admac_tx { struct list_head node; }; +struct admac_hw { + bool set_unk28; +}; + static int admac_alloc_sram_carveout(struct admac_data *ad, enum dma_transfer_direction dir, u32 *out) @@ -747,6 +756,11 @@ static int admac_device_config(struct dma_chan *chan, u32 bus_width = readl_relaxed(ad->base + REG_BUS_WIDTH(adchan->no)) & ~(BUS_WIDTH_WORD_SIZE | BUS_WIDTH_FRAME_SIZE); + if (ad->set_unk28) { + writel_relaxed(T603X_UNK_28_VAL, ad->base + REG_UNK_28); + writel_relaxed(T603X_UNK_28_VAL, ad->base + REG_UNK_2C); + } + switch (is_tx ? config->dst_addr_width : config->src_addr_width) { case DMA_SLAVE_BUSWIDTH_1_BYTE: wordsize = 1; @@ -805,6 +819,7 @@ static int admac_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct admac_data *ad; struct dma_device *dma; + const struct admac_hw *hw; int nchannels; int err, irq, i; @@ -813,6 +828,9 @@ static int admac_probe(struct platform_device *pdev) dev_err(&pdev->dev, "missing or invalid dma-channels property\n"); return -EINVAL; } + hw = of_device_get_match_data(&pdev->dev); + if (!hw) + return -EINVAL; ad = devm_kzalloc(&pdev->dev, struct_size(ad, channels, nchannels), GFP_KERNEL); if (!ad) @@ -821,6 +839,7 @@ static int admac_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ad); ad->dev = &pdev->dev; ad->nchannels = nchannels; + ad->set_unk28 = hw->set_unk28; mutex_init(&ad->cache_alloc_lock); /* @@ -935,9 +954,18 @@ static void admac_remove(struct platform_device *pdev) reset_control_rearm(ad->rstc); } +static const struct admac_hw admac_t8013_hw = { + .set_unk28 = false, +}; + +static const struct admac_hw admac_t8122_hw = { + .set_unk28 = true, +}; + static const struct of_device_id admac_of_match[] = { - { .compatible = "apple,t8103-admac", }, - { .compatible = "apple,admac", }, + { .compatible = "apple,t8122-admac", .data = &admac_t8122_hw }, + { .compatible = "apple,t8103-admac", .data = &admac_t8013_hw }, + { .compatible = "apple,admac", .data = &admac_t8013_hw }, { } }; MODULE_DEVICE_TABLE(of, admac_of_match); From f3cf4b1d7caf06b15aea0e99e8b52c8b43e1b292 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:14:13 +0200 Subject: [PATCH 19/23] ASoC: apple: aop: Add M3 generation built-in mics Those get a new "HF" decimator, and an extra component that needs to be attached Signed-off-by: Sasha Finkelstein --- sound/soc/apple/aop_audio.rs | 388 +++++++++++++++++++++++++++++------ 1 file changed, 329 insertions(+), 59 deletions(-) diff --git a/sound/soc/apple/aop_audio.rs b/sound/soc/apple/aop_audio.rs index 3dbd48d62e7ccf..6cb974a82e7859 100644 --- a/sound/soc/apple/aop_audio.rs +++ b/sound/soc/apple/aop_audio.rs @@ -63,9 +63,13 @@ impl fmt::Debug for U32 { const EPIC_SUBTYPE_WRAPPED_CALL: u16 = 0x20; const CALLTYPE_AUDIO_ATTACH_DEVICE: u32 = 0xc3000002; const CALLTYPE_AUDIO_SET_PROP: u32 = 0xc3000005; -const PDM_NUM_COEFFS: usize = 120; +const DECIM_NUM_COEFFS: usize = 120; +const DECIM_NUM_COEFFS_HF: usize = 1023; const DECIMATION_RATIOS: [u8; 3] = [0xf, 5, 2]; -const COEFFICIENTS: [u8; PDM_NUM_COEFFS * mem::size_of::()] = [ +const DECIMATION_RATIOS_HF: [u8; 3] = [10, 5, 3]; +const DECIM_LATENCY: U32 = U32(15); +const DECIM_LATENCY_HF: u32 = 36; +const COEFFICIENTS: [u8; 400] = [ 0x88, 0x03, 0x00, 0x00, 0x82, 0x08, 0x00, 0x00, 0x51, 0x12, 0x00, 0x00, 0x0a, 0x23, 0x00, 0x00, 0xce, 0x3d, 0x00, 0x00, 0x97, 0x66, 0x00, 0x00, 0x43, 0xa2, 0x00, 0x00, 0x9c, 0xf6, 0x00, 0x00, 0x53, 0x6a, 0x01, 0x00, 0xe6, 0x04, 0x02, 0x00, 0x7e, 0xce, 0x02, 0x00, 0xae, 0xcf, 0x03, 0x00, @@ -91,13 +95,204 @@ const COEFFICIENTS: [u8; PDM_NUM_COEFFS * mem::size_of::()] = [ 0x83, 0xb6, 0xa1, 0xff, 0xe2, 0xd5, 0xef, 0xff, 0x94, 0x9b, 0x76, 0x00, 0xf3, 0xd7, 0x25, 0x00, 0xff, 0xfc, 0x67, 0xff, 0xe3, 0xac, 0xb6, 0xff, 0x52, 0x1b, 0xcc, 0x00, 0x3c, 0x8a, 0x8b, 0x00, 0x9f, 0x0c, 0xcd, 0xfe, 0x5c, 0x68, 0xcc, 0xfe, 0x4d, 0xc5, 0x98, 0x02, 0x82, 0xcf, 0xfb, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -const FILTER_LENGTHS: u32 = 0x542c47; +const COEFFICIENTS_HF: [u8; 3088] = [ + 0x6b, 0xae, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x95, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x47, 0xf1, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x72, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x6b, 0x6f, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0x46, 0xd3, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc2, 0x82, 0xc2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbd, 0xb2, 0x9e, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x4c, 0xa8, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0x69, 0x36, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x1d, 0xa3, 0xf6, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x45, 0xb7, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x64, 0xec, 0x82, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x9d, 0x67, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x79, 0xd7, 0x75, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb5, 0xbe, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x7c, 0x3e, 0x51, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0xf3, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc9, 0x1d, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x41, 0xf0, 0x02, 0x00, 0x00, 0x00, 0x00, + 0xed, 0x80, 0x9b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x43, 0x9c, 0x45, 0x06, 0x00, 0x00, 0x00, 0x00, + 0xaa, 0x3b, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xfe, 0x9d, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x76, 0xbb, 0x08, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc4, 0xc6, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x8b, 0x1a, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x48, 0xe3, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x89, 0xfc, 0x12, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x5f, 0x39, 0x29, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0x6d, 0x6a, 0xaf, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x64, 0x7b, 0x50, 0xea, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xc6, 0xe1, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x8c, 0x53, 0xe1, 0xff, 0xff, 0xff, 0xff, + 0x0d, 0x64, 0x9b, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x09, 0x6d, 0x9a, 0xe3, 0xff, 0xff, 0xff, 0xff, + 0x19, 0xe0, 0x01, 0xeb, 0xff, 0xff, 0xff, 0xff, 0x17, 0x15, 0x39, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0x19, 0x59, 0x48, 0x08, 0x00, 0x00, 0x00, 0x00, 0xe2, 0xa1, 0xcb, 0x1d, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x81, 0xef, 0x36, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xa9, 0x79, 0x52, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x02, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xdf, 0x57, 0x8a, 0x00, 0x00, 0x00, 0x00, + 0xfb, 0x9f, 0x19, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x47, 0xeb, 0x6b, 0xb7, 0x00, 0x00, 0x00, 0x00, + 0x9d, 0x23, 0xdb, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x9d, 0x59, 0xcd, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x9d, 0x59, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x23, 0xdb, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x47, 0xeb, 0x6b, 0xb7, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x9f, 0x19, 0xa3, 0x00, 0x00, 0x00, 0x00, + 0x4a, 0xdf, 0x57, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x02, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0xe3, 0xa9, 0x79, 0x52, 0x00, 0x00, 0x00, 0x00, 0x64, 0x81, 0xef, 0x36, 0x00, 0x00, 0x00, 0x00, + 0xe2, 0xa1, 0xcb, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x19, 0x59, 0x48, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x15, 0x39, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x19, 0xe0, 0x01, 0xeb, 0xff, 0xff, 0xff, 0xff, + 0x09, 0x6d, 0x9a, 0xe3, 0xff, 0xff, 0xff, 0xff, 0x0d, 0x64, 0x9b, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xfb, 0x8c, 0x53, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc6, 0xe1, 0xe4, 0xff, 0xff, 0xff, 0xff, + 0x64, 0x7b, 0x50, 0xea, 0xff, 0xff, 0xff, 0xff, 0x6d, 0x6a, 0xaf, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0x5f, 0x39, 0x29, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x89, 0xfc, 0x12, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0x48, 0xe3, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x1a, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x48, 0xc4, 0xc6, 0x07, 0x00, 0x00, 0x00, 0x00, 0x18, 0x76, 0xbb, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x4e, 0xfe, 0x9d, 0x08, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x3b, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x43, 0x9c, 0x45, 0x06, 0x00, 0x00, 0x00, 0x00, 0xed, 0x80, 0x9b, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x41, 0xf0, 0x02, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x1d, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x9b, 0xf3, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x3e, 0x51, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0xb5, 0xbe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x79, 0xd7, 0x75, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x0c, 0x9d, 0x67, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x64, 0xec, 0x82, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x4c, 0x45, 0xb7, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1d, 0xa3, 0xf6, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x99, 0x69, 0x36, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0xa8, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbd, 0xb2, 0x9e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x82, 0xc2, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x46, 0xd3, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6b, 0x6f, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x72, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0xf1, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x70, 0x95, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6b, 0xae, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8f, 0xc2, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x98, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9f, 0x52, 0xe2, 0xff, 0xff, 0xff, 0xff, 0xff, 0x35, 0x21, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x25, 0xe4, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcd, 0xec, 0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x6b, 0x33, 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0xd8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9a, 0x64, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x75, 0x22, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x8e, 0x2e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x9d, 0x36, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x66, 0xc2, 0x04, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x3c, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x18, 0xf7, 0xe4, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x0e, 0x2e, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x72, 0xea, 0xf7, 0xef, 0xff, 0xff, 0xff, 0xff, 0x41, 0xcb, 0x2e, 0xed, 0xff, 0xff, 0xff, 0xff, + 0x17, 0x9c, 0xae, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xb1, 0xb5, 0xf1, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0xe1, 0x3a, 0xca, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf4, 0xbe, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x72, 0x94, 0x30, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x8a, 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x57, 0xb8, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x52, 0x79, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0x8e, 0x8f, 0x60, 0xc9, 0xff, 0xff, 0xff, 0xff, 0x32, 0x60, 0xeb, 0x98, 0xff, 0xff, 0xff, 0xff, + 0x65, 0x2d, 0x8f, 0x7d, 0xff, 0xff, 0xff, 0xff, 0x67, 0xdd, 0xb5, 0x8a, 0xff, 0xff, 0xff, 0xff, + 0x26, 0x98, 0x96, 0xcd, 0xff, 0xff, 0xff, 0xff, 0x1d, 0xe5, 0xcf, 0x47, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x3c, 0xb2, 0xec, 0x00, 0x00, 0x00, 0x00, 0x66, 0x20, 0x81, 0xa2, 0x01, 0x00, 0x00, 0x00, + 0x2b, 0xb4, 0xbe, 0x47, 0x02, 0x00, 0x00, 0x00, 0x99, 0x16, 0x3e, 0xbb, 0x02, 0x00, 0x00, 0x00, + 0xd9, 0x88, 0xb5, 0xe4, 0x02, 0x00, 0x00, 0x00, 0x99, 0x16, 0x3e, 0xbb, 0x02, 0x00, 0x00, 0x00, + 0x2b, 0xb4, 0xbe, 0x47, 0x02, 0x00, 0x00, 0x00, 0x66, 0x20, 0x81, 0xa2, 0x01, 0x00, 0x00, 0x00, + 0xe1, 0x3c, 0xb2, 0xec, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xe5, 0xcf, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x98, 0x96, 0xcd, 0xff, 0xff, 0xff, 0xff, 0x67, 0xdd, 0xb5, 0x8a, 0xff, 0xff, 0xff, 0xff, + 0x65, 0x2d, 0x8f, 0x7d, 0xff, 0xff, 0xff, 0xff, 0x32, 0x60, 0xeb, 0x98, 0xff, 0xff, 0xff, 0xff, + 0x8e, 0x8f, 0x60, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x52, 0x79, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0x75, 0x57, 0xb8, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x8a, 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x72, 0x94, 0x30, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf4, 0xbe, 0x21, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x3a, 0xca, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb5, 0xf1, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0x17, 0x9c, 0xae, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x41, 0xcb, 0x2e, 0xed, 0xff, 0xff, 0xff, 0xff, + 0x72, 0xea, 0xf7, 0xef, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x0e, 0x2e, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x18, 0xf7, 0xe4, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x3c, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x66, 0xc2, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x9d, 0x36, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x8e, 0x2e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x75, 0x22, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x9a, 0x64, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xd8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6b, 0x33, 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcd, 0xec, 0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x25, 0xe4, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0x35, 0x21, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9f, 0x52, 0xe2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x98, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8f, 0xc2, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x79, 0x48, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x6e, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xb5, 0xec, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, 0xbd, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9a, 0xd2, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x86, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x31, 0xdf, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xed, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x97, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xa4, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc4, 0x9b, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf6, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xad, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0x77, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf9, 0x42, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xc9, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0xbf, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0x94, 0x67, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x91, 0x9d, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbe, 0x71, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf5, 0xde, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0xf3, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x61, 0xa5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xd1, 0xdc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xaf, 0x6c, 0xa9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x0e, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x65, 0x2b, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xed, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x92, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd8, 0x9f, 0xa9, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0x9f, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x87, 0xfc, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0xe7, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x5a, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x57, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xcd, 0x5a, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xd4, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe0, 0x19, 0xe9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x68, 0xa7, 0x71, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x73, 0xe3, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x3a, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xba, 0xa4, 0x19, 0x01, 0x00, 0x00, 0x00, 0x00, 0x96, 0x6b, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x35, 0x3d, 0x93, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xf7, 0x51, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x6e, 0x64, 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0x41, 0x7b, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x27, 0xc5, 0x2f, 0x02, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xbe, 0x5e, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0x04, 0x44, 0xff, 0xff, 0xff, 0xff, 0xff, 0x62, 0xfc, 0x83, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0xbd, 0x4e, 0xac, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x5f, 0x43, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe9, 0x98, 0x6d, 0x02, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xdc, 0x3e, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xbb, 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x25, 0x1c, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x67, 0x17, 0x11, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x11, 0xe7, 0x25, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0xc8, 0xb5, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, 0xa6, 0x2c, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0xb3, 0x5f, 0x04, 0x00, 0x00, 0x00, 0x00, 0x79, 0x42, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x3c, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x3b, 0x50, 0xfa, 0xff, 0xff, 0xff, 0xff, + 0x0e, 0x98, 0x07, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xb5, 0xe7, 0x8e, 0x02, 0x00, 0x00, 0x00, 0x00, + 0xcc, 0xd9, 0x7b, 0x06, 0x00, 0x00, 0x00, 0x00, 0x35, 0xf4, 0x4c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0xfd, 0x2b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x44, 0xf5, 0x8a, 0xf9, 0xff, 0xff, 0xff, 0xff, + 0x55, 0x2b, 0x7b, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x21, 0x8f, 0xb0, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0x4b, 0x6c, 0x5a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x36, 0x50, 0x35, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0xa1, 0x05, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x27, 0xf7, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xac, 0x6c, 0x13, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xdd, 0xf2, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x99, 0x6d, 0x89, 0xff, 0xff, 0xff, 0xff, 0xff, 0x68, 0x1a, 0x44, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x7e, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2e, 0xe4, 0x04, 0x00, 0x00, 0x00, 0x00, + 0xd8, 0x30, 0x0a, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x43, 0xe2, 0x0e, 0xf2, 0xff, 0xff, 0xff, 0xff, + 0x75, 0x3f, 0x39, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xab, 0xf0, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xe6, 0x34, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xd6, 0x71, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x52, 0xee, 0x96, 0x02, 0x00, 0x00, 0x00, 0x00, 0x51, 0x29, 0xa6, 0xf3, 0xff, 0xff, 0xff, 0xff, + 0x09, 0x4e, 0xe9, 0xed, 0xff, 0xff, 0xff, 0xff, 0x06, 0xef, 0xe0, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x88, 0x68, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x30, 0xdf, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x2e, 0xa3, 0xdb, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xde, 0xdb, 0x51, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x93, 0xba, 0xef, 0xec, 0xff, 0xff, 0xff, 0xff, 0x0b, 0xb4, 0x38, 0xea, 0xff, 0xff, 0xff, 0xff, + 0xcd, 0x51, 0x75, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x00, 0xbf, 0x2f, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x05, 0xc2, 0x19, 0x00, 0x00, 0x00, 0x00, 0x20, 0xed, 0xa0, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x3a, 0x63, 0xd8, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x4b, 0xe2, 0x44, 0xe5, 0xff, 0xff, 0xff, 0xff, + 0x56, 0x89, 0xa8, 0xe7, 0xff, 0xff, 0xff, 0xff, 0x0e, 0x62, 0x60, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x85, 0x0c, 0xe2, 0x17, 0x00, 0x00, 0x00, 0x00, 0x91, 0x22, 0x3a, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0xe7, 0x04, 0x34, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xac, 0x28, 0xef, 0xff, 0xff, 0xff, 0xff, + 0x2e, 0xba, 0x30, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x07, 0xdc, 0xe6, 0xff, 0xff, 0xff, 0xff, + 0x6d, 0x3e, 0xd5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x0f, 0xd5, 0x21, 0x00, 0x00, 0x00, 0x00, + 0xbf, 0x57, 0x9f, 0x23, 0x00, 0x00, 0x00, 0x00, 0xae, 0x0a, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x58, 0xe7, 0x7c, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x39, 0x50, 0xd5, 0xff, 0xff, 0xff, 0xff, + 0xb2, 0x32, 0x4d, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x38, 0xc6, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xcc, 0x83, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x69, 0xb0, 0x69, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x91, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x66, 0x3b, 0xd8, 0xff, 0xff, 0xff, 0xff, + 0x7d, 0xf0, 0x2a, 0xce, 0xff, 0xff, 0xff, 0xff, 0xb2, 0x0b, 0x2f, 0xec, 0xff, 0xff, 0xff, 0xff, + 0x2d, 0xad, 0xea, 0x1b, 0x00, 0x00, 0x00, 0x00, 0xee, 0xb9, 0x70, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x74, 0xdc, 0x58, 0x27, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xc2, 0x7c, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x0b, 0x05, 0xd6, 0xca, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x46, 0x04, 0xc8, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x32, 0x57, 0xf2, 0xff, 0xff, 0xff, 0xff, 0x29, 0xa3, 0xd4, 0x29, 0x00, 0x00, 0x00, 0x00, + 0x62, 0x4d, 0x57, 0x42, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x2a, 0x9a, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x9a, 0x8d, 0x6a, 0xea, 0xff, 0xff, 0xff, 0xff, 0x1c, 0xe2, 0x9c, 0xbc, 0xff, 0xff, 0xff, 0xff, + 0xb5, 0x9c, 0xa8, 0xc2, 0xff, 0xff, 0xff, 0xff, 0x04, 0x55, 0x2d, 0xfa, 0xff, 0xff, 0xff, 0xff, + 0xd5, 0x68, 0x10, 0x39, 0x00, 0x00, 0x00, 0x00, 0x17, 0xa8, 0x64, 0x4d, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0xca, 0xef, 0x24, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xab, 0x16, 0xdd, 0xff, 0xff, 0xff, 0xff, + 0xec, 0x0e, 0x8c, 0xad, 0xff, 0xff, 0xff, 0xff, 0x63, 0x20, 0x34, 0xbd, 0xff, 0xff, 0xff, 0xff, + 0x62, 0xc0, 0x93, 0x02, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x38, 0x40, 0x49, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0x28, 0x75, 0x59, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x57, 0xe8, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x82, 0xda, 0x84, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x2f, 0xeb, 0x20, 0x9d, 0xff, 0xff, 0xff, 0xff, + 0xb9, 0x6b, 0xc7, 0xb5, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x48, 0xa8, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x37, 0x15, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x74, 0x23, 0x55, 0x68, 0x00, 0x00, 0x00, 0x00, + 0x8b, 0xd6, 0x4a, 0x26, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe6, 0x59, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0x3d, 0x3f, 0x56, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xa4, 0xcf, 0x12, 0xa9, 0xff, 0xff, 0xff, 0xff, + 0x3a, 0xc5, 0x14, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xae, 0x04, 0xd9, 0x6a, 0x00, 0x00, 0x00, 0x00, + 0x27, 0xe7, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x83, 0x35, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xbf, 0xfb, 0xbb, 0xff, 0xff, 0xff, 0xff, 0x63, 0xba, 0x2d, 0x74, 0xff, 0xff, 0xff, 0xff, + 0x97, 0xe2, 0xab, 0x91, 0xff, 0xff, 0xff, 0xff, 0x57, 0xa5, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x0b, 0xae, 0x78, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x97, 0xf1, 0x9a, 0x00, 0x00, 0x00, 0x00, + 0xc8, 0x79, 0xb8, 0x4c, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x9a, 0xb7, 0xc1, 0xff, 0xff, 0xff, 0xff, + 0xe3, 0xf0, 0x39, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xcb, 0x28, 0xc4, 0x67, 0xff, 0xff, 0xff, 0xff, + 0x79, 0xe2, 0xe5, 0xe1, 0xff, 0xff, 0xff, 0xff, 0x8c, 0x7a, 0x04, 0x79, 0x00, 0x00, 0x00, 0x00, + 0x84, 0xdc, 0x42, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x87, 0xa2, 0x1c, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x4e, 0xaa, 0xe9, 0xff, 0xff, 0xff, 0xff, 0x45, 0x8e, 0x53, 0x50, 0xff, 0xff, 0xff, 0xff, + 0xad, 0x81, 0xc2, 0x25, 0xff, 0xff, 0xff, 0xff, 0x16, 0x3c, 0x3e, 0x8d, 0xff, 0xff, 0xff, 0xff, + 0x5f, 0xde, 0x95, 0x49, 0x00, 0x00, 0x00, 0x00, 0x91, 0xc6, 0x7f, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0xe8, 0x96, 0x73, 0xf1, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x44, 0x66, 0x64, 0x00, 0x00, 0x00, 0x00, + 0xb6, 0xf3, 0xb5, 0x8b, 0xff, 0xff, 0xff, 0xff, 0x2e, 0xbd, 0x92, 0xea, 0xfe, 0xff, 0xff, 0xff, + 0x06, 0x5a, 0xb8, 0xe7, 0xfe, 0xff, 0xff, 0xff, 0x2d, 0xca, 0x07, 0x8f, 0xff, 0xff, 0xff, 0xff, + 0xca, 0x3a, 0xeb, 0x88, 0x00, 0x00, 0x00, 0x00, 0xab, 0xac, 0x3a, 0x4b, 0x01, 0x00, 0x00, 0x00, + 0x4f, 0x55, 0xde, 0x65, 0x01, 0x00, 0x00, 0x00, 0xa5, 0x44, 0x63, 0xbf, 0x00, 0x00, 0x00, 0x00, + 0xc6, 0x47, 0x94, 0xa1, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x5c, 0xad, 0x92, 0xfe, 0xff, 0xff, 0xff, + 0x62, 0x2e, 0x32, 0x13, 0xfe, 0xff, 0xff, 0xff, 0xe9, 0xae, 0xe5, 0x63, 0xfe, 0xff, 0xff, 0xff, + 0xdd, 0x67, 0xd8, 0x6e, 0xff, 0xff, 0xff, 0xff, 0xbb, 0xab, 0x7c, 0xd9, 0x00, 0x00, 0x00, 0x00, + 0x69, 0x27, 0x26, 0x31, 0x02, 0x00, 0x00, 0x00, 0x43, 0x5c, 0xb1, 0x19, 0x03, 0x00, 0x00, 0x00, + 0x49, 0xaf, 0xf9, 0x69, 0x03, 0x00, 0x00, 0x00, 0x2d, 0x04, 0x67, 0x2e, 0x03, 0x00, 0x00, 0x00, + 0xee, 0x25, 0x09, 0x97, 0x02, 0x00, 0x00, 0x00, 0xea, 0x83, 0xfb, 0xdd, 0x01, 0x00, 0x00, 0x00, + 0xda, 0x7a, 0x51, 0x32, 0x01, 0x00, 0x00, 0x00, 0x1f, 0xcb, 0x0c, 0xae, 0x00, 0x00, 0x00, 0x00, + 0xba, 0xe8, 0xe9, 0x56, 0x00, 0x00, 0x00, 0x00, 0xb6, 0xe4, 0x85, 0x25, 0x00, 0x00, 0x00, 0x00, + 0xbd, 0xc0, 0x9e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x2a, 0xf5, 0x03, 0x00, 0x00, 0x00, 0x00, + 0xb1, 0xdb, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x5f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, +]; +const FILTER_LENGTHS: U32 = U32(0x542c47); +const FILTER_LENGTHS_HF: u32 = 0xd94960; const AUDIO_DEV_PDM0: u32 = from_fourcc(b"pdm0"); const AUDIO_DEV_LPAI: u32 = from_fourcc(b"lpai"); const AUDIO_DEV_HPAI: u32 = from_fourcc(b"hpai"); @@ -134,9 +329,9 @@ impl AudioAttachDevice { #[repr(C, packed(4))] #[derive(Clone, Copy, Default)] struct LpaiChannelConfig { - unk1: u32, - unk2: u32, - unk3: u32, + channels_enabled: u32, + channels_supported: u32, + voice_trigger_channel: u32, unk4: u32, } @@ -150,21 +345,15 @@ struct PDMConfig { slow_clock_speed: u32, fast_clock_speed: u32, channel_polarity_select: u32, - channel_phase_select: u32, - unk1: u32, - unk2: u16, - ratio1: u8, - ratio2: u8, - ratio3: u8, - _pad0: u8, - filter_lengths: U32, - coeff_bulk: U32, - coeffs: [u8; PDM_NUM_COEFFS * mem::size_of::()], - unk3: U32, + unk1: u8, + channel_phase_select: U32, + unk2: u8, + decim: DecimatorConfig, + mic_turn_on_time_valid: U32, mic_turn_on_time_ms: U32, _zero0: [u8; 8], _zero1: [u8; 8], - unk4: U32, + mic_settle_time_valid: U32, mic_settle_time_ms: U32, _zero2: [u8; 69], // ????? _pad_extra: u8, // extra padding to increase the struct size to multiple of mem::size_of::() @@ -172,13 +361,32 @@ struct PDMConfig { // PDMConfig is intended to use `#[repr(C, packed)]` but this // conflicts ith pin_init. Instead just ensure that it has the same size as if // it where packed. -static_assert!(mem::size_of::() == 36 + 14 + (120 * 4) + 32 + 69 + 1); +static_assert!(mem::size_of::() == 34 + mem::size_of::() + 32 + 69 + 1); unsafe impl Zeroable for PDMConfig {} #[repr(C, packed(4))] #[derive(Debug, Copy, Clone)] struct DecimatorConfig { + latency: U32, + ratio1: u8, + ratio2: u8, + ratio3: u8, + _pad0: u8, + filter_lengths: U32, + coeff_bulk: U32, + coeffs: [u8; DECIM_NUM_COEFFS * mem::size_of::()], +} +// DecimatorConfig is intended to use `#[repr(C, packed)]` but this +// conflicts ith pin_init. Instead just ensure that it has the same size as if +// it where packed. +static_assert!(mem::size_of::() == 16 + (DECIM_NUM_COEFFS * 4)); + +unsafe impl Zeroable for DecimatorConfig {} + +#[repr(C, packed(4))] +#[derive(Debug, Copy, Clone)] +struct DecimatorConfigHf { latency: u32, ratio1: u8, ratio2: u8, @@ -186,14 +394,14 @@ struct DecimatorConfig { _pad0: u8, filter_lengths: u32, coeff_bulk: u32, - coeffs: [u8; PDM_NUM_COEFFS * mem::size_of::()], + coeffs: [u8; DECIM_NUM_COEFFS_HF * mem::size_of::()], } -// DecimatorConfig is intended to use `#[repr(C, packed)]` but this +// DecimatorConfigHf is intended to use `#[repr(C, packed)]` but this // conflicts ith pin_init. Instead just ensure that it has the same size as if // it where packed. -static_assert!(mem::size_of::() == 16 + (120 * 4)); +static_assert!(mem::size_of::() == 16 + (DECIM_NUM_COEFFS_HF * 8)); -unsafe impl Zeroable for DecimatorConfig {} +unsafe impl Zeroable for DecimatorConfigHf {} #[repr(C, packed(4))] #[derive(Clone, Copy, Default, Debug)] @@ -291,12 +499,18 @@ impl AudioSetDeviceProp { } } +struct SndSocAopHwConfig { + bytes_per_sample: u32, + hf_decimator: bool, +} + struct SndSocAopData { dev: ARef, adata: Arc, service: EPICService, pstate_cookie: Atomic, fwnode: ARef, + hwdata: &'static SndSocAopHwConfig, } impl SndSocAopData { @@ -305,6 +519,7 @@ impl SndSocAopData { adata: Arc, service: EPICService, fwnode: ARef, + hwdata: &'static SndSocAopHwConfig, ) -> Result> { Ok(Arc::new( SndSocAopData { @@ -312,34 +527,43 @@ impl SndSocAopData { adata, service, fwnode, + hwdata, pstate_cookie: Atomic::new(1), }, GFP_KERNEL, )?) } + fn build_decimator_config(&self, decim: &mut DecimatorConfig) { + decim.latency = DECIM_LATENCY; + decim.ratio1 = DECIMATION_RATIOS[0]; + decim.ratio2 = DECIMATION_RATIOS[1]; + decim.ratio3 = DECIMATION_RATIOS[2]; + decim.filter_lengths = FILTER_LENGTHS; + decim.coeff_bulk = U32(DECIM_NUM_COEFFS as u32); + decim.coeffs[..COEFFICIENTS.len()].copy_from_slice(&COEFFICIENTS); + } fn set_pdm_config(&self) -> Result<()> { let pdm_cfg = init!(PDMConfig { - bytes_per_sample: 2, - clock_source: 0x706c6c20, // 'pll ' + bytes_per_sample: self.hwdata.bytes_per_sample, + clock_source: from_fourcc(b"pll "), pdm_frequency: 2400000, pdmc_frequency: 24000000, slow_clock_speed: 24000000, fast_clock_speed: 24000000, channel_polarity_select: 256, - channel_phase_select: 0, - unk1: 0xf7600, + channel_phase_select: U32(0), + unk1: 0, unk2: 0, - ratio1: DECIMATION_RATIOS[0], - ratio2: DECIMATION_RATIOS[1], - ratio3: DECIMATION_RATIOS[2], - filter_lengths: U32(FILTER_LENGTHS), - coeff_bulk: U32(PDM_NUM_COEFFS as u32), - coeffs: COEFFICIENTS, - unk3: U32(1), + mic_turn_on_time_valid: U32(1), mic_turn_on_time_ms: U32(20), - unk4: U32(1), + mic_settle_time_valid: U32(1), mic_settle_time_ms: U32(50), ..Zeroable::init_zeroed() + }).chain(|raw| { + if !self.hwdata.hf_decimator { + self.build_decimator_config(&mut raw.decim); + } + Ok(()) }); let set_prop = AudioSetDeviceProp::::try_init(AUDIO_DEV_PDM0, 200, pdm_cfg); let msg = KBox::try_init(set_prop, GFP_KERNEL)?; @@ -352,15 +576,9 @@ impl SndSocAopData { } } fn set_decimator_config(&self) -> Result<()> { - let pdm_cfg = init!(DecimatorConfig { - latency: 15, - ratio1: DECIMATION_RATIOS[0], - ratio2: DECIMATION_RATIOS[1], - ratio3: DECIMATION_RATIOS[2], - filter_lengths: FILTER_LENGTHS, - coeff_bulk: PDM_NUM_COEFFS as u32, - coeffs: COEFFICIENTS, - ..Zeroable::init_zeroed() + let pdm_cfg = DecimatorConfig::init_zeroed().chain(|raw| { + self.build_decimator_config(raw); + Ok(()) }); let set_prop = AudioSetDeviceProp::::try_init(AUDIO_DEV_PDM0, 210, pdm_cfg); @@ -377,11 +595,39 @@ impl SndSocAopData { Ok(()) } } + fn set_decimator_config_hf(&self) -> Result<()> { + let pdm_cfg = init!(DecimatorConfigHf { + latency: DECIM_LATENCY_HF, + ratio1: DECIMATION_RATIOS_HF[0], + ratio2: DECIMATION_RATIOS_HF[1], + ratio3: DECIMATION_RATIOS_HF[2], + filter_lengths: FILTER_LENGTHS_HF, + coeff_bulk: DECIM_NUM_COEFFS_HF as u32, + ..Zeroable::init_zeroed() + }).chain(|raw| { + raw.coeffs[..COEFFICIENTS_HF.len()].copy_from_slice(&COEFFICIENTS_HF); + Ok(()) + }); + let set_prop = + AudioSetDeviceProp::::try_init(AUDIO_DEV_PDM0, 212, pdm_cfg); + let msg = KBox::try_init(set_prop, GFP_KERNEL)?; + let ret = self.epic_wrapped_call(msg.as_ref())?; + if ret != 0 { + dev_err!( + self.dev, + "Unable to set high frequency decimator config, return code {}", + ret + ); + return Err(EIO); + } else { + Ok(()) + } + } fn set_lpai_channel_cfg(&self) -> Result<()> { let cfg = LpaiChannelConfig { - unk1: 7, - unk2: 7, - unk3: 1, + channels_enabled: 7, + channels_supported: 7, + voice_trigger_channel: 1, unk4: 7, }; let msg = AudioSetDeviceProp::new(AUDIO_DEV_LPAI, 301, cfg); @@ -693,19 +939,36 @@ impl Drop for SndSocAopDriver { unsafe impl Send for SndSocAopDriver {} unsafe impl Sync for SndSocAopDriver {} +const HW_CFG_T8013: SndSocAopHwConfig = SndSocAopHwConfig { + bytes_per_sample: 2, + hf_decimator: false, +}; + +const HW_CFG_T6030: SndSocAopHwConfig = SndSocAopHwConfig { + bytes_per_sample: 3, + hf_decimator: true, +}; + kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - (), - [(of::DeviceId::new(c_str!("apple,aop-audio")), ())] + ::IdInfo, + [ + (of::DeviceId::new(c_str!("apple,aop-audio")), &HW_CFG_T8013), + (of::DeviceId::new(c_str!("apple,t6030-aop-audio")), &HW_CFG_T6030), + ] ); impl platform::Driver for SndSocAopDriver { - type IdInfo = (); + type IdInfo = &'static SndSocAopHwConfig; - const OF_ID_TABLE: Option> = Some(&OF_TABLE); + const OF_ID_TABLE: Option> = Some(&OF_TABLE); - fn probe(pdev: &platform::Device, _info: Option<&()>) -> impl PinInit { + fn probe( + pdev: &platform::Device, + info: Option<&Self::IdInfo> + ) -> impl PinInit { + let info = info.ok_or(ENODEV)?; let dev = ARef::::from(pdev.as_ref()); let parent = pdev.as_ref().parent().unwrap(); // SAFETY: our parent is AOP, and AopDriver is repr(transparent) for Arc @@ -721,13 +984,20 @@ impl platform::Driver for SndSocAopDriver { if !audio && parent_fwnode.property_present(c_str!("apple,no-beamforming")) { return Err(ENODEV); } - let data = SndSocAopData::new(dev, adata, svc, fwnode)?; + let data = SndSocAopData::new(dev, adata, svc, fwnode, info)?; for dev in [AUDIO_DEV_PDM0, AUDIO_DEV_HPAI, AUDIO_DEV_LPAI] { data.audio_attach_device(dev)?; } + if info.hf_decimator { + data.audio_attach_device(from_fourcc(b"lilb"))?; + } data.set_lpai_channel_cfg()?; data.set_pdm_config()?; - data.set_decimator_config()?; + if info.hf_decimator { + data.set_decimator_config_hf()?; + } else { + data.set_decimator_config()?; + } Ok(Self::new(data)?) } } From 7ef0f7cc25647ba3a40cdad7ca5fac3758b6b329 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 1 Aug 2026 10:51:35 +0200 Subject: [PATCH 20/23] fixup! dt-bindings: dma: apple,admac: Add M3 generation ADMACs Signed-off-by: Janne Grunau --- Documentation/devicetree/bindings/dma/apple,admac.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml index 560fd19a4c6f1f..5b4fd8348f99fc 100644 --- a/Documentation/devicetree/bindings/dma/apple,admac.yaml +++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml @@ -24,7 +24,6 @@ properties: compatible: oneOf: - items: - - const: apple,t8122-admac - const: apple,t6020-admac - const: apple,t8103-admac - items: @@ -39,6 +38,7 @@ properties: - apple,t6030-admac - apple,t6031-admac - const: apple,t8122-admac + - const: apple,t8122-admac reg: maxItems: 1 From a79dc5bca4ad8c6ef3bd22a0653cd15291cfccd2 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Tue, 14 Jul 2026 10:52:30 +0200 Subject: [PATCH 21/23] media: apple: isp: add t6030 support Signed-off-by: Sasha Finkelstein --- drivers/media/platform/apple/isp/isp-drv.c | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index c8169a4f99125e..a2e6b71ebc14ba 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -541,6 +541,29 @@ static const struct apple_isp_hw apple_isp_hw_t6020 = { .meta_size = ISP_META_SIZE_T8112, }; +static const struct apple_isp_hw apple_isp_hw_t6030 = { + .gen = ISP_GEN_T6031, + .pmu_base = 0x350704000, + + .dsid_count = 1, + .dsid_clr_base0 = 0x200f14000, + .dsid_clr_range0 = 0x1000, + + .clock_scratch = 0x3503d0920, + .clock_base = 0x0, + .clock_bit = 0x0, + .clock_size = 0x8, + .bandwidth_scratch = 0x3503d0980, + .bandwidth_base = 0x0, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x8, + .mbox_irq_enable = ISP_MBOX_IRQ_ENABLE_T6031, + + .scl1 = true, + .lpdp = false, + .meta_size = ISP_META_SIZE_T6031, +}; + static const struct apple_isp_hw apple_isp_hw_t6031 = { .gen = ISP_GEN_T6031, .pmu_base = 0x292284008, @@ -562,6 +585,7 @@ static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8112-isp", .data = &apple_isp_hw_t8112 }, { .compatible = "apple,t6000-isp", .data = &apple_isp_hw_t6000 }, { .compatible = "apple,t6020-isp", .data = &apple_isp_hw_t6020 }, + { .compatible = "apple,t6030-isp", .data = &apple_isp_hw_t6030 }, { .compatible = "apple,t6031-isp", .data = &apple_isp_hw_t6031 }, {}, }; From ac8d3c4ebe3a2d14d03afddd7dedf939296dfbc7 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Fri, 17 Jul 2026 12:40:39 +0200 Subject: [PATCH 22/23] dts: apple: t6030: Add isp nodes Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t6030-j514s.dts | 4 ++ arch/arm64/boot/dts/apple/t6030-j516s.dts | 4 ++ arch/arm64/boot/dts/apple/t6030.dtsi | 50 ++++++++++++++++++- .../arm64/boot/dts/apple/t603x-j514-j516.dtsi | 2 - 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6030-j514s.dts b/arch/arm64/boot/dts/apple/t6030-j514s.dts index 106df3e83bb908..5891cfe035f83c 100644 --- a/arch/arm64/boot/dts/apple/t6030-j514s.dts +++ b/arch/arm64/boot/dts/apple/t6030-j514s.dts @@ -75,3 +75,7 @@ compatible = "apple,j514-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J514"; }; + +&isp { + apple,platform-id = <16>; +}; diff --git a/arch/arm64/boot/dts/apple/t6030-j516s.dts b/arch/arm64/boot/dts/apple/t6030-j516s.dts index 838c2003419baa..6b59a0f97b166c 100644 --- a/arch/arm64/boot/dts/apple/t6030-j516s.dts +++ b/arch/arm64/boot/dts/apple/t6030-j516s.dts @@ -75,3 +75,7 @@ compatible = "apple,j516-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J516"; }; + +&isp { + apple,platform-id = <16>; +}; diff --git a/arch/arm64/boot/dts/apple/t6030.dtsi b/arch/arm64/boot/dts/apple/t6030.dtsi index 20a93f25b885fc..6021c4642f150e 100644 --- a/arch/arm64/boot/dts/apple/t6030.dtsi +++ b/arch/arm64/boot/dts/apple/t6030.dtsi @@ -13,8 +13,6 @@ #include #include -#define NO_ISP_YET 1 - / { #address-cells = <2>; #size-cells = <2>; @@ -644,6 +642,54 @@ status = "disabled"; }; + isp: isp@2c8000000 { + compatible = "apple,t6030-isp"; + iommus = <&isp_dart0 0>, <&isp_dart1 0>, <&isp_dart2 0>; + reg-names = "coproc", "mbox", "gpio", "mbox2"; + reg = <0x2 0xc8000000 0x0 0x2000000>, + <0x2 0xca4c4000 0x0 0x100>, + <0x2 0xca4c41d0 0x0 0x100>, + <0x2 0xca4c4458 0x0 0x100>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>, <&ps_ispsens0>, + <&ps_isp_cpu>, <&ps_isp_fe>, <&ps_dprx>, + <&ps_isp_secure>, <&ps_isp_be>, <&ps_isp_clr>; + apple,dart-vm-size = <0x0 0xa0000000>; + + status = "disabled"; + }; + + isp_dart0: iommu@2ca4a8000 { + compatible = "apple,t6030-dart", "apple,t8110-dart"; + reg = <0x2 0xca4a8000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + isp_dart1: iommu@2ca4b4000 { + compatible = "apple,t6030-dart", "apple,t8110-dart"; + reg = <0x2 0xca4b4000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + isp_dart2: iommu@2ca4bc000 { + compatible = "apple,t6030-dart", "apple,t8110-dart"; + reg = <0x2 0xca4bc000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + avd: avd@30a000000 { compatible = "apple,t6030-avd", "apple,t8122-avd"; interrupt-parent = <&aic>; diff --git a/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi b/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi index 0adfe50b78e788..b2a9bd5f921cd4 100644 --- a/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi +++ b/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi @@ -304,13 +304,11 @@ }; }; -#ifndef NO_ISP_YET &isp { apple,platform-id = <9>; }; #include "isp-imx558-cfg0.dtsi" -#endif #include "spi1-nvram.dtsi" #include "hwmon-common.dtsi" From 922f0e157063a5aa20da5410fced6a68edf1e12a Mon Sep 17 00:00:00 2001 From: James A DellaMorte Date: Sat, 1 Aug 2026 10:05:13 -0400 Subject: [PATCH 23/23] power: supply: macsmc: add "auto-discharge" charge behaviour for CHLS When lowering the charge-control end threshold on machines that use the CHLS key, the driver unconditionally sets CHLS_FORCE_DISCHARGE, actively draining the battery down to the limit even on AC power. Most laptop charge-limit implementations instead just cap charging at the threshold and let the battery drain naturally through use. Add a new "auto-discharge" charge_behaviour value that opts into the active discharge, and make end-threshold writes preserve the current CHLS_FORCE_DISCHARGE bit instead of forcing it on. "auto" keeps its documented meaning of only respecting the thresholds. The selection lives in the CHLS key itself, so no state is kept in the driver, it persists across reboots, and systems upgrading from the old behaviour keep force-discharge enabled until they explicitly write "auto". Resolves the existing TODO. Co-Authored-By: Claude Fable 5 Signed-off-by: James A DellaMorte --- Documentation/ABI/testing/sysfs-class-power | 2 + drivers/power/supply/macsmc-power.c | 48 ++++++++++++++++++--- drivers/power/supply/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index 32697b926cc8c2..6b439c628b6ee1 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -513,6 +513,8 @@ Description: inhibit-charge: Do not charge while AC is attached inhibit-charge-awake: inhibit-charge only when device is awake force-discharge: Force discharge while AC is attached + auto-discharge: auto, but actively discharge down to + the charge control end threshold ===================== ======================================== What: /sys/class/power_supply//technology diff --git a/drivers/power/supply/macsmc-power.c b/drivers/power/supply/macsmc-power.c index cfc57eb9a471b0..0cbd747794710c 100644 --- a/drivers/power/supply/macsmc-power.c +++ b/drivers/power/supply/macsmc-power.c @@ -295,6 +295,7 @@ static int macsmc_battery_get_charge_behaviour(struct macsmc_power *power) int ret; u8 val8; u8 chte_buf[4]; + u16 vu16; if (power->has_ch0i) { ret = apple_smc_read_u8(power->smc, SMC_KEY(CH0I), &val8); @@ -319,6 +320,14 @@ static int macsmc_battery_get_charge_behaviour(struct macsmc_power *power) return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; } + if (power->has_chls) { + ret = apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16); + if (ret) + return ret; + if (vu16 & CHLS_FORCE_DISCHARGE) + return POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO_DISCHARGE; + } + return POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; } @@ -327,6 +336,10 @@ static int macsmc_battery_set_charge_behaviour(struct macsmc_power *power, int v int ret; switch (val) { + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO_DISCHARGE: + if (!power->has_chls) + return -EOPNOTSUPP; + fallthrough; case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: /* Reset all inhibitors to a known-good 'auto' state */ if (power->has_ch0i) { @@ -344,6 +357,20 @@ static int macsmc_battery_set_charge_behaviour(struct macsmc_power *power, int v if (ret) return ret; } + + /* Set or clear force-discharge to the CHLS charge limit */ + if (power->has_chls) { + u16 vu16; + + ret = apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16); + if (ret) + return ret; + if (val == POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO_DISCHARGE) + vu16 |= CHLS_FORCE_DISCHARGE; + else + vu16 &= ~CHLS_FORCE_DISCHARGE; + return apple_smc_write_u16(power->smc, SMC_KEY(CHLS), vu16); + } return 0; case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: @@ -606,12 +633,18 @@ static int macsmc_battery_set_property(struct power_supply *psy, return 0; case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: if (power->has_chls) { - u16 kval = 0; - /* TODO: Make CHLS_FORCE_DISCHARGE configurable */ + u16 kval; + int ret; + + /* Preserve the force-discharge (auto-discharge) charge_behaviour */ + ret = apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &kval); + if (ret) + return ret; + kval &= CHLS_FORCE_DISCHARGE; if (val->intval < CHLS_MIN_END_THRESHOLD) - kval = CHLS_FORCE_DISCHARGE | CHLS_MIN_END_THRESHOLD; + kval |= CHLS_MIN_END_THRESHOLD; else if (val->intval < 100) - kval = CHLS_FORCE_DISCHARGE | (val->intval & 0xff); + kval |= 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), @@ -945,10 +978,13 @@ static int macsmc_power_probe(struct platform_device *pdev) } /* Detect charge limit method (CHWA vs CHLS) */ - if (apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag) == 0) + if (apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag) == 0) { power->has_chwa = true; - else if (apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16) >= 0) + } else if (apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16) >= 0) { power->has_chls = true; + power->batt_desc.charge_behaviours |= + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO_DISCHARGE); + } if (power->has_chwa || power->has_chls) { props[nprops++] = POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD; diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index f30a7b9ccd5e93..d22541f4a4ecf6 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -146,6 +146,7 @@ static const char * const POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[] = { [POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE] = "inhibit-charge", [POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE] = "inhibit-charge-awake", [POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE] = "force-discharge", + [POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO_DISCHARGE] = "auto-discharge", }; static struct power_supply_attr power_supply_attrs[] __ro_after_init = { diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 7a5e4c3242a01d..82215a75385010 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -221,6 +221,7 @@ enum power_supply_charge_behaviour { POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE, POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE, POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE, + POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO_DISCHARGE, }; enum power_supply_notifier_events {