From bbdcf9095c1f0c1791c8fffb02fbbe939885101a Mon Sep 17 00:00:00 2001 From: coolsnowwolf Date: Sun, 7 Aug 2022 03:58:27 +0000 Subject: [PATCH] target: add Apple Silicon SoC platform (M1/M2) family init support --- target/linux/silicon/Makefile | 29 + target/linux/silicon/armv8/config-5.19 | 510 +++ ...Add-CPU-topology-cpufreq-nodes-for-t.patch | 313 ++ ...arm64-dts-apple-t8103-Add-ANS2-nodes.patch | 56 + ...arm64-dts-apple-t8103-Add-dwc3-nodes.patch | 274 ++ ...-apple-t8103-Add-spi3-keyboard-nodes.patch | 133 + ...arm64-dts-apple-Fix-j45x-model-years.patch | 40 + ...Add-WiFi-module-and-antenna-properti.patch | 112 + ...dts-apple-Add-PCI-power-enable-GPIOs.patch | 31 + ...Add-SMC-node-to-t8103-t6001-devicetr.patch | 51 + ...Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch | 127 + ...s-apple-Re-parent-ANS2-power-domains.patch | 56 + ...Mark-ATC-USB-AON-domains-as-always-o.patch | 39 + ...pple-Add-backlight-node-to-j293-j313.patch | 64 + ...4-dts-apple-t8103-Put-in-audio-nodes.patch | 438 +++ ...ple-t8103-j313-Also-disable-speakers.patch | 33 + ...-dts-apple-Keep-PCIe-power-domain-on.patch | 28 + ...le-Add-initial-t6000-t6001-t6002-DTs.patch | 3024 +++++++++++++++++ ...-apple-Add-J314-and-J316-devicetrees.patch | 250 ++ ...Add-devicetree-for-Apple-Mac-Studio-.patch | 149 + ...Add-devicetree-for-Apple-Mac-Studio-.patch | 178 + ...ts-apple-Add-CPUfreq-nodes-for-t6001.patch | 486 +++ ...le-Add-SMC-node-to-t600x-devicetrees.patch | 50 + ...Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch | 145 + ...-arm64-dts-apple-t6000-Add-spi1-node.patch | 74 + ...e-t600x-j314-j316-Add-NOR-flash-node.patch | 37 + ...-arm64-dts-apple-t600x-Add-spi3-node.patch | 60 + ...-dts-apple-j31-46-Add-keyboard-nodes.patch | 47 + ...arm64-dts-apple-t600x-Add-dwc3-nodes.patch | 631 ++++ ...Add-WiFi-module-and-antenna-properti.patch | 141 + ...dts-apple-Add-PCI-power-enable-GPIOs.patch | 97 + ...pple-Add-backlight-node-to-j314-j316.patch | 37 + ...64-dts-apple-t600-Put-in-audio-nodes.patch | 96 + ...64-dts-apple-t600-Put-in-audio-nodes.patch | 231 ++ ...t600-Add-t8103-compat-to-cpufreq-nod.patch | 32 + ...t8103-Fix-spi4-power-domain-sort-ord.patch | 50 + ...ple-t8103-Add-bluetooth-device-trees.patch | 117 + ...ple-t600x-Add-bluetooth-device-trees.patch | 167 + ...-t8112-Initial-t8112-M2-device-trees.patch | 2800 +++++++++++++++ ...ts-apple-t8112-j413-Fix-IRQ-for-hpm5.patch | 26 + ...Add-Apple-dwc3-bindings-to-ARM-APPLE.patch | 30 + ...S-Add-apple-spi-driver-binding-files.patch | 38 + ...lbox-apple-Implement-flush-operation.patch | 74 + ...-apple-Implement-poll_data-operation.patch | 106 + ...ox-apple-Keep-IRQs-active-in-suspend.patch | 45 + ...ilbox-apple-Fix-races-around-poll-tx.patch | 101 + .../0045-WIP-mailbox-fix-poll.patch | 26 + ...ings-iommu-dart-add-t6000-compatible.patch | 37 + ...-Move-Apple-DART-support-to-its-own-.patch | 825 +++++ ...-Add-DART-subpage-protection-support.patch | 54 + ...-dart-Add-DART-PTE-support-for-t6000.patch | 158 + ...050-iommu-dart-Support-t6000-variant.patch | 99 + ...ommu-dart-Add-suspend-resume-support.patch | 91 + ...052-iommu-dart-Support-64-stream-IDs.patch | 359 ++ ...rt-a-variable-number-of-TTBRs-per-st.patch | 119 + ...-Fix-DART_PARAMS1-2-bit-define-names.patch | 43 + ...rt-different-variants-with-different.patch | 394 +++ .../0056-iommu-dart-Add-t8110-support.patch | 316 ++ ...erial-samsung_tty-Support-runtime-PM.patch | 197 ++ ...-drm-simpledrm-Add-backlight-support.patch | 83 + ...mote-Bad-cell-count-to-debug-message.patch | 29 + ...pport-external-CD-GPIO-on-all-OF-sys.patch | 37 + ...ci-Support-setting-CD-debounce-delay.patch | 65 + ...178a-Bind-only-to-vendor-specific-in.patch | 106 + ...bindings-usb-Add-Apple-dwc3-bindings.patch | 89 + ...le-switch-reset-quirk-for-Apple-DWC3.patch | 172 + ...-cache-flushes-by-a-specified-amount.patch | 141 + ...lease-power-domains-when-probe-fails.patch | 25 + ...S-Add-apple-spi-driver-binding-files.patch | 39 + ...apple-spi-Add-binding-for-Apple-SPI-.patch | 88 + ...-Add-driver-for-Apple-SPI-controller.patch | 618 ++++ ...bindings-dma-Add-apple-admac-binding.patch | 93 + ...e-apple-admac-Add-Apple-ADMAC-driver.patch | 806 +++++ ...a-Add-platform-driver-for-Apple-SoCs.patch | 1364 ++++++++ ...C-tas2770-Set-correct-FSYNC-polarity.patch | 99 + ...ASoC-tas2770-Set-no-of-channels-to-1.patch | 27 + ...5-HACK-ASoC-cs42l42-Disable-regcache.patch | 26 + ...-ASoC-cs42l42-Bypass-device-ID-check.patch | 33 + ...K-ASoC-Add-card-filter_controls-hook.patch | 205 ++ ...Add-asoc_pcm_to_rtd-utility-function.patch | 29 + ...SoC-Allow-an-N-cpus-to-M-codecs-link.patch | 34 + ...080-ASoC-Add-macaudio-machine-driver.patch | 632 ++++ ...oC-tas2764-Extend-driver-to-SN012776.patch | 161 + ...-workaround-for-spurious-shutdowns-o.patch | 147 + ...ate-missing-simple-card-utils-depend.patch | 31 + .../0084-macaudio-Unbork-jack-volume.patch | 25 + ...bcm4329-fmac-Add-Apple-properties-ch.patch | 88 + ...ware-Handle-per-board-clm_blob-files.patch | 76 + ...io-usb-Get-CLM-blob-via-standard-fir.patch | 376 ++ ...e-Support-passing-in-multiple-board_.patch | 181 + ...fmac-pcie-Read-Apple-OTP-information.patch | 299 ++ ...0-brcmfmac-of-Fetch-Apple-properties.patch | 68 + ...rform-firmware-selection-for-Apple-p.patch | 134 + ...e-Allow-platform-to-override-macaddr.patch | 125 + ...sgbuf-Increase-RX-ring-sizes-to-1024.patch | 36 + ...-pcie-Support-PCIe-core-revisions-64.patch | 265 ++ ...-pcie-Add-IDs-properties-for-BCM4378.patch | 97 + ...-Support-strings-in-Apple-_DSM-props.patch | 55 + ...d-support-for-fetching-Apple-ACPI-pr.patch | 127 + ...ovide-a-buffer-of-random-bytes-to-th.patch | 82 + ...-pcie-Add-IDs-properties-for-BCM4355.patch | 93 + ...-pcie-Add-IDs-properties-for-BCM4377.patch | 90 + ...rform-correct-BCM4364-firmware-selec.patch | 78 + ...ly-disable-D11-cores-handle-an-arbit.patch | 53 + ...andle-1024-unit-sizes-for-TCM-blocks.patch | 74 + ...80211-Add-support-for-scan-params-v2.patch | 336 ++ ...-Add-support-for-setting-feats-based.patch | 138 + ...1-Add-support-for-PMKID_V3-operation.patch | 228 ++ ...1-Pass-the-PMK-in-binary-instead-of-.patch | 50 + ...fg80211-Use-WSEC-to-set-SAE-password.patch | 106 + ...-pcie-Add-IDs-properties-for-BCM4387.patch | 96 + ...Add-support-for-downloading-TxCap-bl.patch | 190 ++ ...ac-pcie-Load-and-provide-TxCap-blobs.patch | 92 + ...Add-support-for-external-calibration.patch | 99 + ...-brcmfmac-pcie-Add-BCM4378B3-support.patch | 38 + ...add-CS-delay-peripheral-specific-pro.patch | 40 + ...15-spi-parse-CS-delay-values-from-DT.patch | 52 + ...device-IDs-for-Apple-SPI-HID-devices.patch | 84 + ...e-add-support-for-internal-keyboards.patch | 68 + ...-key-mapping-for-Apple-silicon-MacBo.patch | 64 + ...-key-mapping-for-Macbook-Pro-with-to.patch | 65 + ...se-a-define-of-the-max-number-of-tou.patch | 47 + ...ouse-use-struct-input_mt_pos-for-X-Y.patch | 48 + ...se-ops-function-pointers-for-input-f.patch | 86 + ...se-add-support-for-Macbook-trackpads.patch | 358 ++ ...ransport-spi-add-Apple-SPI-transport.patch | 1323 ++++++++ ...dor-device-IDs-for-Apple-MTP-devices.patch | 38 + ...HOST-bus-type-when-announcing-device.patch | 28 + ...d-apple-Bind-to-HOST-devices-for-MTP.patch | 59 + ...e-Add-MTP-multi-touch-device-support.patch | 174 + ...129-soc-apple-Add-DockChannel-driver.patch | 501 +++ ...ple-DockChannel-HID-transport-driver.patch | 1142 +++++++ ...31-soc-apple-Add-RTKit-helper-driver.patch | 211 ++ ...Drop-incoming-packet-sequence-requir.patch | 62 + ...l-hid-Send-interface-firmware-lazily.patch | 393 +++ ...nel-hid-Handle-M2-Air-keyboard-types.patch | 37 + ...-support-for-generic-FOURCCs-by-exte.patch | 136 + ...soc-apple-rtkit-Add-apple_rtkit_poll.patch | 54 + ...Get-rid-of-apple_rtkit_send_message_.patch | 89 + ...m-apple-Add-new-Apple-Mac-SMC-driver.patch | 969 ++++++ ...ew-gpio-macsmc-driver-for-Apple-Macs.patch | 307 ++ ...smc_power-Driver-for-Apple-SMC-power.patch | 311 ++ ...smc_power-Add-cycle-count-and-health.patch | 43 + ...supply-macsmc_power-Add-present-prop.patch | 35 + ...smc_power-Add-more-props-rework-othe.patch | 334 ++ ...smc_power-Use-BUIC-instead-of-BRSC-f.patch | 29 + ...smc_power-Turn-off-OBC-flags-if-macO.patch | 29 + ...ply-macsmc_power-Add-AC-power-supply.patch | 137 + ...mc-reboot-Add-driver-for-rebooting-v.patch | 397 +++ ...macsmc-driver-for-Apple-Silicon-Macs.patch | 202 ++ ...-New-driver-to-handle-the-Apple-Mac-.patch | 221 ++ ...acsmc-hid-Support-button-lid-wakeups.patch | 99 + .../0151-gpio-macsmc-Add-IRQ-support.patch | 212 ++ ...irst-basic-spmi-driver-for-Apple-SoC.patch | 249 ++ ...153-mfd-Add-a-simple-mfd-spmi-driver.patch | 133 + ...0154-nvmem-Add-spmi-mfd-nvmem-driver.patch | 163 + ...rly-wait-for-status-data-after-write.patch | 53 + ...entries-for-Apple-SoC-cpufreq-driver.patch | 35 + ...req-apple-soc-cpufreq-Add-binding-fo.patch | 149 + ...c-Add-new-driver-to-control-Apple-So.patch | 415 +++ ...Add-CPU-topology-cpufreq-nodes-for-t.patch | 313 ++ ...-cpufreq-apple-soc-Add-T8112-support.patch | 180 + ...apple-pcie-Add-subnode-binding-pwren.patch | 111 + ...iod_set_value_cansleep-in-probe-flow.patch | 41 + ...I-apple-Use-devm-managed-GPIO-getter.patch | 34 + ...obe-all-GPIOs-for-availability-first.patch | 67 + ...-Add-support-for-optional-PWREN-GPIO.patch | 88 + ...net-Add-generic-Bluetooth-controller.patch | 65 + ...Add-Broadcom-BCM4377-family-PCI-Blue.patch | 116 + ...ent-Add-quirk-to-ignore-byte-in-LE-E.patch | 94 + ...d-quirk-to-disable-extended-scanning.patch | 77 + ...m4377-Add-new-driver-for-BCM4377-PCI.patch | 2541 ++++++++++++++ ...0171-Makefile-Add-asahi-EXTRAVERSION.patch | 26 + 173 files changed, 36779 insertions(+) create mode 100644 target/linux/silicon/Makefile create mode 100644 target/linux/silicon/armv8/config-5.19 create mode 100644 target/linux/silicon/patches-5.19/0001-arm64-dts-apple-Add-CPU-topology-cpufreq-nodes-for-t.patch create mode 100644 target/linux/silicon/patches-5.19/0002-arm64-dts-apple-t8103-Add-ANS2-nodes.patch create mode 100644 target/linux/silicon/patches-5.19/0003-arm64-dts-apple-t8103-Add-dwc3-nodes.patch create mode 100644 target/linux/silicon/patches-5.19/0004-arm64-dts-apple-t8103-Add-spi3-keyboard-nodes.patch create mode 100644 target/linux/silicon/patches-5.19/0005-arm64-dts-apple-Fix-j45x-model-years.patch create mode 100644 target/linux/silicon/patches-5.19/0006-arm64-dts-apple-Add-WiFi-module-and-antenna-properti.patch create mode 100644 target/linux/silicon/patches-5.19/0007-arm64-dts-apple-Add-PCI-power-enable-GPIOs.patch create mode 100644 target/linux/silicon/patches-5.19/0008-arm64-dts-apple-Add-SMC-node-to-t8103-t6001-devicetr.patch create mode 100644 target/linux/silicon/patches-5.19/0009-arm64-dts-apple-Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch create mode 100644 target/linux/silicon/patches-5.19/0010-arm64-dts-apple-Re-parent-ANS2-power-domains.patch create mode 100644 target/linux/silicon/patches-5.19/0011-arm64-dts-apple-Mark-ATC-USB-AON-domains-as-always-o.patch create mode 100644 target/linux/silicon/patches-5.19/0012-arm64-dts-apple-Add-backlight-node-to-j293-j313.patch create mode 100644 target/linux/silicon/patches-5.19/0013-arm64-dts-apple-t8103-Put-in-audio-nodes.patch create mode 100644 target/linux/silicon/patches-5.19/0014-arm64-dts-apple-t8103-j313-Also-disable-speakers.patch create mode 100644 target/linux/silicon/patches-5.19/0015-arm64-dts-apple-Keep-PCIe-power-domain-on.patch create mode 100644 target/linux/silicon/patches-5.19/0016-arm64-dts-apple-Add-initial-t6000-t6001-t6002-DTs.patch create mode 100644 target/linux/silicon/patches-5.19/0017-arm64-dts-apple-Add-J314-and-J316-devicetrees.patch create mode 100644 target/linux/silicon/patches-5.19/0018-arm64-dts-apple-Add-devicetree-for-Apple-Mac-Studio-.patch create mode 100644 target/linux/silicon/patches-5.19/0019-arm64-dts-apple-Add-devicetree-for-Apple-Mac-Studio-.patch create mode 100644 target/linux/silicon/patches-5.19/0020-arm64-dts-apple-Add-CPUfreq-nodes-for-t6001.patch create mode 100644 target/linux/silicon/patches-5.19/0021-arm64-dts-apple-Add-SMC-node-to-t600x-devicetrees.patch create mode 100644 target/linux/silicon/patches-5.19/0022-arm64-dts-apple-Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch create mode 100644 target/linux/silicon/patches-5.19/0023-arm64-dts-apple-t6000-Add-spi1-node.patch create mode 100644 target/linux/silicon/patches-5.19/0024-arm64-dts-apple-t600x-j314-j316-Add-NOR-flash-node.patch create mode 100644 target/linux/silicon/patches-5.19/0025-arm64-dts-apple-t600x-Add-spi3-node.patch create mode 100644 target/linux/silicon/patches-5.19/0026-arm64-dts-apple-j31-46-Add-keyboard-nodes.patch create mode 100644 target/linux/silicon/patches-5.19/0027-arm64-dts-apple-t600x-Add-dwc3-nodes.patch create mode 100644 target/linux/silicon/patches-5.19/0028-arm64-dts-apple-Add-WiFi-module-and-antenna-properti.patch create mode 100644 target/linux/silicon/patches-5.19/0029-arm64-dts-apple-Add-PCI-power-enable-GPIOs.patch create mode 100644 target/linux/silicon/patches-5.19/0030-arm64-dts-apple-Add-backlight-node-to-j314-j316.patch create mode 100644 target/linux/silicon/patches-5.19/0031-arm64-dts-apple-t600-Put-in-audio-nodes.patch create mode 100644 target/linux/silicon/patches-5.19/0032-arm64-dts-apple-t600-Put-in-audio-nodes.patch create mode 100644 target/linux/silicon/patches-5.19/0033-arm64-dts-apple-t600-Add-t8103-compat-to-cpufreq-nod.patch create mode 100644 target/linux/silicon/patches-5.19/0034-arm64-dts-apple-t8103-Fix-spi4-power-domain-sort-ord.patch create mode 100644 target/linux/silicon/patches-5.19/0035-arm64-dts-apple-t8103-Add-bluetooth-device-trees.patch create mode 100644 target/linux/silicon/patches-5.19/0036-arm64-dts-apple-t600x-Add-bluetooth-device-trees.patch create mode 100644 target/linux/silicon/patches-5.19/0037-arm64-dts-apple-t8112-Initial-t8112-M2-device-trees.patch create mode 100644 target/linux/silicon/patches-5.19/0038-arm64-dts-apple-t8112-j413-Fix-IRQ-for-hpm5.patch create mode 100644 target/linux/silicon/patches-5.19/0039-MAINTAINERS-Add-Apple-dwc3-bindings-to-ARM-APPLE.patch create mode 100644 target/linux/silicon/patches-5.19/0040-MAINTAINERS-Add-apple-spi-driver-binding-files.patch create mode 100644 target/linux/silicon/patches-5.19/0041-mailbox-apple-Implement-flush-operation.patch create mode 100644 target/linux/silicon/patches-5.19/0042-mailbox-apple-Implement-poll_data-operation.patch create mode 100644 target/linux/silicon/patches-5.19/0043-mailbox-apple-Keep-IRQs-active-in-suspend.patch create mode 100644 target/linux/silicon/patches-5.19/0044-mailbox-apple-Fix-races-around-poll-tx.patch create mode 100644 target/linux/silicon/patches-5.19/0045-WIP-mailbox-fix-poll.patch create mode 100644 target/linux/silicon/patches-5.19/0046-dt-bindings-iommu-dart-add-t6000-compatible.patch create mode 100644 target/linux/silicon/patches-5.19/0047-iommu-io-pgtable-Move-Apple-DART-support-to-its-own-.patch create mode 100644 target/linux/silicon/patches-5.19/0048-iommu-io-pgtable-Add-DART-subpage-protection-support.patch create mode 100644 target/linux/silicon/patches-5.19/0049-iommu-io-pgtable-dart-Add-DART-PTE-support-for-t6000.patch create mode 100644 target/linux/silicon/patches-5.19/0050-iommu-dart-Support-t6000-variant.patch create mode 100644 target/linux/silicon/patches-5.19/0051-iommu-dart-Add-suspend-resume-support.patch create mode 100644 target/linux/silicon/patches-5.19/0052-iommu-dart-Support-64-stream-IDs.patch create mode 100644 target/linux/silicon/patches-5.19/0053-iommu-dart-Support-a-variable-number-of-TTBRs-per-st.patch create mode 100644 target/linux/silicon/patches-5.19/0054-iommu-dart-Fix-DART_PARAMS1-2-bit-define-names.patch create mode 100644 target/linux/silicon/patches-5.19/0055-iommu-dart-Support-different-variants-with-different.patch create mode 100644 target/linux/silicon/patches-5.19/0056-iommu-dart-Add-t8110-support.patch create mode 100644 target/linux/silicon/patches-5.19/0057-tty-serial-samsung_tty-Support-runtime-PM.patch create mode 100644 target/linux/silicon/patches-5.19/0058-drm-simpledrm-Add-backlight-support.patch create mode 100644 target/linux/silicon/patches-5.19/0059-of-Demote-Bad-cell-count-to-debug-message.patch create mode 100644 target/linux/silicon/patches-5.19/0060-mmc-sdhci-pci-Support-external-CD-GPIO-on-all-OF-sys.patch create mode 100644 target/linux/silicon/patches-5.19/0061-mmc-sdhci-pci-Support-setting-CD-debounce-delay.patch create mode 100644 target/linux/silicon/patches-5.19/0062-net-usb-ax88179_178a-Bind-only-to-vendor-specific-in.patch create mode 100644 target/linux/silicon/patches-5.19/0063-dt-bindings-usb-Add-Apple-dwc3-bindings.patch create mode 100644 target/linux/silicon/patches-5.19/0064-usb-dwc3-Add-role-switch-reset-quirk-for-Apple-DWC3.patch create mode 100644 target/linux/silicon/patches-5.19/0065-apple-nvme-defer-cache-flushes-by-a-specified-amount.patch create mode 100644 target/linux/silicon/patches-5.19/0066-apple-nvme-Release-power-domains-when-probe-fails.patch create mode 100644 target/linux/silicon/patches-5.19/0067-MAINTAINERS-Add-apple-spi-driver-binding-files.patch create mode 100644 target/linux/silicon/patches-5.19/0068-dt-bindings-spi-apple-spi-Add-binding-for-Apple-SPI-.patch create mode 100644 target/linux/silicon/patches-5.19/0069-spi-apple-Add-driver-for-Apple-SPI-controller.patch create mode 100644 target/linux/silicon/patches-5.19/0070-dt-bindings-dma-Add-apple-admac-binding.patch create mode 100644 target/linux/silicon/patches-5.19/0071-dmaengine-apple-admac-Add-Apple-ADMAC-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0072-ASoC-apple-mca-Add-platform-driver-for-Apple-SoCs.patch create mode 100644 target/linux/silicon/patches-5.19/0073-ASoC-tas2770-Set-correct-FSYNC-polarity.patch create mode 100644 target/linux/silicon/patches-5.19/0074-HACK-ASoC-tas2770-Set-no-of-channels-to-1.patch create mode 100644 target/linux/silicon/patches-5.19/0075-HACK-ASoC-cs42l42-Disable-regcache.patch create mode 100644 target/linux/silicon/patches-5.19/0076-ASoC-cs42l42-Bypass-device-ID-check.patch create mode 100644 target/linux/silicon/patches-5.19/0077-HACK-ASoC-Add-card-filter_controls-hook.patch create mode 100644 target/linux/silicon/patches-5.19/0078-ASoC-Add-asoc_pcm_to_rtd-utility-function.patch create mode 100644 target/linux/silicon/patches-5.19/0079-HACK-ASoC-Allow-an-N-cpus-to-M-codecs-link.patch create mode 100644 target/linux/silicon/patches-5.19/0080-ASoC-Add-macaudio-machine-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0081-ASoC-tas2764-Extend-driver-to-SN012776.patch create mode 100644 target/linux/silicon/patches-5.19/0082-ASoC-tas2764-Add-workaround-for-spurious-shutdowns-o.patch create mode 100644 target/linux/silicon/patches-5.19/0083-ASoC-macaudio-State-missing-simple-card-utils-depend.patch create mode 100644 target/linux/silicon/patches-5.19/0084-macaudio-Unbork-jack-volume.patch create mode 100644 target/linux/silicon/patches-5.19/0085-dt-bindings-net-bcm4329-fmac-Add-Apple-properties-ch.patch create mode 100644 target/linux/silicon/patches-5.19/0086-brcmfmac-firmware-Handle-per-board-clm_blob-files.patch create mode 100644 target/linux/silicon/patches-5.19/0087-brcmfmac-pcie-sdio-usb-Get-CLM-blob-via-standard-fir.patch create mode 100644 target/linux/silicon/patches-5.19/0088-brcmfmac-firmware-Support-passing-in-multiple-board_.patch create mode 100644 target/linux/silicon/patches-5.19/0089-brcmfmac-pcie-Read-Apple-OTP-information.patch create mode 100644 target/linux/silicon/patches-5.19/0090-brcmfmac-of-Fetch-Apple-properties.patch create mode 100644 target/linux/silicon/patches-5.19/0091-brcmfmac-pcie-Perform-firmware-selection-for-Apple-p.patch create mode 100644 target/linux/silicon/patches-5.19/0092-brcmfmac-firmware-Allow-platform-to-override-macaddr.patch create mode 100644 target/linux/silicon/patches-5.19/0093-brcmfmac-msgbuf-Increase-RX-ring-sizes-to-1024.patch create mode 100644 target/linux/silicon/patches-5.19/0094-brcmfmac-pcie-Support-PCIe-core-revisions-64.patch create mode 100644 target/linux/silicon/patches-5.19/0095-brcmfmac-pcie-Add-IDs-properties-for-BCM4378.patch create mode 100644 target/linux/silicon/patches-5.19/0096-ACPI-property-Support-strings-in-Apple-_DSM-props.patch create mode 100644 target/linux/silicon/patches-5.19/0097-brcmfmac-acpi-Add-support-for-fetching-Apple-ACPI-pr.patch create mode 100644 target/linux/silicon/patches-5.19/0098-brcmfmac-pcie-Provide-a-buffer-of-random-bytes-to-th.patch create mode 100644 target/linux/silicon/patches-5.19/0099-brcmfmac-pcie-Add-IDs-properties-for-BCM4355.patch create mode 100644 target/linux/silicon/patches-5.19/0100-brcmfmac-pcie-Add-IDs-properties-for-BCM4377.patch create mode 100644 target/linux/silicon/patches-5.19/0101-brcmfmac-pcie-Perform-correct-BCM4364-firmware-selec.patch create mode 100644 target/linux/silicon/patches-5.19/0102-brcmfmac-chip-Only-disable-D11-cores-handle-an-arbit.patch create mode 100644 target/linux/silicon/patches-5.19/0103-brcmfmac-chip-Handle-1024-unit-sizes-for-TCM-blocks.patch create mode 100644 target/linux/silicon/patches-5.19/0104-brcmfmac-cfg80211-Add-support-for-scan-params-v2.patch create mode 100644 target/linux/silicon/patches-5.19/0105-brcmfmac-feature-Add-support-for-setting-feats-based.patch create mode 100644 target/linux/silicon/patches-5.19/0106-brcmfmac-cfg80211-Add-support-for-PMKID_V3-operation.patch create mode 100644 target/linux/silicon/patches-5.19/0107-brcmfmac-cfg80211-Pass-the-PMK-in-binary-instead-of-.patch create mode 100644 target/linux/silicon/patches-5.19/0108-brcmflac-cfg80211-Use-WSEC-to-set-SAE-password.patch create mode 100644 target/linux/silicon/patches-5.19/0109-brcmfmac-pcie-Add-IDs-properties-for-BCM4387.patch create mode 100644 target/linux/silicon/patches-5.19/0110-brcmfmac-common-Add-support-for-downloading-TxCap-bl.patch create mode 100644 target/linux/silicon/patches-5.19/0111-brcmfmac-pcie-Load-and-provide-TxCap-blobs.patch create mode 100644 target/linux/silicon/patches-5.19/0112-brcmfmac-common-Add-support-for-external-calibration.patch create mode 100644 target/linux/silicon/patches-5.19/0113-brcmfmac-pcie-Add-BCM4378B3-support.patch create mode 100644 target/linux/silicon/patches-5.19/0114-spi-dt-bindings-add-CS-delay-peripheral-specific-pro.patch create mode 100644 target/linux/silicon/patches-5.19/0115-spi-parse-CS-delay-values-from-DT.patch create mode 100644 target/linux/silicon/patches-5.19/0116-HID-add-device-IDs-for-Apple-SPI-HID-devices.patch create mode 100644 target/linux/silicon/patches-5.19/0117-HID-apple-add-support-for-internal-keyboards.patch create mode 100644 target/linux/silicon/patches-5.19/0118-HID-apple-add-Fn-key-mapping-for-Apple-silicon-MacBo.patch create mode 100644 target/linux/silicon/patches-5.19/0119-HID-apple-add-Fn-key-mapping-for-Macbook-Pro-with-to.patch create mode 100644 target/linux/silicon/patches-5.19/0120-HID-magicmouse-use-a-define-of-the-max-number-of-tou.patch create mode 100644 target/linux/silicon/patches-5.19/0121-HID-magicmouse-use-struct-input_mt_pos-for-X-Y.patch create mode 100644 target/linux/silicon/patches-5.19/0122-HID-magicmouse-use-ops-function-pointers-for-input-f.patch create mode 100644 target/linux/silicon/patches-5.19/0123-HID-magicmouse-add-support-for-Macbook-trackpads.patch create mode 100644 target/linux/silicon/patches-5.19/0124-WIP-HID-transport-spi-add-Apple-SPI-transport.patch create mode 100644 target/linux/silicon/patches-5.19/0125-HID-add-HOST-vendor-device-IDs-for-Apple-MTP-devices.patch create mode 100644 target/linux/silicon/patches-5.19/0126-HID-core-Handle-HOST-bus-type-when-announcing-device.patch create mode 100644 target/linux/silicon/patches-5.19/0127-hid-apple-Bind-to-HOST-devices-for-MTP.patch create mode 100644 target/linux/silicon/patches-5.19/0128-hid-magicmouse-Add-MTP-multi-touch-device-support.patch create mode 100644 target/linux/silicon/patches-5.19/0129-soc-apple-Add-DockChannel-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0130-hid-Add-Apple-DockChannel-HID-transport-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0131-soc-apple-Add-RTKit-helper-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0132-dockchannel-hid-Drop-incoming-packet-sequence-requir.patch create mode 100644 target/linux/silicon/patches-5.19/0133-dockchanel-hid-Send-interface-firmware-lazily.patch create mode 100644 target/linux/silicon/patches-5.19/0134-dockchannel-hid-Handle-M2-Air-keyboard-types.patch create mode 100644 target/linux/silicon/patches-5.19/0135-lib-vsprintf-Add-support-for-generic-FOURCCs-by-exte.patch create mode 100644 target/linux/silicon/patches-5.19/0136-soc-apple-rtkit-Add-apple_rtkit_poll.patch create mode 100644 target/linux/silicon/patches-5.19/0137-soc-apple-rtkit-Get-rid-of-apple_rtkit_send_message_.patch create mode 100644 target/linux/silicon/patches-5.19/0138-platform-apple-Add-new-Apple-Mac-SMC-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0139-gpio-Add-new-gpio-macsmc-driver-for-Apple-Macs.patch create mode 100644 target/linux/silicon/patches-5.19/0140-power-supply-macsmc_power-Driver-for-Apple-SMC-power.patch create mode 100644 target/linux/silicon/patches-5.19/0141-power-supply-macsmc_power-Add-cycle-count-and-health.patch create mode 100644 target/linux/silicon/patches-5.19/0142-power-supply-macsmc_power-Add-present-prop.patch create mode 100644 target/linux/silicon/patches-5.19/0143-power-supply-macsmc_power-Add-more-props-rework-othe.patch create mode 100644 target/linux/silicon/patches-5.19/0144-power-supply-macsmc_power-Use-BUIC-instead-of-BRSC-f.patch create mode 100644 target/linux/silicon/patches-5.19/0145-power-supply-macsmc_power-Turn-off-OBC-flags-if-macO.patch create mode 100644 target/linux/silicon/patches-5.19/0146-power-supply-macsmc_power-Add-AC-power-supply.patch create mode 100644 target/linux/silicon/patches-5.19/0147-power-reset-macsmc-reboot-Add-driver-for-rebooting-v.patch create mode 100644 target/linux/silicon/patches-5.19/0148-rtc-Add-new-rtc-macsmc-driver-for-Apple-Silicon-Macs.patch create mode 100644 target/linux/silicon/patches-5.19/0149-Input-macsmc-hid-New-driver-to-handle-the-Apple-Mac-.patch create mode 100644 target/linux/silicon/patches-5.19/0150-Input-macsmc-hid-Support-button-lid-wakeups.patch create mode 100644 target/linux/silicon/patches-5.19/0151-gpio-macsmc-Add-IRQ-support.patch create mode 100644 target/linux/silicon/patches-5.19/0152-spmi-add-a-first-basic-spmi-driver-for-Apple-SoC.patch create mode 100644 target/linux/silicon/patches-5.19/0153-mfd-Add-a-simple-mfd-spmi-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0154-nvmem-Add-spmi-mfd-nvmem-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0155-spmi-apple-Properly-wait-for-status-data-after-write.patch create mode 100644 target/linux/silicon/patches-5.19/0156-MAINTAINERS-Add-entries-for-Apple-SoC-cpufreq-driver.patch create mode 100644 target/linux/silicon/patches-5.19/0157-dt-bindings-cpufreq-apple-soc-cpufreq-Add-binding-fo.patch create mode 100644 target/linux/silicon/patches-5.19/0158-cpufreq-apple-soc-Add-new-driver-to-control-Apple-So.patch create mode 100644 target/linux/silicon/patches-5.19/0159-arm64-dts-apple-Add-CPU-topology-cpufreq-nodes-for-t.patch create mode 100644 target/linux/silicon/patches-5.19/0160-cpufreq-apple-soc-Add-T8112-support.patch create mode 100644 target/linux/silicon/patches-5.19/0161-dt-bindings-pci-apple-pcie-Add-subnode-binding-pwren.patch create mode 100644 target/linux/silicon/patches-5.19/0162-PCI-apple-Use-gpiod_set_value_cansleep-in-probe-flow.patch create mode 100644 target/linux/silicon/patches-5.19/0163-PCI-apple-Use-devm-managed-GPIO-getter.patch create mode 100644 target/linux/silicon/patches-5.19/0164-PCI-apple-Probe-all-GPIOs-for-availability-first.patch create mode 100644 target/linux/silicon/patches-5.19/0165-PCI-apple-Add-support-for-optional-PWREN-GPIO.patch create mode 100644 target/linux/silicon/patches-5.19/0166-dt-bindings-net-Add-generic-Bluetooth-controller.patch create mode 100644 target/linux/silicon/patches-5.19/0167-dt-bindings-net-Add-Broadcom-BCM4377-family-PCI-Blue.patch create mode 100644 target/linux/silicon/patches-5.19/0168-Bluetooth-hci_event-Add-quirk-to-ignore-byte-in-LE-E.patch create mode 100644 target/linux/silicon/patches-5.19/0169-Bluetooth-Add-quirk-to-disable-extended-scanning.patch create mode 100644 target/linux/silicon/patches-5.19/0170-Bluetooth-hci_bcm4377-Add-new-driver-for-BCM4377-PCI.patch create mode 100644 target/linux/silicon/patches-5.19/0171-Makefile-Add-asahi-EXTRAVERSION.patch diff --git a/target/linux/silicon/Makefile b/target/linux/silicon/Makefile new file mode 100644 index 000000000..e9f3efaa9 --- /dev/null +++ b/target/linux/silicon/Makefile @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# + +include $(TOPDIR)/rules.mk + +ARCH:=arm +BOARD:=silicon +BOARDNAME:=Apple Silicon family +FEATURES:=audio boot-part ext4 fpu squashfs usbgadget +SUBTARGETS:=armv8 + +KERNEL_PATCHVER:=5.19 + +define Target/Description + Build firmware image for Apple Silicon family +endef + +include $(INCLUDE_DIR)/target.mk + +DEFAULT_PACKAGES += \ + e2fsprogs \ + kmod-sound-core \ + kmod-usb-hid \ + mkf2fs \ + partx-utils + +KERNELNAME:=Image dtbs + +$(eval $(call BuildTarget)) \ No newline at end of file diff --git a/target/linux/silicon/armv8/config-5.19 b/target/linux/silicon/armv8/config-5.19 new file mode 100644 index 000000000..8bd9ea04e --- /dev/null +++ b/target/linux/silicon/armv8/config-5.19 @@ -0,0 +1,510 @@ +CONFIG_64BIT=y +# CONFIG_AIO is not set +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +CONFIG_ARCH_APPLE=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=33 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_STACKWALK=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM64=y +CONFIG_ARM64_4K_PAGES=y +CONFIG_ARM64_CNP=y +CONFIG_ARM64_ERRATUM_1165522=y +CONFIG_ARM64_ERRATUM_1286807=y +CONFIG_ARM64_ERRATUM_819472=y +CONFIG_ARM64_ERRATUM_824069=y +CONFIG_ARM64_ERRATUM_826319=y +CONFIG_ARM64_ERRATUM_827319=y +CONFIG_ARM64_ERRATUM_843419=y +CONFIG_ARM64_ERRATUM_858921=y +CONFIG_ARM64_HW_AFDBM=y +CONFIG_ARM64_MODULE_PLTS=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_PAN=y +CONFIG_ARM64_PA_BITS=48 +CONFIG_ARM64_PA_BITS_48=y +CONFIG_ARM64_PMEM=y +CONFIG_ARM64_PTR_AUTH=y +CONFIG_ARM64_SVE=y +# CONFIG_ARM64_SW_TTBR0_PAN is not set +CONFIG_ARM64_TAGGED_ADDR_ABI=y +CONFIG_ARM64_UAO=y +CONFIG_ARM64_VA_BITS=48 +# CONFIG_ARM64_VA_BITS_39 is not set +CONFIG_ARM64_VA_BITS_48=y +CONFIG_ARM64_VHE=y +CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y +CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y +CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_SCMI_PROTOCOL is not set +CONFIG_ARM_SCPI_POWER_DOMAIN=y +CONFIG_ARM_SCPI_PROTOCOL=y +CONFIG_ASN1=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_PM=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_CAVIUM_TX2_ERRATUM_219=y +# CONFIG_CEC_CH7322 is not set +# CONFIG_CEC_MESON_AO is not set +# CONFIG_CEC_MESON_G12A_AO is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLK_QORIQ=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CLZ_TAB=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=16 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_AXG=y +# CONFIG_COMMON_CLK_AXG_AUDIO is not set +CONFIG_COMMON_CLK_CS2000_CP=y +CONFIG_COMMON_CLK_G12A=y +CONFIG_COMMON_CLK_GXBB=y +CONFIG_COMMON_CLK_MESON_AO_CLKC=y +CONFIG_COMMON_CLK_MESON_CPU_DYNDIV=y +CONFIG_COMMON_CLK_MESON_DUALDIV=y +CONFIG_COMMON_CLK_MESON_EE_CLKC=y +CONFIG_COMMON_CLK_MESON_MPLL=y +CONFIG_COMMON_CLK_MESON_PLL=y +CONFIG_COMMON_CLK_MESON_REGMAP=y +CONFIG_COMMON_CLK_MESON_VID_PLL_DIV=y +CONFIG_COMMON_CLK_PWM=y +CONFIG_COMMON_CLK_SCPI=y +CONFIG_COMMON_CLK_XGENE=y +# CONFIG_COMPAT_32BIT_TIME is not set +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_CONTIG_ALLOC=y +CONFIG_COREDUMP=y +CONFIG_CPU_RMAP=y +CONFIG_CRC16=y +CONFIG_CRC7=y +CONFIG_CRC_ITU_T=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_GHASH=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_SHA256=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_INFO=y +CONFIG_DMA_CMA=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DRM=y +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_DW_HDMI=y +# CONFIG_DRM_DW_HDMI_I2S_AUDIO is not set +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FBDEV_OVERALLOC=100 +CONFIG_DRM_GEM_CMA_HELPER=y +CONFIG_DRM_KMS_CMA_HELPER=y +CONFIG_DRM_KMS_FB_HELPER=y +CONFIG_DRM_KMS_HELPER=y +CONFIG_DRM_MALI_DISPLAY=y +CONFIG_DRM_MESON=y +CONFIG_DRM_MESON_DW_HDMI=y +CONFIG_DRM_PANEL=y +CONFIG_DRM_PANEL_BRIDGE=y +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_DVB_CORE=y +CONFIG_DWMAC_DWC_QOS_ETH=y +# CONFIG_DWMAC_GENERIC is not set +CONFIG_DWMAC_MESON=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ELF_CORE=y +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXTCON=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_POSIX_ACL=y +CONFIG_FB=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_SYS_IMAGEBLIT=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAME_POINTER=y +CONFIG_FSL_ERRATUM_A008585=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FTRACE=y +# CONFIG_FTRACE_SYSCALLS is not set +CONFIG_FUJITSU_ERRATUM_010001=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GLOB=y +CONFIG_GPIOLIB=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HDMI=y +CONFIG_HISILICON_ERRATUM_161010101=y +# CONFIG_HIST_TRIGGERS is not set +CONFIG_HOLES_IN_ZONE=y +CONFIG_HWMON=y +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MESON=y +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_MESON=y +CONFIG_ICPLUS_PHY=y +CONFIG_IIO=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_INPUT=y +CONFIG_IPV6=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_PIMSM_V2 is not set +CONFIG_IPV6_SUBTREES=y +CONFIG_IP_MROUTE_COMMON=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +# CONFIG_IR_IMON_RAW is not set +CONFIG_IR_MESON=y +# CONFIG_IR_SERIAL is not set +# CONFIG_IR_SIR is not set +# CONFIG_IR_TOY is not set +CONFIG_JBD2=y +CONFIG_KCMP=y +CONFIG_KEYS=y +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set +CONFIG_LEDS_GPIO=y +CONFIG_LIBFDT=y +# CONFIG_LIRC is not set +CONFIG_LLD_VERSION=0 +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_BUS_MUX=y +# CONFIG_MDIO_BUS_MUX_MESON_G12A is not set +CONFIG_MDIO_BUS_MUX_MMIOREG=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_DEVRES=y +# CONFIG_MDIO_GPIO is not set +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_ATTACH=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CEC_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_PLATFORM_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SDR_SUPPORT=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_TEST_SUPPORT=y +CONFIG_MEDIA_TUNER=y +CONFIG_MEMFD_CREATE=y +CONFIG_MEMORY_ISOLATION=y +CONFIG_MESON_CANVAS=y +CONFIG_MESON_CLK_MEASURE=y +CONFIG_MESON_EE_PM_DOMAINS=y +CONFIG_MESON_EFUSE=y +CONFIG_MESON_GXBB_WATCHDOG=y +CONFIG_MESON_GXL_PHY=y +CONFIG_MESON_GX_PM_DOMAINS=y +CONFIG_MESON_GX_SOCINFO=y +CONFIG_MESON_IRQ_GPIO=y +# CONFIG_MESON_MX_EFUSE is not set +CONFIG_MESON_MX_SOCINFO=y +CONFIG_MESON_SARADC=y +CONFIG_MESON_SECURE_PM_DOMAINS=y +CONFIG_MESON_SM=y +CONFIG_MESON_WATCHDOG=y +# CONFIG_MFD_KHADAS_MCU is not set +CONFIG_MFD_SYSCON=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_CQHCI=y +CONFIG_MMC_DW=y +# CONFIG_MMC_DW_BLUEFIELD is not set +# CONFIG_MMC_DW_EXYNOS is not set +# CONFIG_MMC_DW_HI3798CV200 is not set +CONFIG_MMC_DW_K3=y +CONFIG_MMC_DW_PLTFM=y +CONFIG_MMC_MESON_GX=y +# CONFIG_MMC_MESON_MX_SDIO is not set +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SPI=y +CONFIG_MMC_STM32_SDMMC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MPILIB=y +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_EMATCH=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NLS=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_IOPORT_MAP=y +CONFIG_NR_CPUS=8 +CONFIG_NVMEM=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OID_REGISTRY=y +CONFIG_PADATA=y +CONFIG_PAGE_POOL=y +CONFIG_PARTITION_PERCPU=y +CONFIG_PCS_XPCS=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PHY_MESON8B_USB2=y +CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG=y +CONFIG_PHY_MESON_AXG_PCIE=y +# CONFIG_PHY_MESON_G12A_USB2 is not set +# CONFIG_PHY_MESON_G12A_USB3_PCIE is not set +CONFIG_PHY_MESON_GXL_USB2=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_MESON=y +CONFIG_PINCTRL_MESON8_PMX=y +# CONFIG_PINCTRL_MESON_A1 is not set +# CONFIG_PINCTRL_MESON_AXG is not set +# CONFIG_PINCTRL_MESON_G12A is not set +CONFIG_PINCTRL_MESON_GXBB=y +CONFIG_PINCTRL_MESON_GXL=y +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PLATFORM_MHU=y +CONFIG_PM=y +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_POWER_RESET=y +CONFIG_POWER_SUPPLY=y +CONFIG_POWER_SUPPLY_HWMON=y +CONFIG_PPS=y +CONFIG_PRINTK_TIME=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PWM=y +CONFIG_PWM_MESON=y +CONFIG_PWM_SYSFS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_RATIONAL=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RC_CORE=y +CONFIG_RC_DEVICES=y +# CONFIG_RC_XBOX_DVD is not set +CONFIG_REALTEK_AUTOPM=y +CONFIG_REALTEK_PHY=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_DEBUG=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_MESON=y +# CONFIG_RESET_MESON_AUDIO_ARB is not set +CONFIG_RFS_ACCEL=y +CONFIG_RODATA_FULL_DEFAULT_ENABLED=y +CONFIG_RPS=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_SCSI=y +CONFIG_SDIO_UART=y +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +CONFIG_SENSORS_ARM_SCPI=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_MESON=y +CONFIG_SERIAL_MESON_CONSOLE=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SOC_BUS=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MESON_SPICC=y +CONFIG_SPI_MESON_SPIFC=y +CONFIG_SRCU=y +CONFIG_STACKTRACE=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +# CONFIG_STMMAC_SELFTESTS is not set +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SYNC_FILE=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_TUN=y +CONFIG_UNMAP_KERNEL_AT_EL0=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_DUAL_ROLE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_DUAL_ROLE=y +# CONFIG_USB_DWC3_GADGET is not set +# CONFIG_USB_DWC3_HOST is not set +CONFIG_USB_DWC3_MESON_G12A=y +CONFIG_USB_DWC3_OF_SIMPLE=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +# CONFIG_USB_ETH is not set +CONFIG_USB_GADGET=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_OTG=y +CONFIG_USB_OTG_FSM=y +CONFIG_USB_PHY=y +# CONFIG_USB_PULSE8_CEC is not set +# CONFIG_USB_RAINSHADOW_CEC is not set +CONFIG_USB_ROLE_SWITCH=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_REALTEK=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_VIDEOMODE_HELPERS=y +CONFIG_VMAP_STACK=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_XPS=y +CONFIG_ZONE_DMA32=y \ No newline at end of file diff --git a/target/linux/silicon/patches-5.19/0001-arm64-dts-apple-Add-CPU-topology-cpufreq-nodes-for-t.patch b/target/linux/silicon/patches-5.19/0001-arm64-dts-apple-Add-CPU-topology-cpufreq-nodes-for-t.patch new file mode 100644 index 000000000..63b1539be --- /dev/null +++ b/target/linux/silicon/patches-5.19/0001-arm64-dts-apple-Add-CPU-topology-cpufreq-nodes-for-t.patch @@ -0,0 +1,313 @@ +From 6515c017a89844b13e041b739cba63ca1fd5dcb2 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 3 May 2022 00:08:56 +0900 +Subject: [PATCH 001/171] arm64: dts: apple: Add CPU topology & cpufreq nodes + for t8103 + +Add the missing CPU topology/capacity information and the cpufreq nodes, +so we can have CPU frequency scaling and the scheduler has the +information it needs to make the correct decisions. + +Boost states are commented out, as they are not yet available (that +requires CPU deep sleep support, to be eventually done via PSCI). +The driver supports them fine; the hardware will just refuse to ever +go into them at this time, so don't expose them to users until that's +done. + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103.dtsi | 203 +++++++++++++++++++++++++-- + 1 file changed, 193 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index 9f8f4145db88..3df126a5a7dd 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -22,71 +22,245 @@ cpus { + #address-cells = <2>; + #size-cells = <0>; + +- cpu0: cpu@0 { ++ cpu-map { ++ cluster0 { ++ core0 { ++ cpu = <&cpu_e0>; ++ }; ++ core1 { ++ cpu = <&cpu_e1>; ++ }; ++ core2 { ++ cpu = <&cpu_e2>; ++ }; ++ core3 { ++ cpu = <&cpu_e3>; ++ }; ++ }; ++ ++ cluster1 { ++ core0 { ++ cpu = <&cpu_p0>; ++ }; ++ core1 { ++ cpu = <&cpu_p1>; ++ }; ++ core2 { ++ cpu = <&cpu_p2>; ++ }; ++ core3 { ++ cpu = <&cpu_p3>; ++ }; ++ }; ++ }; ++ ++ cpu_e0: cpu@0 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + +- cpu1: cpu@1 { ++ cpu_e1: cpu@1 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + +- cpu2: cpu@2 { ++ cpu_e2: cpu@2 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + +- cpu3: cpu@3 { ++ cpu_e3: cpu@3 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + +- cpu4: cpu@10100 { ++ cpu_p0: cpu@10100 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + +- cpu5: cpu@10101 { ++ cpu_p1: cpu@10101 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + +- cpu6: cpu@10102 { ++ cpu_p2: cpu@10102 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10102>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + +- cpu7: cpu@10103 { ++ cpu_p3: cpu@10103 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10103>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; ++ }; ++ }; ++ ++ ecluster_opp: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <7500>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <972000000>; ++ opp-level = <2>; ++ clock-latency-ns = <22000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <1332000000>; ++ opp-level = <3>; ++ clock-latency-ns = <27000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-level = <4>; ++ clock-latency-ns = <33000>; ++ }; ++ opp05 { ++ opp-hz = /bits/ 64 <2064000000>; ++ opp-level = <5>; ++ clock-latency-ns = <50000>; + }; + }; + ++ pcluster_opp: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <8000>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <828000000>; ++ opp-level = <2>; ++ clock-latency-ns = <19000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <1056000000>; ++ opp-level = <3>; ++ clock-latency-ns = <21000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <1284000000>; ++ opp-level = <4>; ++ clock-latency-ns = <23000>; ++ }; ++ opp05 { ++ opp-hz = /bits/ 64 <1500000000>; ++ opp-level = <5>; ++ clock-latency-ns = <24000>; ++ }; ++ opp06 { ++ opp-hz = /bits/ 64 <1728000000>; ++ opp-level = <6>; ++ clock-latency-ns = <29000>; ++ }; ++ opp07 { ++ opp-hz = /bits/ 64 <1956000000>; ++ opp-level = <7>; ++ clock-latency-ns = <31000>; ++ }; ++ opp08 { ++ opp-hz = /bits/ 64 <2184000000>; ++ opp-level = <8>; ++ clock-latency-ns = <34000>; ++ }; ++ opp09 { ++ opp-hz = /bits/ 64 <2388000000>; ++ opp-level = <9>; ++ clock-latency-ns = <36000>; ++ }; ++ opp10 { ++ opp-hz = /bits/ 64 <2592000000>; ++ opp-level = <10>; ++ clock-latency-ns = <51000>; ++ }; ++ opp11 { ++ opp-hz = /bits/ 64 <2772000000>; ++ opp-level = <11>; ++ clock-latency-ns = <54000>; ++ }; ++ opp12 { ++ opp-hz = /bits/ 64 <2988000000>; ++ opp-level = <12>; ++ clock-latency-ns = <55000>; ++ }; ++#if 0 ++ /* Not available until CPU deep sleep is implemented */ ++ opp13 { ++ opp-hz = /bits/ 64 <3096000000>; ++ opp-level = <13>; ++ clock-latency-ns = <55000>; ++ turbo-mode; ++ }; ++ opp14 { ++ opp-hz = /bits/ 64 <3144000000>; ++ opp-level = <14>; ++ clock-latency-ns = <56000>; ++ turbo-mode; ++ }; ++ opp15 { ++ opp-hz = /bits/ 64 <3204000000>; ++ opp-level = <15>; ++ clock-latency-ns = <56000>; ++ turbo-mode; ++ }; ++#endif ++ }; ++ + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; +@@ -124,6 +298,15 @@ soc { + ranges; + nonposted-mmio; + ++ cpufreq_hw: cpufreq@210e20000 { ++ compatible = "apple,t8103-soc-cpufreq", "apple,soc-cpufreq"; ++ reg = <0x2 0x10e20000 0 0x1000>, ++ <0x2 0x11e20000 0 0x1000>; ++ reg-names = "cluster0", "cluster1"; ++ ++ #freq-domain-cells = <1>; ++ }; ++ + i2c0: i2c@235010000 { + compatible = "apple,t8103-i2c", "apple,i2c"; + reg = <0x2 0x35010000 0x0 0x4000>; +@@ -229,12 +412,12 @@ aic: interrupt-controller@23b100000 { + affinities { + e-core-pmu-affinity { + apple,fiq-index = ; +- cpus = <&cpu0 &cpu1 &cpu2 &cpu3>; ++ cpus = <&cpu_e0 &cpu_e1 &cpu_e2 &cpu_e3>; + }; + + p-core-pmu-affinity { + apple,fiq-index = ; +- cpus = <&cpu4 &cpu5 &cpu6 &cpu7>; ++ cpus = <&cpu_p0 &cpu_p1 &cpu_p2 &cpu_p3>; + }; + }; + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0002-arm64-dts-apple-t8103-Add-ANS2-nodes.patch b/target/linux/silicon/patches-5.19/0002-arm64-dts-apple-t8103-Add-ANS2-nodes.patch new file mode 100644 index 000000000..d2930c20a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0002-arm64-dts-apple-t8103-Add-ANS2-nodes.patch @@ -0,0 +1,56 @@ +From a994e9c9c1e45fbffeb9844c182e27c58c208404 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Thu, 9 Dec 2021 17:22:51 +0100 +Subject: [PATCH 002/171] arm64: dts: apple: t8103: Add ANS2 nodes + +--- + arch/arm64/boot/dts/apple/t8103.dtsi | 33 ++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index 3df126a5a7dd..66544e39a20a 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -561,6 +561,39 @@ pinctrl_aop: pinctrl@24a820000 { + ; + }; + ++ ans_mbox: mbox@277408000 { ++ compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; ++ reg = <0x2 0x77408000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "send-empty", "send-not-empty", ++ "recv-empty", "recv-not-empty"; ++ #mbox-cells = <0>; ++ power-domains = <&ps_ans2>; ++ }; ++ ++ sart: sart@27bc50000 { ++ compatible = "apple,t8103-sart", "apple,sart2"; ++ reg = <0x2 0x7bc50000 0x0 0x10000>; ++ power-domains = <&ps_ans2>; ++ }; ++ ++ nvme@27bcc0000 { ++ compatible = "apple,t8103-nvme-ans2", "apple,nvme-ans2"; ++ reg = <0x2 0x7bcc0000 0x0 0x40000>, ++ <0x2 0x77400000 0x0 0x4000>; ++ reg-names = "nvme", "ans"; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ mboxes = <&ans_mbox>; ++ apple,sart = <&sart>; ++ power-domains = <&ps_ans2>; ++ resets = <&ps_ans2>; ++ }; ++ + pcie0_dart_0: dart@681008000 { + compatible = "apple,t8103-dart"; + reg = <0x6 0x81008000 0x0 0x4000>; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0003-arm64-dts-apple-t8103-Add-dwc3-nodes.patch b/target/linux/silicon/patches-5.19/0003-arm64-dts-apple-t8103-Add-dwc3-nodes.patch new file mode 100644 index 000000000..8f0b65ae1 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0003-arm64-dts-apple-t8103-Add-dwc3-nodes.patch @@ -0,0 +1,274 @@ +From ba2a0e6cfe463e97ee1056dd45d7fd4eee24bf09 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 26 Nov 2021 15:37:23 +0900 +Subject: [PATCH 003/171] arm64: dts: apple: t8103: Add dwc3 nodes + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-j274.dts | 12 +++++ + arch/arm64/boot/dts/apple/t8103-j293.dts | 12 +++++ + arch/arm64/boot/dts/apple/t8103-j313.dts | 12 +++++ + arch/arm64/boot/dts/apple/t8103-j456.dts | 12 +++++ + arch/arm64/boot/dts/apple/t8103-j457.dts | 12 +++++ + arch/arm64/boot/dts/apple/t8103-jxxx.dtsi | 51 +++++++++++++++++++ + arch/arm64/boot/dts/apple/t8103.dtsi | 60 +++++++++++++++++++++++ + 7 files changed, 171 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts +index 2cd429efba5b..214476814797 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j274.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j274.dts +@@ -21,6 +21,18 @@ aliases { + }; + }; + ++/* ++ * Provide labels for the USB type C ports. ++ */ ++ ++&typec0 { ++ label = "USB-C Back-left"; ++}; ++ ++&typec1 { ++ label = "USB-C Back-right"; ++}; ++ + /* + * Force the bus number assignments so that we can declare some of the + * on-board devices and properties that are populated by the bootloader +diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts +index 49cdf4b560a3..6f08fd64f482 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j293.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j293.dts +@@ -17,6 +17,18 @@ / { + model = "Apple MacBook Pro (13-inch, M1, 2020)"; + }; + ++/* ++ * Provide labels for the USB type C ports. ++ */ ++ ++&typec0 { ++ label = "USB-C Left-back"; ++}; ++ ++&typec1 { ++ label = "USB-C Left-front"; ++}; ++ + /* + * Remove unused PCIe ports and disable the associated DARTs. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts +index b0ebb45bdb6f..114aa87c8cb4 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j313.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j313.dts +@@ -17,6 +17,18 @@ / { + model = "Apple MacBook Air (M1, 2020)"; + }; + ++/* ++ * Provide labels for the USB type C ports. ++ */ ++ ++&typec0 { ++ label = "USB-C Left-back"; ++}; ++ ++&typec1 { ++ label = "USB-C Left-front"; ++}; ++ + /* + * Remove unused PCIe ports and disable the associated DARTs. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts +index 884fddf7d363..9814c97cd9ba 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j456.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j456.dts +@@ -39,6 +39,18 @@ hpm3: usb-pd@3c { + }; + }; + ++/* ++ * Provide labels for the USB type C ports. ++ */ ++ ++&typec0 { ++ label = "USB-C Back-right"; ++}; ++ ++&typec1 { ++ label = "USB-C Back-right-middle"; ++}; ++ + /* + * Force the bus number assignments so that we can declare some of the + * on-board devices and properties that are populated by the bootloader +diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts +index d7c622931627..0f4cc643741c 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j457.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j457.dts +@@ -21,6 +21,18 @@ aliases { + }; + }; + ++/* ++ * Provide labels for the USB type C ports. ++ */ ++ ++&typec0 { ++ label = "USB-C Back-right"; ++}; ++ ++&typec1 { ++ label = "USB-C Back-left"; ++}; ++ + /* + * Force the bus number assignments so that we can declare some of the + * on-board devices and properties that are populated by the bootloader +diff --git a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +index fe2ae40fa9dd..020a9d8b31e9 100644 +--- a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +@@ -52,6 +52,23 @@ hpm0: usb-pd@38 { + interrupt-parent = <&pinctrl_ap>; + interrupts = <106 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec0: connector { ++ compatible = "usb-c-connector"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec0_con_hs: endpoint { ++ remote-endpoint = <&typec0_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm1: usb-pd@3f { +@@ -60,6 +77,40 @@ hpm1: usb-pd@3f { + interrupt-parent = <&pinctrl_ap>; + interrupts = <106 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec1: connector { ++ compatible = "usb-c-connector"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec1_con_hs: endpoint { ++ remote-endpoint = <&typec1_usb_hs>; ++ }; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++/* USB controllers */ ++&dwc3_0 { ++ port { ++ typec0_usb_hs: endpoint { ++ remote-endpoint = <&typec0_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_1 { ++ port { ++ typec1_usb_hs: endpoint { ++ remote-endpoint = <&typec1_con_hs>; ++ }; + }; + }; + +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index 66544e39a20a..ec7234cdc861 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -594,6 +594,66 @@ nvme@27bcc0000 { + resets = <&ps_ans2>; + }; + ++ dwc3_0: usb@382280000 { ++ compatible = "apple,t8103-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0x3 0x82280000 0x0 0x100000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ dr_mode = "otg"; ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ iommus = <&dwc3_0_dart_0 0>, <&dwc3_0_dart_1 1>; ++ power-domains = <&ps_atc0_usb>; ++ }; ++ ++ dwc3_0_dart_0: iommu@382f00000 { ++ compatible = "apple,t8103-dart"; ++ reg = <0x3 0x82f00000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_atc0_usb>; ++ }; ++ ++ dwc3_0_dart_1: iommu@382f80000 { ++ compatible = "apple,t8103-dart"; ++ reg = <0x3 0x82f80000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_atc0_usb>; ++ }; ++ ++ dwc3_1: usb@502280000 { ++ compatible = "apple,t8103-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0x5 0x02280000 0x0 0x100000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ dr_mode = "otg"; ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ iommus = <&dwc3_1_dart_0 0>, <&dwc3_1_dart_1 1>; ++ power-domains = <&ps_atc1_usb>; ++ }; ++ ++ dwc3_1_dart_0: iommu@502f00000 { ++ compatible = "apple,t8103-dart"; ++ reg = <0x5 0x02f00000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_atc1_usb>; ++ }; ++ ++ dwc3_1_dart_1: iommu@502f80000 { ++ compatible = "apple,t8103-dart"; ++ reg = <0x5 0x02f80000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_atc1_usb>; ++ }; ++ + pcie0_dart_0: dart@681008000 { + compatible = "apple,t8103-dart"; + reg = <0x6 0x81008000 0x0 0x4000>; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0004-arm64-dts-apple-t8103-Add-spi3-keyboard-nodes.patch b/target/linux/silicon/patches-5.19/0004-arm64-dts-apple-t8103-Add-spi3-keyboard-nodes.patch new file mode 100644 index 000000000..13513d6bc --- /dev/null +++ b/target/linux/silicon/patches-5.19/0004-arm64-dts-apple-t8103-Add-spi3-keyboard-nodes.patch @@ -0,0 +1,133 @@ +From 226311814eda36c1ad693189e5402ced55e91f11 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Fri, 26 Nov 2021 00:24:15 +0100 +Subject: [PATCH 004/171] arm64: dts: apple: t8103: Add spi3/keyboard nodes + +Enables keyboard and touchpad input on MacBook Air (M1, 2020) and +MacBook Pro (13-inch, M1, 2020). + +Signed-off-by: Janne Grunau +--- + arch/arm64/boot/dts/apple/t8103-j293.dts | 20 +++++++++++++++++ + arch/arm64/boot/dts/apple/t8103-j313.dts | 20 +++++++++++++++++ + arch/arm64/boot/dts/apple/t8103.dtsi | 28 ++++++++++++++++++++++++ + 3 files changed, 68 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts +index 6f08fd64f482..9405e97a85f2 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j293.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j293.dts +@@ -29,6 +29,26 @@ &typec1 { + label = "USB-C Left-front"; + }; + ++&spi3 { ++ status = "okay"; ++ ++ hid-transport@0 { ++ compatible = "apple,spi-hid-transport"; ++ reg = <0>; ++ spi-max-frequency = <8000000>; ++ /* ++ * cs-setup and cs-hold delays are derived from Apple's ADT ++ * Mac OS driver meta data secify 45 us for 'cs to clock' and ++ * 'clock to cs' delays. ++ */ ++ spi-cs-setup-delay-ns = <20000>; ++ spi-cs-hold-delay-ns = <20000>; ++ spi-cs-inactive-delay-ns = <250000>; ++ spien-gpios = <&pinctrl_ap 195 0>; ++ interrupts-extended = <&pinctrl_nub 13 IRQ_TYPE_LEVEL_LOW>; ++ }; ++}; ++ + /* + * Remove unused PCIe ports and disable the associated DARTs. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts +index 114aa87c8cb4..bc84f8af0b1d 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j313.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j313.dts +@@ -29,6 +29,26 @@ &typec1 { + label = "USB-C Left-front"; + }; + ++&spi3 { ++ status = "okay"; ++ ++ hid-transport@0 { ++ compatible = "apple,spi-hid-transport"; ++ reg = <0>; ++ spi-max-frequency = <8000000>; ++ /* ++ * cs-setup and cs-hold delays are derived from Apple's ADT ++ * Mac OS driver meta data secify 45 us for 'cs to clock' and ++ * 'clock to cs' delays. ++ */ ++ spi-cs-setup-delay-ns = <20000>; ++ spi-cs-hold-delay-ns = <20000>; ++ spi-cs-inactive-delay-ns = <250000>; ++ spien-gpios = <&pinctrl_ap 195 0>; ++ interrupts-extended = <&pinctrl_nub 13 IRQ_TYPE_LEVEL_LOW>; ++ }; ++}; ++ + /* + * Remove unused PCIe ports and disable the associated DARTs. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index ec7234cdc861..9750438c30dd 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -290,6 +290,13 @@ clkref: clock-ref { + clock-output-names = "clkref"; + }; + ++ clk_120m: clock-120m { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <120000000>; ++ clock-output-names = "clk_120m"; ++ }; ++ + soc { + compatible = "simple-bus"; + #address-cells = <2>; +@@ -374,6 +381,20 @@ i2c4: i2c@235020000 { + status = "disabled"; /* only used in J293 */ + }; + ++ spi3: spi@23510c000 { ++ compatible = "apple,t8103-spi", "apple,spi"; ++ reg = <0x2 0x3510c000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ clocks = <&clk_120m>; ++ pinctrl-0 = <&spi3_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_spi3>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; /* only used in J293/J313 */ ++ }; ++ + serial0: serial@235200000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x35200000 0x0 0x1000>; +@@ -475,6 +496,13 @@ i2c4_pins: i2c4-pins { + ; + }; + ++ spi3_pins: spi3-pins { ++ pinmux = , ++ , ++ , ++ ; ++ }; ++ + pcie_pins: pcie-pins { + pinmux = , + , +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0005-arm64-dts-apple-Fix-j45x-model-years.patch b/target/linux/silicon/patches-5.19/0005-arm64-dts-apple-Fix-j45x-model-years.patch new file mode 100644 index 000000000..0f4a19625 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0005-arm64-dts-apple-Fix-j45x-model-years.patch @@ -0,0 +1,40 @@ +From d1cc45edca0943c77a7125cb9de0300329314169 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 19 Mar 2022 05:50:47 +0900 +Subject: [PATCH 005/171] arm64: dts: apple: Fix j45x model years + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-j456.dts | 2 +- + arch/arm64/boot/dts/apple/t8103-j457.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts +index 9814c97cd9ba..bb48255250c7 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j456.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j456.dts +@@ -14,7 +14,7 @@ + + / { + compatible = "apple,j456", "apple,t8103", "apple,arm-platform"; +- model = "Apple iMac (24-inch, 4x USB-C, M1, 2020)"; ++ model = "Apple iMac (24-inch, 4x USB-C, M1, 2021)"; + + aliases { + ethernet0 = ðernet0; +diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts +index 0f4cc643741c..80600c3fa769 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j457.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j457.dts +@@ -14,7 +14,7 @@ + + / { + compatible = "apple,j457", "apple,t8103", "apple,arm-platform"; +- model = "Apple iMac (24-inch, 2x USB-C, M1, 2020)"; ++ model = "Apple iMac (24-inch, 2x USB-C, M1, 2021)"; + + aliases { + ethernet0 = ðernet0; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0006-arm64-dts-apple-Add-WiFi-module-and-antenna-properti.patch b/target/linux/silicon/patches-5.19/0006-arm64-dts-apple-Add-WiFi-module-and-antenna-properti.patch new file mode 100644 index 000000000..fb5a1ce83 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0006-arm64-dts-apple-Add-WiFi-module-and-antenna-properti.patch @@ -0,0 +1,112 @@ +From 30c1cffd27d0154787eba4a4a2e9c6a3e7504879 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:07:17 +0900 +Subject: [PATCH 006/171] arm64: dts: apple: Add WiFi module and antenna + properties + +Add the new module-instance/antenna-sku properties required to select +WiFi firmwares properly to all board device trees. + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-j274.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-j293.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-j313.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-j456.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-j457.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-jxxx.dtsi | 2 ++ + 6 files changed, 22 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts +index 214476814797..aaa3019a4db2 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j274.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j274.dts +@@ -21,6 +21,10 @@ aliases { + }; + }; + ++&wifi0 { ++ brcm,board-type = "apple,atlantisb"; ++}; ++ + /* + * Provide labels for the USB type C ports. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts +index 9405e97a85f2..4f5f7d38e799 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j293.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j293.dts +@@ -17,6 +17,10 @@ / { + model = "Apple MacBook Pro (13-inch, M1, 2020)"; + }; + ++&wifi0 { ++ brcm,board-type = "apple,honshu"; ++}; ++ + /* + * Provide labels for the USB type C ports. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts +index bc84f8af0b1d..d6722d8809d1 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j313.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j313.dts +@@ -17,6 +17,10 @@ / { + model = "Apple MacBook Air (M1, 2020)"; + }; + ++&wifi0 { ++ brcm,board-type = "apple,shikoku"; ++}; ++ + /* + * Provide labels for the USB type C ports. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts +index bb48255250c7..3d0a91ac29ae 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j456.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j456.dts +@@ -21,6 +21,10 @@ aliases { + }; + }; + ++&wifi0 { ++ brcm,board-type = "apple,capri"; ++}; ++ + &i2c0 { + hpm2: usb-pd@3b { + compatible = "apple,cd321x"; +diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts +index 80600c3fa769..7e3a0e95e837 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j457.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j457.dts +@@ -21,6 +21,10 @@ aliases { + }; + }; + ++&wifi0 { ++ brcm,board-type = "apple,santorini"; ++}; ++ + /* + * Provide labels for the USB type C ports. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +index 020a9d8b31e9..4fb89066bd17 100644 +--- a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +@@ -122,8 +122,10 @@ typec1_usb_hs: endpoint { + &port00 { + bus-range = <1 1>; + wifi0: network@0,0 { ++ compatible = "pci14e4,4425"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + /* To be filled by the loader */ + local-mac-address = [00 00 00 00 00 00]; ++ apple,antenna-sku = "XX"; + }; + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0007-arm64-dts-apple-Add-PCI-power-enable-GPIOs.patch b/target/linux/silicon/patches-5.19/0007-arm64-dts-apple-Add-PCI-power-enable-GPIOs.patch new file mode 100644 index 000000000..d45d6df8c --- /dev/null +++ b/target/linux/silicon/patches-5.19/0007-arm64-dts-apple-Add-PCI-power-enable-GPIOs.patch @@ -0,0 +1,31 @@ +From 8d2ddaeace21e3960326fb52a052083b5a1f5e1d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 6 Feb 2022 21:22:29 +0900 +Subject: [PATCH 007/171] arm64: dts: apple: Add PCI power enable GPIOs + +t8103: +- WLAN (SMC PMU GPIO #13) +t600x: +- WLAN (SMC PMU GPIO #13) +- SD (SMC PMU GPIO #26) + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-jxxx.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +index 4fb89066bd17..e62664b6e450 100644 +--- a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +@@ -121,6 +121,7 @@ typec1_usb_hs: endpoint { + */ + &port00 { + bus-range = <1 1>; ++ pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; + wifi0: network@0,0 { + compatible = "pci14e4,4425"; + reg = <0x10000 0x0 0x0 0x0 0x0>; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0008-arm64-dts-apple-Add-SMC-node-to-t8103-t6001-devicetr.patch b/target/linux/silicon/patches-5.19/0008-arm64-dts-apple-Add-SMC-node-to-t8103-t6001-devicetr.patch new file mode 100644 index 000000000..3e45d123a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0008-arm64-dts-apple-Add-SMC-node-to-t8103-t6001-devicetr.patch @@ -0,0 +1,51 @@ +From 6728598e7a5a5fb2cb05c65294269b6844b1ea5d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 4 Feb 2022 12:59:39 +0900 +Subject: [PATCH 008/171] arm64: dts: apple: Add SMC node to t8103/t6001 + devicetrees + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103.dtsi | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index 9750438c30dd..23cc325a49bb 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -547,6 +547,32 @@ wdt: watchdog@23d2b0000 { + interrupts = ; + }; + ++ smc_mbox: mbox@23e408000 { ++ compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; ++ reg = <0x2 0x3e408000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "send-empty", "send-not-empty", ++ "recv-empty", "recv-not-empty"; ++ #mbox-cells = <0>; ++ }; ++ ++ smc: smc@23e400000 { ++ compatible = "apple,t8103-smc", "apple,smc"; ++ reg = <0x2 0x3e400000 0x0 0x4000>, ++ <0x2 0x3fe00000 0x0 0x100000>; ++ reg-names = "smc", "sram"; ++ mboxes = <&smc_mbox>; ++ ++ smc_gpio: gpio { ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ + pinctrl_smc: pinctrl@23e820000 { + compatible = "apple,t8103-pinctrl", "apple,pinctrl"; + reg = <0x2 0x3e820000 0x0 0x4000>; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0009-arm64-dts-apple-Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch b/target/linux/silicon/patches-5.19/0009-arm64-dts-apple-Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch new file mode 100644 index 000000000..c104beacf --- /dev/null +++ b/target/linux/silicon/patches-5.19/0009-arm64-dts-apple-Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch @@ -0,0 +1,127 @@ +From aee7c563697559e06f306d8a9e1b5a33c5c330d9 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 18:54:35 +0900 +Subject: [PATCH 009/171] arm64: dts: apple: Add PMU NVMEM and SMC RTC/reboot + nodes + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103.dtsi | 88 ++++++++++++++++++++++++++++ + 1 file changed, 88 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index 23cc325a49bb..c2fb4f32590c 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + / { + compatible = "apple,t8103", "apple,arm-platform"; +@@ -510,6 +511,81 @@ pcie_pins: pcie-pins { + }; + }; + ++ nub_spmi: spmi@23d0d9300 { ++ compatible = "apple,t8103-spmi", "apple,spmi"; ++ reg = <0x2 0x3d0d9300 0x0 0x100>; ++ #address-cells = <2>; ++ #size-cells = <0>; ++ ++ pmu1: pmu@f { ++ compatible = "apple,sera-pmu", "apple,spmi-pmu"; ++ reg = <0xf SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ rtc_nvmem@d000 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0xd000 0x300>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ pm_setting: pm-setting@1 { ++ reg = <0x1 0x1>; ++ }; ++ ++ rtc_offset: rtc-offset@100 { ++ reg = <0x100 0x6>; ++ }; ++ }; ++ ++ legacy_nvmem@9f00 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0x9f00 0x20>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ boot_stage: boot-stage@1 { ++ reg = <0x1 0x1>; ++ }; ++ ++ boot_error_count: boot-error-count@2 { ++ reg = <0x2 0x1>; ++ bits = <0 4>; ++ }; ++ ++ panic_count: panic-count@2 { ++ reg = <0x2 0x1>; ++ bits = <4 4>; ++ }; ++ ++ boot_error_stage: boot-error-stage@3 { ++ reg = <0x3 0x1>; ++ }; ++ ++ shutdown_flag: shutdown-flag@f { ++ reg = <0xf 0x1>; ++ bits = <3 1>; ++ }; ++ }; ++ ++ scrpad_nvmem@a000 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0xa000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ fault_shadow: fault-shadow@67b { ++ reg = <0x67b 0x10>; ++ }; ++ ++ socd: socd@b00 { ++ reg = <0xb00 0x400>; ++ }; ++ }; ++ ++ }; ++ }; ++ + pinctrl_nub: pinctrl@23d1f0000 { + compatible = "apple,t8103-pinctrl", "apple,pinctrl"; + reg = <0x2 0x3d1f0000 0x0 0x4000>; +@@ -571,6 +647,18 @@ smc_gpio: gpio { + gpio-controller; + #gpio-cells = <2>; + }; ++ ++ smc_rtc: rtc { ++ nvmem-cells = <&rtc_offset>; ++ nvmem-cell-names = "rtc_offset"; ++ }; ++ ++ smc_reboot: reboot { ++ nvmem-cells = <&shutdown_flag>, <&boot_stage>, ++ <&boot_error_count>, <&panic_count>, <&pm_setting>; ++ nvmem-cell-names = "shutdown_flag", "boot_stage", ++ "boot_error_count", "panic_count", "pm_setting"; ++ }; + }; + + pinctrl_smc: pinctrl@23e820000 { +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0010-arm64-dts-apple-Re-parent-ANS2-power-domains.patch b/target/linux/silicon/patches-5.19/0010-arm64-dts-apple-Re-parent-ANS2-power-domains.patch new file mode 100644 index 000000000..48855df5d --- /dev/null +++ b/target/linux/silicon/patches-5.19/0010-arm64-dts-apple-Re-parent-ANS2-power-domains.patch @@ -0,0 +1,56 @@ +From ed05baab200d58bdc024e7797780a1d95677dce3 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Wed, 2 Mar 2022 23:23:51 +0900 +Subject: [PATCH 010/171] arm64: dts: apple: Re-parent ANS2 power domains + +Turns out that the APCIE_ST*_SYS domains do hard-depend on ANS2, so +without this they refuse to power up. + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 7 +------ + arch/arm64/boot/dts/apple/t8103.dtsi | 3 ++- + 2 files changed, 3 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +index fc51bc872468..a6dbb1f485d8 100644 +--- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +@@ -725,11 +725,6 @@ ps_ans2: power-controller@3f0 { + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ans2"; +- /* +- * The ADT makes ps_apcie_st depend on ps_ans2 instead, but this +- * doesn't make much sense since ANS2 uses APCIE_ST. +- */ +- power-domains = <&ps_apcie_st>; + }; + + ps_gfx: power-controller@3f8 { +@@ -836,7 +831,7 @@ ps_apcie_st: power-controller@418 { + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "apcie_st"; +- power-domains = <&ps_apcie>; ++ power-domains = <&ps_apcie>, <&ps_ans2>; + }; + + ps_ane_sys: power-controller@470 { +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index c2fb4f32590c..f96a732e6211 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -732,7 +732,8 @@ nvme@27bcc0000 { + interrupts = ; + mboxes = <&ans_mbox>; + apple,sart = <&sart>; +- power-domains = <&ps_ans2>; ++ power-domains = <&ps_ans2>, <&ps_apcie_st>; ++ power-domain-names = "ans", "apcie0"; + resets = <&ps_ans2>; + }; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0011-arm64-dts-apple-Mark-ATC-USB-AON-domains-as-always-o.patch b/target/linux/silicon/patches-5.19/0011-arm64-dts-apple-Mark-ATC-USB-AON-domains-as-always-o.patch new file mode 100644 index 000000000..7fa12f92f --- /dev/null +++ b/target/linux/silicon/patches-5.19/0011-arm64-dts-apple-Mark-ATC-USB-AON-domains-as-always-o.patch @@ -0,0 +1,39 @@ +From b348548945561245a2aea95ef9a9b5afe1efa78c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 3 Mar 2022 02:20:39 +0900 +Subject: [PATCH 011/171] arm64: dts: apple: Mark ATC USB AON domains as + always-on + +Shutting these down breaks dwc3 init done by the firmware. We probably +never want to do this anyway. It might be possible remove this once +a PHY driver is in place to do the init properly, but it may not be +worth it. + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +index a6dbb1f485d8..926b1e54b64b 100644 +--- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +@@ -1103,6 +1103,7 @@ ps_atc0_usb_aon: power-controller@88 { + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc0_usb_aon"; ++ apple,always-on; /* Needs to stay on for dwc3 to work */ + }; + + ps_atc1_usb_aon: power-controller@90 { +@@ -1111,6 +1112,7 @@ ps_atc1_usb_aon: power-controller@90 { + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc1_usb_aon"; ++ apple,always-on; /* Needs to stay on for dwc3 to work */ + }; + + ps_atc0_usb: power-controller@98 { +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0012-arm64-dts-apple-Add-backlight-node-to-j293-j313.patch b/target/linux/silicon/patches-5.19/0012-arm64-dts-apple-Add-backlight-node-to-j293-j313.patch new file mode 100644 index 000000000..4408019ff --- /dev/null +++ b/target/linux/silicon/patches-5.19/0012-arm64-dts-apple-Add-backlight-node-to-j293-j313.patch @@ -0,0 +1,64 @@ +From 470d9385f7c772c4cb88e0fdfa3484baba9d15c9 Mon Sep 17 00:00:00 2001 +From: Thomas Glanzmann +Date: Mon, 21 Feb 2022 23:01:36 +0100 +Subject: [PATCH 012/171] arm64: dts: apple: Add backlight node to j293/j313 + +It can be turned off with: + +echo 1 > /sys/class/backlight/backlight/bl_power + +It can be turned on with: + +echo 0 > /sys/class/backlight/backlight/bl_power + +Needs CONFIG_BACKLIGHT_GPIO=m. + +Signed-off-by: Thomas Glanzmann +--- + arch/arm64/boot/dts/apple/t8103-j293.dts | 12 ++++++++++++ + arch/arm64/boot/dts/apple/t8103-j313.dts | 12 ++++++++++++ + 2 files changed, 24 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts +index 4f5f7d38e799..6f1050185a80 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j293.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j293.dts +@@ -75,3 +75,15 @@ &i2c2 { + &i2c4 { + status = "okay"; + }; ++ ++/ { ++ backlight: gpio-bl { ++ compatible = "gpio-backlight"; ++ gpios = <&smc_gpio 18 GPIO_ACTIVE_HIGH>; ++ default-on; ++ }; ++}; ++ ++&framebuffer0 { ++ backlight = <&backlight>; ++}; +diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts +index d6722d8809d1..3e4045c05905 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j313.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j313.dts +@@ -67,3 +67,15 @@ &pcie0_dart_2 { + + /delete-node/ &port01; + /delete-node/ &port02; ++ ++/ { ++ backlight: gpio-bl { ++ compatible = "gpio-backlight"; ++ gpios = <&smc_gpio 18 GPIO_ACTIVE_HIGH>; ++ default-on; ++ }; ++}; ++ ++&framebuffer0 { ++ backlight = <&backlight>; ++}; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0013-arm64-dts-apple-t8103-Put-in-audio-nodes.patch b/target/linux/silicon/patches-5.19/0013-arm64-dts-apple-t8103-Put-in-audio-nodes.patch new file mode 100644 index 000000000..c8a0e4a1c --- /dev/null +++ b/target/linux/silicon/patches-5.19/0013-arm64-dts-apple-t8103-Put-in-audio-nodes.patch @@ -0,0 +1,438 @@ +From 3af244a2705f3894814a305428501a614c26fb7a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 09:49:59 +0100 +Subject: [PATCH 013/171] arm64: dts: apple: t8103*: Put in audio nodes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Martin PoviÅ¡er +--- + arch/arm64/boot/dts/apple/t8103-j274.dts | 52 +++++++++++++++ + arch/arm64/boot/dts/apple/t8103-j293.dts | 85 ++++++++++++++++++++++++ + arch/arm64/boot/dts/apple/t8103-j313.dts | 61 +++++++++++++++++ + arch/arm64/boot/dts/apple/t8103-j456.dts | 31 +++++++++ + arch/arm64/boot/dts/apple/t8103-j457.dts | 40 +++++++++++ + arch/arm64/boot/dts/apple/t8103.dtsi | 73 ++++++++++++++++++++ + 6 files changed, 342 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts +index aaa3019a4db2..811008bd73f3 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j274.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j274.dts +@@ -56,6 +56,58 @@ ethernet0: ethernet@0,0 { + }; + }; + ++&i2c1 { ++ speaker_amp: codec@31 { ++ compatible = "ti,tas5770l", "ti,tas2770"; ++ reg = <0x31>; ++ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ }; ++}; ++ + &i2c2 { + status = "okay"; ++ ++ jack_codec: codec@48 { ++ compatible = "cirrus,cs42l83", "cirrus,cs42l42"; ++ reg = <0x48>; ++ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <183 IRQ_TYPE_LEVEL_LOW>; ++ #sound-dai-cells = <0>; ++ cirrus,ts-inv = <1>; ++ sound-name-prefix = "Jack"; ++ }; ++}; ++ ++/ { ++ sound { ++ compatible = "apple,j274-macaudio", "apple,macaudio"; ++ model = "Mac mini J274 integrated audio"; ++ ++ dai-link@0 { ++ link-name = "Speaker"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 0>; ++ }; ++ codec { ++ sound-dai = <&speaker_amp>; ++ }; ++ }; ++ ++ dai-link@1 { ++ link-name = "Headphone Jack"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 2>; ++ }; ++ codec { ++ sound-dai = <&jack_codec>; ++ }; ++ }; ++ ++ }; + }; +diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts +index 6f1050185a80..7eb98e6b947c 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j293.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j293.dts +@@ -68,8 +68,54 @@ &pcie0_dart_2 { + /delete-node/ &port01; + /delete-node/ &port02; + ++&i2c1 { ++ speaker_left_rear: codec@31 { ++ compatible = "ti,tas5770l", "ti,tas2770"; ++ reg = <0x31>; ++ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Rear"; ++ }; ++ ++ speaker_left_front: codec@32 { ++ compatible = "ti,tas5770l", "ti,tas2770"; ++ reg = <0x32>; ++ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Front"; ++ }; ++}; ++ + &i2c2 { + status = "okay"; ++ ++ jack_codec: codec@48 { ++ compatible = "cirrus,cs42l83", "cirrus,cs42l42"; ++ reg = <0x48>; ++ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <183 IRQ_TYPE_LEVEL_LOW>; ++ #sound-dai-cells = <0>; ++ cirrus,ts-inv = <1>; ++ }; ++}; ++ ++&i2c3 { ++ speaker_right_rear: codec@34 { ++ compatible = "ti,tas5770l", "ti,tas2770"; ++ reg = <0x34>; ++ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Rear"; ++ }; ++ ++ speaker_right_front: codec@35 { ++ compatible = "ti,tas5770l", "ti,tas2770"; ++ reg = <0x35>; ++ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Front"; ++ }; + }; + + &i2c4 { +@@ -82,6 +128,45 @@ backlight: gpio-bl { + gpios = <&smc_gpio 18 GPIO_ACTIVE_HIGH>; + default-on; + }; ++ ++ sound { ++ compatible = "apple,j293-macaudio", "apple,macaudio"; ++ model = "MacBook Pro J293 integrated audio"; ++ ++ dai-link@0 { ++ /* ++ * DANGER ZONE: You can blow your speakers! ++ * ++ * The drivers are not ready, and unless you are careful ++ * to attenuate the audio stream, you run the risk of ++ * blowing your speakers. ++ */ ++ status = "disabled"; ++ ++ link-name = "Speakers"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 0>, <&mca 1>; ++ }; ++ codec { ++ sound-dai = <&speaker_left_front>, <&speaker_right_front>, ++ <&speaker_left_rear>, <&speaker_right_rear>; ++ }; ++ }; ++ ++ dai-link@1 { ++ link-name = "Headphone Jack"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 2>; ++ }; ++ codec { ++ sound-dai = <&jack_codec>; ++ }; ++ }; ++ }; + }; + + &framebuffer0 { +diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts +index 3e4045c05905..ad3a6edeb651 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j313.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j313.dts +@@ -68,12 +68,73 @@ &pcie0_dart_2 { + /delete-node/ &port01; + /delete-node/ &port02; + ++&i2c1 { ++ speaker_left: codec@31 { ++ compatible = "ti,tas5770l", "ti,tas2770"; ++ reg = <0x31>; ++ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left"; ++ ++ }; ++}; ++ ++&i2c3 { ++ speaker_right: codec@34 { ++ compatible = "ti,tas5770l", "ti,tas2770"; ++ reg = <0x34>; ++ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right"; ++ }; ++ ++ jack_codec: codec@48 { ++ compatible = "cirrus,cs42l83", "cirrus,cs42l42"; ++ reg = <0x48>; ++ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <183 IRQ_TYPE_LEVEL_LOW>; ++ #sound-dai-cells = <0>; ++ cirrus,ts-inv = <1>; ++ sound-name-prefix = "Jack"; ++ }; ++}; ++ + / { + backlight: gpio-bl { + compatible = "gpio-backlight"; + gpios = <&smc_gpio 18 GPIO_ACTIVE_HIGH>; + default-on; + }; ++ ++ sound { ++ compatible = "apple,j313-macaudio", "apple,macaudio"; ++ model = "MacBook Air J313 integrated audio"; ++ ++ dai-link@0 { ++ link-name = "Speakers"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 0>, <&mca 1>; ++ }; ++ codec { ++ sound-dai = <&speaker_left>, <&speaker_right>; ++ }; ++ }; ++ ++ dai-link@1 { ++ link-name = "Headphone Jack"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 2>; ++ }; ++ codec { ++ sound-dai = <&jack_codec>; ++ }; ++ }; ++ }; + }; + + &framebuffer0 { +diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts +index 3d0a91ac29ae..e65053f3bd2c 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j456.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j456.dts +@@ -73,3 +73,34 @@ ethernet0: ethernet@0,0 { + local-mac-address = [00 10 18 00 00 00]; + }; + }; ++ ++&i2c1 { ++ jack_codec: codec@48 { ++ compatible = "cirrus,cs42l83", "cirrus,cs42l42"; ++ reg = <0x48>; ++ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <183 IRQ_TYPE_LEVEL_LOW>; ++ #sound-dai-cells = <0>; ++ cirrus,ts-inv = <1>; ++ }; ++}; ++ ++/ { ++ sound { ++ compatible = "apple,j456-macaudio", "apple,macaudio"; ++ model = "iMac J456 integrated audio"; ++ ++ dai-link@0 { ++ link-name = "Headphone Jack"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 2>; ++ }; ++ codec { ++ sound-dai = <&jack_codec>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts +index 7e3a0e95e837..925fe4058055 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j457.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j457.dts +@@ -61,3 +61,43 @@ &pcie0_dart_1 { + }; + + /delete-node/ &port01; ++ ++&i2c1 { ++ jack_codec: codec@48 { ++ compatible = "cirrus,cs42l83", "cirrus,cs42l42"; ++ reg = <0x48>; ++ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <183 IRQ_TYPE_LEVEL_LOW>; ++ #sound-dai-cells = <0>; ++ cirrus,ts-inv = <1>; ++ }; ++}; ++ ++/ { ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "iMac integrated audio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ simple-audio-card,dai-link@0 { ++ bitclock-inversion; ++ frame-inversion; ++ reg = <0>; ++ format = "i2s"; ++ mclk-fs = <64>; ++ tdm-slot-width = <32>; ++ ++ link0_cpu: cpu { ++ sound-dai = <&mca 2>; ++ bitclock-master; ++ frame-master; ++ }; ++ ++ link0_codec: codec { ++ sound-dai = <&jack_codec>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index f96a732e6211..afb0688cb1c2 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -917,6 +917,79 @@ port02: pci@2,0 { + <0 0 0 4 &port02 0 0 0 3>; + }; + }; ++ ++ dart_sio: iommu@235004000 { ++ compatible = "apple,t8103-dart", "apple,dart"; ++ reg = <0x2 0x35004000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_sio_cpu>; ++ }; ++ ++ nco_inp: clock-ref { ++ compatible = "fixed-factor-clock"; ++ clocks = <&clkref>; ++ #clock-cells = <0>; ++ clock-mult = <75>; ++ clock-div = <2>; // 24 MHz * (75/2) = 900 MHz ++ clock-output-names = "nco_inp"; ++ }; ++ ++ nco: nco@23b044000 { ++ compatible = "apple,t8103-nco", "apple,nco"; ++ reg = <0x2 0x3b044000 0x0 0x14000>; ++ clocks = <&nco_inp>; ++ #clock-cells = <1>; ++ apple,nchannels = <5>; ++ }; ++ ++ admac: dma-controller@238200000 { ++ compatible = "apple,t8103-admac", "apple,admac"; ++ reg = <0x2 0x38200000 0x0 0x34000>; ++ dma-channels = <24>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #dma-cells = <1>; ++ iommus = <&dart_sio 2>; ++ power-domains = <&ps_sio_adma>; ++ apple,internal-irq-destination = <1>; ++ }; ++ ++ mca: mca@38400000 { ++ compatible = "apple,t8103-mca", "apple,mca"; ++ reg = <0x2 0x38400000 0x0 0x18000>, ++ <0x2 0x38300000 0x0 0x30000>; ++ reg-names = "clusters", "switch"; ++ ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ ; ++ ++ clocks = <&nco 0>, <&nco 1>, <&nco 2>, ++ <&nco 3>, <&nco 4>, <&nco 4>; ++ power-domains = <&ps_audio_p>, <&ps_mca0>, <&ps_mca1>, ++ <&ps_mca2>, <&ps_mca3>, <&ps_mca4>, <&ps_mca5>; ++ dmas = <&admac 0>, <&admac 1>, <&admac 2>, <&admac 3>, ++ <&admac 4>, <&admac 5>, <&admac 6>, <&admac 7>, ++ <&admac 8>, <&admac 9>, <&admac 10>, <&admac 11>, ++ <&admac 12>, <&admac 13>, <&admac 14>, <&admac 15>, ++ <&admac 16>, <&admac 17>, <&admac 18>, <&admac 19>, ++ <&admac 20>, <&admac 21>, <&admac 22>, <&admac 23>; ++ dma-names = "tx0a", "rx0a", "tx0b", "rx0b", ++ "tx1a", "rx1a", "tx1b", "rx1b", ++ "tx2a", "rx2a", "tx2b", "rx2b", ++ "tx3a", "rx3a", "tx3b", "rx3b", ++ "tx4a", "rx4a", "tx4b", "rx4b", ++ "tx5a", "rx5a", "tx5b", "rx5b"; ++ ++ #sound-dai-cells = <1>; ++ apple,nclusters = <6>; ++ }; + }; + }; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0014-arm64-dts-apple-t8103-j313-Also-disable-speakers.patch b/target/linux/silicon/patches-5.19/0014-arm64-dts-apple-t8103-j313-Also-disable-speakers.patch new file mode 100644 index 000000000..6c86d6bf4 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0014-arm64-dts-apple-t8103-j313-Also-disable-speakers.patch @@ -0,0 +1,33 @@ +From 461322f8b15d66dc8860c4f940c3f8f4f36bb3a3 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 12 Mar 2022 21:00:22 +0900 +Subject: [PATCH 014/171] arm64: dts: apple: t8103-j313: Also disable speakers + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-j313.dts | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts +index ad3a6edeb651..d1f65e48699f 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j313.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j313.dts +@@ -112,6 +112,15 @@ sound { + model = "MacBook Air J313 integrated audio"; + + dai-link@0 { ++ /* ++ * DANGER ZONE: You can blow your speakers! ++ * ++ * The drivers are not ready, and unless you are careful ++ * to attenuate the audio stream, you run the risk of ++ * blowing your speakers. ++ */ ++ status = "disabled"; ++ + link-name = "Speakers"; + mclk-fs = <64>; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0015-arm64-dts-apple-Keep-PCIe-power-domain-on.patch b/target/linux/silicon/patches-5.19/0015-arm64-dts-apple-Keep-PCIe-power-domain-on.patch new file mode 100644 index 000000000..e8fd03aca --- /dev/null +++ b/target/linux/silicon/patches-5.19/0015-arm64-dts-apple-Keep-PCIe-power-domain-on.patch @@ -0,0 +1,28 @@ +From 79b1406346a1f0bdf8bd326a005e288511ebfaf6 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 17 Mar 2022 23:49:07 +0900 +Subject: [PATCH 015/171] arm64: dts: apple: Keep PCIe power domain on + +This causes flakiness if shut down; don't do it until we find out +what's going on. + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +index 926b1e54b64b..68ae594bf5e9 100644 +--- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +@@ -717,6 +717,7 @@ ps_apcie_gp: power-controller@3e8 { + #reset-cells = <0>; + label = "apcie_gp"; + power-domains = <&ps_apcie>; ++ apple,always-on; /* Breaks things if shut down */ + }; + + ps_ans2: power-controller@3f0 { +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0016-arm64-dts-apple-Add-initial-t6000-t6001-t6002-DTs.patch b/target/linux/silicon/patches-5.19/0016-arm64-dts-apple-Add-initial-t6000-t6001-t6002-DTs.patch new file mode 100644 index 000000000..9f9b8a41e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0016-arm64-dts-apple-Add-initial-t6000-t6001-t6002-DTs.patch @@ -0,0 +1,3024 @@ +From 8fb4c09b034f66e7ba1e3c1b16dfb2e3854af312 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Wed, 10 Nov 2021 19:07:41 +0900 +Subject: [PATCH 016/171] arm64: dts: apple: Add initial t6000/t6001/t6002 DTs + +t6002 is two die version of t6001. Devices on the second die are at a +consistent offset compared to the first die. Use "ranges" properties +to translate the MMIO addresses. To avoid duplication all devices are +separate *.dtsi. C preprocessor macros are used to assign unique node +names and labels. +Devices are split into devices present on die 0, devices present on all +dies and NVMe. +It's unclear if devices on die 1 are fused out or just not used on the +single machine with t6002. + +The M1 Ultra SoC consists of two M1 Max dies. The multi die device +nodes are distributed to include files based on whether they are used +on both dies or just the primary die on the Mac Studio M1 Ultra. +The NVMe is a noteable exception since it is only on the second die. +It seems to be a special case since its interrupt is routed as it were +on die 0. + +t6000 is a cut-down version of t6001, so the former just includes the +latter and disables the missing bits (This is currently just one PMGR +node and all of its domains. + +Signed-off-by: Hector Martin +Co-developed-by: Janne Grunau +Signed-off-by: Janne Grunau +--- + arch/arm64/boot/dts/apple/multi-die-cpp.h | 19 + + arch/arm64/boot/dts/apple/t6000.dtsi | 18 + + arch/arm64/boot/dts/apple/t6001.dtsi | 63 + + arch/arm64/boot/dts/apple/t6002.dtsi | 180 ++ + arch/arm64/boot/dts/apple/t600x-common.dtsi | 128 ++ + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 298 +++ + arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 103 + + .../arm64/boot/dts/apple/t600x-gpio-pins.dtsi | 45 + + arch/arm64/boot/dts/apple/t600x-nvme.dtsi | 42 + + arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 2013 +++++++++++++++++ + 10 files changed, 2909 insertions(+) + create mode 100644 arch/arm64/boot/dts/apple/multi-die-cpp.h + create mode 100644 arch/arm64/boot/dts/apple/t6000.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t6001.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t6002.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t600x-common.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t600x-die0.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t600x-dieX.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t600x-nvme.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t600x-pmgr.dtsi + +diff --git a/arch/arm64/boot/dts/apple/multi-die-cpp.h b/arch/arm64/boot/dts/apple/multi-die-cpp.h +new file mode 100644 +index 000000000000..19b565bb6e0e +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/multi-die-cpp.h +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * C preprocessor macros for t600x multi die support. ++ */ ++ ++#ifndef __DTS_APPLE_MULTI_DIE_CPP_H ++#define __DTS_APPLE_MULTI_DIE_CPP_H ++ ++/* copied include/linux/stringify.h */ ++#define __stringify_1(x...) #x ++#define __stringify(x...) __stringify_1(x) ++ ++#define __concat_1(x, y...) x ## y ++#define __concat(x, y...) __concat_1(x, y) ++ ++#define DIE_NODE(a) __concat(a, DIE) ++#define DIE_LABEL(a) __stringify(__concat(a, DIE)) ++ ++#endif /* !__LINUX_STRINGIFY_H */ +diff --git a/arch/arm64/boot/dts/apple/t6000.dtsi b/arch/arm64/boot/dts/apple/t6000.dtsi +new file mode 100644 +index 000000000000..89c3b211b116 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6000.dtsi +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Apple T6000 "M1 Pro" SoC ++ * ++ * Other names: H13J, "Jade Chop" ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/* This chip is just a cut down version of t6001, so include it and disable the missing parts */ ++ ++#include "t6001.dtsi" ++ ++/ { ++ compatible = "apple,t6000", "apple,arm-platform"; ++}; ++ ++/delete-node/ &pmgr_south; +diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi +new file mode 100644 +index 000000000000..620b17e4031f +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6001.dtsi +@@ -0,0 +1,63 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Apple T6001 "M1 Max" SoC ++ * ++ * Other names: H13J, "Jade" ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "multi-die-cpp.h" ++ ++#include "t600x-common.dtsi" ++ ++/ { ++ compatible = "apple,t6001", "apple,arm-platform"; ++ ++ soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ ranges; ++ nonposted-mmio; ++ ++ // filled via templated includes at the end of the file ++ }; ++}; ++ ++#define DIE ++#define DIE_NO 0 ++ ++&{/soc} { ++ #include "t600x-die0.dtsi" ++ #include "t600x-dieX.dtsi" ++ #include "t600x-nvme.dtsi" ++}; ++ ++#include "t600x-gpio-pins.dtsi" ++#include "t600x-pmgr.dtsi" ++ ++#undef DIE ++#undef DIE_NO ++ ++ ++&aic { ++ affinities { ++ e-core-pmu-affinity { ++ apple,fiq-index = ; ++ cpus = <&cpu_e00 &cpu_e01>; ++ }; ++ ++ p-core-pmu-affinity { ++ apple,fiq-index = ; ++ cpus = <&cpu_p00 &cpu_p01 &cpu_p02 &cpu_p03 ++ &cpu_p10 &cpu_p11 &cpu_p12 &cpu_p13>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi +new file mode 100644 +index 000000000000..736f16aad70f +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6002.dtsi +@@ -0,0 +1,180 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Apple T6002 "M1 Ultra" SoC ++ * ++ * Other names: H13J, "Jade 2C" ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "multi-die-cpp.h" ++ ++#include "t600x-common.dtsi" ++ ++/ { ++ compatible = "apple,t6002", "apple,arm-platform"; ++ ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ cpus { ++ cpu_e10: cpu@800 { ++ compatible = "apple,icestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x800>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_e11: cpu@801 { ++ compatible = "apple,icestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x801>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p20: cpu@10900 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10900>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p21: cpu@10901 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10901>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p22: cpu@10902 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10902>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p23: cpu@10903 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10903>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p30: cpu@10a00 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10a00>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p31: cpu@10a01 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10a01>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p32: cpu@10a02 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10a02>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p33: cpu@10a03 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10a03>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ ranges; ++ nonposted-mmio; ++ ++ die0 { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ nonposted-mmio; ++ ++ // filled via templated includes at the end of the file ++ }; ++ ++ die1 { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x2 0x0 0x22 0x0 0x4 0x0>, ++ <0x7 0x0 0x27 0x0 0xf 0x80000000>; ++ nonposted-mmio; ++ ++ // filled via templated includes at the end of the file ++ }; ++ }; ++}; ++ ++#define DIE ++#define DIE_NO 0 ++ ++&{/soc/die0} { ++ #include "t600x-die0.dtsi" ++ #include "t600x-dieX.dtsi" ++}; ++ ++#include "t600x-pmgr.dtsi" ++#include "t600x-gpio-pins.dtsi" ++ ++#undef DIE ++#undef DIE_NO ++ ++#define DIE _die1 ++#define DIE_NO 1 ++ ++&{/soc/die1} { ++ #include "t600x-dieX.dtsi" ++ #include "t600x-nvme.dtsi" ++}; ++ ++#include "t600x-pmgr.dtsi" ++ ++#undef DIE ++#undef DIE_NO ++ ++ ++&aic { ++ affinities { ++ e-core-pmu-affinity { ++ cpus = <&cpu_e00 &cpu_e01 ++ &cpu_e10 &cpu_e11>; ++ }; ++ ++ p-core-pmu-affinity { ++ cpus = <&cpu_p00 &cpu_p01 &cpu_p02 &cpu_p03 ++ &cpu_p10 &cpu_p11 &cpu_p12 &cpu_p13 ++ &cpu_p20 &cpu_p21 &cpu_p22 &cpu_p23 ++ &cpu_p30 &cpu_p31 &cpu_p32 &cpu_p33>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi +new file mode 100644 +index 000000000000..e29b88e2c853 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi +@@ -0,0 +1,128 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Common Apple T6000 / T6001 / T6002 "M1 Pro/Max/Ultra" SoC ++ * ++ * Other names: H13J, "Jade Chop", "Jade", "Jade 2C" ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/ { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ cpus { ++ #address-cells = <2>; ++ #size-cells = <0>; ++ ++ cpu_e00: cpu@0 { ++ compatible = "apple,icestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x0>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_e01: cpu@1 { ++ compatible = "apple,icestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x1>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p00: cpu@10100 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10100>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p01: cpu@10101 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10101>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p02: cpu@10102 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10102>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p03: cpu@10103 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10103>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p10: cpu@10200 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10200>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p11: cpu@10201 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10201>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p12: cpu@10202 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10202>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ ++ cpu_p13: cpu@10203 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10203>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ }; ++ }; ++ ++ pmu-e { ++ compatible = "apple,icestorm-pmu"; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ }; ++ ++ pmu-p { ++ compatible = "apple,firestorm-pmu"; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupt-parent = <&aic>; ++ interrupt-names = "phys", "virt", "hyp-phys", "hyp-virt"; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ clkref: clock-ref { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ clock-output-names = "clkref"; ++ }; ++ ++}; +diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +new file mode 100644 +index 000000000000..8131352e3ccd +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +@@ -0,0 +1,298 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Devices used on die 0 on the Apple T6002 "M1 Ultra" SoC and present on ++ * Apple T6000 / T6001 "M1 Pro" / "M1 Max". ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++ ++ aic: interrupt-controller@28e100000 { ++ compatible = "apple,t6000-aic", "apple,aic2"; ++ #interrupt-cells = <4>; ++ interrupt-controller; ++ reg = <0x2 0x8e100000 0x0 0xc000>, ++ <0x2 0x8e10c000 0x0 0x4>; ++ reg-names = "core", "event"; ++ power-domains = <&ps_aic>; ++ }; ++ ++ pinctrl_smc: pinctrl@290820000 { ++ compatible = "apple,t6000-pinctrl", "apple,pinctrl"; ++ reg = <0x2 0x90820000 0x0 0x4000>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl_smc 0 0 30>; ++ apple,npins = <30>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ ; ++ }; ++ ++ wdt: watchdog@2922b0000 { ++ compatible = "apple,t6000-wdt", "apple,wdt"; ++ reg = <0x2 0x922b0000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ }; ++ ++ i2c0: i2c@39b040000 { ++ compatible = "apple,t6000-i2c", "apple,i2c"; ++ reg = <0x3 0x9b040000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_i2c0>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ }; ++ ++ i2c1: i2c@39b044000 { ++ compatible = "apple,t6000-i2c", "apple,i2c"; ++ reg = <0x3 0x9b044000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_i2c1>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@39b048000 { ++ compatible = "apple,t6000-i2c", "apple,i2c"; ++ reg = <0x3 0x9b048000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c2_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_i2c2>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@39b04c000 { ++ compatible = "apple,t6000-i2c", "apple,i2c"; ++ reg = <0x3 0x9b04c000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c3_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_i2c3>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@39b050000 { ++ compatible = "apple,t6000-i2c", "apple,i2c"; ++ reg = <0x3 0x9b050000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c4_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_i2c4>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@39b054000 { ++ compatible = "apple,t6000-i2c", "apple,i2c"; ++ reg = <0x3 0x9b054000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c5_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_i2c5>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ status = "disabled"; ++ }; ++ ++ serial0: serial@39b200000 { ++ compatible = "apple,s5l-uart"; ++ reg = <0x3 0x9b200000 0x0 0x1000>; ++ reg-io-width = <4>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ /* ++ * TODO: figure out the clocking properly, there may ++ * be a third selectable clock. ++ */ ++ clocks = <&clkref>, <&clkref>; ++ clock-names = "uart", "clk_uart_baud0"; ++ power-domains = <&ps_uart0>; ++ status = "disabled"; ++ }; ++ ++ pcie0_dart_0: dart@581008000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0x5 0x81008000 0x0 0x4000>; ++ #iommu-cells = <1>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&ps_apcie_gp_sys>; ++ }; ++ ++ pcie0_dart_1: dart@582008000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0x5 0x82008000 0x0 0x4000>; ++ #iommu-cells = <1>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&ps_apcie_gp_sys>; ++ }; ++ ++ pcie0_dart_2: dart@583008000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0x5 0x83008000 0x0 0x4000>; ++ #iommu-cells = <1>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&ps_apcie_gp_sys>; ++ }; ++ ++ pcie0_dart_3: dart@584008000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0x5 0x84008000 0x0 0x4000>; ++ #iommu-cells = <1>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&ps_apcie_gp_sys>; ++ }; ++ ++ pcie0: pcie@590000000 { ++ compatible = "apple,t6000-pcie", "apple,pcie"; ++ device_type = "pci"; ++ ++ reg = <0x5 0x90000000 0x0 0x1000000>, ++ <0x5 0x80000000 0x0 0x100000>, ++ <0x5 0x81000000 0x0 0x4000>, ++ <0x5 0x82000000 0x0 0x4000>, ++ <0x5 0x83000000 0x0 0x4000>, ++ <0x5 0x84000000 0x0 0x4000>; ++ reg-names = "config", "rc", "port0", "port1", "port2", "port3"; ++ ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ ++ msi-controller; ++ msi-parent = <&pcie0>; ++ msi-ranges = <&aic AIC_IRQ 0 1581 IRQ_TYPE_EDGE_RISING 32>; ++ ++ ++ iommu-map = <0x100 &pcie0_dart_0 1 1>, ++ <0x200 &pcie0_dart_1 1 1>, ++ <0x300 &pcie0_dart_2 1 1>, ++ <0x400 &pcie0_dart_3 1 1>; ++ iommu-map-mask = <0xff00>; ++ ++ bus-range = <0 4>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges = <0x43000000 0x5 0xa0000000 0x5 0xa0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xc0000000 0x5 0xc0000000 0x0 0x40000000>; ++ ++ power-domains = <&ps_apcie_gp_sys>; ++ pinctrl-0 = <&pcie_pins>; ++ pinctrl-names = "default"; ++ ++ port00: pci@0,0 { ++ device_type = "pci"; ++ reg = <0x0 0x0 0x0 0x0 0x0>; ++ reset-gpios = <&pinctrl_ap 4 GPIO_ACTIVE_LOW>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port00 0 0 0 0>, ++ <0 0 0 2 &port00 0 0 0 1>, ++ <0 0 0 3 &port00 0 0 0 2>, ++ <0 0 0 4 &port00 0 0 0 3>; ++ }; ++ ++ port01: pci@1,0 { ++ device_type = "pci"; ++ reg = <0x800 0x0 0x0 0x0 0x0>; ++ reset-gpios = <&pinctrl_ap 5 GPIO_ACTIVE_LOW>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port01 0 0 0 0>, ++ <0 0 0 2 &port01 0 0 0 1>, ++ <0 0 0 3 &port01 0 0 0 2>, ++ <0 0 0 4 &port01 0 0 0 3>; ++ }; ++ ++ port02: pci@2,0 { ++ device_type = "pci"; ++ reg = <0x1000 0x0 0x0 0x0 0x0>; ++ reset-gpios = <&pinctrl_ap 6 GPIO_ACTIVE_LOW>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port02 0 0 0 0>, ++ <0 0 0 2 &port02 0 0 0 1>, ++ <0 0 0 3 &port02 0 0 0 2>, ++ <0 0 0 4 &port02 0 0 0 3>; ++ }; ++ ++ port03: pci@3,0 { ++ device_type = "pci"; ++ reg = <0x1800 0x0 0x0 0x0 0x0>; ++ reset-gpios = <&pinctrl_ap 7 GPIO_ACTIVE_LOW>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port03 0 0 0 0>, ++ <0 0 0 2 &port03 0 0 0 1>, ++ <0 0 0 3 &port03 0 0 0 2>, ++ <0 0 0 4 &port03 0 0 0 3>; ++ }; ++ }; +diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +new file mode 100644 +index 000000000000..0a437b68e86c +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +@@ -0,0 +1,103 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Devices used on both dies on the Apple T6002 "M1 Ultra" and present on ++ * Apple T6000/T6001 "M1 Pro/Max". ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++ DIE_NODE(pmgr): power-management@28e080000 { ++ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2 0x8e080000 0 0x4000>; ++ }; ++ ++ DIE_NODE(pmgr_east): power-management@28e580000 { ++ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2 0x8e580000 0 0xc000>; ++ }; ++ ++ DIE_NODE(pmgr_south): power-management@28e680000 { ++ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2 0x8e680000 0 0xc000>; ++ }; ++ ++ DIE_NODE(pinctrl_nub): pinctrl@2921f0000 { ++ compatible = "apple,t6000-pinctrl", "apple,pinctrl"; ++ reg = <0x2 0x921f0000 0x0 0x4000>; ++ power-domains = <&DIE_NODE(ps_nub_gpio)>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&DIE_NODE(pinctrl_nub) 0 0 16>; ++ apple,npins = <16>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ ; ++ }; ++ ++ DIE_NODE(pmgr_mini): power-management@292280000 { ++ compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2 0x92280000 0 0x4000>; ++ }; ++ ++ DIE_NODE(pinctrl_aop): pinctrl@293820000 { ++ compatible = "apple,t6000-pinctrl", "apple,pinctrl"; ++ reg = <0x2 0x93820000 0x0 0x4000>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&DIE_NODE(pinctrl_aop) 0 0 63>; ++ apple,npins = <63>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ ; ++ }; ++ ++ DIE_NODE(pinctrl_ap): pinctrl@39b028000 { ++ compatible = "apple,t6000-pinctrl", "apple,pinctrl"; ++ reg = <0x3 0x9b028000 0x0 0x4000>; ++ ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ ; ++ ++ clocks = <&clkref>; ++ power-domains = <&DIE_NODE(ps_gpio)>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&DIE_NODE(pinctrl_ap) 0 0 255>; ++ apple,npins = <255>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; +diff --git a/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi b/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi +new file mode 100644 +index 000000000000..b31f1a7a2b3f +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi +@@ -0,0 +1,45 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * GPIO pin mappings for Apple T600x SoCs. ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++&pinctrl_ap { ++ i2c0_pins: i2c0-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c1_pins: i2c1-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c2_pins: i2c2-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c3_pins: i2c3-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c4_pins: i2c4-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c5_pins: i2c5-pins { ++ pinmux = , ++ ; ++ }; ++ ++ pcie_pins: pcie-pins { ++ pinmux = , ++ , ++ , ++ ; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t600x-nvme.dtsi b/arch/arm64/boot/dts/apple/t600x-nvme.dtsi +new file mode 100644 +index 000000000000..04c89593735d +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t600x-nvme.dtsi +@@ -0,0 +1,42 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * NVMe related devices for Apple T600x SoCs. ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++ DIE_NODE(ans_mbox): mbox@38f408000 { ++ compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; ++ reg = <0x3 0x8f408000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "send-empty", "send-not-empty", ++ "recv-empty", "recv-not-empty"; ++ power-domains = <&DIE_NODE(ps_ans2)>; ++ #mbox-cells = <0>; ++ }; ++ ++ DIE_NODE(sart): sart@393c50000 { ++ compatible = "apple,t6000-sart", "apple,sart3"; ++ reg = <0x3 0x93c50000 0x0 0x10000>; ++ power-domains = <&DIE_NODE(ps_ans2)>; ++ }; ++ ++ DIE_NODE(nvme): nvme@393cc0000 { ++ compatible = "apple,t6000-nvme-ans2", "apple,nvme-ans2"; ++ reg = <0x3 0x93cc0000 0x0 0x40000>, <0x3 0x8f400000 0x0 0x4000>; ++ reg-names = "nvme", "ans"; ++ interrupt-parent = <&aic>; ++ /* The NVME interrupt is always routed to die */ ++ interrupts = ; ++ mboxes = <&DIE_NODE(ans_mbox)>; ++ apple,sart = <&DIE_NODE(sart)>; ++ power-domains = <&DIE_NODE(ps_ans2)>, ++ <&DIE_NODE(ps_apcie_st_sys)>, ++ <&DIE_NODE(ps_apcie_st1_sys)>; ++ power-domain-names = "ans", "apcie0", "apcie1"; ++ resets = <&DIE_NODE(ps_ans2)>; ++ }; +diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +new file mode 100644 +index 000000000000..5a041501da5b +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +@@ -0,0 +1,2013 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * PMGR Power domains for the Apple T6001 "M1 Max" SoC ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++&DIE_NODE(pmgr) { ++ DIE_NODE(ps_pms_bridge): power-controller@100 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x100 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(pms_bridge); ++ apple,always-on; /* Core device */ ++ }; ++ ++ DIE_NODE(ps_aic): power-controller@108 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x108 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(aic); ++ apple,always-on; /* Core device */ ++ }; ++ ++ DIE_NODE(ps_dwi): power-controller@110 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x110 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dwi); ++ apple,always-on; /* Core device */ ++ }; ++ ++ DIE_NODE(ps_pms): power-controller@118 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x118 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(pms); ++ apple,always-on; /* Core device */ ++ }; ++ ++ DIE_NODE(ps_gpio): power-controller@120 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x120 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(gpio); ++ power-domains = <&DIE_NODE(ps_pms)>, <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_soc_dpe): power-controller@128 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x128 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(soc_dpe); ++ apple,always-on; /* Core device */ ++ }; ++ ++ DIE_NODE(ps_pmgr_soc_ocla): power-controller@130 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x130 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(pmgr_soc_ocla); ++ power-domains = <&DIE_NODE(ps_pms)>; ++ }; ++ ++ DIE_NODE(ps_pcie0_ref): power-controller@138 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x138 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(pcie0_ref); ++ }; ++ ++ DIE_NODE(ps_pcie1_ref): power-controller@140 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x140 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(pcie1_ref); ++ }; ++ ++ DIE_NODE(ps_apcie_st): power-controller@148 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x148 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(apcie_st); ++ power-domains = <&DIE_NODE(ps_pcie1_ref)>; ++ }; ++ ++ DIE_NODE(ps_apcie_gp): power-controller@150 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x150 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(apcie_gp); ++ power-domains = <&DIE_NODE(ps_pcie0_ref)>; ++ }; ++ ++ DIE_NODE(ps_devc0_ivdmc): power-controller@180 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x180 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(devc0_ivdmc); ++ }; ++ ++ DIE_NODE(ps_amcc0): power-controller@188 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x188 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(amcc0); ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ DIE_NODE(ps_amcc2): power-controller@190 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x190 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(amcc2); ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ DIE_NODE(ps_dcs_00): power-controller@198 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x198 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_00); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_01): power-controller@1a0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_01); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_02): power-controller@1a8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_02); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_03): power-controller@1b0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_03); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_08): power-controller@1b8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1b8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_08); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_09): power-controller@1c0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1c0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_09); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_10): power-controller@1c8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1c8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_10); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_11): power-controller@1d0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1d0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_11); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_afi): power-controller@1d8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1d8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afi); ++ apple,always-on; /* Apple Fabric, CPU inteface is here */ ++ }; ++ ++ DIE_NODE(ps_afc): power-controller@1e0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1e0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afc); ++ apple,always-on; /* Apple Fabric, CPU inteface is here */ ++ }; ++ ++ DIE_NODE(ps_afr): power-controller@1e8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1e8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afr); ++ /* Apple Fabric, media DIE_NODE(stuff): this can power down */ ++ }; ++ ++ DIE_NODE(ps_afnc1_ioa): power-controller@1f0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1f0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc1_ioa); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afi)>; ++ }; ++ ++ DIE_NODE(ps_afnc0_ioa): power-controller@1f8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1f8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc0_ioa); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afi)>; ++ }; ++ ++ DIE_NODE(ps_afnc1_ls): power-controller@200 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x200 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc1_ls); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc1_ioa)>; ++ }; ++ ++ DIE_NODE(ps_afnc0_ls): power-controller@208 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x208 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc0_ls); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc0_ioa)>; ++ }; ++ ++ DIE_NODE(ps_afnc1_lw0): power-controller@210 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x210 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc1_lw0); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc1_ls)>; ++ }; ++ ++ DIE_NODE(ps_afnc1_lw1): power-controller@218 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x218 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc1_lw1); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc1_ls)>; ++ }; ++ ++ DIE_NODE(ps_afnc1_lw2): power-controller@220 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x220 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc1_lw2); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc1_ls)>; ++ }; ++ ++ DIE_NODE(ps_afnc0_lw0): power-controller@228 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x228 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc0_lw0); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc0_ls)>; ++ }; ++ ++ DIE_NODE(ps_scodec): power-controller@230 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x230 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(scodec); ++ power-domains = <&DIE_NODE(ps_afnc1_lw0)>; ++ }; ++ ++ DIE_NODE(ps_atc0_common): power-controller@238 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x238 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc0_common); ++ power-domains = <&DIE_NODE(ps_afnc1_lw1)>; ++ }; ++ ++ DIE_NODE(ps_atc1_common): power-controller@240 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x240 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc1_common); ++ power-domains = <&DIE_NODE(ps_afnc1_lw1)>; ++ }; ++ ++ DIE_NODE(ps_c0_usb31drd): power-controller@248 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x248 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(c0_usb31drd); ++ power-domains = <&DIE_NODE(ps_usb)>; ++ }; ++ ++ DIE_NODE(ps_c1_usb31drd): power-controller@250 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x250 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(c1_usb31drd); ++ power-domains = <&DIE_NODE(ps_usb)>; ++ }; ++ ++ DIE_NODE(ps_dispext0_fe): power-controller@258 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x258 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispext0_fe); ++ power-domains = <&DIE_NODE(ps_afi)>; ++ }; ++ ++ DIE_NODE(ps_dispext1_fe): power-controller@260 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x260 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispext1_fe); ++ power-domains = <&DIE_NODE(ps_afi)>; ++ }; ++ ++ DIE_NODE(ps_ane_sys): power-controller@268 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x268 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ane_sys); ++ power-domains = <&DIE_NODE(ps_afr)>; ++ }; ++ ++ DIE_NODE(ps_avd_sys): power-controller@270 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x270 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(avd_sys); ++ power-domains = <&DIE_NODE(ps_afr)>; ++ }; ++ ++ DIE_NODE(ps_dispext0_cpu0): power-controller@280 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x280 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispext0_cpu0); ++ power-domains = <&DIE_NODE(ps_dispext0_fe)>; ++ }; ++ ++ DIE_NODE(ps_dispext1_cpu0): power-controller@2a8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispext1_cpu0); ++ power-domains = <&DIE_NODE(ps_dispext1_fe)>; ++ }; ++ ++ DIE_NODE(ps_ane_sys_cpu): power-controller@2c8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2c8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ane_sys_cpu); ++ power-domains = <&DIE_NODE(ps_ane_sys)>; ++ }; ++ ++#if DIE_NO == 0 ++ /* PMP is only present on die 0 of the M1 Ultra */ ++ DIE_NODE(ps_pmp): power-controller@2d8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2d8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(pmp); ++ }; ++#endif ++ ++ DIE_NODE(ps_pms_sram): power-controller@2e0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2e0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(pms_sram); ++ }; ++ ++ DIE_NODE(ps_apcie_st_sys): power-controller@2e8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2e8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(apcie_st_sys); ++ power-domains = <&DIE_NODE(ps_apcie_st)>, <&DIE_NODE(ps_ans2)>; ++ }; ++ ++ DIE_NODE(ps_apcie_st1_sys): power-controller@2f0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2f0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(apcie_st1_sys); ++ power-domains = <&DIE_NODE(ps_apcie_st)>, <&DIE_NODE(ps_ans2)>; ++ }; ++ ++ DIE_NODE(ps_atc2_common): power-controller@2f8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2f8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc2_common); ++ power-domains = <&DIE_NODE(ps_afnc1_lw1)>; ++ }; ++ ++ DIE_NODE(ps_atc3_common): power-controller@300 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x300 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc3_common); ++ power-domains = <&DIE_NODE(ps_afnc1_lw1)>; ++ }; ++ ++ DIE_NODE(ps_usb): power-controller@318 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x318 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(usb); ++ power-domains = <&DIE_NODE(ps_afnc1_lw2)>; ++ }; ++ ++ DIE_NODE(ps_apcie_gp_sys): power-controller@320 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x320 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(apcie_gp_sys); ++ power-domains = <&DIE_NODE(ps_afnc1_lw2)>, <&DIE_NODE(ps_apcie_gp)>; ++ apple,always-on; /* Breaks things if shut down */ ++ }; ++ ++ DIE_NODE(ps_atc0_cio): power-controller@328 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x328 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc0_cio); ++ power-domains = <&DIE_NODE(ps_atc0_common)>; ++ }; ++ ++ DIE_NODE(ps_atc0_pcie): power-controller@330 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x330 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc0_pcie); ++ power-domains = <&DIE_NODE(ps_atc0_common)>; ++ }; ++ ++ DIE_NODE(ps_atc1_cio): power-controller@338 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x338 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc1_cio); ++ power-domains = <&DIE_NODE(ps_atc1_common)>; ++ }; ++ ++ DIE_NODE(ps_atc1_pcie): power-controller@340 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x340 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc1_pcie); ++ power-domains = <&DIE_NODE(ps_atc1_common)>; ++ }; ++ ++ DIE_NODE(ps_atc2_cio): power-controller@348 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x348 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc2_cio); ++ power-domains = <&DIE_NODE(ps_atc2_common)>; ++ }; ++ ++ DIE_NODE(ps_atc2_pcie): power-controller@350 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x350 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc2_pcie); ++ power-domains = <&DIE_NODE(ps_atc2_common)>; ++ }; ++ ++ DIE_NODE(ps_atc3_cio): power-controller@358 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x358 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc3_cio); ++ power-domains = <&DIE_NODE(ps_atc3_common)>; ++ }; ++ ++ DIE_NODE(ps_atc3_pcie): power-controller@360 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x360 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc3_pcie); ++ power-domains = <&DIE_NODE(ps_atc3_common)>; ++ }; ++ ++ DIE_NODE(ps_c0_usbctl): power-controller@368 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x368 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(c0_usbctl); ++ power-domains = <&DIE_NODE(ps_usb)>; ++ }; ++ ++ DIE_NODE(ps_c1_usbctl): power-controller@370 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x370 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(c1_usbctl); ++ power-domains = <&DIE_NODE(ps_usb)>; ++ }; ++ ++ DIE_NODE(ps_atc0_cio_pcie): power-controller@378 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x378 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc0_cio_pcie); ++ power-domains = <&DIE_NODE(ps_atc0_cio)>; ++ }; ++ ++ DIE_NODE(ps_atc0_cio_usb): power-controller@380 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x380 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc0_cio_usb); ++ power-domains = <&DIE_NODE(ps_atc0_cio)>; ++ }; ++ ++ DIE_NODE(ps_atc1_cio_pcie): power-controller@388 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x388 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc1_cio_pcie); ++ power-domains = <&DIE_NODE(ps_atc1_cio)>; ++ }; ++ ++ DIE_NODE(ps_atc1_cio_usb): power-controller@390 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x390 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc1_cio_usb); ++ power-domains = <&DIE_NODE(ps_atc1_cio)>; ++ }; ++ ++ DIE_NODE(ps_atc2_cio_pcie): power-controller@398 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x398 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc2_cio_pcie); ++ power-domains = <&DIE_NODE(ps_atc2_cio)>; ++ }; ++ ++ DIE_NODE(ps_atc2_cio_usb): power-controller@3a0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc2_cio_usb); ++ power-domains = <&DIE_NODE(ps_atc2_cio)>; ++ }; ++ ++ DIE_NODE(ps_atc3_cio_pcie): power-controller@3a8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc3_cio_pcie); ++ power-domains = <&DIE_NODE(ps_atc3_cio)>; ++ }; ++ ++ DIE_NODE(ps_atc3_cio_usb): power-controller@3b0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc3_cio_usb); ++ power-domains = <&DIE_NODE(ps_atc3_cio)>; ++ }; ++ ++ DIE_NODE(ps_trace_fab): power-controller@3b8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3b8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(trace_fab); ++ }; ++}; ++ ++&DIE_NODE(pmgr_east) { ++ DIE_NODE(ps_clvr_spmi0): power-controller@100 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x100 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(clvr_spmi0); ++ apple,always-on; /* PCPU voltage regulator interface (used by SMC) */ ++ }; ++ ++ DIE_NODE(ps_clvr_spmi1): power-controller@108 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x108 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(clvr_spmi1); ++ apple,always-on; /* GPU voltage regulator interface (used by SMC) */ ++ }; ++ ++ DIE_NODE(ps_clvr_spmi2): power-controller@110 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x110 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(clvr_spmi2); ++ apple,always-on; /* ANE, fabric, AFR voltage regulator interface (used by SMC) */ ++ }; ++ ++ DIE_NODE(ps_clvr_spmi3): power-controller@118 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x118 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(clvr_spmi3); ++ apple,always-on; /* Additional voltage regulator, probably used on T6001 (SMC) */ ++ }; ++ ++ DIE_NODE(ps_clvr_spmi4): power-controller@120 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x120 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(clvr_spmi4); ++ apple,always-on; /* Additional voltage regulator, probably used on T6001 (SMC) */ ++ }; ++ ++ DIE_NODE(ps_ispsens0): power-controller@128 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x128 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ispsens0); ++ }; ++ ++ DIE_NODE(ps_ispsens1): power-controller@130 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x130 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ispsens1); ++ }; ++ ++ DIE_NODE(ps_ispsens2): power-controller@138 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x138 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ispsens2); ++ }; ++ ++ DIE_NODE(ps_ispsens3): power-controller@140 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x140 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ispsens3); ++ }; ++ ++ DIE_NODE(ps_afnc2_ioa): power-controller@148 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x148 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc2_ioa); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afi)>; ++ }; ++ ++ DIE_NODE(ps_afnc2_ls): power-controller@150 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x150 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc2_ls); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc2_ioa)>; ++ }; ++ ++ DIE_NODE(ps_afnc2_lw0): power-controller@158 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x158 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc2_lw0); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc2_ls)>; ++ }; ++ ++ DIE_NODE(ps_afnc2_lw1): power-controller@160 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x160 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc2_lw1); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc2_ls)>; ++ }; ++ ++ DIE_NODE(ps_afnc3_ioa): power-controller@168 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x168 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc3_ioa); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afi)>; ++ }; ++ ++ DIE_NODE(ps_afnc3_ls): power-controller@170 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x170 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc3_ls); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc3_ioa)>; ++ }; ++ ++ DIE_NODE(ps_afnc3_lw0): power-controller@178 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x178 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc3_lw0); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc3_ls)>; ++ }; ++ ++ DIE_NODE(ps_sio): power-controller@180 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x180 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(sio); ++ power-domains = <&DIE_NODE(ps_afnc2_lw1)>; ++ }; ++ ++ DIE_NODE(ps_sio_cpu): power-controller@188 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x188 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(sio_cpu); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_fpwm0): power-controller@190 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x190 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(fpwm0); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_fpwm1): power-controller@198 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x198 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(fpwm1); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_fpwm2): power-controller@1a0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(fpwm2); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_i2c0): power-controller@1a8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(i2c0); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_i2c1): power-controller@1b0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(i2c1); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_i2c2): power-controller@1b8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1b8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(i2c2); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_i2c3): power-controller@1c0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1c0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(i2c3); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_i2c4): power-controller@1c8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1c8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(i2c4); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_i2c5): power-controller@1d0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1d0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(i2c5); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_i2c6): power-controller@1d8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1d8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(i2c6); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_i2c7): power-controller@1e0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1e0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(i2c7); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_spi_p): power-controller@1e8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1e8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(spi_p); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_spi0): power-controller@1f0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1f0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(spi0); ++ power-domains = <&DIE_NODE(ps_spi_p)>; ++ }; ++ ++ DIE_NODE(ps_spi1): power-controller@1f8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1f8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(spi1); ++ power-domains = <&DIE_NODE(ps_spi_p)>; ++ }; ++ ++ DIE_NODE(ps_spi2): power-controller@200 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x200 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(spi2); ++ power-domains = <&DIE_NODE(ps_spi_p)>; ++ }; ++ ++ DIE_NODE(ps_spi3): power-controller@208 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x208 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(spi3); ++ power-domains = <&DIE_NODE(ps_spi_p)>; ++ }; ++ ++ DIE_NODE(ps_spi4): power-controller@210 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x210 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(spi4); ++ power-domains = <&DIE_NODE(ps_spi_p)>; ++ }; ++ ++ DIE_NODE(ps_sio_spmi0): power-controller@218 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x218 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(sio_spmi0); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_sio_spmi1): power-controller@220 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x220 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(sio_spmi1); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_sio_spmi2): power-controller@228 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x228 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(sio_spmi2); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_uart_p): power-controller@230 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x230 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart_p); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_uart_n): power-controller@238 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x238 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart_n); ++ power-domains = <&DIE_NODE(ps_uart_p)>; ++ }; ++ ++ DIE_NODE(ps_uart0): power-controller@240 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x240 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart0); ++ power-domains = <&DIE_NODE(ps_uart_p)>; ++ }; ++ ++ DIE_NODE(ps_uart1): power-controller@248 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x248 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart1); ++ power-domains = <&DIE_NODE(ps_uart_p)>; ++ }; ++ ++ DIE_NODE(ps_uart2): power-controller@250 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x250 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart2); ++ power-domains = <&DIE_NODE(ps_uart_p)>; ++ }; ++ ++ DIE_NODE(ps_uart3): power-controller@258 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x258 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart3); ++ power-domains = <&DIE_NODE(ps_uart_p)>; ++ }; ++ ++ DIE_NODE(ps_uart4): power-controller@260 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x260 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart4); ++ power-domains = <&DIE_NODE(ps_uart_p)>; ++ }; ++ ++ DIE_NODE(ps_uart6): power-controller@268 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x268 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart6); ++ power-domains = <&DIE_NODE(ps_uart_p)>; ++ }; ++ ++ DIE_NODE(ps_uart7): power-controller@270 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x270 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(uart7); ++ power-domains = <&DIE_NODE(ps_uart_p)>; ++ }; ++ ++ DIE_NODE(ps_audio_p): power-controller@278 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x278 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(audio_p); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_sio_adma): power-controller@280 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x280 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(sio_adma); ++ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_mca0): power-controller@288 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x288 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(mca0); ++ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; ++ }; ++ ++ DIE_NODE(ps_mca1): power-controller@290 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x290 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(mca1); ++ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; ++ }; ++ ++ DIE_NODE(ps_mca2): power-controller@298 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x298 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(mca2); ++ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; ++ }; ++ ++ DIE_NODE(ps_mca3): power-controller@2a0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(mca3); ++ power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; ++ }; ++ ++ DIE_NODE(ps_dpa0): power-controller@2a8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dpa0); ++ power-domains = <&DIE_NODE(ps_audio_p)>; ++ }; ++ ++ DIE_NODE(ps_dpa1): power-controller@2b0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dpa1); ++ power-domains = <&DIE_NODE(ps_audio_p)>; ++ }; ++ ++ DIE_NODE(ps_dpa2): power-controller@2b8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2b8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dpa2); ++ power-domains = <&DIE_NODE(ps_audio_p)>; ++ }; ++ ++ DIE_NODE(ps_dpa3): power-controller@2c0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2c0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dpa3); ++ power-domains = <&DIE_NODE(ps_audio_p)>; ++ }; ++ ++ DIE_NODE(ps_dpa4): power-controller@2c8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2c8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dpa4); ++ power-domains = <&DIE_NODE(ps_audio_p)>; ++ }; ++ ++ DIE_NODE(ps_aes): power-controller@2d0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2d0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(aes); ++ power-domains = <&DIE_NODE(ps_sio)>; ++ }; ++ ++ DIE_NODE(ps_amcc1): power-controller@2d8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2d8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(amcc1); ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ DIE_NODE(ps_amcc3): power-controller@2e0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2e0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(amcc3); ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ DIE_NODE(ps_dcs_04): power-controller@2e8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2e8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_04); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_05): power-controller@2f0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2f0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_05); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_06): power-controller@2f8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2f8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_06); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_07): power-controller@300 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x300 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_07); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_12): power-controller@308 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x308 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_12); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_13): power-controller@310 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x310 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_13); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_14): power-controller@318 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x318 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_14); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_15): power-controller@320 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x320 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_15); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_disp0_fe): power-controller@328 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x328 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(disp0_fe); ++ power-domains = <&DIE_NODE(ps_afnc2_lw0)>; ++ apple,always-on; /* TODO: figure out if we can enable PM here */ ++ }; ++ ++ DIE_NODE(ps_disp0_cpu0): power-controller@350 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x350 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(disp0_cpu0); ++ power-domains = <&DIE_NODE(ps_disp0_fe)>; ++ apple,always-on; /* TODO: figure out if we can enable PM here */ ++ apple,min-state = <4>; ++ }; ++ ++ DIE_NODE(ps_dispdfr_fe): power-controller@378 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x378 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispdfr_fe); ++ power-domains = <&DIE_NODE(ps_afnc2_lw1)>; ++ }; ++ ++ DIE_NODE(ps_dispdfr_be): power-controller@380 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x380 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispdfr_be); ++ power-domains = <&DIE_NODE(ps_dispdfr_fe)>; ++ }; ++ ++ DIE_NODE(ps_mipi_dsi): power-controller@388 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x388 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(mipi_dsi); ++ power-domains = <&DIE_NODE(ps_dispdfr_be)>; ++ }; ++ ++ DIE_NODE(ps_jpg): power-controller@390 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x390 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(jpg); ++ power-domains = <&DIE_NODE(ps_afr)>; ++ }; ++ ++ DIE_NODE(ps_msr0): power-controller@398 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x398 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(msr0); ++ power-domains = <&DIE_NODE(ps_afr)>; ++ }; ++ ++ DIE_NODE(ps_msr0_ase_core): power-controller@3a0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(msr0_ase_core); ++ power-domains = <&DIE_NODE(ps_msr0)>; ++ }; ++ ++ DIE_NODE(ps_isp_sys): power-controller@3a8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(isp_sys); ++ power-domains = <&DIE_NODE(ps_afnc2_lw1)>; ++ }; ++ ++ DIE_NODE(ps_venc_sys): power-controller@3b0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc_sys); ++ power-domains = <&DIE_NODE(ps_afr)>; ++ }; ++ ++ DIE_NODE(ps_ans2): power-controller@3b8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3b8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ans2); ++ /* ++ * The ADT makes ps_apcie_st[1]_sys depend on ps_ans2 instead, ++ * but we'd rather have a single power domain for the downstream ++ * device to depend on, so use this node as the child. ++ * This makes more sense anyway (since ANS2 uses APCIE_ST). ++ */ ++ power-domains = <&DIE_NODE(ps_afnc2_lw0)>; ++ }; ++ ++ DIE_NODE(ps_gfx): power-controller@3c0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3c0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(gfx); ++ power-domains = <&DIE_NODE(ps_afr)>; ++ }; ++ ++ DIE_NODE(ps_sep): power-controller@c00 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xc00 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(sep); ++ apple,always-on; /* Locked on */ ++ }; ++ ++ DIE_NODE(ps_venc_dma): power-controller@8000 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8000 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc_dma); ++ power-domains = <&DIE_NODE(ps_venc_sys)>; ++ }; ++ ++ DIE_NODE(ps_venc_pipe4): power-controller@8008 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8008 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc_pipe4); ++ power-domains = <&DIE_NODE(ps_venc_dma)>; ++ }; ++ ++ DIE_NODE(ps_venc_pipe5): power-controller@8010 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8010 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc_pipe5); ++ power-domains = <&DIE_NODE(ps_venc_dma)>; ++ }; ++ ++ DIE_NODE(ps_venc_me0): power-controller@8018 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8018 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc_me0); ++ power-domains = <&DIE_NODE(ps_venc_pipe5)>, <&DIE_NODE(ps_venc_pipe4)>; ++ }; ++ ++ DIE_NODE(ps_venc_me1): power-controller@8020 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8020 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc_me1); ++ power-domains = <&DIE_NODE(ps_venc_me0)>; ++ }; ++}; ++ ++&DIE_NODE(pmgr_south) { ++ DIE_NODE(ps_amcc4): power-controller@100 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x100 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(amcc4); ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ DIE_NODE(ps_amcc5): power-controller@108 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x108 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(amcc5); ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ DIE_NODE(ps_amcc6): power-controller@110 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x110 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(amcc6); ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ DIE_NODE(ps_amcc7): power-controller@118 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x118 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(amcc7); ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ DIE_NODE(ps_dcs_16): power-controller@120 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x120 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_16); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_17): power-controller@128 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x128 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_17); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_18): power-controller@130 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x130 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_18); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_19): power-controller@138 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x138 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_19); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_20): power-controller@140 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x140 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_20); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_21): power-controller@148 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x148 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_21); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_22): power-controller@150 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x150 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_22); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_23): power-controller@158 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x158 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_23); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_24): power-controller@160 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x160 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_24); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_25): power-controller@168 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x168 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_25); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_26): power-controller@170 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x170 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_26); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_27): power-controller@178 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x178 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_27); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_28): power-controller@180 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x180 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_28); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_29): power-controller@188 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x188 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_29); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_30): power-controller@190 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x190 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_30); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_dcs_31): power-controller@198 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x198 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dcs_31); ++ apple,always-on; /* LPDDR5 interface */ ++ }; ++ ++ DIE_NODE(ps_afnc4_ioa): power-controller@1a0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc4_ioa); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afi)>; ++ }; ++ ++ DIE_NODE(ps_afnc4_ls): power-controller@1a8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc4_ls); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc4_ioa)>; ++ }; ++ ++ DIE_NODE(ps_afnc4_lw0): power-controller@1b0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc4_lw0); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc4_ls)>; ++ }; ++ ++ DIE_NODE(ps_afnc5_ioa): power-controller@1b8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1b8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc5_ioa); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afi)>; ++ }; ++ ++ DIE_NODE(ps_afnc5_ls): power-controller@1c0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1c0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc5_ls); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc5_ioa)>; ++ }; ++ ++ DIE_NODE(ps_afnc5_lw0): power-controller@1c8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1c8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(afnc5_lw0); ++ apple,always-on; /* Apple Fabric */ ++ power-domains = <&DIE_NODE(ps_afnc5_ls)>; ++ }; ++ ++ DIE_NODE(ps_dispext2_fe): power-controller@1d0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1d0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispext2_fe); ++ power-domains = <&DIE_NODE(ps_afnc4_lw0)>; ++ }; ++ ++ DIE_NODE(ps_dispext2_cpu0): power-controller@1e8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1e8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispext2_cpu0); ++ power-domains = <&DIE_NODE(ps_dispext2_fe)>; ++ }; ++ ++ DIE_NODE(ps_dispext3_fe): power-controller@210 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x210 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispext3_fe); ++ power-domains = <&DIE_NODE(ps_afnc4_lw0)>; ++ }; ++ ++ DIE_NODE(ps_dispext3_cpu0): power-controller@228 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x228 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(dispext3_cpu0); ++ power-domains = <&DIE_NODE(ps_dispext3_fe)>; ++ }; ++ ++ DIE_NODE(ps_msr1): power-controller@250 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x250 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(msr1); ++ power-domains = <&DIE_NODE(ps_afnc5_lw0)>, <&DIE_NODE(ps_afr)>; ++ }; ++ ++ DIE_NODE(ps_msr1_ase_core): power-controller@258 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x258 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(msr1_ase_core); ++ power-domains = <&DIE_NODE(ps_msr1)>; ++ }; ++ ++ DIE_NODE(ps_venc1_sys): power-controller@260 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x260 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc1_sys); ++ power-domains = <&DIE_NODE(ps_afnc5_lw0)>, <&DIE_NODE(ps_afr)>; ++ }; ++ ++ /* Seems to be disabled on shipping hardware */ ++#if 0 ++ DIE_NODE(ps_ane1_sys): power-controller@268 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x268 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ane1_sys); ++ power-domains = <&DIE_NODE(ps_afnc5_lw0)>; ++ }; ++ ++ DIE_NODE(ps_ane1_sys_cpu): power-controller@270 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x270 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(ane1_sys_cpu); ++ power-domains = <&DIE_NODE(ps_ane1_sys)>; ++ }; ++#endif ++ ++ DIE_NODE(ps_venc1_dma): power-controller@8000 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8000 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc1_dma); ++ power-domains = <&DIE_NODE(ps_venc1_sys)>; ++ }; ++ ++ DIE_NODE(ps_venc1_pipe4): power-controller@8008 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8008 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc1_pipe4); ++ power-domains = <&DIE_NODE(ps_venc1_dma)>; ++ }; ++ ++ DIE_NODE(ps_venc1_pipe5): power-controller@8010 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8010 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc1_pipe5); ++ power-domains = <&DIE_NODE(ps_venc1_dma)>; ++ }; ++ ++ DIE_NODE(ps_venc1_me0): power-controller@8018 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8018 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc1_me0); ++ power-domains = <&DIE_NODE(ps_venc1_pipe4)>, <&DIE_NODE(ps_venc1_pipe5)>; ++ }; ++ ++ DIE_NODE(ps_venc1_me1): power-controller@8020 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8020 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(venc1_me1); ++ power-domains = <&DIE_NODE(ps_venc1_me0)>; ++ }; ++ ++ DIE_NODE(ps_prores): power-controller@c000 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xc000 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(prores); ++ power-domains = <&DIE_NODE(ps_afnc4_lw0)>; ++ }; ++}; ++ ++&DIE_NODE(pmgr_mini) { ++ DIE_NODE(ps_debug): power-controller@58 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x58 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(debug); ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ DIE_NODE(ps_nub_spmi0): power-controller@60 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x60 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(nub_spmi0); ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ DIE_NODE(ps_nub_spmi1): power-controller@68 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x68 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(nub_spmi1); ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ DIE_NODE(ps_nub_aon): power-controller@70 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x70 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(nub_aon); ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ DIE_NODE(ps_msg): power-controller@78 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x78 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(msg); ++ }; ++ ++ DIE_NODE(ps_nub_gpio): power-controller@80 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x80 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(nub_gpio); ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ DIE_NODE(ps_atc0_usb_aon): power-controller@88 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x88 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc0_usb_aon); ++ apple,always-on; /* Needs to stay on for dwc3 to work */ ++ }; ++ ++ DIE_NODE(ps_atc1_usb_aon): power-controller@90 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x90 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc1_usb_aon); ++ apple,always-on; /* Needs to stay on for dwc3 to work */ ++ }; ++ ++ DIE_NODE(ps_atc2_usb_aon): power-controller@98 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x98 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc2_usb_aon); ++ apple,always-on; /* Needs to stay on for dwc3 to work */ ++ }; ++ ++ DIE_NODE(ps_atc3_usb_aon): power-controller@a0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xa0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc3_usb_aon); ++ apple,always-on; /* Needs to stay on for dwc3 to work */ ++ }; ++ ++ DIE_NODE(ps_gp_usb_aon): power-controller@a8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xa8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(gp_usb_aon); ++ }; ++ ++ DIE_NODE(ps_nub_fabric): power-controller@b0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xb0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(nub_fabric); ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ DIE_NODE(ps_nub_sram): power-controller@b8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xb8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(nub_sram); ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ DIE_NODE(ps_debug_usb): power-controller@c0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xc0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(debug_usb); ++ apple,always-on; /* Core AON device */ ++ power-domains = <&DIE_NODE(ps_debug)>; ++ }; ++ ++ DIE_NODE(ps_debug_auth): power-controller@c8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xc8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(debug_auth); ++ apple,always-on; /* Core AON device */ ++ power-domains = <&DIE_NODE(ps_debug)>; ++ }; ++ ++ DIE_NODE(ps_atc0_usb): power-controller@d0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xd0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc0_usb); ++ power-domains = <&DIE_NODE(ps_atc0_usb_aon)>, <&DIE_NODE(ps_atc0_common)>; ++ }; ++ ++ DIE_NODE(ps_atc1_usb): power-controller@d8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xd8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc1_usb); ++ power-domains = <&DIE_NODE(ps_atc1_usb_aon)>, <&DIE_NODE(ps_atc1_common)>; ++ }; ++ ++ DIE_NODE(ps_atc2_usb): power-controller@e0 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xe0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc2_usb); ++ power-domains = <&DIE_NODE(ps_atc2_usb_aon)>, <&DIE_NODE(ps_atc2_common)>; ++ }; ++ ++ DIE_NODE(ps_atc3_usb): power-controller@e8 { ++ compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xe8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = DIE_LABEL(atc3_usb); ++ power-domains = <&DIE_NODE(ps_atc3_usb_aon)>, <&DIE_NODE(ps_atc3_common)>; ++ }; ++}; ++ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0017-arm64-dts-apple-Add-J314-and-J316-devicetrees.patch b/target/linux/silicon/patches-5.19/0017-arm64-dts-apple-Add-J314-and-J316-devicetrees.patch new file mode 100644 index 000000000..23f4c2405 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0017-arm64-dts-apple-Add-J314-and-J316-devicetrees.patch @@ -0,0 +1,250 @@ +From ea9e6404ec5b3f1ce636e0ac67293528b87c8578 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Wed, 10 Nov 2021 19:08:25 +0900 +Subject: [PATCH 017/171] arm64: dts: apple: Add J314 and J316 devicetrees + +These are the 14-inch and 16-inch 2021 MacBooks, in both M1 Pro and M1 +Max variants (t6000 and t6001). + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/Makefile | 4 + + arch/arm64/boot/dts/apple/t6000-j314s.dts | 18 +++ + arch/arm64/boot/dts/apple/t6000-j316s.dts | 18 +++ + arch/arm64/boot/dts/apple/t6001-j314c.dts | 18 +++ + arch/arm64/boot/dts/apple/t6001-j316c.dts | 18 +++ + .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 110 ++++++++++++++++++ + 6 files changed, 186 insertions(+) + create mode 100644 arch/arm64/boot/dts/apple/t6000-j314s.dts + create mode 100644 arch/arm64/boot/dts/apple/t6000-j316s.dts + create mode 100644 arch/arm64/boot/dts/apple/t6001-j314c.dts + create mode 100644 arch/arm64/boot/dts/apple/t6001-j316c.dts + create mode 100644 arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi + +diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile +index c0510c25ca6a..b021931b0a17 100644 +--- a/arch/arm64/boot/dts/apple/Makefile ++++ b/arch/arm64/boot/dts/apple/Makefile +@@ -4,3 +4,7 @@ dtb-$(CONFIG_ARCH_APPLE) += t8103-j293.dtb + dtb-$(CONFIG_ARCH_APPLE) += t8103-j313.dtb + dtb-$(CONFIG_ARCH_APPLE) += t8103-j456.dtb + dtb-$(CONFIG_ARCH_APPLE) += t8103-j457.dtb ++dtb-$(CONFIG_ARCH_APPLE) += t6000-j314s.dtb ++dtb-$(CONFIG_ARCH_APPLE) += t6001-j314c.dtb ++dtb-$(CONFIG_ARCH_APPLE) += t6000-j316s.dtb ++dtb-$(CONFIG_ARCH_APPLE) += t6001-j316c.dtb +diff --git a/arch/arm64/boot/dts/apple/t6000-j314s.dts b/arch/arm64/boot/dts/apple/t6000-j314s.dts +new file mode 100644 +index 000000000000..c9e192848fe3 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6000-j314s.dts +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * MacBook Pro (14-inch, M1 Pro, 2021) ++ * ++ * target-type: J314s ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/dts-v1/; ++ ++#include "t6000.dtsi" ++#include "t600x-j314-j316.dtsi" ++ ++/ { ++ compatible = "apple,j314s", "apple,t6000", "apple,arm-platform"; ++ model = "Apple MacBook Pro (14-inch, M1 Pro, 2021)"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6000-j316s.dts b/arch/arm64/boot/dts/apple/t6000-j316s.dts +new file mode 100644 +index 000000000000..ff1803ce2300 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6000-j316s.dts +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * MacBook Pro (16-inch, M1 Pro, 2021) ++ * ++ * target-type: J316s ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/dts-v1/; ++ ++#include "t6000.dtsi" ++#include "t600x-j314-j316.dtsi" ++ ++/ { ++ compatible = "apple,j316s", "apple,t6000", "apple,arm-platform"; ++ model = "Apple MacBook Pro (16-inch, M1 Pro, 2021)"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6001-j314c.dts b/arch/arm64/boot/dts/apple/t6001-j314c.dts +new file mode 100644 +index 000000000000..1761d15b98c1 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6001-j314c.dts +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * MacBook Pro (14-inch, M1 Max, 2021) ++ * ++ * target-type: J314c ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/dts-v1/; ++ ++#include "t6001.dtsi" ++#include "t600x-j314-j316.dtsi" ++ ++/ { ++ compatible = "apple,j314c", "apple,t6001", "apple,arm-platform"; ++ model = "Apple MacBook Pro (14-inch, M1 Max, 2021)"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6001-j316c.dts b/arch/arm64/boot/dts/apple/t6001-j316c.dts +new file mode 100644 +index 000000000000..750e9beeffc0 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6001-j316c.dts +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * MacBook Pro (16-inch, M1 Max, 2021) ++ * ++ * target-type: J316c ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/dts-v1/; ++ ++#include "t6001.dtsi" ++#include "t600x-j314-j316.dtsi" ++ ++/ { ++ compatible = "apple,j316c", "apple,t6001", "apple,arm-platform"; ++ model = "Apple MacBook Pro (16-inch, M1 Max, 2021)"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +new file mode 100644 +index 000000000000..8079200aeb12 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -0,0 +1,110 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * MacBook Pro (14/16-inch, 2021) ++ * ++ * This file contains the parts common to J314 and J316 devices with both t6000 and t6001. ++ * ++ * target-type: J314s / J314c / J316s / J316c ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/ { ++ aliases { ++ serial0 = &serial0; ++ wifi0 = &wifi0; ++ }; ++ ++ chosen { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ stdout-path = "serial0"; ++ ++ framebuffer0: framebuffer@0 { ++ compatible = "apple,simple-framebuffer", "simple-framebuffer"; ++ reg = <0 0 0 0>; /* To be filled by loader */ ++ /* Format properties will be added by loader */ ++ status = "disabled"; ++ }; ++ }; ++ ++ memory@10000000000 { ++ device_type = "memory"; ++ reg = <0x100 0 0x2 0>; /* To be filled by loader */ ++ }; ++}; ++ ++&serial0 { ++ status = "okay"; ++}; ++ ++/* USB Type C */ ++&i2c0 { ++ hpm0: usb-pd@38 { ++ compatible = "apple,cd321x"; ++ reg = <0x38>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ hpm1: usb-pd@3f { ++ compatible = "apple,cd321x"; ++ reg = <0x3f>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ hpm2: usb-pd@3b { ++ compatible = "apple,cd321x"; ++ reg = <0x3b>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ /* MagSafe port */ ++ hpm5: usb-pd@3a { ++ compatible = "apple,cd321x"; ++ reg = <0x3a>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++}; ++ ++/* PCIe devices */ ++&port00 { ++ /* WLAN */ ++ bus-range = <1 1>; ++ wifi0: wifi@0,0 { ++ reg = <0x10000 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-mac-address = [00 10 18 00 00 10]; ++ }; ++}; ++ ++&port01 { ++ /* SD card reader */ ++ bus-range = <2 2>; ++ sdhci0: mmc@0,0 { ++ compatible = "pci17a0,9755"; ++ reg = <0x20000 0x0 0x0 0x0 0x0>; ++ cd-inverted; ++ wp-inverted; ++ }; ++}; ++ ++&pcie0_dart_2 { ++ status = "disabled"; ++}; ++ ++&pcie0_dart_3 { ++ status = "disabled"; ++}; ++ ++/delete-node/ &port02; ++/delete-node/ &port03; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0018-arm64-dts-apple-Add-devicetree-for-Apple-Mac-Studio-.patch b/target/linux/silicon/patches-5.19/0018-arm64-dts-apple-Add-devicetree-for-Apple-Mac-Studio-.patch new file mode 100644 index 000000000..ffc230aa0 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0018-arm64-dts-apple-Add-devicetree-for-Apple-Mac-Studio-.patch @@ -0,0 +1,149 @@ +From ab01e260000502f8e1f814e05fcbf35667cc1167 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Tue, 3 May 2022 22:05:25 +0200 +Subject: [PATCH 018/171] arm64: dts: apple: Add devicetree for Apple Mac + Studio M1 Max + +Signed-off-by: Janne Grunau +--- + arch/arm64/boot/dts/apple/Makefile | 1 + + arch/arm64/boot/dts/apple/t6001-j375c.dts | 118 ++++++++++++++++++++++ + 2 files changed, 119 insertions(+) + create mode 100644 arch/arm64/boot/dts/apple/t6001-j375c.dts + +diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile +index b021931b0a17..b3ed42594ecd 100644 +--- a/arch/arm64/boot/dts/apple/Makefile ++++ b/arch/arm64/boot/dts/apple/Makefile +@@ -8,3 +8,4 @@ dtb-$(CONFIG_ARCH_APPLE) += t6000-j314s.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6001-j314c.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6000-j316s.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6001-j316c.dtb ++dtb-$(CONFIG_ARCH_APPLE) += t6001-j375c.dtb +diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts +new file mode 100644 +index 000000000000..961104d6bd9a +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts +@@ -0,0 +1,118 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Mac Studio (M1 Max, 2022) ++ * ++ * target-type: J375c ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/dts-v1/; ++ ++#include "t6001.dtsi" ++ ++/ { ++ compatible = "apple,j375c", "apple,t6001", "apple,arm-platform"; ++ model = "Apple Mac Studio (M1 Max, 2022)"; ++ ++ aliases { ++ serial0 = &serial0; ++ wifi0 = &wifi0; ++ }; ++ ++ chosen { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ stdout-path = "serial0"; ++ ++ framebuffer0: framebuffer@0 { ++ compatible = "apple,simple-framebuffer", "simple-framebuffer"; ++ reg = <0 0 0 0>; /* To be filled by loader */ ++ /* Format properties will be added by loader */ ++ status = "disabled"; ++ }; ++ }; ++ ++ memory@10000000000 { ++ device_type = "memory"; ++ reg = <0x100 0 0x2 0>; /* To be filled by loader */ ++ }; ++}; ++ ++&serial0 { ++ status = "okay"; ++}; ++ ++/* USB Type C */ ++&i2c0 { ++ hpm0: usb-pd@38 { ++ compatible = "apple,cd321x"; ++ reg = <0x38>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ hpm1: usb-pd@3f { ++ compatible = "apple,cd321x"; ++ reg = <0x3f>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ hpm2: usb-pd@3b { ++ compatible = "apple,cd321x"; ++ reg = <0x3b>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ hpm3: usb-pd@3c { ++ compatible = "apple,cd321x"; ++ reg = <0x3c>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++}; ++ ++/* PCIe devices */ ++&port00 { ++ /* WLAN */ ++ bus-range = <1 1>; ++ wifi0: wifi@0,0 { ++ reg = <0x10000 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-mac-address = [00 10 18 00 00 10]; ++ }; ++}; ++ ++&port01 { ++ /* SD card reader */ ++ bus-range = <2 2>; ++ sdhci0: mmc@0,0 { ++ compatible = "pci17a0,9755"; ++ reg = <0x20000 0x0 0x0 0x0 0x0>; ++ cd-inverted; ++ wp-inverted; ++ }; ++}; ++ ++&port02 { ++ /* 10 Gbit Ethernet */ ++ bus-range = <3 3>; ++ ethernet0: ethernet@0,0 { ++ reg = <0x30000 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-mac-address = [00 10 18 00 00 00]; ++ }; ++}; ++ ++&port03 { ++ /* USB xHCI */ ++ bus-range = <4 4>; ++}; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0019-arm64-dts-apple-Add-devicetree-for-Apple-Mac-Studio-.patch b/target/linux/silicon/patches-5.19/0019-arm64-dts-apple-Add-devicetree-for-Apple-Mac-Studio-.patch new file mode 100644 index 000000000..1b68e4252 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0019-arm64-dts-apple-Add-devicetree-for-Apple-Mac-Studio-.patch @@ -0,0 +1,178 @@ +From 973a9df0042bad7ee5fa7534f4d74f6f5d44f1c8 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Thu, 24 Mar 2022 17:04:24 +0100 +Subject: [PATCH 019/171] arm64: dts: apple: Add devicetree for Apple Mac + Studio M1 Ultra + +Signed-off-by: Janne Grunau +--- + arch/arm64/boot/dts/apple/Makefile | 1 + + arch/arm64/boot/dts/apple/t6002-j375d.dts | 147 ++++++++++++++++++++++ + 2 files changed, 148 insertions(+) + create mode 100644 arch/arm64/boot/dts/apple/t6002-j375d.dts + +diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile +index b3ed42594ecd..5a7506ff5ea3 100644 +--- a/arch/arm64/boot/dts/apple/Makefile ++++ b/arch/arm64/boot/dts/apple/Makefile +@@ -9,3 +9,4 @@ dtb-$(CONFIG_ARCH_APPLE) += t6001-j314c.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6000-j316s.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6001-j316c.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6001-j375c.dtb ++dtb-$(CONFIG_ARCH_APPLE) += t6002-j375d.dtb +diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts +new file mode 100644 +index 000000000000..95e0c3243818 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts +@@ -0,0 +1,147 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Mac Studio (M1 Ultra, 2022) ++ * ++ * target-type: J375d ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/dts-v1/; ++ ++#include "t6002.dtsi" ++ ++/ { ++ compatible = "apple,j375d", "apple,t6002", "apple,arm-platform"; ++ model = "Apple Mac Studio (M1 Ultra, 2022)"; ++ ++ aliases { ++ serial0 = &serial0; ++ wifi0 = &wifi0; ++ }; ++ ++ chosen { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ stdout-path = "serial0"; ++ ++ framebuffer0: framebuffer@0 { ++ compatible = "apple,simple-framebuffer", "simple-framebuffer"; ++ reg = <0 0 0 0>; /* To be filled by loader */ ++ /* Format properties will be added by loader */ ++ status = "disabled"; ++ }; ++ }; ++ ++ memory@10000000000 { ++ device_type = "memory"; ++ reg = <0x100 0 0x2 0>; /* To be filled by loader */ ++ }; ++}; ++ ++&serial0 { ++ status = "okay"; ++}; ++ ++/* USB Type C */ ++&i2c0 { ++ hpm0: usb-pd@38 { ++ compatible = "apple,cd321x"; ++ reg = <0x38>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ hpm1: usb-pd@3f { ++ compatible = "apple,cd321x"; ++ reg = <0x3f>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ hpm2: usb-pd@3b { ++ compatible = "apple,cd321x"; ++ reg = <0x3b>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ hpm3: usb-pd@3c { ++ compatible = "apple,cd321x"; ++ reg = <0x3c>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ /* front-right */ ++ hpm4: usb-pd@39 { ++ compatible = "apple,cd321x"; ++ reg = <0x39>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++ ++ /* front-left */ ++ hpm5: usb-pd@3a { ++ compatible = "apple,cd321x"; ++ reg = <0x3a>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++}; ++ ++/* PCIe devices */ ++&port00 { ++ /* WLAN */ ++ bus-range = <1 1>; ++ wifi0: wifi@0,0 { ++ reg = <0x10000 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-mac-address = [00 10 18 00 00 10]; ++ }; ++}; ++ ++&port01 { ++ /* SD card reader */ ++ bus-range = <2 2>; ++ sdhci0: mmc@0,0 { ++ compatible = "pci17a0,9755"; ++ reg = <0x20000 0x0 0x0 0x0 0x0>; ++ cd-inverted; ++ wp-inverted; ++ }; ++}; ++ ++&port02 { ++ /* 10 Gbit Ethernet */ ++ bus-range = <3 3>; ++ ethernet0: ethernet@0,0 { ++ reg = <0x30000 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-mac-address = [00 10 18 00 00 00]; ++ }; ++}; ++ ++&port03 { ++ /* USB xHCI */ ++ bus-range = <4 4>; ++}; ++ ++/* delete unused always-on power-domains on die 1 */ ++ ++/delete-node/ &ps_atc2_usb_aon_die1; ++/delete-node/ &ps_atc2_usb_die1; ++ ++/delete-node/ &ps_atc3_usb_aon_die1; ++/delete-node/ &ps_atc3_usb_die1; ++ ++/delete-node/ &ps_disp0_cpu0_die1; ++/delete-node/ &ps_disp0_fe_die1; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0020-arm64-dts-apple-Add-CPUfreq-nodes-for-t6001.patch b/target/linux/silicon/patches-5.19/0020-arm64-dts-apple-Add-CPUfreq-nodes-for-t6001.patch new file mode 100644 index 000000000..a73338cc5 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0020-arm64-dts-apple-Add-CPUfreq-nodes-for-t6001.patch @@ -0,0 +1,486 @@ +From 0bea0800d5e0e32323bbbe2b2edfe16e08116bc9 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 21:34:10 +0900 +Subject: [PATCH 020/171] arm64: dts: apple: Add CPUfreq nodes for t6001 + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t6001.dtsi | 7 + + arch/arm64/boot/dts/apple/t6002.dtsi | 81 +++++++++ + arch/arm64/boot/dts/apple/t600x-common.dtsi | 188 ++++++++++++++++++++ + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 4 + + 4 files changed, 280 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi +index 620b17e4031f..832e9bedc1fb 100644 +--- a/arch/arm64/boot/dts/apple/t6001.dtsi ++++ b/arch/arm64/boot/dts/apple/t6001.dtsi +@@ -47,6 +47,13 @@ soc { + #undef DIE_NO + + ++&cpufreq_hw { ++ reg = <0x2 0x10e20000 0 0x1000>, ++ <0x2 0x11e20000 0 0x1000>, ++ <0x2 0x12e20000 0 0x1000>; ++ reg-names = "cluster0", "cluster1", "cluster2"; ++}; ++ + &aic { + affinities { + e-core-pmu-affinity { +diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi +index 736f16aad70f..f3618df00518 100644 +--- a/arch/arm64/boot/dts/apple/t6002.dtsi ++++ b/arch/arm64/boot/dts/apple/t6002.dtsi +@@ -23,12 +23,56 @@ / { + #size-cells = <2>; + + cpus { ++ cpu-map { ++ cluster3 { ++ core0 { ++ cpu = <&cpu_e10>; ++ }; ++ core1 { ++ cpu = <&cpu_e11>; ++ }; ++ }; ++ ++ cluster4 { ++ core0 { ++ cpu = <&cpu_p20>; ++ }; ++ core1 { ++ cpu = <&cpu_p21>; ++ }; ++ core2 { ++ cpu = <&cpu_p22>; ++ }; ++ core3 { ++ cpu = <&cpu_p23>; ++ }; ++ }; ++ ++ cluster5 { ++ core0 { ++ cpu = <&cpu_p30>; ++ }; ++ core1 { ++ cpu = <&cpu_p31>; ++ }; ++ core2 { ++ cpu = <&cpu_p32>; ++ }; ++ core3 { ++ cpu = <&cpu_p33>; ++ }; ++ }; ++ }; ++ + cpu_e10: cpu@800 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x800>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&icestorm_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 3>; + }; + + cpu_e11: cpu@801 { +@@ -37,6 +81,9 @@ cpu_e11: cpu@801 { + reg = <0x0 0x801>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&icestorm_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 3>; + }; + + cpu_p20: cpu@10900 { +@@ -45,6 +92,9 @@ cpu_p20: cpu@10900 { + reg = <0x0 0x10900>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 4>; + }; + + cpu_p21: cpu@10901 { +@@ -53,6 +103,9 @@ cpu_p21: cpu@10901 { + reg = <0x0 0x10901>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 4>; + }; + + cpu_p22: cpu@10902 { +@@ -61,6 +114,9 @@ cpu_p22: cpu@10902 { + reg = <0x0 0x10902>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 4>; + }; + + cpu_p23: cpu@10903 { +@@ -69,6 +125,9 @@ cpu_p23: cpu@10903 { + reg = <0x0 0x10903>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 4>; + }; + + cpu_p30: cpu@10a00 { +@@ -77,6 +136,9 @@ cpu_p30: cpu@10a00 { + reg = <0x0 0x10a00>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 5>; + }; + + cpu_p31: cpu@10a01 { +@@ -85,6 +147,9 @@ cpu_p31: cpu@10a01 { + reg = <0x0 0x10a01>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 5>; + }; + + cpu_p32: cpu@10a02 { +@@ -93,6 +158,9 @@ cpu_p32: cpu@10a02 { + reg = <0x0 0x10a02>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 5>; + }; + + cpu_p33: cpu@10a03 { +@@ -101,6 +169,9 @@ cpu_p33: cpu@10a03 { + reg = <0x0 0x10a03>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 5>; + }; + }; + +@@ -162,6 +233,16 @@ die1 { + #undef DIE + #undef DIE_NO + ++&cpufreq_hw { ++ reg = <0x2 0x10e20000 0 0x1000>, ++ <0x2 0x11e20000 0 0x1000>, ++ <0x2 0x12e20000 0 0x1000>, ++ <0x22 0x10e20000 0 0x1000>, ++ <0x22 0x11e20000 0 0x1000>, ++ <0x22 0x12e20000 0 0x1000>; ++ reg-names = "cluster0", "cluster1", "cluster2", ++ "cluster3", "cluster4", "cluster5"; ++}; + + &aic { + affinities { +diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi +index e29b88e2c853..06e160880407 100644 +--- a/arch/arm64/boot/dts/apple/t600x-common.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi +@@ -15,12 +15,56 @@ cpus { + #address-cells = <2>; + #size-cells = <0>; + ++ cpu-map { ++ cluster0 { ++ core0 { ++ cpu = <&cpu_e00>; ++ }; ++ core1 { ++ cpu = <&cpu_e01>; ++ }; ++ }; ++ ++ cluster1 { ++ core0 { ++ cpu = <&cpu_p00>; ++ }; ++ core1 { ++ cpu = <&cpu_p01>; ++ }; ++ core2 { ++ cpu = <&cpu_p02>; ++ }; ++ core3 { ++ cpu = <&cpu_p03>; ++ }; ++ }; ++ ++ cluster2 { ++ core0 { ++ cpu = <&cpu_p10>; ++ }; ++ core1 { ++ cpu = <&cpu_p11>; ++ }; ++ core2 { ++ cpu = <&cpu_p12>; ++ }; ++ core3 { ++ cpu = <&cpu_p13>; ++ }; ++ }; ++ }; ++ + cpu_e00: cpu@0 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&icestorm_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + + cpu_e01: cpu@1 { +@@ -29,6 +73,9 @@ cpu_e01: cpu@1 { + reg = <0x0 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&icestorm_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + + cpu_p00: cpu@10100 { +@@ -37,6 +84,9 @@ cpu_p00: cpu@10100 { + reg = <0x0 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + + cpu_p01: cpu@10101 { +@@ -45,6 +95,9 @@ cpu_p01: cpu@10101 { + reg = <0x0 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + + cpu_p02: cpu@10102 { +@@ -53,6 +106,9 @@ cpu_p02: cpu@10102 { + reg = <0x0 0x10102>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + + cpu_p03: cpu@10103 { +@@ -61,6 +117,9 @@ cpu_p03: cpu@10103 { + reg = <0x0 0x10103>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + + cpu_p10: cpu@10200 { +@@ -69,6 +128,9 @@ cpu_p10: cpu@10200 { + reg = <0x0 0x10200>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 2>; + }; + + cpu_p11: cpu@10201 { +@@ -77,6 +139,9 @@ cpu_p11: cpu@10201 { + reg = <0x0 0x10201>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 2>; + }; + + cpu_p12: cpu@10202 { +@@ -85,6 +150,9 @@ cpu_p12: cpu@10202 { + reg = <0x0 0x10202>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 2>; + }; + + cpu_p13: cpu@10203 { +@@ -93,7 +161,127 @@ cpu_p13: cpu@10203 { + reg = <0x0 0x10203>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&firestorm_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 2>; ++ }; ++ }; ++ ++ icestorm_opp: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <7500>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <972000000>; ++ opp-level = <2>; ++ clock-latency-ns = <23000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <1332000000>; ++ opp-level = <3>; ++ clock-latency-ns = <29000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-level = <4>; ++ clock-latency-ns = <40000>; ++ }; ++ opp05 { ++ opp-hz = /bits/ 64 <2064000000>; ++ opp-level = <5>; ++ clock-latency-ns = <50000>; ++ }; ++ }; ++ ++ firestorm_opp: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <8000>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <828000000>; ++ opp-level = <2>; ++ clock-latency-ns = <18000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <1056000000>; ++ opp-level = <3>; ++ clock-latency-ns = <19000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <1296000000>; ++ opp-level = <4>; ++ clock-latency-ns = <23000>; ++ }; ++ opp05 { ++ opp-hz = /bits/ 64 <1524000000>; ++ opp-level = <5>; ++ clock-latency-ns = <24000>; ++ }; ++ opp06 { ++ opp-hz = /bits/ 64 <1752000000>; ++ opp-level = <6>; ++ clock-latency-ns = <28000>; ++ }; ++ opp07 { ++ opp-hz = /bits/ 64 <1980000000>; ++ opp-level = <7>; ++ clock-latency-ns = <31000>; ++ }; ++ opp08 { ++ opp-hz = /bits/ 64 <2208000000>; ++ opp-level = <8>; ++ clock-latency-ns = <45000>; ++ }; ++ opp09 { ++ opp-hz = /bits/ 64 <2448000000>; ++ opp-level = <9>; ++ clock-latency-ns = <49000>; ++ }; ++ opp10 { ++ opp-hz = /bits/ 64 <2676000000>; ++ opp-level = <10>; ++ clock-latency-ns = <53000>; ++ }; ++ opp11 { ++ opp-hz = /bits/ 64 <2904000000>; ++ opp-level = <11>; ++ clock-latency-ns = <56000>; ++ }; ++ opp12 { ++ opp-hz = /bits/ 64 <3036000000>; ++ opp-level = <12>; ++ clock-latency-ns = <56000>; ++ }; ++ /* Not available until CPU deep sleep is implemented ++ opp13 { ++ opp-hz = /bits/ 64 <3132000000>; ++ opp-level = <13>; ++ clock-latency-ns = <56000>; ++ turbo-mode; ++ }; ++ opp14 { ++ opp-hz = /bits/ 64 <3168000000>; ++ opp-level = <14>; ++ clock-latency-ns = <56000>; ++ turbo-mode; ++ }; ++ opp15 { ++ opp-hz = /bits/ 64 <3228000000>; ++ opp-level = <15>; ++ clock-latency-ns = <56000>; ++ turbo-mode; + }; ++ */ + }; + + pmu-e { +diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +index 8131352e3ccd..129984bd9a8b 100644 +--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +@@ -6,6 +6,10 @@ + * Copyright The Asahi Linux Contributors + */ + ++ cpufreq_hw: cpufreq@210e20000 { ++ compatible = "apple,t6000-soc-cpufreq", "apple,soc-cpufreq"; ++ #freq-domain-cells = <1>; ++ }; + + aic: interrupt-controller@28e100000 { + compatible = "apple,t6000-aic", "apple,aic2"; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0021-arm64-dts-apple-Add-SMC-node-to-t600x-devicetrees.patch b/target/linux/silicon/patches-5.19/0021-arm64-dts-apple-Add-SMC-node-to-t600x-devicetrees.patch new file mode 100644 index 000000000..a203802cc --- /dev/null +++ b/target/linux/silicon/patches-5.19/0021-arm64-dts-apple-Add-SMC-node-to-t600x-devicetrees.patch @@ -0,0 +1,50 @@ +From 7946dbabbfec3116b542268cbb3dcb6b4a5bd9c2 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 4 Feb 2022 12:59:39 +0900 +Subject: [PATCH 021/171] arm64: dts: apple: Add SMC node to t600x devicetrees + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 26 +++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +index 129984bd9a8b..6c9649d5a26c 100644 +--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +@@ -21,6 +21,32 @@ aic: interrupt-controller@28e100000 { + power-domains = <&ps_aic>; + }; + ++ smc_mbox: mbox@290408000 { ++ compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; ++ reg = <0x2 0x90408000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "send-empty", "send-not-empty", ++ "recv-empty", "recv-not-empty"; ++ #mbox-cells = <0>; ++ }; ++ ++ smc: smc@290400000 { ++ compatible = "apple,t6000-smc", "apple,smc"; ++ reg = <0x2 0x90400000 0x0 0x4000>, ++ <0x2 0x91e00000 0x0 0x100000>; ++ reg-names = "smc", "sram"; ++ mboxes = <&smc_mbox>; ++ ++ smc_gpio: gpio { ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ + pinctrl_smc: pinctrl@290820000 { + compatible = "apple,t6000-pinctrl", "apple,pinctrl"; + reg = <0x2 0x90820000 0x0 0x4000>; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0022-arm64-dts-apple-Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch b/target/linux/silicon/patches-5.19/0022-arm64-dts-apple-Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch new file mode 100644 index 000000000..514b2b1b9 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0022-arm64-dts-apple-Add-PMU-NVMEM-and-SMC-RTC-reboot-nod.patch @@ -0,0 +1,145 @@ +From d2759ec3852ae04e5a6a87d78dd5a52e67e36bbf Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 18:54:35 +0900 +Subject: [PATCH 022/171] arm64: dts: apple: Add PMU NVMEM and SMC RTC/reboot + nodes + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t6001.dtsi | 1 + + arch/arm64/boot/dts/apple/t6002.dtsi | 1 + + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 87 +++++++++++++++++++++++ + 3 files changed, 89 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi +index 832e9bedc1fb..6b50a9fa68e7 100644 +--- a/arch/arm64/boot/dts/apple/t6001.dtsi ++++ b/arch/arm64/boot/dts/apple/t6001.dtsi +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "multi-die-cpp.h" + +diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi +index f3618df00518..31e2de7fb2ea 100644 +--- a/arch/arm64/boot/dts/apple/t6002.dtsi ++++ b/arch/arm64/boot/dts/apple/t6002.dtsi +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "multi-die-cpp.h" + +diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +index 6c9649d5a26c..928da6734371 100644 +--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +@@ -45,6 +45,18 @@ smc_gpio: gpio { + gpio-controller; + #gpio-cells = <2>; + }; ++ ++ smc_rtc: rtc { ++ nvmem-cells = <&rtc_offset>; ++ nvmem-cell-names = "rtc_offset"; ++ }; ++ ++ smc_reboot: reboot { ++ nvmem-cells = <&shutdown_flag>, <&boot_stage>, ++ <&boot_error_count>, <&panic_count>, <&pm_setting>; ++ nvmem-cell-names = "shutdown_flag", "boot_stage", ++ "boot_error_count", "panic_count", "pm_setting"; ++ }; + }; + + pinctrl_smc: pinctrl@290820000 { +@@ -76,6 +88,81 @@ wdt: watchdog@2922b0000 { + interrupts = ; + }; + ++ nub_spmi0: spmi@2920a1300 { ++ compatible = "apple,t6000-spmi", "apple,spmi"; ++ reg = <0x2 0x920a1300 0x0 0x100>; ++ #address-cells = <2>; ++ #size-cells = <0>; ++ ++ pmu1: pmu@f { ++ compatible = "apple,maverick-pmu", "apple,spmi-pmu"; ++ reg = <0xf SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ rtc_nvmem@1400 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0x1400 0x20>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ pm_setting: pm-setting@5 { ++ reg = <0x5 0x1>; ++ }; ++ ++ rtc_offset: rtc-offset@11 { ++ reg = <0x11 0x6>; ++ }; ++ }; ++ ++ legacy_nvmem@6000 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0x6000 0x20>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ boot_stage: boot-stage@1 { ++ reg = <0x1 0x1>; ++ }; ++ ++ boot_error_count: boot-error-count@2 { ++ reg = <0x2 0x1>; ++ bits = <0 4>; ++ }; ++ ++ panic_count: panic-count@2 { ++ reg = <0x2 0x1>; ++ bits = <4 4>; ++ }; ++ ++ boot_error_stage: boot-error-stage@3 { ++ reg = <0x3 0x1>; ++ }; ++ ++ shutdown_flag: shutdown-flag@f { ++ reg = <0xf 0x1>; ++ bits = <3 1>; ++ }; ++ }; ++ ++ scrpad_nvmem@8000 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0x8000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ fault_shadow: fault-shadow@67b { ++ reg = <0x67b 0x10>; ++ }; ++ ++ socd: socd@b00 { ++ reg = <0xb00 0x400>; ++ }; ++ }; ++ ++ }; ++ }; ++ + i2c0: i2c@39b040000 { + compatible = "apple,t6000-i2c", "apple,i2c"; + reg = <0x3 0x9b040000 0x0 0x4000>; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0023-arm64-dts-apple-t6000-Add-spi1-node.patch b/target/linux/silicon/patches-5.19/0023-arm64-dts-apple-t6000-Add-spi1-node.patch new file mode 100644 index 000000000..400c56cee --- /dev/null +++ b/target/linux/silicon/patches-5.19/0023-arm64-dts-apple-t6000-Add-spi1-node.patch @@ -0,0 +1,74 @@ +From b04e8cf77375704a101a7bcaa485973702cbbc92 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 9 Dec 2021 21:58:10 +0900 +Subject: [PATCH 023/171] arm64: dts: apple: t6000: Add spi1 node + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t600x-common.dtsi | 7 +++++++ + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 14 ++++++++++++++ + arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi | 7 +++++++ + 3 files changed, 28 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi +index 06e160880407..c5ee0c2da778 100644 +--- a/arch/arm64/boot/dts/apple/t600x-common.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi +@@ -313,4 +313,11 @@ clkref: clock-ref { + clock-output-names = "clkref"; + }; + ++ clk_200m: clock-200m { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <200000000>; ++ clock-output-names = "clk_200m"; ++ }; ++ + }; +diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +index 928da6734371..96f8c2189f03 100644 +--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +@@ -246,6 +246,20 @@ i2c5: i2c@39b054000 { + status = "disabled"; + }; + ++ spi1: spi@39b104000 { ++ compatible = "apple,t6000-spi", "apple,spi"; ++ reg = <0x3 0x9b104000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk_200m>; ++ pinctrl-0 = <&spi1_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_spi1>; ++ status = "disabled"; ++ }; ++ + serial0: serial@39b200000 { + compatible = "apple,s5l-uart"; + reg = <0x3 0x9b200000 0x0 0x1000>; +diff --git a/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi b/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi +index b31f1a7a2b3f..855dcf30a502 100644 +--- a/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi +@@ -36,6 +36,13 @@ i2c5_pins: i2c5-pins { + ; + }; + ++ spi1_pins: spi1-pins { ++ pinmux = , ++ , ++ , ++ ; ++ }; ++ + pcie_pins: pcie-pins { + pinmux = , + , +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0024-arm64-dts-apple-t600x-j314-j316-Add-NOR-flash-node.patch b/target/linux/silicon/patches-5.19/0024-arm64-dts-apple-t600x-j314-j316-Add-NOR-flash-node.patch new file mode 100644 index 000000000..bef7a0f32 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0024-arm64-dts-apple-t600x-j314-j316-Add-NOR-flash-node.patch @@ -0,0 +1,37 @@ +From e2a083f709ff6669836587d592b313d7349d0525 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 9 Dec 2021 21:58:29 +0900 +Subject: [PATCH 024/171] arm64: dts: apple: t600x-j314-j316: Add NOR flash + node + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +index 8079200aeb12..55457892c38e 100644 +--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -76,6 +76,18 @@ hpm5: usb-pd@3a { + }; + }; + ++&spi1 { ++ status = "disabled"; ++ ++ flash@0 { ++ compatible = "jedec,spi-nor"; ++ reg = <0x0>; ++ spi-max-frequency = <25000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++}; ++ + /* PCIe devices */ + &port00 { + /* WLAN */ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0025-arm64-dts-apple-t600x-Add-spi3-node.patch b/target/linux/silicon/patches-5.19/0025-arm64-dts-apple-t600x-Add-spi3-node.patch new file mode 100644 index 000000000..8fc71f522 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0025-arm64-dts-apple-t600x-Add-spi3-node.patch @@ -0,0 +1,60 @@ +From 2beaa67dcf1275232f6f52f104d321818289c159 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Thu, 11 Nov 2021 21:31:21 +0100 +Subject: [PATCH 025/171] arm64: dts: apple: t600x: Add spi3 node + +Used for keyboard and touchpad input on MacBook Pro (14/16-inch, +M1 Pro/Max, 2021). + +Signed-off-by: Janne Grunau +--- + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 14 ++++++++++++++ + arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi | 7 +++++++ + 2 files changed, 21 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +index 96f8c2189f03..b549059a3320 100644 +--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +@@ -260,6 +260,20 @@ spi1: spi@39b104000 { + status = "disabled"; + }; + ++ spi3: spi@39b10c000 { ++ compatible = "apple,t6000-spi", "apple,spi"; ++ reg = <0x3 0x9b10c000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkref>; ++ pinctrl-0 = <&spi3_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_spi3>; ++ status = "disabled"; ++ }; ++ + serial0: serial@39b200000 { + compatible = "apple,s5l-uart"; + reg = <0x3 0x9b200000 0x0 0x1000>; +diff --git a/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi b/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi +index 855dcf30a502..1a994c3c1b79 100644 +--- a/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-gpio-pins.dtsi +@@ -43,6 +43,13 @@ spi1_pins: spi1-pins { + ; + }; + ++ spi3_pins: spi3-pins { ++ pinmux = , ++ , ++ , ++ ; ++ }; ++ + pcie_pins: pcie-pins { + pinmux = , + , +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0026-arm64-dts-apple-j31-46-Add-keyboard-nodes.patch b/target/linux/silicon/patches-5.19/0026-arm64-dts-apple-j31-46-Add-keyboard-nodes.patch new file mode 100644 index 000000000..3c87f3188 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0026-arm64-dts-apple-j31-46-Add-keyboard-nodes.patch @@ -0,0 +1,47 @@ +From aec68ba09ead15a0b2b0fc47809146e2fa28ccf5 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Thu, 11 Nov 2021 21:31:21 +0100 +Subject: [PATCH 026/171] arm64: dts: apple: j31[46]: Add keyboard nodes + +Enables keyboard and touchpad input on MacBook Pro (14/16-inch, +M1 Pro/Max, 2021). + +Signed-off-by: Janne Grunau +--- + .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +index 55457892c38e..64280ed76feb 100644 +--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -88,6 +88,26 @@ flash@0 { + }; + }; + ++&spi3 { ++ status = "okay"; ++ ++ hid-transport@0 { ++ compatible = "apple,spi-hid-transport"; ++ reg = <0>; ++ spi-max-frequency = <8000000>; ++ /* ++ * cs-setup and cs-hold delays are derived from Apple's ADT ++ * Mac OS driver meta data secify 45 us for 'cs to clock' and ++ * 'clock to cs' delays. ++ */ ++ spi-cs-setup-delay-ns = <20000>; ++ spi-cs-hold-delay-ns = <20000>; ++ spi-cs-inactive-delay-ns = <250000>; ++ spien-gpios = <&pinctrl_ap 194 0>; ++ interrupts-extended = <&pinctrl_nub 6 IRQ_TYPE_LEVEL_LOW>; ++ }; ++}; ++ + /* PCIe devices */ + &port00 { + /* WLAN */ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0027-arm64-dts-apple-t600x-Add-dwc3-nodes.patch b/target/linux/silicon/patches-5.19/0027-arm64-dts-apple-t600x-Add-dwc3-nodes.patch new file mode 100644 index 000000000..60903303e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0027-arm64-dts-apple-t600x-Add-dwc3-nodes.patch @@ -0,0 +1,631 @@ +From e000de0d79a99fe707b8c86b8ae4f19b6e6cc78e Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Tue, 17 May 2022 23:54:26 +0200 +Subject: [PATCH 027/171] arm64: dts: apple: t600x: Add dwc3 nodes + +Signed-off-by: Janne Grunau +--- + arch/arm64/boot/dts/apple/t6001-j375c.dts | 105 +++++++++++ + arch/arm64/boot/dts/apple/t6002-j375d.dts | 168 ++++++++++++++++++ + arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 124 +++++++++++++ + .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 92 ++++++++++ + 4 files changed, 489 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts +index 961104d6bd9a..7ab07808a5e9 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j375c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts +@@ -53,6 +53,24 @@ hpm0: usb-pd@38 { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec0: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Back Left"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec0_con_hs: endpoint { ++ remote-endpoint = <&typec0_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm1: usb-pd@3f { +@@ -61,6 +79,24 @@ hpm1: usb-pd@3f { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec1: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Back Left Middle"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec1_con_hs: endpoint { ++ remote-endpoint = <&typec1_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm2: usb-pd@3b { +@@ -69,6 +105,24 @@ hpm2: usb-pd@3b { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec2: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Back Right Middle"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec2_con_hs: endpoint { ++ remote-endpoint = <&typec2_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm3: usb-pd@3c { +@@ -77,6 +131,24 @@ hpm3: usb-pd@3c { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec3: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Back Right"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec3_con_hs: endpoint { ++ remote-endpoint = <&typec3_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + }; + +@@ -116,3 +188,36 @@ &port03 { + /* USB xHCI */ + bus-range = <4 4>; + }; ++ ++/* USB controllers */ ++&dwc3_0 { ++ port { ++ typec0_usb_hs: endpoint { ++ remote-endpoint = <&typec0_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_1 { ++ port { ++ typec1_usb_hs: endpoint { ++ remote-endpoint = <&typec1_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_2 { ++ port { ++ typec2_usb_hs: endpoint { ++ remote-endpoint = <&typec2_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_3 { ++ port { ++ typec3_usb_hs: endpoint { ++ remote-endpoint = <&typec3_con_hs>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts +index 95e0c3243818..ed88e1eaf7bb 100644 +--- a/arch/arm64/boot/dts/apple/t6002-j375d.dts ++++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts +@@ -53,6 +53,24 @@ hpm0: usb-pd@38 { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec0: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Back Left"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec0_con_hs: endpoint { ++ remote-endpoint = <&typec0_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm1: usb-pd@3f { +@@ -61,6 +79,24 @@ hpm1: usb-pd@3f { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec1: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Back Left Middle"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec1_con_hs: endpoint { ++ remote-endpoint = <&typec1_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm2: usb-pd@3b { +@@ -69,6 +105,24 @@ hpm2: usb-pd@3b { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec2: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Back Right Middle"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec2_con_hs: endpoint { ++ remote-endpoint = <&typec2_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm3: usb-pd@3c { +@@ -77,6 +131,24 @@ hpm3: usb-pd@3c { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec3: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Back Right"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec3_con_hs: endpoint { ++ remote-endpoint = <&typec3_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + /* front-right */ +@@ -86,6 +158,24 @@ hpm4: usb-pd@39 { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec4: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Front Right"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec4_con_hs: endpoint { ++ remote-endpoint = <&typec4_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + /* front-left */ +@@ -95,6 +185,24 @@ hpm5: usb-pd@3a { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec5: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Front Left"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec5_con_hs: endpoint { ++ remote-endpoint = <&typec5_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + }; + +@@ -135,6 +243,66 @@ &port03 { + bus-range = <4 4>; + }; + ++/* USB controllers */ ++&dwc3_0 { ++ port { ++ typec0_usb_hs: endpoint { ++ remote-endpoint = <&typec0_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_1 { ++ port { ++ typec1_usb_hs: endpoint { ++ remote-endpoint = <&typec1_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_2 { ++ port { ++ typec2_usb_hs: endpoint { ++ remote-endpoint = <&typec2_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_3 { ++ port { ++ typec3_usb_hs: endpoint { ++ remote-endpoint = <&typec3_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_0_die1 { ++ port { ++ typec4_usb_hs: endpoint { ++ remote-endpoint = <&typec4_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_1_die1 { ++ port { ++ typec5_usb_hs: endpoint { ++ remote-endpoint = <&typec5_con_hs>; ++ }; ++ }; ++}; ++ ++/* delete unused USB nodes on die 1 */ ++ ++/delete-node/ &dwc3_2_dart_0_die1; ++/delete-node/ &dwc3_2_dart_1_die1; ++/delete-node/ &dwc3_2_die1; ++ ++/delete-node/ &dwc3_3_dart_0_die1; ++/delete-node/ &dwc3_3_dart_1_die1; ++/delete-node/ &dwc3_3_die1; ++ ++ + /* delete unused always-on power-domains on die 1 */ + + /delete-node/ &ps_atc2_usb_aon_die1; +diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +index 0a437b68e86c..6ada6c7f50fa 100644 +--- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +@@ -101,3 +101,127 @@ DIE_NODE(pinctrl_ap): pinctrl@39b028000 { + interrupt-controller; + #interrupt-cells = <2>; + }; ++ ++ DIE_NODE(dwc3_0_dart_0): iommu@702f00000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0x7 0x02f00000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&DIE_NODE(ps_atc0_usb)>; ++ #iommu-cells = <1>; ++ }; ++ ++ DIE_NODE(dwc3_0_dart_1): iommu@702f80000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0x7 0x02f80000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&DIE_NODE(ps_atc0_usb)>; ++ #iommu-cells = <1>; ++ }; ++ ++ DIE_NODE(dwc3_0): usb@702280000 { ++ compatible = "apple,t6000-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0x7 0x02280000 0x0 0x100000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ /* dr_mode = "otg"; */ ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ iommus = <&DIE_NODE(dwc3_0_dart_0) 0>, ++ <&DIE_NODE(dwc3_0_dart_1) 1>; ++ power-domains = <&DIE_NODE(ps_atc0_usb)>; ++ }; ++ ++ DIE_NODE(dwc3_1_dart_0): iommu@b02f00000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0xb 0x02f00000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&DIE_NODE(ps_atc1_usb)>; ++ #iommu-cells = <1>; ++ }; ++ ++ DIE_NODE(dwc3_1_dart_1): iommu@b02f80000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0xb 0x02f80000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&DIE_NODE(ps_atc1_usb)>; ++ #iommu-cells = <1>; ++ }; ++ ++ DIE_NODE(dwc3_1): usb@b02280000 { ++ compatible = "apple,t6000-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0xb 0x02280000 0x0 0x100000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ /* dr_mode = "otg"; */ ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ iommus = <&DIE_NODE(dwc3_1_dart_0) 0>, ++ <&DIE_NODE(dwc3_1_dart_1) 1>; ++ power-domains = <&DIE_NODE(ps_atc1_usb)>; ++ }; ++ ++ DIE_NODE(dwc3_2_dart_0): iommu@f02f00000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0xf 0x02f00000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&DIE_NODE(ps_atc2_usb)>; ++ #iommu-cells = <1>; ++ }; ++ ++ DIE_NODE(dwc3_2_dart_1): iommu@f02f80000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0xf 0x02f80000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&DIE_NODE(ps_atc2_usb)>; ++ #iommu-cells = <1>; ++ }; ++ ++ DIE_NODE(dwc3_2): usb@f02280000 { ++ compatible = "apple,t6000-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0xf 0x02280000 0x0 0x100000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ /* dr_mode = "otg"; */ ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ iommus = <&DIE_NODE(dwc3_2_dart_0) 0>, ++ <&DIE_NODE(dwc3_2_dart_1) 1>; ++ power-domains = <&DIE_NODE(ps_atc2_usb)>; ++ }; ++ ++ DIE_NODE(dwc3_3_dart_0): iommu@1302f00000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0x13 0x02f00000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&DIE_NODE(ps_atc3_usb)>; ++ #iommu-cells = <1>; ++ }; ++ ++ DIE_NODE(dwc3_3_dart_1): iommu@1302f80000 { ++ compatible = "apple,t6000-dart"; ++ reg = <0x13 0x02f80000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&DIE_NODE(ps_atc3_usb)>; ++ #iommu-cells = <1>; ++ }; ++ ++ DIE_NODE(dwc3_3): usb@1302280000 { ++ compatible = "apple,t6000-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0x13 0x02280000 0x0 0x100000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ /* dr_mode = "otg"; */ ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ iommus = <&DIE_NODE(dwc3_3_dart_0) 0>, ++ <&DIE_NODE(dwc3_3_dart_1) 1>; ++ power-domains = <&DIE_NODE(ps_atc3_usb)>; ++ }; +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +index 64280ed76feb..1582a4caccdb 100644 +--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -48,6 +48,24 @@ hpm0: usb-pd@38 { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec0: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Left Rear"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec0_con_hs: endpoint { ++ remote-endpoint = <&typec0_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm1: usb-pd@3f { +@@ -56,6 +74,24 @@ hpm1: usb-pd@3f { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec1: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Left Front"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec1_con_hs: endpoint { ++ remote-endpoint = <&typec1_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + hpm2: usb-pd@3b { +@@ -64,6 +100,24 @@ hpm2: usb-pd@3b { + interrupt-parent = <&pinctrl_ap>; + interrupts = <174 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; ++ ++ typec2: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C Right"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec2_con_hs: endpoint { ++ remote-endpoint = <&typec2_usb_hs>; ++ }; ++ }; ++ }; ++ }; + }; + + /* MagSafe port */ +@@ -140,3 +194,41 @@ &pcie0_dart_3 { + + /delete-node/ &port02; + /delete-node/ &port03; ++ ++/* USB controllers */ ++&dwc3_0 { ++ port { ++ typec0_usb_hs: endpoint { ++ remote-endpoint = <&typec0_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_1 { ++ port { ++ typec1_usb_hs: endpoint { ++ remote-endpoint = <&typec1_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_2 { ++ port { ++ typec2_usb_hs: endpoint { ++ remote-endpoint = <&typec2_con_hs>; ++ }; ++ }; ++}; ++ ++/* ATC3 is used for DisplayPort -> HDMI only */ ++&dwc3_3_dart_0 { ++ status = "disabled"; ++}; ++ ++&dwc3_3_dart_1 { ++ status = "disabled"; ++}; ++ ++&dwc3_3 { ++ status = "disabled"; ++}; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0028-arm64-dts-apple-Add-WiFi-module-and-antenna-properti.patch b/target/linux/silicon/patches-5.19/0028-arm64-dts-apple-Add-WiFi-module-and-antenna-properti.patch new file mode 100644 index 000000000..fbb38dd06 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0028-arm64-dts-apple-Add-WiFi-module-and-antenna-properti.patch @@ -0,0 +1,141 @@ +From 114701eecdf46c638d373e6cd3c7af3a6f61dbfe Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:07:17 +0900 +Subject: [PATCH 028/171] arm64: dts: apple: Add WiFi module and antenna + properties + +Add the new module-instance/antenna-sku properties required to select +WiFi firmwares properly to all board device trees. + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t6000-j314s.dts | 4 ++++ + arch/arm64/boot/dts/apple/t6000-j316s.dts | 4 ++++ + arch/arm64/boot/dts/apple/t6001-j314c.dts | 4 ++++ + arch/arm64/boot/dts/apple/t6001-j316c.dts | 4 ++++ + arch/arm64/boot/dts/apple/t6001-j375c.dts | 6 ++++++ + arch/arm64/boot/dts/apple/t6002-j375d.dts | 6 ++++++ + arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 2 ++ + 7 files changed, 30 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t6000-j314s.dts b/arch/arm64/boot/dts/apple/t6000-j314s.dts +index c9e192848fe3..ac35870ca129 100644 +--- a/arch/arm64/boot/dts/apple/t6000-j314s.dts ++++ b/arch/arm64/boot/dts/apple/t6000-j314s.dts +@@ -16,3 +16,7 @@ / { + compatible = "apple,j314s", "apple,t6000", "apple,arm-platform"; + model = "Apple MacBook Pro (14-inch, M1 Pro, 2021)"; + }; ++ ++&wifi0 { ++ brcm,board-type = "apple,maldives"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6000-j316s.dts b/arch/arm64/boot/dts/apple/t6000-j316s.dts +index ff1803ce2300..77d6d8c14d74 100644 +--- a/arch/arm64/boot/dts/apple/t6000-j316s.dts ++++ b/arch/arm64/boot/dts/apple/t6000-j316s.dts +@@ -16,3 +16,7 @@ / { + compatible = "apple,j316s", "apple,t6000", "apple,arm-platform"; + model = "Apple MacBook Pro (16-inch, M1 Pro, 2021)"; + }; ++ ++&wifi0 { ++ brcm,board-type = "apple,madagascar"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6001-j314c.dts b/arch/arm64/boot/dts/apple/t6001-j314c.dts +index 1761d15b98c1..0a5655792a8f 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j314c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j314c.dts +@@ -16,3 +16,7 @@ / { + compatible = "apple,j314c", "apple,t6001", "apple,arm-platform"; + model = "Apple MacBook Pro (14-inch, M1 Max, 2021)"; + }; ++ ++&wifi0 { ++ brcm,board-type = "apple,maldives"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6001-j316c.dts b/arch/arm64/boot/dts/apple/t6001-j316c.dts +index 750e9beeffc0..9c215531ea54 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j316c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j316c.dts +@@ -16,3 +16,7 @@ / { + compatible = "apple,j316c", "apple,t6001", "apple,arm-platform"; + model = "Apple MacBook Pro (16-inch, M1 Max, 2021)"; + }; ++ ++&wifi0 { ++ brcm,board-type = "apple,madagascar"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts +index 7ab07808a5e9..15d26674a310 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j375c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts +@@ -157,9 +157,11 @@ &port00 { + /* WLAN */ + bus-range = <1 1>; + wifi0: wifi@0,0 { ++ compatible = "pci14e4,4433"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + /* To be filled by the loader */ + local-mac-address = [00 10 18 00 00 10]; ++ apple,antenna-sku = "XX"; + }; + }; + +@@ -189,6 +191,10 @@ &port03 { + bus-range = <4 4>; + }; + ++&wifi0 { ++ brcm,board-type = "apple,okinawa"; ++}; ++ + /* USB controllers */ + &dwc3_0 { + port { +diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts +index ed88e1eaf7bb..4b84652e0334 100644 +--- a/arch/arm64/boot/dts/apple/t6002-j375d.dts ++++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts +@@ -211,9 +211,11 @@ &port00 { + /* WLAN */ + bus-range = <1 1>; + wifi0: wifi@0,0 { ++ compatible = "pci14e4,4433"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + /* To be filled by the loader */ + local-mac-address = [00 10 18 00 00 10]; ++ apple,antenna-sku = "XX"; + }; + }; + +@@ -243,6 +245,10 @@ &port03 { + bus-range = <4 4>; + }; + ++&wifi0 { ++ brcm,board-type = "apple,okinawa"; ++}; ++ + /* USB controllers */ + &dwc3_0 { + port { +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +index 1582a4caccdb..0296506c043b 100644 +--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -167,9 +167,11 @@ &port00 { + /* WLAN */ + bus-range = <1 1>; + wifi0: wifi@0,0 { ++ compatible = "pci14e4,4433"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + /* To be filled by the loader */ + local-mac-address = [00 10 18 00 00 10]; ++ apple,antenna-sku = "XX"; + }; + }; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0029-arm64-dts-apple-Add-PCI-power-enable-GPIOs.patch b/target/linux/silicon/patches-5.19/0029-arm64-dts-apple-Add-PCI-power-enable-GPIOs.patch new file mode 100644 index 000000000..9af585153 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0029-arm64-dts-apple-Add-PCI-power-enable-GPIOs.patch @@ -0,0 +1,97 @@ +From e1a42fe74f4db0536b104053abc6e28097803873 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 6 Feb 2022 21:22:29 +0900 +Subject: [PATCH 029/171] arm64: dts: apple: Add PCI power enable GPIOs + +t8103: +- WLAN (SMC PMU GPIO #13) +t600x: +- WLAN (SMC PMU GPIO #13) +- SD (SMC PMU GPIO #26) + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t6001-j375c.dts | 3 +++ + arch/arm64/boot/dts/apple/t6002-j375d.dts | 3 +++ + arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 2 ++ + 3 files changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts +index 15d26674a310..561a9a4c2bc1 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j375c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts +@@ -156,6 +156,7 @@ typec3_con_hs: endpoint { + &port00 { + /* WLAN */ + bus-range = <1 1>; ++ pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; + wifi0: wifi@0,0 { + compatible = "pci14e4,4433"; + reg = <0x10000 0x0 0x0 0x0 0x0>; +@@ -168,6 +169,7 @@ wifi0: wifi@0,0 { + &port01 { + /* SD card reader */ + bus-range = <2 2>; ++ pwren-gpios = <&smc_gpio 26 GPIO_ACTIVE_HIGH>; + sdhci0: mmc@0,0 { + compatible = "pci17a0,9755"; + reg = <0x20000 0x0 0x0 0x0 0x0>; +@@ -189,6 +191,7 @@ ethernet0: ethernet@0,0 { + &port03 { + /* USB xHCI */ + bus-range = <4 4>; ++ pwren-gpios = <&smc_gpio 20 GPIO_ACTIVE_HIGH>; + }; + + &wifi0 { +diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts +index 4b84652e0334..72070e9a3277 100644 +--- a/arch/arm64/boot/dts/apple/t6002-j375d.dts ++++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts +@@ -210,6 +210,7 @@ typec5_con_hs: endpoint { + &port00 { + /* WLAN */ + bus-range = <1 1>; ++ pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; + wifi0: wifi@0,0 { + compatible = "pci14e4,4433"; + reg = <0x10000 0x0 0x0 0x0 0x0>; +@@ -222,6 +223,7 @@ wifi0: wifi@0,0 { + &port01 { + /* SD card reader */ + bus-range = <2 2>; ++ pwren-gpios = <&smc_gpio 26 GPIO_ACTIVE_HIGH>; + sdhci0: mmc@0,0 { + compatible = "pci17a0,9755"; + reg = <0x20000 0x0 0x0 0x0 0x0>; +@@ -243,6 +245,7 @@ ethernet0: ethernet@0,0 { + &port03 { + /* USB xHCI */ + bus-range = <4 4>; ++ pwren-gpios = <&smc_gpio 20 GPIO_ACTIVE_HIGH>; + }; + + &wifi0 { +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +index 0296506c043b..21608ca46a55 100644 +--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -166,6 +166,7 @@ hid-transport@0 { + &port00 { + /* WLAN */ + bus-range = <1 1>; ++ pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; + wifi0: wifi@0,0 { + compatible = "pci14e4,4433"; + reg = <0x10000 0x0 0x0 0x0 0x0>; +@@ -178,6 +179,7 @@ wifi0: wifi@0,0 { + &port01 { + /* SD card reader */ + bus-range = <2 2>; ++ pwren-gpios = <&smc_gpio 26 GPIO_ACTIVE_HIGH>; + sdhci0: mmc@0,0 { + compatible = "pci17a0,9755"; + reg = <0x20000 0x0 0x0 0x0 0x0>; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0030-arm64-dts-apple-Add-backlight-node-to-j314-j316.patch b/target/linux/silicon/patches-5.19/0030-arm64-dts-apple-Add-backlight-node-to-j314-j316.patch new file mode 100644 index 000000000..c8082955a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0030-arm64-dts-apple-Add-backlight-node-to-j314-j316.patch @@ -0,0 +1,37 @@ +From fa4bcbf275b4c864bdf5506e44369e9a982d8bc4 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 3 Mar 2022 03:24:36 +0900 +Subject: [PATCH 030/171] arm64: dts: apple: Add backlight node to j314/j316 + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +index 21608ca46a55..c5241d5515cf 100644 +--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -26,6 +26,7 @@ framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ ++ backlight = <&backlight>; + status = "disabled"; + }; + }; +@@ -236,3 +237,11 @@ &dwc3_3_dart_1 { + &dwc3_3 { + status = "disabled"; + }; ++ ++/ { ++ backlight: gpio-bl { ++ compatible = "gpio-backlight"; ++ gpios = <&smc_gpio 19 GPIO_ACTIVE_HIGH>; ++ default-on; ++ }; ++}; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0031-arm64-dts-apple-t600-Put-in-audio-nodes.patch b/target/linux/silicon/patches-5.19/0031-arm64-dts-apple-t600-Put-in-audio-nodes.patch new file mode 100644 index 000000000..ccf0836a4 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0031-arm64-dts-apple-t600-Put-in-audio-nodes.patch @@ -0,0 +1,96 @@ +From c0ab64753e9a149b5c97f42110b5ff21d0d6322f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Fri, 11 Mar 2022 22:16:25 +0100 +Subject: [PATCH 031/171] arm64: dts: apple: t600*: Put in audio nodes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Martin PoviÅ¡er +--- + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 72 +++++++++++++++++++++++ + 1 file changed, 72 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +index b549059a3320..b24dd6ed0a37 100644 +--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +@@ -441,3 +441,75 @@ port03: pci@3,0 { + <0 0 0 4 &port03 0 0 0 3>; + }; + }; ++ ++ dart_sio_0: iommu@39b004000 { ++ compatible = "apple,t6000-dart", "apple,dart"; ++ reg = <0x3 0x9b004000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_sio_cpu>; ++ }; ++ ++ dart_sio_1: iommu@39b008000 { ++ compatible = "apple,t6000-dart", "apple,dart"; ++ reg = <0x3 0x9b008000 0x0 0x8000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_sio_cpu>; ++ }; ++ ++ nco_clkref: clock-ref { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <1068000000>; ++ clock-output-names = "nco_ref"; ++ }; ++ ++ nco: nco@28e03c000 { ++ compatible = "apple,t6000-nco", "apple,nco"; ++ reg = <0x2 0x8e03c000 0x0 0x14000>; ++ clocks = <&nco_clkref>; ++ #clock-cells = <1>; ++ }; ++ ++ admac: dma-controller@39b400000 { ++ compatible = "apple,t6000-admac", "apple,admac"; ++ reg = <0x3 0x9b400000 0x0 0x34000>; ++ dma-channels = <16>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #dma-cells = <1>; ++ iommus = <&dart_sio_0 2>, <&dart_sio_1 2>; ++ power-domains = <&ps_sio_adma>; ++ apple,internal-irq-destination = <1>; ++ }; ++ ++ mca: mca@9b600000 { ++ compatible = "apple,t6000-mca", "apple,mca"; ++ reg = <0x3 0x9b600000 0x0 0x10000>, ++ <0x3 0x9b500000 0x0 0x20000>; ++ reg-names = "clusters", "switch"; ++ ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ ++ clocks = <&nco 0>, <&nco 1>, <&nco 2>, <&nco 3>; ++ power-domains = <&ps_audio_p>, <&ps_mca0>, <&ps_mca1>, ++ <&ps_mca2>, <&ps_mca3>; ++ dmas = <&admac 0>, <&admac 1>, <&admac 2>, <&admac 3>, ++ <&admac 4>, <&admac 5>, <&admac 6>, <&admac 7>, ++ <&admac 8>, <&admac 9>, <&admac 10>, <&admac 11>, ++ <&admac 12>, <&admac 13>, <&admac 14>, <&admac 15>; ++ dma-names = "tx0a", "rx0a", "tx0b", "rx0b", ++ "tx1a", "rx1a", "tx1b", "rx1b", ++ "tx2a", "rx2a", "tx2b", "rx2b", ++ "tx3a", "rx3a", "tx3b", "rx3b"; ++ ++ #sound-dai-cells = <1>; ++ apple,nclusters = <4>; ++ }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0032-arm64-dts-apple-t600-Put-in-audio-nodes.patch b/target/linux/silicon/patches-5.19/0032-arm64-dts-apple-t600-Put-in-audio-nodes.patch new file mode 100644 index 000000000..9f912ac5f --- /dev/null +++ b/target/linux/silicon/patches-5.19/0032-arm64-dts-apple-t600-Put-in-audio-nodes.patch @@ -0,0 +1,231 @@ +From c390136c1f033e36969ea59352034603aca42071 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Fri, 11 Mar 2022 22:16:25 +0100 +Subject: [PATCH 032/171] arm64: dts: apple: t600*: Put in audio nodes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Martin PoviÅ¡er +--- + arch/arm64/boot/dts/apple/t6001-j375c.dts | 40 +++++++++ + arch/arm64/boot/dts/apple/t6002-j375d.dts | 40 +++++++++ + .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 87 +++++++++++++++++++ + 3 files changed, 167 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts +index 561a9a4c2bc1..84be4c83f4d4 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j375c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts +@@ -152,6 +152,18 @@ typec3_con_hs: endpoint { + }; + }; + ++/* Audio */ ++&i2c1 { ++ status = "okay"; ++ ++ speaker: codec@38 { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x38>; ++ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ }; ++}; ++ + /* PCIe devices */ + &port00 { + /* WLAN */ +@@ -230,3 +242,31 @@ typec3_usb_hs: endpoint { + }; + }; + }; ++ ++/ { ++ sound { ++ compatible = "apple,j375-macaudio", "apple,macaudio"; ++ model = "Mac Studio J375 integrated audio"; ++ ++ /* ++ * DANGER ZONE: You can blow your speakers! ++ * ++ * The drivers are not ready, and unless you are careful ++ * to attenuate the audio stream, you run the risk of ++ * blowing your speakers. ++ */ ++ status = "disabled"; ++ ++ dai-link@0 { ++ link-name = "Speaker"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 0>; ++ }; ++ codec { ++ sound-dai = <&speaker>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts +index 72070e9a3277..58463d957d09 100644 +--- a/arch/arm64/boot/dts/apple/t6002-j375d.dts ++++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts +@@ -206,6 +206,18 @@ typec5_con_hs: endpoint { + }; + }; + ++/* Audio */ ++&i2c1 { ++ status = "okay"; ++ ++ speaker: codec@38 { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x38>; ++ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ }; ++}; ++ + /* PCIe devices */ + &port00 { + /* WLAN */ +@@ -322,3 +334,31 @@ typec5_usb_hs: endpoint { + + /delete-node/ &ps_disp0_cpu0_die1; + /delete-node/ &ps_disp0_fe_die1; ++ ++/ { ++ sound { ++ compatible = "apple,j375-macaudio", "apple,macaudio"; ++ model = "Mac Studio J375 integrated audio"; ++ ++ /* ++ * DANGER ZONE: You can blow your speakers! ++ * ++ * The drivers are not ready, and unless you are careful ++ * to attenuate the audio stream, you run the risk of ++ * blowing your speakers. ++ */ ++ status = "disabled"; ++ ++ dai-link@0 { ++ link-name = "Speaker"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 0>; ++ }; ++ codec { ++ sound-dai = <&speaker>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +index c5241d5515cf..666183f385b5 100644 +--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -131,6 +131,62 @@ hpm5: usb-pd@3a { + }; + }; + ++&i2c1 { ++ status = "okay"; ++ ++ speaker_left_tweet: codec@3a { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x3a>; ++ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Tweeter"; ++ }; ++ ++ speaker_left_woof1: codec@38 { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x38>; ++ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Woofer 1"; ++ }; ++ ++ speaker_left_woof2: codec@39 { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x39>; ++ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Woofer 2"; ++ }; ++}; ++ ++&i2c3 { ++ status = "okay"; ++ ++ speaker_right_tweet: codec@3d { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x3d>; ++ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Tweeter"; ++ }; ++ ++ speaker_right_woof1: codec@3b { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x3b>; ++ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Woofer 1"; ++ }; ++ ++ speaker_right_woof2: codec@3c { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x3c>; ++ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Woofer 2"; ++ }; ++}; ++ + &spi1 { + status = "disabled"; + +@@ -244,4 +300,35 @@ backlight: gpio-bl { + gpios = <&smc_gpio 19 GPIO_ACTIVE_HIGH>; + default-on; + }; ++ ++ sound { ++ compatible = "apple,j314-macaudio", "apple,macaudio"; ++ model = "MacBook Pro J314/6 integrated audio"; ++ ++ /* ++ * DANGER ZONE: You can blow your speakers! ++ * ++ * The drivers are not ready, and unless you are careful ++ * to attenuate the audio stream, you run the risk of ++ * blowing your speakers. ++ */ ++ status = "disabled"; ++ ++ dai-link@0 { ++ link-name = "Speakers"; ++ mclk-fs = <256>; ++ ++ cpu { ++ sound-dai = <&mca 0>, <&mca 1>; ++ }; ++ codec { ++ sound-dai = <&speaker_left_woof1>, ++ <&speaker_right_woof1>, ++ <&speaker_left_tweet>, ++ <&speaker_right_tweet>, ++ <&speaker_left_woof2>, ++ <&speaker_right_woof2>; ++ }; ++ }; ++ }; + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0033-arm64-dts-apple-t600-Add-t8103-compat-to-cpufreq-nod.patch b/target/linux/silicon/patches-5.19/0033-arm64-dts-apple-t600-Add-t8103-compat-to-cpufreq-nod.patch new file mode 100644 index 000000000..65ba27266 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0033-arm64-dts-apple-t600-Add-t8103-compat-to-cpufreq-nod.patch @@ -0,0 +1,32 @@ +From 0672eebb472aaef8449aec4cb064acc86e3aae37 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 30 Jun 2022 21:48:46 +0900 +Subject: [PATCH 033/171] arm64: dts: apple: t600*: Add t8103 compat to cpufreq + node + +t600x seems to be fully compatible with t8103, but t8112 introduced +minor changes which means we can't provide full functionality with the +common compatible. Let t600x claim t8103 compatibility, treating the +latter as the common baseline for this SoC family. + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +index b24dd6ed0a37..4c203778aa89 100644 +--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi +@@ -7,7 +7,7 @@ + */ + + cpufreq_hw: cpufreq@210e20000 { +- compatible = "apple,t6000-soc-cpufreq", "apple,soc-cpufreq"; ++ compatible = "apple,t6000-soc-cpufreq", "apple,t8103-soc-cpufreq", "apple,soc-cpufreq"; + #freq-domain-cells = <1>; + }; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0034-arm64-dts-apple-t8103-Fix-spi4-power-domain-sort-ord.patch b/target/linux/silicon/patches-5.19/0034-arm64-dts-apple-t8103-Fix-spi4-power-domain-sort-ord.patch new file mode 100644 index 000000000..2e3d04e1d --- /dev/null +++ b/target/linux/silicon/patches-5.19/0034-arm64-dts-apple-t8103-Fix-spi4-power-domain-sort-ord.patch @@ -0,0 +1,50 @@ +From 6b11a54eb684f097803307b96eb5681c9168b506 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 27 Jun 2022 22:21:34 +0900 +Subject: [PATCH 034/171] arm64: dts: apple: t8103: Fix spi4 power domain sort + order + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +index 68ae594bf5e9..df7f56483ee8 100644 +--- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +@@ -387,6 +387,15 @@ ps_spi3: power-controller@258 { + power-domains = <&ps_sio>, <&ps_spi_p>; + }; + ++ ps_spi4: power-controller@260 { ++ compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x260 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "spi4"; ++ power-domains = <&ps_sio>, <&ps_spi_p>; ++ }; ++ + ps_uart_n: power-controller@268 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x268 4>; +@@ -558,15 +567,6 @@ ps_mcc: power-controller@2f8 { + apple,always-on; /* Memory controller */ + }; + +- ps_spi4: power-controller@260 { +- compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; +- reg = <0x260 4>; +- #power-domain-cells = <0>; +- #reset-cells = <0>; +- label = "spi4"; +- power-domains = <&ps_sio>, <&ps_spi_p>; +- }; +- + ps_dcs0: power-controller@300 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x300 4>; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0035-arm64-dts-apple-t8103-Add-bluetooth-device-trees.patch b/target/linux/silicon/patches-5.19/0035-arm64-dts-apple-t8103-Add-bluetooth-device-trees.patch new file mode 100644 index 000000000..c112e420b --- /dev/null +++ b/target/linux/silicon/patches-5.19/0035-arm64-dts-apple-t8103-Add-bluetooth-device-trees.patch @@ -0,0 +1,117 @@ +From 3b6593525fd6fe8d09e46e8543fcce20088de1e0 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Wed, 6 Jul 2022 20:04:20 +0200 +Subject: [PATCH 035/171] arm64: dts: apple: t8103: Add bluetooth device trees + +Signed-off-by: Sven Peter +--- + arch/arm64/boot/dts/apple/t8103-j274.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-j293.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-j313.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-j456.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-j457.dts | 4 ++++ + arch/arm64/boot/dts/apple/t8103-jxxx.dtsi | 8 ++++++++ + 6 files changed, 28 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts +index 811008bd73f3..4efbb085e407 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j274.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j274.dts +@@ -25,6 +25,10 @@ &wifi0 { + brcm,board-type = "apple,atlantisb"; + }; + ++&bluetooth0 { ++ brcm,board-type = "apple,atlantisb"; ++}; ++ + /* + * Provide labels for the USB type C ports. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts +index 7eb98e6b947c..3a5ae54f0b9f 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j293.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j293.dts +@@ -21,6 +21,10 @@ &wifi0 { + brcm,board-type = "apple,honshu"; + }; + ++&bluetooth0 { ++ brcm,board-type = "apple,honshu"; ++}; ++ + /* + * Provide labels for the USB type C ports. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts +index d1f65e48699f..b51f651d2326 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j313.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j313.dts +@@ -21,6 +21,10 @@ &wifi0 { + brcm,board-type = "apple,shikoku"; + }; + ++&bluetooth0 { ++ brcm,board-type = "apple,shikoku"; ++}; ++ + /* + * Provide labels for the USB type C ports. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts +index e65053f3bd2c..5e098e8056e1 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j456.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j456.dts +@@ -25,6 +25,10 @@ &wifi0 { + brcm,board-type = "apple,capri"; + }; + ++&bluetooth0 { ++ brcm,board-type = "apple,capri"; ++}; ++ + &i2c0 { + hpm2: usb-pd@3b { + compatible = "apple,cd321x"; +diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts +index 925fe4058055..f67c0b52075a 100644 +--- a/arch/arm64/boot/dts/apple/t8103-j457.dts ++++ b/arch/arm64/boot/dts/apple/t8103-j457.dts +@@ -25,6 +25,10 @@ &wifi0 { + brcm,board-type = "apple,santorini"; + }; + ++&bluetooth0 { ++ brcm,board-type = "apple,santorini"; ++}; ++ + /* + * Provide labels for the USB type C ports. + */ +diff --git a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +index e62664b6e450..7a814c7abe0c 100644 +--- a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +@@ -11,6 +11,7 @@ + + / { + aliases { ++ bluetooth0 = &bluetooth0; + serial0 = &serial0; + serial2 = &serial2; + wifi0 = &wifi0; +@@ -129,4 +130,11 @@ wifi0: network@0,0 { + local-mac-address = [00 00 00 00 00 00]; + apple,antenna-sku = "XX"; + }; ++ ++ bluetooth0: network@0,1 { ++ compatible = "pci14e4,5f69"; ++ reg = <0x10100 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-bd-address = [00 00 00 00 00 00]; ++ }; + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0036-arm64-dts-apple-t600x-Add-bluetooth-device-trees.patch b/target/linux/silicon/patches-5.19/0036-arm64-dts-apple-t600x-Add-bluetooth-device-trees.patch new file mode 100644 index 000000000..f596259d0 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0036-arm64-dts-apple-t600x-Add-bluetooth-device-trees.patch @@ -0,0 +1,167 @@ +From 14fa82e8f1e6e379983d8222ed3214552c4b5c48 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 11 Jul 2022 20:05:02 +0900 +Subject: [PATCH 036/171] arm64: dts: apple: t600x: Add bluetooth device trees + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t6000-j314s.dts | 4 ++++ + arch/arm64/boot/dts/apple/t6000-j316s.dts | 4 ++++ + arch/arm64/boot/dts/apple/t6001-j314c.dts | 4 ++++ + arch/arm64/boot/dts/apple/t6001-j316c.dts | 4 ++++ + arch/arm64/boot/dts/apple/t6001-j375c.dts | 12 ++++++++++++ + arch/arm64/boot/dts/apple/t6002-j375d.dts | 12 ++++++++++++ + arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 8 ++++++++ + 7 files changed, 48 insertions(+) + +diff --git a/arch/arm64/boot/dts/apple/t6000-j314s.dts b/arch/arm64/boot/dts/apple/t6000-j314s.dts +index ac35870ca129..1430b91ff1b1 100644 +--- a/arch/arm64/boot/dts/apple/t6000-j314s.dts ++++ b/arch/arm64/boot/dts/apple/t6000-j314s.dts +@@ -20,3 +20,7 @@ / { + &wifi0 { + brcm,board-type = "apple,maldives"; + }; ++ ++&bluetooth0 { ++ brcm,board-type = "apple,maldives"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6000-j316s.dts b/arch/arm64/boot/dts/apple/t6000-j316s.dts +index 77d6d8c14d74..da0cbe7d9673 100644 +--- a/arch/arm64/boot/dts/apple/t6000-j316s.dts ++++ b/arch/arm64/boot/dts/apple/t6000-j316s.dts +@@ -20,3 +20,7 @@ / { + &wifi0 { + brcm,board-type = "apple,madagascar"; + }; ++ ++&bluetooth0 { ++ brcm,board-type = "apple,madagascar"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6001-j314c.dts b/arch/arm64/boot/dts/apple/t6001-j314c.dts +index 0a5655792a8f..c37097dcfdb3 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j314c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j314c.dts +@@ -20,3 +20,7 @@ / { + &wifi0 { + brcm,board-type = "apple,maldives"; + }; ++ ++&bluetooth0 { ++ brcm,board-type = "apple,maldives"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6001-j316c.dts b/arch/arm64/boot/dts/apple/t6001-j316c.dts +index 9c215531ea54..3bc6e0c3294c 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j316c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j316c.dts +@@ -20,3 +20,7 @@ / { + &wifi0 { + brcm,board-type = "apple,madagascar"; + }; ++ ++&bluetooth0 { ++ brcm,board-type = "apple,madagascar"; ++}; +diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts +index 84be4c83f4d4..0f278170bd7a 100644 +--- a/arch/arm64/boot/dts/apple/t6001-j375c.dts ++++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts +@@ -18,6 +18,7 @@ / { + aliases { + serial0 = &serial0; + wifi0 = &wifi0; ++ bluetooth0 = &bluetooth0; + }; + + chosen { +@@ -176,6 +177,13 @@ wifi0: wifi@0,0 { + local-mac-address = [00 10 18 00 00 10]; + apple,antenna-sku = "XX"; + }; ++ ++ bluetooth0: network@0,1 { ++ compatible = "pci14e4,5f71"; ++ reg = <0x10100 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-bd-address = [00 00 00 00 00 00]; ++ }; + }; + + &port01 { +@@ -210,6 +218,10 @@ &wifi0 { + brcm,board-type = "apple,okinawa"; + }; + ++&bluetooth0 { ++ brcm,board-type = "apple,okinawa"; ++}; ++ + /* USB controllers */ + &dwc3_0 { + port { +diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts +index 58463d957d09..e3a554c6aa5e 100644 +--- a/arch/arm64/boot/dts/apple/t6002-j375d.dts ++++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts +@@ -18,6 +18,7 @@ / { + aliases { + serial0 = &serial0; + wifi0 = &wifi0; ++ bluetooth0 = &bluetooth0; + }; + + chosen { +@@ -230,6 +231,13 @@ wifi0: wifi@0,0 { + local-mac-address = [00 10 18 00 00 10]; + apple,antenna-sku = "XX"; + }; ++ ++ bluetooth0: network@0,1 { ++ compatible = "pci14e4,5f71"; ++ reg = <0x10100 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-bd-address = [00 00 00 00 00 00]; ++ }; + }; + + &port01 { +@@ -264,6 +272,10 @@ &wifi0 { + brcm,board-type = "apple,okinawa"; + }; + ++&bluetooth0 { ++ brcm,board-type = "apple,okinawa"; ++}; ++ + /* USB controllers */ + &dwc3_0 { + port { +diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +index 666183f385b5..bbe66ea64f09 100644 +--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi ++++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +@@ -13,6 +13,7 @@ / { + aliases { + serial0 = &serial0; + wifi0 = &wifi0; ++ bluetooth0 = &bluetooth0; + }; + + chosen { +@@ -231,6 +232,13 @@ wifi0: wifi@0,0 { + local-mac-address = [00 10 18 00 00 10]; + apple,antenna-sku = "XX"; + }; ++ ++ bluetooth0: network@0,1 { ++ compatible = "pci14e4,5f71"; ++ reg = <0x10100 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-bd-address = [00 00 00 00 00 00]; ++ }; + }; + + &port01 { +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0037-arm64-dts-apple-t8112-Initial-t8112-M2-device-trees.patch b/target/linux/silicon/patches-5.19/0037-arm64-dts-apple-t8112-Initial-t8112-M2-device-trees.patch new file mode 100644 index 000000000..9f65909e5 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0037-arm64-dts-apple-t8112-Initial-t8112-M2-device-trees.patch @@ -0,0 +1,2800 @@ +From 820a0e0e2e8a3772a61340016b1ebac1b937eaa4 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 27 Jun 2022 22:21:14 +0900 +Subject: [PATCH 037/171] arm64: dts: apple: t8112: Initial t8112 (M2) device + trees + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/Makefile | 2 + + arch/arm64/boot/dts/apple/t8112-j413.dts | 182 ++++ + arch/arm64/boot/dts/apple/t8112-j493.dts | 171 +++ + arch/arm64/boot/dts/apple/t8112-jxxx.dtsi | 145 +++ + arch/arm64/boot/dts/apple/t8112-pmgr.dtsi | 1141 +++++++++++++++++++++ + arch/arm64/boot/dts/apple/t8112.dtsi | 1097 ++++++++++++++++++++ + 6 files changed, 2738 insertions(+) + create mode 100644 arch/arm64/boot/dts/apple/t8112-j413.dts + create mode 100644 arch/arm64/boot/dts/apple/t8112-j493.dts + create mode 100644 arch/arm64/boot/dts/apple/t8112-jxxx.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t8112-pmgr.dtsi + create mode 100644 arch/arm64/boot/dts/apple/t8112.dtsi + +diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile +index 5a7506ff5ea3..9d002bbbe98f 100644 +--- a/arch/arm64/boot/dts/apple/Makefile ++++ b/arch/arm64/boot/dts/apple/Makefile +@@ -10,3 +10,5 @@ dtb-$(CONFIG_ARCH_APPLE) += t6000-j316s.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6001-j316c.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6001-j375c.dtb + dtb-$(CONFIG_ARCH_APPLE) += t6002-j375d.dtb ++dtb-$(CONFIG_ARCH_APPLE) += t8112-j413.dtb ++dtb-$(CONFIG_ARCH_APPLE) += t8112-j493.dtb +diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts +new file mode 100644 +index 000000000000..0cc993c0a5b4 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t8112-j413.dts +@@ -0,0 +1,182 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Apple MacBook Air (M2, 2022) ++ * ++ * target-type: J413 ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/dts-v1/; ++ ++#include "t8112.dtsi" ++#include "t8112-jxxx.dtsi" ++ ++/ { ++ compatible = "apple,j413", "apple,t8112", "apple,arm-platform"; ++ model = "Apple MacBook Air (13-inch, M2, 2022)"; ++ ++ aliases { ++ wifi0 = &wifi0; ++ bluetooth0 = &bluetooth0; ++ }; ++}; ++ ++/* ++ * Force the bus number assignments so that we can declare some of the ++ * on-board devices and properties that are populated by the bootloader ++ * (such as MAC addresses). ++ */ ++&port00 { ++ bus-range = <1 1>; ++ pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; ++ wifi0: wifi@0,0 { ++ compatible = "pci14e4,4433"; ++ reg = <0x10000 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-mac-address = [00 10 18 00 00 10]; ++ apple,antenna-sku = "XX"; ++ brcm,board-type = "apple,hokkaido"; ++ }; ++ ++ bluetooth0: network@0,1 { ++ compatible = "pci14e4,5f71"; ++ reg = <0x10100 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-bd-address = [00 00 00 00 00 00]; ++ brcm,board-type = "apple,hokkaido"; ++ }; ++}; ++ ++/* ++ * Provide labels for the USB type C ports. ++ */ ++ ++&typec0 { ++ label = "USB-C Left-back"; ++}; ++ ++&typec1 { ++ label = "USB-C Left-front"; ++}; ++ ++/* ++ * Remove unused PCIe ports and disable the associated DARTs. ++ */ ++ ++/delete-node/ &port01; ++/delete-node/ &port02; ++/delete-node/ &port03; ++ ++&i2c0 { ++ /* MagSafe port */ ++ hpm5: usb-pd@3a { ++ compatible = "apple,cd321x"; ++ reg = <0x3a>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ }; ++}; ++ ++&i2c1 { ++ speaker_left_rear: codec@38 { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x38>; ++ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Rear"; ++ }; ++ ++ speaker_left_front: codec@39 { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x39>; ++ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Front"; ++ }; ++}; ++ ++&i2c2 { ++ status = "okay"; ++}; ++ ++&i2c3 { ++ speaker_right_rear: codec@3b { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x3b>; ++ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Rear"; ++ }; ++ ++ speaker_right_front: codec@3c { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x3c>; ++ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Front"; ++ }; ++}; ++ ++&i2c4 { ++ status = "okay"; ++}; ++ ++/ { ++ backlight: gpio-bl { ++ compatible = "gpio-backlight"; ++ gpios = <&smc_gpio 18 GPIO_ACTIVE_HIGH>; ++ default-on; ++ }; ++ ++ sound { ++ compatible = "apple,j413-macaudio", "apple,macaudio"; ++ model = "MacBook Pro J413 integrated audio"; ++ ++ dai-link@0 { ++ /* ++ * DANGER ZONE: You can blow your speakers! ++ * ++ * The drivers are not ready, and unless you are careful ++ * to attenuate the audio stream, you run the risk of ++ * blowing your speakers. ++ */ ++ status = "disabled"; ++ ++ link-name = "Speakers"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 0>, <&mca 1>; ++ }; ++ codec { ++ sound-dai = <&speaker_left_front>, <&speaker_right_front>, ++ <&speaker_left_rear>, <&speaker_right_rear>; ++ }; ++ }; ++#if 0 ++ dai-link@1 { ++ link-name = "Headphone Jack"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 2>; ++ }; ++ codec { ++ sound-dai = <&jack_codec>; ++ }; ++ }; ++#endif ++ }; ++}; ++ ++&framebuffer0 { ++ backlight = <&backlight>; ++}; ++ ++&mtp_hid { ++ multi-touch { ++ firmware-name = "apple/tpmtfw-j413.bin"; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts +new file mode 100644 +index 000000000000..aa8c045cd1ac +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t8112-j493.dts +@@ -0,0 +1,171 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Apple MacBook Pro (13-inch, M1, 2022) ++ * ++ * target-type: J493 ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/dts-v1/; ++ ++#include "t8112.dtsi" ++#include "t8112-jxxx.dtsi" ++ ++/ { ++ compatible = "apple,j493", "apple,t8112", "apple,arm-platform"; ++ model = "Apple MacBook Pro (13-inch, M2, 2022)"; ++ ++ aliases { ++ wifi0 = &wifi0; ++ bluetooth0 = &bluetooth0; ++ }; ++}; ++ ++/* ++ * Force the bus number assignments so that we can declare some of the ++ * on-board devices and properties that are populated by the bootloader ++ * (such as MAC addresses). ++ */ ++&port00 { ++ bus-range = <1 1>; ++ pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; ++ wifi0: network@0,0 { ++ compatible = "pci14e4,4425"; ++ reg = <0x10000 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-mac-address = [00 00 00 00 00 00]; ++ apple,antenna-sku = "XX"; ++ brcm,board-type = "apple,kyushu"; ++ }; ++ ++ bluetooth0: network@0,1 { ++ compatible = "pci14e4,5f69"; ++ reg = <0x10100 0x0 0x0 0x0 0x0>; ++ /* To be filled by the loader */ ++ local-bd-address = [00 00 00 00 00 00]; ++ brcm,board-type = "apple,kyushu"; ++ }; ++}; ++ ++/* ++ * Provide labels for the USB type C ports. ++ */ ++ ++&typec0 { ++ label = "USB-C Left-back"; ++}; ++ ++&typec1 { ++ label = "USB-C Left-front"; ++}; ++ ++/* ++ * Remove unused PCIe ports and disable the associated DARTs. ++ */ ++ ++/delete-node/ &port01; ++/delete-node/ &port02; ++/delete-node/ &port03; ++ ++&i2c1 { ++ speaker_left_rear: codec@38 { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x38>; ++ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Rear"; ++ }; ++ ++ speaker_left_front: codec@39 { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x39>; ++ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Left Front"; ++ }; ++}; ++ ++&i2c2 { ++ status = "okay"; ++}; ++ ++&i2c3 { ++ speaker_right_rear: codec@3b { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x3b>; ++ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Rear"; ++ }; ++ ++ speaker_right_front: codec@3c { ++ compatible = "ti,sn012776", "ti,tas2764"; ++ reg = <0x3c>; ++ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "Right Front"; ++ }; ++}; ++ ++&i2c4 { ++ status = "okay"; ++}; ++ ++/ { ++ backlight: gpio-bl { ++ compatible = "gpio-backlight"; ++ gpios = <&smc_gpio 18 GPIO_ACTIVE_HIGH>; ++ default-on; ++ }; ++ ++ sound { ++ compatible = "apple,j493-macaudio", "apple,macaudio"; ++ model = "MacBook Pro J493 integrated audio"; ++ ++ dai-link@0 { ++ /* ++ * DANGER ZONE: You can blow your speakers! ++ * ++ * The drivers are not ready, and unless you are careful ++ * to attenuate the audio stream, you run the risk of ++ * blowing your speakers. ++ */ ++ status = "disabled"; ++ ++ link-name = "Speakers"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 0>, <&mca 1>; ++ }; ++ codec { ++ sound-dai = <&speaker_left_front>, <&speaker_right_front>, ++ <&speaker_left_rear>, <&speaker_right_rear>; ++ }; ++ }; ++#if 0 ++ dai-link@1 { ++ link-name = "Headphone Jack"; ++ mclk-fs = <64>; ++ ++ cpu { ++ sound-dai = <&mca 2>; ++ }; ++ codec { ++ sound-dai = <&jack_codec>; ++ }; ++ }; ++#endif ++ }; ++}; ++ ++&framebuffer0 { ++ backlight = <&backlight>; ++}; ++ ++&mtp_hid { ++ multi-touch { ++ firmware-name = "apple/tpmtfw-j493.bin"; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi +new file mode 100644 +index 000000000000..a66f14f795b1 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Apple M2 MacBook Air/Pro (M2, 2022) ++ * ++ * This file contains parts common to all Apple M2 devices using the t8112. ++ * ++ * target-type: J493, J413 ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++/ { ++ aliases { ++ serial0 = &serial0; ++ serial2 = &serial2; ++ }; ++ ++ chosen { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ stdout-path = "serial0"; ++ ++ framebuffer0: framebuffer@0 { ++ compatible = "apple,simple-framebuffer", "simple-framebuffer"; ++ reg = <0 0 0 0>; /* To be filled by loader */ ++ /* Format properties will be added by loader */ ++ status = "disabled"; ++ }; ++ }; ++ ++ memory@800000000 { ++ device_type = "memory"; ++ reg = <0x8 0 0x2 0>; /* To be filled by loader */ ++ }; ++}; ++ ++&serial0 { ++ status = "okay"; ++}; ++ ++&serial2 { ++ status = "okay"; ++}; ++ ++&i2c0 { ++ hpm0: usb-pd@38 { ++ compatible = "apple,cd321x"; ++ reg = <0x38>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <8 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ ++ typec0: connector { ++ compatible = "usb-c-connector"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec0_con_hs: endpoint { ++ remote-endpoint = <&typec0_usb_hs>; ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ hpm1: usb-pd@3f { ++ compatible = "apple,cd321x"; ++ reg = <0x3f>; ++ interrupt-parent = <&pinctrl_ap>; ++ interrupts = <8 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "irq"; ++ ++ typec1: connector { ++ compatible = "usb-c-connector"; ++ power-role = "dual"; ++ data-role = "dual"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ port@0 { ++ reg = <0>; ++ typec1_con_hs: endpoint { ++ remote-endpoint = <&typec1_usb_hs>; ++ }; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++/* USB controllers */ ++&dwc3_0 { ++ port { ++ typec0_usb_hs: endpoint { ++ remote-endpoint = <&typec0_con_hs>; ++ }; ++ }; ++}; ++ ++&dwc3_1 { ++ port { ++ typec1_usb_hs: endpoint { ++ remote-endpoint = <&typec1_con_hs>; ++ }; ++ }; ++}; ++ ++&mtp { ++ status = "okay"; ++}; ++&mtp_mbox{ ++ status = "okay"; ++}; ++&mtp_dart { ++ status = "okay"; ++}; ++&mtp_dockchannel { ++ status = "okay"; ++}; ++&mtp_hid { ++ multi-touch { ++ apple,afe-reset-gpios = <&smc_gpio 8 GPIO_ACTIVE_LOW>; ++ }; ++ ++ keyboard { ++ }; ++ ++ stm { ++ apple,stm-reset-gpios = <&smc_gpio 24 GPIO_ACTIVE_LOW>; ++ }; ++ ++ actuator { ++ }; ++ ++ tp_accel { ++ }; ++}; +diff --git a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi +new file mode 100644 +index 000000000000..0f2d810921c8 +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi +@@ -0,0 +1,1141 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * PMGR Power domains for the Apple T8112 "M2" SoC ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++ ++&pmgr { ++ ps_sbr: power-controller@100 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x100 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "sbr"; ++ apple,always-on; /* Core device */ ++ }; ++ ++ ps_aic: power-controller@108 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x108 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "aic"; ++ apple,always-on; /* Core device */ ++ }; ++ ++ ps_dwi: power-controller@110 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x110 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dwi"; ++ apple,always-on; /* Core device */ ++ }; ++ ++ ps_soc_spmi0: power-controller@118 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x118 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "soc_spmi0"; ++ }; ++ ++ ps_gpio: power-controller@120 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x120 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "gpio"; ++ }; ++ ++ ps_pms_busif: power-controller@128 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x128 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "pms_busif"; ++ apple,always-on; /* Core device */ ++ }; ++ ++ ps_pms: power-controller@130 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x130 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "pms"; ++ apple,always-on; /* Core device */ ++ }; ++ ++ ps_pms_c1ppt: power-controller@160 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x160 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "pms_c1ppt"; ++ power-domains = <&ps_pms>; ++ }; ++ ++ ps_soc_dpe: power-controller@168 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x168 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "soc_dpe"; ++ apple,always-on; /* Core device */ ++ }; ++ ++ ps_pmgr_soc_ocla: power-controller@170 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x170 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "pmgr_soc_ocla"; ++ power-domains = <&ps_pms>; ++ }; ++ ++ ps_ispsens0: power-controller@178 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x178 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "ispsens0"; ++ }; ++ ++ ps_ispsens1: power-controller@180 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x180 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "ispsens1"; ++ }; ++ ++ ps_ispsens2: power-controller@188 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x188 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "ispsens2"; ++ }; ++ ++ ps_ispsens3: power-controller@190 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x190 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "ispsens3"; ++ }; ++ ++ ps_pcie_ref: power-controller@198 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x198 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "pcie_ref"; ++ }; ++ ++ ps_aft0: power-controller@1a0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "aft0"; ++ }; ++ ++ ps_imx: power-controller@1a8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "imx"; ++ apple,always-on; /* Apple fabric, critical block */ ++ }; ++ ++ ps_sio_busif: power-controller@1b0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "sio_busif"; ++ }; ++ ++ ps_sio: power-controller@1b8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1b8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "sio"; ++ apple,always-on; ++ power-domains = <&ps_sio_busif>; ++ }; ++ ++ ps_sio_cpu: power-controller@1c0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1c0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "sio_cpu"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_fpwm0: power-controller@1c8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1c8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "fpwm0"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_fpwm1: power-controller@1d0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1d0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "fpwm1"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_fpwm2: power-controller@1d8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1d8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "fpwm2"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_i2c0: power-controller@1e0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1e0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "i2c0"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_i2c1: power-controller@1e8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1e8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "i2c1"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_i2c2: power-controller@1f0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1f0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "i2c2"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_i2c3: power-controller@1f8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x1f8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "i2c3"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_i2c4: power-controller@200 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x200 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "i2c4"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_spi_p: power-controller@208 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x208 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "spi_p"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_uart_p: power-controller@210 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x210 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart_p"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_audio_p: power-controller@218 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x218 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "audio_p"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_aes: power-controller@220 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x220 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "aes"; ++ power-domains = <&ps_sio>; ++ }; ++ ++ ps_spi0: power-controller@228 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x228 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "spi0"; ++ power-domains = <&ps_spi_p>; ++ }; ++ ++ ps_spi1: power-controller@230 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x230 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "spi1"; ++ power-domains = <&ps_spi_p>; ++ }; ++ ++ ps_spi2: power-controller@238 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x238 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "spi2"; ++ power-domains = <&ps_spi_p>; ++ }; ++ ++ ps_spi3: power-controller@240 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x240 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "spi3"; ++ power-domains = <&ps_spi_p>; ++ }; ++ ++ ps_spi4: power-controller@248 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x248 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "spi4"; ++ power-domains = <&ps_spi_p>; ++ }; ++ ++ ps_spi5: power-controller@250 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x250 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "spi5"; ++ power-domains = <&ps_spi_p>; ++ }; ++ ++ ps_uart_n: power-controller@258 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x258 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart_n"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart0: power-controller@260 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x260 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart0"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart1: power-controller@268 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x268 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart1"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart2: power-controller@270 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x270 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart2"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart3: power-controller@278 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x278 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart3"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart4: power-controller@280 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x280 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart4"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart5: power-controller@288 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x288 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart5"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart6: power-controller@290 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x290 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart6"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart7: power-controller@298 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x298 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart7"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_uart8: power-controller@2a0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "uart8"; ++ power-domains = <&ps_uart_p>; ++ }; ++ ++ ps_sio_adma: power-controller@2a8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "sio_adma"; ++ power-domains = <&ps_spi_p>, <&ps_audio_p>; ++ }; ++ ++ ps_dpa0: power-controller@2b0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dpa0"; ++ power-domains = <&ps_audio_p>; ++ }; ++ ++ ps_dpa1: power-controller@2b8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2b8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dpa1"; ++ power-domains = <&ps_audio_p>; ++ }; ++ ++ ps_mca0: power-controller@2c0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2c0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mca0"; ++ power-domains = <&ps_sio_adma>, <&ps_audio_p>; ++ }; ++ ++ ps_mca1: power-controller@2c8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2c8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mca1"; ++ power-domains = <&ps_sio_adma>, <&ps_audio_p>; ++ }; ++ ++ ps_mca2: power-controller@2d0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2d0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mca2"; ++ power-domains = <&ps_sio_adma>, <&ps_audio_p>; ++ }; ++ ++ ps_mca3: power-controller@2d8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2d8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mca3"; ++ power-domains = <&ps_sio_adma>, <&ps_audio_p>; ++ }; ++ ++ ps_mca4: power-controller@2e0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2e0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mca4"; ++ power-domains = <&ps_sio_adma>, <&ps_audio_p>; ++ }; ++ ++ ps_mca5: power-controller@2e8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2e8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mca5"; ++ power-domains = <&ps_sio_adma>, <&ps_audio_p>; ++ }; ++ ++ ps_mcc: power-controller@2f0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2f0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mcc"; ++ apple,always-on; /* Memory controller */ ++ }; ++ ++ ps_dcs0: power-controller@2f8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x2f8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dcs0"; ++ apple,always-on; /* LPDDR4 interface */ ++ }; ++ ++ ps_dcs2: power-controller@300 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x300 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dcs2"; ++ apple,always-on; /* LPDDR4 interface */ ++ }; ++ ++ ps_dcs1: power-controller@308 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x308 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dcs1"; ++ apple,always-on; /* LPDDR4 interface */ ++ }; ++ ++ ps_dcs3: power-controller@310 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x310 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dcs3"; ++ apple,always-on; /* LPDDR4 interface */ ++ }; ++ ++ ps_dcs4: power-controller@318 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x318 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dcs4"; ++ apple,always-on; /* LPDDR4 interface */ ++ }; ++ ++ ps_dcs5: power-controller@320 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x320 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dcs5"; ++ apple,always-on; /* LPDDR4 interface */ ++ }; ++ ++ ps_dcs6: power-controller@328 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x328 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dcs6"; ++ apple,always-on; /* LPDDR4 interface */ ++ }; ++ ++ ps_dcs7: power-controller@330 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x330 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dcs7"; ++ apple,always-on; /* LPDDR4 interface */ ++ }; ++ ++ ps_smx0: power-controller@338 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x338 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "smx0"; ++ apple,always-on; /* Apple fabric, critical block */ ++ }; ++ ++ ps_smx1: power-controller@340 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x340 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "smx1"; ++ apple,always-on; /* Apple fabric, critical block */ ++ }; ++ ++ ps_apcie: power-controller@348 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x348 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "apcie"; ++ power-domains = <&ps_imx>, <&ps_pcie_ref>; ++ }; ++ ++ ps_rmx0: power-controller@350 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x350 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "rmx0"; ++ /* Apple Fabric, display/image stuff: this can power down */ ++ }; ++ ++ ps_rmx1: power-controller@358 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x358 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "rmx1"; ++ /* Apple Fabric, display/image stuff: this can power down */ ++ }; ++ ++ ps_cmx: power-controller@360 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x360 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "cmx"; ++ apple,always-on; /* Apple fabric, critical block */ ++ }; ++ ++ ps_mmx: power-controller@368 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x368 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mmx"; ++ /* Apple Fabric, media stuff: this can power down */ ++ }; ++ ++ ps_disp0_sys: power-controller@370 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x370 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "disp0_sys"; ++ power-domains = <&ps_rmx1>; ++ apple,always-on; /* TODO: figure out if we can enable PM here */ ++ }; ++ ++ ps_disp0_fe: power-controller@378 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x378 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "disp0_fe"; ++ power-domains = <&ps_disp0_sys>; ++ apple,always-on; /* TODO: figure out if we can enable PM here */ ++ }; ++ ++ ps_dispext_sys: power-controller@380 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x380 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dispext_sys"; ++ power-domains = <&ps_rmx0>; ++ }; ++ ++ ps_dispext_fe: power-controller@388 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x388 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dispext_fe"; ++ power-domains = <&ps_dispext_sys>; ++ }; ++ ++ ps_dispext_cpu0: power-controller@3c8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3c8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dispext_cpu0"; ++ power-domains = <&ps_dispext_fe>; ++ apple,min-state = <4>; ++ }; ++ ++ ps_dptx_ext_phy: power-controller@3d8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3d8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dptx_ext_phy"; ++ }; ++ ++ ps_dispdfr_fe: power-controller@3e0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3e0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dispdfr_fe"; ++ power-domains = <&ps_rmx0>; ++ }; ++ ++ ps_dispdfr_be: power-controller@3e8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3e8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "dispdfr_be"; ++ power-domains = <&ps_dispdfr_fe>; ++ }; ++ ++ ps_mipi_dsi: power-controller@3f0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3f0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "mipi_dsi"; ++ power-domains = <&ps_dispdfr_be>; ++ }; ++ ++ ps_jpg: power-controller@3f8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x3f8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "jpg"; ++ power-domains = <&ps_cmx>; ++ }; ++ ++ ps_apcie_gp: power-controller@400 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x400 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "apcie_gp"; ++ power-domains = <&ps_apcie>; ++ apple,always-on; /* Breaks things if shut down */ ++ }; ++ ++ ps_msr: power-controller@408 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x408 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "msr"; ++ power-domains = <&ps_imx>; ++ }; ++ ++ ps_pmp: power-controller@410 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x410 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "pmp"; ++ apple,always-on; ++ }; ++ ++ ps_pms_sram: power-controller@418 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x418 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "pms_sram"; ++ apple,always-on; ++ }; ++ ++ ps_msr_ase_core: power-controller@420 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x420 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "msr_ase_core"; ++ power-domains = <&ps_msr>; ++ }; ++ ++ ps_ans: power-controller@428 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x428 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "ans"; ++ power-domains = <&ps_imx>; ++ }; ++ ++ ps_gfx: power-controller@430 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x430 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "gfx"; ++ }; ++ ++ ps_isp_sys: power-controller@438 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x438 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "isp_sys"; ++ power-domains = <&ps_rmx1>; ++ }; ++ ++ ps_venc_sys: power-controller@440 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x440 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "venc_sys"; ++ power-domains = <&ps_rmx1>; ++ }; ++ ++ ps_avd_sys: power-controller@448 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x448 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "avd_sys"; ++ power-domains = <&ps_mmx>; ++ }; ++ ++ ps_apcie_st: power-controller@450 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x450 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "apcie_st"; ++ power-domains = <&ps_apcie>, <&ps_ans>; ++ }; ++ ++ ps_atc0_common: power-controller@458 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x458 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc0_common"; ++ power-domains = <&ps_imx>; ++ }; ++ ++ ps_atc0_pcie: power-controller@460 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x460 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc0_pcie"; ++ power-domains = <&ps_atc0_common>; ++ }; ++ ++ ps_atc0_cio: power-controller@468 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x468 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc0_cio"; ++ power-domains = <&ps_atc0_common>; ++ }; ++ ++ ps_atc0_cio_pcie: power-controller@470 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x470 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc0_cio_pcie"; ++ power-domains = <&ps_atc0_cio>; ++ }; ++ ++ ps_atc0_cio_usb: power-controller@478 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x478 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc0_cio_usb"; ++ power-domains = <&ps_atc0_cio>; ++ }; ++ ++ ps_atc1_common: power-controller@480 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x480 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc1_common"; ++ power-domains = <&ps_rmx0>; ++ }; ++ ++ ps_atc1_pcie: power-controller@488 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x488 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc1_pcie"; ++ power-domains = <&ps_atc1_common>; ++ }; ++ ++ ps_atc1_cio: power-controller@490 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x490 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc1_cio"; ++ power-domains = <&ps_atc1_common>; ++ }; ++ ++ ps_atc1_cio_pcie: power-controller@498 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x498 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc1_cio_pcie"; ++ power-domains = <&ps_atc1_cio>; ++ }; ++ ++ ps_atc1_cio_usb: power-controller@4a0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x4a0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc1_cio_usb"; ++ power-domains = <&ps_atc1_cio>; ++ }; ++ ++ ps_ane_sys: power-controller@4a8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x4a8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "ane_sys"; ++ power-domains = <&ps_mmx>; ++ }; ++ ++ ps_scodec: power-controller@4b0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x4b0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "scodec"; ++ power-domains = <&ps_rmx0>; ++ }; ++ ++ ps_sep: power-controller@c00 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xc00 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "sep"; ++ apple,always-on; ++ }; ++ ++ ps_venc_dma: power-controller@8000 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8000 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "venc_dma"; ++ power-domains = <&ps_venc_sys>; ++ }; ++ ++ ps_venc_pipe4: power-controller@8008 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8008 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "venc_pipe4"; ++ power-domains = <&ps_venc_dma>; ++ }; ++ ++ ps_venc_pipe5: power-controller@8010 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8010 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "venc_pipe5"; ++ power-domains = <&ps_venc_dma>; ++ }; ++ ++ ps_venc_me0: power-controller@8018 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8018 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "venc_me0"; ++ power-domains = <&ps_venc_pipe5>, <&ps_venc_pipe4>; ++ }; ++ ++ ps_venc_me1: power-controller@8020 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x8020 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "venc_me1"; ++ power-domains = <&ps_venc_pipe5>, <&ps_venc_pipe4>; ++ }; ++ ++ ps_disp0_cpu0: power-controller@10000 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x10000 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "disp0_cpu0"; ++ power-domains = <&ps_disp0_fe>; ++ apple,min-state = <4>; ++ }; ++}; ++ ++&pmgr_mini { ++ ++ ps_debug_gated: power-controller@58 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x58 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "debug_gated"; ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ ps_nub_spmi0: power-controller@60 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x60 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "nub_spmi0"; ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ ps_nub_spmi1: power-controller@68 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x68 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "nub_spmi1"; ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ ps_nub_aon: power-controller@70 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x70 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "nub_aon"; ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ ps_msg: power-controller@78 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x78 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "msg"; ++ }; ++ ++ ps_nub_gpio: power-controller@80 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x80 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "nub_gpio"; ++ apple,always-on; ++ }; ++ ++ ps_atc0_usb_aon: power-controller@88 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x88 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc0_usb_aon"; ++ apple,always-on; /* Needs to stay on for dwc3 to work */ ++ }; ++ ++ ps_atc1_usb_aon: power-controller@90 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x90 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc1_usb_aon"; ++ apple,always-on; /* Needs to stay on for dwc3 to work */ ++ }; ++ ++ ps_atc0_usb: power-controller@98 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0x98 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc0_usb"; ++ power-domains = <&ps_atc0_usb_aon>, <&ps_atc0_common>; ++ }; ++ ++ ps_atc1_usb: power-controller@a0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xa0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "atc1_usb"; ++ power-domains = <&ps_atc1_usb_aon>, <&ps_atc1_common>; ++ }; ++ ++ ps_nub_fabric: power-controller@a8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xa8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "nub_fabric"; ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ ps_nub_sram: power-controller@b0 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xb0 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "nub_sram"; ++ apple,always-on; /* Core AON device */ ++ }; ++ ++ ps_debug_switch: power-controller@b8 { ++ compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; ++ reg = <0xb8 4>; ++ #power-domain-cells = <0>; ++ #reset-cells = <0>; ++ label = "debug_switch"; ++ apple,always-on; /* Core AON device */ ++ }; ++}; ++ +diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi +new file mode 100644 +index 000000000000..852937ec80ea +--- /dev/null ++++ b/arch/arm64/boot/dts/apple/t8112.dtsi +@@ -0,0 +1,1097 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR MIT ++/* ++ * Apple T8112 "M2" SoC ++ * ++ * Other names: H14G ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/ { ++ compatible = "apple,t8112", "apple,arm-platform"; ++ ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ cpus { ++ #address-cells = <2>; ++ #size-cells = <0>; ++ ++ cpu-map { ++ cluster0 { ++ core0 { ++ cpu = <&cpu_e0>; ++ }; ++ core1 { ++ cpu = <&cpu_e1>; ++ }; ++ core2 { ++ cpu = <&cpu_e2>; ++ }; ++ core3 { ++ cpu = <&cpu_e3>; ++ }; ++ }; ++ ++ cluster1 { ++ core0 { ++ cpu = <&cpu_p0>; ++ }; ++ core1 { ++ cpu = <&cpu_p1>; ++ }; ++ core2 { ++ cpu = <&cpu_p2>; ++ }; ++ core3 { ++ cpu = <&cpu_p3>; ++ }; ++ }; ++ }; ++ ++ cpu_e0: cpu@0 { ++ compatible = "apple,blizzard"; ++ device_type = "cpu"; ++ reg = <0x0 0x0>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; // TODO ++ apple,freq-domain = <&cpufreq_hw 0>; ++ }; ++ ++ cpu_e1: cpu@1 { ++ compatible = "apple,blizzard"; ++ device_type = "cpu"; ++ reg = <0x0 0x1>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; // TODO ++ apple,freq-domain = <&cpufreq_hw 0>; ++ }; ++ ++ cpu_e2: cpu@2 { ++ compatible = "apple,blizzard"; ++ device_type = "cpu"; ++ reg = <0x0 0x2>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; // TODO ++ apple,freq-domain = <&cpufreq_hw 0>; ++ }; ++ ++ cpu_e3: cpu@3 { ++ compatible = "apple,blizzard"; ++ device_type = "cpu"; ++ reg = <0x0 0x3>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; // TODO ++ apple,freq-domain = <&cpufreq_hw 0>; ++ }; ++ ++ cpu_p0: cpu@10100 { ++ compatible = "apple,avalanche"; ++ device_type = "cpu"; ++ reg = <0x0 0x10100>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; ++ }; ++ ++ cpu_p1: cpu@10101 { ++ compatible = "apple,avalanche"; ++ device_type = "cpu"; ++ reg = <0x0 0x10101>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; ++ }; ++ ++ cpu_p2: cpu@10102 { ++ compatible = "apple,avalanche"; ++ device_type = "cpu"; ++ reg = <0x0 0x10102>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; ++ }; ++ ++ cpu_p3: cpu@10103 { ++ compatible = "apple,avalanche"; ++ device_type = "cpu"; ++ reg = <0x0 0x10103>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; ++ }; ++ }; ++ ++ ecluster_opp: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <7500>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <912000000>; ++ opp-level = <2>; ++ clock-latency-ns = <20000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <1284000000>; ++ opp-level = <3>; ++ clock-latency-ns = <22000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <1752000000>; ++ opp-level = <4>; ++ clock-latency-ns = <30000>; ++ }; ++ opp05 { ++ opp-hz = /bits/ 64 <2004000000>; ++ opp-level = <5>; ++ clock-latency-ns = <35000>; ++ }; ++ opp06 { ++ opp-hz = /bits/ 64 <2256000000>; ++ opp-level = <6>; ++ clock-latency-ns = <39000>; ++ }; ++ opp07 { ++ opp-hz = /bits/ 64 <2424000000>; ++ opp-level = <7>; ++ clock-latency-ns = <53000>; ++ }; ++ }; ++ ++ pcluster_opp: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <660000000>; ++ opp-level = <1>; ++ clock-latency-ns = <9000>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <924000000>; ++ opp-level = <2>; ++ clock-latency-ns = <19000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <1188000000>; ++ opp-level = <3>; ++ clock-latency-ns = <22000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <1452000000>; ++ opp-level = <4>; ++ clock-latency-ns = <24000>; ++ }; ++ opp05 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-level = <5>; ++ clock-latency-ns = <26000>; ++ }; ++ opp06 { ++ opp-hz = /bits/ 64 <1968000000>; ++ opp-level = <6>; ++ clock-latency-ns = <28000>; ++ }; ++ opp07 { ++ opp-hz = /bits/ 64 <2208000000>; ++ opp-level = <7>; ++ clock-latency-ns = <30000>; ++ }; ++ opp08 { ++ opp-hz = /bits/ 64 <2400000000>; ++ opp-level = <8>; ++ clock-latency-ns = <33000>; ++ }; ++ opp09 { ++ opp-hz = /bits/ 64 <2568000000>; ++ opp-level = <9>; ++ clock-latency-ns = <34000>; ++ }; ++ opp10 { ++ opp-hz = /bits/ 64 <2724000000>; ++ opp-level = <10>; ++ clock-latency-ns = <36000>; ++ }; ++ opp11 { ++ opp-hz = /bits/ 64 <2868000000>; ++ opp-level = <11>; ++ clock-latency-ns = <41000>; ++ }; ++ opp12 { ++ opp-hz = /bits/ 64 <2988000000>; ++ opp-level = <12>; ++ clock-latency-ns = <42000>; ++ }; ++ opp13 { ++ opp-hz = /bits/ 64 <3096000000>; ++ opp-level = <13>; ++ clock-latency-ns = <44000>; ++ }; ++ opp14 { ++ opp-hz = /bits/ 64 <3204000000>; ++ opp-level = <14>; ++ clock-latency-ns = <46000>; ++ }; ++ /* Not available until CPU deep sleep is implemented */ ++#if 0 ++ opp15 { ++ opp-hz = /bits/ 64 <3324000000>; ++ opp-level = <15>; ++ clock-latency-ns = <62000>; ++ turbo-mode; ++ }; ++ opp16 { ++ opp-hz = /bits/ 64 <3408000000>; ++ opp-level = <16>; ++ clock-latency-ns = <62000>; ++ turbo-mode; ++ }; ++ opp17 { ++ opp-hz = /bits/ 64 <3504000000>; ++ opp-level = <17>; ++ clock-latency-ns = <62000>; ++ turbo-mode; ++ }; ++#endif ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupt-parent = <&aic>; ++ interrupt-names = "phys", "virt", "hyp-phys", "hyp-virt"; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ pmu-e { ++ compatible = "apple,blizzard-pmu"; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ }; ++ ++ pmu-p { ++ compatible = "apple,avalanche-pmu"; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ }; ++ ++ clkref: clock-ref { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ clock-output-names = "clkref"; ++ }; ++ ++ clk_120m: clock-120m { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <120000000>; ++ clock-output-names = "clk_120m"; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ ranges; ++ nonposted-mmio; ++ ++ cpufreq_hw: cpufreq@210e20000 { ++ compatible = "apple,t8112-soc-cpufreq", "apple,soc-cpufreq"; ++ reg = <0x2 0x10e20000 0 0x1000>, ++ <0x2 0x11e20000 0 0x1000>; ++ reg-names = "cluster0", "cluster1"; ++ ++ #freq-domain-cells = <1>; ++ }; ++ ++ i2c0: i2c@235010000 { ++ compatible = "apple,t8112-i2c", "apple,i2c"; ++ reg = <0x2 0x35010000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-names = "default"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ power-domains = <&ps_i2c0>; ++ }; ++ ++ i2c1: i2c@235014000 { ++ compatible = "apple,t8112-i2c", "apple,i2c"; ++ reg = <0x2 0x35014000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-names = "default"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ power-domains = <&ps_i2c1>; ++ }; ++ ++ i2c2: i2c@235018000 { ++ compatible = "apple,t8112-i2c", "apple,i2c"; ++ reg = <0x2 0x35018000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c2_pins>; ++ pinctrl-names = "default"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ status = "disabled"; /* not used in all devices */ ++ power-domains = <&ps_i2c2>; ++ }; ++ ++ i2c3: i2c@23501c000 { ++ compatible = "apple,t8112-i2c", "apple,i2c"; ++ reg = <0x2 0x3501c000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c3_pins>; ++ pinctrl-names = "default"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ power-domains = <&ps_i2c3>; ++ }; ++ ++ i2c4: i2c@235020000 { ++ compatible = "apple,t8112-i2c", "apple,i2c"; ++ reg = <0x2 0x35020000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ pinctrl-0 = <&i2c4_pins>; ++ pinctrl-names = "default"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ power-domains = <&ps_i2c4>; ++ status = "disabled"; ++ }; ++ ++ spi3: spi@23510c000 { ++ compatible = "apple,t8112-spi", "apple,spi"; ++ reg = <0x2 0x3510c000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ clocks = <&clk_120m>; ++ pinctrl-0 = <&spi3_pins>; ++ pinctrl-names = "default"; ++ power-domains = <&ps_spi3>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ serial0: serial@235200000 { ++ compatible = "apple,s5l-uart"; ++ reg = <0x2 0x35200000 0x0 0x1000>; ++ reg-io-width = <4>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ /* ++ * TODO: figure out the clocking properly, there may ++ * be a third selectable clock. ++ */ ++ clocks = <&clkref>, <&clkref>; ++ clock-names = "uart", "clk_uart_baud0"; ++ power-domains = <&ps_uart0>; ++ status = "disabled"; ++ }; ++ ++ serial2: serial@235208000 { ++ compatible = "apple,s5l-uart"; ++ reg = <0x2 0x35208000 0x0 0x1000>; ++ reg-io-width = <4>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ clocks = <&clkref>, <&clkref>; ++ clock-names = "uart", "clk_uart_baud0"; ++ power-domains = <&ps_uart2>; ++ status = "disabled"; ++ }; ++ ++ aic: interrupt-controller@23b0c0000 { ++ compatible = "apple,t8112-aic", "apple,aic2"; ++ #interrupt-cells = <3>; ++ interrupt-controller; ++ reg = <0x2 0x3b0c0000 0x0 0x8000>, ++ <0x2 0x3b0c8000 0x0 0x4>; ++ reg-names = "core", "event"; ++ power-domains = <&ps_aic>; ++ ++ affinities { ++ e-core-pmu-affinity { ++ apple,fiq-index = ; ++ cpus = <&cpu_e0 &cpu_e1 &cpu_e2 &cpu_e3>; ++ }; ++ ++ p-core-pmu-affinity { ++ apple,fiq-index = ; ++ cpus = <&cpu_p0 &cpu_p1 &cpu_p2 &cpu_p3>; ++ }; ++ }; ++ }; ++ ++ pmgr: power-management@23b700000 { ++ compatible = "apple,t8112-pmgr", "apple,pmgr", "syscon", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2 0x3b700000 0 0x10000>; ++ }; ++ ++ pinctrl_ap: pinctrl@23c100000 { ++ compatible = "apple,t8112-pinctrl", "apple,pinctrl"; ++ reg = <0x2 0x3c100000 0x0 0x100000>; ++ power-domains = <&ps_gpio>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl_ap 0 0 213>; ++ apple,npins = <213>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ ; ++ ++ i2c0_pins: i2c0-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c1_pins: i2c1-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c2_pins: i2c2-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c3_pins: i2c3-pins { ++ pinmux = , ++ ; ++ }; ++ ++ i2c4_pins: i2c4-pins { ++ pinmux = , ++ ; ++ }; ++ ++ spi3_pins: spi3-pins { ++ pinmux = , ++ , ++ , ++ ; ++ }; ++ ++ pcie_pins: pcie-pins { ++ pinmux = ; ++ // TODO: 3 more CLKREQs ++ }; ++ }; ++ ++ nub_spmi: spmi@23d0d9300 { ++ compatible = "apple,t8112-spmi", "apple,spmi"; ++ reg = <0x2 0x3d714000 0x0 0x100>; ++ #address-cells = <2>; ++ #size-cells = <0>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ ; ++ ++ pmu1: pmu@e { ++ compatible = "apple,stowe-pmu", "apple,spmi-pmu"; ++ reg = <0xe SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ rtc_nvmem@f800 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0xf800 0x300>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ pm_setting: pm-setting@1 { ++ reg = <0x1 0x1>; ++ }; ++ ++ rtc_offset: rtc-offset@100 { ++ reg = <0x100 0x6>; ++ }; ++ }; ++ ++ legacy_nvmem@f700 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0xf700 0x20>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ boot_stage: boot-stage@1 { ++ reg = <0x1 0x1>; ++ }; ++ ++ boot_error_count: boot-error-count@2 { ++ reg = <0x2 0x1>; ++ bits = <0 4>; ++ }; ++ ++ panic_count: panic-count@2 { ++ reg = <0x2 0x1>; ++ bits = <4 4>; ++ }; ++ ++ boot_error_stage: boot-error-stage@3 { ++ reg = <0x3 0x1>; ++ }; ++ ++ shutdown_flag: shutdown-flag@f { ++ reg = <0xf 0x1>; ++ bits = <3 1>; ++ }; ++ }; ++ ++ scrpad_nvmem@8000 { ++ compatible = "apple,spmi-pmu-nvmem"; ++ reg = <0x8000 0x2800>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ fault_shadow: fault-shadow@67b { ++ reg = <0x67b 0x10>; ++ }; ++ ++ socd: socd@b00 { ++ reg = <0xb00 0x400>; ++ }; ++ }; ++ ++ }; ++ }; ++ ++ pinctrl_nub: pinctrl@23d1f0000 { ++ compatible = "apple,t8112-pinctrl", "apple,pinctrl"; ++ reg = <0x2 0x3d1f0000 0x0 0x4000>; ++ power-domains = <&ps_nub_gpio>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl_nub 0 0 24>; ++ apple,npins = <24>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ ; ++ }; ++ ++ pmgr_mini: power-management@23d280000 { ++ compatible = "apple,t8112-pmgr", "apple,pmgr", "syscon", "simple-mfd"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2 0x3d280000 0 0x4000>; ++ }; ++ ++ wdt: watchdog@23d2b0000 { ++ compatible = "apple,t8112-wdt", "apple,wdt"; ++ reg = <0x2 0x3d2b0000 0x0 0x4000>; ++ clocks = <&clkref>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ }; ++ ++ smc_mbox: mbox@23e408000 { ++ compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; ++ reg = <0x2 0x3e408000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "send-empty", "send-not-empty", ++ "recv-empty", "recv-not-empty"; ++ #mbox-cells = <0>; ++ }; ++ ++ smc: smc@23e400000 { ++ compatible = "apple,t8112-smc", "apple,smc"; ++ reg = <0x2 0x3e400000 0x0 0x4000>, ++ <0x2 0x3fe00000 0x0 0x100000>; ++ reg-names = "smc", "sram"; ++ mboxes = <&smc_mbox>; ++ ++ smc_gpio: gpio { ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ smc_rtc: rtc { ++ nvmem-cells = <&rtc_offset>; ++ nvmem-cell-names = "rtc_offset"; ++ }; ++ ++ smc_reboot: reboot { ++ nvmem-cells = <&shutdown_flag>, <&boot_stage>, ++ <&boot_error_count>, <&panic_count>, <&pm_setting>; ++ nvmem-cell-names = "shutdown_flag", "boot_stage", ++ "boot_error_count", "panic_count", "pm_setting"; ++ }; ++ }; ++ ++ pinctrl_smc: pinctrl@23e820000 { ++ compatible = "apple,t8112-pinctrl", "apple,pinctrl"; ++ reg = <0x2 0x3e820000 0x0 0x4000>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl_smc 0 0 18>; ++ apple,npins = <18>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ ; ++ }; ++ ++ pinctrl_aop: pinctrl@24a820000 { ++ compatible = "apple,t8112-pinctrl", "apple,pinctrl"; ++ reg = <0x2 0x4a820000 0x0 0x4000>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl_aop 0 0 54>; ++ apple,npins = <54>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ ; ++ }; ++ ++ mtp: mtp@24e400000 { ++ compatible = "apple,t8112-mtp", "apple,t8112-rtk-helper-asc4", "apple,mtp", "apple,rtk-helper-asc4"; ++ reg = <0x2 0x4e400000 0x0 0x4000>, ++ <0x2 0x4ec9c000 0x0 0x8000>; ++ reg-names = "asc", "sram"; ++ mboxes = <&mtp_mbox>; ++ iommus = <&mtp_dart 1>; ++ #helper-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ ++ mtp_mbox: mbox@24e408000 { ++ compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; ++ reg = <0x2 0x4e408000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "send-empty", "send-not-empty", ++ "recv-empty", "recv-not-empty"; ++ #mbox-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ ++ mtp_dart: iommu@24e808000 { ++ compatible = "apple,t8112-dart", "apple,t8110-dart"; ++ reg = <0x2 0x4e808000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ ++ status = "disabled"; ++ }; ++ ++ mtp_dockchannel: fifo@24eb14000 { ++ compatible = "apple,t8112-dockchannel", "apple,dockchannel"; ++ reg = <0x2 0x4eb14000 0x0 0x4000>; ++ reg-names = "irq"; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ ++ ranges = <0 0x2 0x4eb28000 0x20000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ status = "disabled"; ++ ++ mtp_hid: input@8000 { ++ compatible = "apple,dockchannel-hid"; ++ reg = <0x8000 0x4000>, ++ <0xc000 0x4000>, ++ <0x0000 0x4000>, ++ <0x4000 0x4000>; ++ reg-names = "config", "data", ++ "rmt-config", "rmt-data"; ++ iommus = <&mtp_dart 1>; ++ interrupt-parent = <&mtp_dockchannel>; ++ interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, ++ <3 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "tx", "rx"; ++ ++ apple,fifo-size = <0x800>; ++ apple,helper-cpu = <&mtp>; ++ }; ++ ++ }; ++ ++ ans_mbox: mbox@277408000 { ++ compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; ++ reg = <0x2 0x77408000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "send-empty", "send-not-empty", ++ "recv-empty", "recv-not-empty"; ++ #mbox-cells = <0>; ++ power-domains = <&ps_ans>; ++ }; ++ ++ sart: sart@27bc50000 { ++ compatible = "apple,t8112-sart", "apple,t6000-sart"; ++ reg = <0x2 0x7bc50000 0x0 0x10000>; ++ power-domains = <&ps_ans>; ++ }; ++ ++ nvme@27bcc0000 { ++ compatible = "apple,t8112-nvme-ans2", "apple,nvme-ans2"; ++ reg = <0x2 0x7bcc0000 0x0 0x40000>, ++ <0x2 0x77400000 0x0 0x4000>; ++ reg-names = "nvme", "ans"; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ mboxes = <&ans_mbox>; ++ apple,sart = <&sart>; ++ power-domains = <&ps_ans>, <&ps_apcie_st>; ++ power-domain-names = "ans", "apcie0"; ++ resets = <&ps_ans>; ++ }; ++ ++ dwc3_0: usb@382280000 { ++ compatible = "apple,t8112-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0x3 0x82280000 0x0 0x100000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ dr_mode = "otg"; ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ iommus = <&dwc3_0_dart_0 0>, <&dwc3_0_dart_1 1>; ++ power-domains = <&ps_atc0_usb>; ++ }; ++ ++ dwc3_0_dart_0: iommu@382f00000 { ++ compatible = "apple,t8112-dart", "apple,t8110-dart"; ++ reg = <0x3 0x82f00000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_atc0_usb>; ++ }; ++ ++ dwc3_0_dart_1: iommu@382f80000 { ++ compatible = "apple,t8112-dart", "apple,t8110-dart"; ++ reg = <0x3 0x82f80000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_atc0_usb>; ++ }; ++ ++ dwc3_1: usb@502280000 { ++ compatible = "apple,t8112-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0x5 0x02280000 0x0 0x100000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ dr_mode = "otg"; ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ iommus = <&dwc3_1_dart_0 0>, <&dwc3_1_dart_1 1>; ++ power-domains = <&ps_atc1_usb>; ++ }; ++ ++ dwc3_1_dart_0: iommu@502f00000 { ++ compatible = "apple,t8112-dart", "apple,t8110-dart"; ++ reg = <0x5 0x02f00000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_atc1_usb>; ++ }; ++ ++ dwc3_1_dart_1: iommu@502f80000 { ++ compatible = "apple,t8112-dart", "apple,t8110-dart"; ++ reg = <0x5 0x02f80000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_atc1_usb>; ++ }; ++ ++ pcie0_dart: dart@681008000 { ++ compatible = "apple,t8112-dart", "apple,t8110-dart"; ++ reg = <0x6 0x81008000 0x0 0x4000>; ++ #iommu-cells = <1>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ power-domains = <&ps_apcie_gp>; ++ }; ++ ++ pcie0: pcie@690000000 { ++ compatible = "apple,t8112-pcie", "apple,pcie"; ++ device_type = "pci"; ++ ++ reg = <0x6 0x90000000 0x0 0x1000000>, ++ <0x6 0x80000000 0x0 0x100000>, ++ <0x6 0x81000000 0x0 0x4000>, ++ <0x6 0x82000000 0x0 0x4000>, ++ <0x6 0x83000000 0x0 0x4000>, ++ <0x6 0x84000000 0x0 0x4000>; ++ reg-names = "config", "rc", "port0", "port1", "port2", "port3"; ++ ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ ; ++ ++ msi-controller; ++ msi-parent = <&pcie0>; ++ msi-ranges = <&aic AIC_IRQ 793 IRQ_TYPE_EDGE_RISING 32>; ++ ++ iommu-map = <0x100 &pcie0_dart 0 1>, ++ <0x200 &pcie0_dart 1 1>, ++ <0x300 &pcie0_dart 2 1>, ++ <0x400 &pcie0_dart 3 1>; ++ iommu-map-mask = <0xff00>; ++ ++ bus-range = <0 4>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges = <0x43000000 0x6 0xa0000000 0x6 0xa0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xc0000000 0x6 0xc0000000 0x0 0x40000000>; ++ ++ power-domains = <&ps_apcie_gp>; ++ pinctrl-0 = <&pcie_pins>; ++ pinctrl-names = "default"; ++ ++ port00: pci@0,0 { ++ device_type = "pci"; ++ reg = <0x0 0x0 0x0 0x0 0x0>; ++ reset-gpios = <&pinctrl_ap 166 GPIO_ACTIVE_LOW>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port00 0 0 0 0>, ++ <0 0 0 2 &port00 0 0 0 1>, ++ <0 0 0 3 &port00 0 0 0 2>, ++ <0 0 0 4 &port00 0 0 0 3>; ++ }; ++ ++ /* TODO: GPIOs unknown */ ++ port01: pci@1,0 { ++ device_type = "pci"; ++ reg = <0x800 0x0 0x0 0x0 0x0>; ++ //reset-gpios = <&pinctrl_ap 153 GPIO_ACTIVE_LOW>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port01 0 0 0 0>, ++ <0 0 0 2 &port01 0 0 0 1>, ++ <0 0 0 3 &port01 0 0 0 2>, ++ <0 0 0 4 &port01 0 0 0 3>; ++ }; ++ ++ port02: pci@2,0 { ++ device_type = "pci"; ++ reg = <0x1000 0x0 0x0 0x0 0x0>; ++ //reset-gpios = <&pinctrl_ap 33 GPIO_ACTIVE_LOW>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port02 0 0 0 0>, ++ <0 0 0 2 &port02 0 0 0 1>, ++ <0 0 0 3 &port02 0 0 0 2>, ++ <0 0 0 4 &port02 0 0 0 3>; ++ }; ++ ++ port03: pci@3,0 { ++ device_type = "pci"; ++ reg = <0x1800 0x0 0x0 0x0 0x0>; ++ //reset-gpios = <&pinctrl_ap 33 GPIO_ACTIVE_LOW>; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port03 0 0 0 0>, ++ <0 0 0 2 &port03 0 0 0 1>, ++ <0 0 0 3 &port03 0 0 0 2>, ++ <0 0 0 4 &port03 0 0 0 3>; ++ }; ++ }; ++ ++ dart_sio: iommu@235004000 { ++ compatible = "apple,t8112-dart", "apple,t8110-dart", "apple,dart"; ++ reg = <0x2 0x35004000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ power-domains = <&ps_sio_cpu>; ++ }; ++ ++ nco_inp: clock-ref { ++ compatible = "fixed-factor-clock"; ++ clocks = <&clkref>; ++ #clock-cells = <0>; ++ clock-mult = <75>; ++ clock-div = <2>; // 24 MHz * (75/2) = 900 MHz ++ clock-output-names = "nco_inp"; ++ }; ++ ++ nco: nco@23b044000 { ++ compatible = "apple,t8112-nco", "apple,nco"; ++ reg = <0x2 0x3b044000 0x0 0x14000>; ++ clocks = <&nco_inp>; ++ #clock-cells = <1>; ++ apple,nchannels = <5>; ++ }; ++ ++ admac: dma-controller@238200000 { ++ compatible = "apple,t8112-admac", "apple,admac"; ++ reg = <0x2 0x38200000 0x0 0x34000>; ++ dma-channels = <24>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #dma-cells = <1>; ++ iommus = <&dart_sio 2>; ++ power-domains = <&ps_sio_adma>; ++ apple,internal-irq-destination = <1>; ++ }; ++ ++ mca: mca@38400000 { ++ compatible = "apple,t8112-mca", "apple,mca"; ++ reg = <0x2 0x38400000 0x0 0x18000>, ++ <0x2 0x38300000 0x0 0x30000>; ++ reg-names = "clusters", "switch"; ++ ++ interrupt-parent = <&aic>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ ; ++ ++ clocks = <&nco 0>, <&nco 1>, <&nco 2>, ++ <&nco 3>, <&nco 4>, <&nco 4>; ++ power-domains = <&ps_audio_p>, <&ps_mca0>, <&ps_mca1>, ++ <&ps_mca2>, <&ps_mca3>, <&ps_mca4>, <&ps_mca5>; ++ dmas = <&admac 0>, <&admac 1>, <&admac 2>, <&admac 3>, ++ <&admac 4>, <&admac 5>, <&admac 6>, <&admac 7>, ++ <&admac 8>, <&admac 9>, <&admac 10>, <&admac 11>, ++ <&admac 12>, <&admac 13>, <&admac 14>, <&admac 15>, ++ <&admac 16>, <&admac 17>, <&admac 18>, <&admac 19>, ++ <&admac 20>, <&admac 21>, <&admac 22>, <&admac 23>; ++ dma-names = "tx0a", "rx0a", "tx0b", "rx0b", ++ "tx1a", "rx1a", "tx1b", "rx1b", ++ "tx2a", "rx2a", "tx2b", "rx2b", ++ "tx3a", "rx3a", "tx3b", "rx3b", ++ "tx4a", "rx4a", "tx4b", "rx4b", ++ "tx5a", "rx5a", "tx5b", "rx5b"; ++ ++ #sound-dai-cells = <1>; ++ apple,nclusters = <6>; ++ }; ++ }; ++}; ++ ++#include "t8112-pmgr.dtsi" +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0038-arm64-dts-apple-t8112-j413-Fix-IRQ-for-hpm5.patch b/target/linux/silicon/patches-5.19/0038-arm64-dts-apple-t8112-j413-Fix-IRQ-for-hpm5.patch new file mode 100644 index 000000000..24d5f70cd --- /dev/null +++ b/target/linux/silicon/patches-5.19/0038-arm64-dts-apple-t8112-j413-Fix-IRQ-for-hpm5.patch @@ -0,0 +1,26 @@ +From 792f2972bf4474af46468ab83cc7e0ab91469f2c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 24 Jul 2022 00:11:49 +0900 +Subject: [PATCH 038/171] arm64: dts: apple: t8112-j413: Fix IRQ for hpm5 + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8112-j413.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts +index 0cc993c0a5b4..0d4306a39fe8 100644 +--- a/arch/arm64/boot/dts/apple/t8112-j413.dts ++++ b/arch/arm64/boot/dts/apple/t8112-j413.dts +@@ -74,7 +74,7 @@ hpm5: usb-pd@3a { + compatible = "apple,cd321x"; + reg = <0x3a>; + interrupt-parent = <&pinctrl_ap>; +- interrupts = <174 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; + }; + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0039-MAINTAINERS-Add-Apple-dwc3-bindings-to-ARM-APPLE.patch b/target/linux/silicon/patches-5.19/0039-MAINTAINERS-Add-Apple-dwc3-bindings-to-ARM-APPLE.patch new file mode 100644 index 000000000..545955d6d --- /dev/null +++ b/target/linux/silicon/patches-5.19/0039-MAINTAINERS-Add-Apple-dwc3-bindings-to-ARM-APPLE.patch @@ -0,0 +1,30 @@ +From aa4f300d5409c9a3d21787d170755ed417f95157 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 12 Dec 2021 12:28:41 +0900 +Subject: [PATCH 039/171] MAINTAINERS: Add Apple dwc3 bindings to ARM/APPLE + +This Apple dwc3 controller variance is present on Apple ARM SoCs (t8103/t600x). + +Splitting this change from the binding/driver commits to avoid merge +conflicts with other things touching this section, as usual. + +Signed-off-by: Hector Martin +--- + MAINTAINERS | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 64379c699903..b346659f9562 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1843,6 +1843,7 @@ F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml + F: Documentation/devicetree/bindings/pci/apple,pcie.yaml + F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml + F: Documentation/devicetree/bindings/power/apple* ++F: Documentation/devicetree/bindings/usb/apple,dwc3.yaml + F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml + F: arch/arm64/boot/dts/apple/ + F: drivers/clk/clk-apple-nco.c +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0040-MAINTAINERS-Add-apple-spi-driver-binding-files.patch b/target/linux/silicon/patches-5.19/0040-MAINTAINERS-Add-apple-spi-driver-binding-files.patch new file mode 100644 index 000000000..3775039a7 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0040-MAINTAINERS-Add-apple-spi-driver-binding-files.patch @@ -0,0 +1,38 @@ +From fa0ce4da1a4d60e003f808c21c008fb19ee31152 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 12 Dec 2021 12:28:41 +0900 +Subject: [PATCH 040/171] MAINTAINERS: Add apple-spi driver & binding files + +This Apple SPI controller is present on Apple ARM SoCs (t8103/t6000). + +Splitting this change from the binding/driver commits to avoid merge +conflicts with other things touching this section, as usual. + +Signed-off-by: Hector Martin +--- + MAINTAINERS | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index b346659f9562..629c1a177d3f 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1843,6 +1843,7 @@ F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml + F: Documentation/devicetree/bindings/pci/apple,pcie.yaml + F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml + F: Documentation/devicetree/bindings/power/apple* ++F: Documentation/devicetree/bindings/spi/apple,spi.yaml + F: Documentation/devicetree/bindings/usb/apple,dwc3.yaml + F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml + F: arch/arm64/boot/dts/apple/ +@@ -1856,6 +1857,7 @@ F: drivers/nvme/host/apple.c + F: drivers/nvmem/apple-efuses.c + F: drivers/pinctrl/pinctrl-apple-gpio.c + F: drivers/soc/apple/* ++F: drivers/spi/spi-apple.c + F: drivers/watchdog/apple_wdt.c + F: include/dt-bindings/interrupt-controller/apple-aic.h + F: include/dt-bindings/pinctrl/apple.h +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0041-mailbox-apple-Implement-flush-operation.patch b/target/linux/silicon/patches-5.19/0041-mailbox-apple-Implement-flush-operation.patch new file mode 100644 index 000000000..11ad2e035 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0041-mailbox-apple-Implement-flush-operation.patch @@ -0,0 +1,74 @@ +From 8a4bb71a27420d66c52e0b0347dddb5853c69a15 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 8 Feb 2022 16:57:47 +0900 +Subject: [PATCH 041/171] mailbox: apple: Implement flush() operation + +This allows clients to use the atomic-safe mailbox API style. + +Signed-off-by: Hector Martin +--- + drivers/mailbox/apple-mailbox.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/drivers/mailbox/apple-mailbox.c b/drivers/mailbox/apple-mailbox.c +index 496c4951ccb1..33e7acf71e3e 100644 +--- a/drivers/mailbox/apple-mailbox.c ++++ b/drivers/mailbox/apple-mailbox.c +@@ -17,6 +17,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -112,6 +113,14 @@ static bool apple_mbox_hw_can_send(struct apple_mbox *apple_mbox) + return !(mbox_ctrl & apple_mbox->hw->control_full); + } + ++static bool apple_mbox_hw_send_empty(struct apple_mbox *apple_mbox) ++{ ++ u32 mbox_ctrl = ++ readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control); ++ ++ return mbox_ctrl & apple_mbox->hw->control_empty; ++} ++ + static int apple_mbox_hw_send(struct apple_mbox *apple_mbox, + struct apple_mbox_msg *msg) + { +@@ -219,6 +228,23 @@ static irqreturn_t apple_mbox_recv_irq(int irq, void *data) + return IRQ_HANDLED; + } + ++static int apple_mbox_chan_flush(struct mbox_chan *chan, unsigned long timeout) ++{ ++ struct apple_mbox *apple_mbox = chan->con_priv; ++ unsigned long deadline = jiffies + msecs_to_jiffies(timeout); ++ ++ while (time_before(jiffies, deadline)) { ++ if (apple_mbox_hw_send_empty(apple_mbox)) { ++ mbox_chan_txdone(&apple_mbox->chan, 0); ++ return 0; ++ } ++ ++ udelay(1); ++ } ++ ++ return -ETIME; ++} ++ + static int apple_mbox_chan_startup(struct mbox_chan *chan) + { + struct apple_mbox *apple_mbox = chan->con_priv; +@@ -250,6 +276,7 @@ static void apple_mbox_chan_shutdown(struct mbox_chan *chan) + + static const struct mbox_chan_ops apple_mbox_ops = { + .send_data = apple_mbox_chan_send_data, ++ .flush = apple_mbox_chan_flush, + .startup = apple_mbox_chan_startup, + .shutdown = apple_mbox_chan_shutdown, + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0042-mailbox-apple-Implement-poll_data-operation.patch b/target/linux/silicon/patches-5.19/0042-mailbox-apple-Implement-poll_data-operation.patch new file mode 100644 index 000000000..e8890e056 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0042-mailbox-apple-Implement-poll_data-operation.patch @@ -0,0 +1,106 @@ +From fa28fb2edcc310f9038538b2f1d27998b01c7db7 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 8 Feb 2022 19:16:08 +0900 +Subject: [PATCH 042/171] mailbox: apple: Implement poll_data() operation + +This allows clients running in atomic context to poll for messages to +arrive. + +Signed-off-by: Hector Martin +--- + drivers/mailbox/apple-mailbox.c | 37 ++++++++++++++++++++++++++++++--- + 1 file changed, 34 insertions(+), 3 deletions(-) + +diff --git a/drivers/mailbox/apple-mailbox.c b/drivers/mailbox/apple-mailbox.c +index 33e7acf71e3e..1c14ff63f3d3 100644 +--- a/drivers/mailbox/apple-mailbox.c ++++ b/drivers/mailbox/apple-mailbox.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + + #define APPLE_ASC_MBOX_CONTROL_FULL BIT(16) +@@ -101,6 +102,7 @@ struct apple_mbox { + + struct device *dev; + struct mbox_controller controller; ++ spinlock_t rx_lock; + }; + + static const struct of_device_id apple_mbox_of_match[]; +@@ -204,13 +206,16 @@ static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data) + return IRQ_HANDLED; + } + +-static irqreturn_t apple_mbox_recv_irq(int irq, void *data) ++static int apple_mbox_poll(struct apple_mbox *apple_mbox) + { +- struct apple_mbox *apple_mbox = data; ++ + struct apple_mbox_msg msg; ++ int ret = 0; + +- while (apple_mbox_hw_recv(apple_mbox, &msg) == 0) ++ while (apple_mbox_hw_recv(apple_mbox, &msg) == 0) { + mbox_chan_received_data(&apple_mbox->chan, (void *)&msg); ++ ret++; ++ } + + /* + * The interrupt will keep firing even if there are no more messages +@@ -225,9 +230,33 @@ static irqreturn_t apple_mbox_recv_irq(int irq, void *data) + apple_mbox->regs + apple_mbox->hw->irq_ack); + } + ++ return ret; ++} ++ ++static irqreturn_t apple_mbox_recv_irq(int irq, void *data) ++{ ++ struct apple_mbox *apple_mbox = data; ++ ++ spin_lock(&apple_mbox->rx_lock); ++ apple_mbox_poll(apple_mbox); ++ spin_unlock(&apple_mbox->rx_lock); ++ + return IRQ_HANDLED; + } + ++static bool apple_mbox_chan_peek_data(struct mbox_chan *chan) ++{ ++ struct apple_mbox *apple_mbox = chan->con_priv; ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&apple_mbox->rx_lock, flags); ++ ret = apple_mbox_poll(apple_mbox); ++ spin_unlock_irqrestore(&apple_mbox->rx_lock, flags); ++ ++ return ret > 0; ++} ++ + static int apple_mbox_chan_flush(struct mbox_chan *chan, unsigned long timeout) + { + struct apple_mbox *apple_mbox = chan->con_priv; +@@ -276,6 +305,7 @@ static void apple_mbox_chan_shutdown(struct mbox_chan *chan) + + static const struct mbox_chan_ops apple_mbox_ops = { + .send_data = apple_mbox_chan_send_data, ++ .peek_data = apple_mbox_chan_peek_data, + .flush = apple_mbox_chan_flush, + .startup = apple_mbox_chan_startup, + .shutdown = apple_mbox_chan_shutdown, +@@ -331,6 +361,7 @@ static int apple_mbox_probe(struct platform_device *pdev) + mbox->controller.txdone_irq = true; + mbox->controller.of_xlate = apple_mbox_of_xlate; + mbox->chan.con_priv = mbox; ++ spin_lock_init(&mbox->rx_lock); + + irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev)); + if (!irqname) +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0043-mailbox-apple-Keep-IRQs-active-in-suspend.patch b/target/linux/silicon/patches-5.19/0043-mailbox-apple-Keep-IRQs-active-in-suspend.patch new file mode 100644 index 000000000..2825bd321 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0043-mailbox-apple-Keep-IRQs-active-in-suspend.patch @@ -0,0 +1,45 @@ +From 9a204cb4333ca42ebc6401f8c782f99c82f3a75d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 5 Mar 2022 01:08:33 +0900 +Subject: [PATCH 043/171] mailbox: apple: Keep IRQs active in suspend + +Some consumers (notably SMC) need to be wakeup sources for s2idle, +so the IRQs need to stay enabled during suspend. We expect +consumers to properly suspend coprocessors such that no IRQs would +be triggered where not necessary, so this can be done unconditionally. + +Signed-off-by: Hector Martin +--- + drivers/mailbox/apple-mailbox.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/mailbox/apple-mailbox.c b/drivers/mailbox/apple-mailbox.c +index 1c14ff63f3d3..4b34b4d11bd6 100644 +--- a/drivers/mailbox/apple-mailbox.c ++++ b/drivers/mailbox/apple-mailbox.c +@@ -369,8 +369,8 @@ static int apple_mbox_probe(struct platform_device *pdev) + + ret = devm_request_threaded_irq(dev, mbox->irq_recv_not_empty, NULL, + apple_mbox_recv_irq, +- IRQF_NO_AUTOEN | IRQF_ONESHOT, irqname, +- mbox); ++ IRQF_NO_AUTOEN | IRQF_ONESHOT | IRQF_NO_SUSPEND, ++ irqname, mbox); + if (ret) + return ret; + +@@ -378,9 +378,8 @@ static int apple_mbox_probe(struct platform_device *pdev) + if (!irqname) + return -ENOMEM; + +- ret = devm_request_irq(dev, mbox->irq_send_empty, +- apple_mbox_send_empty_irq, IRQF_NO_AUTOEN, +- irqname, mbox); ++ ret = devm_request_irq(dev, mbox->irq_send_empty, apple_mbox_send_empty_irq, ++ IRQF_NO_AUTOEN | IRQF_NO_SUSPEND, irqname, mbox); + if (ret) + return ret; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0044-mailbox-apple-Fix-races-around-poll-tx.patch b/target/linux/silicon/patches-5.19/0044-mailbox-apple-Fix-races-around-poll-tx.patch new file mode 100644 index 000000000..bcb75ad0f --- /dev/null +++ b/target/linux/silicon/patches-5.19/0044-mailbox-apple-Fix-races-around-poll-tx.patch @@ -0,0 +1,101 @@ +From f30928052eeecd551f0d3bbf5a7ac63913cbf6ae Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 5 May 2022 01:36:27 +0900 +Subject: [PATCH 044/171] mailbox: apple: Fix races around poll/tx + +Signed-off-by: Hector Martin +--- + drivers/mailbox/apple-mailbox.c | 33 +++++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +diff --git a/drivers/mailbox/apple-mailbox.c b/drivers/mailbox/apple-mailbox.c +index 4b34b4d11bd6..06c7ad3b1c03 100644 +--- a/drivers/mailbox/apple-mailbox.c ++++ b/drivers/mailbox/apple-mailbox.c +@@ -103,6 +103,8 @@ struct apple_mbox { + struct device *dev; + struct mbox_controller controller; + spinlock_t rx_lock; ++ spinlock_t tx_lock; ++ bool tx_pending; + }; + + static const struct of_device_id apple_mbox_of_match[]; +@@ -166,11 +168,15 @@ static int apple_mbox_chan_send_data(struct mbox_chan *chan, void *data) + { + struct apple_mbox *apple_mbox = chan->con_priv; + struct apple_mbox_msg *msg = data; ++ unsigned long flags; + int ret; + ++ spin_lock_irqsave(&apple_mbox->tx_lock, flags); ++ WARN_ON(apple_mbox->tx_pending); ++ + ret = apple_mbox_hw_send(apple_mbox, msg); + if (ret) +- return ret; ++ goto err_unlock; + + /* + * The interrupt is level triggered and will keep firing as long as the +@@ -185,9 +191,13 @@ static int apple_mbox_chan_send_data(struct mbox_chan *chan, void *data) + writel_relaxed(apple_mbox->hw->irq_bit_send_empty, + apple_mbox->regs + apple_mbox->hw->irq_ack); + } ++ apple_mbox->tx_pending = true; + enable_irq(apple_mbox->irq_send_empty); + +- return 0; ++err_unlock: ++ spin_unlock_irqrestore(&apple_mbox->tx_lock, flags); ++ ++ return ret; + } + + static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data) +@@ -202,7 +212,14 @@ static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data) + * it at the main controller again. + */ + disable_irq_nosync(apple_mbox->irq_send_empty); +- mbox_chan_txdone(&apple_mbox->chan, 0); ++ spin_lock(&apple_mbox->tx_lock); ++ if (apple_mbox->tx_pending) { ++ apple_mbox->tx_pending = false; ++ spin_unlock(&apple_mbox->tx_lock); ++ mbox_chan_txdone(&apple_mbox->chan, 0); ++ } else { ++ spin_unlock(&apple_mbox->tx_lock); ++ } + return IRQ_HANDLED; + } + +@@ -261,10 +278,17 @@ static int apple_mbox_chan_flush(struct mbox_chan *chan, unsigned long timeout) + { + struct apple_mbox *apple_mbox = chan->con_priv; + unsigned long deadline = jiffies + msecs_to_jiffies(timeout); ++ unsigned long flags; + + while (time_before(jiffies, deadline)) { + if (apple_mbox_hw_send_empty(apple_mbox)) { +- mbox_chan_txdone(&apple_mbox->chan, 0); ++ spin_lock_irqsave(&apple_mbox->tx_lock, flags); ++ if (apple_mbox->tx_pending) { ++ apple_mbox->tx_pending = false; ++ disable_irq_nosync(apple_mbox->irq_send_empty); ++ } ++ /* Mailbox subsystem will call txdone for us */ ++ spin_unlock_irqrestore(&apple_mbox->tx_lock, flags); + return 0; + } + +@@ -362,6 +386,7 @@ static int apple_mbox_probe(struct platform_device *pdev) + mbox->controller.of_xlate = apple_mbox_of_xlate; + mbox->chan.con_priv = mbox; + spin_lock_init(&mbox->rx_lock); ++ spin_lock_init(&mbox->tx_lock); + + irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev)); + if (!irqname) +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0045-WIP-mailbox-fix-poll.patch b/target/linux/silicon/patches-5.19/0045-WIP-mailbox-fix-poll.patch new file mode 100644 index 000000000..88fee4e25 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0045-WIP-mailbox-fix-poll.patch @@ -0,0 +1,26 @@ +From 34019420175a9edf6d35b567815757eee727f078 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 5 May 2022 01:37:01 +0900 +Subject: [PATCH 045/171] WIP: mailbox: fix poll + +Signed-off-by: Hector Martin +--- + drivers/mailbox/mailbox.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index 4229b9b5da98..e27500e8cba9 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -310,7 +310,7 @@ int mbox_flush(struct mbox_chan *chan, unsigned long timeout) + return -ENOTSUPP; + + ret = chan->mbox->ops->flush(chan, timeout); +- if (ret < 0) ++ if (ret >= 0) + tx_tick(chan, ret); + + return ret; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0046-dt-bindings-iommu-dart-add-t6000-compatible.patch b/target/linux/silicon/patches-5.19/0046-dt-bindings-iommu-dart-add-t6000-compatible.patch new file mode 100644 index 000000000..5e879e5cd --- /dev/null +++ b/target/linux/silicon/patches-5.19/0046-dt-bindings-iommu-dart-add-t6000-compatible.patch @@ -0,0 +1,37 @@ +From 88e0c4540822cbd63ec7618eaed2279126bdd042 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Tue, 2 Nov 2021 18:10:51 +0100 +Subject: [PATCH 046/171] dt-bindings: iommu: dart: add t6000 compatible + +The M1 Max/Pro SoCs come with a new DART variant that is incompatible with +the previous one. Add a new compatible for those. + +Signed-off-by: Sven Peter +Acked-by: Rob Herring + +Series-changes: 2 +- added Rob's Acked-by: + +Patch-cc: Mark Kettenis +--- + Documentation/devicetree/bindings/iommu/apple,dart.yaml | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/iommu/apple,dart.yaml b/Documentation/devicetree/bindings/iommu/apple,dart.yaml +index 82ad669feef7..06af2bacbe97 100644 +--- a/Documentation/devicetree/bindings/iommu/apple,dart.yaml ++++ b/Documentation/devicetree/bindings/iommu/apple,dart.yaml +@@ -22,7 +22,9 @@ description: |+ + + properties: + compatible: +- const: apple,t8103-dart ++ enum: ++ - apple,t8103-dart ++ - apple,t6000-dart + + reg: + maxItems: 1 +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0047-iommu-io-pgtable-Move-Apple-DART-support-to-its-own-.patch b/target/linux/silicon/patches-5.19/0047-iommu-io-pgtable-Move-Apple-DART-support-to-its-own-.patch new file mode 100644 index 000000000..a64290244 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0047-iommu-io-pgtable-Move-Apple-DART-support-to-its-own-.patch @@ -0,0 +1,825 @@ +From 799fd906a17a263eaad29e3246dc4b468bb1edc6 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Wed, 8 Jun 2022 19:07:49 +0200 +Subject: [PATCH 047/171] iommu/io-pgtable: Move Apple DART support to its own + file + +The pte format used by the DARTs found in the Apple M1 (t8103) is not +fully compatible with io-pgtable-arm. The 24 MSB are used for subpage +protection (mapping only parts of page) and conflict with the address +mask. In addition bit 1 is not available for tagging entries but disables +subpage protection. Subpage protection could be useful to support a CPU +granule of 4k with the fixed IOMMU page size of 16k. + +The DARTs found on Apple M1 Pro/Max/Ultra use another different pte +format which is even less compatible. To support an output address size +of 42 bit the address is shifted down by 4. Subpage protection is +mandatory and bit 1 signifies uncached mappings used by the display +controller. + +It would be advantageous to share code for all known Apple DART +variants to support common features. The page table allocator for DARTs +is less complex since it uses a two levels of translation table without +support for huge pages. + +Signed-off-by: Janne Grunau + +Series-changes: 2 +- add APPLE_DART2 io-pgtable format + +Series-changes: 3 +- move APPLE_DART to its own io-pgtable implementation, copied from + io-pgtable-arm and simplified + +Series-version: 3 +Cover-letter: +iommu: M1 Pro/Max DART support +Hej, + +this is the next attempt adding support for the DART found in Apple's +M1 Pro/Max/Ultra. This adds a separate io-pgtable implementation for +DART. As already mentioned in v2 the pte format is not fully compatible +with io-pgtable-arm. Especially the 2nd least significant bit is used +and is not available to tag tables/pages. +io-pgtable-dart.c is copied from io-pgtable-arm.c and support for +unused features is removed. Support for 4k IO pages is left for A7 to +A11 SoCs as there's work underway to run Linux on them. + +The incompatibilities between both Apple DART pte seems manageable in +their own io-pgtable implementation. A short list of the known +differences: + + - the physical addresses are shifted left by 4 bits and and have 2 more + bits inside the PTE entries + - the read/write protection flags are at a different position + - the subpage protection feature is now mandatory. For Linux we can + just configure it to always allow access to the entire page. + - BIT(1) tags "uncached" mappings (used for the display controller) + +There is second type of DART (t8110) present on M1 Pro/Max SoCs which +uses the same PTE format as t6000. +END + +Series-to: iommu@lists.linux-foundation.org +Series-cc: asahi@lists.linux.dev +Series-cc: Konrad Dybcio +--- + MAINTAINERS | 1 + + drivers/iommu/Kconfig | 11 +- + drivers/iommu/Makefile | 1 + + drivers/iommu/io-pgtable-arm.c | 63 ---- + drivers/iommu/io-pgtable-dart.c | 580 ++++++++++++++++++++++++++++++++ + drivers/iommu/io-pgtable.c | 2 + + 6 files changed, 594 insertions(+), 64 deletions(-) + create mode 100644 drivers/iommu/io-pgtable-dart.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 64379c699903..cb0ceb0b2cfc 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1849,6 +1849,7 @@ F: drivers/clk/clk-apple-nco.c + F: drivers/i2c/busses/i2c-pasemi-core.c + F: drivers/i2c/busses/i2c-pasemi-platform.c + F: drivers/iommu/apple-dart.c ++F: drivers/iommu/io-pgtable-dart.c + F: drivers/irqchip/irq-apple-aic.c + F: drivers/mailbox/apple-mailbox.c + F: drivers/nvme/host/apple.c +diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig +index c79a0df090c0..58603124dd42 100644 +--- a/drivers/iommu/Kconfig ++++ b/drivers/iommu/Kconfig +@@ -67,6 +67,15 @@ config IOMMU_IO_PGTABLE_ARMV7S_SELFTEST + + If unsure, say N here. + ++config IOMMU_IO_PGTABLE_DART ++ bool "Apple DART Formats" ++ select IOMMU_IO_PGTABLE ++ depends on ARM64 || (COMPILE_TEST && !GENERIC_ATOMIC64) ++ help ++ Enable support for the Apple DART pagetable formats. These include ++ the t8020 and t6000/t8110 DART formats used in Apple M1/M2 family ++ SoCs. ++ + endmenu + + config IOMMU_DEBUGFS +@@ -294,7 +303,7 @@ config APPLE_DART + tristate "Apple DART IOMMU Support" + depends on ARCH_APPLE || (COMPILE_TEST && !GENERIC_ATOMIC64) + select IOMMU_API +- select IOMMU_IO_PGTABLE_LPAE ++ select IOMMU_IO_PGTABLE_DART + default ARCH_APPLE + help + Support for Apple DART (Device Address Resolution Table) IOMMUs +diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile +index 44475a9b3eea..cc9f381013c3 100644 +--- a/drivers/iommu/Makefile ++++ b/drivers/iommu/Makefile +@@ -8,6 +8,7 @@ obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o + obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o + obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o + obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o ++obj-$(CONFIG_IOMMU_IO_PGTABLE_DART) += io-pgtable-dart.o + obj-$(CONFIG_IOASID) += ioasid.o + obj-$(CONFIG_IOMMU_IOVA) += iova.o + obj-$(CONFIG_OF_IOMMU) += of_iommu.o +diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c +index 94ff319ae8ac..d7f5e23da643 100644 +--- a/drivers/iommu/io-pgtable-arm.c ++++ b/drivers/iommu/io-pgtable-arm.c +@@ -130,9 +130,6 @@ + #define ARM_MALI_LPAE_MEMATTR_IMP_DEF 0x88ULL + #define ARM_MALI_LPAE_MEMATTR_WRITE_ALLOC 0x8DULL + +-#define APPLE_DART_PTE_PROT_NO_WRITE (1<<7) +-#define APPLE_DART_PTE_PROT_NO_READ (1<<8) +- + /* IOPTE accessors */ + #define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d)) + +@@ -406,15 +403,6 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, + { + arm_lpae_iopte pte; + +- if (data->iop.fmt == APPLE_DART) { +- pte = 0; +- if (!(prot & IOMMU_WRITE)) +- pte |= APPLE_DART_PTE_PROT_NO_WRITE; +- if (!(prot & IOMMU_READ)) +- pte |= APPLE_DART_PTE_PROT_NO_READ; +- return pte; +- } +- + if (data->iop.fmt == ARM_64_LPAE_S1 || + data->iop.fmt == ARM_32_LPAE_S1) { + pte = ARM_LPAE_PTE_nG; +@@ -1107,52 +1095,6 @@ arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) + return NULL; + } + +-static struct io_pgtable * +-apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) +-{ +- struct arm_lpae_io_pgtable *data; +- int i; +- +- if (cfg->oas > 36) +- return NULL; +- +- data = arm_lpae_alloc_pgtable(cfg); +- if (!data) +- return NULL; +- +- /* +- * The table format itself always uses two levels, but the total VA +- * space is mapped by four separate tables, making the MMIO registers +- * an effective "level 1". For simplicity, though, we treat this +- * equivalently to LPAE stage 2 concatenation at level 2, with the +- * additional TTBRs each just pointing at consecutive pages. +- */ +- if (data->start_level < 1) +- goto out_free_data; +- if (data->start_level == 1 && data->pgd_bits > 2) +- goto out_free_data; +- if (data->start_level > 1) +- data->pgd_bits = 0; +- data->start_level = 2; +- cfg->apple_dart_cfg.n_ttbrs = 1 << data->pgd_bits; +- data->pgd_bits += data->bits_per_level; +- +- data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data), GFP_KERNEL, +- cfg); +- if (!data->pgd) +- goto out_free_data; +- +- for (i = 0; i < cfg->apple_dart_cfg.n_ttbrs; ++i) +- cfg->apple_dart_cfg.ttbr[i] = +- virt_to_phys(data->pgd + i * ARM_LPAE_GRANULE(data)); +- +- return &data->iop; +- +-out_free_data: +- kfree(data); +- return NULL; +-} +- + struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = { + .alloc = arm_64_lpae_alloc_pgtable_s1, + .free = arm_lpae_free_pgtable, +@@ -1178,11 +1120,6 @@ struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns = { + .free = arm_lpae_free_pgtable, + }; + +-struct io_pgtable_init_fns io_pgtable_apple_dart_init_fns = { +- .alloc = apple_dart_alloc_pgtable, +- .free = arm_lpae_free_pgtable, +-}; +- + #ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST + + static struct io_pgtable_cfg *cfg_cookie __initdata; +diff --git a/drivers/iommu/io-pgtable-dart.c b/drivers/iommu/io-pgtable-dart.c +new file mode 100644 +index 000000000000..0c5222942c65 +--- /dev/null ++++ b/drivers/iommu/io-pgtable-dart.c +@@ -0,0 +1,580 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Apple DART page table allocator. ++ * ++ * Copyright (C) 2022 The Asahi Linux Contributors ++ * ++ * Based on io-pgtable-arm. ++ * ++ * Copyright (C) 2014 ARM Limited ++ * ++ * Author: Will Deacon ++ */ ++ ++#define pr_fmt(fmt) "dart io-pgtable: " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define DART_MAX_ADDR_BITS 52 ++#define DART_MAX_LEVELS 3 ++ ++/* Struct accessors */ ++#define io_pgtable_to_data(x) \ ++ container_of((x), struct dart_io_pgtable, iop) ++ ++#define io_pgtable_ops_to_data(x) \ ++ io_pgtable_to_data(io_pgtable_ops_to_pgtable(x)) ++ ++/* ++ * Calculate the right shift amount to get to the portion describing level l ++ * in a virtual address mapped by the pagetable in d. ++ */ ++#define DART_LVL_SHIFT(l, d) \ ++ (((DART_MAX_LEVELS - (l)) * (d)->bits_per_level) + \ ++ ilog2(sizeof(dart_iopte))) ++ ++#define DART_GRANULE(d) \ ++ (sizeof(dart_iopte) << (d)->bits_per_level) ++#define DART_PGD_SIZE(d) \ ++ (sizeof(dart_iopte) << (d)->pgd_bits) ++ ++#define DART_PTES_PER_TABLE(d) \ ++ (DART_GRANULE(d) >> ilog2(sizeof(dart_iopte))) ++ ++/* ++ * Calculate the index at level l used to map virtual address a using the ++ * pagetable in d. ++ */ ++#define DART_PGD_IDX(l, d) \ ++ ((l) == (d)->start_level ? (d)->pgd_bits - (d)->bits_per_level : 0) ++ ++#define DART_LVL_IDX(a, l, d) \ ++ (((u64)(a) >> DART_LVL_SHIFT(l, d)) & \ ++ ((1 << ((d)->bits_per_level + DART_PGD_IDX(l, d))) - 1)) ++ ++/* Calculate the block/page mapping size at level l for pagetable in d. */ ++#define DART_BLOCK_SIZE(l, d) (1ULL << DART_LVL_SHIFT(l, d)) ++ ++#define APPLE_DART1_PADDR_MASK GENMASK_ULL(35, 12) ++ ++/* Apple DART1 protection bits */ ++#define APPLE_DART1_PTE_PROT_NO_READ BIT(8) ++#define APPLE_DART1_PTE_PROT_NO_WRITE BIT(7) ++#define APPLE_DART1_PTE_PROT_SP_DIS BIT(1) ++ ++/* marks PTE as valid */ ++#define APPLE_DART_PTE_VALID BIT(0) ++ ++/* IOPTE accessors */ ++#define iopte_deref(pte, d) __va(iopte_to_paddr(pte, d)) ++ ++struct dart_io_pgtable { ++ struct io_pgtable iop; ++ ++ int pgd_bits; ++ int start_level; ++ int bits_per_level; ++ ++ void *pgd; ++}; ++ ++typedef u64 dart_iopte; ++ ++static inline bool iopte_leaf(dart_iopte pte, int lvl, ++ enum io_pgtable_fmt fmt) ++{ ++ return (lvl == (DART_MAX_LEVELS - 1)) && (pte & APPLE_DART_PTE_VALID); ++} ++ ++static dart_iopte paddr_to_iopte(phys_addr_t paddr, ++ struct dart_io_pgtable *data) ++{ ++ return paddr & APPLE_DART1_PADDR_MASK; ++} ++ ++static phys_addr_t iopte_to_paddr(dart_iopte pte, ++ struct dart_io_pgtable *data) ++{ ++ return pte & APPLE_DART1_PADDR_MASK; ++} ++ ++static void *__dart_alloc_pages(size_t size, gfp_t gfp, ++ struct io_pgtable_cfg *cfg) ++{ ++ struct device *dev = cfg->iommu_dev; ++ int order = get_order(size); ++ struct page *p; ++ ++ VM_BUG_ON((gfp & __GFP_HIGHMEM)); ++ p = alloc_pages_node(dev ? dev_to_node(dev) : NUMA_NO_NODE, ++ gfp | __GFP_ZERO, order); ++ if (!p) ++ return NULL; ++ ++ return page_address(p); ++} ++ ++static void __dart_free_pages(void *pages, size_t size) ++{ ++ free_pages((unsigned long)pages, get_order(size)); ++} ++ ++static void __dart_init_pte(struct dart_io_pgtable *data, ++ phys_addr_t paddr, dart_iopte prot, ++ int lvl, int num_entries, dart_iopte *ptep) ++{ ++ dart_iopte pte = prot; ++ size_t sz = DART_BLOCK_SIZE(lvl, data); ++ int i; ++ ++ if (lvl == DART_MAX_LEVELS - 1) ++ pte |= APPLE_DART1_PTE_PROT_SP_DIS; ++ ++ pte |= APPLE_DART_PTE_VALID; ++ ++ for (i = 0; i < num_entries; i++) ++ ptep[i] = pte | paddr_to_iopte(paddr + i * sz, data); ++} ++ ++static int dart_init_pte(struct dart_io_pgtable *data, ++ unsigned long iova, phys_addr_t paddr, ++ dart_iopte prot, int lvl, int num_entries, ++ dart_iopte *ptep) ++{ ++ int i; ++ ++ for (i = 0; i < num_entries; i++) ++ if (iopte_leaf(ptep[i], lvl, data->iop.fmt)) { ++ /* We require an unmap first */ ++ WARN_ON(iopte_leaf(ptep[i], lvl, data->iop.fmt)); ++ return -EEXIST; ++ } ++ ++ __dart_init_pte(data, paddr, prot, lvl, num_entries, ptep); ++ return 0; ++} ++ ++static dart_iopte dart_install_table(dart_iopte *table, ++ dart_iopte *ptep, ++ dart_iopte curr, ++ struct dart_io_pgtable *data) ++{ ++ dart_iopte old, new; ++ ++ new = paddr_to_iopte(__pa(table), data) | APPLE_DART_PTE_VALID; ++ ++ /* ++ * Ensure the table itself is visible before its PTE can be. ++ * Whilst we could get away with cmpxchg64_release below, this ++ * doesn't have any ordering semantics when !CONFIG_SMP. ++ */ ++ dma_wmb(); ++ ++ old = cmpxchg64_relaxed(ptep, curr, new); ++ ++ return old; ++} ++ ++static int __dart_map(struct dart_io_pgtable *data, unsigned long iova, ++ phys_addr_t paddr, size_t size, size_t pgcount, ++ dart_iopte prot, int lvl, dart_iopte *ptep, ++ gfp_t gfp, size_t *mapped) ++{ ++ dart_iopte *cptep, pte; ++ size_t block_size = DART_BLOCK_SIZE(lvl, data); ++ size_t tblsz = DART_GRANULE(data); ++ struct io_pgtable_cfg *cfg = &data->iop.cfg; ++ int ret = 0, num_entries, max_entries, map_idx_start; ++ ++ /* Find our entry at the current level */ ++ map_idx_start = DART_LVL_IDX(iova, lvl, data); ++ ptep += map_idx_start; ++ ++ /* If we can install a leaf entry at this level, then do so */ ++ if (size == block_size) { ++ max_entries = DART_PTES_PER_TABLE(data) - map_idx_start; ++ num_entries = min_t(int, pgcount, max_entries); ++ ret = dart_init_pte(data, iova, paddr, prot, lvl, num_entries, ptep); ++ if (!ret && mapped) ++ *mapped += num_entries * size; ++ ++ return ret; ++ } ++ ++ /* We can't allocate tables at the final level */ ++ if (WARN_ON(lvl >= DART_MAX_LEVELS - 1)) ++ return -EINVAL; ++ ++ /* Grab a pointer to the next level */ ++ pte = READ_ONCE(*ptep); ++ if (!pte) { ++ cptep = __dart_alloc_pages(tblsz, gfp, cfg); ++ if (!cptep) ++ return -ENOMEM; ++ ++ pte = dart_install_table(cptep, ptep, 0, data); ++ if (pte) ++ __dart_free_pages(cptep, tblsz); ++ } ++ ++ if (pte && !iopte_leaf(pte, lvl, data->iop.fmt)) { ++ cptep = iopte_deref(pte, data); ++ } else if (pte) { ++ /* We require an unmap first */ ++ WARN_ON(pte); ++ return -EEXIST; ++ } ++ ++ /* Rinse, repeat */ ++ return __dart_map(data, iova, paddr, size, pgcount, prot, lvl + 1, ++ cptep, gfp, mapped); ++} ++ ++static dart_iopte dart_prot_to_pte(struct dart_io_pgtable *data, ++ int prot) ++{ ++ dart_iopte pte = 0; ++ ++ if (!(prot & IOMMU_WRITE)) ++ pte |= APPLE_DART1_PTE_PROT_NO_WRITE; ++ if (!(prot & IOMMU_READ)) ++ pte |= APPLE_DART1_PTE_PROT_NO_READ; ++ ++ return pte; ++} ++ ++static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova, ++ phys_addr_t paddr, size_t pgsize, size_t pgcount, ++ int iommu_prot, gfp_t gfp, size_t *mapped) ++{ ++ struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops); ++ struct io_pgtable_cfg *cfg = &data->iop.cfg; ++ dart_iopte *ptep = data->pgd; ++ int ret, lvl = data->start_level; ++ dart_iopte prot; ++ long iaext = (s64)iova >> cfg->ias; ++ ++ if (WARN_ON(!pgsize || (pgsize & cfg->pgsize_bitmap) != pgsize)) ++ return -EINVAL; ++ ++ if (WARN_ON(iaext || paddr >> cfg->oas)) ++ return -ERANGE; ++ ++ /* If no access, then nothing to do */ ++ if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE))) ++ return 0; ++ ++ prot = dart_prot_to_pte(data, iommu_prot); ++ ret = __dart_map(data, iova, paddr, pgsize, pgcount, prot, lvl, ++ ptep, gfp, mapped); ++ /* ++ * Synchronise all PTE updates for the new mapping before there's ++ * a chance for anything to kick off a table walk for the new iova. ++ */ ++ wmb(); ++ ++ return ret; ++} ++ ++static int dart_map(struct io_pgtable_ops *ops, unsigned long iova, ++ phys_addr_t paddr, size_t size, int iommu_prot, gfp_t gfp) ++{ ++ return dart_map_pages(ops, iova, paddr, size, 1, iommu_prot, gfp, ++ NULL); ++} ++ ++static void __dart_free_pgtable(struct dart_io_pgtable *data, int lvl, ++ dart_iopte *ptep) ++{ ++ dart_iopte *start, *end; ++ unsigned long table_size; ++ ++ if (lvl == data->start_level) ++ table_size = DART_PGD_SIZE(data); ++ else ++ table_size = DART_GRANULE(data); ++ ++ start = ptep; ++ ++ /* Only leaf entries at the last level */ ++ if (lvl == DART_MAX_LEVELS - 1) ++ end = ptep; ++ else ++ end = (void *)ptep + table_size; ++ ++ while (ptep != end) { ++ dart_iopte pte = *ptep++; ++ ++ if (!pte || iopte_leaf(pte, lvl, data->iop.fmt)) ++ continue; ++ ++ __dart_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); ++ } ++ ++ __dart_free_pages(start, table_size); ++} ++ ++static size_t __dart_unmap(struct dart_io_pgtable *data, ++ struct iommu_iotlb_gather *gather, ++ unsigned long iova, size_t size, size_t pgcount, ++ int lvl, dart_iopte *ptep) ++{ ++ dart_iopte pte; ++ struct io_pgtable *iop = &data->iop; ++ int i = 0, num_entries, max_entries, unmap_idx_start; ++ ++ /* Something went horribly wrong and we ran out of page table */ ++ if (WARN_ON(lvl == DART_MAX_LEVELS)) ++ return 0; ++ ++ unmap_idx_start = DART_LVL_IDX(iova, lvl, data); ++ ptep += unmap_idx_start; ++ pte = READ_ONCE(*ptep); ++ if (WARN_ON(!pte)) ++ return 0; ++ ++ /* If the size matches this level, we're in the right place */ ++ if (size == DART_BLOCK_SIZE(lvl, data)) { ++ max_entries = DART_PTES_PER_TABLE(data) - unmap_idx_start; ++ num_entries = min_t(int, pgcount, max_entries); ++ ++ while (i < num_entries) { ++ pte = READ_ONCE(*ptep); ++ if (WARN_ON(!pte)) ++ break; ++ ++ /* clear pte */ ++ *ptep = 0; ++ ++ if (!iopte_leaf(pte, lvl, iop->fmt)) { ++ /* Also flush any partial walks */ ++ io_pgtable_tlb_flush_walk(iop, iova + i * size, size, ++ DART_GRANULE(data)); ++ __dart_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); ++ } else if (!iommu_iotlb_gather_queued(gather)) { ++ io_pgtable_tlb_add_page(iop, gather, iova + i * size, size); ++ } ++ ++ ptep++; ++ i++; ++ } ++ ++ return i * size; ++ } ++ ++ /* Keep on walkin' */ ++ ptep = iopte_deref(pte, data); ++ return __dart_unmap(data, gather, iova, size, pgcount, lvl + 1, ptep); ++} ++ ++static size_t dart_unmap_pages(struct io_pgtable_ops *ops, unsigned long iova, ++ size_t pgsize, size_t pgcount, ++ struct iommu_iotlb_gather *gather) ++{ ++ struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops); ++ struct io_pgtable_cfg *cfg = &data->iop.cfg; ++ dart_iopte *ptep = data->pgd; ++ long iaext = (s64)iova >> cfg->ias; ++ ++ if (WARN_ON(!pgsize || (pgsize & cfg->pgsize_bitmap) != pgsize || !pgcount)) ++ return 0; ++ ++ if (WARN_ON(iaext)) ++ return 0; ++ ++ return __dart_unmap(data, gather, iova, pgsize, pgcount, ++ data->start_level, ptep); ++} ++ ++static size_t dart_unmap(struct io_pgtable_ops *ops, unsigned long iova, ++ size_t size, struct iommu_iotlb_gather *gather) ++{ ++ return dart_unmap_pages(ops, iova, size, 1, gather); ++} ++ ++static phys_addr_t dart_iova_to_phys(struct io_pgtable_ops *ops, ++ unsigned long iova) ++{ ++ struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops); ++ dart_iopte pte, *ptep = data->pgd; ++ int lvl = data->start_level; ++ ++ do { ++ /* Valid IOPTE pointer? */ ++ if (!ptep) ++ return 0; ++ ++ /* Grab the IOPTE we're interested in */ ++ ptep += DART_LVL_IDX(iova, lvl, data); ++ pte = READ_ONCE(*ptep); ++ ++ /* Valid entry? */ ++ if (!pte) ++ return 0; ++ ++ /* Leaf entry? */ ++ if (iopte_leaf(pte, lvl, data->iop.fmt)) ++ goto found_translation; ++ ++ /* Take it to the next level */ ++ ptep = iopte_deref(pte, data); ++ } while (++lvl < DART_MAX_LEVELS); ++ ++ /* Ran out of page tables to walk */ ++ return 0; ++ ++found_translation: ++ iova &= (DART_BLOCK_SIZE(lvl, data) - 1); ++ return iopte_to_paddr(pte, data) | iova; ++} ++ ++static void dart_restrict_pgsizes(struct io_pgtable_cfg *cfg) ++{ ++ unsigned long granule, page_sizes; ++ unsigned int max_addr_bits = 48; ++ ++ /* ++ * We need to restrict the supported page sizes to match the ++ * translation regime for a particular granule. Aim to match ++ * the CPU page size if possible, otherwise prefer smaller sizes. ++ * While we're at it, restrict the block sizes to match the ++ * chosen granule. ++ */ ++ if (cfg->pgsize_bitmap & PAGE_SIZE) ++ granule = PAGE_SIZE; ++ else if (cfg->pgsize_bitmap & ~PAGE_MASK) ++ granule = 1UL << __fls(cfg->pgsize_bitmap & ~PAGE_MASK); ++ else if (cfg->pgsize_bitmap & PAGE_MASK) ++ granule = 1UL << __ffs(cfg->pgsize_bitmap & PAGE_MASK); ++ else ++ granule = 0; ++ ++ switch (granule) { ++ case SZ_4K: ++ page_sizes = (SZ_4K | SZ_2M | SZ_1G); ++ break; ++ case SZ_16K: ++ page_sizes = (SZ_16K | SZ_32M); ++ break; ++ default: ++ page_sizes = 0; ++ } ++ ++ cfg->pgsize_bitmap &= page_sizes; ++ cfg->ias = min(cfg->ias, max_addr_bits); ++ cfg->oas = min(cfg->oas, max_addr_bits); ++} ++ ++static struct dart_io_pgtable * ++dart_alloc_pgtable(struct io_pgtable_cfg *cfg) ++{ ++ struct dart_io_pgtable *data; ++ int bits_per_level, levels, va_bits, pg_shift; ++ ++ dart_restrict_pgsizes(cfg); ++ ++ if (!(cfg->pgsize_bitmap & (SZ_4K | SZ_16K))) ++ return NULL; ++ ++ if (cfg->ias > DART_MAX_ADDR_BITS) ++ return NULL; ++ ++ if (cfg->oas > DART_MAX_ADDR_BITS) ++ return NULL; ++ ++ pg_shift = __ffs(cfg->pgsize_bitmap); ++ bits_per_level = pg_shift - ilog2(sizeof(dart_iopte)); ++ ++ va_bits = cfg->ias - pg_shift; ++ levels = DIV_ROUND_UP(va_bits, bits_per_level); ++ if (levels > DART_MAX_LEVELS) ++ return NULL; ++ ++ data = kmalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return NULL; ++ ++ data->bits_per_level = bits_per_level; ++ data->start_level = DART_MAX_LEVELS - levels; ++ ++ /* Calculate the actual size of our pgd (without concatenation) */ ++ data->pgd_bits = va_bits - (data->bits_per_level * (levels - 1)); ++ ++ data->iop.ops = (struct io_pgtable_ops) { ++ .map = dart_map, ++ .map_pages = dart_map_pages, ++ .unmap = dart_unmap, ++ .unmap_pages = dart_unmap_pages, ++ .iova_to_phys = dart_iova_to_phys, ++ }; ++ ++ return data; ++} ++ ++static struct io_pgtable * ++apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) ++{ ++ struct dart_io_pgtable *data; ++ int i; ++ ++ if (!cfg->coherent_walk) ++ return NULL; ++ ++ if (cfg->oas > 36) ++ return NULL; ++ ++ data = dart_alloc_pgtable(cfg); ++ if (!data) ++ return NULL; ++ ++ /* ++ * The table format itself always uses two levels, but the total VA ++ * space is mapped by four separate tables, making the MMIO registers ++ * an effective "level 1". For simplicity, though, we treat this ++ * equivalently to LPAE stage 2 concatenation at level 2, with the ++ * additional TTBRs each just pointing at consecutive pages. ++ */ ++ if (data->start_level == 0 && data->pgd_bits > 2) ++ goto out_free_data; ++ if (data->start_level > 0) ++ data->pgd_bits = 0; ++ data->start_level = 1; ++ cfg->apple_dart_cfg.n_ttbrs = 1 << data->pgd_bits; ++ data->pgd_bits += data->bits_per_level; ++ ++ data->pgd = __dart_alloc_pages(DART_PGD_SIZE(data), GFP_KERNEL, ++ cfg); ++ if (!data->pgd) ++ goto out_free_data; ++ ++ for (i = 0; i < cfg->apple_dart_cfg.n_ttbrs; ++i) ++ cfg->apple_dart_cfg.ttbr[i] = ++ virt_to_phys(data->pgd + i * DART_GRANULE(data)); ++ ++ return &data->iop; ++ ++out_free_data: ++ kfree(data); ++ return NULL; ++} ++ ++static void apple_dart_free_pgtable(struct io_pgtable *iop) ++{ ++ struct dart_io_pgtable *data = io_pgtable_to_data(iop); ++ ++ __dart_free_pgtable(data, data->start_level, data->pgd); ++ kfree(data); ++} ++ ++struct io_pgtable_init_fns io_pgtable_apple_dart_init_fns = { ++ .alloc = apple_dart_alloc_pgtable, ++ .free = apple_dart_free_pgtable, ++}; +diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c +index f4bfcef98297..16205ea9272c 100644 +--- a/drivers/iommu/io-pgtable.c ++++ b/drivers/iommu/io-pgtable.c +@@ -20,6 +20,8 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = { + [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns, + [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns, + [ARM_MALI_LPAE] = &io_pgtable_arm_mali_lpae_init_fns, ++#endif ++#ifdef CONFIG_IOMMU_IO_PGTABLE_DART + [APPLE_DART] = &io_pgtable_apple_dart_init_fns, + #endif + #ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0048-iommu-io-pgtable-Add-DART-subpage-protection-support.patch b/target/linux/silicon/patches-5.19/0048-iommu-io-pgtable-Add-DART-subpage-protection-support.patch new file mode 100644 index 000000000..e600568ad --- /dev/null +++ b/target/linux/silicon/patches-5.19/0048-iommu-io-pgtable-Add-DART-subpage-protection-support.patch @@ -0,0 +1,54 @@ +From cd16901670e12ae1185f2488e74f50ce5d72c5fb Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Wed, 17 Nov 2021 19:40:16 +0100 +Subject: [PATCH 048/171] iommu/io-pgtable: Add DART subpage protection support + +DART allows to only expose a subpage to the device. While this is an +optional feature on the M1 DARTs the new ones present on the Pro/Max +models require this field in every PTE. + +Signed-off-by: Sven Peter +Signed-off-by: Janne Grunau + +Commit-changes: 3 +- apply change to io-pgtable-dart.c +--- + drivers/iommu/io-pgtable-dart.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/iommu/io-pgtable-dart.c b/drivers/iommu/io-pgtable-dart.c +index 0c5222942c65..fa8025c03bb5 100644 +--- a/drivers/iommu/io-pgtable-dart.c ++++ b/drivers/iommu/io-pgtable-dart.c +@@ -14,6 +14,7 @@ + #define pr_fmt(fmt) "dart io-pgtable: " fmt + + #include ++#include + #include + #include + #include +@@ -63,6 +64,9 @@ + /* Calculate the block/page mapping size at level l for pagetable in d. */ + #define DART_BLOCK_SIZE(l, d) (1ULL << DART_LVL_SHIFT(l, d)) + ++#define APPLE_DART_PTE_SUBPAGE_START GENMASK_ULL(63, 52) ++#define APPLE_DART_PTE_SUBPAGE_END GENMASK_ULL(51, 40) ++ + #define APPLE_DART1_PADDR_MASK GENMASK_ULL(35, 12) + + /* Apple DART1 protection bits */ +@@ -140,6 +144,10 @@ static void __dart_init_pte(struct dart_io_pgtable *data, + + pte |= APPLE_DART_PTE_VALID; + ++ /* subpage protection: always allow access to the entire page */ ++ pte |= FIELD_PREP(APPLE_DART_PTE_SUBPAGE_START, 0); ++ pte |= FIELD_PREP(APPLE_DART_PTE_SUBPAGE_END, 0xfff); ++ + for (i = 0; i < num_entries; i++) + ptep[i] = pte | paddr_to_iopte(paddr + i * sz, data); + } +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0049-iommu-io-pgtable-dart-Add-DART-PTE-support-for-t6000.patch b/target/linux/silicon/patches-5.19/0049-iommu-io-pgtable-dart-Add-DART-PTE-support-for-t6000.patch new file mode 100644 index 000000000..c10dcda37 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0049-iommu-io-pgtable-dart-Add-DART-PTE-support-for-t6000.patch @@ -0,0 +1,158 @@ +From 318506bc8e5c558c1df0a964ce2fe112681d3452 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Tue, 2 Nov 2021 18:10:53 +0100 +Subject: [PATCH 049/171] iommu/io-pgtable-dart: Add DART PTE support for t6000 + +The DARTs present in the M1 Pro/Max/Ultra SoC use a diffent PTE format. +They support a 42bit physical address space by shifting the paddr and +extending its mask inside the PTE. +They also come with mandatory sub-page protection now which we just +configure to always allow access to the entire page. This feature is +already present but optional on the previous DARTs which allows to +unconditionally configure it. + +Signed-off-by: Sven Peter +Co-developed-by: Janne Grunau +Signed-off-by: Janne Grunau + +Commit-changes: 2 +- add APPLE_DART2 PTE format + +Commit-changes: 3 +- apply change to io-pgtable-dart.c +- handle pte <> paddr conversion based on the pte format instead of + the output address size +--- + drivers/iommu/io-pgtable-dart.c | 51 +++++++++++++++++++++++++++------ + drivers/iommu/io-pgtable.c | 1 + + include/linux/io-pgtable.h | 1 + + 3 files changed, 45 insertions(+), 8 deletions(-) + +diff --git a/drivers/iommu/io-pgtable-dart.c b/drivers/iommu/io-pgtable-dart.c +index fa8025c03bb5..9c3c2505f3dc 100644 +--- a/drivers/iommu/io-pgtable-dart.c ++++ b/drivers/iommu/io-pgtable-dart.c +@@ -68,12 +68,19 @@ + #define APPLE_DART_PTE_SUBPAGE_END GENMASK_ULL(51, 40) + + #define APPLE_DART1_PADDR_MASK GENMASK_ULL(35, 12) ++#define APPLE_DART2_PADDR_MASK GENMASK_ULL(37, 10) ++#define APPLE_DART2_PADDR_SHIFT (4) + + /* Apple DART1 protection bits */ + #define APPLE_DART1_PTE_PROT_NO_READ BIT(8) + #define APPLE_DART1_PTE_PROT_NO_WRITE BIT(7) + #define APPLE_DART1_PTE_PROT_SP_DIS BIT(1) + ++/* Apple DART2 protection bits */ ++#define APPLE_DART2_PTE_PROT_NO_READ BIT(3) ++#define APPLE_DART2_PTE_PROT_NO_WRITE BIT(2) ++#define APPLE_DART2_PTE_PROT_NO_CACHE BIT(1) ++ + /* marks PTE as valid */ + #define APPLE_DART_PTE_VALID BIT(0) + +@@ -101,13 +108,31 @@ static inline bool iopte_leaf(dart_iopte pte, int lvl, + static dart_iopte paddr_to_iopte(phys_addr_t paddr, + struct dart_io_pgtable *data) + { +- return paddr & APPLE_DART1_PADDR_MASK; ++ dart_iopte pte; ++ ++ if (data->iop.fmt == APPLE_DART) ++ return paddr & APPLE_DART1_PADDR_MASK; ++ ++ /* format is APPLE_DART2 */ ++ pte = paddr >> APPLE_DART2_PADDR_SHIFT; ++ pte &= APPLE_DART2_PADDR_MASK; ++ ++ return pte; + } + + static phys_addr_t iopte_to_paddr(dart_iopte pte, + struct dart_io_pgtable *data) + { +- return pte & APPLE_DART1_PADDR_MASK; ++ u64 paddr; ++ ++ if (data->iop.fmt == APPLE_DART) ++ return pte & APPLE_DART1_PADDR_MASK; ++ ++ /* format is APPLE_DART2 */ ++ paddr = pte & APPLE_DART2_PADDR_MASK; ++ paddr <<= APPLE_DART2_PADDR_SHIFT; ++ ++ return paddr; + } + + static void *__dart_alloc_pages(size_t size, gfp_t gfp, +@@ -139,7 +164,7 @@ static void __dart_init_pte(struct dart_io_pgtable *data, + size_t sz = DART_BLOCK_SIZE(lvl, data); + int i; + +- if (lvl == DART_MAX_LEVELS - 1) ++ if (lvl == DART_MAX_LEVELS - 1 && data->iop.fmt == APPLE_DART) + pte |= APPLE_DART1_PTE_PROT_SP_DIS; + + pte |= APPLE_DART_PTE_VALID; +@@ -251,10 +276,20 @@ static dart_iopte dart_prot_to_pte(struct dart_io_pgtable *data, + { + dart_iopte pte = 0; + +- if (!(prot & IOMMU_WRITE)) +- pte |= APPLE_DART1_PTE_PROT_NO_WRITE; +- if (!(prot & IOMMU_READ)) +- pte |= APPLE_DART1_PTE_PROT_NO_READ; ++ if (data->iop.fmt == APPLE_DART) { ++ if (!(prot & IOMMU_WRITE)) ++ pte |= APPLE_DART1_PTE_PROT_NO_WRITE; ++ if (!(prot & IOMMU_READ)) ++ pte |= APPLE_DART1_PTE_PROT_NO_READ; ++ } ++ if (data->iop.fmt == APPLE_DART2) { ++ if (!(prot & IOMMU_WRITE)) ++ pte |= APPLE_DART2_PTE_PROT_NO_WRITE; ++ if (!(prot & IOMMU_READ)) ++ pte |= APPLE_DART2_PTE_PROT_NO_READ; ++ if (!(prot & IOMMU_CACHE)) ++ pte |= APPLE_DART2_PTE_PROT_NO_CACHE; ++ } + + return pte; + } +@@ -536,7 +571,7 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) + if (!cfg->coherent_walk) + return NULL; + +- if (cfg->oas > 36) ++ if (cfg->oas != 36 && cfg->oas != 42) + return NULL; + + data = dart_alloc_pgtable(cfg); +diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c +index 16205ea9272c..49f46e1eabf7 100644 +--- a/drivers/iommu/io-pgtable.c ++++ b/drivers/iommu/io-pgtable.c +@@ -23,6 +23,7 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = { + #endif + #ifdef CONFIG_IOMMU_IO_PGTABLE_DART + [APPLE_DART] = &io_pgtable_apple_dart_init_fns, ++ [APPLE_DART2] = &io_pgtable_apple_dart_init_fns, + #endif + #ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S + [ARM_V7S] = &io_pgtable_arm_v7s_init_fns, +diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h +index 86af6f0a00a2..76b98511cbc8 100644 +--- a/include/linux/io-pgtable.h ++++ b/include/linux/io-pgtable.h +@@ -17,6 +17,7 @@ enum io_pgtable_fmt { + ARM_MALI_LPAE, + AMD_IOMMU_V1, + APPLE_DART, ++ APPLE_DART2, + IO_PGTABLE_NUM_FMTS, + }; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0050-iommu-dart-Support-t6000-variant.patch b/target/linux/silicon/patches-5.19/0050-iommu-dart-Support-t6000-variant.patch new file mode 100644 index 000000000..c9d4049fd --- /dev/null +++ b/target/linux/silicon/patches-5.19/0050-iommu-dart-Support-t6000-variant.patch @@ -0,0 +1,99 @@ +From 69d73a2d8f767b1e1d4ea00fcd8be33f5fc8b7c0 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Tue, 2 Nov 2021 18:10:52 +0100 +Subject: [PATCH 050/171] iommu: dart: Support t6000 variant + +The M1 Pro/Max/Ultra SoCs come with a new variant of DART which +supports a larger physical address space with a different PTE format. +Pass through the correct paddr address space size and the PTE format +to the io-pgtable code which will take care of the rest. + +Signed-off-by: Sven Peter +Co-developed-by: Janne Grunau +Signed-off-by: Janne Grunau + +Commit-changes: 2 +- use APPLE_DART2 PTE format for dart-t6000 + +Commit-changes: 3 +- apply change to io-pgtable-dart.c +--- + drivers/iommu/apple-dart.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c +index 8af0242a90d9..e5793c0d08b4 100644 +--- a/drivers/iommu/apple-dart.c ++++ b/drivers/iommu/apple-dart.c +@@ -81,10 +81,16 @@ + #define DART_TTBR_VALID BIT(31) + #define DART_TTBR_SHIFT 12 + ++struct apple_dart_hw { ++ u32 oas; ++ enum io_pgtable_fmt fmt; ++}; ++ + /* + * Private structure associated with each DART device. + * + * @dev: device struct ++ * @hw: SoC-specific hardware data + * @regs: mapped MMIO region + * @irq: interrupt number, can be shared with other DARTs + * @clks: clocks associated with this DART +@@ -98,6 +104,7 @@ + */ + struct apple_dart { + struct device *dev; ++ const struct apple_dart_hw *hw; + + void __iomem *regs; + +@@ -421,13 +428,13 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain, + pgtbl_cfg = (struct io_pgtable_cfg){ + .pgsize_bitmap = dart->pgsize, + .ias = 32, +- .oas = 36, ++ .oas = dart->hw->oas, + .coherent_walk = 1, + .iommu_dev = dart->dev, + }; + + dart_domain->pgtbl_ops = +- alloc_io_pgtable_ops(APPLE_DART, &pgtbl_cfg, domain); ++ alloc_io_pgtable_ops(dart->hw->fmt, &pgtbl_cfg, domain); + if (!dart_domain->pgtbl_ops) { + ret = -ENOMEM; + goto done; +@@ -858,6 +865,7 @@ static int apple_dart_probe(struct platform_device *pdev) + return -ENOMEM; + + dart->dev = dev; ++ dart->hw = of_device_get_match_data(dev); + spin_lock_init(&dart->lock); + + dart->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); +@@ -946,8 +954,18 @@ static int apple_dart_remove(struct platform_device *pdev) + return 0; + } + ++static const struct apple_dart_hw apple_dart_hw_t8103 = { ++ .oas = 36, ++ .fmt = APPLE_DART, ++}; ++static const struct apple_dart_hw apple_dart_hw_t6000 = { ++ .oas = 42, ++ .fmt = APPLE_DART2, ++}; ++ + static const struct of_device_id apple_dart_of_match[] = { +- { .compatible = "apple,t8103-dart", .data = NULL }, ++ { .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 }, ++ { .compatible = "apple,t6000-dart", .data = &apple_dart_hw_t6000 }, + {}, + }; + MODULE_DEVICE_TABLE(of, apple_dart_of_match); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0051-iommu-dart-Add-suspend-resume-support.patch b/target/linux/silicon/patches-5.19/0051-iommu-dart-Add-suspend-resume-support.patch new file mode 100644 index 000000000..c73919747 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0051-iommu-dart-Add-suspend-resume-support.patch @@ -0,0 +1,91 @@ +From 6b1080a482294824b6dfb65501de061a86a1939d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 5 Mar 2022 21:17:10 +0900 +Subject: [PATCH 051/171] iommu: dart: Add suspend/resume support + +We need to save/restore the TCR/TTBR registers, since they are lost +on power gate. + +Signed-off-by: Hector Martin +--- + drivers/iommu/apple-dart.c | 50 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c +index e5793c0d08b4..90aceb6ac774 100644 +--- a/drivers/iommu/apple-dart.c ++++ b/drivers/iommu/apple-dart.c +@@ -120,6 +120,9 @@ struct apple_dart { + + struct iommu_group *sid2group[DART_MAX_STREAMS]; + struct iommu_device iommu; ++ ++ u32 save_tcr[DART_MAX_STREAMS]; ++ u32 save_ttbr[DART_MAX_STREAMS][DART_MAX_TTBR]; + }; + + /* +@@ -963,6 +966,50 @@ static const struct apple_dart_hw apple_dart_hw_t6000 = { + .fmt = APPLE_DART2, + }; + ++#ifdef CONFIG_PM_SLEEP ++static int apple_dart_suspend(struct device *dev) ++{ ++ struct apple_dart *dart = dev_get_drvdata(dev); ++ unsigned int sid, idx; ++ ++ for (sid = 0; sid < DART_MAX_STREAMS; sid++) { ++ dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(sid)); ++ for (idx = 0; idx < DART_MAX_TTBR; idx++) ++ dart->save_ttbr[sid][idx] = ++ readl_relaxed(dart->regs + DART_TTBR(sid, idx)); ++ } ++ ++ return 0; ++} ++ ++static int apple_dart_resume(struct device *dev) ++{ ++ struct apple_dart *dart = dev_get_drvdata(dev); ++ unsigned int sid, idx; ++ int ret; ++ ++ ret = apple_dart_hw_reset(dart); ++ if (ret) { ++ dev_err(dev, "Failed to reset DART on resume\n"); ++ return ret; ++ } ++ ++ for (sid = 0; sid < DART_MAX_STREAMS; sid++) { ++ for (idx = 0; idx < DART_MAX_TTBR; idx++) ++ writel_relaxed(dart->save_ttbr[sid][idx], ++ dart->regs + DART_TTBR(sid, idx)); ++ writel_relaxed(dart->save_tcr[sid], dart->regs + DART_TCR(sid)); ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops apple_dart_pm_ops = { ++ .suspend = apple_dart_suspend, ++ .resume = apple_dart_resume, ++}; ++#endif ++ + static const struct of_device_id apple_dart_of_match[] = { + { .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 }, + { .compatible = "apple,t6000-dart", .data = &apple_dart_hw_t6000 }, +@@ -975,6 +1022,9 @@ static struct platform_driver apple_dart_driver = { + .name = "apple-dart", + .of_match_table = apple_dart_of_match, + .suppress_bind_attrs = true, ++#ifdef CONFIG_PM_SLEEP ++ .pm = &apple_dart_pm_ops, ++#endif + }, + .probe = apple_dart_probe, + .remove = apple_dart_remove, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0052-iommu-dart-Support-64-stream-IDs.patch b/target/linux/silicon/patches-5.19/0052-iommu-dart-Support-64-stream-IDs.patch new file mode 100644 index 000000000..805fab178 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0052-iommu-dart-Support-64-stream-IDs.patch @@ -0,0 +1,359 @@ +From 82d7ff6fe9af1e8cd39bce1d46a679074b8d7749 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 28 Jun 2022 01:07:20 +0900 +Subject: [PATCH 052/171] iommu: dart: Support >64 stream IDs + +T8110 DARTs have up to 256 SIDs, so we need to switch to a bitmap to +handle them properly. + +Signed-off-by: Hector Martin +--- + drivers/iommu/apple-dart.c | 113 +++++++++++++++++++++++-------------- + 1 file changed, 70 insertions(+), 43 deletions(-) + +diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c +index 90aceb6ac774..39e6f86dd525 100644 +--- a/drivers/iommu/apple-dart.c ++++ b/drivers/iommu/apple-dart.c +@@ -33,11 +33,10 @@ + #include + #include + +-#define DART_MAX_STREAMS 16 ++#define DART_MAX_STREAMS 256 + #define DART_MAX_TTBR 4 + #define MAX_DARTS_PER_DEVICE 2 + +-#define DART_STREAM_ALL 0xffff + + #define DART_PARAMS1 0x00 + #define DART_PARAMS_PAGE_SHIFT GENMASK(27, 24) +@@ -84,6 +83,8 @@ + struct apple_dart_hw { + u32 oas; + enum io_pgtable_fmt fmt; ++ ++ int max_sid_count; + }; + + /* +@@ -115,6 +116,7 @@ struct apple_dart { + spinlock_t lock; + + u32 pgsize; ++ u32 num_streams; + u32 supports_bypass : 1; + u32 force_bypass : 1; + +@@ -142,11 +144,11 @@ struct apple_dart { + */ + struct apple_dart_stream_map { + struct apple_dart *dart; +- unsigned long sidmap; ++ DECLARE_BITMAP(sidmap, DART_MAX_STREAMS); + }; + struct apple_dart_atomic_stream_map { + struct apple_dart *dart; +- atomic64_t sidmap; ++ atomic_long_t sidmap[BITS_TO_LONGS(DART_MAX_STREAMS)]; + }; + + /* +@@ -204,50 +206,55 @@ static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom) + static void + apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map) + { ++ struct apple_dart *dart = stream_map->dart; + int sid; + +- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) ++ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) + writel(DART_TCR_TRANSLATE_ENABLE, +- stream_map->dart->regs + DART_TCR(sid)); ++ dart->regs + DART_TCR(sid)); + } + + static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map) + { ++ struct apple_dart *dart = stream_map->dart; + int sid; + +- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) +- writel(0, stream_map->dart->regs + DART_TCR(sid)); ++ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) ++ writel(0, dart->regs + DART_TCR(sid)); + } + + static void + apple_dart_hw_enable_bypass(struct apple_dart_stream_map *stream_map) + { ++ struct apple_dart *dart = stream_map->dart; + int sid; + + WARN_ON(!stream_map->dart->supports_bypass); +- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) ++ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) + writel(DART_TCR_BYPASS0_ENABLE | DART_TCR_BYPASS1_ENABLE, +- stream_map->dart->regs + DART_TCR(sid)); ++ dart->regs + DART_TCR(sid)); + } + + static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map, + u8 idx, phys_addr_t paddr) + { ++ struct apple_dart *dart = stream_map->dart; + int sid; + + WARN_ON(paddr & ((1 << DART_TTBR_SHIFT) - 1)); +- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) ++ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) + writel(DART_TTBR_VALID | (paddr >> DART_TTBR_SHIFT), +- stream_map->dart->regs + DART_TTBR(sid, idx)); ++ dart->regs + DART_TTBR(sid, idx)); + } + + static void apple_dart_hw_clear_ttbr(struct apple_dart_stream_map *stream_map, + u8 idx) + { ++ struct apple_dart *dart = stream_map->dart; + int sid; + +- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) +- writel(0, stream_map->dart->regs + DART_TTBR(sid, idx)); ++ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) ++ writel(0, dart->regs + DART_TTBR(sid, idx)); + } + + static void +@@ -269,7 +276,7 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map, + + spin_lock_irqsave(&stream_map->dart->lock, flags); + +- writel(stream_map->sidmap, stream_map->dart->regs + DART_STREAM_SELECT); ++ writel(stream_map->sidmap[0], stream_map->dart->regs + DART_STREAM_SELECT); + writel(command, stream_map->dart->regs + DART_STREAM_COMMAND); + + ret = readl_poll_timeout_atomic( +@@ -282,7 +289,7 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map, + if (ret) { + dev_err(stream_map->dart->dev, + "busy bit did not clear after command %x for streams %lx\n", +- command, stream_map->sidmap); ++ command, stream_map->sidmap[0]); + return ret; + } + +@@ -300,6 +307,7 @@ static int apple_dart_hw_reset(struct apple_dart *dart) + { + u32 config; + struct apple_dart_stream_map stream_map; ++ int i; + + config = readl(dart->regs + DART_CONFIG); + if (config & DART_CONFIG_LOCK) { +@@ -309,12 +317,14 @@ static int apple_dart_hw_reset(struct apple_dart *dart) + } + + stream_map.dart = dart; +- stream_map.sidmap = DART_STREAM_ALL; ++ bitmap_zero(stream_map.sidmap, DART_MAX_STREAMS); ++ bitmap_set(stream_map.sidmap, 0, dart->num_streams); + apple_dart_hw_disable_dma(&stream_map); + apple_dart_hw_clear_all_ttbrs(&stream_map); + + /* enable all streams globally since TCR is used to control isolation */ +- writel(DART_STREAM_ALL, dart->regs + DART_STREAMS_ENABLE); ++ for (i = 0; i < BITS_TO_U32(dart->num_streams); i++) ++ writel(U32_MAX, dart->regs + DART_STREAMS_ENABLE); + + /* clear any pending errors before the interrupt is unmasked */ + writel(readl(dart->regs + DART_ERROR), dart->regs + DART_ERROR); +@@ -324,13 +334,16 @@ static int apple_dart_hw_reset(struct apple_dart *dart) + + static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain) + { +- int i; ++ int i, j; + struct apple_dart_atomic_stream_map *domain_stream_map; + struct apple_dart_stream_map stream_map; + + for_each_stream_map(i, domain, domain_stream_map) { + stream_map.dart = domain_stream_map->dart; +- stream_map.sidmap = atomic64_read(&domain_stream_map->sidmap); ++ ++ for (j = 0; j < BITS_TO_LONGS(stream_map.dart->num_streams); j++) ++ stream_map.sidmap[j] = atomic64_read(&domain_stream_map->sidmap[j]); ++ + apple_dart_hw_invalidate_tlb(&stream_map); + } + } +@@ -415,7 +428,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain, + struct apple_dart *dart = cfg->stream_maps[0].dart; + struct io_pgtable_cfg pgtbl_cfg; + int ret = 0; +- int i; ++ int i, j; + + mutex_lock(&dart_domain->init_lock); + +@@ -424,8 +437,9 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain, + + for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) { + dart_domain->stream_maps[i].dart = cfg->stream_maps[i].dart; +- atomic64_set(&dart_domain->stream_maps[i].sidmap, +- cfg->stream_maps[i].sidmap); ++ for (j = 0; j < BITS_TO_LONGS(dart->num_streams); j++) ++ atomic64_set(&dart_domain->stream_maps[i].sidmap[j], ++ cfg->stream_maps[i].sidmap[j]); + } + + pgtbl_cfg = (struct io_pgtable_cfg){ +@@ -460,7 +474,7 @@ apple_dart_mod_streams(struct apple_dart_atomic_stream_map *domain_maps, + struct apple_dart_stream_map *master_maps, + bool add_streams) + { +- int i; ++ int i, j; + + for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) { + if (domain_maps[i].dart != master_maps[i].dart) +@@ -470,12 +484,14 @@ apple_dart_mod_streams(struct apple_dart_atomic_stream_map *domain_maps, + for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) { + if (!domain_maps[i].dart) + break; +- if (add_streams) +- atomic64_or(master_maps[i].sidmap, +- &domain_maps[i].sidmap); +- else +- atomic64_and(~master_maps[i].sidmap, +- &domain_maps[i].sidmap); ++ for (j = 0; j < BITS_TO_LONGS(domain_maps[i].dart->num_streams); j++) { ++ if (add_streams) ++ atomic64_or(master_maps[i].sidmap[j], ++ &domain_maps[i].sidmap[j]); ++ else ++ atomic64_and(~master_maps[i].sidmap[j], ++ &domain_maps[i].sidmap[j]); ++ } + } + + return 0; +@@ -642,14 +658,14 @@ static int apple_dart_of_xlate(struct device *dev, struct of_phandle_args *args) + + for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) { + if (cfg->stream_maps[i].dart == dart) { +- cfg->stream_maps[i].sidmap |= 1 << sid; ++ set_bit(sid, cfg->stream_maps[i].sidmap); + return 0; + } + } + for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) { + if (!cfg->stream_maps[i].dart) { + cfg->stream_maps[i].dart = dart; +- cfg->stream_maps[i].sidmap = 1 << sid; ++ set_bit(sid, cfg->stream_maps[i].sidmap); + return 0; + } + } +@@ -668,7 +684,7 @@ static void apple_dart_release_group(void *iommu_data) + mutex_lock(&apple_dart_groups_lock); + + for_each_stream_map(i, group_master_cfg, stream_map) +- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) ++ for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams) + stream_map->dart->sid2group[sid] = NULL; + + kfree(iommu_data); +@@ -687,7 +703,7 @@ static struct iommu_group *apple_dart_device_group(struct device *dev) + mutex_lock(&apple_dart_groups_lock); + + for_each_stream_map(i, cfg, stream_map) { +- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) { ++ for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams) { + struct iommu_group *stream_group = + stream_map->dart->sid2group[sid]; + +@@ -726,7 +742,7 @@ static struct iommu_group *apple_dart_device_group(struct device *dev) + apple_dart_release_group); + + for_each_stream_map(i, cfg, stream_map) +- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) ++ for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams) + stream_map->dart->sid2group[sid] = group; + + res = group; +@@ -893,16 +909,25 @@ static int apple_dart_probe(struct platform_device *pdev) + if (ret) + return ret; + +- ret = apple_dart_hw_reset(dart); +- if (ret) +- goto err_clk_disable; +- + dart_params[0] = readl(dart->regs + DART_PARAMS1); + dart_params[1] = readl(dart->regs + DART_PARAMS2); + dart->pgsize = 1 << FIELD_GET(DART_PARAMS_PAGE_SHIFT, dart_params[0]); + dart->supports_bypass = dart_params[1] & DART_PARAMS_BYPASS_SUPPORT; ++ ++ dart->num_streams = dart->hw->max_sid_count; ++ ++ if (dart->num_streams > DART_MAX_STREAMS) { ++ dev_err(&pdev->dev, "Too many streams (%d > %d)\n", ++ dart->num_streams, DART_MAX_STREAMS); ++ goto err_clk_disable; ++ } ++ + dart->force_bypass = dart->pgsize > PAGE_SIZE; + ++ ret = apple_dart_hw_reset(dart); ++ if (ret) ++ goto err_clk_disable; ++ + ret = request_irq(dart->irq, apple_dart_irq, IRQF_SHARED, + "apple-dart fault handler", dart); + if (ret) +@@ -925,8 +950,8 @@ static int apple_dart_probe(struct platform_device *pdev) + + dev_info( + &pdev->dev, +- "DART [pagesize %x, bypass support: %d, bypass forced: %d] initialized\n", +- dart->pgsize, dart->supports_bypass, dart->force_bypass); ++ "DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d] initialized\n", ++ dart->pgsize, dart->num_streams, dart->supports_bypass, dart->force_bypass); + return 0; + + err_sysfs_remove: +@@ -960,10 +985,12 @@ static int apple_dart_remove(struct platform_device *pdev) + static const struct apple_dart_hw apple_dart_hw_t8103 = { + .oas = 36, + .fmt = APPLE_DART, ++ .max_sid_count = 16, + }; + static const struct apple_dart_hw apple_dart_hw_t6000 = { + .oas = 42, + .fmt = APPLE_DART2, ++ .max_sid_count = 16, + }; + + #ifdef CONFIG_PM_SLEEP +@@ -972,7 +999,7 @@ static int apple_dart_suspend(struct device *dev) + struct apple_dart *dart = dev_get_drvdata(dev); + unsigned int sid, idx; + +- for (sid = 0; sid < DART_MAX_STREAMS; sid++) { ++ for (sid = 0; sid < dart->num_streams; sid++) { + dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(sid)); + for (idx = 0; idx < DART_MAX_TTBR; idx++) + dart->save_ttbr[sid][idx] = +@@ -994,7 +1021,7 @@ static int apple_dart_resume(struct device *dev) + return ret; + } + +- for (sid = 0; sid < DART_MAX_STREAMS; sid++) { ++ for (sid = 0; sid < dart->num_streams; sid++) { + for (idx = 0; idx < DART_MAX_TTBR; idx++) + writel_relaxed(dart->save_ttbr[sid][idx], + dart->regs + DART_TTBR(sid, idx)); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0053-iommu-dart-Support-a-variable-number-of-TTBRs-per-st.patch b/target/linux/silicon/patches-5.19/0053-iommu-dart-Support-a-variable-number-of-TTBRs-per-st.patch new file mode 100644 index 000000000..45aefa743 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0053-iommu-dart-Support-a-variable-number-of-TTBRs-per-st.patch @@ -0,0 +1,119 @@ +From 180390038e38222406314cb6eea2182a7817b459 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 28 Jun 2022 01:16:28 +0900 +Subject: [PATCH 053/171] iommu: dart: Support a variable number of TTBRs per + stream + +T8110 only has one TTBR per stream, so un-hardcode that. + +Signed-off-by: Hector Martin +--- + drivers/iommu/apple-dart.c | 28 +++++++++++++++++++--------- + 1 file changed, 19 insertions(+), 9 deletions(-) + +diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c +index 39e6f86dd525..9f2751c12070 100644 +--- a/drivers/iommu/apple-dart.c ++++ b/drivers/iommu/apple-dart.c +@@ -76,15 +76,21 @@ + #define DART_TCR_BYPASS0_ENABLE BIT(8) + #define DART_TCR_BYPASS1_ENABLE BIT(12) + +-#define DART_TTBR(sid, idx) (0x200 + 16 * (sid) + 4 * (idx)) + #define DART_TTBR_VALID BIT(31) + #define DART_TTBR_SHIFT 12 + ++#define DART_TTBR(dart, sid, idx) (0x200 + \ ++ (((dart)->hw->ttbr_count * (sid)) << 2) + \ ++ ((idx) << 2)) ++ ++ + struct apple_dart_hw { + u32 oas; + enum io_pgtable_fmt fmt; + + int max_sid_count; ++ ++ int ttbr_count; + }; + + /* +@@ -244,7 +250,7 @@ static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map, + WARN_ON(paddr & ((1 << DART_TTBR_SHIFT) - 1)); + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) + writel(DART_TTBR_VALID | (paddr >> DART_TTBR_SHIFT), +- dart->regs + DART_TTBR(sid, idx)); ++ dart->regs + DART_TTBR(dart, sid, idx)); + } + + static void apple_dart_hw_clear_ttbr(struct apple_dart_stream_map *stream_map, +@@ -254,7 +260,7 @@ static void apple_dart_hw_clear_ttbr(struct apple_dart_stream_map *stream_map, + int sid; + + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) +- writel(0, dart->regs + DART_TTBR(sid, idx)); ++ writel(0, dart->regs + DART_TTBR(dart, sid, idx)); + } + + static void +@@ -262,7 +268,7 @@ apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map *stream_map) + { + int i; + +- for (i = 0; i < DART_MAX_TTBR; ++i) ++ for (i = 0; i < stream_map->dart->hw->ttbr_count; ++i) + apple_dart_hw_clear_ttbr(stream_map, i); + } + +@@ -414,7 +420,7 @@ apple_dart_setup_translation(struct apple_dart_domain *domain, + for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i) + apple_dart_hw_set_ttbr(stream_map, i, + pgtbl_cfg->apple_dart_cfg.ttbr[i]); +- for (; i < DART_MAX_TTBR; ++i) ++ for (; i < stream_map->dart->hw->ttbr_count; ++i) + apple_dart_hw_clear_ttbr(stream_map, i); + + apple_dart_hw_enable_translation(stream_map); +@@ -986,11 +992,15 @@ static const struct apple_dart_hw apple_dart_hw_t8103 = { + .oas = 36, + .fmt = APPLE_DART, + .max_sid_count = 16, ++ ++ .ttbr_count = 4, + }; + static const struct apple_dart_hw apple_dart_hw_t6000 = { + .oas = 42, + .fmt = APPLE_DART2, + .max_sid_count = 16, ++ ++ .ttbr_count = 4, + }; + + #ifdef CONFIG_PM_SLEEP +@@ -1001,9 +1011,9 @@ static int apple_dart_suspend(struct device *dev) + + for (sid = 0; sid < dart->num_streams; sid++) { + dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(sid)); +- for (idx = 0; idx < DART_MAX_TTBR; idx++) ++ for (idx = 0; idx < dart->hw->ttbr_count; idx++) + dart->save_ttbr[sid][idx] = +- readl_relaxed(dart->regs + DART_TTBR(sid, idx)); ++ readl_relaxed(dart->regs + DART_TTBR(dart, sid, idx)); + } + + return 0; +@@ -1022,9 +1032,9 @@ static int apple_dart_resume(struct device *dev) + } + + for (sid = 0; sid < dart->num_streams; sid++) { +- for (idx = 0; idx < DART_MAX_TTBR; idx++) ++ for (idx = 0; idx < dart->hw->ttbr_count; idx++) + writel_relaxed(dart->save_ttbr[sid][idx], +- dart->regs + DART_TTBR(sid, idx)); ++ dart->regs + DART_TTBR(dart, sid, idx)); + writel_relaxed(dart->save_tcr[sid], dart->regs + DART_TCR(sid)); + } + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0054-iommu-dart-Fix-DART_PARAMS1-2-bit-define-names.patch b/target/linux/silicon/patches-5.19/0054-iommu-dart-Fix-DART_PARAMS1-2-bit-define-names.patch new file mode 100644 index 000000000..c8d4bc03c --- /dev/null +++ b/target/linux/silicon/patches-5.19/0054-iommu-dart-Fix-DART_PARAMS1-2-bit-define-names.patch @@ -0,0 +1,43 @@ +From 85ab83f3cc7a4f0bfff8edd1662c2d98cda766a1 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 28 Jun 2022 01:20:52 +0900 +Subject: [PATCH 054/171] iommu: dart: Fix DART_PARAMS1/2 bit define names + +They didn't have the PARAMS reg index in them, but they should. + +Signed-off-by: Hector Martin +--- + drivers/iommu/apple-dart.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c +index 9f2751c12070..e6b641037429 100644 +--- a/drivers/iommu/apple-dart.c ++++ b/drivers/iommu/apple-dart.c +@@ -39,10 +39,10 @@ + + + #define DART_PARAMS1 0x00 +-#define DART_PARAMS_PAGE_SHIFT GENMASK(27, 24) ++#define DART_PARAMS1_PAGE_SHIFT GENMASK(27, 24) + + #define DART_PARAMS2 0x04 +-#define DART_PARAMS_BYPASS_SUPPORT BIT(0) ++#define DART_PARAMS2_BYPASS_SUPPORT BIT(0) + + #define DART_STREAM_COMMAND 0x20 + #define DART_STREAM_COMMAND_BUSY BIT(2) +@@ -917,8 +917,8 @@ static int apple_dart_probe(struct platform_device *pdev) + + dart_params[0] = readl(dart->regs + DART_PARAMS1); + dart_params[1] = readl(dart->regs + DART_PARAMS2); +- dart->pgsize = 1 << FIELD_GET(DART_PARAMS_PAGE_SHIFT, dart_params[0]); +- dart->supports_bypass = dart_params[1] & DART_PARAMS_BYPASS_SUPPORT; ++ dart->pgsize = 1 << FIELD_GET(DART_PARAMS1_PAGE_SHIFT, dart_params[0]); ++ dart->supports_bypass = dart_params[1] & DART_PARAMS2_BYPASS_SUPPORT; + + dart->num_streams = dart->hw->max_sid_count; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0055-iommu-dart-Support-different-variants-with-different.patch b/target/linux/silicon/patches-5.19/0055-iommu-dart-Support-different-variants-with-different.patch new file mode 100644 index 000000000..7ef4b10c7 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0055-iommu-dart-Support-different-variants-with-different.patch @@ -0,0 +1,394 @@ +From fbe7133a9b1e71ee18185dd7c67712c909515bfd Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 28 Jun 2022 01:27:28 +0900 +Subject: [PATCH 055/171] iommu: dart: Support different variants with + different registers + +T8110 has a new register layout. To accomodate this, first move all the +register offsets to the hw structure, and rename all the existing +registers to DART_T8020_*. + +Signed-off-by: Hector Martin +--- + drivers/iommu/apple-dart.c | 188 ++++++++++++++++++++++++------------- + 1 file changed, 125 insertions(+), 63 deletions(-) + +diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c +index e6b641037429..3f89db3f8e99 100644 +--- a/drivers/iommu/apple-dart.c ++++ b/drivers/iommu/apple-dart.c +@@ -37,6 +37,7 @@ + #define DART_MAX_TTBR 4 + #define MAX_DARTS_PER_DEVICE 2 + ++/* Common registers */ + + #define DART_PARAMS1 0x00 + #define DART_PARAMS1_PAGE_SHIFT GENMASK(27, 24) +@@ -44,52 +45,79 @@ + #define DART_PARAMS2 0x04 + #define DART_PARAMS2_BYPASS_SUPPORT BIT(0) + +-#define DART_STREAM_COMMAND 0x20 +-#define DART_STREAM_COMMAND_BUSY BIT(2) +-#define DART_STREAM_COMMAND_INVALIDATE BIT(20) ++/* T8020/T6000 registers */ + +-#define DART_STREAM_SELECT 0x34 ++#define DART_T8020_STREAM_COMMAND 0x20 ++#define DART_T8020_STREAM_COMMAND_BUSY BIT(2) ++#define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20) + +-#define DART_ERROR 0x40 +-#define DART_ERROR_STREAM GENMASK(27, 24) +-#define DART_ERROR_CODE GENMASK(11, 0) +-#define DART_ERROR_FLAG BIT(31) ++#define DART_T8020_STREAM_SELECT 0x34 + +-#define DART_ERROR_READ_FAULT BIT(4) +-#define DART_ERROR_WRITE_FAULT BIT(3) +-#define DART_ERROR_NO_PTE BIT(2) +-#define DART_ERROR_NO_PMD BIT(1) +-#define DART_ERROR_NO_TTBR BIT(0) ++#define DART_T8020_ERROR 0x40 ++#define DART_T8020_ERROR_STREAM GENMASK(27, 24) ++#define DART_T8020_ERROR_CODE GENMASK(11, 0) ++#define DART_T8020_ERROR_FLAG BIT(31) + +-#define DART_CONFIG 0x60 +-#define DART_CONFIG_LOCK BIT(15) ++#define DART_T8020_ERROR_READ_FAULT BIT(4) ++#define DART_T8020_ERROR_WRITE_FAULT BIT(3) ++#define DART_T8020_ERROR_NO_PTE BIT(2) ++#define DART_T8020_ERROR_NO_PMD BIT(1) ++#define DART_T8020_ERROR_NO_TTBR BIT(0) ++ ++#define DART_T8020_CONFIG 0x60 ++#define DART_T8020_CONFIG_LOCK BIT(15) + + #define DART_STREAM_COMMAND_BUSY_TIMEOUT 100 + +-#define DART_ERROR_ADDR_HI 0x54 +-#define DART_ERROR_ADDR_LO 0x50 ++#define DART_T8020_ERROR_ADDR_HI 0x54 ++#define DART_T8020_ERROR_ADDR_LO 0x50 ++ ++#define DART_T8020_STREAMS_ENABLE 0xfc + +-#define DART_STREAMS_ENABLE 0xfc ++#define DART_T8020_TCR 0x100 ++#define DART_T8020_TCR_TRANSLATE_ENABLE BIT(7) ++#define DART_T8020_TCR_BYPASS_DART BIT(8) ++#define DART_T8020_TCR_BYPASS_DAPF BIT(12) + +-#define DART_TCR(sid) (0x100 + 4 * (sid)) +-#define DART_TCR_TRANSLATE_ENABLE BIT(7) +-#define DART_TCR_BYPASS0_ENABLE BIT(8) +-#define DART_TCR_BYPASS1_ENABLE BIT(12) ++#define DART_T8020_TTBR 0x200 ++#define DART_T8020_TTBR_VALID BIT(31) ++#define DART_T8020_TTBR_ADDR_OFF 0 ++#define DART_T8020_TTBR_SHIFT 12 + +-#define DART_TTBR_VALID BIT(31) +-#define DART_TTBR_SHIFT 12 ++#define DART_TCR(dart, sid) ((dart)->hw->tcr + ((sid) << 2)) + +-#define DART_TTBR(dart, sid, idx) (0x200 + \ ++#define DART_TTBR(dart, sid, idx) ((dart)->hw->ttbr + \ + (((dart)->hw->ttbr_count * (sid)) << 2) + \ + ((idx) << 2)) + ++struct apple_dart_stream_map; + + struct apple_dart_hw { ++ irqreturn_t (*irq_handler)(int irq, void *dev); ++ int (*invalidate_tlb)(struct apple_dart_stream_map *stream_map); ++ + u32 oas; + enum io_pgtable_fmt fmt; + + int max_sid_count; + ++ u64 lock; ++ u64 lock_bit; ++ ++ u64 error; ++ ++ u64 enable_streams; ++ u64 disable_streams; ++ ++ u64 tcr; ++ u64 tcr_enabled; ++ u64 tcr_disabled; ++ u64 tcr_bypass; ++ ++ u64 ttbr; ++ u64 ttbr_valid; ++ u64 ttbr_addr_off; ++ u64 ttbr_shift; + int ttbr_count; + }; + +@@ -216,8 +244,7 @@ apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map) + int sid; + + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) +- writel(DART_TCR_TRANSLATE_ENABLE, +- dart->regs + DART_TCR(sid)); ++ writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid)); + } + + static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map) +@@ -226,7 +253,7 @@ static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map) + int sid; + + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) +- writel(0, dart->regs + DART_TCR(sid)); ++ writel(dart->hw->tcr_disabled, dart->regs + DART_TCR(dart, sid)); + } + + static void +@@ -237,8 +264,8 @@ apple_dart_hw_enable_bypass(struct apple_dart_stream_map *stream_map) + + WARN_ON(!stream_map->dart->supports_bypass); + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) +- writel(DART_TCR_BYPASS0_ENABLE | DART_TCR_BYPASS1_ENABLE, +- dart->regs + DART_TCR(sid)); ++ writel(dart->hw->tcr_bypass, ++ dart->regs + DART_TCR(dart, sid)); + } + + static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map, +@@ -247,9 +274,10 @@ static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map, + struct apple_dart *dart = stream_map->dart; + int sid; + +- WARN_ON(paddr & ((1 << DART_TTBR_SHIFT) - 1)); ++ WARN_ON(paddr & ((1 << dart->hw->ttbr_shift) - 1)); + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) +- writel(DART_TTBR_VALID | (paddr >> DART_TTBR_SHIFT), ++ writel(dart->hw->ttbr_valid | ++ (paddr >> dart->hw->ttbr_shift) << dart->hw->ttbr_addr_off, + dart->regs + DART_TTBR(dart, sid, idx)); + } + +@@ -273,7 +301,7 @@ apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map *stream_map) + } + + static int +-apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map, ++apple_dart_t8020_hw_stream_command(struct apple_dart_stream_map *stream_map, + u32 command) + { + unsigned long flags; +@@ -282,12 +310,12 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map, + + spin_lock_irqsave(&stream_map->dart->lock, flags); + +- writel(stream_map->sidmap[0], stream_map->dart->regs + DART_STREAM_SELECT); +- writel(command, stream_map->dart->regs + DART_STREAM_COMMAND); ++ writel(stream_map->sidmap[0], stream_map->dart->regs + DART_T8020_STREAM_SELECT); ++ writel(command, stream_map->dart->regs + DART_T8020_STREAM_COMMAND); + + ret = readl_poll_timeout_atomic( +- stream_map->dart->regs + DART_STREAM_COMMAND, command_reg, +- !(command_reg & DART_STREAM_COMMAND_BUSY), 1, ++ stream_map->dart->regs + DART_T8020_STREAM_COMMAND, command_reg, ++ !(command_reg & DART_T8020_STREAM_COMMAND_BUSY), 1, + DART_STREAM_COMMAND_BUSY_TIMEOUT); + + spin_unlock_irqrestore(&stream_map->dart->lock, flags); +@@ -303,10 +331,10 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map, + } + + static int +-apple_dart_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map) ++apple_dart_t8020_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map) + { +- return apple_dart_hw_stream_command(stream_map, +- DART_STREAM_COMMAND_INVALIDATE); ++ return apple_dart_t8020_hw_stream_command( ++ stream_map, DART_T8020_STREAM_COMMAND_INVALIDATE); + } + + static int apple_dart_hw_reset(struct apple_dart *dart) +@@ -315,8 +343,8 @@ static int apple_dart_hw_reset(struct apple_dart *dart) + struct apple_dart_stream_map stream_map; + int i; + +- config = readl(dart->regs + DART_CONFIG); +- if (config & DART_CONFIG_LOCK) { ++ config = readl(dart->regs + dart->hw->lock); ++ if (config & dart->hw->lock_bit) { + dev_err(dart->dev, "DART is locked down until reboot: %08x\n", + config); + return -EINVAL; +@@ -330,12 +358,12 @@ static int apple_dart_hw_reset(struct apple_dart *dart) + + /* enable all streams globally since TCR is used to control isolation */ + for (i = 0; i < BITS_TO_U32(dart->num_streams); i++) +- writel(U32_MAX, dart->regs + DART_STREAMS_ENABLE); ++ writel(U32_MAX, dart->regs + dart->hw->enable_streams); + + /* clear any pending errors before the interrupt is unmasked */ +- writel(readl(dart->regs + DART_ERROR), dart->regs + DART_ERROR); ++ writel(readl(dart->regs + dart->hw->error), dart->regs + dart->hw->error); + +- return apple_dart_hw_invalidate_tlb(&stream_map); ++ return dart->hw->invalidate_tlb(&stream_map); + } + + static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain) +@@ -350,7 +378,7 @@ static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain) + for (j = 0; j < BITS_TO_LONGS(stream_map.dart->num_streams); j++) + stream_map.sidmap[j] = atomic64_read(&domain_stream_map->sidmap[j]); + +- apple_dart_hw_invalidate_tlb(&stream_map); ++ stream_map.dart->hw->invalidate_tlb(&stream_map); + } + } + +@@ -424,7 +452,7 @@ apple_dart_setup_translation(struct apple_dart_domain *domain, + apple_dart_hw_clear_ttbr(stream_map, i); + + apple_dart_hw_enable_translation(stream_map); +- apple_dart_hw_invalidate_tlb(stream_map); ++ stream_map->dart->hw->invalidate_tlb(stream_map); + } + + static int apple_dart_finalize_domain(struct iommu_domain *domain, +@@ -819,30 +847,30 @@ static const struct iommu_ops apple_dart_iommu_ops = { + } + }; + +-static irqreturn_t apple_dart_irq(int irq, void *dev) ++static irqreturn_t apple_dart_t8020_irq(int irq, void *dev) + { + struct apple_dart *dart = dev; + const char *fault_name = NULL; +- u32 error = readl(dart->regs + DART_ERROR); +- u32 error_code = FIELD_GET(DART_ERROR_CODE, error); +- u32 addr_lo = readl(dart->regs + DART_ERROR_ADDR_LO); +- u32 addr_hi = readl(dart->regs + DART_ERROR_ADDR_HI); ++ u32 error = readl(dart->regs + DART_T8020_ERROR); ++ u32 error_code = FIELD_GET(DART_T8020_ERROR_CODE, error); ++ u32 addr_lo = readl(dart->regs + DART_T8020_ERROR_ADDR_LO); ++ u32 addr_hi = readl(dart->regs + DART_T8020_ERROR_ADDR_HI); + u64 addr = addr_lo | (((u64)addr_hi) << 32); +- u8 stream_idx = FIELD_GET(DART_ERROR_STREAM, error); ++ u8 stream_idx = FIELD_GET(DART_T8020_ERROR_STREAM, error); + +- if (!(error & DART_ERROR_FLAG)) ++ if (!(error & DART_T8020_ERROR_FLAG)) + return IRQ_NONE; + + /* there should only be a single bit set but let's use == to be sure */ +- if (error_code == DART_ERROR_READ_FAULT) ++ if (error_code == DART_T8020_ERROR_READ_FAULT) + fault_name = "READ FAULT"; +- else if (error_code == DART_ERROR_WRITE_FAULT) ++ else if (error_code == DART_T8020_ERROR_WRITE_FAULT) + fault_name = "WRITE FAULT"; +- else if (error_code == DART_ERROR_NO_PTE) ++ else if (error_code == DART_T8020_ERROR_NO_PTE) + fault_name = "NO PTE FOR IOVA"; +- else if (error_code == DART_ERROR_NO_PMD) ++ else if (error_code == DART_T8020_ERROR_NO_PMD) + fault_name = "NO PMD FOR IOVA"; +- else if (error_code == DART_ERROR_NO_TTBR) ++ else if (error_code == DART_T8020_ERROR_NO_TTBR) + fault_name = "NO TTBR FOR IOVA"; + else + fault_name = "unknown"; +@@ -852,7 +880,7 @@ static irqreturn_t apple_dart_irq(int irq, void *dev) + "translation fault: status:0x%x stream:%d code:0x%x (%s) at 0x%llx", + error, stream_idx, error_code, fault_name, addr); + +- writel(error, dart->regs + DART_ERROR); ++ writel(error, dart->regs + DART_T8020_ERROR); + return IRQ_HANDLED; + } + +@@ -934,7 +962,7 @@ static int apple_dart_probe(struct platform_device *pdev) + if (ret) + goto err_clk_disable; + +- ret = request_irq(dart->irq, apple_dart_irq, IRQF_SHARED, ++ ret = request_irq(dart->irq, dart->hw->irq_handler, IRQF_SHARED, + "apple-dart fault handler", dart); + if (ret) + goto err_clk_disable; +@@ -989,17 +1017,51 @@ static int apple_dart_remove(struct platform_device *pdev) + } + + static const struct apple_dart_hw apple_dart_hw_t8103 = { ++ .irq_handler = apple_dart_t8020_irq, ++ .invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb, + .oas = 36, + .fmt = APPLE_DART, + .max_sid_count = 16, + ++ .enable_streams = DART_T8020_STREAMS_ENABLE, ++ .lock = DART_T8020_CONFIG, ++ .lock_bit = DART_T8020_CONFIG_LOCK, ++ ++ .error = DART_T8020_ERROR, ++ ++ .tcr = DART_T8020_TCR, ++ .tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE, ++ .tcr_disabled = 0, ++ .tcr_bypass = DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART, ++ ++ .ttbr = DART_T8020_TTBR, ++ .ttbr_valid = DART_T8020_TTBR_VALID, ++ .ttbr_addr_off = DART_T8020_TTBR_ADDR_OFF, ++ .ttbr_shift = DART_T8020_TTBR_SHIFT, + .ttbr_count = 4, + }; + static const struct apple_dart_hw apple_dart_hw_t6000 = { ++ .irq_handler = apple_dart_t8020_irq, ++ .invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb, + .oas = 42, + .fmt = APPLE_DART2, + .max_sid_count = 16, + ++ .enable_streams = DART_T8020_STREAMS_ENABLE, ++ .lock = DART_T8020_CONFIG, ++ .lock_bit = DART_T8020_CONFIG_LOCK, ++ ++ .error = DART_T8020_ERROR, ++ ++ .tcr = DART_T8020_TCR, ++ .tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE, ++ .tcr_disabled = 0, ++ .tcr_bypass = DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART, ++ ++ .ttbr = DART_T8020_TTBR, ++ .ttbr_valid = DART_T8020_TTBR_VALID, ++ .ttbr_addr_off = DART_T8020_TTBR_ADDR_OFF, ++ .ttbr_shift = DART_T8020_TTBR_SHIFT, + .ttbr_count = 4, + }; + +@@ -1010,7 +1072,7 @@ static int apple_dart_suspend(struct device *dev) + unsigned int sid, idx; + + for (sid = 0; sid < dart->num_streams; sid++) { +- dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(sid)); ++ dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(dart, sid)); + for (idx = 0; idx < dart->hw->ttbr_count; idx++) + dart->save_ttbr[sid][idx] = + readl_relaxed(dart->regs + DART_TTBR(dart, sid, idx)); +@@ -1035,7 +1097,7 @@ static int apple_dart_resume(struct device *dev) + for (idx = 0; idx < dart->hw->ttbr_count; idx++) + writel_relaxed(dart->save_ttbr[sid][idx], + dart->regs + DART_TTBR(dart, sid, idx)); +- writel_relaxed(dart->save_tcr[sid], dart->regs + DART_TCR(sid)); ++ writel_relaxed(dart->save_tcr[sid], dart->regs + DART_TCR(dart, sid)); + } + + return 0; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0056-iommu-dart-Add-t8110-support.patch b/target/linux/silicon/patches-5.19/0056-iommu-dart-Add-t8110-support.patch new file mode 100644 index 000000000..0770d12fa --- /dev/null +++ b/target/linux/silicon/patches-5.19/0056-iommu-dart-Add-t8110-support.patch @@ -0,0 +1,316 @@ +From 50f73e1258c60ccd081a09339f77176f0f9bc49c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 28 Jun 2022 01:33:40 +0900 +Subject: [PATCH 056/171] iommu: dart: Add t8110 support + +Signed-off-by: Hector Martin +--- + drivers/iommu/apple-dart.c | 200 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 197 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c +index 3f89db3f8e99..249798e26e5d 100644 +--- a/drivers/iommu/apple-dart.c ++++ b/drivers/iommu/apple-dart.c +@@ -84,6 +84,62 @@ + #define DART_T8020_TTBR_ADDR_OFF 0 + #define DART_T8020_TTBR_SHIFT 12 + ++/* T8110 registers */ ++ ++#define DART_T8110_PARAMS3 0x08 ++#define DART_T8110_PARAMS3_PA_WIDTH GENMASK(29, 24) ++#define DART_T8110_PARAMS3_VA_WIDTH GENMASK(21, 16) ++#define DART_T8110_PARAMS3_VER_MAJ GENMASK(15, 8) ++#define DART_T8110_PARAMS3_VER_MIN GENMASK(7, 0) ++ ++#define DART_T8110_PARAMS4 0x0c ++#define DART_T8110_PARAMS4_NUM_CLIENTS GENMASK(24, 16) ++#define DART_T8110_PARAMS4_NUM_SIDS GENMASK(8, 0) ++ ++#define DART_T8110_TLB_CMD 0x80 ++#define DART_T8110_TLB_CMD_BUSY BIT(31) ++#define DART_T8110_TLB_CMD_OP GENMASK(10, 8) ++#define DART_T8110_TLB_CMD_OP_FLUSH_ALL 0 ++#define DART_T8110_TLB_CMD_OP_FLUSH_SID 1 ++#define DART_T8110_TLB_CMD_STREAM GENMASK(7, 0) ++ ++#define DART_T8110_ERROR 0x100 ++#define DART_T8110_ERROR_STREAM GENMASK(27, 20) ++#define DART_T8110_ERROR_CODE GENMASK(14, 0) ++#define DART_T8110_ERROR_FLAG BIT(31) ++ ++#define DART_T8110_ERROR_MASK 0x104 ++ ++#define DART_T8110_ERROR_READ_FAULT BIT(4) ++#define DART_T8110_ERROR_WRITE_FAULT BIT(3) ++#define DART_T8110_ERROR_NO_PTE BIT(3) ++#define DART_T8110_ERROR_NO_PMD BIT(2) ++#define DART_T8110_ERROR_NO_PGD BIT(1) ++#define DART_T8110_ERROR_NO_TTBR BIT(0) ++ ++#define DART_T8110_ERROR_ADDR_LO 0x170 ++#define DART_T8110_ERROR_ADDR_HI 0x174 ++ ++#define DART_T8110_PROTECT 0x200 ++#define DART_T8110_UNPROTECT 0x204 ++#define DART_T8110_PROTECT_LOCK 0x208 ++#define DART_T8110_PROTECT_TTBR_TCR BIT(0) ++ ++#define DART_T8110_ENABLE_STREAMS 0xc00 ++#define DART_T8110_DISABLE_STREAMS 0xc20 ++ ++#define DART_T8110_TCR 0x1000 ++#define DART_T8110_TCR_REMAP GENMASK(11, 8) ++#define DART_T8110_TCR_REMAP_EN BIT(7) ++#define DART_T8110_TCR_BYPASS_DAPF BIT(2) ++#define DART_T8110_TCR_BYPASS_DART BIT(1) ++#define DART_T8110_TCR_TRANSLATE_ENABLE BIT(0) ++ ++#define DART_T8110_TTBR 0x1400 ++#define DART_T8110_TTBR_VALID BIT(0) ++#define DART_T8110_TTBR_ADDR_OFF 2 ++#define DART_T8110_TTBR_SHIFT 14 ++ + #define DART_TCR(dart, sid) ((dart)->hw->tcr + ((sid) << 2)) + + #define DART_TTBR(dart, sid, idx) ((dart)->hw->ttbr + \ +@@ -92,7 +148,14 @@ + + struct apple_dart_stream_map; + ++enum dart_type { ++ DART_T8020, ++ DART_T6000, ++ DART_T8110, ++}; ++ + struct apple_dart_hw { ++ enum dart_type type; + irqreturn_t (*irq_handler)(int irq, void *dev); + int (*invalidate_tlb)(struct apple_dart_stream_map *stream_map); + +@@ -149,6 +212,7 @@ struct apple_dart { + + spinlock_t lock; + ++ u32 oas; + u32 pgsize; + u32 num_streams; + u32 supports_bypass : 1; +@@ -330,6 +394,44 @@ apple_dart_t8020_hw_stream_command(struct apple_dart_stream_map *stream_map, + return 0; + } + ++static int ++apple_dart_t8110_hw_tlb_command(struct apple_dart_stream_map *stream_map, ++ u32 command) ++{ ++ struct apple_dart *dart = stream_map->dart; ++ unsigned long flags; ++ int ret = 0; ++ int sid; ++ ++ spin_lock_irqsave(&dart->lock, flags); ++ ++ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) { ++ u32 val = FIELD_PREP(DART_T8110_TLB_CMD_OP, command) | ++ FIELD_PREP(DART_T8110_TLB_CMD_STREAM, sid); ++ writel(val, dart->regs + DART_T8110_TLB_CMD); ++ ++ ret = readl_poll_timeout_atomic( ++ dart->regs + DART_T8110_TLB_CMD, val, ++ !(val & DART_T8110_TLB_CMD_BUSY), 1, ++ DART_STREAM_COMMAND_BUSY_TIMEOUT); ++ ++ if (ret) ++ break; ++ ++ } ++ ++ spin_unlock_irqrestore(&dart->lock, flags); ++ ++ if (ret) { ++ dev_err(stream_map->dart->dev, ++ "busy bit did not clear after command %x for stream %d\n", ++ command, sid); ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int + apple_dart_t8020_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map) + { +@@ -337,6 +439,13 @@ apple_dart_t8020_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map) + stream_map, DART_T8020_STREAM_COMMAND_INVALIDATE); + } + ++static int ++apple_dart_t8110_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map) ++{ ++ return apple_dart_t8110_hw_tlb_command( ++ stream_map, DART_T8110_TLB_CMD_OP_FLUSH_SID); ++} ++ + static int apple_dart_hw_reset(struct apple_dart *dart) + { + u32 config; +@@ -363,6 +472,9 @@ static int apple_dart_hw_reset(struct apple_dart *dart) + /* clear any pending errors before the interrupt is unmasked */ + writel(readl(dart->regs + dart->hw->error), dart->regs + dart->hw->error); + ++ if (dart->hw->type == DART_T8110) ++ writel(0, dart->regs + DART_T8110_ERROR_MASK); ++ + return dart->hw->invalidate_tlb(&stream_map); + } + +@@ -479,7 +591,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain, + pgtbl_cfg = (struct io_pgtable_cfg){ + .pgsize_bitmap = dart->pgsize, + .ias = 32, +- .oas = dart->hw->oas, ++ .oas = dart->oas, + .coherent_walk = 1, + .iommu_dev = dart->dev, + }; +@@ -884,6 +996,46 @@ static irqreturn_t apple_dart_t8020_irq(int irq, void *dev) + return IRQ_HANDLED; + } + ++ ++static irqreturn_t apple_dart_t8110_irq(int irq, void *dev) ++{ ++ struct apple_dart *dart = dev; ++ const char *fault_name = NULL; ++ u32 error = readl(dart->regs + DART_T8110_ERROR); ++ u32 error_code = FIELD_GET(DART_T8110_ERROR_CODE, error); ++ u32 addr_lo = readl(dart->regs + DART_T8110_ERROR_ADDR_LO); ++ u32 addr_hi = readl(dart->regs + DART_T8110_ERROR_ADDR_HI); ++ u64 addr = addr_lo | (((u64)addr_hi) << 32); ++ u8 stream_idx = FIELD_GET(DART_T8110_ERROR_STREAM, error); ++ ++ if (!(error & DART_T8110_ERROR_FLAG)) ++ return IRQ_NONE; ++ ++ /* there should only be a single bit set but let's use == to be sure */ ++ if (error_code == DART_T8110_ERROR_READ_FAULT) ++ fault_name = "READ FAULT"; ++ else if (error_code == DART_T8110_ERROR_WRITE_FAULT) ++ fault_name = "WRITE FAULT"; ++ else if (error_code == DART_T8110_ERROR_NO_PTE) ++ fault_name = "NO PTE FOR IOVA"; ++ else if (error_code == DART_T8110_ERROR_NO_PMD) ++ fault_name = "NO PMD FOR IOVA"; ++ else if (error_code == DART_T8110_ERROR_NO_PGD) ++ fault_name = "NO PGD FOR IOVA"; ++ else if (error_code == DART_T8110_ERROR_NO_TTBR) ++ fault_name = "NO TTBR FOR IOVA"; ++ else ++ fault_name = "unknown"; ++ ++ dev_err_ratelimited( ++ dart->dev, ++ "translation fault: status:0x%x stream:%d code:0x%x (%s) at 0x%llx", ++ error, stream_idx, error_code, fault_name, addr); ++ ++ writel(error, dart->regs + DART_T8110_ERROR); ++ return IRQ_HANDLED; ++} ++ + static int apple_dart_set_bus_ops(const struct iommu_ops *ops) + { + int ret; +@@ -908,7 +1060,7 @@ static int apple_dart_set_bus_ops(const struct iommu_ops *ops) + static int apple_dart_probe(struct platform_device *pdev) + { + int ret; +- u32 dart_params[2]; ++ u32 dart_params[4]; + struct resource *res; + struct apple_dart *dart; + struct device *dev = &pdev->dev; +@@ -948,7 +1100,20 @@ static int apple_dart_probe(struct platform_device *pdev) + dart->pgsize = 1 << FIELD_GET(DART_PARAMS1_PAGE_SHIFT, dart_params[0]); + dart->supports_bypass = dart_params[1] & DART_PARAMS2_BYPASS_SUPPORT; + +- dart->num_streams = dart->hw->max_sid_count; ++ switch (dart->hw->type) { ++ case DART_T8020: ++ case DART_T6000: ++ dart->oas = dart->hw->oas; ++ dart->num_streams = dart->hw->max_sid_count; ++ break; ++ ++ case DART_T8110: ++ dart_params[2] = readl(dart->regs + DART_T8110_PARAMS3); ++ dart_params[3] = readl(dart->regs + DART_T8110_PARAMS4); ++ dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]); ++ dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]); ++ break; ++ } + + if (dart->num_streams > DART_MAX_STREAMS) { + dev_err(&pdev->dev, "Too many streams (%d > %d)\n", +@@ -1017,6 +1182,7 @@ static int apple_dart_remove(struct platform_device *pdev) + } + + static const struct apple_dart_hw apple_dart_hw_t8103 = { ++ .type = DART_T8020, + .irq_handler = apple_dart_t8020_irq, + .invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb, + .oas = 36, +@@ -1041,6 +1207,7 @@ static const struct apple_dart_hw apple_dart_hw_t8103 = { + .ttbr_count = 4, + }; + static const struct apple_dart_hw apple_dart_hw_t6000 = { ++ .type = DART_T6000, + .irq_handler = apple_dart_t8020_irq, + .invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb, + .oas = 42, +@@ -1065,6 +1232,32 @@ static const struct apple_dart_hw apple_dart_hw_t6000 = { + .ttbr_count = 4, + }; + ++static const struct apple_dart_hw apple_dart_hw_t8110 = { ++ .type = DART_T8110, ++ .irq_handler = apple_dart_t8110_irq, ++ .invalidate_tlb = apple_dart_t8110_hw_invalidate_tlb, ++ .fmt = APPLE_DART2, ++ .max_sid_count = 256, ++ ++ .enable_streams = DART_T8110_ENABLE_STREAMS, ++ .disable_streams = DART_T8110_DISABLE_STREAMS, ++ .lock = DART_T8110_PROTECT, ++ .lock_bit = DART_T8110_PROTECT_TTBR_TCR, ++ ++ .error = DART_T8110_ERROR, ++ ++ .tcr = DART_T8110_TCR, ++ .tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE, ++ .tcr_disabled = 0, ++ .tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART, ++ ++ .ttbr = DART_T8110_TTBR, ++ .ttbr_valid = DART_T8110_TTBR_VALID, ++ .ttbr_addr_off = DART_T8110_TTBR_ADDR_OFF, ++ .ttbr_shift = DART_T8110_TTBR_SHIFT, ++ .ttbr_count = 1, ++}; ++ + #ifdef CONFIG_PM_SLEEP + static int apple_dart_suspend(struct device *dev) + { +@@ -1110,6 +1303,7 @@ static const struct dev_pm_ops apple_dart_pm_ops = { + #endif + + static const struct of_device_id apple_dart_of_match[] = { ++ { .compatible = "apple,t8110-dart", .data = &apple_dart_hw_t8110 }, + { .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 }, + { .compatible = "apple,t6000-dart", .data = &apple_dart_hw_t6000 }, + {}, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0057-tty-serial-samsung_tty-Support-runtime-PM.patch b/target/linux/silicon/patches-5.19/0057-tty-serial-samsung_tty-Support-runtime-PM.patch new file mode 100644 index 000000000..4776980f4 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0057-tty-serial-samsung_tty-Support-runtime-PM.patch @@ -0,0 +1,197 @@ +From e375f9d76a88bc847d44f38157c2dba1c7e02203 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 20 Sep 2021 02:23:11 +0900 +Subject: [PATCH 057/171] tty: serial: samsung_tty: Support runtime PM + +This allows idle UART devices to be suspended using the standard +runtime-PM framework. The logic is modeled after stm32-usart. + +Signed-off-by: Hector Martin +--- + drivers/tty/serial/samsung_tty.c | 92 ++++++++++++++++++++------------ + 1 file changed, 59 insertions(+), 33 deletions(-) + +diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c +index 1afe47b62ad5..2a4ba4f3d23c 100644 +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + #include + + /* UART name and device definitions */ +@@ -1354,30 +1355,49 @@ static int apple_s5l_serial_startup(struct uart_port *port) + + /* power power management control */ + ++static int __maybe_unused s3c24xx_serial_runtime_suspend(struct device *dev) ++{ ++ struct uart_port *port = dev_get_drvdata(dev); ++ struct s3c24xx_uart_port *ourport = to_ourport(port); ++ int timeout = 10000; ++ ++ while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) ++ udelay(100); ++ ++ if (!IS_ERR(ourport->baudclk)) ++ clk_disable_unprepare(ourport->baudclk); ++ ++ clk_disable_unprepare(ourport->clk); ++ return 0; ++}; ++ ++static int __maybe_unused s3c24xx_serial_runtime_resume(struct device *dev) ++{ ++ struct uart_port *port = dev_get_drvdata(dev); ++ struct s3c24xx_uart_port *ourport = to_ourport(port); ++ ++ clk_prepare_enable(ourport->clk); ++ ++ if (!IS_ERR(ourport->baudclk)) ++ clk_prepare_enable(ourport->baudclk); ++ return 0; ++}; ++ + static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, + unsigned int old) + { + struct s3c24xx_uart_port *ourport = to_ourport(port); +- int timeout = 10000; + + ourport->pm_level = level; + + switch (level) { +- case 3: +- while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) +- udelay(100); +- +- if (!IS_ERR(ourport->baudclk)) +- clk_disable_unprepare(ourport->baudclk); +- +- clk_disable_unprepare(ourport->clk); ++ case UART_PM_STATE_OFF: ++ pm_runtime_mark_last_busy(port->dev); ++ pm_runtime_put_sync(port->dev); + break; + +- case 0: +- clk_prepare_enable(ourport->clk); +- +- if (!IS_ERR(ourport->baudclk)) +- clk_prepare_enable(ourport->baudclk); ++ case UART_PM_STATE_ON: ++ pm_runtime_get_sync(port->dev); + break; + default: + dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level); +@@ -2248,18 +2268,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) + } + } + ++ pm_runtime_get_noresume(&pdev->dev); ++ pm_runtime_set_active(&pdev->dev); ++ pm_runtime_enable(&pdev->dev); ++ + dev_dbg(&pdev->dev, "%s: adding port\n", __func__); + uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); + platform_set_drvdata(pdev, &ourport->port); + +- /* +- * Deactivate the clock enabled in s3c24xx_serial_init_port here, +- * so that a potential re-enablement through the pm-callback overlaps +- * and keeps the clock enabled in this case. +- */ +- clk_disable_unprepare(ourport->clk); +- if (!IS_ERR(ourport->baudclk)) +- clk_disable_unprepare(ourport->baudclk); ++ pm_runtime_put_sync(&pdev->dev); + + ret = s3c24xx_serial_cpufreq_register(ourport); + if (ret < 0) +@@ -2273,10 +2290,21 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) + static int s3c24xx_serial_remove(struct platform_device *dev) + { + struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); ++ struct s3c24xx_uart_port *ourport = to_ourport(port); + + if (port) { ++ pm_runtime_get_sync(&dev->dev); ++ + s3c24xx_serial_cpufreq_deregister(to_ourport(port)); + uart_remove_one_port(&s3c24xx_uart_drv, port); ++ ++ clk_disable_unprepare(ourport->clk); ++ if (!IS_ERR(ourport->baudclk)) ++ clk_disable_unprepare(ourport->baudclk); ++ ++ pm_runtime_disable(&dev->dev); ++ pm_runtime_set_suspended(&dev->dev); ++ pm_runtime_put_noidle(&dev->dev); + } + + uart_unregister_driver(&s3c24xx_uart_drv); +@@ -2285,8 +2313,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev) + } + + /* UART power management code */ +-#ifdef CONFIG_PM_SLEEP +-static int s3c24xx_serial_suspend(struct device *dev) ++ ++static int __maybe_unused s3c24xx_serial_suspend(struct device *dev) + { + struct uart_port *port = s3c24xx_dev_to_port(dev); + +@@ -2296,7 +2324,7 @@ static int s3c24xx_serial_suspend(struct device *dev) + return 0; + } + +-static int s3c24xx_serial_resume(struct device *dev) ++static int __maybe_unused s3c24xx_serial_resume(struct device *dev) + { + struct uart_port *port = s3c24xx_dev_to_port(dev); + struct s3c24xx_uart_port *ourport = to_ourport(port); +@@ -2316,7 +2344,7 @@ static int s3c24xx_serial_resume(struct device *dev) + return 0; + } + +-static int s3c24xx_serial_resume_noirq(struct device *dev) ++static int __maybe_unused s3c24xx_serial_resume_noirq(struct device *dev) + { + struct uart_port *port = s3c24xx_dev_to_port(dev); + struct s3c24xx_uart_port *ourport = to_ourport(port); +@@ -2386,16 +2414,14 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) + } + + static const struct dev_pm_ops s3c24xx_serial_pm_ops = { ++#ifdef CONFIG_PM_SLEEP + .suspend = s3c24xx_serial_suspend, + .resume = s3c24xx_serial_resume, + .resume_noirq = s3c24xx_serial_resume_noirq, ++#endif ++ SET_RUNTIME_PM_OPS(s3c24xx_serial_runtime_suspend, ++ s3c24xx_serial_runtime_resume, NULL) + }; +-#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops) +- +-#else /* !CONFIG_PM_SLEEP */ +- +-#define SERIAL_SAMSUNG_PM_OPS NULL +-#endif /* CONFIG_PM_SLEEP */ + + /* Console code */ + +@@ -2936,7 +2962,7 @@ static struct platform_driver samsung_serial_driver = { + .id_table = s3c24xx_serial_driver_ids, + .driver = { + .name = "samsung-uart", +- .pm = SERIAL_SAMSUNG_PM_OPS, ++ .pm = &s3c24xx_serial_pm_ops, + .of_match_table = of_match_ptr(s3c24xx_uart_dt_match), + }, + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0058-drm-simpledrm-Add-backlight-support.patch b/target/linux/silicon/patches-5.19/0058-drm-simpledrm-Add-backlight-support.patch new file mode 100644 index 000000000..16753131a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0058-drm-simpledrm-Add-backlight-support.patch @@ -0,0 +1,83 @@ +From 33d1d04ba47ab79e38400038347b1ef04aca10fc Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 4 Mar 2022 19:19:38 +0900 +Subject: [PATCH 058/171] drm/simpledrm: Add backlight support + +Allows devicetrees to link the simplefb node to a backlight device, +and toggles power to the backlight when the display pipe is +enabled/disabled. This is sufficient for basic DPMS style functionality +in trivial devices. + +Signed-off-by: Hector Martin +--- + drivers/gpu/drm/tiny/Kconfig | 1 + + drivers/gpu/drm/tiny/simpledrm.c | 14 ++++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig +index 627d637a1e7e..20c78bb1365d 100644 +--- a/drivers/gpu/drm/tiny/Kconfig ++++ b/drivers/gpu/drm/tiny/Kconfig +@@ -71,6 +71,7 @@ config DRM_SIMPLEDRM + depends on DRM && MMU + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER ++ select BACKLIGHT_CLASS_DEVICE + help + DRM driver for simple platform-provided framebuffers. + +diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c +index 5422363690e7..40de01efbbd9 100644 +--- a/drivers/gpu/drm/tiny/simpledrm.c ++++ b/drivers/gpu/drm/tiny/simpledrm.c +@@ -1,5 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0-only + ++#include + #include + #include + #include +@@ -225,6 +226,9 @@ struct simpledrm_device { + size_t nformats; + struct drm_connector connector; + struct drm_simple_display_pipe pipe; ++ ++ /* backlight */ ++ struct backlight_device *backlight; + }; + + static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev) +@@ -673,6 +677,9 @@ simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, + dst += drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip); + drm_fb_blit_toio(dst, sdev->pitch, sdev->format->format, vmap, fb, &src_clip); + ++ if (sdev->backlight) ++ backlight_enable(sdev->backlight); ++ + drm_dev_exit(idx); + } + +@@ -686,6 +693,9 @@ simpledrm_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) + if (!drm_dev_enter(dev, &idx)) + return; + ++ if (sdev->backlight) ++ backlight_disable(sdev->backlight); ++ + /* Clear screen to black if disabled */ + memset_io(sdev->screen_base, 0, sdev->pitch * sdev->mode.vdisplay); + +@@ -845,6 +855,10 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev) + sdev->pdev = pdev; + platform_set_drvdata(pdev, sdev); + ++ sdev->backlight = devm_of_find_backlight(&pdev->dev); ++ if (IS_ERR(sdev->backlight)) ++ sdev->backlight = NULL; ++ + ret = simpledrm_device_init_clocks(sdev); + if (ret) + return ERR_PTR(ret); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0059-of-Demote-Bad-cell-count-to-debug-message.patch b/target/linux/silicon/patches-5.19/0059-of-Demote-Bad-cell-count-to-debug-message.patch new file mode 100644 index 000000000..66c11e272 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0059-of-Demote-Bad-cell-count-to-debug-message.patch @@ -0,0 +1,29 @@ +From a9d5ced1ff2a58014dc850ece702cc194884870d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 12 Mar 2022 00:07:09 +0900 +Subject: [PATCH 059/171] of: Demote "Bad cell count" to debug message + +This happens on the SPMI bus... TODO: figure out what the right solution +is here. + +Signed-off-by: Hector Martin +--- + drivers/of/address.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/of/address.c b/drivers/of/address.c +index 94f017d808c4..68f54ec92496 100644 +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -538,7 +538,7 @@ static u64 __of_translate_address(struct device_node *dev, + pbus = of_match_bus(parent); + pbus->count_cells(dev, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { +- pr_err("Bad cell count for %pOF\n", dev); ++ pr_debug("Bad cell count for %pOF\n", dev); + break; + } + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0060-mmc-sdhci-pci-Support-external-CD-GPIO-on-all-OF-sys.patch b/target/linux/silicon/patches-5.19/0060-mmc-sdhci-pci-Support-external-CD-GPIO-on-all-OF-sys.patch new file mode 100644 index 000000000..a9889b2b2 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0060-mmc-sdhci-pci-Support-external-CD-GPIO-on-all-OF-sys.patch @@ -0,0 +1,37 @@ +From 2c80db171f88a2c7384cfefbd20ba4b2ed570e5c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 5 May 2022 01:40:31 +0900 +Subject: [PATCH 060/171] mmc: sdhci-pci: Support external CD GPIO on all OF + systems + +Allow OF systems to specify an external CD GPIO on all devices, +even if they have an internal CD feature. + +Signed-off-by: Hector Martin +--- + drivers/mmc/host/sdhci-pci-core.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c +index ed53276f6ad9..a711b4be3867 100644 +--- a/drivers/mmc/host/sdhci-pci-core.c ++++ b/drivers/mmc/host/sdhci-pci-core.c +@@ -2096,6 +2096,15 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( + dev_warn(&pdev->dev, "failed to setup card detect gpio\n"); + slot->cd_idx = -1; + } ++ } else if (is_of_node(pdev->dev.fwnode)) { ++ /* Allow all OF systems to use a CD GPIO if provided */ ++ ++ ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, ++ slot->cd_override_level, 0); ++ if (ret == -EPROBE_DEFER) ++ goto remove; ++ else if (ret == 0) ++ slot->cd_idx = 0; + } + + if (chip->fixes && chip->fixes->add_host) +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0061-mmc-sdhci-pci-Support-setting-CD-debounce-delay.patch b/target/linux/silicon/patches-5.19/0061-mmc-sdhci-pci-Support-setting-CD-debounce-delay.patch new file mode 100644 index 000000000..27773b9ce --- /dev/null +++ b/target/linux/silicon/patches-5.19/0061-mmc-sdhci-pci-Support-setting-CD-debounce-delay.patch @@ -0,0 +1,65 @@ +From 5f9f115872ee614c22a9417f68ae9100ec32b5c7 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 5 May 2022 02:27:35 +0900 +Subject: [PATCH 061/171] mmc: sdhci-pci: Support setting CD debounce delay + +Some systems (e.g. 2021 MacBook Pro 14/16") have noncompliant connectors +where CD activates before the card is fully inserted. We need debounce +delay support on these to avoid detection failures when the card isn't +inserted very quickly. + +Set the default to 200ms for all systems instead of 0. This is the +default on non-PCI platforms, and will probably help other systems too. +The naughty MacBooks will need closer to 750ms in the device tree to +be reliable... + +Signed-off-by: Hector Martin +--- + drivers/mmc/host/sdhci-pci-core.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c +index a711b4be3867..2fd4221b24aa 100644 +--- a/drivers/mmc/host/sdhci-pci-core.c ++++ b/drivers/mmc/host/sdhci-pci-core.c +@@ -2015,6 +2015,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( + struct sdhci_host *host; + int ret, bar = first_bar + slotno; + size_t priv_size = chip->fixes ? chip->fixes->priv_size : 0; ++ u32 cd_debounce_delay_ms; + + if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); +@@ -2081,6 +2082,10 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( + if (host->mmc->caps & MMC_CAP_CD_WAKE) + device_init_wakeup(&pdev->dev, true); + ++ if (device_property_read_u32(&pdev->dev, "cd-debounce-delay-ms", ++ &cd_debounce_delay_ms)) ++ cd_debounce_delay_ms = 200; ++ + if (slot->cd_idx >= 0) { + ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, + slot->cd_override_level, 0); +@@ -2088,7 +2093,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( + ret = mmc_gpiod_request_cd(host->mmc, NULL, + slot->cd_idx, + slot->cd_override_level, +- 0); ++ cd_debounce_delay_ms * 1000); + if (ret == -EPROBE_DEFER) + goto remove; + +@@ -2100,7 +2105,8 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( + /* Allow all OF systems to use a CD GPIO if provided */ + + ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, +- slot->cd_override_level, 0); ++ slot->cd_override_level, ++ cd_debounce_delay_ms * 1000); + if (ret == -EPROBE_DEFER) + goto remove; + else if (ret == 0) +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0062-net-usb-ax88179_178a-Bind-only-to-vendor-specific-in.patch b/target/linux/silicon/patches-5.19/0062-net-usb-ax88179_178a-Bind-only-to-vendor-specific-in.patch new file mode 100644 index 000000000..f59622e2a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0062-net-usb-ax88179_178a-Bind-only-to-vendor-specific-in.patch @@ -0,0 +1,106 @@ +From f60e434c0766aaf5db2d775bbcba49d896e1f518 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 2 May 2022 19:46:47 +0900 +Subject: [PATCH 062/171] net: usb: ax88179_178a: Bind only to vendor-specific + interface + +The Anker PowerExpand USB-C to Gigabit Ethernet adapter uses this +chipset, but exposes CDC Ethernet configurations as well as the +vendor specific one. This driver ends up binding first to both CDC +interfaces, tries to instantiate two Ethernet interfaces talking to +the same device, and the result is a nice fireworks show. + +Change all the ID matches to specifically match the vendor-specific +interface. By default the device comes up in CDC mode and is bound by +that driver (which works fine); users may switch it to the vendor +interface using sysfs to set bConfigurationValue, at which point the +device actually goes through a reconnect cycle and comes back as a +vendor specific only device, and then this driver binds and works too. + +The affected device uses VID/PID 0b95:1790, but we might as well change +all of them for good measure, since there is no good reason for this +driver to bind to standard CDC Ethernet interfaces. + +v3: Added VID/PID info to commit message + +Signed-off-by: Hector Martin +--- + drivers/net/usb/ax88179_178a.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c +index ac2d400d1d6c..aeb0294385ed 100644 +--- a/drivers/net/usb/ax88179_178a.c ++++ b/drivers/net/usb/ax88179_178a.c +@@ -1965,55 +1965,55 @@ static const struct driver_info at_umc2000sp_info = { + static const struct usb_device_id products[] = { + { + /* ASIX AX88179 10/100/1000 */ +- USB_DEVICE(0x0b95, 0x1790), ++ USB_DEVICE_AND_INTERFACE_INFO(0x0b95, 0x1790, 0xff, 0xff, 0), + .driver_info = (unsigned long)&ax88179_info, + }, { + /* ASIX AX88178A 10/100/1000 */ +- USB_DEVICE(0x0b95, 0x178a), ++ USB_DEVICE_AND_INTERFACE_INFO(0x0b95, 0x178a, 0xff, 0xff, 0), + .driver_info = (unsigned long)&ax88178a_info, + }, { + /* Cypress GX3 SuperSpeed to Gigabit Ethernet Bridge Controller */ +- USB_DEVICE(0x04b4, 0x3610), ++ USB_DEVICE_AND_INTERFACE_INFO(0x04b4, 0x3610, 0xff, 0xff, 0), + .driver_info = (unsigned long)&cypress_GX3_info, + }, { + /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */ +- USB_DEVICE(0x2001, 0x4a00), ++ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x4a00, 0xff, 0xff, 0), + .driver_info = (unsigned long)&dlink_dub1312_info, + }, { + /* Sitecom USB 3.0 to Gigabit Adapter */ +- USB_DEVICE(0x0df6, 0x0072), ++ USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0072, 0xff, 0xff, 0), + .driver_info = (unsigned long)&sitecom_info, + }, { + /* Samsung USB Ethernet Adapter */ +- USB_DEVICE(0x04e8, 0xa100), ++ USB_DEVICE_AND_INTERFACE_INFO(0x04e8, 0xa100, 0xff, 0xff, 0), + .driver_info = (unsigned long)&samsung_info, + }, { + /* Lenovo OneLinkDock Gigabit LAN */ +- USB_DEVICE(0x17ef, 0x304b), ++ USB_DEVICE_AND_INTERFACE_INFO(0x17ef, 0x304b, 0xff, 0xff, 0), + .driver_info = (unsigned long)&lenovo_info, + }, { + /* Belkin B2B128 USB 3.0 Hub + Gigabit Ethernet Adapter */ +- USB_DEVICE(0x050d, 0x0128), ++ USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x0128, 0xff, 0xff, 0), + .driver_info = (unsigned long)&belkin_info, + }, { + /* Toshiba USB 3.0 GBit Ethernet Adapter */ +- USB_DEVICE(0x0930, 0x0a13), ++ USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x0a13, 0xff, 0xff, 0), + .driver_info = (unsigned long)&toshiba_info, + }, { + /* Magic Control Technology U3-A9003 USB 3.0 Gigabit Ethernet Adapter */ +- USB_DEVICE(0x0711, 0x0179), ++ USB_DEVICE_AND_INTERFACE_INFO(0x0711, 0x0179, 0xff, 0xff, 0), + .driver_info = (unsigned long)&mct_info, + }, { + /* Allied Telesis AT-UMC2000 USB 3.0/USB 3.1 Gen 1 to Gigabit Ethernet Adapter */ +- USB_DEVICE(0x07c9, 0x000e), ++ USB_DEVICE_AND_INTERFACE_INFO(0x07c9, 0x000e, 0xff, 0xff, 0), + .driver_info = (unsigned long)&at_umc2000_info, + }, { + /* Allied Telesis AT-UMC200 USB 3.0/USB 3.1 Gen 1 to Fast Ethernet Adapter */ +- USB_DEVICE(0x07c9, 0x000f), ++ USB_DEVICE_AND_INTERFACE_INFO(0x07c9, 0x000f, 0xff, 0xff, 0), + .driver_info = (unsigned long)&at_umc200_info, + }, { + /* Allied Telesis AT-UMC2000/SP USB 3.0/USB 3.1 Gen 1 to Gigabit Ethernet Adapter */ +- USB_DEVICE(0x07c9, 0x0010), ++ USB_DEVICE_AND_INTERFACE_INFO(0x07c9, 0x0010, 0xff, 0xff, 0), + .driver_info = (unsigned long)&at_umc2000sp_info, + }, + { }, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0063-dt-bindings-usb-Add-Apple-dwc3-bindings.patch b/target/linux/silicon/patches-5.19/0063-dt-bindings-usb-Add-Apple-dwc3-bindings.patch new file mode 100644 index 000000000..a27985157 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0063-dt-bindings-usb-Add-Apple-dwc3-bindings.patch @@ -0,0 +1,89 @@ +From 834ab8867f3537c2a1c40853309aeb63401f7b34 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Sun, 7 Nov 2021 11:21:19 +0100 +Subject: [PATCH 063/171] dt-bindings: usb: Add Apple dwc3 bindings + +Apple Silicon SoCs such as the M1 have multiple USB controllers based on +the Synopsys DesignWare USB3 controller. +References to the ATC PHY required for SuperSpeed are left out for now +until support has been upstreamed as well. + +Signed-off-by: Sven Peter +--- + .../devicetree/bindings/usb/apple,dwc3.yaml | 64 +++++++++++++++++++ + 1 file changed, 64 insertions(+) + create mode 100644 Documentation/devicetree/bindings/usb/apple,dwc3.yaml + +diff --git a/Documentation/devicetree/bindings/usb/apple,dwc3.yaml b/Documentation/devicetree/bindings/usb/apple,dwc3.yaml +new file mode 100644 +index 000000000000..fb3b3489e6b2 +--- /dev/null ++++ b/Documentation/devicetree/bindings/usb/apple,dwc3.yaml +@@ -0,0 +1,64 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/usb/apple,dwc3.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Apple Silicon DWC3 USB controller ++ ++maintainers: ++ - Sven Peter ++ ++description: ++ On Apple Silicon SoCs such as the M1 each Type-C port has a corresponding ++ USB controller based on the Synopsys DesignWare USB3 controller. ++ ++ The common content of this binding is defined in snps,dwc3.yaml. ++ ++allOf: ++ - $ref: snps,dwc3.yaml# ++ ++select: ++ properties: ++ compatible: ++ contains: ++ const: apple,dwc3 ++ required: ++ - compatible ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - apple,t8103-dwc3 ++ - apple,t6000-dwc3 ++ - const: apple,dwc3 ++ - const: snps,dwc3 ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++unevaluatedProperties: false ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ ++examples: ++ - | ++ #include ++ #include ++ ++ usb@82280000 { ++ compatible = "apple,t8103-dwc3", "apple,dwc3", "snps,dwc3"; ++ reg = <0x82280000 0x10000>; ++ interrupts = ; ++ ++ dr_mode = "otg"; ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++ }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0064-usb-dwc3-Add-role-switch-reset-quirk-for-Apple-DWC3.patch b/target/linux/silicon/patches-5.19/0064-usb-dwc3-Add-role-switch-reset-quirk-for-Apple-DWC3.patch new file mode 100644 index 000000000..63aad9454 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0064-usb-dwc3-Add-role-switch-reset-quirk-for-Apple-DWC3.patch @@ -0,0 +1,172 @@ +From bda2c5ab3f028f25bf7d0e8196ee1dee38973153 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Sun, 7 Nov 2021 11:21:20 +0100 +Subject: [PATCH 064/171] usb: dwc3: Add role switch reset quirk for Apple DWC3 + +As mad as it sounds, the dwc3 controller present on the Apple M1 must be +reset and reinitialized whenever a device is unplugged from the root port. +The only reliable unplug/plug notification available comes from the USB +PD controller through the role-switch infrastructure. + +This is required for at least two reasons: + + - The USB2 D+/D- lines are connected through a stateful eUSB2 repeater + which in turn is controlled by a variant of the TI TPS6598x USB PD + chip. When the USB PD controller detects a hotplug event it resets + the eUSB2 repeater. Afterwards, no new device is recognized before + the DWC3 core and PHY are reset as well. + + - It's possible to completely break the dwc3 controller by switching + it to device mode and unplugging the cable at just the wrong time. + Even a CORESOFTRESET is not enough to allow new devices again. + The only workaround is to trigger a hard reset of the entire + dwc3 core. + +Signed-off-by: Sven Peter +--- + drivers/usb/dwc3/core.c | 41 ++++++++++++++++++++++++++++++++++++++--- + drivers/usb/dwc3/core.h | 6 ++++++ + drivers/usb/dwc3/drd.c | 7 +++++++ + 3 files changed, 51 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 573421984948..b4c58deccabb 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -116,6 +116,9 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) + dwc->current_dr_role = mode; + } + ++static void dwc3_core_exit(struct dwc3 *dwc); ++static int dwc3_core_init_for_resume(struct dwc3 *dwc); ++ + static void __dwc3_set_mode(struct work_struct *work) + { + struct dwc3 *dwc = work_to_dwc(work); +@@ -130,10 +133,11 @@ static void __dwc3_set_mode(struct work_struct *work) + if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG) + dwc3_otg_update(dwc, 0); + +- if (!dwc->desired_dr_role) ++ if (!dwc->desired_dr_role && !dwc->role_switch_reset_quirk) + goto out; + +- if (dwc->desired_dr_role == dwc->current_dr_role) ++ if (dwc->desired_dr_role == dwc->current_dr_role && ++ !dwc->role_switch_reset_quirk) + goto out; + + if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) +@@ -158,6 +162,34 @@ static void __dwc3_set_mode(struct work_struct *work) + break; + } + ++ if (dwc->role_switch_reset_quirk) { ++ if (dwc->current_dr_role) { ++ dwc->current_dr_role = 0; ++ dwc3_core_exit(dwc); ++ } ++ ++ if (dwc->desired_dr_role) { ++ /* ++ * the first call to __dwc3_set_mode comes from ++ * dwc3_drd_init. In that case dwc3_core_init has been ++ * called but dwc->current_dr_role is zero such that ++ * we must not reinitialize the core again here. ++ */ ++ if (dwc->role_switch_reset_quirk_initialized) { ++ ret = dwc3_core_init_for_resume(dwc); ++ if (ret) { ++ dev_err(dwc->dev, ++ "failed to reinitialize core\n"); ++ goto out; ++ } ++ } ++ ++ dwc->role_switch_reset_quirk_initialized = 1; ++ } else { ++ goto out; ++ } ++ } ++ + /* For DRD host or device mode only */ + if (dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) { + reg = dwc3_readl(dwc->regs, DWC3_GCTL); +@@ -1764,6 +1796,9 @@ static int dwc3_probe(struct platform_device *pdev) + return dev_err_probe(dev, PTR_ERR(dwc->susp_clk), + "could not get suspend clock\n"); + } ++ ++ if (of_device_is_compatible(dev->of_node, "apple,dwc3")) ++ dwc->role_switch_reset_quirk = true; + } + + ret = reset_control_deassert(dwc->reset); +@@ -1900,7 +1935,6 @@ static int dwc3_remove(struct platform_device *pdev) + return 0; + } + +-#ifdef CONFIG_PM + static int dwc3_core_init_for_resume(struct dwc3 *dwc) + { + int ret; +@@ -1927,6 +1961,7 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc) + return ret; + } + ++#ifdef CONFIG_PM + static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) + { + unsigned long flags; +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index 81c486b3941c..ee0225ce2234 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -1103,6 +1103,9 @@ struct dwc3_scratchpad_array { + * 3 - Reserved + * @dis_metastability_quirk: set to disable metastability quirk. + * @dis_split_quirk: set to disable split boundary. ++ * @role_switch_reset_quirk: set to force reinitialization after any role switch ++ * @role_switch_reset_quirk_initialized: set to true after the first role switch ++ * which is triggered from dwc3_drd_init directly + * @imod_interval: set the interrupt moderation interval in 250ns + * increments or 0 to disable. + * @max_cfg_eps: current max number of IN eps used across all USB configs. +@@ -1318,6 +1321,9 @@ struct dwc3 { + unsigned dis_split_quirk:1; + unsigned async_callbacks:1; + ++ unsigned role_switch_reset_quirk:1; ++ unsigned role_switch_reset_quirk_initialized:1; ++ + u16 imod_interval; + + int max_cfg_eps; +diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c +index 039bf241769a..4579505cac1f 100644 +--- a/drivers/usb/dwc3/drd.c ++++ b/drivers/usb/dwc3/drd.c +@@ -461,6 +461,9 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, + break; + } + ++ if (dwc->role_switch_reset_quirk && role == USB_ROLE_NONE) ++ mode = 0; ++ + dwc3_set_mode(dwc, mode); + return 0; + } +@@ -489,6 +492,10 @@ static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw) + role = USB_ROLE_DEVICE; + break; + } ++ ++ if (dwc->role_switch_reset_quirk && !dwc->current_dr_role) ++ role = USB_ROLE_NONE; ++ + spin_unlock_irqrestore(&dwc->lock, flags); + return role; + } +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0065-apple-nvme-defer-cache-flushes-by-a-specified-amount.patch b/target/linux/silicon/patches-5.19/0065-apple-nvme-defer-cache-flushes-by-a-specified-amount.patch new file mode 100644 index 000000000..1290c64e4 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0065-apple-nvme-defer-cache-flushes-by-a-specified-amount.patch @@ -0,0 +1,141 @@ +From 6c8c3ae8ce7813a315f4729865f99d0d318f678a Mon Sep 17 00:00:00 2001 +From: Jens Axboe +Date: Wed, 16 Feb 2022 12:17:58 -0700 +Subject: [PATCH 065/171] apple-nvme: defer cache flushes by a specified amount + +Cache flushes on the M1 nvme are really slow, taking 17-18 msec to +complete. This can slow down workloads considerably, pure random writes +end up being bound by the flush latency and hence run at 55-60 IOPS. + +Add a deferred flush work around to provide better performance, at a +minimal risk. By default, flushes are delayed at most 1 second, but this +is configurable. + +With this work-around, a pure random write workload runs at ~12K IOPS +rather than 56 IOPS. + +Signed-off-by: Jens Axboe +--- + drivers/nvme/host/apple.c | 69 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 69 insertions(+) + +diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c +index d702d7d60235..46294f99a1b0 100644 +--- a/drivers/nvme/host/apple.c ++++ b/drivers/nvme/host/apple.c +@@ -195,8 +195,20 @@ struct apple_nvme { + + int irq; + spinlock_t lock; ++ ++ /* ++ * Delayed cache flush handling state ++ */ ++ struct nvme_ns *flush_ns; ++ unsigned long flush_interval; ++ unsigned long last_flush; ++ struct delayed_work flush_dwork; + }; + ++unsigned int flush_interval = 1000; ++module_param(flush_interval, uint, 0644); ++MODULE_PARM_DESC(flush_interval, "Grace period in msecs between flushes"); ++ + static_assert(sizeof(struct nvme_command) == 64); + static_assert(sizeof(struct apple_nvmmu_tcb) == 128); + +@@ -729,6 +741,26 @@ static int apple_nvme_remove_sq(struct apple_nvme *anv) + return nvme_submit_sync_cmd(anv->ctrl.admin_q, &c, NULL, 0); + } + ++static bool apple_nvme_delayed_flush(struct apple_nvme *anv, struct nvme_ns *ns, ++ struct request *req) ++{ ++ if (!anv->flush_interval || req_op(req) != REQ_OP_FLUSH) ++ return false; ++ if (delayed_work_pending(&anv->flush_dwork)) ++ return true; ++ if (time_before(jiffies, anv->last_flush + anv->flush_interval)) { ++ kblockd_mod_delayed_work_on(WORK_CPU_UNBOUND, &anv->flush_dwork, ++ anv->flush_interval); ++ if (WARN_ON_ONCE(anv->flush_ns && anv->flush_ns != ns)) ++ goto out; ++ anv->flush_ns = ns; ++ return true; ++ } ++out: ++ anv->last_flush = jiffies; ++ return false; ++} ++ + static blk_status_t apple_nvme_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) + { +@@ -764,6 +796,12 @@ static blk_status_t apple_nvme_queue_rq(struct blk_mq_hw_ctx *hctx, + } + + blk_mq_start_request(req); ++ ++ if (apple_nvme_delayed_flush(anv, ns, req)) { ++ blk_mq_complete_request(req); ++ return BLK_STS_OK; ++ } ++ + apple_nvme_submit_cmd(q, cmnd); + return BLK_STS_OK; + +@@ -1366,6 +1404,28 @@ static int apple_nvme_attach_genpd(struct apple_nvme *anv) + return 0; + } + ++static void apple_nvme_flush_work(struct work_struct *work) ++{ ++ struct nvme_command c = { }; ++ struct apple_nvme *anv; ++ struct nvme_ns *ns; ++ int err; ++ ++ anv = container_of(work, struct apple_nvme, flush_dwork.work); ++ ns = anv->flush_ns; ++ if (WARN_ON_ONCE(!ns)) ++ return; ++ ++ c.common.opcode = nvme_cmd_flush; ++ c.common.nsid = cpu_to_le32(anv->flush_ns->head->ns_id); ++ err = nvme_submit_sync_cmd(ns->queue, &c, NULL, 0); ++ if (err) { ++ dev_err(anv->dev, "Deferred flush failed: %d\n", err); ++ } else { ++ anv->last_flush = jiffies; ++ } ++} ++ + static int apple_nvme_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -1508,6 +1568,14 @@ static int apple_nvme_probe(struct platform_device *pdev) + goto put_dev; + } + ++ if (flush_interval) { ++ anv->flush_interval = msecs_to_jiffies(flush_interval); ++ anv->flush_ns = NULL; ++ anv->last_flush = jiffies - anv->flush_interval; ++ } ++ ++ INIT_DELAYED_WORK(&anv->flush_dwork, apple_nvme_flush_work); ++ + nvme_reset_ctrl(&anv->ctrl); + async_schedule(apple_nvme_async_probe, anv); + +@@ -1541,6 +1609,7 @@ static void apple_nvme_shutdown(struct platform_device *pdev) + { + struct apple_nvme *anv = platform_get_drvdata(pdev); + ++ flush_delayed_work(&anv->flush_dwork); + apple_nvme_disable(anv, true); + if (apple_rtkit_is_running(anv->rtk)) + apple_rtkit_shutdown(anv->rtk); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0066-apple-nvme-Release-power-domains-when-probe-fails.patch b/target/linux/silicon/patches-5.19/0066-apple-nvme-Release-power-domains-when-probe-fails.patch new file mode 100644 index 000000000..a3a561655 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0066-apple-nvme-Release-power-domains-when-probe-fails.patch @@ -0,0 +1,25 @@ +From 17290bf07058d3b52c3a750be73831827af3f98d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 27 Jun 2022 21:47:43 +0900 +Subject: [PATCH 066/171] apple-nvme: Release power domains when probe fails + +Signed-off-by: Hector Martin +--- + drivers/nvme/host/apple.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c +index 46294f99a1b0..67cef4dda24c 100644 +--- a/drivers/nvme/host/apple.c ++++ b/drivers/nvme/host/apple.c +@@ -1582,6 +1582,7 @@ static int apple_nvme_probe(struct platform_device *pdev) + return 0; + + put_dev: ++ apple_nvme_detach_genpd(anv); + put_device(anv->dev); + return ret; + } +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0067-MAINTAINERS-Add-apple-spi-driver-binding-files.patch b/target/linux/silicon/patches-5.19/0067-MAINTAINERS-Add-apple-spi-driver-binding-files.patch new file mode 100644 index 000000000..6e9fd40f6 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0067-MAINTAINERS-Add-apple-spi-driver-binding-files.patch @@ -0,0 +1,39 @@ +From ef2e86f869f55da922fcb8235cd32ea78fe3e2b7 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 12 Dec 2021 12:28:41 +0900 +Subject: [PATCH 067/171] MAINTAINERS: Add apple-spi driver & binding files + +This Apple SPI controller is present on Apple ARM SoCs (t8103/t6000). + +Splitting this change from the binding/driver commits to avoid merge +conflicts with other things touching this section, as usual. + +Signed-off-by: Hector Martin +--- + MAINTAINERS | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 64379c699903..629c1a177d3f 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1843,6 +1843,8 @@ F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml + F: Documentation/devicetree/bindings/pci/apple,pcie.yaml + F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml + F: Documentation/devicetree/bindings/power/apple* ++F: Documentation/devicetree/bindings/spi/apple,spi.yaml ++F: Documentation/devicetree/bindings/usb/apple,dwc3.yaml + F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml + F: arch/arm64/boot/dts/apple/ + F: drivers/clk/clk-apple-nco.c +@@ -1855,6 +1857,7 @@ F: drivers/nvme/host/apple.c + F: drivers/nvmem/apple-efuses.c + F: drivers/pinctrl/pinctrl-apple-gpio.c + F: drivers/soc/apple/* ++F: drivers/spi/spi-apple.c + F: drivers/watchdog/apple_wdt.c + F: include/dt-bindings/interrupt-controller/apple-aic.h + F: include/dt-bindings/pinctrl/apple.h +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0068-dt-bindings-spi-apple-spi-Add-binding-for-Apple-SPI-.patch b/target/linux/silicon/patches-5.19/0068-dt-bindings-spi-apple-spi-Add-binding-for-Apple-SPI-.patch new file mode 100644 index 000000000..cfb6fa3cc --- /dev/null +++ b/target/linux/silicon/patches-5.19/0068-dt-bindings-spi-apple-spi-Add-binding-for-Apple-SPI-.patch @@ -0,0 +1,88 @@ +From c26ea602ff1a0f7d01421320ed5bea2f611f73cd Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 12 Dec 2021 11:46:33 +0900 +Subject: [PATCH 068/171] dt-bindings: spi: apple,spi: Add binding for Apple + SPI controllers + +The Apple SPI controller is present in SoCs such as the M1 (t8103) and +M1 Pro/Max (t600x). This controller uses one IRQ and one clock, and +doesn't need any special properties, so the binding is trivial. + +Signed-off-by: Hector Martin +--- + .../devicetree/bindings/spi/apple,spi.yaml | 63 +++++++++++++++++++ + 1 file changed, 63 insertions(+) + create mode 100644 Documentation/devicetree/bindings/spi/apple,spi.yaml + +diff --git a/Documentation/devicetree/bindings/spi/apple,spi.yaml b/Documentation/devicetree/bindings/spi/apple,spi.yaml +new file mode 100644 +index 000000000000..bcbdc8943e92 +--- /dev/null ++++ b/Documentation/devicetree/bindings/spi/apple,spi.yaml +@@ -0,0 +1,63 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/spi/apple,spi.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Apple ARM SoC SPI controller ++ ++allOf: ++ - $ref: "spi-controller.yaml#" ++ ++maintainers: ++ - Hector Martin ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - apple,t8103-spi ++ - apple,t6000-spi ++ - const: apple,spi ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ power-domains: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - interrupts ++ - '#address-cells' ++ - '#size-cells' ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ ++ soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ spi: spi@39b104000 { ++ compatible = "apple,t6000-spi", "apple,spi"; ++ reg = <0x3 0x9b104000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk>; ++ }; ++ }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0069-spi-apple-Add-driver-for-Apple-SPI-controller.patch b/target/linux/silicon/patches-5.19/0069-spi-apple-Add-driver-for-Apple-SPI-controller.patch new file mode 100644 index 000000000..e83565fbc --- /dev/null +++ b/target/linux/silicon/patches-5.19/0069-spi-apple-Add-driver-for-Apple-SPI-controller.patch @@ -0,0 +1,618 @@ +From 90521a1e8c3ebf5c2ee27d2e3f62bb81cf28e23f Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 9 Dec 2021 21:55:49 +0900 +Subject: [PATCH 069/171] spi: apple: Add driver for Apple SPI controller + +This SPI controller is present in Apple SoCs such as the M1 (t8103) and +M1 Pro/Max (t600x). It is a relatively straightforward design with two +16-entry FIFOs, arbitrary transfer sizes (up to 2**32 - 1) and fully +configurable word size up to 32 bits. It supports one hardware CS line +which can also be driven via the pinctrl/GPIO driver instead, if +desired. TX and RX can be independently enabled. + +There are a surprising number of knobs for tweaking details of the +transfer, most of which we do not use right now. Hardware CS control +is available, but we haven't found a way to make it stay low across +multiple logical transfers, so we just use software CS control for now. + +There is also a shared DMA offload coprocessor that can be used to handle +larger transfers without requiring an IRQ every 8-16 words, but that +feature depends on a bunch of scaffolding that isn't ready to be +upstreamed yet, so leave it for later. + +The hardware shares some register bit definitions with spi-s3c24xx which +suggests it has a shared legacy with Samsung SoCs, but it is too +different to warrant sharing a driver. + +Signed-off-by: Hector Martin +--- + drivers/spi/Kconfig | 8 + + drivers/spi/Makefile | 1 + + drivers/spi/spi-apple.c | 544 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 553 insertions(+) + create mode 100644 drivers/spi/spi-apple.c + +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 3b1044ebc400..863e215a5127 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -79,6 +79,14 @@ config SPI_ALTERA_DFL + Altera SPI master controller. The SPI master is connected + to a SPI slave to Avalon bridge in a Intel MAX BMC. + ++config SPI_APPLE ++ tristate "Apple SoC SPI Controller platform driver" ++ depends on ARCH_APPLE || COMPILE_TEST ++ help ++ This enables support for the SPI controller present on ++ many Apple SoCs, including the t8103 (M1) and t600x ++ (M1 Pro/Max). ++ + config SPI_AR934X + tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver" + depends on ATH79 || COMPILE_TEST +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index 0f44eb6083a5..f86ba8634f77 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o + obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o + obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o + obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o ++obj-$(CONFIG_SPI_APPLE) += spi-apple.o + obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o + obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o + obj-$(CONFIG_SPI_ASPEED_SMC) += spi-aspeed-smc.o +diff --git a/drivers/spi/spi-apple.c b/drivers/spi/spi-apple.c +new file mode 100644 +index 000000000000..c483ad3f69ef +--- /dev/null ++++ b/drivers/spi/spi-apple.c +@@ -0,0 +1,544 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Apple SoC SPI device driver ++ * ++ * Copyright The Asahi Linux Contributors ++ * ++ * Based on spi-sifive.c, Copyright 2018 SiFive, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define APPLE_SPI_CTRL 0x000 ++#define APPLE_SPI_CTRL_RUN BIT(0) ++#define APPLE_SPI_CTRL_TX_RESET BIT(2) ++#define APPLE_SPI_CTRL_RX_RESET BIT(3) ++ ++#define APPLE_SPI_CFG 0x004 ++#define APPLE_SPI_CFG_CPHA BIT(1) ++#define APPLE_SPI_CFG_CPOL BIT(2) ++#define APPLE_SPI_CFG_MODE GENMASK(6, 5) ++#define APPLE_SPI_CFG_MODE_POLLED 0 ++#define APPLE_SPI_CFG_MODE_IRQ 1 ++#define APPLE_SPI_CFG_MODE_DMA 2 ++#define APPLE_SPI_CFG_IE_RXCOMPLETE BIT(7) ++#define APPLE_SPI_CFG_IE_TXRXTHRESH BIT(8) ++#define APPLE_SPI_CFG_LSB_FIRST BIT(13) ++#define APPLE_SPI_CFG_WORD_SIZE GENMASK(16, 15) ++#define APPLE_SPI_CFG_WORD_SIZE_8B 0 ++#define APPLE_SPI_CFG_WORD_SIZE_16B 1 ++#define APPLE_SPI_CFG_WORD_SIZE_32B 2 ++#define APPLE_SPI_CFG_FIFO_THRESH GENMASK(18, 17) ++#define APPLE_SPI_CFG_FIFO_THRESH_8B 0 ++#define APPLE_SPI_CFG_FIFO_THRESH_4B 1 ++#define APPLE_SPI_CFG_FIFO_THRESH_1B 2 ++#define APPLE_SPI_CFG_IE_TXCOMPLETE BIT(21) ++ ++#define APPLE_SPI_STATUS 0x008 ++#define APPLE_SPI_STATUS_RXCOMPLETE BIT(0) ++#define APPLE_SPI_STATUS_TXRXTHRESH BIT(1) ++#define APPLE_SPI_STATUS_TXCOMPLETE BIT(2) ++ ++#define APPLE_SPI_PIN 0x00c ++#define APPLE_SPI_PIN_KEEP_MOSI BIT(0) ++#define APPLE_SPI_PIN_CS BIT(1) ++ ++#define APPLE_SPI_TXDATA 0x010 ++#define APPLE_SPI_RXDATA 0x020 ++#define APPLE_SPI_CLKDIV 0x030 ++#define APPLE_SPI_CLKDIV_MAX 0x7ff ++#define APPLE_SPI_RXCNT 0x034 ++#define APPLE_SPI_WORD_DELAY 0x038 ++#define APPLE_SPI_TXCNT 0x04c ++ ++#define APPLE_SPI_FIFOSTAT 0x10c ++#define APPLE_SPI_FIFOSTAT_TXFULL BIT(4) ++#define APPLE_SPI_FIFOSTAT_LEVEL_TX GENMASK(15, 8) ++#define APPLE_SPI_FIFOSTAT_RXEMPTY BIT(20) ++#define APPLE_SPI_FIFOSTAT_LEVEL_RX GENMASK(31, 24) ++ ++#define APPLE_SPI_IE_XFER 0x130 ++#define APPLE_SPI_IF_XFER 0x134 ++#define APPLE_SPI_XFER_RXCOMPLETE BIT(0) ++#define APPLE_SPI_XFER_TXCOMPLETE BIT(1) ++ ++#define APPLE_SPI_IE_FIFO 0x138 ++#define APPLE_SPI_IF_FIFO 0x13c ++#define APPLE_SPI_FIFO_RXTHRESH BIT(4) ++#define APPLE_SPI_FIFO_TXTHRESH BIT(5) ++#define APPLE_SPI_FIFO_RXFULL BIT(8) ++#define APPLE_SPI_FIFO_TXEMPTY BIT(9) ++#define APPLE_SPI_FIFO_RXUNDERRUN BIT(16) ++#define APPLE_SPI_FIFO_TXOVERFLOW BIT(17) ++ ++#define APPLE_SPI_SHIFTCFG 0x150 ++#define APPLE_SPI_SHIFTCFG_CLK_ENABLE BIT(0) ++#define APPLE_SPI_SHIFTCFG_CS_ENABLE BIT(1) ++#define APPLE_SPI_SHIFTCFG_AND_CLK_DATA BIT(8) ++#define APPLE_SPI_SHIFTCFG_CS_AS_DATA BIT(9) ++#define APPLE_SPI_SHIFTCFG_TX_ENABLE BIT(10) ++#define APPLE_SPI_SHIFTCFG_RX_ENABLE BIT(11) ++#define APPLE_SPI_SHIFTCFG_BITS GENMASK(21, 16) ++#define APPLE_SPI_SHIFTCFG_OVERRIDE_CS BIT(24) ++ ++#define APPLE_SPI_PINCFG 0x154 ++#define APPLE_SPI_PINCFG_KEEP_CLK BIT(0) ++#define APPLE_SPI_PINCFG_KEEP_CS BIT(1) ++#define APPLE_SPI_PINCFG_KEEP_MOSI BIT(2) ++#define APPLE_SPI_PINCFG_CLK_IDLE_VAL BIT(8) ++#define APPLE_SPI_PINCFG_CS_IDLE_VAL BIT(9) ++#define APPLE_SPI_PINCFG_MOSI_IDLE_VAL BIT(10) ++ ++#define APPLE_SPI_DELAY_PRE 0x160 ++#define APPLE_SPI_DELAY_POST 0x168 ++#define APPLE_SPI_DELAY_ENABLE BIT(0) ++#define APPLE_SPI_DELAY_NO_INTERBYTE BIT(1) ++#define APPLE_SPI_DELAY_SET_SCK BIT(4) ++#define APPLE_SPI_DELAY_SET_MOSI BIT(6) ++#define APPLE_SPI_DELAY_SCK_VAL BIT(8) ++#define APPLE_SPI_DELAY_MOSI_VAL BIT(12) ++ ++#define APPLE_SPI_FIFO_DEPTH 16 ++ ++/* ++ * The slowest refclock available is 24MHz, the highest divider is 0x7ff, ++ * the largest word size is 32 bits, the FIFO depth is 16, the maximum ++ * intra-word delay is 0xffff refclocks. So the maximum time a transfer ++ * cycle can take is: ++ * ++ * (0x7ff * 32 + 0xffff) * 16 / 24e6 Hz ~= 87ms ++ * ++ * Double it and round it up to 200ms for good measure. ++ */ ++#define APPLE_SPI_TIMEOUT_MS 200 ++ ++struct apple_spi { ++ void __iomem *regs; /* MMIO register address */ ++ struct clk *clk; /* bus clock */ ++ struct completion done; /* wake-up from interrupt */ ++}; ++ ++static inline void reg_write(struct apple_spi *spi, int offset, u32 value) ++{ ++ writel_relaxed(value, spi->regs + offset); ++} ++ ++static inline u32 reg_read(struct apple_spi *spi, int offset) ++{ ++ return readl_relaxed(spi->regs + offset); ++} ++ ++static inline void reg_mask(struct apple_spi *spi, int offset, u32 clear, u32 set) ++{ ++ u32 val = reg_read(spi, offset); ++ ++ val &= ~clear; ++ val |= set; ++ reg_write(spi, offset, val); ++} ++ ++static void apple_spi_init(struct apple_spi *spi) ++{ ++ /* Set CS high (inactive) and disable override and auto-CS */ ++ reg_write(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS); ++ reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_OVERRIDE_CS, 0); ++ reg_mask(spi, APPLE_SPI_PINCFG, APPLE_SPI_PINCFG_CS_IDLE_VAL, APPLE_SPI_PINCFG_KEEP_CS); ++ ++ /* Reset FIFOs */ ++ reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET); ++ ++ /* Configure defaults */ ++ reg_write(spi, APPLE_SPI_CFG, ++ FIELD_PREP(APPLE_SPI_CFG_FIFO_THRESH, APPLE_SPI_CFG_FIFO_THRESH_8B) | ++ FIELD_PREP(APPLE_SPI_CFG_MODE, APPLE_SPI_CFG_MODE_IRQ) | ++ FIELD_PREP(APPLE_SPI_CFG_WORD_SIZE, APPLE_SPI_CFG_WORD_SIZE_8B)); ++ ++ /* Disable IRQs */ ++ reg_write(spi, APPLE_SPI_IE_FIFO, 0); ++ reg_write(spi, APPLE_SPI_IE_XFER, 0); ++ ++ /* Disable delays */ ++ reg_write(spi, APPLE_SPI_DELAY_PRE, 0); ++ reg_write(spi, APPLE_SPI_DELAY_POST, 0); ++} ++ ++static int apple_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *msg) ++{ ++ struct apple_spi *spi = spi_controller_get_devdata(ctlr); ++ struct spi_device *device = msg->spi; ++ ++ u32 cfg = ((device->mode & SPI_CPHA ? APPLE_SPI_CFG_CPHA : 0) | ++ (device->mode & SPI_CPOL ? APPLE_SPI_CFG_CPOL : 0) | ++ (device->mode & SPI_LSB_FIRST ? APPLE_SPI_CFG_LSB_FIRST : 0)); ++ ++ /* Update core config */ ++ reg_mask(spi, APPLE_SPI_CFG, ++ APPLE_SPI_CFG_CPHA | APPLE_SPI_CFG_CPOL | APPLE_SPI_CFG_LSB_FIRST, cfg); ++ ++ return 0; ++} ++ ++static void apple_spi_set_cs(struct spi_device *device, bool is_high) ++{ ++ struct apple_spi *spi = spi_controller_get_devdata(device->controller); ++ ++ reg_mask(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS, is_high ? APPLE_SPI_PIN_CS : 0); ++} ++ ++static bool apple_spi_prep_transfer(struct apple_spi *spi, struct spi_transfer *t) ++{ ++ u32 cr, fifo_threshold; ++ ++ /* Calculate and program the clock rate */ ++ cr = DIV_ROUND_UP(clk_get_rate(spi->clk), t->speed_hz); ++ reg_write(spi, APPLE_SPI_CLKDIV, min_t(u32, cr, APPLE_SPI_CLKDIV_MAX)); ++ ++ /* Update bits per word */ ++ reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_BITS, ++ FIELD_PREP(APPLE_SPI_SHIFTCFG_BITS, t->bits_per_word)); ++ ++ /* We will want to poll if the time we need to wait is ++ * less than the context switching time. ++ * Let's call that threshold 5us. The operation will take: ++ * bits_per_word * fifo_threshold / hz <= 5 * 10^-6 ++ * 200000 * bits_per_word * fifo_threshold <= hz ++ */ ++ fifo_threshold = APPLE_SPI_FIFO_DEPTH / 2; ++ return (200000 * t->bits_per_word * fifo_threshold) <= t->speed_hz; ++} ++ ++static irqreturn_t apple_spi_irq(int irq, void *dev_id) ++{ ++ struct apple_spi *spi = dev_id; ++ u32 fifo = reg_read(spi, APPLE_SPI_IF_FIFO) & reg_read(spi, APPLE_SPI_IE_FIFO); ++ u32 xfer = reg_read(spi, APPLE_SPI_IF_XFER) & reg_read(spi, APPLE_SPI_IE_XFER); ++ ++ if (fifo || xfer) { ++ /* Disable interrupts until next transfer */ ++ reg_write(spi, APPLE_SPI_IE_XFER, 0); ++ reg_write(spi, APPLE_SPI_IE_FIFO, 0); ++ complete(&spi->done); ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static int apple_spi_wait(struct apple_spi *spi, u32 fifo_bit, u32 xfer_bit, int poll) ++{ ++ int ret = 0; ++ ++ if (poll) { ++ u32 fifo, xfer; ++ unsigned long timeout = jiffies + APPLE_SPI_TIMEOUT_MS * HZ / 1000; ++ ++ do { ++ fifo = reg_read(spi, APPLE_SPI_IF_FIFO); ++ xfer = reg_read(spi, APPLE_SPI_IF_XFER); ++ if (time_after(jiffies, timeout)) { ++ ret = -ETIMEDOUT; ++ break; ++ } ++ } while (!((fifo & fifo_bit) || (xfer & xfer_bit))); ++ } else { ++ reinit_completion(&spi->done); ++ reg_write(spi, APPLE_SPI_IE_XFER, xfer_bit); ++ reg_write(spi, APPLE_SPI_IE_FIFO, fifo_bit); ++ ++ if (!wait_for_completion_timeout(&spi->done, ++ msecs_to_jiffies(APPLE_SPI_TIMEOUT_MS))) ++ ret = -ETIMEDOUT; ++ ++ reg_write(spi, APPLE_SPI_IE_XFER, 0); ++ reg_write(spi, APPLE_SPI_IE_FIFO, 0); ++ } ++ ++ return ret; ++} ++ ++static void apple_spi_tx(struct apple_spi *spi, const void **tx_ptr, u32 *left, ++ unsigned int bytes_per_word) ++{ ++ u32 inuse, words, wrote; ++ ++ if (!*tx_ptr) ++ return; ++ ++ inuse = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_TX, reg_read(spi, APPLE_SPI_FIFOSTAT)); ++ words = wrote = min_t(u32, *left, APPLE_SPI_FIFO_DEPTH - inuse); ++ ++ if (!words) ++ return; ++ ++ *left -= words; ++ ++ switch (bytes_per_word) { ++ case 1: { ++ const u8 *p = *tx_ptr; ++ ++ while (words--) ++ reg_write(spi, APPLE_SPI_TXDATA, *p++); ++ break; ++ } ++ case 2: { ++ const u16 *p = *tx_ptr; ++ ++ while (words--) ++ reg_write(spi, APPLE_SPI_TXDATA, *p++); ++ break; ++ } ++ case 4: { ++ const u32 *p = *tx_ptr; ++ ++ while (words--) ++ reg_write(spi, APPLE_SPI_TXDATA, *p++); ++ break; ++ } ++ default: ++ WARN_ON(1); ++ } ++ ++ *tx_ptr = ((u8 *)*tx_ptr) + bytes_per_word * wrote; ++} ++ ++static void apple_spi_rx(struct apple_spi *spi, void **rx_ptr, u32 *left, ++ unsigned int bytes_per_word) ++{ ++ u32 words, read; ++ ++ if (!*rx_ptr) ++ return; ++ ++ words = read = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_RX, reg_read(spi, APPLE_SPI_FIFOSTAT)); ++ WARN_ON(words > *left); ++ ++ if (!words) ++ return; ++ ++ *left -= min_t(u32, *left, words); ++ ++ switch (bytes_per_word) { ++ case 1: { ++ u8 *p = *rx_ptr; ++ ++ while (words--) ++ *p++ = reg_read(spi, APPLE_SPI_RXDATA); ++ break; ++ } ++ case 2: { ++ u16 *p = *rx_ptr; ++ ++ while (words--) ++ *p++ = reg_read(spi, APPLE_SPI_RXDATA); ++ break; ++ } ++ case 4: { ++ u32 *p = *rx_ptr; ++ ++ while (words--) ++ *p++ = reg_read(spi, APPLE_SPI_RXDATA); ++ break; ++ } ++ default: ++ WARN_ON(1); ++ } ++ ++ *rx_ptr = ((u8 *)*rx_ptr) + bytes_per_word * read; ++} ++ ++static int apple_spi_transfer_one(struct spi_controller *ctlr, struct spi_device *device, ++ struct spi_transfer *t) ++{ ++ struct apple_spi *spi = spi_controller_get_devdata(ctlr); ++ bool poll = apple_spi_prep_transfer(spi, t); ++ const void *tx_ptr = t->tx_buf; ++ void *rx_ptr = t->rx_buf; ++ unsigned int bytes_per_word; ++ u32 words, remaining_tx, remaining_rx; ++ u32 xfer_flags = 0; ++ u32 fifo_flags; ++ int retries = 100; ++ int ret = 0; ++ ++ if (t->bits_per_word > 16) ++ bytes_per_word = 4; ++ else if (t->bits_per_word > 8) ++ bytes_per_word = 2; ++ else ++ bytes_per_word = 1; ++ ++ words = t->len / bytes_per_word; ++ remaining_tx = tx_ptr ? words : 0; ++ remaining_rx = rx_ptr ? words : 0; ++ ++ /* Reset FIFOs */ ++ reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET); ++ ++ /* Clear IRQ flags */ ++ reg_write(spi, APPLE_SPI_IF_XFER, ~0); ++ reg_write(spi, APPLE_SPI_IF_FIFO, ~0); ++ ++ /* Determine transfer completion flags we wait for */ ++ if (tx_ptr) ++ xfer_flags |= APPLE_SPI_XFER_TXCOMPLETE; ++ if (rx_ptr) ++ xfer_flags |= APPLE_SPI_XFER_RXCOMPLETE; ++ ++ /* Set transfer length */ ++ reg_write(spi, APPLE_SPI_TXCNT, remaining_tx); ++ reg_write(spi, APPLE_SPI_RXCNT, remaining_rx); ++ ++ /* Prime transmit FIFO */ ++ apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); ++ ++ /* Start transfer */ ++ reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RUN); ++ ++ /* TX again since a few words get popped off immediately */ ++ apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); ++ ++ while (xfer_flags) { ++ fifo_flags = 0; ++ ++ if (remaining_tx) ++ fifo_flags |= APPLE_SPI_FIFO_TXTHRESH; ++ if (remaining_rx) ++ fifo_flags |= APPLE_SPI_FIFO_RXTHRESH; ++ ++ /* Wait for anything to happen */ ++ ret = apple_spi_wait(spi, fifo_flags, xfer_flags, poll); ++ if (ret) { ++ dev_err(&ctlr->dev, "transfer timed out (remaining %d tx, %d rx)\n", ++ remaining_tx, remaining_rx); ++ goto err; ++ } ++ ++ /* Stop waiting on transfer halves once they complete */ ++ xfer_flags &= ~reg_read(spi, APPLE_SPI_IF_XFER); ++ ++ /* Transmit and receive everything we can */ ++ apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); ++ apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word); ++ } ++ ++ /* ++ * Sometimes the transfer completes before the last word is in the RX FIFO. ++ * Normally one retry is all it takes to get the last word out. ++ */ ++ while (remaining_rx && retries--) ++ apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word); ++ ++ if (remaining_tx) ++ dev_err(&ctlr->dev, "transfer completed with %d words left to transmit\n", ++ remaining_tx); ++ if (remaining_rx) ++ dev_err(&ctlr->dev, "transfer completed with %d words left to receive\n", ++ remaining_rx); ++ ++err: ++ fifo_flags = reg_read(spi, APPLE_SPI_IF_FIFO); ++ WARN_ON(fifo_flags & APPLE_SPI_FIFO_TXOVERFLOW); ++ WARN_ON(fifo_flags & APPLE_SPI_FIFO_RXUNDERRUN); ++ ++ /* Stop transfer */ ++ reg_write(spi, APPLE_SPI_CTRL, 0); ++ ++ return ret; ++} ++ ++static void apple_spi_clk_disable_unprepare(void *data) ++{ ++ clk_disable_unprepare(data); ++} ++ ++static int apple_spi_probe(struct platform_device *pdev) ++{ ++ struct apple_spi *spi; ++ int ret, irq; ++ struct spi_controller *ctlr; ++ ++ ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(struct apple_spi)); ++ if (!ctlr) ++ return dev_err_probe(&pdev->dev, -ENOMEM, "out of memory\n"); ++ ++ spi = spi_controller_get_devdata(ctlr); ++ init_completion(&spi->done); ++ platform_set_drvdata(pdev, ctlr); ++ ++ spi->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(spi->regs)) ++ return PTR_ERR(spi->regs); ++ ++ spi->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(spi->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk), "Unable to find bus clock\n"); ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ return irq; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, irq, apple_spi_irq, 0, ++ dev_name(&pdev->dev), spi); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "Unable to bind to interrupt\n"); ++ ++ ret = clk_prepare_enable(spi->clk); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "Unable to enable bus clock\n"); ++ ++ ret = devm_add_action_or_reset(&pdev->dev, apple_spi_clk_disable_unprepare, spi->clk); ++ if (ret) ++ return ret; ++ ++ ctlr->dev.of_node = pdev->dev.of_node; ++ ctlr->bus_num = pdev->id; ++ ctlr->num_chipselect = 1; ++ ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; ++ ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); ++ ctlr->flags = 0; ++ ctlr->prepare_message = apple_spi_prepare_message; ++ ctlr->set_cs = apple_spi_set_cs; ++ ctlr->transfer_one = apple_spi_transfer_one; ++ ctlr->auto_runtime_pm = true; ++ ++ pm_runtime_set_active(&pdev->dev); ++ devm_pm_runtime_enable(&pdev->dev); ++ ++ apple_spi_init(spi); ++ ++ ret = devm_spi_register_controller(&pdev->dev, ctlr); ++ if (ret < 0) ++ return dev_err_probe(&pdev->dev, ret, "devm_spi_register_controller failed\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id apple_spi_of_match[] = { ++ { .compatible = "apple,spi", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, apple_spi_of_match); ++ ++static struct platform_driver apple_spi_driver = { ++ .probe = apple_spi_probe, ++ .driver = { ++ .name = "apple-spi", ++ .owner = THIS_MODULE, ++ .of_match_table = apple_spi_of_match, ++ }, ++}; ++module_platform_driver(apple_spi_driver); ++ ++MODULE_AUTHOR("Hector Martin "); ++MODULE_DESCRIPTION("Apple SoC SPI driver"); ++MODULE_LICENSE("GPL"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0070-dt-bindings-dma-Add-apple-admac-binding.patch b/target/linux/silicon/patches-5.19/0070-dt-bindings-dma-Add-apple-admac-binding.patch new file mode 100644 index 000000000..bb3c6d12d --- /dev/null +++ b/target/linux/silicon/patches-5.19/0070-dt-bindings-dma-Add-apple-admac-binding.patch @@ -0,0 +1,93 @@ +From c67e6dd3d9c5590394faf5138021ba7ebe306343 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 09:50:39 +0100 +Subject: [PATCH 070/171] dt-bindings: dma: Add apple,admac binding +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Audio DMA Controller (ADMAC) is used to load and store audio +samples from/to system memory. It is present on Apple SoCs from +the "Apple Silicon" family. + +Signed-off-by: Martin PoviÅ¡er +--- + .../devicetree/bindings/dma/apple,admac.yaml | 65 +++++++++++++++++++ + 1 file changed, 65 insertions(+) + create mode 100644 Documentation/devicetree/bindings/dma/apple,admac.yaml + +diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml +new file mode 100644 +index 000000000000..34ede3b0de2c +--- /dev/null ++++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml +@@ -0,0 +1,65 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/dma/apple,admac.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Apple Audio DMA Controller (ADMAC) ++ ++description: | ++ The Audio DMA Controller (ADMAC) is used to load and store audio ++ samples from/to system memory. It is present on Apple SoCs ++ from the "Apple Silicon" family. ++ ++maintainers: ++ - Martin PoviÅ¡er ++ ++allOf: ++ - $ref: "dma-controller.yaml#" ++ ++properties: ++ compatible: ++ items: ++ - const: apple,t8103-admac ++ - const: apple,admac ++ ++ reg: ++ maxItems: 1 ++ ++ '#dma-cells': ++ const: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - '#dma-cells' ++ - dma-channels ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ ++ dart_sio: iommu@235004000 { ++ compatible = "apple,t8103-dart", "apple,dart"; ++ reg = <0x2 0x35004000 0x0 0x4000>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #iommu-cells = <1>; ++ }; ++ ++ admac: dma-controller@238200000 { ++ compatible = "apple,t8103-admac", "apple,admac"; ++ reg = <0x2 0x38200000 0x0 0x34000>; ++ dma-channels = <12>; ++ interrupt-parent = <&aic>; ++ interrupts = ; ++ #dma-cells = <1>; ++ iommus = <&dart_sio 2>; ++ }; +\ No newline at end of file +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0071-dmaengine-apple-admac-Add-Apple-ADMAC-driver.patch b/target/linux/silicon/patches-5.19/0071-dmaengine-apple-admac-Add-Apple-ADMAC-driver.patch new file mode 100644 index 000000000..99b46d452 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0071-dmaengine-apple-admac-Add-Apple-ADMAC-driver.patch @@ -0,0 +1,806 @@ +From 594ea25c7f3f1ee8d0e952c6547bcd06843f9045 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 09:49:23 +0100 +Subject: [PATCH 071/171] dmaengine: apple-admac: Add Apple ADMAC driver + +Add driver for Audio DMA Controller present on Apple SoCs +from the "Apple Silicon" family. +--- + drivers/dma/Kconfig | 8 + + drivers/dma/Makefile | 1 + + drivers/dma/apple-admac.c | 752 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 761 insertions(+) + create mode 100644 drivers/dma/apple-admac.c + +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index 487ed4ddc3be..bda78b8172d4 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -85,6 +85,14 @@ config AMCC_PPC440SPE_ADMA + help + Enable support for the AMCC PPC440SPe RAID engines. + ++config APPLE_ADMAC ++ tristate "Apple ADMAC support" ++ depends on ARCH_APPLE || COMPILE_TEST ++ select DMA_ENGINE ++ default ARCH_APPLE ++ help ++ Enable support for Audio DMA Controller found on Apple Silicon chips. ++ + config AT_HDMAC + tristate "Atmel AHB DMA support" + depends on ARCH_AT91 +diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile +index 2f1b87ffd7ab..10f7d4241001 100644 +--- a/drivers/dma/Makefile ++++ b/drivers/dma/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_ALTERA_MSGDMA) += altera-msgdma.o + obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o + obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/ + obj-$(CONFIG_AMD_PTDMA) += ptdma/ ++obj-$(CONFIG_APPLE_ADMAC) += apple-admac.o + obj-$(CONFIG_AT_HDMAC) += at_hdmac.o + obj-$(CONFIG_AT_XDMAC) += at_xdmac.o + obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o +diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c +new file mode 100644 +index 000000000000..aa4c07bcb72a +--- /dev/null ++++ b/drivers/dma/apple-admac.c +@@ -0,0 +1,752 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dmaengine.h" ++ ++#define NCHANNELS_MAX 64 ++ ++#define RING_WRITE_SLOT GENMASK(1, 0) ++#define RING_READ_SLOT GENMASK(5, 4) ++#define RING_FULL BIT(9) ++#define RING_EMPTY BIT(8) ++#define RING_ERR BIT(10) ++ ++#define STATUS_DESC_DONE BIT(0) ++#define STATUS_ERR BIT(6) ++ ++#define FLAG_DESC_NOTIFY BIT(16) ++ ++#define REG_TX_START 0x0000 ++#define REG_TX_STOP 0x0004 ++#define REG_RX_START 0x0008 ++#define REG_RX_STOP 0x000c ++ ++#define REG_CHAN_CTL(ch) (0x8000 + (ch)*0x200) ++#define REG_CHAN_CTL_RST_RINGS BIT(0) ++ ++#define REG_DESC_RING(ch) (0x8070 + (ch)*0x200) ++#define REG_REPORT_RING(ch) (0x8074 + (ch)*0x200) ++ ++#define REG_RESIDUE(ch) (0x8064 + (ch)*0x200) ++ ++#define REG_BUS_WIDTH(ch) (0x8040 + (ch)*0x200) ++ ++#define BUS_WIDTH_8BIT 0x00 ++#define BUS_WIDTH_16BIT 0x01 ++#define BUS_WIDTH_32BIT 0x02 ++#define BUS_WIDTH_FRAME_2_WORDS 0x10 ++#define BUS_WIDTH_FRAME_4_WORDS 0x20 ++ ++#define REG_CHAN_BURSTSIZE(ch) (0x8054 + (ch)*0x200) ++ ++#define REG_DESC_WRITE(ch) (0x10000 + (ch / 2) * 0x4 + (ch & 1) * 0x4000) ++#define REG_REPORT_READ(ch) (0x10100 + (ch / 2) * 0x4 + (ch & 1) * 0x4000) ++ ++#define IRQ_INDEX_MAX 3 ++ ++#define REG_TX_INTSTATE(idx) (0x0030 + (idx) * 4) ++#define REG_RX_INTSTATE(idx) (0x0040 + (idx) * 4) ++#define REG_CHAN_INTSTATUS(ch,idx) (0x8010 + (ch) * 0x200 + (idx) * 4) ++#define REG_CHAN_INTMASK(ch,idx) (0x8020 + (ch) * 0x200 + (idx) * 4) ++ ++struct admac_data; ++struct admac_tx; ++ ++struct admac_chan { ++ int no; ++ struct admac_data *host; ++ struct dma_chan chan; ++ struct tasklet_struct tasklet; ++ ++ spinlock_t lock; ++ struct admac_tx *current_tx; ++ int nperiod_acks; ++ ++ struct list_head submitted; ++ struct list_head issued; ++}; ++ ++struct admac_data { ++ struct dma_device dma; ++ struct device *dev; ++ __iomem void *base; ++ ++ int irq_index; ++ int nchannels; ++ struct admac_chan channels[]; ++}; ++ ++struct admac_tx { ++ struct dma_async_tx_descriptor tx; ++ bool cyclic; ++ dma_addr_t buf_addr; ++ dma_addr_t buf_end; ++ size_t buf_len; ++ size_t period_len; ++ ++ size_t submitted_pos; ++ size_t reclaimed_pos; ++ ++ struct list_head node; ++}; ++ ++static void admac_poke(struct admac_data *ad, int reg, u32 val) ++{ ++ writel_relaxed(val, ad->base + reg); ++} ++ ++static u32 admac_peek(struct admac_data *ad, int reg) ++{ ++ return readl_relaxed(ad->base + reg); ++} ++ ++static void admac_modify(struct admac_data *ad, int reg, u32 mask, u32 val) ++{ ++ void __iomem *addr = ad->base + reg; ++ u32 curr = readl_relaxed(addr); ++ ++ writel_relaxed((curr & ~mask) | (val & mask), addr); ++} ++ ++static struct admac_chan *to_admac_chan(struct dma_chan *chan) ++{ ++ return container_of(chan, struct admac_chan, chan); ++} ++ ++static struct admac_tx *to_admac_tx(struct dma_async_tx_descriptor *tx) ++{ ++ return container_of(tx, struct admac_tx, tx); ++} ++ ++static enum dma_transfer_direction admac_chan_direction(int channo) ++{ ++ return (channo & 1) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; ++} ++ ++static dma_cookie_t admac_tx_submit(struct dma_async_tx_descriptor *tx) ++{ ++ struct admac_tx *adtx = to_admac_tx(tx); ++ struct admac_chan *adchan = to_admac_chan(tx->chan); ++ unsigned long flags; ++ dma_cookie_t cookie; ++ ++ spin_lock_irqsave(&adchan->lock, flags); ++ cookie = dma_cookie_assign(tx); ++ list_add_tail(&adtx->node, &adchan->submitted); ++ spin_unlock_irqrestore(&adchan->lock, flags); ++ ++ return cookie; ++} ++ ++static int admac_desc_free(struct dma_async_tx_descriptor *tx) ++{ ++ struct admac_tx *adtx = to_admac_tx(tx); ++ devm_kfree(to_admac_chan(tx->chan)->host->dev, adtx); ++ return 0; ++} ++ ++static struct dma_async_tx_descriptor *admac_prep_dma_cyclic( ++ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, ++ size_t period_len, enum dma_transfer_direction direction, ++ unsigned long flags) ++{ ++ struct admac_chan *adchan = container_of(chan, struct admac_chan, chan); ++ struct admac_tx *adtx; ++ ++ if (direction != admac_chan_direction(adchan->no)) ++ return NULL; ++ ++ adtx = devm_kzalloc(adchan->host->dev, sizeof(*adtx), GFP_NOWAIT); ++ if (!adtx) ++ return NULL; ++ ++ adtx->cyclic = true; ++ ++ adtx->buf_addr = buf_addr; ++ adtx->buf_len = buf_len; ++ adtx->buf_end = buf_addr + buf_len; ++ adtx->period_len = period_len; ++ ++ adtx->submitted_pos = 0; ++ adtx->reclaimed_pos = 0; ++ ++ dma_async_tx_descriptor_init(&adtx->tx, chan); ++ adtx->tx.tx_submit = admac_tx_submit; ++ adtx->tx.desc_free = admac_desc_free; ++ ++ return &adtx->tx; ++} ++ ++/* ++ * Write one hardware descriptor for a dmaegine cyclic transaction. ++ */ ++static void admac_cyclic_write_one_desc(struct admac_data *ad, int channo, ++ struct admac_tx *tx) ++{ ++ dma_addr_t addr; ++ ++ if (WARN_ON(!tx->cyclic)) ++ return; ++ ++ addr = tx->buf_addr + (tx->submitted_pos % tx->buf_len); ++ WARN_ON(addr + tx->period_len > tx->buf_end); ++ ++ dev_dbg(ad->dev, "ch%d descriptor: addr=0x%llx len=0x%x flags=0x%lx\n", ++ channo, addr, (u32) tx->period_len, FLAG_DESC_NOTIFY); ++ ++ admac_poke(ad, REG_DESC_WRITE(channo), addr); ++ admac_poke(ad, REG_DESC_WRITE(channo), addr >> 32); ++ admac_poke(ad, REG_DESC_WRITE(channo), tx->period_len); ++ admac_poke(ad, REG_DESC_WRITE(channo), FLAG_DESC_NOTIFY); ++ ++ tx->submitted_pos += tx->period_len; ++ tx->submitted_pos %= 2 * tx->buf_len; ++} ++ ++/* ++ * Write all the hardware descriptors for a cyclic transaction ++ * there is space for. ++ */ ++static void admac_cyclic_write_desc(struct admac_data *ad, int channo, ++ struct admac_tx *tx) ++{ ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ if (admac_peek(ad, REG_DESC_RING(channo)) & RING_FULL) ++ break; ++ admac_cyclic_write_one_desc(ad, channo, tx); ++ } ++} ++ ++static int admac_alloc_chan_resources(struct dma_chan *chan) ++{ ++ return 0; ++} ++ ++static void admac_free_chan_resources(struct dma_chan *chan) ++{ ++ // TODO ++} ++ ++static int admac_ring_noccupied_slots(int ringval) ++{ ++ int wrslot = FIELD_GET(RING_WRITE_SLOT, ringval); ++ int rdslot = FIELD_GET(RING_READ_SLOT, ringval); ++ ++ if (wrslot != rdslot) { ++ return (wrslot + 4 - rdslot) % 4; ++ } else { ++ WARN_ON((ringval & (RING_FULL | RING_EMPTY)) == 0); ++ ++ if (ringval & RING_FULL) ++ return 4; ++ else ++ return 0; ++ } ++} ++ ++/* ++ * Read from hardware the residue of a cyclic dmaengine transaction. ++ */ ++u32 admac_cyclic_read_residue(struct admac_data *ad, int channo, struct admac_tx *adtx) ++{ ++ u32 ring1, ring2; ++ u32 residue1, residue2; ++ int nreports; ++ size_t pos; ++ ++ ring1 = admac_peek(ad, REG_REPORT_RING(channo)); ++ residue1 = admac_peek(ad, REG_RESIDUE(channo)); ++ ring2 = admac_peek(ad, REG_REPORT_RING(channo)); ++ residue2 = admac_peek(ad, REG_RESIDUE(channo)); ++ ++ if (residue2 > residue1) { ++ // engine must have loaded next descriptor between the two residue reads ++ nreports = admac_ring_noccupied_slots(ring1) + 1; ++ } else { ++ // no descriptor load between the two reads, ring2 is safe to use ++ nreports = admac_ring_noccupied_slots(ring2); ++ } ++ ++ pos = adtx->reclaimed_pos + adtx->period_len * (nreports + 1) \ ++ - residue2; ++ ++ return adtx->buf_len - pos % adtx->buf_len; ++} ++ ++static enum dma_status admac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ struct admac_chan *adchan = to_admac_chan(chan); ++ struct admac_data *ad = adchan->host; ++ struct admac_tx *adtx; ++ ++ enum dma_status ret; ++ size_t residue; ++ unsigned long flags; ++ ++ ret = dma_cookie_status(chan, cookie, txstate); ++ if (ret == DMA_COMPLETE || !txstate) ++ return ret; ++ ++ spin_lock_irqsave(&adchan->lock, flags); ++ adtx = adchan->current_tx; ++ ++ if (adtx && adtx->tx.cookie == cookie) { ++ ret = DMA_IN_PROGRESS; ++ residue = admac_cyclic_read_residue(ad, adchan->no, adtx); ++ } else { ++ ret = DMA_IN_PROGRESS; ++ residue = 0; ++ list_for_each_entry(adtx, &adchan->issued, node) { ++ if (adtx->tx.cookie == cookie) { ++ residue = adtx->buf_len; ++ break; ++ } ++ } ++ } ++ spin_unlock_irqrestore(&adchan->lock, flags); ++ ++ dma_set_residue(txstate, residue); ++ return ret; ++} ++ ++static void admac_start_chan(struct admac_chan *adchan) ++{ ++ u32 startbit = 1 << (adchan->no / 2); ++ switch (admac_chan_direction(adchan->no)) { ++ case DMA_MEM_TO_DEV: ++ admac_poke(adchan->host, REG_TX_START, startbit); ++ break; ++ case DMA_DEV_TO_MEM: ++ admac_poke(adchan->host, REG_RX_START, startbit); ++ break; ++ default: ++ break; ++ } ++ dev_dbg(adchan->host->dev, "ch%d start\n", adchan->no); ++} ++ ++static void admac_stop_chan(struct admac_chan *adchan) ++{ ++ u32 stopbit = 1 << (adchan->no / 2); ++ switch (admac_chan_direction(adchan->no)) { ++ case DMA_MEM_TO_DEV: ++ admac_poke(adchan->host, REG_TX_STOP, stopbit); ++ break; ++ case DMA_DEV_TO_MEM: ++ admac_poke(adchan->host, REG_RX_STOP, stopbit); ++ break; ++ default: ++ break; ++ } ++ dev_dbg(adchan->host->dev, "ch%d stop\n", adchan->no); ++} ++ ++static void admac_start_current_tx(struct admac_chan *adchan) ++{ ++ struct admac_data *ad = adchan->host; ++ int ch = adchan->no; ++ ++ admac_poke(ad, REG_CHAN_INTSTATUS(ch, ad->irq_index), ++ STATUS_DESC_DONE | STATUS_ERR); ++ admac_poke(ad, REG_CHAN_CTL(ch), REG_CHAN_CTL_RST_RINGS); ++ admac_poke(ad, REG_CHAN_CTL(ch), 0); ++ ++ admac_cyclic_write_one_desc(ad, ch, adchan->current_tx); ++ admac_start_chan(adchan); ++ admac_cyclic_write_desc(ad, ch, adchan->current_tx); ++} ++ ++static void admac_issue_pending(struct dma_chan *chan) ++{ ++ struct admac_chan *adchan = to_admac_chan(chan); ++ struct admac_tx *tx; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adchan->lock, flags); ++ list_splice_tail_init(&adchan->submitted, &adchan->issued); ++ if (!list_empty(&adchan->issued) && !adchan->current_tx) { ++ tx = list_first_entry(&adchan->issued, struct admac_tx, node); ++ list_del(&tx->node); ++ ++ adchan->current_tx = tx; ++ adchan->nperiod_acks = 0; ++ admac_start_current_tx(adchan); ++ } ++ spin_unlock_irqrestore(&adchan->lock, flags); ++} ++ ++static int admac_pause(struct dma_chan *chan) ++{ ++ struct admac_chan *adchan = to_admac_chan(chan); ++ ++ admac_stop_chan(adchan); ++ ++ return 0; ++} ++ ++static int admac_resume(struct dma_chan *chan) ++{ ++ struct admac_chan *adchan = to_admac_chan(chan); ++ ++ admac_start_chan(adchan); ++ ++ return 0; ++} ++ ++static int admac_terminate_all(struct dma_chan *chan) ++{ ++ struct admac_chan *adchan = to_admac_chan(chan); ++ struct admac_tx *adtx, *_adtx; ++ unsigned long flags; ++ LIST_HEAD(head); ++ ++ spin_lock_irqsave(&adchan->lock, flags); ++ admac_stop_chan(adchan); ++ adchan->current_tx = NULL; ++ list_splice_tail_init(&adchan->submitted, &head); ++ list_splice_tail_init(&adchan->issued, &head); ++ spin_unlock_irqrestore(&adchan->lock, flags); ++ ++ list_for_each_entry_safe(adtx, _adtx, &head, node) { ++ list_del(&adtx->node); ++ admac_desc_free(&adtx->tx); ++ } ++ ++ return 0; ++} ++ ++static struct dma_chan *admac_dma_of_xlate(struct of_phandle_args *dma_spec, ++ struct of_dma *ofdma) ++{ ++ struct admac_data *ad = (struct admac_data*) ofdma->of_dma_data; ++ unsigned int index; ++ ++ if (dma_spec->args_count != 1) ++ return NULL; ++ ++ index = dma_spec->args[0]; ++ ++ if (index >= ad->nchannels) { ++ dev_err(ad->dev, "channel index %u out of bounds\n", index); ++ return NULL; ++ } ++ ++ return &ad->channels[index].chan; ++} ++ ++static int admac_drain_reports(struct admac_data *ad, int channo) ++{ ++ int count; ++ ++ for (count = 0; count < 4; count++) { ++ u32 countval_hi, countval_lo, unk1, flags; ++ ++ if (admac_peek(ad, REG_REPORT_RING(channo)) & RING_EMPTY) ++ break; ++ ++ countval_lo = admac_peek(ad, REG_REPORT_READ(channo)); ++ countval_hi = admac_peek(ad, REG_REPORT_READ(channo)); ++ unk1 = admac_peek(ad, REG_REPORT_READ(channo)); ++ flags = admac_peek(ad, REG_REPORT_READ(channo)); ++ ++ dev_dbg(ad->dev, "ch%d report: countval=0x%llx unk1=0x%x flags=0x%x\n", ++ channo, ((u64) countval_hi) << 32 | countval_lo, unk1, flags); ++ } ++ ++ return count; ++} ++ ++static void admac_handle_status_err(struct admac_data *ad, int channo) ++{ ++ bool handled = false; ++ ++ if (admac_peek(ad, REG_DESC_RING(channo) & RING_ERR)) { ++ admac_poke(ad, REG_DESC_RING(channo), RING_ERR); ++ dev_err(ad->dev, "ch%d descriptor ring error\n", channo); ++ handled = true; ++ } ++ ++ if (admac_peek(ad, REG_REPORT_RING(channo)) & RING_ERR) { ++ admac_poke(ad, REG_REPORT_RING(channo), RING_ERR); ++ dev_err(ad->dev, "ch%d report ring error\n", channo); ++ handled = true; ++ } ++ ++ if (unlikely(!handled)) { ++ dev_err(ad->dev, "ch%d unknown error, masking future error interrupts\n", channo); ++ admac_modify(ad, REG_CHAN_INTMASK(channo, ad->irq_index), STATUS_ERR, 0); ++ } ++} ++ ++static void admac_handle_status_desc_done(struct admac_data *ad, int channo) ++{ ++ struct admac_chan *adchan = &ad->channels[channo]; ++ unsigned long flags; ++ int nreports; ++ ++ admac_poke(ad, REG_CHAN_INTSTATUS(channo, ad->irq_index), ++ STATUS_DESC_DONE); ++ ++ spin_lock_irqsave(&adchan->lock, flags); ++ nreports = admac_drain_reports(ad, channo); ++ ++ if (adchan->current_tx) { ++ struct admac_tx *tx = adchan->current_tx; ++ ++ adchan->nperiod_acks += nreports; ++ tx->reclaimed_pos += nreports * tx->period_len; ++ tx->reclaimed_pos %= 2 * tx->buf_len; ++ ++ admac_cyclic_write_desc(ad, channo, tx); ++ tasklet_schedule(&adchan->tasklet); ++ } ++ spin_unlock_irqrestore(&adchan->lock, flags); ++} ++ ++static void admac_handle_chan_int(struct admac_data *ad, int no) ++{ ++ u32 cause = admac_peek(ad, REG_CHAN_INTSTATUS(no, ad->irq_index)); ++ ++ if (cause & STATUS_ERR) ++ admac_handle_status_err(ad, no); ++ ++ if (cause & STATUS_DESC_DONE) ++ admac_handle_status_desc_done(ad, no); ++} ++ ++static irqreturn_t admac_interrupt(int irq, void *devid) ++{ ++ struct admac_data *ad = devid; ++ u32 rx_intstate, tx_intstate; ++ int i; ++ ++ rx_intstate = admac_peek(ad, REG_RX_INTSTATE(ad->irq_index)); ++ tx_intstate = admac_peek(ad, REG_TX_INTSTATE(ad->irq_index)); ++ ++ for (i = 0; i < ad->nchannels; i += 2) ++ if (tx_intstate & (1 << (i / 2))) ++ admac_handle_chan_int(ad, i); ++ ++ for (i = 1; i < ad->nchannels; i += 2) ++ if (rx_intstate & (1 << (i / 2))) ++ admac_handle_chan_int(ad, i); ++ ++ return (tx_intstate | rx_intstate) != 0 ? IRQ_HANDLED : IRQ_NONE; ++} ++ ++static void admac_chan_tasklet(struct tasklet_struct *t) ++{ ++ struct admac_chan *adchan = from_tasklet(adchan, t, tasklet); ++ struct admac_tx *adtx; ++ struct dmaengine_desc_callback cb; ++ struct dmaengine_result tx_result; ++ int nacks; ++ ++ spin_lock_irq(&adchan->lock); ++ adtx = adchan->current_tx; ++ nacks = adchan->nperiod_acks; ++ adchan->nperiod_acks = 0; ++ spin_unlock_irq(&adchan->lock); ++ ++ if (!adtx || !nacks) ++ return; ++ ++ tx_result.result = DMA_TRANS_NOERROR; ++ tx_result.residue = 0; ++ ++ dmaengine_desc_get_callback(&adtx->tx, &cb); ++ while (nacks--) ++ dmaengine_desc_callback_invoke(&cb, &tx_result); ++} ++ ++static int admac_device_config(struct dma_chan *chan, ++ struct dma_slave_config *config) ++{ ++ struct admac_chan *adchan = to_admac_chan(chan); ++ struct admac_data *ad = adchan->host; ++ bool is_tx = admac_chan_direction(adchan->no) == DMA_MEM_TO_DEV; ++ u32 bus_width = 0; ++ ++ ++ switch (is_tx ? config->dst_addr_width : config->src_addr_width) { ++ case DMA_SLAVE_BUSWIDTH_1_BYTE: ++ bus_width |= BUS_WIDTH_8BIT; ++ break; ++ case DMA_SLAVE_BUSWIDTH_2_BYTES: ++ bus_width |= BUS_WIDTH_16BIT; ++ break; ++ case DMA_SLAVE_BUSWIDTH_4_BYTES: ++ bus_width |= BUS_WIDTH_32BIT; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (is_tx ? config->dst_port_window_size : config->src_port_window_size) { ++ case 0 ... 1: ++ break; ++ case 2: ++ bus_width |= BUS_WIDTH_FRAME_2_WORDS; ++ break; ++ case 4: ++ bus_width |= BUS_WIDTH_FRAME_4_WORDS; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ admac_poke(adchan->host, REG_BUS_WIDTH(adchan->no), bus_width); ++ ++ /* TODO: burst size */ ++ ++ admac_poke(adchan->host, REG_CHAN_BURSTSIZE(adchan->no), 0xc00060); ++ ++ /* TODO: this belongs elsewhere */ ++ admac_poke(adchan->host, REG_CHAN_INTSTATUS(adchan->no, ad->irq_index), ++ STATUS_DESC_DONE | STATUS_ERR); ++ admac_poke(adchan->host, REG_CHAN_INTMASK(adchan->no, ad->irq_index), ++ STATUS_DESC_DONE | STATUS_ERR); ++ return 0; ++} ++ ++static int admac_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct admac_data *ad; ++ struct dma_device *dma; ++ int nchannels; ++ int err, irq, i; ++ ++ err = of_property_read_u32(np, "dma-channels", &nchannels); ++ if (err || nchannels > NCHANNELS_MAX) { ++ dev_err(&pdev->dev, "missing or invalid dma-channels property\n"); ++ return -EINVAL; ++ } ++ ++ ad = devm_kzalloc(&pdev->dev, struct_size(ad, channels, nchannels), GFP_KERNEL); ++ if (!ad) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, ad); ++ ad->dev = &pdev->dev; ++ ad->nchannels = nchannels; ++ ++ err = of_property_read_u32(np, "apple,internal-irq-destination", &ad->irq_index); ++ if (err || ad->irq_index > IRQ_INDEX_MAX) { ++ dev_err(&pdev->dev, "missing or invalid apple,internal-irq-destination property\n"); ++ return -EINVAL; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "unable to obtain interrupt resource\n"); ++ return irq; ++ } ++ ++ err = devm_request_irq(&pdev->dev, irq, admac_interrupt, ++ 0, dev_name(&pdev->dev), ad); ++ if (err) { ++ dev_err(&pdev->dev, "unable to register interrupt: %d\n", err); ++ return err; ++ } ++ ++ ad->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(ad->base)) { ++ dev_err(&pdev->dev, "unable to obtain MMIO resource\n"); ++ return PTR_ERR(ad->base); ++ } ++ ++ dma = &ad->dma; ++ ++ dma_cap_set(DMA_PRIVATE, dma->cap_mask); ++ dma_cap_set(DMA_CYCLIC, dma->cap_mask); ++ ++ dma->dev = &pdev->dev; ++ dma->device_alloc_chan_resources = admac_alloc_chan_resources; ++ dma->device_free_chan_resources = admac_free_chan_resources; ++ dma->device_tx_status = admac_tx_status; ++ dma->device_issue_pending = admac_issue_pending; ++ dma->device_terminate_all = admac_terminate_all; ++ dma->device_prep_dma_cyclic = admac_prep_dma_cyclic; ++ dma->device_config = admac_device_config; ++ dma->device_pause = admac_pause; ++ dma->device_resume = admac_resume; ++ ++ dma->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM); ++ dma->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; ++ dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | ++ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | ++ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); ++ ++ INIT_LIST_HEAD(&dma->channels); ++ for (i = 0; i < nchannels; i++) { ++ struct admac_chan *adchan = &ad->channels[i]; ++ adchan->host = ad; ++ adchan->no = i; ++ adchan->chan.device = &ad->dma; ++ dma_cookie_init(&adchan->chan); ++ spin_lock_init(&adchan->lock); ++ INIT_LIST_HEAD(&adchan->submitted); ++ INIT_LIST_HEAD(&adchan->issued); ++ list_add_tail(&adchan->chan.device_node, &dma->channels); ++ tasklet_setup(&adchan->tasklet, admac_chan_tasklet); ++ } ++ ++ err = dma_async_device_register(&ad->dma); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register DMA device: %d\n", err); ++ return err; ++ } ++ ++ err = of_dma_controller_register(pdev->dev.of_node, admac_dma_of_xlate, ad); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register with OF: %d\n", err); ++ dma_async_device_unregister(&ad->dma); ++ return err; ++ } ++ ++ dev_dbg(&pdev->dev, "all good, ready to go!\n"); ++ ++ return 0; ++} ++ ++static int admac_remove(struct platform_device *pdev) ++{ ++ struct admac_data *ad = platform_get_drvdata(pdev); ++ ++ of_dma_controller_free(pdev->dev.of_node); ++ dma_async_device_unregister(&ad->dma); ++ ++ return 0; ++} ++ ++static const struct of_device_id admac_of_match[] = { ++ { .compatible = "apple,admac", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, admac_of_match); ++ ++static struct platform_driver apple_admac_driver = { ++ .driver = { ++ .name = "apple-admac", ++ .of_match_table = admac_of_match, ++ }, ++ .probe = admac_probe, ++ .remove = admac_remove, ++}; ++module_platform_driver(apple_admac_driver); ++ ++MODULE_AUTHOR("Martin PoviÅ¡er "); ++MODULE_DESCRIPTION("Driver for Audio DMA Controller (ADMAC) in Apple SoCs"); ++MODULE_LICENSE("GPL v2"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0072-ASoC-apple-mca-Add-platform-driver-for-Apple-SoCs.patch b/target/linux/silicon/patches-5.19/0072-ASoC-apple-mca-Add-platform-driver-for-Apple-SoCs.patch new file mode 100644 index 000000000..fb074a512 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0072-ASoC-apple-mca-Add-platform-driver-for-Apple-SoCs.patch @@ -0,0 +1,1364 @@ +From d9574a2027fbf3a6ffd1b32ca6838cd4e77519f2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 10:33:16 +0100 +Subject: [PATCH 072/171] ASoC: apple-mca: Add platform driver for Apple SoCs + +Add ASoC platform driver for the MCA block found on Apple SoCs +from the "Apple Silicon" family. +--- + sound/soc/Kconfig | 1 + + sound/soc/Makefile | 1 + + sound/soc/apple/Kconfig | 11 + + sound/soc/apple/Makefile | 3 + + sound/soc/apple/mca.c | 1287 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 1303 insertions(+) + create mode 100644 sound/soc/apple/Kconfig + create mode 100644 sound/soc/apple/Makefile + create mode 100644 sound/soc/apple/mca.c + +diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig +index 7d4747b6bab2..848fbae26c3b 100644 +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -68,6 +68,7 @@ config SND_SOC_ACPI + # All the supported SoCs + source "sound/soc/adi/Kconfig" + source "sound/soc/amd/Kconfig" ++source "sound/soc/apple/Kconfig" + source "sound/soc/atmel/Kconfig" + source "sound/soc/au1x/Kconfig" + source "sound/soc/bcm/Kconfig" +diff --git a/sound/soc/Makefile b/sound/soc/Makefile +index d4528962ac34..9b198d4edf37 100644 +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -34,6 +34,7 @@ obj-$(CONFIG_SND_SOC_ACPI) += snd-soc-acpi.o + obj-$(CONFIG_SND_SOC) += snd-soc-core.o + obj-$(CONFIG_SND_SOC) += codecs/ + obj-$(CONFIG_SND_SOC) += generic/ ++obj-$(CONFIG_SND_SOC) += apple/ + obj-$(CONFIG_SND_SOC) += adi/ + obj-$(CONFIG_SND_SOC) += amd/ + obj-$(CONFIG_SND_SOC) += atmel/ +diff --git a/sound/soc/apple/Kconfig b/sound/soc/apple/Kconfig +new file mode 100644 +index 000000000000..ebe66d713b96 +--- /dev/null ++++ b/sound/soc/apple/Kconfig +@@ -0,0 +1,11 @@ ++config SND_SOC_APPLE_MCA ++ tristate "Apple Silicon MCA driver" ++ depends on ARCH_APPLE || COMPILE_TEST ++ select SND_DMAENGINE_PCM ++ select CONFIG_COMMON_CLK ++ select APPLE_ADMAC ++ select APPLE_NCO ++ default ARCH_APPLE ++ help ++ This option enables an ASoC platform driver for MCA blocks found ++ on Apple Silicon SoCs. +diff --git a/sound/soc/apple/Makefile b/sound/soc/apple/Makefile +new file mode 100644 +index 000000000000..c1e492d57649 +--- /dev/null ++++ b/sound/soc/apple/Makefile +@@ -0,0 +1,3 @@ ++snd-soc-apple-mca-objs := mca.o ++ ++obj-$(CONFIG_SND_SOC_APPLE_MCA) += snd-soc-apple-mca.o +diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c +new file mode 100644 +index 000000000000..846dba0383a1 +--- /dev/null ++++ b/sound/soc/apple/mca.c +@@ -0,0 +1,1287 @@ ++#define USE_RXB_FOR_CAPTURE ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* relative to cluster base */ ++#define REG_STATUS 0x0 ++#define STATUS_MCLK_EN BIT(0) ++#define REG_MCLK_CONF 0x4 ++#define MCLK_CONF_DIV GENMASK(11, 8) ++ ++#define REG_SYNCGEN_STATUS 0x100 ++#define SYNCGEN_STATUS_EN BIT(0) ++#define REG_SYNCGEN_MCLK_SEL 0x104 ++#define SYNCGEN_MCLK_SEL GENMASK(3, 0) ++#define REG_SYNCGEN_HI_PERIOD 0x108 ++#define REG_SYNCGEN_LO_PERIOD 0x10c ++ ++#define REG_PORT_ENABLES 0x600 ++#define PORT_ENABLES_CLOCKS GENMASK(2, 1) ++#define PORT_ENABLES_TX_DATA BIT(3) ++#define REG_PORT_CLOCK_SEL 0x604 ++#define PORT_CLOCK_SEL GENMASK(11, 8) ++#define REG_PORT_DATA_SEL 0x608 ++#define PORT_DATA_SEL_TXA(cl) (1 << ((cl)*2)) ++#define PORT_DATA_SEL_TXB(cl) (2 << ((cl)*2)) ++ ++#define REG_INTSTATE 0x700 ++#define REG_INTMASK 0x704 ++ ++/* bases of serdes units (relative to cluster) */ ++#define CLUSTER_RXA_OFF 0x200 ++#define CLUSTER_TXA_OFF 0x300 ++#define CLUSTER_RXB_OFF 0x400 ++#define CLUSTER_TXB_OFF 0x500 ++ ++#define CLUSTER_TX_OFF CLUSTER_TXA_OFF ++ ++#ifndef USE_RXB_FOR_CAPTURE ++#define CLUSTER_RX_OFF CLUSTER_RXA_OFF ++#else ++#define CLUSTER_RX_OFF CLUSTER_RXB_OFF ++#endif ++ ++/* relative to serdes unit base */ ++#define REG_SERDES_STATUS 0x00 ++#define SERDES_STATUS_EN BIT(0) ++#define SERDES_STATUS_RST BIT(1) ++#define REG_TX_SERDES_CONF 0x04 ++#define REG_RX_SERDES_CONF 0x08 ++#define SERDES_CONF_NCHANS GENMASK(3, 0) ++#define SERDES_CONF_WIDTH_MASK GENMASK(8, 4) ++#define SERDES_CONF_WIDTH_16BIT 0x40 ++#define SERDES_CONF_WIDTH_20BIT 0x80 ++#define SERDES_CONF_WIDTH_24BIT 0xc0 ++#define SERDES_CONF_WIDTH_32BIT 0x100 ++#define SERDES_CONF_BCLK_POL 0x400 ++#define SERDES_CONF_LSB_FIRST 0x800 ++#define SERDES_CONF_UNK1 BIT(12) ++#define SERDES_CONF_UNK2 BIT(13) ++#define SERDES_CONF_UNK3 BIT(14) ++#define SERDES_CONF_NO_DATA_FEEDBACK BIT(14) ++#define SERDES_CONF_SYNC_SEL GENMASK(18, 16) ++#define SERDES_CONF_SOME_RST BIT(19) ++#define REG_TX_SERDES_BITSTART 0x08 ++#define REG_RX_SERDES_BITSTART 0x0c ++#define REG_TX_SERDES_SLOTMASK 0x0c ++#define REG_RX_SERDES_SLOTMASK 0x10 ++#define REG_RX_SERDES_PORT 0x04 ++ ++/* relative to switch base */ ++#define REG_DMA_ADAPTER_A(cl) (0x8000 * (cl)) ++#define REG_DMA_ADAPTER_B(cl) (0x8000 * (cl) + 0x4000) ++#define DMA_ADAPTER_TX_LSB_PAD GENMASK(4, 0) ++#define DMA_ADAPTER_TX_NCHANS GENMASK(6, 5) ++#define DMA_ADAPTER_RX_MSB_PAD GENMASK(12, 8) ++#define DMA_ADAPTER_RX_NCHANS GENMASK(14, 13) ++#define DMA_ADAPTER_NCHANS GENMASK(22, 20) ++ ++#define SWITCH_STRIDE 0x8000 ++#define CLUSTER_STRIDE 0x4000 ++ ++#define MAX_NCLUSTERS 6 ++ ++struct mca_dai { ++ struct mca_route *in_route; ++ unsigned int tdm_slots; ++ unsigned int tdm_slot_width; ++ unsigned int tdm_tx_mask; ++ unsigned int tdm_rx_mask; ++ unsigned long set_sysclk; ++ u32 fmt_bitstart; ++ bool fmt_bclk_inv; ++}; ++ ++struct mca_cluster { ++ int no; ++ struct mca_data *host; ++ struct device *pd_dev; ++ struct clk *clk_parent; ++ struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1]; ++ struct mca_dai port; ++}; ++ ++#define mca_dai_to_cluster(dai) \ ++ container_of(dai, struct mca_cluster, port) ++ ++struct mca_data { ++ struct device *dev; ++ ++ __iomem void *base; ++ __iomem void *switch_base; ++ ++ struct device *pd_dev; ++ struct device_link *pd_link; ++ ++ int nclusters; ++ struct mca_cluster clusters[]; ++}; ++ ++struct mca_route { ++ struct mca_data *host; ++ ++ struct clk *clk_parent; ++ bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1]; ++ ++ struct device_link *pd_link; ++ ++ /* ++ * Cluster selectors for different facilities ++ * that constitute the 'route' ++ */ ++ int clock; ++ int syncgen; ++ int serdes; ++ ++ int ndais; ++ struct mca_dai *dais[]; ++}; ++ ++static struct mca_route *mca_route_for_rtd(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0); ++ struct mca_data *mca = snd_soc_dai_get_drvdata(dai); ++ return mca->clusters[dai->id].port.in_route; ++} ++ ++static struct mca_dai *mca_dai_for_soc_dai(struct snd_soc_dai *dai) ++{ ++ struct mca_data *mca = snd_soc_dai_get_drvdata(dai); ++ return &mca->clusters[dai->id].port; ++} ++ ++static u32 mca_peek(struct mca_data *mca, int cluster, int regoffset) ++{ ++ int offset = (CLUSTER_STRIDE * cluster) + regoffset; ++ ++ return readl_relaxed(mca->base + offset); ++} ++ ++static void mca_poke(struct mca_data *mca, int cluster, ++ int regoffset, u32 val) ++{ ++ int offset = (CLUSTER_STRIDE * cluster) + regoffset; ++ dev_dbg(mca->dev, "regs: %x <- %x\n", offset, val); ++ writel_relaxed(val, mca->base + offset); ++} ++ ++static void mca_modify(struct mca_data *mca, int cluster, ++ int regoffset, u32 mask, u32 val) ++{ ++ int offset = (CLUSTER_STRIDE * cluster) + regoffset; ++ __iomem void *p = mca->base + offset; ++ u32 newval = (val & mask) | (readl_relaxed(p) & ~mask); ++ dev_dbg(mca->dev, "regs: %x <- %x\n", offset, newval); ++ writel_relaxed(newval, p); ++} ++ ++static int mca_reset_dais(struct mca_route *route, ++ struct snd_pcm_substream *substream, int cmd) ++{ ++ struct mca_data *mca = route->host; ++ bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; ++ int serdes_unit = is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ mca_modify(mca, route->serdes, ++ serdes_unit + REG_SERDES_STATUS, ++ SERDES_STATUS_EN | SERDES_STATUS_RST, ++ SERDES_STATUS_RST); ++ mca_modify(mca, route->serdes, ++ serdes_unit + ++ (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF), ++ SERDES_CONF_SOME_RST, SERDES_CONF_SOME_RST); ++ (void)mca_peek(mca, route->serdes, ++ serdes_unit + ++ (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF)); ++ mca_modify(mca, route->serdes, ++ serdes_unit + ++ (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF), ++ SERDES_STATUS_RST, 0); ++ WARN_ON(mca_peek(mca, route->serdes, REG_SERDES_STATUS) ++ & SERDES_STATUS_RST); ++ ++ dev_dbg(mca->dev, "trigger reset\n"); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int mca_trigger_dais(struct mca_route *route, ++ struct snd_pcm_substream *substream, int cmd) ++{ ++ struct mca_data *mca = route->host; ++ bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; ++ int serdes_unit = is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ mca_modify(mca, route->serdes, ++ serdes_unit + REG_SERDES_STATUS, ++ SERDES_STATUS_EN | SERDES_STATUS_RST, ++ SERDES_STATUS_EN); ++ ++ dev_dbg(mca->dev, "trigger start\n"); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ mca_modify(mca, route->serdes, ++ serdes_unit + REG_SERDES_STATUS, ++ SERDES_STATUS_EN, 0); ++ ++ dev_dbg(mca->dev, "trigger stop\n"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static bool mca_clocks_in_use(struct mca_route *route) ++{ ++ int stream; ++ ++ for_each_pcm_streams(stream) ++ if (route->clocks_in_use[stream]) ++ return true; ++ return false; ++} ++ ++static int mca_prepare(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ++ struct mca_route *route = mca_route_for_rtd(rtd); ++ struct mca_data *mca = route->host; ++ struct mca_cluster *cluster; ++ ++ int ret; ++ ++ if (!mca_clocks_in_use(route)) { ++ ret = clk_prepare_enable(route->clk_parent); ++ if (ret) { ++ dev_err(mca->dev, "unable to enable parent clock %d: %d\n", ++ route->clock, ret); ++ return ret; ++ } ++ ++ /* ++ * We only prop-up PD of the syncgen cluster. That is okay ++ * in combination with the way we are constructing 'routes' ++ * where only single cluster needs powering up. ++ */ ++ cluster = &mca->clusters[route->syncgen]; ++ route->pd_link = device_link_add(rtd->dev, cluster->pd_dev, ++ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | ++ DL_FLAG_RPM_ACTIVE); ++ if (!route->pd_link) { ++ dev_err(mca->dev, "unable to prop-up cluster's power domain " ++ "(cluster %d)\n", route->syncgen); ++ clk_disable_unprepare(route->clk_parent); ++ return -EINVAL; ++ } ++ ++ mca_poke(mca, route->syncgen, REG_SYNCGEN_MCLK_SEL, ++ route->clock + 1); ++ mca_modify(mca, route->syncgen, ++ REG_SYNCGEN_STATUS, ++ SYNCGEN_STATUS_EN, SYNCGEN_STATUS_EN); ++ mca_modify(mca, route->clock, ++ REG_STATUS, ++ STATUS_MCLK_EN, STATUS_MCLK_EN); ++ } ++ ++ route->clocks_in_use[substream->stream] = true; ++ ++ return 0; ++} ++ ++static int mca_hw_free(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream) ++{ ++ struct mca_route *route = mca_route_for_rtd(asoc_substream_to_rtd(substream)); ++ struct mca_data *mca = route->host; ++ ++ if (!mca_clocks_in_use(route)) ++ return 0; /* Nothing to do */ ++ ++ route->clocks_in_use[substream->stream] = false; ++ ++ if (!mca_clocks_in_use(route)) { ++ mca_modify(mca, route->syncgen, ++ REG_SYNCGEN_STATUS, ++ SYNCGEN_STATUS_EN, 0); ++ mca_modify(mca, route->clock, ++ REG_STATUS, ++ STATUS_MCLK_EN, 0); ++ ++ device_link_del(route->pd_link); ++ clk_disable_unprepare(route->clk_parent); ++ } ++ ++ return 0; ++} ++ ++#define div_ceil(A, B) ((A)/(B) + ((A)%(B) ? 1 : 0)) ++ ++static int mca_configure_serdes(struct mca_data *mca, int cluster, int serdes_unit, ++ unsigned int mask, int slots, int nchans, int slot_width, bool is_tx, int port) ++{ ++ u32 serdes_conf; ++ ++ serdes_conf = FIELD_PREP(SERDES_CONF_NCHANS, max(slots, 1) - 1); ++ ++ switch (slot_width) { ++ case 16: ++ serdes_conf |= SERDES_CONF_WIDTH_16BIT; ++ break; ++ case 20: ++ serdes_conf |= SERDES_CONF_WIDTH_20BIT; ++ break; ++ case 24: ++ serdes_conf |= SERDES_CONF_WIDTH_24BIT; ++ break; ++ case 32: ++ serdes_conf |= SERDES_CONF_WIDTH_32BIT; ++ break; ++ default: ++ goto err; ++ } ++ ++ mca_modify(mca, cluster, ++ serdes_unit + (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF), ++ SERDES_CONF_WIDTH_MASK | SERDES_CONF_NCHANS, serdes_conf); ++ ++ if (is_tx) { ++ mca_poke(mca, cluster, ++ serdes_unit + REG_TX_SERDES_SLOTMASK, ++ 0xffffffff); ++ /* ++ * TODO: Actually consider where the hot bits ++ * are placed in the mask, instead of assuming ++ * it's the bottom bits. ++ */ ++ mca_poke(mca, cluster, ++ serdes_unit + REG_TX_SERDES_SLOTMASK + 0x4, ++ ~((u32) mask & ((1 << nchans) - 1))); ++ mca_poke(mca, cluster, ++ serdes_unit + REG_TX_SERDES_SLOTMASK + 0x8, ++ 0xffffffff); ++ mca_poke(mca, cluster, ++ serdes_unit + REG_TX_SERDES_SLOTMASK + 0xc, ++ ~((u32) mask)); ++ } else { ++ mca_poke(mca, cluster, ++ serdes_unit + REG_RX_SERDES_SLOTMASK, ++ 0xffffffff); ++ mca_poke(mca, cluster, ++ serdes_unit + REG_RX_SERDES_SLOTMASK + 0x4, ++ ~((u32) mask)); ++ mca_poke(mca, cluster, ++ serdes_unit + REG_RX_SERDES_PORT, ++ 1 << port); ++ } ++ ++ return 0; ++ ++err: ++ dev_err(mca->dev, "unsupported SERDES configuration requested (mask=0x%x slots=%d slot_width=%d)\n", ++ mask, slots, slot_width); ++ return -EINVAL; ++} ++ ++static int mca_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ++ unsigned int rx_mask, int slots, int slot_width) ++{ ++ struct mca_dai *mdai = mca_dai_for_soc_dai(dai); ++ ++ mdai->tdm_slots = slots; ++ mdai->tdm_slot_width = slot_width; ++ mdai->tdm_tx_mask = tx_mask; ++ mdai->tdm_rx_mask = rx_mask; ++ ++ return 0; ++} ++ ++static int mca_dai_set_fmt(struct snd_soc_dai *dai, ++ unsigned int fmt) ++{ ++ struct mca_data *mca = snd_soc_dai_get_drvdata(dai); ++ struct mca_dai *mdai = mca_dai_for_soc_dai(dai); ++ struct mca_route *route = mdai->in_route; ++ bool bclk_inv = false, fpol_inv = false; ++ u32 bitstart; ++ ++ if (WARN_ON(route)) ++ return -EBUSY; ++ ++ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != ++ SND_SOC_DAIFMT_CBC_CFC) ++ goto err; ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ fpol_inv = 0; ++ bitstart = 1; ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ fpol_inv = 1; ++ bitstart = 0; ++ break; ++ default: ++ goto err; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_IF: ++ case SND_SOC_DAIFMT_IB_IF: ++ fpol_inv ^= 1; ++ break; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ case SND_SOC_DAIFMT_NB_IF: ++ bclk_inv = true; ++ } ++ ++ if (!fpol_inv) ++ goto err; ++ ++ mdai->fmt_bitstart = bitstart; ++ mdai->fmt_bclk_inv = bclk_inv; ++ ++ return 0; ++ ++err: ++ dev_err(mca->dev, "unsupported DAI format (0x%x) requested\n", fmt); ++ return -EINVAL; ++} ++ ++static int mca_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, ++ unsigned int freq, int dir) ++{ ++ int ret; ++ ++ struct mca_dai *mdai = mca_dai_for_soc_dai(dai); ++ struct mca_route *route = mdai->in_route; ++ ++ if (freq == mdai->set_sysclk) ++ return 0; ++ ++ if (mca_clocks_in_use(route)) ++ return -EBUSY; ++ ++ ret = clk_set_rate(route->clk_parent, freq); ++ if (!ret) ++ mdai->set_sysclk = freq; ++ return ret; ++} ++ ++static const struct snd_soc_dai_ops mca_dai_ops = { ++ .set_fmt = mca_dai_set_fmt, ++ .set_sysclk = mca_dai_set_sysclk, ++ .set_tdm_slot = mca_dai_set_tdm_slot, ++}; ++ ++static int mca_set_runtime_hwparams(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream, struct dma_chan *chan) ++{ ++ struct device *dma_dev = chan->device->dev; ++ struct snd_dmaengine_dai_dma_data dma_data = {}; ++ int ret; ++ ++ struct snd_pcm_hardware hw; ++ ++ memset(&hw, 0, sizeof(hw)); ++ ++ hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_INTERLEAVED; ++ hw.periods_min = 2; ++ hw.periods_max = UINT_MAX; ++ hw.period_bytes_min = 256; ++ hw.period_bytes_max = dma_get_max_seg_size(dma_dev); ++ hw.buffer_bytes_max = SIZE_MAX; ++ hw.fifo_size = 16; ++ ++ ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, ++ &dma_data, &hw, chan); ++ ++ if (ret) ++ return ret; ++ ++ return snd_soc_set_runtime_hwparams(substream, &hw); ++} ++ ++static int mca_pcm_open(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream) ++{ ++ struct mca_data *mca = snd_soc_component_get_drvdata(component); ++ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ++ struct mca_route *route = mca_route_for_rtd(rtd); ++ struct dma_chan *chan = mca->clusters[route->serdes].dma_chans[substream->stream]; ++ int ret, i; ++ ++ if (WARN_ON(!route)) ++ return -EINVAL; ++ ++ for (i = 0; i < route->ndais; i++) { ++ int dai_no = mca_dai_to_cluster(route->dais[i])->no; ++ ++ mca_poke(mca, dai_no, REG_PORT_ENABLES, ++ PORT_ENABLES_CLOCKS | PORT_ENABLES_TX_DATA); ++ mca_poke(mca, dai_no, REG_PORT_CLOCK_SEL, ++ FIELD_PREP(PORT_CLOCK_SEL, route->syncgen + 1)); ++ mca_poke(mca, dai_no, REG_PORT_DATA_SEL, ++ PORT_DATA_SEL_TXA(route->serdes)); ++ } ++ ++ switch (substream->stream) { ++ case SNDRV_PCM_STREAM_PLAYBACK: ++ mca_modify(mca, route->serdes, CLUSTER_TX_OFF + REG_TX_SERDES_CONF, ++ SERDES_CONF_UNK1 | SERDES_CONF_UNK2 | SERDES_CONF_UNK3, ++ SERDES_CONF_UNK1 | SERDES_CONF_UNK2 | SERDES_CONF_UNK3); ++ mca_modify(mca, route->serdes, CLUSTER_TX_OFF + REG_TX_SERDES_CONF, ++ SERDES_CONF_SYNC_SEL, ++ FIELD_PREP(SERDES_CONF_SYNC_SEL, route->syncgen + 1)); ++ break; ++ ++ case SNDRV_PCM_STREAM_CAPTURE: ++ mca_modify(mca, route->serdes, CLUSTER_RX_OFF + REG_RX_SERDES_CONF, ++ SERDES_CONF_UNK1 | SERDES_CONF_UNK2 | SERDES_CONF_UNK3 ++ | SERDES_CONF_NO_DATA_FEEDBACK, ++ SERDES_CONF_UNK1 | SERDES_CONF_UNK2 ++ | SERDES_CONF_NO_DATA_FEEDBACK); ++ mca_modify(mca, route->serdes, CLUSTER_RX_OFF + REG_RX_SERDES_CONF, ++ SERDES_CONF_SYNC_SEL, ++ FIELD_PREP(SERDES_CONF_SYNC_SEL, route->syncgen + 1)); ++ break; ++ ++ default: ++ break; ++ } ++ ++ ret = mca_set_runtime_hwparams(component, substream, chan); ++ if (ret) ++ return ret; ++ ++ return snd_dmaengine_pcm_open(substream, chan); ++} ++ ++static int mca_hw_params_dma(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); ++ struct dma_slave_config slave_config; ++ int ret; ++ ++ memset(&slave_config, 0, sizeof(slave_config)); ++ ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config); ++ if (ret < 0) ++ return ret; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ slave_config.dst_port_window_size = min((int) params_channels(params), 4); ++ else ++ slave_config.src_port_window_size = min((int) params_channels(params), 4); ++ ++ return dmaengine_slave_config(chan, &slave_config); ++} ++ ++static int mca_get_dais_tdm_slots(struct mca_route *route, bool is_tx, ++ int *slot_width, int *slots, int *mask) ++{ ++ struct mca_dai *mdai; ++ unsigned int tdm_slot_width, tdm_tx_mask, tdm_rx_mask; ++ unsigned int tdm_slots = 0; ++ int i; ++ ++#define __pick_up_dai_tdm_param(param) \ ++ { \ ++ if (tdm_slots && mdai->param != param) \ ++ return -EINVAL; \ ++ param = mdai->param; \ ++ } ++ ++ for (i = 0; i < route->ndais; i++) { ++ mdai = route->dais[i]; ++ ++ if (mdai->tdm_slots) { ++ if (is_tx) { ++ __pick_up_dai_tdm_param(tdm_tx_mask); ++ } else { ++ __pick_up_dai_tdm_param(tdm_rx_mask); ++ } ++ ++ __pick_up_dai_tdm_param(tdm_slot_width); ++ __pick_up_dai_tdm_param(tdm_slots); ++ } ++ } ++ ++ if (tdm_slots) { ++ *slots = tdm_slots; ++ *slot_width = tdm_slot_width; ++ *mask = is_tx ? tdm_tx_mask : tdm_rx_mask; ++ } ++ ++ return 0; ++} ++ ++static int mca_get_dais_sysclk(struct mca_route *route, unsigned long *sysclk) ++{ ++ struct mca_dai *mdai; ++ unsigned long set_sysclk = 0; ++ int i; ++ ++ for (i = 0; i < route->ndais; i++) { ++ mdai = route->dais[i]; ++ ++ if (!mdai->set_sysclk) ++ continue; ++ ++ if (set_sysclk && mdai->set_sysclk != set_sysclk) ++ return -EINVAL; ++ ++ set_sysclk = mdai->set_sysclk; ++ } ++ ++ if (set_sysclk) ++ *sysclk = set_sysclk; ++ ++ return 0; ++} ++ ++static int mca_hw_params_dais(struct mca_route *route, ++ struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct mca_data *mca = route->host; ++ struct device *dev = route->host->dev; ++ bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; ++ unsigned int samp_rate = params_rate(params); ++ bool refine_tdm = false; ++ unsigned int tdm_slots, tdm_slot_width, tdm_mask; ++ unsigned long bclk_ratio; ++ unsigned long sysclk; ++ u32 regval, pad; ++ int ret, dai_no, nchans_ceiled; ++ ++ tdm_slot_width = 0; ++ ret = mca_get_dais_tdm_slots(route, is_tx, ++ &tdm_slot_width, &tdm_slots, &tdm_mask); ++ ++ if (ret < 0) { ++ dev_err(dev, "bad dai TDM settings\n"); ++ return ret; ++ } ++ ++ if (!tdm_slot_width) { ++ /* ++ * We were not given TDM settings from above, set initial ++ * guesses which will later be refined. ++ */ ++ tdm_slot_width = params_width(params); ++ tdm_slots = params_channels(params); ++ refine_tdm = true; ++ } ++ ++ sysclk = 0; ++ ret = mca_get_dais_sysclk(route, &sysclk); ++ ++ if (ret < 0) { ++ dev_err(dev, "bad dai sysclk settings\n"); ++ return ret; ++ } ++ ++ if (sysclk) { ++ bclk_ratio = sysclk / samp_rate; ++ } else { ++ bclk_ratio = tdm_slot_width * tdm_slots; ++ } ++ ++ if (refine_tdm) { ++ int nchannels = params_channels(params); ++ ++ if (nchannels > 2) { ++ dev_err(dev, "nchannels > 2 and no TDM\n"); ++ return -EINVAL; ++ } ++ ++ if ((bclk_ratio % nchannels) != 0) { ++ dev_err(dev, "bclk ratio (%ld) not divisible by nchannels (%d)\n", ++ bclk_ratio, nchannels); ++ return -EINVAL; ++ } ++ ++ tdm_slot_width = bclk_ratio / nchannels; ++ ++ if (tdm_slot_width > 32 && nchannels == 1) ++ tdm_slot_width = 32; ++ ++ if (tdm_slot_width < params_width(params)) { ++ dev_err(dev, "TDM slots too narrow tdm=%d params=%d\n", ++ tdm_slot_width, params_width(params)); ++ return -EINVAL; ++ } ++ ++ tdm_mask = (1 << tdm_slots) - 1; ++ } ++ ++ dai_no = mca_dai_to_cluster(route->dais[0])->no; ++ ++ ret = mca_configure_serdes(mca, route->serdes, is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF, ++ tdm_mask, tdm_slots, params_channels(params), ++ tdm_slot_width, is_tx, dai_no); ++ if (ret) ++ return ret; ++ ++ pad = 32 - params_width(params); ++ ++ /* ++ * TODO: Here the register semantics aren't clear. ++ */ ++ nchans_ceiled = min((int) params_channels(params), 4); ++ regval = FIELD_PREP(DMA_ADAPTER_NCHANS, nchans_ceiled) ++ | FIELD_PREP(DMA_ADAPTER_TX_NCHANS, 0x2) ++ | FIELD_PREP(DMA_ADAPTER_RX_NCHANS, 0x2) ++ | FIELD_PREP(DMA_ADAPTER_TX_LSB_PAD, pad) ++ | FIELD_PREP(DMA_ADAPTER_RX_MSB_PAD, pad); ++ ++#ifndef USE_RXB_FOR_CAPTURE ++ writel_relaxed(regval, mca->switch_base + REG_DMA_ADAPTER_A(route->serdes)); ++#else ++ if (is_tx) ++ writel_relaxed(regval, mca->switch_base + REG_DMA_ADAPTER_A(route->serdes)); ++ else ++ writel_relaxed(regval, mca->switch_base + REG_DMA_ADAPTER_B(route->serdes)); ++#endif ++ ++ if (!mca_clocks_in_use(route)) { ++ /* ++ * Set up FSYNC duty cycle to be as even as possible. ++ */ ++ mca_poke(mca, route->syncgen, ++ REG_SYNCGEN_HI_PERIOD, ++ (bclk_ratio / 2) - 1); ++ mca_poke(mca, route->syncgen, ++ REG_SYNCGEN_LO_PERIOD, ++ ((bclk_ratio + 1) / 2) - 1); ++ ++ mca_poke(mca, route->clock, ++ REG_MCLK_CONF, ++ FIELD_PREP(MCLK_CONF_DIV, 0x1)); ++ ++ ret = clk_set_rate(route->clk_parent, bclk_ratio * samp_rate); ++ if (ret) { ++ dev_err(mca->dev, "unable to set parent clock %d: %d\n", ++ route->clock, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int mca_hw_params(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct mca_route *route = mca_route_for_rtd( ++ asoc_substream_to_rtd(substream)); ++ int ret; ++ ++ ret = mca_hw_params_dma(component, substream, params); ++ if (ret < 0) ++ return ret; ++ ++ return mca_hw_params_dais(route, substream, params); ++} ++ ++static int mca_close(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream) ++{ ++ return snd_dmaengine_pcm_close(substream); ++} ++ ++#if 0 ++static void mca_flush_adapter_fifo(struct mca_route *route) ++{ ++ struct mca_data *mca = route->host; ++ int i; ++ u32 ptr; ++ ++ ptr = readl_relaxed(mca->switch_base + REG_DMA_ADAPTER_A(route->serdes) + 0x8); ++ dev_dbg(route->host->dev, "flush fifo: entered at %x\n", ptr); ++ ++ for (i = 0; i < 256; i++) { ++ if (ptr == 0xbc) ++ break; ++ ++ writel_relaxed(0, mca->switch_base + REG_DMA_ADAPTER_A(route->serdes) + 0xc); ++ (void) readl_relaxed(mca->switch_base + REG_DMA_ADAPTER_A(route->serdes) + 0xc); ++ ++ ptr = readl_relaxed(mca->switch_base + REG_DMA_ADAPTER_A(route->serdes) + 0x8); ++ } ++ ++ dev_dbg(route->host->dev, "flush fifo: left at %x\n", ptr); ++} ++#endif ++ ++static int mca_trigger(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream, int cmd) ++{ ++ struct mca_route *route = mca_route_for_rtd(asoc_substream_to_rtd(substream)); ++ int ret; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ ret = mca_reset_dais(route, substream, cmd); ++ if (ret < 0) ++ return ret; ++ ++ //mca_flush_adapter_fifo(route); ++ ++ ret = snd_dmaengine_pcm_trigger(substream, cmd); ++ if (ret < 0) ++ return ret; ++ ++ ret = mca_trigger_dais(route, substream, cmd); ++ if (ret < 0) ++ goto revert_dmaengine; ++ return 0; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ ret = mca_trigger_dais(route, substream, cmd); ++ if (ret < 0) ++ return ret; ++ ++ return snd_dmaengine_pcm_trigger(substream, cmd); ++ } ++ ++revert_dmaengine: ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ snd_dmaengine_pcm_trigger(substream, SNDRV_PCM_TRIGGER_STOP); ++ break; ++ ++ case SNDRV_PCM_TRIGGER_RESUME: ++ snd_dmaengine_pcm_trigger(substream, SNDRV_PCM_TRIGGER_STOP); ++ break; ++ ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ snd_dmaengine_pcm_trigger(substream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); ++ break; ++ } ++ ++ return ret; ++} ++ ++static snd_pcm_uframes_t mca_pointer(struct snd_soc_component *component, ++ struct snd_pcm_substream *substream) ++{ ++ return snd_dmaengine_pcm_pointer(substream); ++} ++ ++static int mca_pcm_new(struct snd_soc_component *component, ++ struct snd_soc_pcm_runtime *rtd) ++{ ++ struct mca_data *mca = snd_soc_component_get_drvdata(component); ++ struct mca_route *route; ++ struct snd_soc_dai *dai; ++ struct mca_dai *mdai; ++ struct mca_cluster *cluster; ++ unsigned int i; ++ int ret = 0; ++ ++ route = devm_kzalloc(mca->dev, struct_size(route, dais, rtd->num_cpus), GFP_KERNEL); ++ ++ if (!route) ++ return -ENOMEM; ++ ++ route->host = mca; ++ ++ for_each_rtd_cpu_dais(rtd, i, dai) { ++ if (dai->component != component) { ++ dev_err(mca->dev, "foreign CPU dai in PCM\n"); ++ goto exit_free; ++ } ++ ++ mdai = &mca->clusters[dai->id].port; ++ ++ if (WARN_ON(mdai->in_route)) { ++ ret = -EINVAL; ++ goto exit_free; ++ } ++ ++ mdai->in_route = route; ++ route->dais[i] = mdai; ++ } ++ route->ndais = rtd->num_cpus; ++ ++ /* ++ * Pick facilities from cluster of the first dai. ++ */ ++ cluster = mca_dai_to_cluster(route->dais[0]); ++ ++ route->clock = cluster->no; ++ route->syncgen = cluster->no; ++ route->serdes = cluster->no; ++ ++ route->clk_parent = cluster->clk_parent; ++ ++ for_each_pcm_streams(i) { ++ struct snd_pcm_substream *substream = rtd->pcm->streams[i].substream; ++ struct dma_chan *chan = cluster->dma_chans[i]; ++ ++ if (!substream) ++ continue; ++ ++ if (!chan) { ++ dev_err(component->dev, "missing DMA channel for stream %d " ++ "on serdes %d\n", i, route->serdes); ++ return -EINVAL; ++ } ++ ++ snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV_IRAM, ++ chan->device->dev, 512*1024*6, ++ SIZE_MAX); ++ } ++ ++ /* Look at the first dai for daifmt settings */ ++ mdai = route->dais[0]; ++ ++ mca_modify(mca, route->serdes, CLUSTER_TX_OFF + REG_TX_SERDES_CONF, ++ SERDES_CONF_BCLK_POL, ++ mdai->fmt_bclk_inv ? SERDES_CONF_BCLK_POL : 0); ++ mca_poke(mca, route->serdes, CLUSTER_TX_OFF + REG_TX_SERDES_BITSTART, ++ mdai->fmt_bitstart); ++ mca_modify(mca, route->serdes, CLUSTER_RX_OFF + REG_RX_SERDES_CONF, ++ SERDES_CONF_BCLK_POL, ++ mdai->fmt_bclk_inv ? SERDES_CONF_BCLK_POL : 0); ++ mca_poke(mca, route->serdes, CLUSTER_RX_OFF + REG_RX_SERDES_BITSTART, ++ mdai->fmt_bitstart); ++ ++ return ret; ++ ++exit_free: ++ devm_kfree(mca->dev, route); ++ return ret; ++} ++ ++static void mca_pcm_free(struct snd_soc_component *component, ++ struct snd_pcm *pcm) ++{ ++ struct mca_data *mca = snd_soc_component_get_drvdata(component); ++ struct mca_route *route = mca_route_for_rtd(asoc_pcm_to_rtd(pcm)); ++ int i; ++ ++ for (i = 0; i < route->ndais; i++) ++ route->dais[i]->in_route = NULL; ++ ++ devm_kfree(mca->dev, route); ++} ++ ++#if 0 ++static irqreturn_t mca_interrupt(int irq, void *devid) ++{ ++ struct mca_cluster *cl = devid; ++ struct mca_data *mca = cl->host; ++ u32 mask = mca_peek(mca, cl->no, REG_INTMASK); ++ u32 state = mca_peek(mca, cl->no, REG_INTSTATE); ++ u32 cleared; ++ ++ mca_poke(mca, cl->no, REG_INTSTATE, state & mask); ++ cleared = state & ~mca_peek(mca, cl->no, REG_INTSTATE); ++ ++ dev_dbg(mca->dev, "cl%d: took an interrupt. state=%x mask=%x unmasked=%x cleared=%x\n", ++ cl->no, state, mask, state & mask, cleared); ++ ++ mca_poke(mca, cl->no, REG_INTMASK, mask & (~state | cleared)); ++ ++ return true ? IRQ_HANDLED : IRQ_NONE; ++} ++#endif ++ ++static const struct snd_soc_component_driver mca_component = { ++ .name = "apple-mca", ++ .open = mca_pcm_open, ++ .close = mca_close, ++ .prepare = mca_prepare, ++ .hw_free = mca_hw_free, ++ .hw_params = mca_hw_params, ++ .trigger = mca_trigger, ++ .pointer = mca_pointer, ++ .pcm_construct = mca_pcm_new, ++ .pcm_destruct = mca_pcm_free, ++}; ++ ++static void apple_mca_release(struct mca_data *mca) ++{ ++ int i, stream; ++ ++ for (i = 0; i < mca->nclusters; i++) { ++ struct mca_cluster *cl = &mca->clusters[i]; ++ ++ for_each_pcm_streams(stream) { ++ if (IS_ERR_OR_NULL(cl->dma_chans[stream])) ++ continue; ++ ++ dma_release_channel(cl->dma_chans[stream]); ++ } ++ ++ if (!IS_ERR_OR_NULL(cl->clk_parent)) ++ clk_put(cl->clk_parent); ++ ++ if (!IS_ERR_OR_NULL(cl->pd_dev)) ++ dev_pm_domain_detach(cl->pd_dev, true); ++ } ++ ++ if (mca->pd_link) ++ device_link_del(mca->pd_link); ++ ++ if (!IS_ERR_OR_NULL(mca->pd_dev)) ++ dev_pm_domain_detach(mca->pd_dev, true); ++} ++ ++static int apple_mca_probe(struct platform_device *pdev) ++{ ++ struct mca_data *mca; ++ struct mca_cluster *clusters; ++ struct snd_soc_dai_driver *dai_drivers; ++ int nclusters; ++ int irq, ret, i; ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "apple,nclusters", &nclusters); ++ if (ret || nclusters > MAX_NCLUSTERS) { ++ dev_err(&pdev->dev, "missing or invalid apple,nclusters property\n"); ++ return -EINVAL; ++ } ++ ++ mca = devm_kzalloc(&pdev->dev, struct_size(mca, clusters, nclusters), ++ GFP_KERNEL); ++ if (!mca) ++ return -ENOMEM; ++ ++ mca->dev = &pdev->dev; ++ mca->nclusters = nclusters; ++ platform_set_drvdata(pdev, mca); ++ clusters = mca->clusters; ++ ++ mca->base = devm_platform_ioremap_resource_byname(pdev, "clusters"); ++ if (IS_ERR(mca->base)) { ++ dev_err(&pdev->dev, "unable to obtain clusters MMIO resource: %ld\n", ++ PTR_ERR(mca->base)); ++ return PTR_ERR(mca->base); ++ } ++ ++ mca->switch_base = devm_platform_ioremap_resource_byname(pdev, "switch"); ++ if (IS_ERR(mca->switch_base)) { ++ dev_err(&pdev->dev, "unable to obtain switch MMIO resource: %ld\n", ++ PTR_ERR(mca->switch_base)); ++ return PTR_ERR(mca->switch_base); ++ } ++ ++ { ++ struct reset_control *rst; ++ rst = of_reset_control_array_get(pdev->dev.of_node, true, true, false); ++ if (IS_ERR(rst)) { ++ dev_err(&pdev->dev, "unable to obtain reset control: %ld\n", ++ PTR_ERR(rst)); ++ } else if (rst) { ++ reset_control_reset(rst); ++ reset_control_put(rst); ++ } ++ } ++ ++ dai_drivers = devm_kzalloc(&pdev->dev, sizeof(*dai_drivers) * nclusters, ++ GFP_KERNEL); ++ if (!dai_drivers) ++ return -ENOMEM; ++ ++ mca->pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, 0); ++ if (IS_ERR(mca->pd_dev)) ++ return -EINVAL; ++ ++ mca->pd_link = device_link_add(&pdev->dev, mca->pd_dev, ++ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | ++ DL_FLAG_RPM_ACTIVE); ++ if (!mca->pd_link) { ++ ret = -EINVAL; ++ goto err_release; ++ } ++ ++ for (i = 0; i < nclusters; i++) { ++ struct mca_cluster *cl = &clusters[i]; ++ struct snd_soc_dai_driver *drv = &dai_drivers[i]; ++ int stream; ++ ++ cl->host = mca; ++ cl->no = i; ++ ++ cl->clk_parent = of_clk_get(pdev->dev.of_node, i); ++ if (IS_ERR(cl->clk_parent)) { ++ dev_err(&pdev->dev, "unable to obtain clock %d: %ld\n", ++ i, PTR_ERR(cl->clk_parent)); ++ ret = PTR_ERR(cl->clk_parent); ++ goto err_release; ++ } ++ ++ cl->pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i + 1); ++ if (IS_ERR(cl->pd_dev)) { ++ dev_err(&pdev->dev, "unable to obtain cluster %d PD: %ld\n", ++ i, PTR_ERR(cl->pd_dev)); ++ ret = PTR_ERR(cl->pd_dev); ++ goto err_release; ++ } ++ ++#if 0 ++ ret = clk_rate_exclusive_get(clk); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to get clock rate exclusivity\n"); ++ goto err_release; ++ } ++ ++#endif ++ ++ irq = platform_get_irq_optional(pdev, i); ++ if (irq >= 0) { ++ dev_dbg(&pdev->dev, "have IRQs for cluster %d\n", i); ++#if 0 ++ ret = devm_request_irq(&pdev->dev, irq, mca_interrupt, ++ 0, dev_name(&pdev->dev), cl); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to register interrupt: %d\n", ret); ++ goto err_release; ++ } ++ mca_poke(mca, i, REG_INTMASK, 0xffffffff); ++#endif ++ } ++ ++ for_each_pcm_streams(stream) { ++ struct dma_chan *chan; ++ bool is_tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); ++#ifndef USE_RXB_FOR_CAPTURE ++ char *name = devm_kasprintf(&pdev->dev, GFP_KERNEL, ++ is_tx ? "tx%da" : "rx%da", i); ++#else ++ char *name = devm_kasprintf(&pdev->dev, GFP_KERNEL, ++ is_tx ? "tx%da" : "rx%db", i); ++#endif ++ ++ chan = of_dma_request_slave_channel(pdev->dev.of_node, name); ++ if (IS_ERR(chan)) { ++ if (PTR_ERR(chan) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "no %s DMA channel: %ld\n", ++ name, PTR_ERR(chan)); ++ ++ ret = PTR_ERR(chan); ++ goto err_release; ++ } ++ ++ cl->dma_chans[stream] = chan; ++ } ++ ++ drv->id = i; ++ drv->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, ++ "mca-i2s-%d", i); ++ if (!drv->name) { ++ ret = -ENOMEM; ++ goto err_release; ++ } ++ drv->ops = &mca_dai_ops; ++ drv->playback.channels_min = 1; ++ drv->playback.channels_max = 32; ++ drv->playback.rates = SNDRV_PCM_RATE_8000_192000; ++ drv->playback.formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE; ++ drv->capture.channels_min = 1; ++ drv->capture.channels_max = 32; ++ drv->capture.rates = SNDRV_PCM_RATE_8000_192000; ++ drv->capture.formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE; ++ drv->symmetric_rate = 1; ++ } ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &mca_component, ++ dai_drivers, nclusters); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to register ASoC component: %d\n", ret); ++ goto err_release; ++ } ++ ++ dev_dbg(&pdev->dev, "all good, ready to go!\n"); ++ return 0; ++ ++err_release: ++ apple_mca_release(mca); ++ return ret; ++} ++ ++static int apple_mca_remove(struct platform_device *pdev) ++{ ++ struct mca_data *mca = platform_get_drvdata(pdev); ++ ++ apple_mca_release(mca); ++ /* TODO */ ++ ++ return 0; ++} ++ ++static const struct of_device_id apple_mca_of_match[] = { ++ { .compatible = "apple,mca", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, apple_mca_of_match); ++ ++static struct platform_driver apple_mca_driver = { ++ .driver = { ++ .name = "apple-mca", ++ .owner = THIS_MODULE, ++ .of_match_table = apple_mca_of_match, ++ }, ++ .probe = apple_mca_probe, ++ .remove = apple_mca_remove, ++}; ++module_platform_driver(apple_mca_driver); ++ ++MODULE_AUTHOR("Martin PoviÅ¡er "); ++MODULE_DESCRIPTION("ASoC platform driver for Apple Silicon SoCs"); ++MODULE_LICENSE("GPL"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0073-ASoC-tas2770-Set-correct-FSYNC-polarity.patch b/target/linux/silicon/patches-5.19/0073-ASoC-tas2770-Set-correct-FSYNC-polarity.patch new file mode 100644 index 000000000..86b9493ed --- /dev/null +++ b/target/linux/silicon/patches-5.19/0073-ASoC-tas2770-Set-correct-FSYNC-polarity.patch @@ -0,0 +1,99 @@ +From 25cfbd57efaf69fbbf65c4db2c4d541b8715e5f8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 09:49:34 +0100 +Subject: [PATCH 073/171] ASoC: tas2770: Set correct FSYNC polarity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix setting of FSYNC polarity for DAI formats other than I2S. Also +add support for polarity inversion. + +Signed-off-by: Martin PoviÅ¡er +--- + sound/soc/codecs/tas2770.c | 21 ++++++++++++++++++++- + sound/soc/codecs/tas2770.h | 3 +++ + 2 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c +index c1dbd978d550..2b214223265e 100644 +--- a/sound/soc/codecs/tas2770.c ++++ b/sound/soc/codecs/tas2770.c +@@ -337,7 +337,7 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) + struct snd_soc_component *component = dai->component; + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); +- u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; ++ u8 tdm_rx_start_slot = 0, invert_fpol = 0, fpol_preinv = 0, asi_cfg_1 = 0; + int ret; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +@@ -349,9 +349,15 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_IF: ++ invert_fpol = 1; ++ fallthrough; + case SND_SOC_DAIFMT_NB_NF: + asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_RSING; + break; ++ case SND_SOC_DAIFMT_IB_IF: ++ invert_fpol = 1; ++ fallthrough; + case SND_SOC_DAIFMT_IB_NF: + asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_FALING; + break; +@@ -369,15 +375,19 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + tdm_rx_start_slot = 1; ++ fpol_preinv = 0; + break; + case SND_SOC_DAIFMT_DSP_A: + tdm_rx_start_slot = 0; ++ fpol_preinv = 1; + break; + case SND_SOC_DAIFMT_DSP_B: + tdm_rx_start_slot = 1; ++ fpol_preinv = 1; + break; + case SND_SOC_DAIFMT_LEFT_J: + tdm_rx_start_slot = 0; ++ fpol_preinv = 1; + break; + default: + dev_err(tas2770->dev, +@@ -391,6 +401,15 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) + if (ret < 0) + return ret; + ++ ++ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG0, ++ TAS2770_TDM_CFG_REG0_FPOL_MASK, ++ (fpol_preinv ^ invert_fpol) ++ ? TAS2770_TDM_CFG_REG0_FPOL_RSING ++ : TAS2770_TDM_CFG_REG0_FPOL_FALING); ++ if (ret < 0) ++ return ret; ++ + return 0; + } + +diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h +index d156666bcc55..42277fb6bc10 100644 +--- a/sound/soc/codecs/tas2770.h ++++ b/sound/soc/codecs/tas2770.h +@@ -41,6 +41,9 @@ + #define TAS2770_TDM_CFG_REG0_31_44_1_48KHZ 0x6 + #define TAS2770_TDM_CFG_REG0_31_88_2_96KHZ 0x8 + #define TAS2770_TDM_CFG_REG0_31_176_4_192KHZ 0xa ++#define TAS2770_TDM_CFG_REG0_FPOL_MASK BIT(0) ++#define TAS2770_TDM_CFG_REG0_FPOL_RSING 0 ++#define TAS2770_TDM_CFG_REG0_FPOL_FALING 1 + /* TDM Configuration Reg1 */ + #define TAS2770_TDM_CFG_REG1 TAS2770_REG(0X0, 0x0B) + #define TAS2770_TDM_CFG_REG1_MASK GENMASK(5, 1) +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0074-HACK-ASoC-tas2770-Set-no-of-channels-to-1.patch b/target/linux/silicon/patches-5.19/0074-HACK-ASoC-tas2770-Set-no-of-channels-to-1.patch new file mode 100644 index 000000000..a5ab344f0 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0074-HACK-ASoC-tas2770-Set-no-of-channels-to-1.patch @@ -0,0 +1,27 @@ +From b65315774f730e0b8553230d6cff9912a0341ca9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 09:49:45 +0100 +Subject: [PATCH 074/171] HACK: ASoC: tas2770: Set no of channels to 1 + +--- + sound/soc/codecs/tas2770.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c +index 2b214223265e..753e3f8d459a 100644 +--- a/sound/soc/codecs/tas2770.c ++++ b/sound/soc/codecs/tas2770.c +@@ -508,8 +508,8 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = { + .id = 0, + .playback = { + .stream_name = "ASI1 Playback", +- .channels_min = 2, +- .channels_max = 2, ++ .channels_min = 1, ++ .channels_max = 1, + .rates = TAS2770_RATES, + .formats = TAS2770_FORMATS, + }, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0075-HACK-ASoC-cs42l42-Disable-regcache.patch b/target/linux/silicon/patches-5.19/0075-HACK-ASoC-cs42l42-Disable-regcache.patch new file mode 100644 index 000000000..2d2e6b2ff --- /dev/null +++ b/target/linux/silicon/patches-5.19/0075-HACK-ASoC-cs42l42-Disable-regcache.patch @@ -0,0 +1,26 @@ +From 289067bf88e5b44f8e5a34535693bd01bb3adb97 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 09:49:48 +0100 +Subject: [PATCH 075/171] HACK: ASoC: cs42l42: Disable regcache + +There's some issue that has yet to be pinned down. +--- + sound/soc/codecs/cs42l42.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c +index 4fade2388797..5fb28df85b8a 100644 +--- a/sound/soc/codecs/cs42l42.c ++++ b/sound/soc/codecs/cs42l42.c +@@ -380,7 +380,7 @@ static const struct regmap_config cs42l42_regmap = { + .max_register = CS42L42_MAX_REGISTER, + .reg_defaults = cs42l42_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults), +- .cache_type = REGCACHE_RBTREE, ++ //.cache_type = REGCACHE_RBTREE, + + .use_single_read = true, + .use_single_write = true, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0076-ASoC-cs42l42-Bypass-device-ID-check.patch b/target/linux/silicon/patches-5.19/0076-ASoC-cs42l42-Bypass-device-ID-check.patch new file mode 100644 index 000000000..eac1f0820 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0076-ASoC-cs42l42-Bypass-device-ID-check.patch @@ -0,0 +1,33 @@ +From 27fe5e0a4429c0a92635d1395a673fcea6289046 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 09:49:50 +0100 +Subject: [PATCH 076/171] ASoC: cs42l42: Bypass device ID check + +The cs42l42 driver is also applicable to the cs42l83 part. +--- + sound/soc/codecs/cs42l42.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c +index 5fb28df85b8a..2a98f9bc7144 100644 +--- a/sound/soc/codecs/cs42l42.c ++++ b/sound/soc/codecs/cs42l42.c +@@ -2273,13 +2273,10 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) + goto err_disable; + } + +- if (devid != CS42L42_CHIP_ID) { +- ret = -ENODEV; +- dev_err(&i2c_client->dev, ++ if (devid != CS42L42_CHIP_ID) ++ dev_warn(&i2c_client->dev, + "CS42L42 Device ID (%X). Expected %X\n", + devid, CS42L42_CHIP_ID); +- goto err_disable; +- } + + ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®); + if (ret < 0) { +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0077-HACK-ASoC-Add-card-filter_controls-hook.patch b/target/linux/silicon/patches-5.19/0077-HACK-ASoC-Add-card-filter_controls-hook.patch new file mode 100644 index 000000000..3fa7d4271 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0077-HACK-ASoC-Add-card-filter_controls-hook.patch @@ -0,0 +1,205 @@ +From 170220fc8fb15839654131612ac3dc84bb4469ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sun, 20 Feb 2022 14:29:38 +0100 +Subject: [PATCH 077/171] HACK: ASoC: Add card->filter_controls hook +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add a new ASoC card callback for filtering the kcontrols of the card's +constituent components. This lets the card take over some of the +controls, deciding their value instead of leaving it up to userspace. + +Also, and here's the HACK: part, move dapm_new_widgets call in front +of the card's late_probe call. This way all kcontrols should have been +crated by the time late_probe is called. + +Signed-off-by: Martin PoviÅ¡er +--- + include/sound/soc.h | 3 +++ + sound/soc/soc-core.c | 45 +++++++++++++++++++++++++++----------------- + sound/soc/soc-dapm.c | 34 ++++++++++++++++++++++++++++----- + 3 files changed, 60 insertions(+), 22 deletions(-) + +diff --git a/include/sound/soc.h b/include/sound/soc.h +index b276dcb5d4e8..7ef168a8c759 100644 +--- a/include/sound/soc.h ++++ b/include/sound/soc.h +@@ -916,6 +916,9 @@ struct snd_soc_card { + int (*late_probe)(struct snd_soc_card *card); + int (*remove)(struct snd_soc_card *card); + ++ int (*filter_controls)(struct snd_soc_card *card, ++ struct snd_kcontrol *kcontrol); ++ + /* the pre and post PM functions are used to do any PM work before and + * after the codec and DAI's do any PM work. */ + int (*suspend_pre)(struct snd_soc_card *card); +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index 9574f86dd4de..37e2a8b2af10 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -2069,12 +2069,12 @@ static int snd_soc_bind_card(struct snd_soc_card *card) + } + } + ++ snd_soc_dapm_new_widgets(card); ++ + ret = snd_soc_card_late_probe(card); + if (ret < 0) + goto probe_end; + +- snd_soc_dapm_new_widgets(card); +- + ret = snd_card_register(card->snd_card); + if (ret < 0) { + dev_err(card->dev, "ASoC: failed to register soundcard %d\n", +@@ -2209,19 +2209,34 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, + } + EXPORT_SYMBOL_GPL(snd_soc_cnew); + +-static int snd_soc_add_controls(struct snd_card *card, struct device *dev, ++static int snd_soc_add_controls(struct snd_soc_card *card, struct device *dev, + const struct snd_kcontrol_new *controls, int num_controls, + const char *prefix, void *data) + { +- int i; ++ int i, err; + + for (i = 0; i < num_controls; i++) { +- const struct snd_kcontrol_new *control = &controls[i]; +- int err = snd_ctl_add(card, snd_soc_cnew(control, data, +- control->name, prefix)); ++ const struct snd_kcontrol_new *control_new = &controls[i]; ++ struct snd_kcontrol *control; ++ ++ control = snd_soc_cnew(control_new, data, ++ control_new->name, prefix); ++ ++ if (card->filter_controls) { ++ err = card->filter_controls(card, control); ++ if (err < 0) { ++ snd_ctl_free_one(control); ++ return err; ++ } else if (err) { ++ continue; ++ } ++ } ++ ++ err = snd_ctl_add(card->snd_card, control); ++ + if (err < 0) { + dev_err(dev, "ASoC: Failed to add %s: %d\n", +- control->name, err); ++ control_new->name, err); + return err; + } + } +@@ -2241,9 +2256,7 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev, + int snd_soc_add_component_controls(struct snd_soc_component *component, + const struct snd_kcontrol_new *controls, unsigned int num_controls) + { +- struct snd_card *card = component->card->snd_card; +- +- return snd_soc_add_controls(card, component->dev, controls, ++ return snd_soc_add_controls(component->card, component->dev, controls, + num_controls, component->name_prefix, component); + } + EXPORT_SYMBOL_GPL(snd_soc_add_component_controls); +@@ -2258,13 +2271,11 @@ EXPORT_SYMBOL_GPL(snd_soc_add_component_controls); + * + * Return 0 for success, else error. + */ +-int snd_soc_add_card_controls(struct snd_soc_card *soc_card, ++int snd_soc_add_card_controls(struct snd_soc_card *card, + const struct snd_kcontrol_new *controls, int num_controls) + { +- struct snd_card *card = soc_card->snd_card; +- +- return snd_soc_add_controls(card, soc_card->dev, controls, num_controls, +- NULL, soc_card); ++ return snd_soc_add_controls(card, card->dev, controls, num_controls, ++ NULL, card); + } + EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); + +@@ -2281,7 +2292,7 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); + int snd_soc_add_dai_controls(struct snd_soc_dai *dai, + const struct snd_kcontrol_new *controls, int num_controls) + { +- struct snd_card *card = dai->component->card->snd_card; ++ struct snd_soc_card *card = dai->component->card; + + return snd_soc_add_controls(card, dai->dev, controls, num_controls, + NULL, dai); +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index a8e842e02cdc..c87137f364da 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -878,7 +878,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, + int kci) + { + struct snd_soc_dapm_context *dapm = w->dapm; +- struct snd_card *card = dapm->card->snd_card; ++ struct snd_soc_card *card = dapm->card; + const char *prefix; + size_t prefix_len; + int shared; +@@ -962,7 +962,19 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, + goto exit_free; + } + +- ret = snd_ctl_add(card, kcontrol); ++ if (card->filter_controls) { ++ ret = card->filter_controls(card, kcontrol); ++ if (ret < 0) { ++ snd_ctl_free_one(kcontrol); ++ goto exit_free; ++ } ++ ++ if (!ret) ++ ret = snd_ctl_add(card->snd_card, kcontrol); ++ } else { ++ ret = snd_ctl_add(card->snd_card, kcontrol); ++ } ++ + if (ret < 0) { + dev_err(dapm->dev, + "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", +@@ -1079,7 +1091,7 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) + /* create new dapm dai link control */ + static int dapm_new_dai_link(struct snd_soc_dapm_widget *w) + { +- int i; ++ int i, ret; + struct snd_soc_pcm_runtime *rtd = w->priv; + + /* create control for links with > 1 config */ +@@ -1089,10 +1101,22 @@ static int dapm_new_dai_link(struct snd_soc_dapm_widget *w) + /* add kcontrol */ + for (i = 0; i < w->num_kcontrols; i++) { + struct snd_soc_dapm_context *dapm = w->dapm; +- struct snd_card *card = dapm->card->snd_card; ++ struct snd_soc_card *card = dapm->card; + struct snd_kcontrol *kcontrol = snd_soc_cnew(&w->kcontrol_news[i], + w, w->name, NULL); +- int ret = snd_ctl_add(card, kcontrol); ++ ++ if (card->filter_controls) { ++ ret = card->filter_controls(card, kcontrol); ++ if (ret < 0) { ++ snd_ctl_free_one(kcontrol); ++ return ret; ++ } ++ ++ if (!ret) ++ ret = snd_ctl_add(card->snd_card, kcontrol); ++ } else { ++ ret = snd_ctl_add(card->snd_card, kcontrol); ++ } + + if (ret < 0) { + dev_err(dapm->dev, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0078-ASoC-Add-asoc_pcm_to_rtd-utility-function.patch b/target/linux/silicon/patches-5.19/0078-ASoC-Add-asoc_pcm_to_rtd-utility-function.patch new file mode 100644 index 000000000..4db68b8f9 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0078-ASoC-Add-asoc_pcm_to_rtd-utility-function.patch @@ -0,0 +1,29 @@ +From 3153617d401d69c1d4f52eb3ca69f5b4b8d2086a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Thu, 24 Feb 2022 14:50:34 +0100 +Subject: [PATCH 078/171] ASoC: Add asoc_pcm_to_rtd utility function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Martin PoviÅ¡er +--- + include/sound/soc.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/sound/soc.h b/include/sound/soc.h +index 7ef168a8c759..73cc83d73163 100644 +--- a/include/sound/soc.h ++++ b/include/sound/soc.h +@@ -1101,6 +1101,8 @@ struct snd_soc_pcm_runtime { + #define asoc_rtd_to_codec(rtd, n) (rtd)->dais[n + (rtd)->num_cpus] + #define asoc_substream_to_rtd(substream) \ + (struct snd_soc_pcm_runtime *)snd_pcm_substream_chip(substream) ++#define asoc_pcm_to_rtd(pcm) \ ++ ((struct snd_soc_pcm_runtime *)pcm->private_data) + + #define for_each_rtd_components(rtd, i, component) \ + for ((i) = 0, component = NULL; \ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0079-HACK-ASoC-Allow-an-N-cpus-to-M-codecs-link.patch b/target/linux/silicon/patches-5.19/0079-HACK-ASoC-Allow-an-N-cpus-to-M-codecs-link.patch new file mode 100644 index 000000000..d3855866e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0079-HACK-ASoC-Allow-an-N-cpus-to-M-codecs-link.patch @@ -0,0 +1,34 @@ +From 3a8e536be0711ee4985c227fee67e569aa93f9a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Thu, 24 Feb 2022 14:51:00 +0100 +Subject: [PATCH 079/171] HACK: ASoC: Allow an N-cpus-to-M-codecs link +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Martin PoviÅ¡er +--- + sound/soc/soc-pcm.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index a827cc3c158a..542c308df17c 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -2811,9 +2811,10 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, + } else if (rtd->num_cpus == rtd->num_codecs) { + cpu_dai = asoc_rtd_to_cpu(rtd, i); + } else { +- dev_err(rtd->card->dev, +- "N cpus to M codecs link is not supported yet\n"); +- return -EINVAL; ++ cpu_dai = asoc_rtd_to_cpu(rtd, 0); ++ //dev_err(rtd->card->dev, ++ // "N cpus to M codecs link is not supported yet\n"); ++ //return -EINVAL; + } + + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0080-ASoC-Add-macaudio-machine-driver.patch b/target/linux/silicon/patches-5.19/0080-ASoC-Add-macaudio-machine-driver.patch new file mode 100644 index 000000000..ab75b8d46 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0080-ASoC-Add-macaudio-machine-driver.patch @@ -0,0 +1,632 @@ +From 1bd9f82e027617111fd5a1a653dad3880f71ddf7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Sat, 19 Feb 2022 09:49:56 +0100 +Subject: [PATCH 080/171] ASoC: Add macaudio machine driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Martin PoviÅ¡er +--- + sound/soc/apple/Kconfig | 9 + + sound/soc/apple/Makefile | 3 + + sound/soc/apple/macaudio.c | 579 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 591 insertions(+) + create mode 100644 sound/soc/apple/macaudio.c + +diff --git a/sound/soc/apple/Kconfig b/sound/soc/apple/Kconfig +index ebe66d713b96..a3f6a97140e2 100644 +--- a/sound/soc/apple/Kconfig ++++ b/sound/soc/apple/Kconfig +@@ -1,3 +1,12 @@ ++ ++config SND_SOC_APPLE_SILICON ++ tristate "ASoC machine driver for Apple Silicon Macs" ++ depends on ARCH_APPLE || COMPILE_TEST ++ select SND_SOC_APPLE_MCA ++ default ARCH_APPLE ++ help ++ This option enables an ASoC machine driver for Apple Silicon Macs. ++ + config SND_SOC_APPLE_MCA + tristate "Apple Silicon MCA driver" + depends on ARCH_APPLE || COMPILE_TEST +diff --git a/sound/soc/apple/Makefile b/sound/soc/apple/Makefile +index c1e492d57649..a45cf8213c29 100644 +--- a/sound/soc/apple/Makefile ++++ b/sound/soc/apple/Makefile +@@ -1,3 +1,6 @@ + snd-soc-apple-mca-objs := mca.o ++snd-soc-apple-silicon-objs := macaudio.o + + obj-$(CONFIG_SND_SOC_APPLE_MCA) += snd-soc-apple-mca.o ++obj-$(CONFIG_SND_SOC_APPLE_SILICON) += snd-soc-apple-silicon.o ++ +diff --git a/sound/soc/apple/macaudio.c b/sound/soc/apple/macaudio.c +new file mode 100644 +index 000000000000..a1f2b1fcea1f +--- /dev/null ++++ b/sound/soc/apple/macaudio.c +@@ -0,0 +1,579 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * ASoC machine driver for Apple Silicon Macs ++ * ++ * Copyright (C) The Asahi Linux Contributors ++ * ++ * Based on sound/soc/qcom/{sc7180.c|common.c} ++ * ++ * Copyright (c) 2018, Linaro Limited. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_NAME "snd-soc-apple-macaudio" ++ ++struct macaudio_snd_data { ++ struct snd_soc_card card; ++ struct snd_soc_jack_pin pin; ++ struct snd_soc_jack jack; ++ ++ struct macaudio_link_props { ++ unsigned int mclk_fs; ++ } *link_props; ++ ++ const struct snd_pcm_chmap_elem *speaker_chmap; ++ ++ unsigned int speaker_nchans_array[2]; ++ struct snd_pcm_hw_constraint_list speaker_nchans_list; ++ ++ struct list_head hidden_kcontrols; ++}; ++ ++static int macaudio_parse_of(struct macaudio_snd_data *ma, struct snd_soc_card *card) ++{ ++ struct device_node *np; ++ struct device_node *codec = NULL; ++ struct device_node *cpu = NULL; ++ struct device *dev = card->dev; ++ struct snd_soc_dai_link *link; ++ struct macaudio_link_props *link_props; ++ int ret, num_links; ++ int i = 0; ++ ++ ret = snd_soc_of_parse_card_name(card, "model"); ++ if (ret) { ++ dev_err(dev, "Error parsing card name: %d\n", ret); ++ return ret; ++ } ++ ++ ret = asoc_simple_parse_routing(card, NULL); ++ if (ret) { ++ return ret; ++ } ++ ++ /* Populate links */ ++ num_links = of_get_available_child_count(dev->of_node); ++ ++ /* Allocate the DAI link array */ ++ card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); ++ ma->link_props = devm_kcalloc(dev, num_links, sizeof(*ma->link_props), GFP_KERNEL); ++ if (!card->dai_link || !ma->link_props) ++ return -ENOMEM; ++ ++ card->num_links = num_links; ++ link = card->dai_link; ++ link_props = ma->link_props; ++ ++ for_each_available_child_of_node(dev->of_node, np) { ++ link->id = i++; ++ ++ /* CPU side is bit and frame clock master, I2S with both clocks inverted */ ++ link->dai_fmt = SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_CBC_CFC | ++ SND_SOC_DAIFMT_GATED | ++ SND_SOC_DAIFMT_IB_IF; ++ ++ ret = of_property_read_string(np, "link-name", &link->name); ++ if (ret) { ++ dev_err(card->dev, "Missing link name\n"); ++ goto err_put_np; ++ } ++ ++ cpu = of_get_child_by_name(np, "cpu"); ++ codec = of_get_child_by_name(np, "codec"); ++ ++ if (!codec || !cpu) { ++ dev_err(dev, "Missing DAI specifications for '%s'\n", link->name); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); ++ if (ret < 0) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(card->dev, "%s: codec dai not found: %d\n", ++ link->name, ret); ++ goto err; ++ } ++ ++ ret = snd_soc_of_get_dai_link_cpus(dev, cpu, link); ++ if (ret < 0) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(card->dev, "%s: cpu dai not found: %d\n", ++ link->name, ret); ++ goto err; ++ } ++ ++ link->num_platforms = 1; ++ link->platforms = devm_kzalloc(dev, sizeof(*link->platforms), ++ GFP_KERNEL); ++ if (!link->platforms) { ++ ret = -ENOMEM; ++ goto err_put_np; ++ } ++ link->platforms->of_node = link->cpus->of_node; ++ ++ of_property_read_u32(np, "mclk-fs", &link_props->mclk_fs); ++ ++ link->stream_name = link->name; ++ link++; ++ link_props++; ++ ++ of_node_put(cpu); ++ of_node_put(codec); ++ } ++ ++ /* TODO: snd_soc_of_get_dai_link_codecs cleanup */ ++ ++ return 0; ++err: ++ of_node_put(cpu); ++ of_node_put(codec); ++err_put_np: ++ of_node_put(np); ++ return ret; ++} ++ ++static int macaudio_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ++ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(rtd->card); ++ struct macaudio_link_props *props = &ma->link_props[rtd->num]; ++ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); ++ struct snd_soc_dai *dai; ++ int i, mclk; ++ ++ if (props->mclk_fs) { ++ mclk = params_rate(params) * props->mclk_fs; ++ ++ for_each_rtd_codec_dais(rtd, i, dai) ++ snd_soc_dai_set_sysclk(dai, 0, mclk, SND_SOC_CLOCK_IN); ++ ++ snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT); ++ } ++ ++ return 0; ++} ++ ++static void macaudio_shutdown(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ++ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(rtd->card); ++ struct macaudio_link_props *props = &ma->link_props[rtd->num]; ++ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); ++ struct snd_soc_dai *dai; ++ int i; ++ ++ if (props->mclk_fs) { ++ for_each_rtd_codec_dais(rtd, i, dai) ++ snd_soc_dai_set_sysclk(dai, 0, 0, SND_SOC_CLOCK_IN); ++ ++ snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT); ++ } ++} ++ ++ ++static int macaudio_startup(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); ++ struct snd_soc_card *card = rtd->card; ++ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card); ++ struct snd_pcm_hw_constraint_list *nchans_list = &ma->speaker_nchans_list; ++ unsigned int *nchans_array = ma->speaker_nchans_array; ++ int ret; ++ ++ if (!strcmp(rtd->dai_link->name, "Speakers")) { ++ if (rtd->num_codecs > 2) { ++ nchans_list->count = 2; ++ nchans_list->list = nchans_array; ++ nchans_array[0] = 2; ++ nchans_array[1] = rtd->num_codecs; ++ ++ ret = snd_pcm_hw_constraint_list(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_CHANNELS, nchans_list); ++ if (ret < 0) ++ return ret; ++ } else if (rtd->num_codecs == 2) { ++ ret = snd_pcm_hw_constraint_single(substream->runtime, ++ SNDRV_PCM_HW_PARAM_CHANNELS, 2); ++ if (ret < 0) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int macaudio_assign_tdm(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_card *card = rtd->card; ++ struct snd_soc_dai *dai, *cpu_dai; ++ int ret, i; ++ int nchans = 0, nslots = 0, slot_width = 32; ++ ++ nslots = rtd->num_codecs; ++ ++ for_each_rtd_codec_dais(rtd, i, dai) { ++ int codec_nchans = 1; ++ int mask = ((1 << codec_nchans) - 1) << nchans; ++ ++ ret = snd_soc_dai_set_tdm_slot(dai, mask, ++ mask, nslots, slot_width); ++ if (ret == -EINVAL) ++ /* Try without the RX mask */ ++ ret = snd_soc_dai_set_tdm_slot(dai, mask, ++ 0, nslots, slot_width); ++ ++ if (ret < 0) { ++ dev_err(card->dev, "DAI %s refuses TDM settings: %d", ++ dai->name, ret); ++ return ret; ++ } ++ ++ nchans += codec_nchans; ++ } ++ ++ cpu_dai = asoc_rtd_to_cpu(rtd, 0); ++ ret = snd_soc_dai_set_tdm_slot(cpu_dai, (1 << nslots) - 1, ++ (1 << nslots) - 1, nslots, slot_width); ++ if (ret < 0) { ++ dev_err(card->dev, "CPU DAI %s refuses TDM settings: %d", ++ cpu_dai->name, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int macaudio_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_card *card = rtd->card; ++ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card); ++ struct snd_soc_component *component; ++ int ret, i; ++ ++ if (rtd->num_codecs > 1) { ++ ret = macaudio_assign_tdm(rtd); ++ if (ret < 0) ++ return ret; ++ } ++ ++ for_each_rtd_components(rtd, i, component) ++ snd_soc_component_set_jack(component, &ma->jack, NULL); ++ ++ return 0; ++} ++ ++static void macaudio_exit(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_component *component; ++ int i; ++ ++ for_each_rtd_components(rtd, i, component) ++ snd_soc_component_set_jack(component, NULL, NULL); ++} ++ ++struct fixed_kctl { ++ char *name; ++ char *value; ++} macaudio_fixed_kctls[] = { ++ {"ASI1 Sel", "Left"}, ++ {"Left ASI1 Sel", "Left"}, ++ {"Right ASI1 Sel", "Left"}, ++ {"Left Front ASI1 Sel", "Left"}, ++ {"Left Rear ASI1 Sel", "Left"}, ++ {"Right Front ASI1 Sel", "Left"}, ++ {"Right Rear ASI1 Sel", "Left"}, ++ {"Left Tweeter ASI1 Sel", "Left"}, ++ {"Left Woofer 1 ASI1 Sel", "Left"}, ++ {"Left Woofer 2 ASI1 Sel", "Left"}, ++ {"Right Tweeter ASI1 Sel", "Left"}, ++ {"Right Woofer 1 ASI1 Sel", "Left"}, ++ {"Right Woofer 2 ASI1 Sel", "Left"}, ++ {"Left ISENSE Switch", "Off"}, ++ {"Left VSENSE Switch", "Off"}, ++ {"Right ISENSE Switch", "Off"}, ++ {"Right VSENSE Switch", "Off"}, ++ {"Jack Mixer Volume", "63"}, ++ { } ++}; ++ ++static struct fixed_kctl *find_fixed_kctl(const char *name) ++{ ++ struct fixed_kctl *fctl; ++ ++ for (fctl = macaudio_fixed_kctls; fctl->name != NULL; fctl++) ++ if (!strcmp(fctl->name, name)) ++ return fctl; ++ ++ return NULL; ++} ++ ++static int macaudio_probe(struct snd_soc_card *card) ++{ ++ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card); ++ int ret; ++ ++ INIT_LIST_HEAD(&ma->hidden_kcontrols); ++ ++ ma->pin.pin = "Headphones"; ++ ma->pin.mask = SND_JACK_HEADSET | SND_JACK_HEADPHONE; ++ ret = snd_soc_card_jack_new_pins(card, ma->pin.pin, ++ SND_JACK_HEADSET | ++ SND_JACK_HEADPHONE | ++ SND_JACK_BTN_0 | SND_JACK_BTN_1 | ++ SND_JACK_BTN_2 | SND_JACK_BTN_3, ++ &ma->jack, &ma->pin, 1); ++ ++ if (ret < 0) ++ dev_err(card->dev, "jack creation failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int macaudio_remove(struct snd_soc_card *card) ++{ ++ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card); ++ struct snd_kcontrol *kcontrol; ++ ++ list_for_each_entry(kcontrol, &ma->hidden_kcontrols, list) ++ snd_ctl_free_one(kcontrol); ++ ++ return 0; ++} ++ ++static void snd_soc_kcontrol_set_strval(struct snd_soc_card *card, ++ struct snd_kcontrol *kcontrol, const char *strvalue) ++{ ++ struct snd_ctl_elem_value value; ++ struct snd_ctl_elem_info info; ++ int sel, i, ret; ++ ++ ret = kcontrol->info(kcontrol, &info); ++ if (ret < 0) { ++ dev_err(card->dev, "can't obtain info on control '%s': %d", ++ kcontrol->id.name, ret); ++ return; ++ } ++ ++ switch (info.type) { ++ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: ++ for (sel = 0; sel < info.value.enumerated.items; sel++) { ++ info.value.enumerated.item = sel; ++ kcontrol->info(kcontrol, &info); ++ ++ if (!strcmp(strvalue, info.value.enumerated.name)) ++ break; ++ } ++ ++ if (sel == info.value.enumerated.items) ++ goto not_avail; ++ ++ for (i = 0; i < info.count; i++) ++ value.value.enumerated.item[i] = sel; ++ break; ++ ++ case SNDRV_CTL_ELEM_TYPE_BOOLEAN: ++ sel = !strcmp(strvalue, "On"); ++ ++ if (!sel && strcmp(strvalue, "Off")) ++ goto not_avail; ++ ++ for (i = 0; i < info.count; i++) /* TODO */ ++ value.value.integer.value[i] = sel; ++ break; ++ ++ case SNDRV_CTL_ELEM_TYPE_INTEGER: ++ if (kstrtoint(strvalue, 10, &sel)) ++ goto not_avail; ++ ++ for (i = 0; i < info.count; i++) ++ value.value.integer.value[i] = sel; ++ break; ++ ++ default: ++ dev_err(card->dev, "%s: control '%s' has unsupported type %d", ++ __func__, kcontrol->id.name, info.type); ++ return; ++ } ++ ++ ret = kcontrol->put(kcontrol, &value); ++ if (ret < 0) { ++ dev_err(card->dev, "can't set control '%s' to '%s': %d", ++ kcontrol->id.name, strvalue, ret); ++ return; ++ } ++ ++ dev_info(card->dev, "set '%s' to '%s'", ++ kcontrol->id.name, strvalue); ++ return; ++ ++not_avail: ++ dev_err(card->dev, "option '%s' on control '%s' not available", ++ strvalue, kcontrol->id.name); ++ return; ++ ++} ++ ++static int macaudio_late_probe(struct snd_soc_card *card) ++{ ++ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card); ++ struct snd_kcontrol *kcontrol; ++ struct snd_soc_pcm_runtime *rtd; ++ int ret; ++ ++ list_for_each_entry(kcontrol, &ma->hidden_kcontrols, list) { ++ struct fixed_kctl *fctl = find_fixed_kctl(kcontrol->id.name); ++ ++ if (fctl) ++ snd_soc_kcontrol_set_strval(card, kcontrol, fctl->value); ++ } ++ ++ for_each_card_rtds(card, rtd) { ++ bool speakers_link = !strcmp(rtd->dai_link->name, "Speaker") ++ || !strcmp(rtd->dai_link->name, "Speakers"); ++ ++ if (speakers_link && ma->speaker_chmap) { ++ ret = snd_pcm_add_chmap_ctls(rtd->pcm, ++ SNDRV_PCM_STREAM_PLAYBACK, ma->speaker_chmap, ++ rtd->num_codecs, 0, NULL); ++ if (ret < 0) ++ dev_err(card->dev, "failed to add channel map on '%s': %d\n", ++ rtd->dai_link->name, ret); ++ } ++ } ++ ++ return 0; ++} ++ ++static int macaudio_filter_controls(struct snd_soc_card *card, ++ struct snd_kcontrol *kcontrol) ++{ ++ struct fixed_kctl *fctl = find_fixed_kctl(kcontrol->id.name); ++ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card); ++ ++ dev_info(card->dev, "visiting control %s, have match %d\n", ++ kcontrol->id.name, !!fctl); ++ ++ if (!fctl) ++ return 0; ++ ++ list_add_tail(&kcontrol->list, &ma->hidden_kcontrols); ++ return 1; ++} ++ ++static const struct snd_soc_ops macaudio_ops = { ++ .startup = macaudio_startup, ++ .shutdown = macaudio_shutdown, ++ .hw_params = macaudio_hw_params, ++}; ++ ++static const struct snd_soc_dapm_widget macaudio_snd_widgets[] = { ++ SND_SOC_DAPM_HP("Headphones", NULL), ++}; ++ ++static const struct snd_pcm_chmap_elem macaudio_j274_chmaps[] = { ++ { .channels = 1, ++ .map = { SNDRV_CHMAP_MONO } }, ++ { } ++}; ++ ++static const struct snd_pcm_chmap_elem macaudio_j293_chmaps[] = { ++ { .channels = 2, ++ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, ++ { .channels = 4, ++ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, ++ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, ++ { } ++}; ++ ++static const struct snd_pcm_chmap_elem macaudio_j314_chmaps[] = { ++ { .channels = 2, ++ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, ++ { .channels = 6, ++ .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR, ++ SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, ++ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, ++ { } ++}; ++ ++static const struct of_device_id macaudio_snd_device_id[] = { ++ { .compatible = "apple,j274-macaudio", .data = macaudio_j274_chmaps }, ++ { .compatible = "apple,j293-macaudio", .data = macaudio_j293_chmaps }, ++ { .compatible = "apple,j314-macaudio", .data = macaudio_j314_chmaps }, ++ { .compatible = "apple,macaudio", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, macaudio_snd_device_id); ++ ++static int macaudio_snd_platform_probe(struct platform_device *pdev) ++{ ++ struct snd_soc_card *card; ++ struct macaudio_snd_data *data; ++ struct device *dev = &pdev->dev; ++ struct snd_soc_dai_link *link; ++ const struct of_device_id *of_id; ++ int ret; ++ int i; ++ ++ of_id = of_match_device(macaudio_snd_device_id, dev); ++ if (!of_id) ++ return -EINVAL; ++ ++ /* Allocate the private data */ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->speaker_chmap = of_id->data; ++ card = &data->card; ++ snd_soc_card_set_drvdata(card, data); ++ ++ card->owner = THIS_MODULE; ++ card->driver_name = DRIVER_NAME; ++ card->dev = dev; ++ card->dapm_widgets = macaudio_snd_widgets; ++ card->num_dapm_widgets = ARRAY_SIZE(macaudio_snd_widgets); ++ card->probe = macaudio_probe; ++ card->late_probe = macaudio_late_probe; ++ card->remove = macaudio_remove; ++ card->filter_controls = macaudio_filter_controls; ++ card->remove = macaudio_remove; ++ ++ ret = macaudio_parse_of(data, card); ++ if (ret) ++ return ret; ++ ++ for_each_card_prelinks(card, i, link) { ++ link->ops = &macaudio_ops; ++ link->init = macaudio_init; ++ link->exit = macaudio_exit; ++ } ++ ++ return devm_snd_soc_register_card(dev, card); ++} ++ ++static struct platform_driver macaudio_snd_driver = { ++ .probe = macaudio_snd_platform_probe, ++ .driver = { ++ .name = DRIVER_NAME, ++ .of_match_table = macaudio_snd_device_id, ++ .pm = &snd_soc_pm_ops, ++ }, ++}; ++module_platform_driver(macaudio_snd_driver); ++ ++MODULE_AUTHOR("Martin PoviÅ¡er "); ++MODULE_DESCRIPTION("Apple Silicon Macs machine sound driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0081-ASoC-tas2764-Extend-driver-to-SN012776.patch b/target/linux/silicon/patches-5.19/0081-ASoC-tas2764-Extend-driver-to-SN012776.patch new file mode 100644 index 000000000..8c0be0ef0 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0081-ASoC-tas2764-Extend-driver-to-SN012776.patch @@ -0,0 +1,161 @@ +From 11d06018fefa454eff591ade9181e20a23acff48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Fri, 11 Mar 2022 11:55:44 +0100 +Subject: [PATCH 081/171] ASoC: tas2764: Extend driver to SN012776 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +SN012776 is a speaker amp chip found in Apple's 2021 laptops. It appears +similar and more-or-less compatible to TAS2764. Extend the TAS2764 +driver with some SN012776 specifics and configure the chip assuming +it's in one of the Apple machines. + +Signed-off-by: Martin PoviÅ¡er +--- + sound/soc/codecs/tas2764.c | 51 ++++++++++++++++++++++++++++++++++---- + sound/soc/codecs/tas2764.h | 3 +++ + 2 files changed, 49 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c +index 4cb788f3e5f7..dd36c99e633b 100644 +--- a/sound/soc/codecs/tas2764.c ++++ b/sound/soc/codecs/tas2764.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -25,13 +26,20 @@ + + #include "tas2764.h" + ++enum tas2764_devid { ++ DEVID_TAS2764 = 0, ++ DEVID_SN012776 = 1 ++}; ++ + struct tas2764_priv { + struct snd_soc_component *component; + struct gpio_desc *reset_gpio; + struct gpio_desc *sdz_gpio; + struct regmap *regmap; + struct device *dev; +- ++ ++ enum tas2764_devid devid; ++ + int v_sense_slot; + int i_sense_slot; + }; +@@ -502,10 +510,16 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = { + }, + }; + ++static uint8_t sn012776_bop_presets[] = { ++ 0x01, 0x32, 0x02, 0x22, 0x83, 0x2d, 0x80, 0x02, 0x06, ++ 0x32, 0x46, 0x30, 0x02, 0x06, 0x38, 0x40, 0x30, 0x02, ++ 0x06, 0x3e, 0x37, 0x30, 0xff, 0xe6 ++}; ++ + static int tas2764_codec_probe(struct snd_soc_component *component) + { + struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); +- int ret; ++ int ret, i; + + tas2764->component = component; + +@@ -532,6 +546,23 @@ static int tas2764_codec_probe(struct snd_soc_component *component) + if (ret < 0) + return ret; + ++ if (tas2764->devid == DEVID_SN012776) { ++ ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, ++ TAS2764_PWR_CTRL_BOP_SRC, ++ TAS2764_PWR_CTRL_BOP_SRC); ++ if (ret < 0) ++ return ret; ++ ++ for (i = 0; i < ARRAY_SIZE(sn012776_bop_presets); i++) { ++ ret = snd_soc_component_write(component, ++ TAS2764_BOP_CFG0 + i, ++ sn012776_bop_presets[i]); ++ ++ if (ret < 0) ++ return ret; ++ } ++ } ++ + return 0; + } + +@@ -631,9 +662,12 @@ static int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764) + return 0; + } + ++static const struct of_device_id tas2764_of_match[]; ++ + static int tas2764_i2c_probe(struct i2c_client *client) + { + struct tas2764_priv *tas2764; ++ const struct of_device_id *of_id = NULL; + int result; + + tas2764 = devm_kzalloc(&client->dev, sizeof(struct tas2764_priv), +@@ -641,6 +675,14 @@ static int tas2764_i2c_probe(struct i2c_client *client) + if (!tas2764) + return -ENOMEM; + ++ if (client->dev.of_node) ++ of_id = of_match_device(tas2764_of_match, &client->dev); ++ ++ if (of_id) ++ tas2764->devid = (enum tas2764_devid) of_id->data; ++ else ++ tas2764->devid = DEVID_TAS2764; ++ + tas2764->dev = &client->dev; + i2c_set_clientdata(client, tas2764); + dev_set_drvdata(&client->dev, tas2764); +@@ -674,13 +716,12 @@ static const struct i2c_device_id tas2764_i2c_id[] = { + }; + MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id); + +-#if defined(CONFIG_OF) + static const struct of_device_id tas2764_of_match[] = { +- { .compatible = "ti,tas2764" }, ++ { .compatible = "ti,tas2764", .data = (void*) DEVID_TAS2764 }, ++ { .compatible = "ti,sn012776", .data = (void*) DEVID_SN012776 }, + {}, + }; + MODULE_DEVICE_TABLE(of, tas2764_of_match); +-#endif + + static struct i2c_driver tas2764_i2c_driver = { + .driver = { +diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h +index f015f22a083b..d7e171a9480c 100644 +--- a/sound/soc/codecs/tas2764.h ++++ b/sound/soc/codecs/tas2764.h +@@ -29,6 +29,7 @@ + #define TAS2764_PWR_CTRL_ACTIVE 0x0 + #define TAS2764_PWR_CTRL_MUTE BIT(0) + #define TAS2764_PWR_CTRL_SHUTDOWN BIT(1) ++#define TAS2764_PWR_CTRL_BOP_SRC BIT(7) + + #define TAS2764_VSENSE_POWER_EN 3 + #define TAS2764_ISENSE_POWER_EN 4 +@@ -87,4 +88,6 @@ + #define TAS2764_TDM_CFG6_ISNS_ENABLE BIT(6) + #define TAS2764_TDM_CFG6_50_MASK GENMASK(5, 0) + ++#define TAS2764_BOP_CFG0 TAS2764_REG(0X0, 0x1d) ++ + #endif /* __TAS2764__ */ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0082-ASoC-tas2764-Add-workaround-for-spurious-shutdowns-o.patch b/target/linux/silicon/patches-5.19/0082-ASoC-tas2764-Add-workaround-for-spurious-shutdowns-o.patch new file mode 100644 index 000000000..5df84c5b4 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0082-ASoC-tas2764-Add-workaround-for-spurious-shutdowns-o.patch @@ -0,0 +1,147 @@ +From b94fc3351432c6a0a75962c4af03750d8879d205 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 13 Mar 2022 03:13:08 +0900 +Subject: [PATCH 082/171] ASoC: tas2764: Add workaround for spurious shutdowns + on SN012776 + +It seems that on SHUTDOWN -> MUTE transitions, the SN012776 can end up +in a borked state raising an overcurrent error. + +Going through the ACTIVE state seems to make it work reliably, so do +that. + +Signed-off-by: Hector Martin +--- + sound/soc/codecs/tas2764.c | 65 +++++++++++++++++++++----------------- + 1 file changed, 36 insertions(+), 29 deletions(-) + +diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c +index dd36c99e633b..b3c99f470916 100644 +--- a/sound/soc/codecs/tas2764.c ++++ b/sound/soc/codecs/tas2764.c +@@ -58,27 +58,47 @@ static void tas2764_reset(struct tas2764_priv *tas2764) + usleep_range(1000, 2000); + } + ++static int tas2764_set_power(struct tas2764_priv *tas2764, u8 mode) ++{ ++ int ret; ++ ++ // TODO: Does this only affect the SN012776 variant? ++ if (tas2764->devid == DEVID_SN012776 && mode == TAS2764_PWR_CTRL_MUTE) { ++ ret = snd_soc_component_update_bits(tas2764->component, ++ TAS2764_PWR_CTRL, ++ TAS2764_PWR_CTRL_MASK, ++ TAS2764_PWR_CTRL_ACTIVE); ++ if (ret < 0) ++ return ret; ++ } ++ ++ ret = snd_soc_component_update_bits(tas2764->component, ++ TAS2764_PWR_CTRL, ++ TAS2764_PWR_CTRL_MASK, ++ mode); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++ + static int tas2764_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) + { + struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); ++ u8 mode; + + switch (level) { + case SND_SOC_BIAS_ON: +- snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, +- TAS2764_PWR_CTRL_MASK, +- TAS2764_PWR_CTRL_ACTIVE); ++ mode = TAS2764_PWR_CTRL_ACTIVE; + break; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_PREPARE: +- snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, +- TAS2764_PWR_CTRL_MASK, +- TAS2764_PWR_CTRL_MUTE); ++ mode = TAS2764_PWR_CTRL_MUTE; + break; + case SND_SOC_BIAS_OFF: +- snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, +- TAS2764_PWR_CTRL_MASK, +- TAS2764_PWR_CTRL_SHUTDOWN); ++ mode = TAS2764_PWR_CTRL_SHUTDOWN; + break; + + default: +@@ -87,7 +107,7 @@ static int tas2764_set_bias_level(struct snd_soc_component *component, + return -EINVAL; + } + +- return 0; ++ return tas2764_set_power(tas2764, mode); + } + + #ifdef CONFIG_PM +@@ -96,10 +116,7 @@ static int tas2764_codec_suspend(struct snd_soc_component *component) + struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); + int ret; + +- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, +- TAS2764_PWR_CTRL_MASK, +- TAS2764_PWR_CTRL_SHUTDOWN); +- ++ ret = tas2764_set_power(tas2764, TAS2764_PWR_CTRL_SHUTDOWN); + if (ret < 0) + return ret; + +@@ -122,10 +139,7 @@ static int tas2764_codec_resume(struct snd_soc_component *component) + usleep_range(1000, 2000); + } + +- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, +- TAS2764_PWR_CTRL_MASK, +- TAS2764_PWR_CTRL_ACTIVE); +- ++ ret = tas2764_set_power(tas2764, TAS2764_PWR_CTRL_ACTIVE); + if (ret < 0) + return ret; + +@@ -154,28 +168,21 @@ static int tas2764_dac_event(struct snd_soc_dapm_widget *w, + { + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); +- int ret; ++ u8 mode; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: +- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, +- TAS2764_PWR_CTRL_MASK, +- TAS2764_PWR_CTRL_MUTE); ++ mode = TAS2764_PWR_CTRL_MUTE; + break; + case SND_SOC_DAPM_PRE_PMD: +- ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, +- TAS2764_PWR_CTRL_MASK, +- TAS2764_PWR_CTRL_SHUTDOWN); ++ mode = TAS2764_PWR_CTRL_SHUTDOWN; + break; + default: + dev_err(tas2764->dev, "Unsupported event\n"); + return -EINVAL; + } + +- if (ret < 0) +- return ret; +- +- return 0; ++ return tas2764_set_power(tas2764, mode); + } + + static const struct snd_kcontrol_new isense_switch = +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0083-ASoC-macaudio-State-missing-simple-card-utils-depend.patch b/target/linux/silicon/patches-5.19/0083-ASoC-macaudio-State-missing-simple-card-utils-depend.patch new file mode 100644 index 000000000..ac64d224e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0083-ASoC-macaudio-State-missing-simple-card-utils-depend.patch @@ -0,0 +1,31 @@ +From 91b1840731bc223fdfa0b86b0d9b1904213e3299 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Povi=C5=A1er?= +Date: Tue, 15 Mar 2022 19:41:05 +0100 +Subject: [PATCH 083/171] ASoC: macaudio: State missing simple-card-utils + dependency + +State that the macaudio module depends on simple-card-utils to fix build +errors of the kind: + +ld.lld: error: undefined symbol: asoc_simple_parse_routing +>>> referenced by macaudio.c:59 (sound/soc/apple/macaudio.c:59) +>>> soc/apple/macaudio.o:(macaudio_snd_platform_probe) in archive +--- + sound/soc/apple/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/apple/Kconfig b/sound/soc/apple/Kconfig +index a3f6a97140e2..ce6188aa659d 100644 +--- a/sound/soc/apple/Kconfig ++++ b/sound/soc/apple/Kconfig +@@ -3,6 +3,7 @@ config SND_SOC_APPLE_SILICON + tristate "ASoC machine driver for Apple Silicon Macs" + depends on ARCH_APPLE || COMPILE_TEST + select SND_SOC_APPLE_MCA ++ select SND_SIMPLE_CARD_UTILS + default ARCH_APPLE + help + This option enables an ASoC machine driver for Apple Silicon Macs. +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0084-macaudio-Unbork-jack-volume.patch b/target/linux/silicon/patches-5.19/0084-macaudio-Unbork-jack-volume.patch new file mode 100644 index 000000000..d9889b166 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0084-macaudio-Unbork-jack-volume.patch @@ -0,0 +1,25 @@ +From ddf6983d9229819248d0373854d32b4e4a0e123d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 19 Mar 2022 06:06:20 +0900 +Subject: [PATCH 084/171] macaudio: Unbork jack volume + +Signed-off-by: Hector Martin +--- + sound/soc/apple/macaudio.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/sound/soc/apple/macaudio.c b/sound/soc/apple/macaudio.c +index a1f2b1fcea1f..d39ef638ea95 100644 +--- a/sound/soc/apple/macaudio.c ++++ b/sound/soc/apple/macaudio.c +@@ -305,7 +305,6 @@ struct fixed_kctl { + {"Left VSENSE Switch", "Off"}, + {"Right ISENSE Switch", "Off"}, + {"Right VSENSE Switch", "Off"}, +- {"Jack Mixer Volume", "63"}, + { } + }; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0085-dt-bindings-net-bcm4329-fmac-Add-Apple-properties-ch.patch b/target/linux/silicon/patches-5.19/0085-dt-bindings-net-bcm4329-fmac-Add-Apple-properties-ch.patch new file mode 100644 index 000000000..29137f449 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0085-dt-bindings-net-bcm4329-fmac-Add-Apple-properties-ch.patch @@ -0,0 +1,88 @@ +From 4c5d245b445841af3cff2d861a3b461c645b3b57 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 26 Dec 2021 22:04:09 +0900 +Subject: [PATCH 085/171] dt-bindings: net: bcm4329-fmac: Add Apple properties + & chips + +This binding is currently used for SDIO devices, but these chips are +also used as PCIe devices on DT platforms and may be represented in the +DT. Re-use the existing binding and add chip compatibles used by Apple +T2 and M1 platforms (the T2 ones are not known to be used in DT +platforms, but we might as well document them). + +Then, add properties required for firmware selection and calibration on +M1 machines. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../net/wireless/brcm,bcm4329-fmac.yaml | 37 +++++++++++++++++-- + 1 file changed, 34 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml +index c11f23b20c4c..8b4147c64355 100644 +--- a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml ++++ b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml +@@ -4,7 +4,7 @@ + $id: http://devicetree.org/schemas/net/wireless/brcm,bcm4329-fmac.yaml# + $schema: http://devicetree.org/meta-schemas/core.yaml# + +-title: Broadcom BCM4329 family fullmac wireless SDIO devices ++title: Broadcom BCM4329 family fullmac wireless SDIO/PCIE devices + + maintainers: + - Arend van Spriel +@@ -42,10 +42,16 @@ properties: + - cypress,cyw43012-fmac + - const: brcm,bcm4329-fmac + - const: brcm,bcm4329-fmac ++ - enum: ++ - pci14e4,43dc # BCM4355 ++ - pci14e4,4464 # BCM4364 ++ - pci14e4,4488 # BCM4377 ++ - pci14e4,4425 # BCM4378 ++ - pci14e4,4433 # BCM4387 + + reg: +- description: SDIO function number for the device, for most cases +- this will be 1. ++ description: SDIO function number for the device (for most cases ++ this will be 1) or PCI device identifier. + + interrupts: + maxItems: 1 +@@ -75,6 +81,31 @@ properties: + items: + pattern: '^[A-Z][A-Z]-[A-Z][0-9A-Z]-[0-9]+$' + ++ brcm,cal-blob: ++ $ref: /schemas/types.yaml#/definitions/uint8-array ++ description: A per-device calibration blob for the Wi-Fi radio. This ++ should be filled in by the bootloader from platform configuration ++ data, if necessary, and will be uploaded to the device if present. ++ ++ brcm,board-type: ++ $ref: /schemas/types.yaml#/definitions/string ++ description: Overrides the board type, which is normally the compatible of ++ the root node. This can be used to decouple the overall system board or ++ device name from the board type for WiFi purposes, which is used to ++ construct firmware and NVRAM configuration filenames, allowing for ++ multiple devices that share the same module or characteristics for the ++ WiFi subsystem to share the same firmware/NVRAM files. On Apple platforms, ++ this should be the Apple module-instance codename prefixed by "apple,", ++ e.g. "apple,honshu". ++ ++ apple,antenna-sku: ++ $ref: /schemas/types.yaml#/definitions/string ++ description: Antenna SKU used to identify a specific antenna configuration ++ on Apple platforms. This is use to build firmware filenames, to allow ++ platforms with different antenna configs to have different firmware and/or ++ NVRAM. This would normally be filled in by the bootloader from platform ++ configuration data. ++ + required: + - compatible + - reg +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0086-brcmfmac-firmware-Handle-per-board-clm_blob-files.patch b/target/linux/silicon/patches-5.19/0086-brcmfmac-firmware-Handle-per-board-clm_blob-files.patch new file mode 100644 index 000000000..202bae11e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0086-brcmfmac-firmware-Handle-per-board-clm_blob-files.patch @@ -0,0 +1,76 @@ +From 6e3dabd08775a78c7a6ba10779bdb9418852cd1b Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 18 Dec 2021 20:52:04 +0900 +Subject: [PATCH 086/171] brcmfmac: firmware: Handle per-board clm_blob files + +Teach brcm_alt_fw_paths to correctly split off variable length +extensions, and enable alt firmware lookups for the CLM blob firmware +requests. + +Apple platforms have per-board CLM blob files. + +Acked-by: Linus Walleij +Reviewed-by: Arend van Spriel +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/firmware.c | 33 +++++++++++-------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +index dcbe55b56e43..deacd39b3f7b 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +@@ -596,22 +596,29 @@ static int brcmf_fw_complete_request(const struct firmware *fw, + + static char *brcm_alt_fw_path(const char *path, const char *board_type) + { +- char alt_path[BRCMF_FW_NAME_LEN]; +- char suffix[5]; ++ char base[BRCMF_FW_NAME_LEN]; ++ const char *suffix; ++ char *ret; + +- strscpy(alt_path, path, BRCMF_FW_NAME_LEN); +- /* At least one character + suffix */ +- if (strlen(alt_path) < 5) ++ if (!board_type) + return NULL; + +- /* strip .txt or .bin at the end */ +- strscpy(suffix, alt_path + strlen(alt_path) - 4, 5); +- alt_path[strlen(alt_path) - 4] = 0; +- strlcat(alt_path, ".", BRCMF_FW_NAME_LEN); +- strlcat(alt_path, board_type, BRCMF_FW_NAME_LEN); +- strlcat(alt_path, suffix, BRCMF_FW_NAME_LEN); ++ suffix = strrchr(path, '.'); ++ if (!suffix || suffix == path) ++ return NULL; ++ ++ /* strip extension at the end */ ++ strscpy(base, path, BRCMF_FW_NAME_LEN); ++ base[suffix - path] = 0; ++ ++ ret = kasprintf(GFP_KERNEL, "%s.%s%s", base, board_type, suffix); ++ if (!ret) ++ brcmf_err("out of memory allocating firmware path for '%s'\n", ++ path); ++ ++ brcmf_dbg(TRACE, "FW alt path: %s\n", ret); + +- return kstrdup(alt_path, GFP_KERNEL); ++ return ret; + } + + static int brcmf_fw_request_firmware(const struct firmware **fw, +@@ -621,7 +628,7 @@ static int brcmf_fw_request_firmware(const struct firmware **fw, + int ret; + + /* Files can be board-specific, first try a board-specific path */ +- if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) { ++ if (fwctx->req->board_type) { + char *alt_path; + + alt_path = brcm_alt_fw_path(cur->path, fwctx->req->board_type); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0087-brcmfmac-pcie-sdio-usb-Get-CLM-blob-via-standard-fir.patch b/target/linux/silicon/patches-5.19/0087-brcmfmac-pcie-sdio-usb-Get-CLM-blob-via-standard-fir.patch new file mode 100644 index 000000000..df39e2a68 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0087-brcmfmac-pcie-sdio-usb-Get-CLM-blob-via-standard-fir.patch @@ -0,0 +1,376 @@ +From a0e0f6cebc9a2112a11c56d0f6c55681cf2b120d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:13:49 +0900 +Subject: [PATCH 087/171] brcmfmac: pcie/sdio/usb: Get CLM blob via standard + firmware mechanism + +Now that the firmware fetcher can handle per-board CLM files, load the +CLM blob alongside the other firmware files and change the bus API to +just return the existing blob, instead of fetching the filename. + +This enables per-board CLM blobs, which are required on Apple platforms. + +Acked-by: Linus Walleij +Reviewed-by: Arend van Spriel +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/bus.h | 19 ++++++--- + .../broadcom/brcm80211/brcmfmac/common.c | 12 +----- + .../broadcom/brcm80211/brcmfmac/pcie.c | 39 ++++++++++++------- + .../broadcom/brcm80211/brcmfmac/sdio.c | 36 ++++++++++------- + .../broadcom/brcm80211/brcmfmac/sdio.h | 2 + + .../broadcom/brcm80211/brcmfmac/usb.c | 23 +++-------- + 6 files changed, 69 insertions(+), 62 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +index 3f5da3bb6aa5..b13af8f631f3 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -7,6 +7,8 @@ + #define BRCMFMAC_BUS_H + + #include "debug.h" ++#include ++#include + + /* IDs of the 6 default common rings of msgbuf protocol */ + #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0 +@@ -34,6 +36,11 @@ enum brcmf_bus_protocol_type { + BRCMF_PROTO_MSGBUF + }; + ++/* Firmware blobs that may be available */ ++enum brcmf_blob_type { ++ BRCMF_BLOB_CLM, ++}; ++ + struct brcmf_mp_device; + + struct brcmf_bus_dcmd { +@@ -60,7 +67,7 @@ struct brcmf_bus_dcmd { + * @wowl_config: specify if dongle is configured for wowl when going to suspend + * @get_ramsize: obtain size of device memory. + * @get_memdump: obtain device memory dump in provided buffer. +- * @get_fwname: obtain firmware name. ++ * @get_blob: obtain a firmware blob. + * + * This structure provides an abstract interface towards the + * bus specific driver. For control messages to common driver +@@ -77,8 +84,8 @@ struct brcmf_bus_ops { + void (*wowl_config)(struct device *dev, bool enabled); + size_t (*get_ramsize)(struct device *dev); + int (*get_memdump)(struct device *dev, void *data, size_t len); +- int (*get_fwname)(struct device *dev, const char *ext, +- unsigned char *fw_name); ++ int (*get_blob)(struct device *dev, const struct firmware **fw, ++ enum brcmf_blob_type type); + void (*debugfs_create)(struct device *dev); + int (*reset)(struct device *dev); + }; +@@ -220,10 +227,10 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len) + } + + static inline +-int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext, +- unsigned char *fw_name) ++int brcmf_bus_get_blob(struct brcmf_bus *bus, const struct firmware **fw, ++ enum brcmf_blob_type type) + { +- return bus->ops->get_fwname(bus->dev, ext, fw_name); ++ return bus->ops->get_blob(bus->dev, fw, type); + } + + static inline +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +index fe01da9e620d..95d4c133efdd 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -123,7 +123,6 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) + struct brcmf_bus *bus = drvr->bus_if; + struct brcmf_dload_data_le *chunk_buf; + const struct firmware *clm = NULL; +- u8 clm_name[BRCMF_FW_NAME_LEN]; + u32 chunk_len; + u32 datalen; + u32 cumulative_len; +@@ -133,15 +132,8 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) + + brcmf_dbg(TRACE, "Enter\n"); + +- memset(clm_name, 0, sizeof(clm_name)); +- err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name); +- if (err) { +- bphy_err(drvr, "get CLM blob file name failed (%d)\n", err); +- return err; +- } +- +- err = firmware_request_nowarn(&clm, clm_name, bus->dev); +- if (err) { ++ err = brcmf_bus_get_blob(bus, &clm, BRCMF_BLOB_CLM); ++ if (err || !clm) { + brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", + err); + return 0; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 97f0f13dfe50..ec73d2620ec9 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -66,6 +66,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt"); + + /* per-board firmware binaries */ + MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin"); ++MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.clm_blob"); + + static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), +@@ -261,6 +262,8 @@ struct brcmf_pciedev_info { + struct pci_dev *pdev; + char fw_name[BRCMF_FW_NAME_LEN]; + char nvram_name[BRCMF_FW_NAME_LEN]; ++ char clm_name[BRCMF_FW_NAME_LEN]; ++ const struct firmware *clm_fw; + void __iomem *regs; + void __iomem *tcm; + u32 ram_base; +@@ -1382,23 +1385,25 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len) + return 0; + } + +-static +-int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name) ++static int brcmf_pcie_get_blob(struct device *dev, const struct firmware **fw, ++ enum brcmf_blob_type type) + { + struct brcmf_bus *bus_if = dev_get_drvdata(dev); +- struct brcmf_fw_request *fwreq; +- struct brcmf_fw_name fwnames[] = { +- { ext, fw_name }, +- }; ++ struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie; ++ struct brcmf_pciedev_info *devinfo = buspub->devinfo; + +- fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, +- brcmf_pcie_fwnames, +- ARRAY_SIZE(brcmf_pcie_fwnames), +- fwnames, ARRAY_SIZE(fwnames)); +- if (!fwreq) +- return -ENOMEM; ++ switch (type) { ++ case BRCMF_BLOB_CLM: ++ *fw = devinfo->clm_fw; ++ devinfo->clm_fw = NULL; ++ break; ++ default: ++ return -ENOENT; ++ } ++ ++ if (!*fw) ++ return -ENOENT; + +- kfree(fwreq); + return 0; + } + +@@ -1445,7 +1450,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { + .wowl_config = brcmf_pcie_wowl_config, + .get_ramsize = brcmf_pcie_get_ramsize, + .get_memdump = brcmf_pcie_get_memdump, +- .get_fwname = brcmf_pcie_get_fwname, ++ .get_blob = brcmf_pcie_get_blob, + .reset = brcmf_pcie_reset, + }; + +@@ -1731,6 +1736,7 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { + + #define BRCMF_PCIE_FW_CODE 0 + #define BRCMF_PCIE_FW_NVRAM 1 ++#define BRCMF_PCIE_FW_CLM 2 + + static void brcmf_pcie_setup(struct device *dev, int ret, + struct brcmf_fw_request *fwreq) +@@ -1755,6 +1761,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret, + fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary; + nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data; + nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len; ++ devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary; + kfree(fwreq); + + ret = brcmf_chip_get_raminfo(devinfo->ci); +@@ -1830,6 +1837,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) + struct brcmf_fw_name fwnames[] = { + { ".bin", devinfo->fw_name }, + { ".txt", devinfo->nvram_name }, ++ { ".clm_blob", devinfo->clm_name }, + }; + + fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev, +@@ -1842,6 +1850,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) + fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY; + fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; + fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL; ++ fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY; ++ fwreq->items[BRCMF_PCIE_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL; + fwreq->board_type = devinfo->settings->board_type; + /* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */ + fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1; +@@ -1981,6 +1991,7 @@ brcmf_pcie_remove(struct pci_dev *pdev) + brcmf_pcie_release_ringbuffers(devinfo); + brcmf_pcie_reset_device(devinfo); + brcmf_pcie_release_resource(devinfo); ++ release_firmware(devinfo->clm_fw); + + if (devinfo->ci) + brcmf_chip_detach(devinfo->ci); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +index 212fbbe1cd7e..27dc8ed29ac8 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -4130,23 +4130,24 @@ brcmf_sdio_watchdog(struct timer_list *t) + } + } + +-static +-int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name) ++static int brcmf_sdio_get_blob(struct device *dev, const struct firmware **fw, ++ enum brcmf_blob_type type) + { + struct brcmf_bus *bus_if = dev_get_drvdata(dev); +- struct brcmf_fw_request *fwreq; +- struct brcmf_fw_name fwnames[] = { +- { ext, fw_name }, +- }; ++ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + +- fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, +- brcmf_sdio_fwnames, +- ARRAY_SIZE(brcmf_sdio_fwnames), +- fwnames, ARRAY_SIZE(fwnames)); +- if (!fwreq) +- return -ENOMEM; ++ switch (type) { ++ case BRCMF_BLOB_CLM: ++ *fw = sdiodev->clm_fw; ++ sdiodev->clm_fw = NULL; ++ break; ++ default: ++ return -ENOENT; ++ } ++ ++ if (!*fw) ++ return -ENOENT; + +- kfree(fwreq); + return 0; + } + +@@ -4189,13 +4190,14 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { + .wowl_config = brcmf_sdio_wowl_config, + .get_ramsize = brcmf_sdio_bus_get_ramsize, + .get_memdump = brcmf_sdio_bus_get_memdump, +- .get_fwname = brcmf_sdio_get_fwname, ++ .get_blob = brcmf_sdio_get_blob, + .debugfs_create = brcmf_sdio_debugfs_create, + .reset = brcmf_sdio_bus_reset + }; + + #define BRCMF_SDIO_FW_CODE 0 + #define BRCMF_SDIO_FW_NVRAM 1 ++#define BRCMF_SDIO_FW_CLM 2 + + static void brcmf_sdio_firmware_callback(struct device *dev, int err, + struct brcmf_fw_request *fwreq) +@@ -4218,6 +4220,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, + code = fwreq->items[BRCMF_SDIO_FW_CODE].binary; + nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data; + nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len; ++ sdiod->clm_fw = fwreq->items[BRCMF_SDIO_FW_CLM].binary; + kfree(fwreq); + + /* try to download image and nvram to the dongle */ +@@ -4416,6 +4419,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) + struct brcmf_fw_name fwnames[] = { + { ".bin", bus->sdiodev->fw_name }, + { ".txt", bus->sdiodev->nvram_name }, ++ { ".clm_blob", bus->sdiodev->clm_name }, + }; + + fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, +@@ -4427,6 +4431,8 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) + + fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY; + fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; ++ fwreq->items[BRCMF_SDIO_FW_CLM].type = BRCMF_FW_TYPE_BINARY; ++ fwreq->items[BRCMF_SDIO_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL; + fwreq->board_type = bus->sdiodev->settings->board_type; + + return fwreq; +@@ -4583,6 +4589,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) + if (bus->sdiodev->settings) + brcmf_release_module_param(bus->sdiodev->settings); + ++ release_firmware(bus->sdiodev->clm_fw); ++ bus->sdiodev->clm_fw = NULL; + kfree(bus->rxbuf); + kfree(bus->hdrbuf); + kfree(bus); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +index 15d2c02fa3ec..7b74c295e4c9 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +@@ -186,9 +186,11 @@ struct brcmf_sdio_dev { + struct sg_table sgtable; + char fw_name[BRCMF_FW_NAME_LEN]; + char nvram_name[BRCMF_FW_NAME_LEN]; ++ char clm_name[BRCMF_FW_NAME_LEN]; + bool wowl_enabled; + enum brcmf_sdiod_state state; + struct brcmf_sdiod_freezer *freezer; ++ const struct firmware *clm_fw; + }; + + /* sdio core registers */ +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +index 9fb68c2dc7e3..85e18fb9c497 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -1154,24 +1154,11 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, + return NULL; + } + +-static +-int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name) ++static int brcmf_usb_get_blob(struct device *dev, const struct firmware **fw, ++ enum brcmf_blob_type type) + { +- struct brcmf_bus *bus = dev_get_drvdata(dev); +- struct brcmf_fw_request *fwreq; +- struct brcmf_fw_name fwnames[] = { +- { ext, fw_name }, +- }; +- +- fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev, +- brcmf_usb_fwnames, +- ARRAY_SIZE(brcmf_usb_fwnames), +- fwnames, ARRAY_SIZE(fwnames)); +- if (!fwreq) +- return -ENOMEM; +- +- kfree(fwreq); +- return 0; ++ /* No blobs for USB devices... */ ++ return -ENOENT; + } + + static const struct brcmf_bus_ops brcmf_usb_bus_ops = { +@@ -1180,7 +1167,7 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = { + .txdata = brcmf_usb_tx, + .txctl = brcmf_usb_tx_ctlpkt, + .rxctl = brcmf_usb_rx_ctlpkt, +- .get_fwname = brcmf_usb_get_fwname, ++ .get_blob = brcmf_usb_get_blob, + }; + + #define BRCMF_USB_FW_CODE 0 +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0088-brcmfmac-firmware-Support-passing-in-multiple-board_.patch b/target/linux/silicon/patches-5.19/0088-brcmfmac-firmware-Support-passing-in-multiple-board_.patch new file mode 100644 index 000000000..c8ea1a0c8 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0088-brcmfmac-firmware-Support-passing-in-multiple-board_.patch @@ -0,0 +1,181 @@ +From 95500b48e476af858b0a3ae6c96d9fe8ab92cb61 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 7 Jan 2022 11:14:44 +0900 +Subject: [PATCH 088/171] brcmfmac: firmware: Support passing in multiple + board_types + +Apple platforms have firmware and config files identified with multiple +dimensions. We want to be able to find the most specific firmware +available for any given platform, progressively trying more general +firmwares. + +To do this, first add support for passing in multiple board_types, +which will be tried in sequence. + +Since this will cause more log spam due to missing firmwares, also +switch the secondary firmware fecthes to use the _nowarn variant, which +will not log if the firmware is not found. + +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/firmware.c | 53 +++++++++++++++---- + .../broadcom/brcm80211/brcmfmac/firmware.h | 4 +- + .../broadcom/brcm80211/brcmfmac/pcie.c | 4 +- + .../broadcom/brcm80211/brcmfmac/sdio.c | 2 +- + 4 files changed, 49 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +index deacd39b3f7b..d04a59cf4a1e 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +@@ -430,6 +430,7 @@ struct brcmf_fw { + struct device *dev; + struct brcmf_fw_request *req; + u32 curpos; ++ unsigned int board_index; + void (*done)(struct device *dev, int err, struct brcmf_fw_request *req); + }; + +@@ -625,17 +626,21 @@ static int brcmf_fw_request_firmware(const struct firmware **fw, + struct brcmf_fw *fwctx) + { + struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos]; ++ unsigned int i; + int ret; + +- /* Files can be board-specific, first try a board-specific path */ +- if (fwctx->req->board_type) { ++ /* Files can be board-specific, first try board-specific paths */ ++ for (i = 0; i < ARRAY_SIZE(fwctx->req->board_types); i++) { + char *alt_path; + +- alt_path = brcm_alt_fw_path(cur->path, fwctx->req->board_type); ++ if (!fwctx->req->board_types[i]) ++ goto fallback; ++ alt_path = brcm_alt_fw_path(cur->path, ++ fwctx->req->board_types[i]); + if (!alt_path) + goto fallback; + +- ret = request_firmware(fw, alt_path, fwctx->dev); ++ ret = firmware_request_nowarn(fw, alt_path, fwctx->dev); + kfree(alt_path); + if (ret == 0) + return ret; +@@ -669,15 +674,40 @@ static void brcmf_fw_request_done_alt_path(const struct firmware *fw, void *ctx) + { + struct brcmf_fw *fwctx = ctx; + struct brcmf_fw_item *first = &fwctx->req->items[0]; ++ const char *board_type, *alt_path; + int ret = 0; + +- /* Fall back to canonical path if board firmware not found */ +- if (!fw) +- ret = request_firmware_nowait(THIS_MODULE, true, first->path, ++ if (fw) { ++ brcmf_fw_request_done(fw, ctx); ++ return; ++ } ++ ++ /* Try next board firmware */ ++ if (fwctx->board_index < ARRAY_SIZE(fwctx->req->board_types)) { ++ board_type = fwctx->req->board_types[fwctx->board_index++]; ++ if (!board_type) ++ goto fallback; ++ alt_path = brcm_alt_fw_path(first->path, board_type); ++ if (!alt_path) ++ goto fallback; ++ ++ ret = request_firmware_nowait(THIS_MODULE, true, alt_path, + fwctx->dev, GFP_KERNEL, fwctx, +- brcmf_fw_request_done); ++ brcmf_fw_request_done_alt_path); ++ kfree(alt_path); + +- if (fw || ret < 0) ++ if (ret < 0) ++ brcmf_fw_request_done(fw, ctx); ++ return; ++ } ++ ++fallback: ++ /* Fall back to canonical path if board firmware not found */ ++ ret = request_firmware_nowait(THIS_MODULE, true, first->path, ++ fwctx->dev, GFP_KERNEL, fwctx, ++ brcmf_fw_request_done); ++ ++ if (ret < 0) + brcmf_fw_request_done(fw, ctx); + } + +@@ -721,10 +751,11 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req, + fwctx->done = fw_cb; + + /* First try alternative board-specific path if any */ +- if (fwctx->req->board_type) ++ if (fwctx->req->board_types[0]) + alt_path = brcm_alt_fw_path(first->path, +- fwctx->req->board_type); ++ fwctx->req->board_types[0]); + if (alt_path) { ++ fwctx->board_index++; + ret = request_firmware_nowait(THIS_MODULE, true, alt_path, + fwctx->dev, GFP_KERNEL, fwctx, + brcmf_fw_request_done_alt_path); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h +index e290dec9c53d..1266cbaee072 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h +@@ -11,6 +11,8 @@ + + #define BRCMF_FW_DEFAULT_PATH "brcm/" + ++#define BRCMF_FW_MAX_BOARD_TYPES 8 ++ + /** + * struct brcmf_firmware_mapping - Used to map chipid/revmask to firmware + * filename and nvram filename. Each bus type implementation should create +@@ -66,7 +68,7 @@ struct brcmf_fw_request { + u16 domain_nr; + u16 bus_nr; + u32 n_items; +- const char *board_type; ++ const char *board_types[BRCMF_FW_MAX_BOARD_TYPES]; + struct brcmf_fw_item items[]; + }; + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index ec73d2620ec9..2a74c9d8d46a 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -1852,11 +1852,13 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) + fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL; + fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY; + fwreq->items[BRCMF_PCIE_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL; +- fwreq->board_type = devinfo->settings->board_type; + /* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */ + fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1; + fwreq->bus_nr = devinfo->pdev->bus->number; + ++ brcmf_dbg(PCIE, "Board: %s\n", devinfo->settings->board_type); ++ fwreq->board_types[0] = devinfo->settings->board_type; ++ + return fwreq; + } + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +index 27dc8ed29ac8..2b71991f7d9b 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -4433,7 +4433,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) + fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; + fwreq->items[BRCMF_SDIO_FW_CLM].type = BRCMF_FW_TYPE_BINARY; + fwreq->items[BRCMF_SDIO_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL; +- fwreq->board_type = bus->sdiodev->settings->board_type; ++ fwreq->board_types[0] = bus->sdiodev->settings->board_type; + + return fwreq; + } +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0089-brcmfmac-pcie-Read-Apple-OTP-information.patch b/target/linux/silicon/patches-5.19/0089-brcmfmac-pcie-Read-Apple-OTP-information.patch new file mode 100644 index 000000000..e98372f37 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0089-brcmfmac-pcie-Read-Apple-OTP-information.patch @@ -0,0 +1,299 @@ +From e5b8ff4d315b814e2d81e40838a6df7164f61a77 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:26:34 +0900 +Subject: [PATCH 089/171] brcmfmac: pcie: Read Apple OTP information + +On Apple platforms, the One Time Programmable ROM in the Broadcom chips +contains information about the specific board design (module, vendor, +version) that is required to select the correct NVRAM file. Parse this +OTP ROM and extract the required strings. + +Note that the user OTP offset/size is per-chip. This patch does not add +any chips yet. + +Reviewed-by: Arend van Spriel +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/pcie.c | 218 ++++++++++++++++++ + include/linux/bcma/bcma_driver_chipcommon.h | 1 + + 2 files changed, 219 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 2a74c9d8d46a..17d0353e9105 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -256,6 +256,15 @@ struct brcmf_pcie_core_info { + u32 wrapbase; + }; + ++#define BRCMF_OTP_MAX_PARAM_LEN 16 ++ ++struct brcmf_otp_params { ++ char module[BRCMF_OTP_MAX_PARAM_LEN]; ++ char vendor[BRCMF_OTP_MAX_PARAM_LEN]; ++ char version[BRCMF_OTP_MAX_PARAM_LEN]; ++ bool valid; ++}; ++ + struct brcmf_pciedev_info { + enum brcmf_pcie_state state; + bool in_irq; +@@ -283,6 +292,7 @@ struct brcmf_pciedev_info { + void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + u16 value); + struct brcmf_mp_device *settings; ++ struct brcmf_otp_params otp; + }; + + struct brcmf_pcie_ringbuf { +@@ -354,6 +364,14 @@ static void brcmf_pcie_setup(struct device *dev, int ret, + static struct brcmf_fw_request * + brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo); + ++static u16 ++brcmf_pcie_read_reg16(struct brcmf_pciedev_info *devinfo, u32 reg_offset) ++{ ++ void __iomem *address = devinfo->regs + reg_offset; ++ ++ return ioread16(address); ++} ++ + static u32 + brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset) + { +@@ -499,6 +517,8 @@ brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + } + + ++#define READCC32(devinfo, reg) brcmf_pcie_read_reg32(devinfo, \ ++ CHIPCREGOFFS(reg)) + #define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \ + CHIPCREGOFFS(reg), value) + +@@ -1734,6 +1754,198 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { + .write32 = brcmf_pcie_buscore_write32, + }; + ++#define BRCMF_OTP_SYS_VENDOR 0x15 ++#define BRCMF_OTP_BRCM_CIS 0x80 ++ ++#define BRCMF_OTP_VENDOR_HDR 0x00000008 ++ ++static int ++brcmf_pcie_parse_otp_sys_vendor(struct brcmf_pciedev_info *devinfo, ++ u8 *data, size_t size) ++{ ++ int idx = 4; ++ const char *chip_params; ++ const char *board_params; ++ const char *p; ++ ++ /* 4-byte header and two empty strings */ ++ if (size < 6) ++ return -EINVAL; ++ ++ if (get_unaligned_le32(data) != BRCMF_OTP_VENDOR_HDR) ++ return -EINVAL; ++ ++ chip_params = &data[idx]; ++ ++ /* Skip first string, including terminator */ ++ idx += strnlen(chip_params, size - idx) + 1; ++ if (idx >= size) ++ return -EINVAL; ++ ++ board_params = &data[idx]; ++ ++ /* Skip to terminator of second string */ ++ idx += strnlen(board_params, size - idx); ++ if (idx >= size) ++ return -EINVAL; ++ ++ /* At this point both strings are guaranteed NUL-terminated */ ++ brcmf_dbg(PCIE, "OTP: chip_params='%s' board_params='%s'\n", ++ chip_params, board_params); ++ ++ p = skip_spaces(board_params); ++ while (*p) { ++ char tag = *p++; ++ const char *end; ++ size_t len; ++ ++ if (*p++ != '=') /* implicit NUL check */ ++ return -EINVAL; ++ ++ /* *p might be NUL here, if so end == p and len == 0 */ ++ end = strchrnul(p, ' '); ++ len = end - p; ++ ++ /* leave 1 byte for NUL in destination string */ ++ if (len > (BRCMF_OTP_MAX_PARAM_LEN - 1)) ++ return -EINVAL; ++ ++ /* Copy len characters plus a NUL terminator */ ++ switch (tag) { ++ case 'M': ++ strscpy(devinfo->otp.module, p, len + 1); ++ break; ++ case 'V': ++ strscpy(devinfo->otp.vendor, p, len + 1); ++ break; ++ case 'm': ++ strscpy(devinfo->otp.version, p, len + 1); ++ break; ++ } ++ ++ /* Skip to next arg, if any */ ++ p = skip_spaces(end); ++ } ++ ++ brcmf_dbg(PCIE, "OTP: module=%s vendor=%s version=%s\n", ++ devinfo->otp.module, devinfo->otp.vendor, ++ devinfo->otp.version); ++ ++ if (!devinfo->otp.module[0] || ++ !devinfo->otp.vendor[0] || ++ !devinfo->otp.version[0]) ++ return -EINVAL; ++ ++ devinfo->otp.valid = true; ++ return 0; ++} ++ ++static int ++brcmf_pcie_parse_otp(struct brcmf_pciedev_info *devinfo, u8 *otp, size_t size) ++{ ++ int p = 0; ++ int ret = -EINVAL; ++ ++ brcmf_dbg(PCIE, "parse_otp size=%ld\n", size); ++ ++ while (p < (size - 1)) { ++ u8 type = otp[p]; ++ u8 length = otp[p + 1]; ++ ++ if (type == 0) ++ break; ++ ++ if ((p + 2 + length) > size) ++ break; ++ ++ switch (type) { ++ case BRCMF_OTP_SYS_VENDOR: ++ brcmf_dbg(PCIE, "OTP @ 0x%x (%d): SYS_VENDOR\n", ++ p, length); ++ ret = brcmf_pcie_parse_otp_sys_vendor(devinfo, ++ &otp[p + 2], ++ length); ++ break; ++ case BRCMF_OTP_BRCM_CIS: ++ brcmf_dbg(PCIE, "OTP @ 0x%x (%d): BRCM_CIS\n", ++ p, length); ++ break; ++ default: ++ brcmf_dbg(PCIE, "OTP @ 0x%x (%d): Unknown type 0x%x\n", ++ p, length, type); ++ break; ++ } ++ ++ p += 2 + length; ++ } ++ ++ return ret; ++} ++ ++static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo) ++{ ++ const struct pci_dev *pdev = devinfo->pdev; ++ struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); ++ u32 coreid, base, words, idx, sromctl; ++ u16 *otp; ++ struct brcmf_core *core; ++ int ret; ++ ++ switch (devinfo->ci->chip) { ++ default: ++ /* OTP not supported on this chip */ ++ return 0; ++ } ++ ++ core = brcmf_chip_get_core(devinfo->ci, coreid); ++ if (!core) { ++ brcmf_err(bus, "No OTP core\n"); ++ return -ENODEV; ++ } ++ ++ if (coreid == BCMA_CORE_CHIPCOMMON) { ++ /* Chips with OTP accessed via ChipCommon need additional ++ * handling to access the OTP ++ */ ++ brcmf_pcie_select_core(devinfo, coreid); ++ sromctl = READCC32(devinfo, sromcontrol); ++ ++ if (!(sromctl & BCMA_CC_SROM_CONTROL_OTP_PRESENT)) { ++ /* Chip lacks OTP, try without it... */ ++ brcmf_err(bus, ++ "OTP unavailable, using default firmware\n"); ++ return 0; ++ } ++ ++ /* Map OTP to shadow area */ ++ WRITECC32(devinfo, sromcontrol, ++ sromctl | BCMA_CC_SROM_CONTROL_OTPSEL); ++ } ++ ++ otp = kcalloc(words, sizeof(u16), GFP_KERNEL); ++ if (!otp) ++ return -ENOMEM; ++ ++ /* Map bus window to SROM/OTP shadow area in core */ ++ base = brcmf_pcie_buscore_prep_addr(devinfo->pdev, base + core->base); ++ ++ brcmf_dbg(PCIE, "OTP data:\n"); ++ for (idx = 0; idx < words; idx++) { ++ otp[idx] = brcmf_pcie_read_reg16(devinfo, base + 2 * idx); ++ brcmf_dbg(PCIE, "[%8x] 0x%04x\n", base + 2 * idx, otp[idx]); ++ } ++ ++ if (coreid == BCMA_CORE_CHIPCOMMON) { ++ brcmf_pcie_select_core(devinfo, coreid); ++ WRITECC32(devinfo, sromcontrol, sromctl); ++ } ++ ++ ret = brcmf_pcie_parse_otp(devinfo, (u8 *)otp, 2 * words); ++ kfree(otp); ++ ++ return ret; ++} ++ + #define BRCMF_PCIE_FW_CODE 0 + #define BRCMF_PCIE_FW_NVRAM 1 + #define BRCMF_PCIE_FW_CLM 2 +@@ -1930,6 +2142,12 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) + if (ret) + goto fail_bus; + ++ ret = brcmf_pcie_read_otp(devinfo); ++ if (ret) { ++ brcmf_err(bus, "failed to parse OTP\n"); ++ goto fail_brcmf; ++ } ++ + fwreq = brcmf_pcie_prepare_fw_request(devinfo); + if (!fwreq) { + ret = -ENOMEM; +diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h +index e3314f746bfa..2d94c30ed439 100644 +--- a/include/linux/bcma/bcma_driver_chipcommon.h ++++ b/include/linux/bcma/bcma_driver_chipcommon.h +@@ -271,6 +271,7 @@ + #define BCMA_CC_SROM_CONTROL_OP_WRDIS 0x40000000 + #define BCMA_CC_SROM_CONTROL_OP_WREN 0x60000000 + #define BCMA_CC_SROM_CONTROL_OTPSEL 0x00000010 ++#define BCMA_CC_SROM_CONTROL_OTP_PRESENT 0x00000020 + #define BCMA_CC_SROM_CONTROL_LOCK 0x00000008 + #define BCMA_CC_SROM_CONTROL_SIZE_MASK 0x00000006 + #define BCMA_CC_SROM_CONTROL_SIZE_1K 0x00000000 +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0090-brcmfmac-of-Fetch-Apple-properties.patch b/target/linux/silicon/patches-5.19/0090-brcmfmac-of-Fetch-Apple-properties.patch new file mode 100644 index 000000000..fd8b9803f --- /dev/null +++ b/target/linux/silicon/patches-5.19/0090-brcmfmac-of-Fetch-Apple-properties.patch @@ -0,0 +1,68 @@ +From 59a447e856db9a2c8312d617a6a4f89a629d1bff Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:27:19 +0900 +Subject: [PATCH 090/171] brcmfmac: of: Fetch Apple properties + +On Apple ARM64 platforms, firmware selection requires two properties +that come from system firmware: the module-instance (aka "island", a +codename representing a given hardware platform) and the antenna-sku. +We map Apple's module codenames to board_types in the form +"apple,". + +The mapped board_type is added to the DTS file in that form, while the +antenna-sku is forwarded by our bootloader from the Apple Device Tree +into the FDT. Grab them from the DT so firmware selection can use +them. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../wireless/broadcom/brcm80211/brcmfmac/common.h | 1 + + .../net/wireless/broadcom/brcm80211/brcmfmac/of.c | 12 +++++++++++- + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +index 15accc88d5c0..1f678bbd87aa 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -51,6 +51,7 @@ struct brcmf_mp_device { + struct brcmfmac_pd_cc *country_codes; + const char *board_type; + unsigned char mac[ETH_ALEN]; ++ const char *antenna_sku; + union { + struct brcmfmac_sdio_pd sdio; + } bus; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +index 083ac58f466d..644cc48eae40 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +@@ -64,14 +64,24 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + { + struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio; + struct device_node *root, *np = dev->of_node; ++ const char *prop; + int irq; + int err; + u32 irqf; + u32 val; + ++ /* Apple ARM64 platforms have their own idea of board type, passed in ++ * via the device tree. They also have an antenna SKU parameter ++ */ ++ if (!of_property_read_string(np, "brcm,board-type", &prop)) ++ settings->board_type = prop; ++ ++ if (!of_property_read_string(np, "apple,antenna-sku", &prop)) ++ settings->antenna_sku = prop; ++ + /* Set board-type to the first string of the machine compatible prop */ + root = of_find_node_by_path("/"); +- if (root) { ++ if (root && !settings->board_type) { + int i; + char *board_type; + const char *tmp; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0091-brcmfmac-pcie-Perform-firmware-selection-for-Apple-p.patch b/target/linux/silicon/patches-5.19/0091-brcmfmac-pcie-Perform-firmware-selection-for-Apple-p.patch new file mode 100644 index 000000000..5f490fbbf --- /dev/null +++ b/target/linux/silicon/patches-5.19/0091-brcmfmac-pcie-Perform-firmware-selection-for-Apple-p.patch @@ -0,0 +1,134 @@ +From 608e39fd3521d26bfc846383626f4605d7b273a7 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:45:21 +0900 +Subject: [PATCH 091/171] brcmfmac: pcie: Perform firmware selection for Apple + platforms + +On Apple platforms, firmware selection uses the following elements: + + Property Example Source + ============== ======= ======================== +* Chip name 4378 Device ID +* Chip revision B1 OTP +* Platform shikoku DT (ARM64) or ACPI (x86) +* Module type RASP OTP +* Module vendor m OTP +* Module version 6.11 OTP +* Antenna SKU X3 DT (ARM64) or ACPI (x86) + +In macOS, these firmwares are stored using filenames in this format +under /usr/share/firmware/wifi: + + C-4378__s-B1/P-shikoku-X3_M-RASP_V-m__m-6.11.txt + +To prepare firmwares for Linux, we rename these to a scheme following +the existing brcmfmac convention: + + brcmfmac-pcie.apple,--\ + --.txt + +The NVRAM uses all the components, while the firmware and CLM blob only +use the chip/revision/platform/antenna_sku: + + brcmfmac-pcie.apple,-.bin + +e.g. + + brcm/brcmfmac4378b1-pcie.apple,shikoku-RASP-m-6.11-X3.txt + brcm/brcmfmac4378b1-pcie.apple,shikoku-X3.bin + +In addition, since there are over 1000 files in total, many of which are +symlinks or outright duplicates, we deduplicate and prune the firmware +tree to reduce firmware filenames to fewer dimensions. For example, the +shikoku platform (MacBook Air M1 2020) simplifies to just 4 files: + + brcm/brcmfmac4378b1-pcie.apple,shikoku.clm_blob + brcm/brcmfmac4378b1-pcie.apple,shikoku.bin + brcm/brcmfmac4378b1-pcie.apple,shikoku-RASP-m.txt + brcm/brcmfmac4378b1-pcie.apple,shikoku-RASP-u.txt + +This reduces the total file count to around 170, of which 75 are +symlinks and 95 are regular files: 7 firmware blobs, 27 CLM blobs, and +61 NVRAM config files. We also slightly process NVRAM files to correct +some formatting issues. + +To handle this, the driver must try the following path formats when +looking for firmware files: + + brcm/brcmfmac4378b1-pcie.apple,shikoku-RASP-m-6.11-X3.txt + brcm/brcmfmac4378b1-pcie.apple,shikoku-RASP-m-6.11.txt + brcm/brcmfmac4378b1-pcie.apple,shikoku-RASP-m.txt + brcm/brcmfmac4378b1-pcie.apple,shikoku-RASP.txt + brcm/brcmfmac4378b1-pcie.apple,shikoku-X3.txt * + brcm/brcmfmac4378b1-pcie.apple,shikoku.txt + +* Not relevant for NVRAM, only for firmware/CLM. + +The chip revision nominally comes from OTP on Apple platforms, but it +can be mapped to the PCI revision number, so we ignore the OTP revision +and continue to use the existing PCI revision mechanism to identify chip +revisions, as the driver already does for other chips. Unfortunately, +the mapping is not consistent between different chip types, so this has +to be determined experimentally. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/pcie.c | 41 ++++++++++++++++++- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 17d0353e9105..86807d990cc7 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -2068,8 +2068,45 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) + fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1; + fwreq->bus_nr = devinfo->pdev->bus->number; + +- brcmf_dbg(PCIE, "Board: %s\n", devinfo->settings->board_type); +- fwreq->board_types[0] = devinfo->settings->board_type; ++ /* Apple platforms with fancy firmware/NVRAM selection */ ++ if (devinfo->settings->board_type && ++ devinfo->settings->antenna_sku && ++ devinfo->otp.valid) { ++ const struct brcmf_otp_params *otp = &devinfo->otp; ++ struct device *dev = &devinfo->pdev->dev; ++ const char **bt = fwreq->board_types; ++ ++ brcmf_dbg(PCIE, "Apple board: %s\n", ++ devinfo->settings->board_type); ++ ++ /* Example: apple,shikoku-RASP-m-6.11-X3 */ ++ bt[0] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s-%s-%s-%s", ++ devinfo->settings->board_type, ++ otp->module, otp->vendor, otp->version, ++ devinfo->settings->antenna_sku); ++ bt[1] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s-%s-%s", ++ devinfo->settings->board_type, ++ otp->module, otp->vendor, otp->version); ++ bt[2] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s-%s", ++ devinfo->settings->board_type, ++ otp->module, otp->vendor); ++ bt[3] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s", ++ devinfo->settings->board_type, ++ otp->module); ++ bt[4] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s", ++ devinfo->settings->board_type, ++ devinfo->settings->antenna_sku); ++ bt[5] = devinfo->settings->board_type; ++ ++ if (!bt[0] || !bt[1] || !bt[2] || !bt[3] || !bt[4]) { ++ kfree(fwreq); ++ return NULL; ++ } ++ ++ } else { ++ brcmf_dbg(PCIE, "Board: %s\n", devinfo->settings->board_type); ++ fwreq->board_types[0] = devinfo->settings->board_type; ++ } + + return fwreq; + } +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0092-brcmfmac-firmware-Allow-platform-to-override-macaddr.patch b/target/linux/silicon/patches-5.19/0092-brcmfmac-firmware-Allow-platform-to-override-macaddr.patch new file mode 100644 index 000000000..439980bec --- /dev/null +++ b/target/linux/silicon/patches-5.19/0092-brcmfmac-firmware-Allow-platform-to-override-macaddr.patch @@ -0,0 +1,125 @@ +From 76efd4b5d7adea522c649c6b44d7379e981141b5 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 23 Dec 2021 22:32:08 +0900 +Subject: [PATCH 092/171] brcmfmac: firmware: Allow platform to override + macaddr + +On Device Tree platforms, it is customary to be able to set the MAC +address via the Device Tree, as it is often stored in system firmware. +This is particularly relevant for Apple ARM64 platforms, where this +information comes from system configuration and passed through by the +bootloader into the DT. + +Implement support for this by fetching the platform MAC address and +adding or replacing the macaddr= property in nvram. This becomes the +dongle's default MAC address. + +On platforms with an SROM MAC address, this overrides it. On platforms +without one, such as Apple ARM64 devices, this is required for the +firmware to boot (it will fail if it does not have a valid MAC at all). + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/firmware.c | 28 +++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +index d04a59cf4a1e..fbfc9458d240 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +@@ -21,6 +21,8 @@ + #define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */ + #define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */ + #define BRCMF_FW_DEFAULT_BOARDREV "boardrev=0xff" ++#define BRCMF_FW_MACADDR_FMT "macaddr=%pM" ++#define BRCMF_FW_MACADDR_LEN (7 + ETH_ALEN * 3) + + enum nvram_parser_state { + IDLE, +@@ -57,6 +59,7 @@ struct nvram_parser { + bool multi_dev_v1; + bool multi_dev_v2; + bool boardrev_found; ++ bool strip_mac; + }; + + /* +@@ -121,6 +124,10 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp) + nvp->multi_dev_v2 = true; + if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0) + nvp->boardrev_found = true; ++ /* strip macaddr if platform MAC overrides */ ++ if (nvp->strip_mac && ++ strncmp(&nvp->data[nvp->entry], "macaddr", 7) == 0) ++ st = COMMENT; + } else if (!is_nvram_char(c) || c == ' ') { + brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n", + nvp->line, nvp->column); +@@ -209,6 +216,7 @@ static int brcmf_init_nvram_parser(struct nvram_parser *nvp, + size = data_len; + /* Add space for properties we may add */ + size += strlen(BRCMF_FW_DEFAULT_BOARDREV) + 1; ++ size += BRCMF_FW_MACADDR_LEN + 1; + /* Alloc for extra 0 byte + roundup by 4 + length field */ + size += 1 + 3 + sizeof(u32); + nvp->nvram = kzalloc(size, GFP_KERNEL); +@@ -368,22 +376,34 @@ static void brcmf_fw_add_defaults(struct nvram_parser *nvp) + nvp->nvram_len++; + } + ++static void brcmf_fw_add_macaddr(struct nvram_parser *nvp, u8 *mac) ++{ ++ BUG_ON(snprintf(&nvp->nvram[nvp->nvram_len], BRCMF_FW_MACADDR_LEN + 1, ++ BRCMF_FW_MACADDR_FMT, mac) != BRCMF_FW_MACADDR_LEN); ++ nvp->nvram_len += BRCMF_FW_MACADDR_LEN + 1; ++} ++ + /* brcmf_nvram_strip :Takes a buffer of "=\n" lines read from a fil + * and ending in a NUL. Removes carriage returns, empty lines, comment lines, + * and converts newlines to NULs. Shortens buffer as needed and pads with NULs. + * End of buffer is completed with token identifying length of buffer. + */ + static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len, +- u32 *new_length, u16 domain_nr, u16 bus_nr) ++ u32 *new_length, u16 domain_nr, u16 bus_nr, ++ struct device *dev) + { + struct nvram_parser nvp; + u32 pad; + u32 token; + __le32 token_le; ++ u8 mac[ETH_ALEN]; + + if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0) + return NULL; + ++ if (eth_platform_get_mac_address(dev, mac) == 0) ++ nvp.strip_mac = true; ++ + while (nvp.pos < data_len) { + nvp.state = nv_parser_states[nvp.state](&nvp); + if (nvp.state == END) +@@ -404,6 +424,9 @@ static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len, + + brcmf_fw_add_defaults(&nvp); + ++ if (nvp.strip_mac) ++ brcmf_fw_add_macaddr(&nvp, mac); ++ + pad = nvp.nvram_len; + *new_length = roundup(nvp.nvram_len + 1, 4); + while (pad != *new_length) { +@@ -547,7 +570,8 @@ static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) + if (data) + nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length, + fwctx->req->domain_nr, +- fwctx->req->bus_nr); ++ fwctx->req->bus_nr, ++ fwctx->dev); + + if (free_bcm47xx_nvram) + bcm47xx_nvram_release_contents(data); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0093-brcmfmac-msgbuf-Increase-RX-ring-sizes-to-1024.patch b/target/linux/silicon/patches-5.19/0093-brcmfmac-msgbuf-Increase-RX-ring-sizes-to-1024.patch new file mode 100644 index 000000000..e1eca97b6 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0093-brcmfmac-msgbuf-Increase-RX-ring-sizes-to-1024.patch @@ -0,0 +1,36 @@ +From 9fd60252c13e93ca8ff245f63faf248da6c390f4 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:39:04 +0900 +Subject: [PATCH 093/171] brcmfmac: msgbuf: Increase RX ring sizes to 1024 + +Newer chips used on Apple platforms have a max_rxbufpost greater than +512, which causes warnings when brcmf_msgbuf_rxbuf_data_fill tries to +put more entries in the ring than will fit. Increase the ring sizes +to 1024. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h +index 2e322edbb907..6a849f4a94dd 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h +@@ -8,10 +8,10 @@ + #ifdef CONFIG_BRCMFMAC_PROTO_MSGBUF + + #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 64 +-#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 512 ++#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 1024 + #define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 64 + #define BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM 1024 +-#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 512 ++#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 1024 + #define BRCMF_H2D_TXFLOWRING_MAX_ITEM 512 + + #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40 +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0094-brcmfmac-pcie-Support-PCIe-core-revisions-64.patch b/target/linux/silicon/patches-5.19/0094-brcmfmac-pcie-Support-PCIe-core-revisions-64.patch new file mode 100644 index 000000000..f2307ed02 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0094-brcmfmac-pcie-Support-PCIe-core-revisions-64.patch @@ -0,0 +1,265 @@ +From aa48c835720f5e04ebbe14e3f6b053c8415fb6d9 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:25:35 +0900 +Subject: [PATCH 094/171] brcmfmac: pcie: Support PCIe core revisions >= 64 + +These newer PCIe core revisions include new sets of registers that must +be used instead of the legacy ones. Introduce a brcmf_pcie_reginfo to +hold the specific register offsets and values to use for a given +platform, and change all the register accesses to indirect through it. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/pcie.c | 125 +++++++++++++++--- + 1 file changed, 105 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 86807d990cc7..a2ef3de834f6 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -119,6 +119,12 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0 0x140 + #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1 0x144 + ++#define BRCMF_PCIE_64_PCIE2REG_INTMASK 0xC14 ++#define BRCMF_PCIE_64_PCIE2REG_MAILBOXINT 0xC30 ++#define BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK 0xC34 ++#define BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0 0xA20 ++#define BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1 0xA24 ++ + #define BRCMF_PCIE2_INTA 0x01 + #define BRCMF_PCIE2_INTB 0x02 + +@@ -138,6 +144,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + #define BRCMF_PCIE_MB_INT_D2H3_DB0 0x400000 + #define BRCMF_PCIE_MB_INT_D2H3_DB1 0x800000 + ++#define BRCMF_PCIE_MB_INT_FN0 (BRCMF_PCIE_MB_INT_FN0_0 | \ ++ BRCMF_PCIE_MB_INT_FN0_1) + #define BRCMF_PCIE_MB_INT_D2H_DB (BRCMF_PCIE_MB_INT_D2H0_DB0 | \ + BRCMF_PCIE_MB_INT_D2H0_DB1 | \ + BRCMF_PCIE_MB_INT_D2H1_DB0 | \ +@@ -147,6 +155,40 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_PCIE_MB_INT_D2H3_DB0 | \ + BRCMF_PCIE_MB_INT_D2H3_DB1) + ++#define BRCMF_PCIE_64_MB_INT_D2H0_DB0 0x1 ++#define BRCMF_PCIE_64_MB_INT_D2H0_DB1 0x2 ++#define BRCMF_PCIE_64_MB_INT_D2H1_DB0 0x4 ++#define BRCMF_PCIE_64_MB_INT_D2H1_DB1 0x8 ++#define BRCMF_PCIE_64_MB_INT_D2H2_DB0 0x10 ++#define BRCMF_PCIE_64_MB_INT_D2H2_DB1 0x20 ++#define BRCMF_PCIE_64_MB_INT_D2H3_DB0 0x40 ++#define BRCMF_PCIE_64_MB_INT_D2H3_DB1 0x80 ++#define BRCMF_PCIE_64_MB_INT_D2H4_DB0 0x100 ++#define BRCMF_PCIE_64_MB_INT_D2H4_DB1 0x200 ++#define BRCMF_PCIE_64_MB_INT_D2H5_DB0 0x400 ++#define BRCMF_PCIE_64_MB_INT_D2H5_DB1 0x800 ++#define BRCMF_PCIE_64_MB_INT_D2H6_DB0 0x1000 ++#define BRCMF_PCIE_64_MB_INT_D2H6_DB1 0x2000 ++#define BRCMF_PCIE_64_MB_INT_D2H7_DB0 0x4000 ++#define BRCMF_PCIE_64_MB_INT_D2H7_DB1 0x8000 ++ ++#define BRCMF_PCIE_64_MB_INT_D2H_DB (BRCMF_PCIE_64_MB_INT_D2H0_DB0 | \ ++ BRCMF_PCIE_64_MB_INT_D2H0_DB1 | \ ++ BRCMF_PCIE_64_MB_INT_D2H1_DB0 | \ ++ BRCMF_PCIE_64_MB_INT_D2H1_DB1 | \ ++ BRCMF_PCIE_64_MB_INT_D2H2_DB0 | \ ++ BRCMF_PCIE_64_MB_INT_D2H2_DB1 | \ ++ BRCMF_PCIE_64_MB_INT_D2H3_DB0 | \ ++ BRCMF_PCIE_64_MB_INT_D2H3_DB1 | \ ++ BRCMF_PCIE_64_MB_INT_D2H4_DB0 | \ ++ BRCMF_PCIE_64_MB_INT_D2H4_DB1 | \ ++ BRCMF_PCIE_64_MB_INT_D2H5_DB0 | \ ++ BRCMF_PCIE_64_MB_INT_D2H5_DB1 | \ ++ BRCMF_PCIE_64_MB_INT_D2H6_DB0 | \ ++ BRCMF_PCIE_64_MB_INT_D2H6_DB1 | \ ++ BRCMF_PCIE_64_MB_INT_D2H7_DB0 | \ ++ BRCMF_PCIE_64_MB_INT_D2H7_DB1) ++ + #define BRCMF_PCIE_SHARED_VERSION_7 7 + #define BRCMF_PCIE_MIN_SHARED_VERSION 5 + #define BRCMF_PCIE_MAX_SHARED_VERSION BRCMF_PCIE_SHARED_VERSION_7 +@@ -273,6 +315,7 @@ struct brcmf_pciedev_info { + char nvram_name[BRCMF_FW_NAME_LEN]; + char clm_name[BRCMF_FW_NAME_LEN]; + const struct firmware *clm_fw; ++ const struct brcmf_pcie_reginfo *reginfo; + void __iomem *regs; + void __iomem *tcm; + u32 ram_base; +@@ -359,6 +402,36 @@ static const u32 brcmf_ring_itemsize[BRCMF_NROF_COMMON_MSGRINGS] = { + BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE + }; + ++struct brcmf_pcie_reginfo { ++ u32 intmask; ++ u32 mailboxint; ++ u32 mailboxmask; ++ u32 h2d_mailbox_0; ++ u32 h2d_mailbox_1; ++ u32 int_d2h_db; ++ u32 int_fn0; ++}; ++ ++static const struct brcmf_pcie_reginfo brcmf_reginfo_default = { ++ .intmask = BRCMF_PCIE_PCIE2REG_INTMASK, ++ .mailboxint = BRCMF_PCIE_PCIE2REG_MAILBOXINT, ++ .mailboxmask = BRCMF_PCIE_PCIE2REG_MAILBOXMASK, ++ .h2d_mailbox_0 = BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0, ++ .h2d_mailbox_1 = BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1, ++ .int_d2h_db = BRCMF_PCIE_MB_INT_D2H_DB, ++ .int_fn0 = BRCMF_PCIE_MB_INT_FN0, ++}; ++ ++static const struct brcmf_pcie_reginfo brcmf_reginfo_64 = { ++ .intmask = BRCMF_PCIE_64_PCIE2REG_INTMASK, ++ .mailboxint = BRCMF_PCIE_64_PCIE2REG_MAILBOXINT, ++ .mailboxmask = BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK, ++ .h2d_mailbox_0 = BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0, ++ .h2d_mailbox_1 = BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1, ++ .int_d2h_db = BRCMF_PCIE_64_MB_INT_D2H_DB, ++ .int_fn0 = 0, ++}; ++ + static void brcmf_pcie_setup(struct device *dev, int ret, + struct brcmf_fw_request *fwreq); + static struct brcmf_fw_request * +@@ -802,30 +875,29 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo, + + static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo) + { +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0); ++ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxmask, 0); + } + + + static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo) + { +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, +- BRCMF_PCIE_MB_INT_D2H_DB | +- BRCMF_PCIE_MB_INT_FN0_0 | +- BRCMF_PCIE_MB_INT_FN0_1); ++ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxmask, ++ devinfo->reginfo->int_d2h_db | ++ devinfo->reginfo->int_fn0); + } + + static void brcmf_pcie_hostready(struct brcmf_pciedev_info *devinfo) + { + if (devinfo->shared.flags & BRCMF_PCIE_SHARED_HOSTRDY_DB1) + brcmf_pcie_write_reg32(devinfo, +- BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1, 1); ++ devinfo->reginfo->h2d_mailbox_1, 1); + } + + static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg) + { + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; + +- if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT)) { ++ if (brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint)) { + brcmf_pcie_intr_disable(devinfo); + brcmf_dbg(PCIE, "Enter\n"); + return IRQ_WAKE_THREAD; +@@ -840,15 +912,14 @@ static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg) + u32 status; + + devinfo->in_irq = true; +- status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); ++ status = brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint); + brcmf_dbg(PCIE, "Enter %x\n", status); + if (status) { +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, ++ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxint, + status); +- if (status & (BRCMF_PCIE_MB_INT_FN0_0 | +- BRCMF_PCIE_MB_INT_FN0_1)) ++ if (status & devinfo->reginfo->int_fn0) + brcmf_pcie_handle_mb_data(devinfo); +- if (status & BRCMF_PCIE_MB_INT_D2H_DB) { ++ if (status & devinfo->reginfo->int_d2h_db) { + if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) + brcmf_proto_msgbuf_rx_trigger( + &devinfo->pdev->dev); +@@ -907,8 +978,8 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo) + if (devinfo->in_irq) + brcmf_err(bus, "Still in IRQ (processing) !!!\n"); + +- status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status); ++ status = brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint); ++ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxint, status); + + devinfo->irq_allocated = false; + } +@@ -960,7 +1031,7 @@ static int brcmf_pcie_ring_mb_ring_bell(void *ctx) + + brcmf_dbg(PCIE, "RING !\n"); + /* Any arbitrary value will do, lets use 1 */ +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0, 1); ++ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->h2d_mailbox_0, 1); + + return 0; + } +@@ -1723,15 +1794,22 @@ static int brcmf_pcie_buscoreprep(void *ctx) + static int brcmf_pcie_buscore_reset(void *ctx, struct brcmf_chip *chip) + { + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; +- u32 val; ++ struct brcmf_core *core; ++ u32 val, reg; + + devinfo->ci = chip; + brcmf_pcie_reset_device(devinfo); + +- val = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); ++ /* reginfo is not ready yet */ ++ core = brcmf_chip_get_core(chip, BCMA_CORE_PCIE2); ++ if (core->rev >= 64) ++ reg = BRCMF_PCIE_64_PCIE2REG_MAILBOXINT; ++ else ++ reg = BRCMF_PCIE_PCIE2REG_MAILBOXINT; ++ ++ val = brcmf_pcie_read_reg32(devinfo, reg); + if (val != 0xffffffff) +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, +- val); ++ brcmf_pcie_write_reg32(devinfo, reg, val); + + return 0; + } +@@ -2119,6 +2197,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) + struct brcmf_pciedev_info *devinfo; + struct brcmf_pciedev *pcie_bus_dev; + struct brcmf_bus *bus; ++ struct brcmf_core *core; + + brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device); + +@@ -2137,6 +2216,12 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) + goto fail; + } + ++ core = brcmf_chip_get_core(devinfo->ci, BCMA_CORE_PCIE2); ++ if (core->rev >= 64) ++ devinfo->reginfo = &brcmf_reginfo_64; ++ else ++ devinfo->reginfo = &brcmf_reginfo_default; ++ + pcie_bus_dev = kzalloc(sizeof(*pcie_bus_dev), GFP_KERNEL); + if (pcie_bus_dev == NULL) { + ret = -ENOMEM; +@@ -2306,7 +2391,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev) + brcmf_dbg(PCIE, "Enter, dev=%p, bus=%p\n", dev, bus); + + /* Check if device is still up and running, if so we are ready */ +- if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK) != 0) { ++ if (brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->intmask) != 0) { + brcmf_dbg(PCIE, "Try to wakeup device....\n"); + if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM)) + goto cleanup; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0095-brcmfmac-pcie-Add-IDs-properties-for-BCM4378.patch b/target/linux/silicon/patches-5.19/0095-brcmfmac-pcie-Add-IDs-properties-for-BCM4378.patch new file mode 100644 index 000000000..47ad96d42 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0095-brcmfmac-pcie-Add-IDs-properties-for-BCM4378.patch @@ -0,0 +1,97 @@ +From 54af2b6f4ba6a6a477d9739d24fafe447b1235a3 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:46:40 +0900 +Subject: [PATCH 095/171] brcmfmac: pcie: Add IDs/properties for BCM4378 + +This chip is present on Apple M1 (t8103) platforms: + +* atlantisb (apple,j274): Mac mini (M1, 2020) +* honshu (apple,j293): MacBook Pro (13-inch, M1, 2020) +* shikoku (apple,j313): MacBook Air (M1, 2020) +* capri (apple,j456): iMac (24-inch, 4x USB-C, M1, 2020) +* santorini (apple,j457): iMac (24-inch, 2x USB-C, M1, 2020) + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 2 ++ + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 8 ++++++++ + .../net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 2 ++ + 3 files changed, 12 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 4ec7773b6906..7f1d6cea2141 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -732,6 +732,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) + return 0x160000; + case CY_CC_43752_CHIP_ID: + return 0x170000; ++ case BRCM_CC_4378_CHIP_ID: ++ return 0x352000; + default: + brcmf_err("unknown chip: %s\n", ci->pub.name); + break; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index a2ef3de834f6..2ca2c4b603cf 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -59,6 +59,7 @@ BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie"); + BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); + BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); + BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); ++BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); + + /* firmware config files */ + MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt"); +@@ -88,6 +89,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), ++ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFFF, 4378B1), /* 3 */ + }; + + #define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */ +@@ -1970,6 +1972,11 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo) + int ret; + + switch (devinfo->ci->chip) { ++ case BRCM_CC_4378_CHIP_ID: ++ coreid = BCMA_CORE_GCI; ++ base = 0x1120; ++ words = 0x170; ++ break; + default: + /* OTP not supported on this chip */ + return 0; +@@ -2458,6 +2465,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { + BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID), ++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID), + { /* end: all zeroes */ } + }; + +diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +index ed0b707f0cdf..43158a404652 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +@@ -51,6 +51,7 @@ + #define BRCM_CC_43664_CHIP_ID 43664 + #define BRCM_CC_43666_CHIP_ID 43666 + #define BRCM_CC_4371_CHIP_ID 0x4371 ++#define BRCM_CC_4378_CHIP_ID 0x4378 + #define CY_CC_4373_CHIP_ID 0x4373 + #define CY_CC_43012_CHIP_ID 43012 + #define CY_CC_43752_CHIP_ID 43752 +@@ -87,6 +88,7 @@ + #define BRCM_PCIE_4366_2G_DEVICE_ID 0x43c4 + #define BRCM_PCIE_4366_5G_DEVICE_ID 0x43c5 + #define BRCM_PCIE_4371_DEVICE_ID 0x440d ++#define BRCM_PCIE_4378_DEVICE_ID 0x4425 + + + /* brcmsmac IDs */ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0096-ACPI-property-Support-strings-in-Apple-_DSM-props.patch b/target/linux/silicon/patches-5.19/0096-ACPI-property-Support-strings-in-Apple-_DSM-props.patch new file mode 100644 index 000000000..13f1fce41 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0096-ACPI-property-Support-strings-in-Apple-_DSM-props.patch @@ -0,0 +1,55 @@ +From 7107b9724f933acdb31a3cc87dc80ce7a7484bd5 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 23 Dec 2021 19:51:11 +0900 +Subject: [PATCH 096/171] ACPI / property: Support strings in Apple _DSM props + +The Wi-Fi module in Apple machines has a "module-instance" device +property that specifies the platform type and is used for firmware +selection. Its value is a string, so add support for string values in +acpi_extract_apple_properties(). + +Reviewed-by: Lukas Wunner +Acked-by: Linus Walleij +Signed-off-by: Hector Martin +--- + drivers/acpi/x86/apple.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c +index c285c91a5e9c..71b8f103ab0f 100644 +--- a/drivers/acpi/x86/apple.c ++++ b/drivers/acpi/x86/apple.c +@@ -70,13 +70,16 @@ void acpi_extract_apple_properties(struct acpi_device *adev) + + if ( key->type != ACPI_TYPE_STRING || + (val->type != ACPI_TYPE_INTEGER && +- val->type != ACPI_TYPE_BUFFER)) ++ val->type != ACPI_TYPE_BUFFER && ++ val->type != ACPI_TYPE_STRING)) + continue; /* skip invalid properties */ + + __set_bit(i, valid); + newsize += key->string.length + 1; + if ( val->type == ACPI_TYPE_BUFFER) + newsize += val->buffer.length; ++ else if (val->type == ACPI_TYPE_STRING) ++ newsize += val->string.length + 1; + } + + numvalid = bitmap_weight(valid, numprops); +@@ -118,6 +121,12 @@ void acpi_extract_apple_properties(struct acpi_device *adev) + newprops[v].type = val->type; + if (val->type == ACPI_TYPE_INTEGER) { + newprops[v].integer.value = val->integer.value; ++ } else if (val->type == ACPI_TYPE_STRING) { ++ newprops[v].string.length = val->string.length; ++ newprops[v].string.pointer = free_space; ++ memcpy(free_space, val->string.pointer, ++ val->string.length); ++ free_space += val->string.length + 1; + } else { + newprops[v].buffer.length = val->buffer.length; + newprops[v].buffer.pointer = free_space; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0097-brcmfmac-acpi-Add-support-for-fetching-Apple-ACPI-pr.patch b/target/linux/silicon/patches-5.19/0097-brcmfmac-acpi-Add-support-for-fetching-Apple-ACPI-pr.patch new file mode 100644 index 000000000..289eed869 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0097-brcmfmac-acpi-Add-support-for-fetching-Apple-ACPI-pr.patch @@ -0,0 +1,127 @@ +From 30cf50137a081ece01ac609de4131e20b8cccc1c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 23 Dec 2021 19:51:36 +0900 +Subject: [PATCH 097/171] brcmfmac: acpi: Add support for fetching Apple ACPI + properties + +On DT platforms, the module-instance and antenna-sku-info properties +are passed in the DT. On ACPI platforms, module-instance is passed via +the analogous Apple device property mechanism, while the antenna SKU +info is instead obtained via an ACPI method that grabs it from +non-volatile storage. + +Add support for this, to allow proper firmware selection on Apple +platforms. + +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/Makefile | 2 + + .../broadcom/brcm80211/brcmfmac/acpi.c | 52 +++++++++++++++++++ + .../broadcom/brcm80211/brcmfmac/common.c | 1 + + .../broadcom/brcm80211/brcmfmac/common.h | 9 ++++ + 4 files changed, 64 insertions(+) + create mode 100644 drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile +index 13c13504a6e8..19009eb9db93 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile +@@ -47,3 +47,5 @@ brcmfmac-$(CONFIG_OF) += \ + of.o + brcmfmac-$(CONFIG_DMI) += \ + dmi.o ++brcmfmac-$(CONFIG_ACPI) += \ ++ acpi.o +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c +new file mode 100644 +index 000000000000..dec6a83d13b1 +--- /dev/null ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/acpi.c +@@ -0,0 +1,52 @@ ++// SPDX-License-Identifier: ISC ++/* ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include "debug.h" ++#include "core.h" ++#include "common.h" ++ ++void brcmf_acpi_probe(struct device *dev, enum brcmf_bus_type bus_type, ++ struct brcmf_mp_device *settings) ++{ ++ acpi_status status; ++ const union acpi_object *o; ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ struct acpi_device *adev = ACPI_COMPANION(dev); ++ ++ if (!adev) ++ return; ++ ++ if (!ACPI_FAILURE(acpi_dev_get_property(adev, "module-instance", ++ ACPI_TYPE_STRING, &o))) { ++ brcmf_dbg(INFO, "ACPI module-instance=%s\n", o->string.pointer); ++ settings->board_type = devm_kasprintf(dev, GFP_KERNEL, ++ "apple,%s", ++ o->string.pointer); ++ } else { ++ brcmf_dbg(INFO, "No ACPI module-instance\n"); ++ } ++ ++ status = acpi_evaluate_object(adev->handle, "RWCV", NULL, &buf); ++ o = buf.pointer; ++ if (!ACPI_FAILURE(status) && o && o->type == ACPI_TYPE_BUFFER && ++ o->buffer.length >= 2) { ++ char *antenna_sku = devm_kzalloc(dev, 3, GFP_KERNEL); ++ ++ if (!antenna_sku) { ++ brcmf_err("Failed to allocate antenna-sku"); ++ } else { ++ memcpy(antenna_sku, o->buffer.pointer, 2); ++ brcmf_dbg(INFO, "ACPI RWCV data=%*phN antenna-sku=%s\n", ++ (int)o->buffer.length, o->buffer.pointer, ++ antenna_sku); ++ settings->antenna_sku = antenna_sku; ++ } ++ ++ kfree(buf.pointer); ++ } else { ++ brcmf_dbg(INFO, "No ACPI antenna-sku\n"); ++ } ++} +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +index 95d4c133efdd..ea2475bfc2d7 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -448,6 +448,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, + /* No platform data for this device, try OF and DMI data */ + brcmf_dmi_probe(settings, chip, chiprev); + brcmf_of_probe(dev, bus_type, settings); ++ brcmf_acpi_probe(dev, bus_type, settings); + } + return settings; + } +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +index 1f678bbd87aa..960b1042a7c2 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -74,6 +74,15 @@ static inline void + brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {} + #endif + ++#ifdef CONFIG_ACPI ++void brcmf_acpi_probe(struct device *dev, enum brcmf_bus_type bus_type, ++ struct brcmf_mp_device *settings); ++#else ++static inline void brcmf_acpi_probe(struct device *dev, ++ enum brcmf_bus_type bus_type, ++ struct brcmf_mp_device *settings) {} ++#endif ++ + u8 brcmf_map_prio_to_prec(void *cfg, u8 prio); + + u8 brcmf_map_prio_to_aci(void *cfg, u8 prio); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0098-brcmfmac-pcie-Provide-a-buffer-of-random-bytes-to-th.patch b/target/linux/silicon/patches-5.19/0098-brcmfmac-pcie-Provide-a-buffer-of-random-bytes-to-th.patch new file mode 100644 index 000000000..599e2314e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0098-brcmfmac-pcie-Provide-a-buffer-of-random-bytes-to-th.patch @@ -0,0 +1,82 @@ +From b696ea7c641c2172aff67297e9c0f13d8d46620f Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 23 Dec 2021 19:30:17 +0900 +Subject: [PATCH 098/171] brcmfmac: pcie: Provide a buffer of random bytes to + the device + +Newer Apple firmwares on chipsets without a hardware RNG require the +host to provide a buffer of 256 random bytes to the device on +initialization. This buffer is present immediately before NVRAM, +suffixed by a footer containing a magic number and the buffer length. + +This won't affect chips/firmwares that do not use this feature, so do it +unconditionally. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/pcie.c | 29 +++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 2ca2c4b603cf..1e2afca5a60b 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -1625,6 +1626,13 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, + return 0; + } + ++struct brcmf_random_seed_footer { ++ __le32 length; ++ __le32 magic; ++}; ++ ++#define BRCMF_RANDOM_SEED_MAGIC 0xfeedc0de ++#define BRCMF_RANDOM_SEED_LENGTH 0x100 + + static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, + const struct firmware *fw, void *nvram, +@@ -1656,11 +1664,32 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, + brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0); + + if (nvram) { ++ size_t rand_len = BRCMF_RANDOM_SEED_LENGTH; ++ struct brcmf_random_seed_footer footer = { ++ .length = cpu_to_le32(rand_len), ++ .magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC), ++ }; ++ void *randbuf; ++ + brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name); + address = devinfo->ci->rambase + devinfo->ci->ramsize - + nvram_len; + memcpy_toio(devinfo->tcm + address, nvram, nvram_len); + brcmf_fw_nvram_free(nvram); ++ ++ /* Some Apple chips/firmwares expect a buffer of random data ++ * to be present before NVRAM ++ */ ++ brcmf_dbg(PCIE, "Download random seed\n"); ++ ++ address -= sizeof(footer); ++ memcpy_toio(devinfo->tcm + address, &footer, sizeof(footer)); ++ ++ address -= rand_len; ++ randbuf = kzalloc(rand_len, GFP_KERNEL); ++ get_random_bytes(randbuf, rand_len); ++ memcpy_toio(devinfo->tcm + address, randbuf, rand_len); ++ kfree(randbuf); + } else { + brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", + devinfo->nvram_name); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0099-brcmfmac-pcie-Add-IDs-properties-for-BCM4355.patch b/target/linux/silicon/patches-5.19/0099-brcmfmac-pcie-Add-IDs-properties-for-BCM4355.patch new file mode 100644 index 000000000..5b4695e0a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0099-brcmfmac-pcie-Add-IDs-properties-for-BCM4355.patch @@ -0,0 +1,93 @@ +From f95a34b8e22248b66182a277a825dbb751f25a88 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:50:15 +0900 +Subject: [PATCH 099/171] brcmfmac: pcie: Add IDs/properties for BCM4355 + +This chip is present on at least these Apple T2 Macs: + +* hawaii: MacBook Air 13" (Late 2018) +* hawaii: MacBook Air 13" (True Tone, 2019) + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 1 + + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 8 ++++++++ + .../net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 2 ++ + 3 files changed, 11 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 7f1d6cea2141..6ac6a4414eda 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -727,6 +727,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) + return 0x200000; + case BRCM_CC_4359_CHIP_ID: + return (ci->pub.chiprev < 9) ? 0x180000 : 0x160000; ++ case BRCM_CC_4355_CHIP_ID: + case BRCM_CC_4364_CHIP_ID: + case CY_CC_4373_CHIP_ID: + return 0x160000; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 1e2afca5a60b..67f79985e4b8 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -50,6 +50,7 @@ enum brcmf_pcie_state { + BRCMF_FW_DEF(43602, "brcmfmac43602-pcie"); + BRCMF_FW_DEF(4350, "brcmfmac4350-pcie"); + BRCMF_FW_DEF(4350C, "brcmfmac4350c2-pcie"); ++BRCMF_FW_CLM_DEF(4355C1, "brcmfmac4355c1-pcie"); + BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-pcie"); + BRCMF_FW_CLM_DEF(43570, "brcmfmac43570-pcie"); + BRCMF_FW_DEF(4358, "brcmfmac4358-pcie"); +@@ -76,6 +77,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C), + BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), + BRCMF_FW_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C), ++ BRCMF_FW_ENTRY(BRCM_CC_4355_CHIP_ID, 0xFFFFFFFF, 4355C1), /* 12 */ + BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), + BRCMF_FW_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), + BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570), +@@ -2001,6 +2003,11 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo) + int ret; + + switch (devinfo->ci->chip) { ++ case BRCM_CC_4355_CHIP_ID: ++ coreid = BCMA_CORE_CHIPCOMMON; ++ base = 0x8c0; ++ words = 0xb2; ++ break; + case BRCM_CC_4378_CHIP_ID: + coreid = BCMA_CORE_GCI; + base = 0x1120; +@@ -2475,6 +2482,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { + BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID), + BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_RAW_DEVICE_ID), ++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4355_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), +diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +index 43158a404652..81ada150ee30 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +@@ -37,6 +37,7 @@ + #define BRCM_CC_4350_CHIP_ID 0x4350 + #define BRCM_CC_43525_CHIP_ID 43525 + #define BRCM_CC_4354_CHIP_ID 0x4354 ++#define BRCM_CC_4355_CHIP_ID 0x4355 + #define BRCM_CC_4356_CHIP_ID 0x4356 + #define BRCM_CC_43566_CHIP_ID 43566 + #define BRCM_CC_43567_CHIP_ID 43567 +@@ -70,6 +71,7 @@ + #define BRCM_PCIE_4350_DEVICE_ID 0x43a3 + #define BRCM_PCIE_4354_DEVICE_ID 0x43df + #define BRCM_PCIE_4354_RAW_DEVICE_ID 0x4354 ++#define BRCM_PCIE_4355_DEVICE_ID 0x43dc + #define BRCM_PCIE_4356_DEVICE_ID 0x43ec + #define BRCM_PCIE_43567_DEVICE_ID 0x43d3 + #define BRCM_PCIE_43570_DEVICE_ID 0x43d9 +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0100-brcmfmac-pcie-Add-IDs-properties-for-BCM4377.patch b/target/linux/silicon/patches-5.19/0100-brcmfmac-pcie-Add-IDs-properties-for-BCM4377.patch new file mode 100644 index 000000000..fe0476ae8 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0100-brcmfmac-pcie-Add-IDs-properties-for-BCM4377.patch @@ -0,0 +1,90 @@ +From 3061cca00baa4d818204d3c02b6bf07a87c69150 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:51:31 +0900 +Subject: [PATCH 100/171] brcmfmac: pcie: Add IDs/properties for BCM4377 + +This chip is present on at least these Apple T2 Macs: + +* tahiti: MacBook Pro 13" (2020, 2 TB3) +* formosa: MacBook Pro 13" (Touch/2019) +* fiji: MacBook Air 13" (Scissor, 2020) + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 1 + + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 4 ++++ + drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 2 ++ + 3 files changed, 7 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 6ac6a4414eda..4108108f0431 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -732,6 +732,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) + case CY_CC_4373_CHIP_ID: + return 0x160000; + case CY_CC_43752_CHIP_ID: ++ case BRCM_CC_4377_CHIP_ID: + return 0x170000; + case BRCM_CC_4378_CHIP_ID: + return 0x352000; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 67f79985e4b8..d33919fd1db9 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -61,6 +61,7 @@ BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie"); + BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); + BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); + BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); ++BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); + BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); + + /* firmware config files */ +@@ -92,6 +93,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), ++ BRCMF_FW_ENTRY(BRCM_CC_4377_CHIP_ID, 0xFFFFFFFF, 4377B3), /* 4 */ + BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFFF, 4378B1), /* 3 */ + }; + +@@ -2008,6 +2010,7 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo) + base = 0x8c0; + words = 0xb2; + break; ++ case BRCM_CC_4377_CHIP_ID: + case BRCM_CC_4378_CHIP_ID: + coreid = BCMA_CORE_GCI; + base = 0x1120; +@@ -2502,6 +2505,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { + BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID), ++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID), + { /* end: all zeroes */ } + }; +diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +index 81ada150ee30..6aea4a82e4db 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +@@ -52,6 +52,7 @@ + #define BRCM_CC_43664_CHIP_ID 43664 + #define BRCM_CC_43666_CHIP_ID 43666 + #define BRCM_CC_4371_CHIP_ID 0x4371 ++#define BRCM_CC_4377_CHIP_ID 0x4377 + #define BRCM_CC_4378_CHIP_ID 0x4378 + #define CY_CC_4373_CHIP_ID 0x4373 + #define CY_CC_43012_CHIP_ID 43012 +@@ -90,6 +91,7 @@ + #define BRCM_PCIE_4366_2G_DEVICE_ID 0x43c4 + #define BRCM_PCIE_4366_5G_DEVICE_ID 0x43c5 + #define BRCM_PCIE_4371_DEVICE_ID 0x440d ++#define BRCM_PCIE_4377_DEVICE_ID 0x4488 + #define BRCM_PCIE_4378_DEVICE_ID 0x4425 + + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0101-brcmfmac-pcie-Perform-correct-BCM4364-firmware-selec.patch b/target/linux/silicon/patches-5.19/0101-brcmfmac-pcie-Perform-correct-BCM4364-firmware-selec.patch new file mode 100644 index 000000000..cb45ed38d --- /dev/null +++ b/target/linux/silicon/patches-5.19/0101-brcmfmac-pcie-Perform-correct-BCM4364-firmware-selec.patch @@ -0,0 +1,78 @@ +From 042f6e70e7e365ff921edd13060a638bc7c8ef77 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:51:52 +0900 +Subject: [PATCH 101/171] brcmfmac: pcie: Perform correct BCM4364 firmware + selection + +This chip exists in two revisions (B2=r3 and B3=r4) on different +platforms, and was added without regard to doing proper firmware +selection or differentiating between them. Fix this to have proper +per-revision firmwares and support Apple NVRAM selection. + +Revision B2 is present on at least these Apple T2 Macs: + +kauai: MacBook Pro 15" (Touch/2018-2019) +maui: MacBook Pro 13" (Touch/2018-2019) +lanai: Mac mini (Late 2018) +ekans: iMac Pro 27" (5K, Late 2017) + +And these non-T2 Macs: + +nihau: iMac 27" (5K, 2019) + +Revision B3 is present on at least these Apple T2 Macs: + +bali: MacBook Pro 16" (2019) +trinidad: MacBook Pro 13" (2020, 4 TB3) +borneo: MacBook Pro 16" (2019, 5600M) +kahana: Mac Pro (2019) +kahana: Mac Pro (2019, Rack) +hanauma: iMac 27" (5K, 2020) +kure: iMac 27" (5K, 2020, 5700/XT) + +Fixes: 24f0bd136264 ("brcmfmac: add the BRCM 4364 found in MacBook Pro 15,2") +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index d33919fd1db9..4e5964dd6c47 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -55,7 +55,8 @@ BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-pcie"); + BRCMF_FW_CLM_DEF(43570, "brcmfmac43570-pcie"); + BRCMF_FW_DEF(4358, "brcmfmac4358-pcie"); + BRCMF_FW_DEF(4359, "brcmfmac4359-pcie"); +-BRCMF_FW_DEF(4364, "brcmfmac4364-pcie"); ++BRCMF_FW_CLM_DEF(4364B2, "brcmfmac4364b2-pcie"); ++BRCMF_FW_CLM_DEF(4364B3, "brcmfmac4364b3-pcie"); + BRCMF_FW_DEF(4365B, "brcmfmac4365b-pcie"); + BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie"); + BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); +@@ -85,7 +86,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_FW_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570), + BRCMF_FW_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), + BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), +- BRCMF_FW_ENTRY(BRCM_CC_4364_CHIP_ID, 0xFFFFFFFF, 4364), ++ BRCMF_FW_ENTRY(BRCM_CC_4364_CHIP_ID, 0x0000000F, 4364B2), /* 3 */ ++ BRCMF_FW_ENTRY(BRCM_CC_4364_CHIP_ID, 0xFFFFFFF0, 4364B3), /* 4 */ + BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B), + BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C), + BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), +@@ -2010,6 +2012,11 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo) + base = 0x8c0; + words = 0xb2; + break; ++ case BRCM_CC_4364_CHIP_ID: ++ coreid = BCMA_CORE_CHIPCOMMON; ++ base = 0x8c0; ++ words = 0x1a0; ++ break; + case BRCM_CC_4377_CHIP_ID: + case BRCM_CC_4378_CHIP_ID: + coreid = BCMA_CORE_GCI; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0102-brcmfmac-chip-Only-disable-D11-cores-handle-an-arbit.patch b/target/linux/silicon/patches-5.19/0102-brcmfmac-chip-Only-disable-D11-cores-handle-an-arbit.patch new file mode 100644 index 000000000..cdd582079 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0102-brcmfmac-chip-Only-disable-D11-cores-handle-an-arbit.patch @@ -0,0 +1,53 @@ +From c36c6c77df947acbc4e562a7bc199bff06b79210 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 20 Dec 2021 20:00:57 +0900 +Subject: [PATCH 102/171] brcmfmac: chip: Only disable D11 cores; handle an + arbitrary number + +At least on BCM4387, the D11 cores are held in reset on cold startup and +firmware expects to release reset itself. Just assert reset here and let +firmware deassert it. Premature deassertion results in the firmware +failing to initialize properly some of the time, with strange AXI bus +errors. + +Also, BCM4387 has 3 cores, up from 2. The logic for handling that is in +brcmf_chip_ai_resetcore(), but since we aren't using that any more, just +handle it here. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 4108108f0431..8266466283e4 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -1290,15 +1290,18 @@ static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip) + static inline void + brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip) + { ++ int i; + struct brcmf_core *core; + + brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); + +- core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); +- brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | +- D11_BCMA_IOCTL_PHYCLOCKEN, +- D11_BCMA_IOCTL_PHYCLOCKEN, +- D11_BCMA_IOCTL_PHYCLOCKEN); ++ /* Disable the cores only and let the firmware enable them. ++ * Releasing reset ourselves breaks BCM4387 in weird ways. ++ */ ++ for (i = 0; (core = brcmf_chip_get_d11core(&chip->pub, i)); i++) ++ brcmf_chip_coredisable(core, D11_BCMA_IOCTL_PHYRESET | ++ D11_BCMA_IOCTL_PHYCLOCKEN, ++ D11_BCMA_IOCTL_PHYCLOCKEN); + } + + static bool brcmf_chip_cr4_set_active(struct brcmf_chip_priv *chip, u32 rstvec) +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0103-brcmfmac-chip-Handle-1024-unit-sizes-for-TCM-blocks.patch b/target/linux/silicon/patches-5.19/0103-brcmfmac-chip-Handle-1024-unit-sizes-for-TCM-blocks.patch new file mode 100644 index 000000000..2fc84cacc --- /dev/null +++ b/target/linux/silicon/patches-5.19/0103-brcmfmac-chip-Handle-1024-unit-sizes-for-TCM-blocks.patch @@ -0,0 +1,74 @@ +From 7ab58741bf0d62ff5600dffaf34d06634403f465 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:14:59 +0900 +Subject: [PATCH 103/171] brcmfmac: chip: Handle 1024-unit sizes for TCM blocks + +BCM4387 has trailing odd-sized blocks as part of TCM which have +their size described as a multiple of 1024 instead of 8192. Handle this +so we can compute the TCM size properly. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 8266466283e4..78d835dea8d2 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -212,8 +212,8 @@ struct sbsocramregs { + #define ARMCR4_TCBANB_MASK 0xf + #define ARMCR4_TCBANB_SHIFT 0 + +-#define ARMCR4_BSZ_MASK 0x3f +-#define ARMCR4_BSZ_MULT 8192 ++#define ARMCR4_BSZ_MASK 0x7f ++#define ARMCR4_BLK_1K_MASK 0x200 + + struct brcmf_core_priv { + struct brcmf_core pub; +@@ -675,7 +675,8 @@ static u32 brcmf_chip_sysmem_ramsize(struct brcmf_core_priv *sysmem) + } + + /** Return the TCM-RAM size of the ARMCR4 core. */ +-static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4) ++static u32 brcmf_chip_tcm_ramsize(struct brcmf_chip_priv *ci, ++ struct brcmf_core_priv *cr4) + { + u32 corecap; + u32 memsize = 0; +@@ -683,6 +684,7 @@ static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4) + u32 nbb; + u32 totb; + u32 bxinfo; ++ u32 blksize; + u32 idx; + + corecap = brcmf_chip_core_read32(cr4, ARMCR4_CAP); +@@ -694,7 +696,12 @@ static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4) + for (idx = 0; idx < totb; idx++) { + brcmf_chip_core_write32(cr4, ARMCR4_BANKIDX, idx); + bxinfo = brcmf_chip_core_read32(cr4, ARMCR4_BANKINFO); +- memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; ++ if (bxinfo & ARMCR4_BLK_1K_MASK) ++ blksize = 1024; ++ else ++ blksize = 8192; ++ ++ memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * blksize; + } + + return memsize; +@@ -753,7 +760,7 @@ int brcmf_chip_get_raminfo(struct brcmf_chip *pub) + mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_ARM_CR4); + if (mem) { + mem_core = container_of(mem, struct brcmf_core_priv, pub); +- ci->pub.ramsize = brcmf_chip_tcm_ramsize(mem_core); ++ ci->pub.ramsize = brcmf_chip_tcm_ramsize(ci, mem_core); + ci->pub.rambase = brcmf_chip_tcm_rambase(ci); + if (ci->pub.rambase == INVALID_RAMBASE) { + brcmf_err("RAM base not provided with ARM CR4 core\n"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0104-brcmfmac-cfg80211-Add-support-for-scan-params-v2.patch b/target/linux/silicon/patches-5.19/0104-brcmfmac-cfg80211-Add-support-for-scan-params-v2.patch new file mode 100644 index 000000000..c341d5b3f --- /dev/null +++ b/target/linux/silicon/patches-5.19/0104-brcmfmac-cfg80211-Add-support-for-scan-params-v2.patch @@ -0,0 +1,336 @@ +From 289dcba688d11fbaace7b9011ec1aab5c85f78ba Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 20 Dec 2021 03:39:44 +0900 +Subject: [PATCH 104/171] brcmfmac: cfg80211: Add support for scan params v2 + +This new API version is required for at least the BCM4387 firmware. Add +support for it, with a fallback to the v1 API. + +Acked-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 113 ++++++++++++++---- + .../broadcom/brcm80211/brcmfmac/feature.c | 1 + + .../broadcom/brcm80211/brcmfmac/feature.h | 4 +- + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 49 +++++++- + 4 files changed, 145 insertions(+), 22 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index 605206abe424..3d477f2e5b20 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -770,12 +770,50 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc) + } + } + ++static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, ++ struct brcmf_scan_params_v2_le *params_le, ++ struct cfg80211_scan_request *request); ++ ++static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le, ++ struct brcmf_scan_params_le *params_le) ++{ ++ size_t params_size; ++ u32 ch; ++ int n_channels, n_ssids; ++ ++ memcpy(¶ms_le->ssid_le, ¶ms_v2_le->ssid_le, ++ sizeof(params_le->ssid_le)); ++ memcpy(¶ms_le->bssid, ¶ms_v2_le->bssid, ++ sizeof(params_le->bssid)); ++ ++ params_le->bss_type = params_v2_le->bss_type; ++ params_le->scan_type = params_v2_le->scan_type; ++ params_le->nprobes = params_v2_le->nprobes; ++ params_le->active_time = params_v2_le->active_time; ++ params_le->passive_time = params_v2_le->passive_time; ++ params_le->home_time = params_v2_le->home_time; ++ params_le->channel_num = params_v2_le->channel_num; ++ ++ ch = le32_to_cpu(params_v2_le->channel_num); ++ n_channels = ch & BRCMF_SCAN_PARAMS_COUNT_MASK; ++ n_ssids = ch >> BRCMF_SCAN_PARAMS_NSSID_SHIFT; ++ ++ params_size = sizeof(u16) * n_channels; ++ if (n_ssids > 0) { ++ params_size = roundup(params_size, sizeof(u32)); ++ params_size += sizeof(struct brcmf_ssid_le) * n_ssids; ++ } ++ ++ memcpy(¶ms_le->channel_list[0], ++ ¶ms_v2_le->channel_list[0], params_size); ++} ++ + s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, + struct brcmf_if *ifp, bool aborted, + bool fw_abort) + { + struct brcmf_pub *drvr = cfg->pub; +- struct brcmf_scan_params_le params_le; ++ struct brcmf_scan_params_v2_le params_v2_le; + struct cfg80211_scan_request *scan_request; + u64 reqid; + u32 bucket; +@@ -794,20 +832,23 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, + if (fw_abort) { + /* Do a scan abort to stop the driver's scan engine */ + brcmf_dbg(SCAN, "ABORT scan in firmware\n"); +- memset(¶ms_le, 0, sizeof(params_le)); +- eth_broadcast_addr(params_le.bssid); +- params_le.bss_type = DOT11_BSSTYPE_ANY; +- params_le.scan_type = 0; +- params_le.channel_num = cpu_to_le32(1); +- params_le.nprobes = cpu_to_le32(1); +- params_le.active_time = cpu_to_le32(-1); +- params_le.passive_time = cpu_to_le32(-1); +- params_le.home_time = cpu_to_le32(-1); +- /* Scan is aborted by setting channel_list[0] to -1 */ +- params_le.channel_list[0] = cpu_to_le16(-1); ++ ++ brcmf_escan_prep(cfg, ¶ms_v2_le, NULL); ++ + /* E-Scan (or anyother type) can be aborted by SCAN */ +- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, +- ¶ms_le, sizeof(params_le)); ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) { ++ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, ++ ¶ms_v2_le, ++ sizeof(params_v2_le)); ++ } else { ++ struct brcmf_scan_params_le params_le; ++ ++ brcmf_scan_params_v2_to_v1(¶ms_v2_le, ¶ms_le); ++ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, ++ ¶ms_le, ++ sizeof(params_le)); ++ } ++ + if (err) + bphy_err(drvr, "Scan abort failed\n"); + } +@@ -1027,7 +1068,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, + } + + static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, +- struct brcmf_scan_params_le *params_le, ++ struct brcmf_scan_params_v2_le *params_le, + struct cfg80211_scan_request *request) + { + u32 n_ssids; +@@ -1036,9 +1077,14 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + s32 offset; + u16 chanspec; + char *ptr; ++ int length; + struct brcmf_ssid_le ssid_le; + + eth_broadcast_addr(params_le->bssid); ++ ++ length = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE; ++ ++ params_le->version = BRCMF_SCAN_PARAMS_VERSION_V2; + params_le->bss_type = DOT11_BSSTYPE_ANY; + params_le->scan_type = BRCMF_SCANTYPE_ACTIVE; + params_le->channel_num = 0; +@@ -1048,6 +1094,15 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + params_le->home_time = cpu_to_le32(-1); + memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le)); + ++ /* Scan abort */ ++ if (!request) { ++ length += sizeof(u16); ++ params_le->channel_num = cpu_to_le32(1); ++ params_le->channel_list[0] = cpu_to_le16(-1); ++ params_le->length = cpu_to_le16(length); ++ return; ++ } ++ + n_ssids = request->n_ssids; + n_channels = request->n_channels; + +@@ -1055,6 +1110,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n", + n_channels); + if (n_channels > 0) { ++ length += roundup(sizeof(u16) * n_channels, sizeof(u32)); + for (i = 0; i < n_channels; i++) { + chanspec = channel_to_chanspec(&cfg->d11inf, + request->channels[i]); +@@ -1065,12 +1121,14 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + } else { + brcmf_dbg(SCAN, "Scanning all channels\n"); + } ++ + /* Copy ssid array if applicable */ + brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids); + if (n_ssids > 0) { +- offset = offsetof(struct brcmf_scan_params_le, channel_list) + ++ offset = offsetof(struct brcmf_scan_params_v2_le, channel_list) + + n_channels * sizeof(u16); + offset = roundup(offset, sizeof(u32)); ++ length += sizeof(ssid_le) * n_ssids, + ptr = (char *)params_le + offset; + for (i = 0; i < n_ssids; i++) { + memset(&ssid_le, 0, sizeof(ssid_le)); +@@ -1090,6 +1148,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + brcmf_dbg(SCAN, "Performing passive scan\n"); + params_le->scan_type = BRCMF_SCANTYPE_PASSIVE; + } ++ params_le->length = cpu_to_le16(length); + /* Adding mask to channel numbers */ + params_le->channel_num = + cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) | +@@ -1101,8 +1160,8 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, + struct cfg80211_scan_request *request) + { + struct brcmf_pub *drvr = cfg->pub; +- s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + +- offsetof(struct brcmf_escan_params_le, params_le); ++ s32 params_size = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE + ++ offsetof(struct brcmf_escan_params_le, params_v2_le); + struct brcmf_escan_params_le *params; + s32 err = 0; + +@@ -1122,8 +1181,22 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, + goto exit; + } + BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN); +- brcmf_escan_prep(cfg, ¶ms->params_le, request); +- params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); ++ brcmf_escan_prep(cfg, ¶ms->params_v2_le, request); ++ ++ params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION_V2); ++ ++ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) { ++ struct brcmf_escan_params_le *params_v1; ++ ++ params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE; ++ params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE; ++ params_v1 = kzalloc(params_size, GFP_KERNEL); ++ params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); ++ brcmf_scan_params_v2_to_v1(¶ms->params_v2_le, ¶ms_v1->params_le); ++ kfree(params); ++ params = params_v1; ++ } ++ + params->action = cpu_to_le16(WL_ESCAN_ACTION_START); + params->sync_id = cpu_to_le16(0x1234); + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +index d2ac844e1e9f..19df83399a45 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +@@ -288,6 +288,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) + ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC); + + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); ++ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver"); + + if (drvr->settings->feature_disable) { + brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n", +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +index d1f4257af696..9d098a068d13 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +@@ -29,6 +29,7 @@ + * DOT11H: firmware supports 802.11h + * SAE: simultaneous authentication of equals + * FWAUTH: Firmware authenticator ++ * SCAN_V2: Version 2 scan params + */ + #define BRCMF_FEAT_LIST \ + BRCMF_FEAT_DEF(MBSS) \ +@@ -51,7 +52,8 @@ + BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \ + BRCMF_FEAT_DEF(DOT11H) \ + BRCMF_FEAT_DEF(SAE) \ +- BRCMF_FEAT_DEF(FWAUTH) ++ BRCMF_FEAT_DEF(FWAUTH) \ ++ BRCMF_FEAT_DEF(SCAN_V2) + + /* + * Quirks: +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +index c87b829adb0d..648dc302b998 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -48,6 +48,10 @@ + + /* size of brcmf_scan_params not including variable length array */ + #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 ++#define BRCMF_SCAN_PARAMS_V2_FIXED_SIZE 72 ++ ++/* version of brcmf_scan_params structure */ ++#define BRCMF_SCAN_PARAMS_VERSION_V2 2 + + /* masks for channel and ssid count */ + #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff +@@ -67,6 +71,7 @@ + #define BRCMF_PRIMARY_KEY (1 << 1) + #define DOT11_BSSTYPE_ANY 2 + #define BRCMF_ESCAN_REQ_VERSION 1 ++#define BRCMF_ESCAN_REQ_VERSION_V2 2 + + #define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ + +@@ -386,6 +391,45 @@ struct brcmf_scan_params_le { + __le16 channel_list[1]; /* list of chanspecs */ + }; + ++struct brcmf_scan_params_v2_le { ++ __le16 version; /* structure version */ ++ __le16 length; /* structure length */ ++ struct brcmf_ssid_le ssid_le; /* default: {0, ""} */ ++ u8 bssid[ETH_ALEN]; /* default: bcast */ ++ s8 bss_type; /* default: any, ++ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT ++ */ ++ u8 pad; ++ __le32 scan_type; /* flags, 0 use default */ ++ __le32 nprobes; /* -1 use default, number of probes per channel */ ++ __le32 active_time; /* -1 use default, dwell time per channel for ++ * active scanning ++ */ ++ __le32 passive_time; /* -1 use default, dwell time per channel ++ * for passive scanning ++ */ ++ __le32 home_time; /* -1 use default, dwell time for the ++ * home channel between channel scans ++ */ ++ __le32 channel_num; /* count of channels and ssids that follow ++ * ++ * low half is count of channels in ++ * channel_list, 0 means default (use all ++ * available channels) ++ * ++ * high half is entries in struct brcmf_ssid ++ * array that follows channel_list, aligned for ++ * s32 (4 bytes) meaning an odd channel count ++ * implies a 2-byte pad between end of ++ * channel_list and first ssid ++ * ++ * if ssid count is zero, single ssid in the ++ * fixed parameter portion is assumed, otherwise ++ * ssid in the fixed portion is ignored ++ */ ++ __le16 channel_list[1]; /* list of chanspecs */ ++}; ++ + struct brcmf_scan_results { + u32 buflen; + u32 version; +@@ -397,7 +441,10 @@ struct brcmf_escan_params_le { + __le32 version; + __le16 action; + __le16 sync_id; +- struct brcmf_scan_params_le params_le; ++ union { ++ struct brcmf_scan_params_le params_le; ++ struct brcmf_scan_params_v2_le params_v2_le; ++ }; + }; + + struct brcmf_escan_result_le { +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0105-brcmfmac-feature-Add-support-for-setting-feats-based.patch b/target/linux/silicon/patches-5.19/0105-brcmfmac-feature-Add-support-for-setting-feats-based.patch new file mode 100644 index 000000000..07a37a782 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0105-brcmfmac-feature-Add-support-for-setting-feats-based.patch @@ -0,0 +1,138 @@ +From 219660e563a04cd417b918fcda232433acbea543 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 20 Dec 2021 18:15:10 +0900 +Subject: [PATCH 105/171] brcmfmac: feature: Add support for setting feats + based on WLC version + +The "wlc_ver" iovar returns information on the WLC and EPI versions. +This can be used to determine whether the PMKID_V2 and _V3 features are +supported. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/feature.c | 48 +++++++++++++++++++ + .../broadcom/brcm80211/brcmfmac/feature.h | 4 +- + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 25 ++++++++++ + 3 files changed, 76 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +index 19df83399a45..ac873677343c 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +@@ -126,6 +126,53 @@ static void brcmf_feat_firmware_overrides(struct brcmf_pub *drv) + drv->feat_flags |= feat_flags; + } + ++struct brcmf_feat_wlcfeat { ++ u16 min_ver_major; ++ u16 min_ver_minor; ++ u32 feat_flags; ++}; ++ ++static const struct brcmf_feat_wlcfeat brcmf_feat_wlcfeat_map[] = { ++ { 12, 0, BIT(BRCMF_FEAT_PMKID_V2) }, ++ { 13, 0, BIT(BRCMF_FEAT_PMKID_V3) }, ++}; ++ ++static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv) ++{ ++ struct brcmf_if *ifp = brcmf_get_ifp(drv, 0); ++ const struct brcmf_feat_wlcfeat *e; ++ struct brcmf_wlc_version_le ver; ++ u32 feat_flags = 0; ++ int i, err, major, minor; ++ ++ err = brcmf_fil_iovar_data_get(ifp, "wlc_ver", &ver, sizeof(ver)); ++ if (err) ++ return; ++ ++ major = le16_to_cpu(ver.wlc_ver_major); ++ minor = le16_to_cpu(ver.wlc_ver_minor); ++ ++ brcmf_dbg(INFO, "WLC version: %d.%d\n", major, minor); ++ ++ for (i = 0; i < ARRAY_SIZE(brcmf_feat_wlcfeat_map); i++) { ++ e = &brcmf_feat_wlcfeat_map[i]; ++ if (major > e->min_ver_major || ++ (major == e->min_ver_major && ++ minor >= e->min_ver_minor)) { ++ feat_flags |= e->feat_flags; ++ } ++ } ++ ++ if (!feat_flags) ++ return; ++ ++ for (i = 0; i < BRCMF_FEAT_LAST; i++) ++ if (feat_flags & BIT(i)) ++ brcmf_dbg(INFO, "enabling firmware feature: %s\n", ++ brcmf_feat_names[i]); ++ drv->feat_flags |= feat_flags; ++} ++ + /** + * brcmf_feat_iovar_int_get() - determine feature through iovar query. + * +@@ -297,6 +344,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) + ifp->drvr->feat_flags &= ~drvr->settings->feature_disable; + } + ++ brcmf_feat_wlc_version_overrides(drvr); + brcmf_feat_firmware_overrides(drvr); + + /* set chip related quirks */ +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +index 9d098a068d13..becbcc50d57a 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +@@ -53,7 +53,9 @@ + BRCMF_FEAT_DEF(DOT11H) \ + BRCMF_FEAT_DEF(SAE) \ + BRCMF_FEAT_DEF(FWAUTH) \ +- BRCMF_FEAT_DEF(SCAN_V2) ++ BRCMF_FEAT_DEF(SCAN_V2) \ ++ BRCMF_FEAT_DEF(PMKID_V2) \ ++ BRCMF_FEAT_DEF(PMKID_V3) + + /* + * Quirks: +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +index 648dc302b998..a75aabb0933b 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -788,6 +788,31 @@ struct brcmf_rev_info_le { + __le32 nvramrev; + }; + ++/** ++ * struct brcmf_wlc_version_le - firmware revision info. ++ * ++ * @version: structure version. ++ * @length: structure length. ++ * @epi_ver_major: EPI major version ++ * @epi_ver_minor: EPI minor version ++ * @epi_ver_rc: EPI rc version ++ * @epi_ver_incr: EPI increment version ++ * @wlc_ver_major: WLC major version ++ * @wlc_ver_minor: WLC minor version ++ */ ++struct brcmf_wlc_version_le { ++ __le16 version; ++ __le16 length; ++ ++ __le16 epi_ver_major; ++ __le16 epi_ver_minor; ++ __le16 epi_ver_rc; ++ __le16 epi_ver_incr; ++ ++ __le16 wlc_ver_major; ++ __le16 wlc_ver_minor; ++}; ++ + /** + * struct brcmf_assoclist_le - request assoc list. + * +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0106-brcmfmac-cfg80211-Add-support-for-PMKID_V3-operation.patch b/target/linux/silicon/patches-5.19/0106-brcmfmac-cfg80211-Add-support-for-PMKID_V3-operation.patch new file mode 100644 index 000000000..c5c492b2e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0106-brcmfmac-cfg80211-Add-support-for-PMKID_V3-operation.patch @@ -0,0 +1,228 @@ +From abc68682c16899030b797094581a781c7fadd784 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 20 Dec 2021 18:16:33 +0900 +Subject: [PATCH 106/171] brcmfmac: cfg80211: Add support for PMKID_V3 + operations + +Add support for the new PMKID_V3 API, which allows performing PMKID +mutations individually, instead of requiring the driver to keep track of +the full list. This new API is required by at least BCM4387. + +Note that PMKID_V2 is not implemented yet. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 52 +++++++++++- + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 83 +++++++++++++++++++ + 2 files changed, 132 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index 3d477f2e5b20..6ed53665b0dd 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -4051,6 +4051,37 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, + return 0; + } + ++static s32 ++brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa, ++ bool alive) ++{ ++ struct brcmf_pmk_op_v3_le *pmk_op; ++ int length = offsetof(struct brcmf_pmk_op_v3_le, pmk); ++ int ret; ++ ++ pmk_op = kzalloc(sizeof(*pmk_op), GFP_KERNEL); ++ pmk_op->version = cpu_to_le16(BRCMF_PMKSA_VER_3); ++ ++ if (!pmksa) { ++ /* Flush operation, operate on entire list */ ++ pmk_op->count = cpu_to_le16(0); ++ } else { ++ /* Single PMK operation */ ++ pmk_op->count = cpu_to_le16(1); ++ length += sizeof(struct brcmf_pmksa_v3); ++ memcpy(pmk_op->pmk[0].bssid, pmksa->bssid, ETH_ALEN); ++ memcpy(pmk_op->pmk[0].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); ++ pmk_op->pmk[0].pmkid_len = WLAN_PMKID_LEN; ++ pmk_op->pmk[0].time_left = alive ? BRCMF_PMKSA_NO_EXPIRY : 0; ++ } ++ ++ pmk_op->length = cpu_to_le16(length); ++ ++ ret = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_op, sizeof(*pmk_op)); ++ kfree(pmk_op); ++ return ret; ++} ++ + static __used s32 + brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp) + { +@@ -4087,6 +4118,14 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, + if (!check_vif_up(ifp->vif)) + return -EIO; + ++ brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmksa->bssid); ++ brcmf_dbg(CONN, "%*ph\n", WLAN_PMKID_LEN, pmksa->pmkid); ++ ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3)) ++ return brcmf_pmksa_v3_op(ifp, pmksa, true); ++ ++ /* TODO: implement PMKID_V2 */ ++ + npmk = le32_to_cpu(cfg->pmk_list.npmk); + for (i = 0; i < npmk; i++) + if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN)) +@@ -4103,9 +4142,6 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, + return -EINVAL; + } + +- brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid); +- brcmf_dbg(CONN, "%*ph\n", WLAN_PMKID_LEN, pmk[npmk].pmkid); +- + err = brcmf_update_pmklist(cfg, ifp); + + brcmf_dbg(TRACE, "Exit\n"); +@@ -4129,6 +4165,11 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, + + brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid); + ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3)) ++ return brcmf_pmksa_v3_op(ifp, pmksa, false); ++ ++ /* TODO: implement PMKID_V2 */ ++ + npmk = le32_to_cpu(cfg->pmk_list.npmk); + for (i = 0; i < npmk; i++) + if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN)) +@@ -4165,6 +4206,11 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) + if (!check_vif_up(ifp->vif)) + return -EIO; + ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PMKID_V3)) ++ return brcmf_pmksa_v3_op(ifp, NULL, false); ++ ++ /* TODO: implement PMKID_V2 */ ++ + memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list)); + err = brcmf_update_pmklist(cfg, ifp); + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +index a75aabb0933b..9debd7248344 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -174,6 +174,10 @@ + + #define BRCMF_HE_CAP_MCS_MAP_NSS_MAX 8 + ++#define BRCMF_PMKSA_VER_2 2 ++#define BRCMF_PMKSA_VER_3 3 ++#define BRCMF_PMKSA_NO_EXPIRY 0xffffffff ++ + /* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each + * ioctl. It is relatively small because firmware has small maximum size input + * playload restriction for ioctls. +@@ -355,6 +359,12 @@ struct brcmf_ssid_le { + unsigned char SSID[IEEE80211_MAX_SSID_LEN]; + }; + ++/* Alternate SSID structure used in some places... */ ++struct brcmf_ssid8_le { ++ u8 SSID_len; ++ unsigned char SSID[IEEE80211_MAX_SSID_LEN]; ++}; ++ + struct brcmf_scan_params_le { + struct brcmf_ssid_le ssid_le; /* default: {0, ""} */ + u8 bssid[ETH_ALEN]; /* default: bcast */ +@@ -875,6 +885,51 @@ struct brcmf_pmksa { + u8 pmkid[WLAN_PMKID_LEN]; + }; + ++/** ++ * struct brcmf_pmksa_v2 - PMK Security Association ++ * ++ * @length: Length of the structure. ++ * @bssid: The AP's BSSID. ++ * @pmkid: The PMK ID. ++ * @pmk: PMK material for FILS key derivation. ++ * @pmk_len: Length of PMK data. ++ * @ssid: The AP's SSID. ++ * @fils_cache_id: FILS cache identifier ++ */ ++struct brcmf_pmksa_v2 { ++ __le16 length; ++ u8 bssid[ETH_ALEN]; ++ u8 pmkid[WLAN_PMKID_LEN]; ++ u8 pmk[WLAN_PMK_LEN_SUITE_B_192]; ++ __le16 pmk_len; ++ struct brcmf_ssid8_le ssid; ++ u16 fils_cache_id; ++}; ++ ++/** ++ * struct brcmf_pmksa_v3 - PMK Security Association ++ * ++ * @bssid: The AP's BSSID. ++ * @pmkid: The PMK ID. ++ * @pmkid_len: The length of the PMK ID. ++ * @pmk: PMK material for FILS key derivation. ++ * @pmk_len: Length of PMK data. ++ * @fils_cache_id: FILS cache identifier ++ * @ssid: The AP's SSID. ++ * @time_left: Remaining time until expiry. 0 = expired, ~0 = no expiry. ++ */ ++struct brcmf_pmksa_v3 { ++ u8 bssid[ETH_ALEN]; ++ u8 pmkid[WLAN_PMKID_LEN]; ++ u8 pmkid_len; ++ u8 pmk[WLAN_PMK_LEN_SUITE_B_192]; ++ u8 pmk_len; ++ __le16 fils_cache_id; ++ u8 pad; ++ struct brcmf_ssid8_le ssid; ++ __le32 time_left; ++}; ++ + /** + * struct brcmf_pmk_list_le - List of pmksa's. + * +@@ -886,6 +941,34 @@ struct brcmf_pmk_list_le { + struct brcmf_pmksa pmk[BRCMF_MAXPMKID]; + }; + ++/** ++ * struct brcmf_pmk_list_v2_le - List of pmksa's. ++ * ++ * @version: Request version. ++ * @length: Length of this structure. ++ * @pmk: PMK SA information. ++ */ ++struct brcmf_pmk_list_v2_le { ++ __le16 version; ++ __le16 length; ++ struct brcmf_pmksa_v2 pmk[BRCMF_MAXPMKID]; ++}; ++ ++/** ++ * struct brcmf_pmk_op_v3_le - Operation on PMKSA list. ++ * ++ * @version: Request version. ++ * @length: Length of this structure. ++ * @pmk: PMK SA information. ++ */ ++struct brcmf_pmk_op_v3_le { ++ __le16 version; ++ __le16 length; ++ __le16 count; ++ __le16 pad; ++ struct brcmf_pmksa_v3 pmk[BRCMF_MAXPMKID]; ++}; ++ + /** + * struct brcmf_pno_param_le - PNO scan configuration parameters + * +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0107-brcmfmac-cfg80211-Pass-the-PMK-in-binary-instead-of-.patch b/target/linux/silicon/patches-5.19/0107-brcmfmac-cfg80211-Pass-the-PMK-in-binary-instead-of-.patch new file mode 100644 index 000000000..7de7d322b --- /dev/null +++ b/target/linux/silicon/patches-5.19/0107-brcmfmac-cfg80211-Pass-the-PMK-in-binary-instead-of-.patch @@ -0,0 +1,50 @@ +From 1afeed973f6d538e18e171e55bfa91e25e6b804f Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 20 Dec 2021 19:15:58 +0900 +Subject: [PATCH 107/171] brcmfmac: cfg80211: Pass the PMK in binary instead of + hex + +Apparently the hex passphrase mechanism does not work on newer +chips/firmware (e.g. BCM4387). It seems there was a simple way of +passing it in binary all along, so use that and avoid the hexification. + +OpenBSD has been doing it like this from the beginning, so this should +work on all chips. + +Also clear the structure before setting the PMK. This was leaking +uninitialized stack contents to the device. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index 6ed53665b0dd..7789f74707a7 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -1421,13 +1421,14 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) + { + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_wsec_pmk_le pmk; +- int i, err; ++ int err; ++ ++ memset(&pmk, 0, sizeof(pmk)); + +- /* convert to firmware key format */ +- pmk.key_len = cpu_to_le16(pmk_len << 1); +- pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE); +- for (i = 0; i < pmk_len; i++) +- snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]); ++ /* pass pmk directly */ ++ pmk.key_len = cpu_to_le16(pmk_len); ++ pmk.flags = cpu_to_le16(0); ++ memcpy(pmk.key, pmk_data, pmk_len); + + /* store psk in firmware */ + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0108-brcmflac-cfg80211-Use-WSEC-to-set-SAE-password.patch b/target/linux/silicon/patches-5.19/0108-brcmflac-cfg80211-Use-WSEC-to-set-SAE-password.patch new file mode 100644 index 000000000..522ca760e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0108-brcmflac-cfg80211-Use-WSEC-to-set-SAE-password.patch @@ -0,0 +1,106 @@ +From e918f78b4880ada8e5b5d6a53906c7d86db4b5ec Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 6 Jan 2022 19:45:15 +0900 +Subject: [PATCH 108/171] brcmflac: cfg80211: Use WSEC to set SAE password + +Using the WSEC command instead of sae_password seems to be the supported +mechanism on newer firmware, and also how the brcmdhd driver does it. + +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 46 ++++++++----------- + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 2 +- + 2 files changed, 20 insertions(+), 28 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index 7789f74707a7..63ecbbe11af1 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -1417,52 +1417,44 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e) + return reason; + } + +-static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) ++static int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, u16 key_len, u16 flags) + { + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_wsec_pmk_le pmk; + int err; + ++ if (key_len > sizeof(pmk.key)) { ++ bphy_err(drvr, "key must be less than %zu bytes\n", ++ sizeof(pmk.key)); ++ return -EINVAL; ++ } ++ + memset(&pmk, 0, sizeof(pmk)); + +- /* pass pmk directly */ +- pmk.key_len = cpu_to_le16(pmk_len); +- pmk.flags = cpu_to_le16(0); +- memcpy(pmk.key, pmk_data, pmk_len); ++ /* pass key material directly */ ++ pmk.key_len = cpu_to_le16(key_len); ++ pmk.flags = cpu_to_le16(flags); ++ memcpy(pmk.key, key, key_len); + +- /* store psk in firmware */ ++ /* store key material in firmware */ + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, + &pmk, sizeof(pmk)); + if (err < 0) + bphy_err(drvr, "failed to change PSK in firmware (len=%u)\n", +- pmk_len); ++ key_len); + + return err; + } + ++static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) ++{ ++ return brcmf_set_wsec(ifp, pmk_data, pmk_len, 0); ++} ++ + static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data, + u16 pwd_len) + { +- struct brcmf_pub *drvr = ifp->drvr; +- struct brcmf_wsec_sae_pwd_le sae_pwd; +- int err; +- +- if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { +- bphy_err(drvr, "sae_password must be less than %d\n", +- BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); +- return -EINVAL; +- } +- +- sae_pwd.key_len = cpu_to_le16(pwd_len); +- memcpy(sae_pwd.key, pwd_data, pwd_len); +- +- err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, +- sizeof(sae_pwd)); +- if (err < 0) +- bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", +- pwd_len); +- +- return err; ++ return brcmf_set_wsec(ifp, pwd_data, pwd_len, BRCMF_WSEC_PASSPHRASE); + } + + static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason, +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +index 9debd7248344..1d406649eca2 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -574,7 +574,7 @@ struct brcmf_wsec_key_le { + struct brcmf_wsec_pmk_le { + __le16 key_len; + __le16 flags; +- u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; ++ u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN]; + }; + + /** +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0109-brcmfmac-pcie-Add-IDs-properties-for-BCM4387.patch b/target/linux/silicon/patches-5.19/0109-brcmfmac-pcie-Add-IDs-properties-for-BCM4387.patch new file mode 100644 index 000000000..9617d55d9 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0109-brcmfmac-pcie-Add-IDs-properties-for-BCM4387.patch @@ -0,0 +1,96 @@ +From 5a7fc90929ae21acab41856221149be1343d0e09 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 21 Dec 2021 17:52:03 +0900 +Subject: [PATCH 109/171] brcmfmac: pcie: Add IDs/properties for BCM4387 + +This chip is present on Apple M1 Pro/Max (t600x) platforms: + +* maldives (apple,j314s): MacBook Pro (14-inch, M1 Pro, 2021) +* maldives (apple,j314c): MacBook Pro (14-inch, M1 Max, 2021) +* madagascar (apple,j316s): MacBook Pro (16-inch, M1 Pro, 2021) +* madagascar (apple,j316c): MacBook Pro (16-inch, M1 Max, 2021) + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 2 ++ + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 8 ++++++++ + .../net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 2 ++ + 3 files changed, 12 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 78d835dea8d2..99502de31d56 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -743,6 +743,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) + return 0x170000; + case BRCM_CC_4378_CHIP_ID: + return 0x352000; ++ case BRCM_CC_4387_CHIP_ID: ++ return 0x740000; + default: + brcmf_err("unknown chip: %s\n", ci->pub.name); + break; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 4e5964dd6c47..3597571039a9 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -64,6 +64,7 @@ BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); + BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); + BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); + BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); ++BRCMF_FW_CLM_DEF(4387C2, "brcmfmac4387c2-pcie"); + + /* firmware config files */ + MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt"); +@@ -97,6 +98,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), + BRCMF_FW_ENTRY(BRCM_CC_4377_CHIP_ID, 0xFFFFFFFF, 4377B3), /* 4 */ + BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFFF, 4378B1), /* 3 */ ++ BRCMF_FW_ENTRY(BRCM_CC_4387_CHIP_ID, 0xFFFFFFFF, 4387C2), /* 7 */ + }; + + #define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */ +@@ -2023,6 +2025,11 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo) + base = 0x1120; + words = 0x170; + break; ++ case BRCM_CC_4387_CHIP_ID: ++ coreid = BCMA_CORE_GCI; ++ base = 0x113c; ++ words = 0x170; ++ break; + default: + /* OTP not supported on this chip */ + return 0; +@@ -2514,6 +2521,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { + BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID), ++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID), + { /* end: all zeroes */ } + }; + +diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +index 6aea4a82e4db..7e863cea344f 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +@@ -54,6 +54,7 @@ + #define BRCM_CC_4371_CHIP_ID 0x4371 + #define BRCM_CC_4377_CHIP_ID 0x4377 + #define BRCM_CC_4378_CHIP_ID 0x4378 ++#define BRCM_CC_4387_CHIP_ID 0x4387 + #define CY_CC_4373_CHIP_ID 0x4373 + #define CY_CC_43012_CHIP_ID 43012 + #define CY_CC_43752_CHIP_ID 43752 +@@ -93,6 +94,7 @@ + #define BRCM_PCIE_4371_DEVICE_ID 0x440d + #define BRCM_PCIE_4377_DEVICE_ID 0x4488 + #define BRCM_PCIE_4378_DEVICE_ID 0x4425 ++#define BRCM_PCIE_4387_DEVICE_ID 0x4433 + + + /* brcmsmac IDs */ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0110-brcmfmac-common-Add-support-for-downloading-TxCap-bl.patch b/target/linux/silicon/patches-5.19/0110-brcmfmac-common-Add-support-for-downloading-TxCap-bl.patch new file mode 100644 index 000000000..d082be6ed --- /dev/null +++ b/target/linux/silicon/patches-5.19/0110-brcmfmac-common-Add-support-for-downloading-TxCap-bl.patch @@ -0,0 +1,190 @@ +From 5646bfbf2b14b996481e6ec951df7979cfa15e46 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 26 Dec 2021 00:25:00 +0900 +Subject: [PATCH 110/171] brcmfmac: common: Add support for downloading TxCap + blobs + +The TxCap blobs are additional data blobs used on Apple devices, and +are uploaded analogously to CLM blobs. Add core support for doing this. + +Acked-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/bus.h | 1 + + .../broadcom/brcm80211/brcmfmac/common.c | 97 +++++++++++++------ + 2 files changed, 71 insertions(+), 27 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +index b13af8f631f3..f4bd98da9761 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -39,6 +39,7 @@ enum brcmf_bus_protocol_type { + /* Firmware blobs that may be available */ + enum brcmf_blob_type { + BRCMF_BLOB_CLM, ++ BRCMF_BLOB_TXCAP, + }; + + struct brcmf_mp_device; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +index ea2475bfc2d7..d36aeca5c74e 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -101,7 +101,7 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp) + + static int brcmf_c_download(struct brcmf_if *ifp, u16 flag, + struct brcmf_dload_data_le *dload_buf, +- u32 len) ++ u32 len, const char *var) + { + s32 err; + +@@ -112,17 +112,17 @@ static int brcmf_c_download(struct brcmf_if *ifp, u16 flag, + dload_buf->crc = cpu_to_le32(0); + len = sizeof(*dload_buf) + len - 1; + +- err = brcmf_fil_iovar_data_set(ifp, "clmload", dload_buf, len); ++ err = brcmf_fil_iovar_data_set(ifp, var, dload_buf, len); + + return err; + } + +-static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) ++static int brcmf_c_download_blob(struct brcmf_if *ifp, ++ const void *data, size_t size, ++ const char *loadvar, const char *statvar) + { + struct brcmf_pub *drvr = ifp->drvr; +- struct brcmf_bus *bus = drvr->bus_if; + struct brcmf_dload_data_le *chunk_buf; +- const struct firmware *clm = NULL; + u32 chunk_len; + u32 datalen; + u32 cumulative_len; +@@ -132,20 +132,11 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) + + brcmf_dbg(TRACE, "Enter\n"); + +- err = brcmf_bus_get_blob(bus, &clm, BRCMF_BLOB_CLM); +- if (err || !clm) { +- brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", +- err); +- return 0; +- } +- + chunk_buf = kzalloc(sizeof(*chunk_buf) + MAX_CHUNK_LEN - 1, GFP_KERNEL); +- if (!chunk_buf) { +- err = -ENOMEM; +- goto done; +- } ++ if (!chunk_buf) ++ return -ENOMEM; + +- datalen = clm->size; ++ datalen = size; + cumulative_len = 0; + do { + if (datalen > MAX_CHUNK_LEN) { +@@ -154,9 +145,10 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) + chunk_len = datalen; + dl_flag |= DL_END; + } +- memcpy(chunk_buf->data, clm->data + cumulative_len, chunk_len); ++ memcpy(chunk_buf->data, data + cumulative_len, chunk_len); + +- err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len); ++ err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len, ++ loadvar); + + dl_flag &= ~DL_BEGIN; + +@@ -165,20 +157,64 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) + } while ((datalen > 0) && (err == 0)); + + if (err) { +- bphy_err(drvr, "clmload (%zu byte file) failed (%d)\n", +- clm->size, err); +- /* Retrieve clmload_status and print */ +- err = brcmf_fil_iovar_int_get(ifp, "clmload_status", &status); ++ bphy_err(drvr, "%s (%zu byte file) failed (%d)\n", ++ loadvar, size, err); ++ /* Retrieve status and print */ ++ err = brcmf_fil_iovar_int_get(ifp, statvar, &status); + if (err) +- bphy_err(drvr, "get clmload_status failed (%d)\n", err); ++ bphy_err(drvr, "get %s failed (%d)\n", statvar, err); + else +- brcmf_dbg(INFO, "clmload_status=%d\n", status); ++ brcmf_dbg(INFO, "%s=%d\n", statvar, status); + err = -EIO; + } + + kfree(chunk_buf); +-done: +- release_firmware(clm); ++ return err; ++} ++ ++static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) ++{ ++ struct brcmf_pub *drvr = ifp->drvr; ++ struct brcmf_bus *bus = drvr->bus_if; ++ const struct firmware *fw = NULL; ++ s32 err; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_CLM); ++ if (err || !fw) { ++ brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", ++ err); ++ return 0; ++ } ++ ++ err = brcmf_c_download_blob(ifp, fw->data, fw->size, ++ "clmload", "clmload_status"); ++ ++ release_firmware(fw); ++ return err; ++} ++ ++static int brcmf_c_process_txcap_blob(struct brcmf_if *ifp) ++{ ++ struct brcmf_pub *drvr = ifp->drvr; ++ struct brcmf_bus *bus = drvr->bus_if; ++ const struct firmware *fw = NULL; ++ s32 err; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_TXCAP); ++ if (err || !fw) { ++ brcmf_info("no txcap_blob available (err=%d)\n", err); ++ return 0; ++ } ++ ++ brcmf_info("TxCap blob found, loading\n"); ++ err = brcmf_c_download_blob(ifp, fw->data, fw->size, ++ "txcapload", "txcapload_status"); ++ ++ release_firmware(fw); + return err; + } + +@@ -259,6 +295,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) + goto done; + } + ++ /* Do TxCap downloading, if needed */ ++ err = brcmf_c_process_txcap_blob(ifp); ++ if (err < 0) { ++ bphy_err(drvr, "download TxCap blob file failed, %d\n", err); ++ goto done; ++ } ++ + /* query for 'ver' to get version info from firmware */ + memset(buf, 0, sizeof(buf)); + err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf)); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0111-brcmfmac-pcie-Load-and-provide-TxCap-blobs.patch b/target/linux/silicon/patches-5.19/0111-brcmfmac-pcie-Load-and-provide-TxCap-blobs.patch new file mode 100644 index 000000000..3c3933974 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0111-brcmfmac-pcie-Load-and-provide-TxCap-blobs.patch @@ -0,0 +1,92 @@ +From ab6af8c73a7d8ef3402a2d9cbccaecd707c52491 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 26 Dec 2021 00:26:10 +0900 +Subject: [PATCH 111/171] brcmfmac: pcie: Load and provide TxCap blobs + +These blobs are named .txcap_blob, and exist alongside the existing +.clm_blob files. Use the existing firmware machinery to provide them to +the core. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 3597571039a9..da24915d3555 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -73,6 +73,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt"); + /* per-board firmware binaries */ + MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin"); + MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.clm_blob"); ++MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txcap_blob"); + + static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), +@@ -325,7 +326,9 @@ struct brcmf_pciedev_info { + char fw_name[BRCMF_FW_NAME_LEN]; + char nvram_name[BRCMF_FW_NAME_LEN]; + char clm_name[BRCMF_FW_NAME_LEN]; ++ char txcap_name[BRCMF_FW_NAME_LEN]; + const struct firmware *clm_fw; ++ const struct firmware *txcap_fw; + const struct brcmf_pcie_reginfo *reginfo; + void __iomem *regs; + void __iomem *tcm; +@@ -1499,6 +1502,10 @@ static int brcmf_pcie_get_blob(struct device *dev, const struct firmware **fw, + *fw = devinfo->clm_fw; + devinfo->clm_fw = NULL; + break; ++ case BRCMF_BLOB_TXCAP: ++ *fw = devinfo->txcap_fw; ++ devinfo->txcap_fw = NULL; ++ break; + default: + return -ENOENT; + } +@@ -2087,6 +2094,7 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo) + #define BRCMF_PCIE_FW_CODE 0 + #define BRCMF_PCIE_FW_NVRAM 1 + #define BRCMF_PCIE_FW_CLM 2 ++#define BRCMF_PCIE_FW_TXCAP 3 + + static void brcmf_pcie_setup(struct device *dev, int ret, + struct brcmf_fw_request *fwreq) +@@ -2112,6 +2120,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret, + nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data; + nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len; + devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary; ++ devinfo->txcap_fw = fwreq->items[BRCMF_PCIE_FW_TXCAP].binary; + kfree(fwreq); + + ret = brcmf_chip_get_raminfo(devinfo->ci); +@@ -2188,6 +2197,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) + { ".bin", devinfo->fw_name }, + { ".txt", devinfo->nvram_name }, + { ".clm_blob", devinfo->clm_name }, ++ { ".txcap_blob", devinfo->txcap_name }, + }; + + fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev, +@@ -2202,6 +2212,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) + fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL; + fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY; + fwreq->items[BRCMF_PCIE_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL; ++ fwreq->items[BRCMF_PCIE_FW_TXCAP].type = BRCMF_FW_TYPE_BINARY; ++ fwreq->items[BRCMF_PCIE_FW_TXCAP].flags = BRCMF_FW_REQF_OPTIONAL; + /* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */ + fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1; + fwreq->bus_nr = devinfo->pdev->bus->number; +@@ -2394,6 +2406,7 @@ brcmf_pcie_remove(struct pci_dev *pdev) + brcmf_pcie_reset_device(devinfo); + brcmf_pcie_release_resource(devinfo); + release_firmware(devinfo->clm_fw); ++ release_firmware(devinfo->txcap_fw); + + if (devinfo->ci) + brcmf_chip_detach(devinfo->ci); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0112-brcmfmac-common-Add-support-for-external-calibration.patch b/target/linux/silicon/patches-5.19/0112-brcmfmac-common-Add-support-for-external-calibration.patch new file mode 100644 index 000000000..3b229170c --- /dev/null +++ b/target/linux/silicon/patches-5.19/0112-brcmfmac-common-Add-support-for-external-calibration.patch @@ -0,0 +1,99 @@ +From 16db59b33f07783e609897e51a686d3c10e3a4c1 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 26 Dec 2021 00:53:37 +0900 +Subject: [PATCH 112/171] brcmfmac: common: Add support for external + calibration blobs + +The calibration blob for a chip is normally stored in SROM and loaded +internally by the firmware. However, Apple ARM64 platforms instead store +it as part of platform configuration data, and provide it via the Apple +Device Tree. We forward this into the Linux DT in the bootloader. + +Add support for taking this blob from the DT and loading it into the +dongle. The loading mechanism is the same as used for the CLM and TxCap +blobs. + +Reviewed-by: Linus Walleij +Signed-off-by: Hector Martin +--- + .../broadcom/brcm80211/brcmfmac/common.c | 24 +++++++++++++++++++ + .../broadcom/brcm80211/brcmfmac/common.h | 2 ++ + .../wireless/broadcom/brcm80211/brcmfmac/of.c | 7 ++++++ + 3 files changed, 33 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +index d36aeca5c74e..280ca0f1ba18 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -218,6 +218,23 @@ static int brcmf_c_process_txcap_blob(struct brcmf_if *ifp) + return err; + } + ++static int brcmf_c_process_cal_blob(struct brcmf_if *ifp) ++{ ++ struct brcmf_pub *drvr = ifp->drvr; ++ struct brcmf_mp_device *settings = drvr->settings; ++ s32 err; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ ++ if (!settings->cal_blob || !settings->cal_size) ++ return 0; ++ ++ brcmf_info("Calibration blob provided by platform, loading\n"); ++ err = brcmf_c_download_blob(ifp, settings->cal_blob, settings->cal_size, ++ "calload", "calload_status"); ++ return err; ++} ++ + int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) + { + struct brcmf_pub *drvr = ifp->drvr; +@@ -302,6 +319,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) + goto done; + } + ++ /* Download external calibration blob, if available */ ++ err = brcmf_c_process_cal_blob(ifp); ++ if (err < 0) { ++ bphy_err(drvr, "download calibration blob file failed, %d\n", err); ++ goto done; ++ } ++ + /* query for 'ver' to get version info from firmware */ + memset(buf, 0, sizeof(buf)); + err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf)); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +index 960b1042a7c2..39e8abcf0522 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -52,6 +52,8 @@ struct brcmf_mp_device { + const char *board_type; + unsigned char mac[ETH_ALEN]; + const char *antenna_sku; ++ const void *cal_blob; ++ int cal_size; + union { + struct brcmfmac_sdio_pd sdio; + } bus; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +index 644cc48eae40..60a97277d798 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +@@ -79,6 +79,13 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + if (!of_property_read_string(np, "apple,antenna-sku", &prop)) + settings->antenna_sku = prop; + ++ /* The WLAN calibration blob is normally stored in SROM, but Apple ++ * ARM64 platforms pass it via the DT instead. ++ */ ++ prop = of_get_property(np, "brcm,cal-blob", &settings->cal_size); ++ if (prop && settings->cal_size) ++ settings->cal_blob = prop; ++ + /* Set board-type to the first string of the machine compatible prop */ + root = of_find_node_by_path("/"); + if (root && !settings->board_type) { +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0113-brcmfmac-pcie-Add-BCM4378B3-support.patch b/target/linux/silicon/patches-5.19/0113-brcmfmac-pcie-Add-BCM4378B3-support.patch new file mode 100644 index 000000000..6ce194daf --- /dev/null +++ b/target/linux/silicon/patches-5.19/0113-brcmfmac-pcie-Add-BCM4378B3-support.patch @@ -0,0 +1,38 @@ +From 6d48b52b1d74f5a14d7a99e4007810b2fb04d3bb Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 1 Jul 2022 23:51:23 +0900 +Subject: [PATCH 113/171] brcmfmac: pcie: Add BCM4378B3 support + +BCM4378B3 is a new silicon revision of BCM4378 present on the Apple M2 +13" MacBook Pro "kyushu". Its PCI revision number is 5. + +Signed-off-by: Hector Martin +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index da24915d3555..d26a412c9ca3 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -64,6 +64,7 @@ BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); + BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); + BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); + BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); ++BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie"); + BRCMF_FW_CLM_DEF(4387C2, "brcmfmac4387c2-pcie"); + + /* firmware config files */ +@@ -98,7 +99,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { + BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), + BRCMF_FW_ENTRY(BRCM_CC_4377_CHIP_ID, 0xFFFFFFFF, 4377B3), /* 4 */ +- BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFFF, 4378B1), /* 3 */ ++ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0x0000000F, 4378B1), /* 3 */ ++ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFE0, 4378B3), /* 5 */ + BRCMF_FW_ENTRY(BRCM_CC_4387_CHIP_ID, 0xFFFFFFFF, 4387C2), /* 7 */ + }; + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0114-spi-dt-bindings-add-CS-delay-peripheral-specific-pro.patch b/target/linux/silicon/patches-5.19/0114-spi-dt-bindings-add-CS-delay-peripheral-specific-pro.patch new file mode 100644 index 000000000..c1e46494b --- /dev/null +++ b/target/linux/silicon/patches-5.19/0114-spi-dt-bindings-add-CS-delay-peripheral-specific-pro.patch @@ -0,0 +1,40 @@ +From c95842f5056635608ee0faed77884edb0ac4d5a9 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Sat, 11 Dec 2021 11:48:56 +0100 +Subject: [PATCH 114/171] spi: dt-bindings: add CS delay peripheral-specific + properties + +These properties are modelled after Linux' struct spi_device cs_setup, +cs_hold and cs_inactive delay values. + +Signed-off-by: Janne Grunau +--- + .../bindings/spi/spi-peripheral-props.yaml | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +index 5e32928c4fc3..e8e86e4e4596 100644 +--- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml ++++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +@@ -108,6 +108,18 @@ properties: + minItems: 2 + maxItems: 4 + ++ spi-cs-setup-delay-ns: ++ description: ++ Delay, in nanoseconds, after chip select is asserted. ++ ++ spi-cs-hold-delay-ns: ++ description: ++ Delay, in nanoseconds, before chip select is de-asserted. ++ ++ spi-cs-inactive-delay-ns: ++ description: ++ Delay, in nanoseconds, after chip select is de-asserted. ++ + # The controller specific properties go here. + allOf: + - $ref: cdns,qspi-nor-peripheral-props.yaml# +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0115-spi-parse-CS-delay-values-from-DT.patch b/target/linux/silicon/patches-5.19/0115-spi-parse-CS-delay-values-from-DT.patch new file mode 100644 index 000000000..4f1189e08 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0115-spi-parse-CS-delay-values-from-DT.patch @@ -0,0 +1,52 @@ +From 9bdcdedc55c469556ca5c21ae129bd3ec0b19762 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Sat, 11 Dec 2021 12:21:04 +0100 +Subject: [PATCH 115/171] spi: parse CS delay values from DT + +Signed-off-by: Janne Grunau +--- + drivers/spi/spi.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index ea09d1b42bf6..c8342b950783 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -2059,6 +2059,22 @@ void spi_flush_queue(struct spi_controller *ctlr) + /*-------------------------------------------------------------------------*/ + + #if defined(CONFIG_OF) ++static void of_spi_parse_dt_cs_delay(struct device_node *nc, ++ struct spi_delay *delay, const char *prop) ++{ ++ u32 value; ++ ++ if (!of_property_read_u32(nc, prop, &value)) { ++ if (value > U16_MAX) { ++ delay->value = DIV_ROUND_UP(value, 1000); ++ delay->unit = SPI_DELAY_UNIT_USECS; ++ } else { ++ delay->value = value; ++ delay->unit = SPI_DELAY_UNIT_NSECS; ++ } ++ } ++} ++ + static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, + struct device_node *nc) + { +@@ -2148,6 +2164,11 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, + if (!of_property_read_u32(nc, "spi-max-frequency", &value)) + spi->max_speed_hz = value; + ++ /* Device CS delays */ ++ of_spi_parse_dt_cs_delay(nc, &spi->cs_setup, "spi-cs-setup-delay-ns"); ++ of_spi_parse_dt_cs_delay(nc, &spi->cs_hold, "spi-cs-hold-delay-ns"); ++ of_spi_parse_dt_cs_delay(nc, &spi->cs_inactive, "spi-cs-inactive-delay-ns"); ++ + return 0; + } + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0116-HID-add-device-IDs-for-Apple-SPI-HID-devices.patch b/target/linux/silicon/patches-5.19/0116-HID-add-device-IDs-for-Apple-SPI-HID-devices.patch new file mode 100644 index 000000000..5dff7ddc2 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0116-HID-add-device-IDs-for-Apple-SPI-HID-devices.patch @@ -0,0 +1,84 @@ +From 2f160927c7f5de32ea8fe86c682565cacccdbaa4 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Sun, 12 Dec 2021 20:40:04 +0100 +Subject: [PATCH 116/171] HID: add device IDs for Apple SPI HID devices + +Apple Silicon based laptop use SPI as transport for HID. Add support for +SPI-based HID devices and and Apple keyboard and trackpad devices. +Intel based laptops using the keyboard input driver applespi use the +same HID over SPI protocol and can be supported later. + +This requires SPI keyboard/mouse HID types since Apple's intenal +keyboards/trackpads use the same product id. + +Signed-off-by: Janne Grunau +--- + drivers/hid/hid-core.c | 3 +++ + drivers/hid/hid-ids.h | 5 +++++ + include/linux/hid.h | 6 +++++- + 3 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 00154a1cd2d8..22f313716a12 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -2219,6 +2219,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) + case BUS_I2C: + bus = "I2C"; + break; ++ case BUS_SPI: ++ bus = "SPI"; ++ break; + case BUS_VIRTUAL: + bus = "VIRTUAL"; + break; +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index d9eb676abe96..98f922774df9 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -89,6 +89,7 @@ + + #define USB_VENDOR_ID_APPLE 0x05ac + #define BT_VENDOR_ID_APPLE 0x004c ++#define SPI_VENDOR_ID_APPLE 0x05ac + #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 + #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d + #define USB_DEVICE_ID_APPLE_MAGICMOUSE2 0x0269 +@@ -185,6 +186,10 @@ + #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 0x029c + #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 0x029a + #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021 0x029f ++#define SPI_DEVICE_ID_APPLE_MACBOOK_AIR_2020 0x0281 ++#define SPI_DEVICE_ID_APPLE_MACBOOK_PRO13_2020 0x0341 ++#define SPI_DEVICE_ID_APPLE_MACBOOK_PRO14_2021 0x0342 ++#define SPI_DEVICE_ID_APPLE_MACBOOK_PRO16_2021 0x0343 + + #define USB_VENDOR_ID_ASUS 0x0486 + #define USB_DEVICE_ID_ASUS_T91MT 0x0185 +diff --git a/include/linux/hid.h b/include/linux/hid.h +index 4363a63b9775..dacfc4c7ce01 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -569,7 +569,9 @@ struct hid_input { + enum hid_type { + HID_TYPE_OTHER = 0, + HID_TYPE_USBMOUSE, +- HID_TYPE_USBNONE ++ HID_TYPE_USBNONE, ++ HID_TYPE_SPI_KEYBOARD, ++ HID_TYPE_SPI_MOUSE, + }; + + enum hid_battery_status { +@@ -715,6 +717,8 @@ struct hid_descriptor { + .bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod) + #define HID_I2C_DEVICE(ven, prod) \ + .bus = BUS_I2C, .vendor = (ven), .product = (prod) ++#define HID_SPI_DEVICE(ven, prod) \ ++ .bus = BUS_SPI, .vendor = (ven), .product = (prod) + + #define HID_REPORT_ID(rep) \ + .report_type = (rep) +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0117-HID-apple-add-support-for-internal-keyboards.patch b/target/linux/silicon/patches-5.19/0117-HID-apple-add-support-for-internal-keyboards.patch new file mode 100644 index 000000000..9f1fa0bc5 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0117-HID-apple-add-support-for-internal-keyboards.patch @@ -0,0 +1,68 @@ +From f0822fe21629ff17bacc0bc48a89bc956d6343a5 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Thu, 16 Dec 2021 21:15:31 +0100 +Subject: [PATCH 117/171] HID: apple: add support for internal keyboards + +Apple MacBook keyboards started using HID over SPI in 2015. With the +addition of the SPI HID transport they can be supported by this driver. +Support all product ids over with the Apple SPI vendor id for now. +Individual product ids will have to be added for a correct Fn/function +key mapping. + +Enable by default on the Apple Arm platform. + +Signed-off-by: Janne Grunau +--- + drivers/hid/Kconfig | 4 ++-- + drivers/hid/hid-apple.c | 6 ++++++ + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 70da5931082f..77c3c00c877c 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -130,7 +130,7 @@ config HID_APPLE + depends on HID + depends on LEDS_CLASS + depends on NEW_LEDS +- default !EXPERT ++ default !EXPERT || SPI_HID_APPLE + help + Support for some Apple devices which less or more break + HID specification. +@@ -1041,7 +1041,7 @@ config HID_SONY + * Guitar Hero PS3 and PC guitar dongles + + config SONY_FF +- bool "Sony PS2/3/4 accessories force feedback support" ++ bool "Sony PS2/3/4 accessories force feedback support" + depends on HID_SONY + select INPUT_FF_MEMLESS + help +diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c +index 42a568902f49..a085ea01d5b9 100644 +--- a/drivers/hid/hid-apple.c ++++ b/drivers/hid/hid-apple.c +@@ -783,6 +783,10 @@ static int apple_probe(struct hid_device *hdev, + struct apple_sc *asc; + int ret; + ++ if (id->bus == BUS_SPI && id->vendor == SPI_VENDOR_ID_APPLE && ++ hdev->type != HID_TYPE_SPI_KEYBOARD) ++ return -ENODEV; ++ + asc = devm_kzalloc(&hdev->dev, sizeof(*asc), GFP_KERNEL); + if (asc == NULL) { + hid_err(hdev, "can't alloc apple descriptor\n"); +@@ -1024,6 +1028,8 @@ static const struct hid_device_id apple_devices[] = { + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, ++ { HID_SPI_DEVICE(SPI_VENDOR_ID_APPLE, HID_ANY_ID), ++ .driver_data = APPLE_HAS_FN }, + + { } + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0118-HID-apple-add-Fn-key-mapping-for-Apple-silicon-MacBo.patch b/target/linux/silicon/patches-5.19/0118-HID-apple-add-Fn-key-mapping-for-Apple-silicon-MacBo.patch new file mode 100644 index 000000000..54d0b45cf --- /dev/null +++ b/target/linux/silicon/patches-5.19/0118-HID-apple-add-Fn-key-mapping-for-Apple-silicon-MacBo.patch @@ -0,0 +1,64 @@ +From 2774e7333992ed45f44c7e190863b60a49876663 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Sun, 19 Dec 2021 18:08:15 +0100 +Subject: [PATCH 118/171] HID: apple: add Fn key mapping for Apple silicon + MacBooks + +Signed-off-by: Janne Grunau +--- + drivers/hid/hid-apple.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c +index a085ea01d5b9..1511a2bda01f 100644 +--- a/drivers/hid/hid-apple.c ++++ b/drivers/hid/hid-apple.c +@@ -252,6 +252,28 @@ static const struct apple_key_translation apple_fn_keys[] = { + { } + }; + ++static const struct apple_key_translation apple_fn_keys_spi[] = { ++ { KEY_BACKSPACE, KEY_DELETE }, ++ { KEY_ENTER, KEY_INSERT }, ++ { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, ++ { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, ++ { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, ++ { KEY_F4, KEY_SEARCH, APPLE_FLAG_FKEY }, ++ { KEY_F5, KEY_RECORD, APPLE_FLAG_FKEY }, ++ { KEY_F6, KEY_SLEEP, APPLE_FLAG_FKEY }, ++ { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, ++ { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, ++ { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, ++ { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, ++ { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, ++ { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, ++ { KEY_UP, KEY_PAGEUP }, ++ { KEY_DOWN, KEY_PAGEDOWN }, ++ { KEY_LEFT, KEY_HOME }, ++ { KEY_RIGHT, KEY_END }, ++ { } ++}; ++ + static const struct apple_key_translation powerbook_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, +@@ -400,6 +422,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, + else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && + hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) + table = macbookair_fn_keys; ++ else if (hid->vendor == SPI_VENDOR_ID_APPLE) ++ table = apple_fn_keys_spi; + else if (hid->product < 0x21d || hid->product >= 0x300) + table = powerbook_fn_keys; + else +@@ -607,6 +631,7 @@ static void apple_setup_input(struct input_dev *input) + + /* Enable all needed keys */ + apple_setup_key_translation(input, apple_fn_keys); ++ apple_setup_key_translation(input, apple_fn_keys_spi); + apple_setup_key_translation(input, powerbook_fn_keys); + apple_setup_key_translation(input, powerbook_numlock_keys); + apple_setup_key_translation(input, apple_iso_keyboard); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0119-HID-apple-add-Fn-key-mapping-for-Macbook-Pro-with-to.patch b/target/linux/silicon/patches-5.19/0119-HID-apple-add-Fn-key-mapping-for-Macbook-Pro-with-to.patch new file mode 100644 index 000000000..66264c7dd --- /dev/null +++ b/target/linux/silicon/patches-5.19/0119-HID-apple-add-Fn-key-mapping-for-Macbook-Pro-with-to.patch @@ -0,0 +1,65 @@ +From 45ee3be14adf625c8ee187485e8e24587e467f16 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Wed, 5 Jan 2022 23:27:34 +0100 +Subject: [PATCH 119/171] HID: apple: add Fn key mapping for Macbook Pro with + touchbar + +Signed-off-by: Janne Grunau +--- + drivers/hid/hid-apple.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c +index 1511a2bda01f..6700cbac2575 100644 +--- a/drivers/hid/hid-apple.c ++++ b/drivers/hid/hid-apple.c +@@ -274,6 +274,28 @@ static const struct apple_key_translation apple_fn_keys_spi[] = { + { } + }; + ++static const struct apple_key_translation apple_fn_keys_mbp13[] = { ++ { KEY_BACKSPACE, KEY_DELETE }, ++ { KEY_ENTER, KEY_INSERT }, ++ { KEY_UP, KEY_PAGEUP }, ++ { KEY_DOWN, KEY_PAGEDOWN }, ++ { KEY_LEFT, KEY_HOME }, ++ { KEY_RIGHT, KEY_END }, ++ { KEY_1, KEY_F1 }, ++ { KEY_2, KEY_F2 }, ++ { KEY_3, KEY_F3 }, ++ { KEY_4, KEY_F4 }, ++ { KEY_5, KEY_F5 }, ++ { KEY_6, KEY_F6 }, ++ { KEY_7, KEY_F7 }, ++ { KEY_8, KEY_F8 }, ++ { KEY_9, KEY_F9 }, ++ { KEY_0, KEY_F10 }, ++ { KEY_MINUS, KEY_F11 }, ++ { KEY_EQUAL, KEY_F12 }, ++ { } ++}; ++ + static const struct apple_key_translation powerbook_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, +@@ -422,6 +444,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, + else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && + hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) + table = macbookair_fn_keys; ++ else if (hid->vendor == SPI_VENDOR_ID_APPLE && ++ hid->product == SPI_DEVICE_ID_APPLE_MACBOOK_PRO13_2020) ++ table = apple_fn_keys_mbp13; + else if (hid->vendor == SPI_VENDOR_ID_APPLE) + table = apple_fn_keys_spi; + else if (hid->product < 0x21d || hid->product >= 0x300) +@@ -632,6 +657,7 @@ static void apple_setup_input(struct input_dev *input) + /* Enable all needed keys */ + apple_setup_key_translation(input, apple_fn_keys); + apple_setup_key_translation(input, apple_fn_keys_spi); ++ apple_setup_key_translation(input, apple_fn_keys_mbp13); + apple_setup_key_translation(input, powerbook_fn_keys); + apple_setup_key_translation(input, powerbook_numlock_keys); + apple_setup_key_translation(input, apple_iso_keyboard); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0120-HID-magicmouse-use-a-define-of-the-max-number-of-tou.patch b/target/linux/silicon/patches-5.19/0120-HID-magicmouse-use-a-define-of-the-max-number-of-tou.patch new file mode 100644 index 000000000..2469c6d35 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0120-HID-magicmouse-use-a-define-of-the-max-number-of-tou.patch @@ -0,0 +1,47 @@ +From 868d1a8a613bcae69bcbde7b42ced0ff97110d09 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Thu, 16 Dec 2021 00:10:51 +0100 +Subject: [PATCH 120/171] HID: magicmouse: use a define of the max number of + touch contacts + +Signed-off-by: Janne Grunau +--- + drivers/hid/hid-magicmouse.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c +index 664a624a363d..f4192e503b2c 100644 +--- a/drivers/hid/hid-magicmouse.c ++++ b/drivers/hid/hid-magicmouse.c +@@ -61,6 +61,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie + #define DOUBLE_REPORT_ID 0xf7 + #define USB_BATTERY_TIMEOUT_MS 60000 + ++#define MAX_CONTACTS 16 ++ + /* These definitions are not precise, but they're close enough. (Bits + * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem + * to be some kind of bit mask -- 0x20 may be a near-field reading, +@@ -139,8 +141,8 @@ struct magicmouse_sc { + u8 size; + bool scroll_x_active; + bool scroll_y_active; +- } touches[16]; +- int tracking_ids[16]; ++ } touches[MAX_CONTACTS]; ++ int tracking_ids[MAX_CONTACTS]; + + struct hid_device *hdev; + struct delayed_work work; +@@ -592,7 +594,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd + + __set_bit(EV_ABS, input->evbit); + +- error = input_mt_init_slots(input, 16, mt_flags); ++ error = input_mt_init_slots(input, MAX_CONTACTS, mt_flags); + if (error) + return error; + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0121-HID-magicmouse-use-struct-input_mt_pos-for-X-Y.patch b/target/linux/silicon/patches-5.19/0121-HID-magicmouse-use-struct-input_mt_pos-for-X-Y.patch new file mode 100644 index 000000000..3e5a60348 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0121-HID-magicmouse-use-struct-input_mt_pos-for-X-Y.patch @@ -0,0 +1,48 @@ +From 40b569fd3e7dc56dc7c32a0d86dd8675764a784e Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Thu, 16 Dec 2021 00:12:35 +0100 +Subject: [PATCH 121/171] HID: magicmouse: use struct input_mt_pos for X/Y + +Signed-off-by: Janne Grunau +--- + drivers/hid/hid-magicmouse.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c +index f4192e503b2c..a02bdddb64b2 100644 +--- a/drivers/hid/hid-magicmouse.c ++++ b/drivers/hid/hid-magicmouse.c +@@ -131,9 +131,8 @@ struct magicmouse_sc { + int scroll_accel; + unsigned long scroll_jiffies; + ++ struct input_mt_pos pos[MAX_CONTACTS]; + struct { +- short x; +- short y; + short scroll_x; + short scroll_y; + short scroll_x_hr; +@@ -190,7 +189,7 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) + } else if (last_state != 0) { + state = last_state; + } else if ((id = magicmouse_firm_touch(msc)) >= 0) { +- int x = msc->touches[id].x; ++ int x = msc->pos[id].x; + if (x < middle_button_start) + state = 1; + else if (x > middle_button_stop) +@@ -251,8 +250,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda + + /* Store tracking ID and other fields. */ + msc->tracking_ids[raw_id] = id; +- msc->touches[id].x = x; +- msc->touches[id].y = y; ++ msc->pos[id].x = x; ++ msc->pos[id].y = y; + msc->touches[id].size = size; + + /* If requested, emulate a scroll wheel by detecting small +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0122-HID-magicmouse-use-ops-function-pointers-for-input-f.patch b/target/linux/silicon/patches-5.19/0122-HID-magicmouse-use-ops-function-pointers-for-input-f.patch new file mode 100644 index 000000000..e4c43ef24 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0122-HID-magicmouse-use-ops-function-pointers-for-input-f.patch @@ -0,0 +1,86 @@ +From 808129b77c405db99bde9b78efd2e12204acbdf9 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Thu, 16 Dec 2021 00:15:30 +0100 +Subject: [PATCH 122/171] HID: magicmouse: use ops function pointers for input + functionality + +Will be used for supporting MacBook trackpads connected via SPI. + +Signed-off-by: Janne Grunau +--- + drivers/hid/hid-magicmouse.c | 31 ++++++++++++++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c +index a02bdddb64b2..734e97234890 100644 +--- a/drivers/hid/hid-magicmouse.c ++++ b/drivers/hid/hid-magicmouse.c +@@ -113,6 +113,13 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie + #define TRACKPAD2_RES_Y \ + ((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100)) + ++ ++struct magicmouse_input_ops { ++ int (*raw_event)(struct hid_device *hdev, ++ struct hid_report *report, u8 *data, int size); ++ int (*setup_input)(struct input_dev *input, struct hid_device *hdev); ++}; ++ + /** + * struct magicmouse_sc - Tracks Magic Mouse-specific data. + * @input: Input device through which we report events. +@@ -146,6 +153,7 @@ struct magicmouse_sc { + struct hid_device *hdev; + struct delayed_work work; + struct timer_list battery_timer; ++ struct magicmouse_input_ops input_ops; + }; + + static int magicmouse_firm_touch(struct magicmouse_sc *msc) +@@ -375,6 +383,14 @@ static int magicmouse_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) + { + struct magicmouse_sc *msc = hid_get_drvdata(hdev); ++ ++ return msc->input_ops.raw_event(hdev, report, data, size); ++} ++ ++static int magicmouse_raw_event_usb(struct hid_device *hdev, ++ struct hid_report *report, u8 *data, int size) ++{ ++ struct magicmouse_sc *msc = hid_get_drvdata(hdev); + struct input_dev *input = msc->input; + int x = 0, y = 0, ii, clicks = 0, npoints; + +@@ -520,7 +536,17 @@ static int magicmouse_event(struct hid_device *hdev, struct hid_field *field, + return 0; + } + +-static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) ++ ++static int magicmouse_setup_input(struct input_dev *input, ++ struct hid_device *hdev) ++{ ++ struct magicmouse_sc *msc = hid_get_drvdata(hdev); ++ ++ return msc->input_ops.setup_input(input, hdev); ++} ++ ++static int magicmouse_setup_input_usb(struct input_dev *input, ++ struct hid_device *hdev) + { + int error; + int mt_flags = 0; +@@ -807,6 +833,9 @@ static int magicmouse_probe(struct hid_device *hdev, + return -ENOMEM; + } + ++ msc->input_ops.raw_event = magicmouse_raw_event_usb; ++ msc->input_ops.setup_input = magicmouse_setup_input_usb; ++ + msc->scroll_accel = SCROLL_ACCEL_DEFAULT; + msc->hdev = hdev; + INIT_DEFERRABLE_WORK(&msc->work, magicmouse_enable_mt_work); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0123-HID-magicmouse-add-support-for-Macbook-trackpads.patch b/target/linux/silicon/patches-5.19/0123-HID-magicmouse-add-support-for-Macbook-trackpads.patch new file mode 100644 index 000000000..1a9fe31ee --- /dev/null +++ b/target/linux/silicon/patches-5.19/0123-HID-magicmouse-add-support-for-Macbook-trackpads.patch @@ -0,0 +1,358 @@ +From 89d8ef52b73399098877813502dc8320f7f07a69 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Thu, 16 Dec 2021 01:17:48 +0100 +Subject: [PATCH 123/171] HID: magicmouse: add support for Macbook trackpads + +The trackpads in Macbooks beginning in 2015 are HID devices connected +over SPI. On Intel Macbooks they are currently supported by applespi.c. +This chang adds support for the trackpads on Apple Silicon Macbooks +starting in late 2020. They use a new HID over SPI transport driver. +The touch report format differs from USB/BT Magic Trackpads. It is the +same format as the type 4 format supported by bcm5974.c. + +Signed-off-by: Janne Grunau +--- + drivers/hid/Kconfig | 4 +- + drivers/hid/hid-magicmouse.c | 259 ++++++++++++++++++++++++++++++++++- + 2 files changed, 260 insertions(+), 3 deletions(-) + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 77c3c00c877c..abaf704d5a81 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -676,11 +676,13 @@ config LOGIWHEELS_FF + config HID_MAGICMOUSE + tristate "Apple Magic Mouse/Trackpad multi-touch support" + depends on HID ++ default SPI_HID_APPLE + help + Support for the Apple Magic Mouse/Trackpad multi-touch. + + Say Y here if you want support for the multi-touch features of the +- Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad. ++ Apple Wireless "Magic" Mouse, the Apple Wireless "Magic" Trackpad and ++ fource touch Trackpads in Macbooks starting from 2015. + + config HID_MALTRON + tristate "Maltron L90 keyboard" +diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c +index 734e97234890..65c4b6307ce9 100644 +--- a/drivers/hid/hid-magicmouse.c ++++ b/drivers/hid/hid-magicmouse.c +@@ -113,6 +113,18 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie + #define TRACKPAD2_RES_Y \ + ((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100)) + ++#define J314_TP_DIMENSION_X (float)13000 ++#define J314_TP_MIN_X -5900 ++#define J314_TP_MAX_X 6500 ++#define J314_TP_RES_X \ ++ ((J314_TP_MAX_X - J314_TP_MIN_X) / (J314_TP_DIMENSION_X / 100)) ++#define J314_TP_DIMENSION_Y (float)8100 ++#define J314_TP_MIN_Y -200 ++#define J314_TP_MAX_Y 7400 ++#define J314_TP_RES_Y \ ++ ((J314_TP_MAX_Y - J314_TP_MIN_Y) / (J314_TP_DIMENSION_Y / 100)) ++ ++#define J314_TP_MAX_FINGER_ORIENTATION 16384 + + struct magicmouse_input_ops { + int (*raw_event)(struct hid_device *hdev, +@@ -519,6 +531,157 @@ static int magicmouse_raw_event_usb(struct hid_device *hdev, + return 1; + } + ++/** ++ * struct tp_finger - single trackpad finger structure, le16-aligned ++ * ++ * @unknown1: unknown ++ * @unknown2: unknown ++ * @abs_x: absolute x coordinate ++ * @abs_y: absolute y coordinate ++ * @rel_x: relative x coordinate ++ * @rel_y: relative y coordinate ++ * @tool_major: tool area, major axis ++ * @tool_minor: tool area, minor axis ++ * @orientation: 16384 when point, else 15 bit angle ++ * @touch_major: touch area, major axis ++ * @touch_minor: touch area, minor axis ++ * @unused: zeros ++ * @pressure: pressure on forcetouch touchpad ++ * @multi: one finger: varies, more fingers: constant ++ * @crc16: on last finger: crc over the whole message struct ++ * (i.e. message header + this struct) minus the last ++ * @crc16 field; unknown on all other fingers. ++ */ ++struct tp_finger { ++ __le16 unknown1; ++ __le16 unknown2; ++ __le16 abs_x; ++ __le16 abs_y; ++ __le16 rel_x; ++ __le16 rel_y; ++ __le16 tool_major; ++ __le16 tool_minor; ++ __le16 orientation; ++ __le16 touch_major; ++ __le16 touch_minor; ++ __le16 unused[2]; ++ __le16 pressure; ++ __le16 multi; ++} __attribute__((packed, aligned(2))); ++ ++/** ++ * struct trackpad report ++ * ++ * @report_id: reportid ++ * @buttons: HID Usage Buttons 3 1-bit reports ++ * @num_fingers: the number of fingers being reported in @fingers ++ * @clicked: same as @buttons ++ */ ++struct tp_header { ++ // HID mouse report ++ u8 report_id; ++ u8 buttons; ++ u8 rel_x; ++ u8 rel_y; ++ u8 padding[4]; ++ // HID vendor part, up to 1751 bytes ++ u8 unknown[22]; ++ u8 num_fingers; ++ u8 clicked; ++ u8 unknown3[14]; ++}; ++ ++static inline int le16_to_int(__le16 x) ++{ ++ return (signed short)le16_to_cpu(x); ++} ++ ++static void report_finger_data(struct input_dev *input, int slot, ++ const struct input_mt_pos *pos, ++ const struct tp_finger *f) ++{ ++ input_mt_slot(input, slot); ++ input_mt_report_slot_state(input, MT_TOOL_FINGER, true); ++ ++ input_report_abs(input, ABS_MT_TOUCH_MAJOR, ++ le16_to_int(f->touch_major) << 1); ++ input_report_abs(input, ABS_MT_TOUCH_MINOR, ++ le16_to_int(f->touch_minor) << 1); ++ input_report_abs(input, ABS_MT_WIDTH_MAJOR, ++ le16_to_int(f->tool_major) << 1); ++ input_report_abs(input, ABS_MT_WIDTH_MINOR, ++ le16_to_int(f->tool_minor) << 1); ++ input_report_abs(input, ABS_MT_ORIENTATION, ++ J314_TP_MAX_FINGER_ORIENTATION - le16_to_int(f->orientation)); ++ input_report_abs(input, ABS_MT_PRESSURE, le16_to_int(f->pressure)); ++ input_report_abs(input, ABS_MT_POSITION_X, pos->x); ++ input_report_abs(input, ABS_MT_POSITION_Y, pos->y); ++} ++ ++static int magicmouse_raw_event_spi(struct hid_device *hdev, ++ struct hid_report *report, u8 *data, int size) ++{ ++ struct magicmouse_sc *msc = hid_get_drvdata(hdev); ++ struct input_dev *input = msc->input; ++ struct tp_header *tp_hdr; ++ struct tp_finger *f; ++ int i, n; ++ u32 npoints; ++ const size_t hdr_sz = sizeof(struct tp_header); ++ const size_t touch_sz = sizeof(struct tp_finger); ++ u8 map_contacs[MAX_CONTACTS]; ++ ++ // hid_warn(hdev, "%s\n", __func__); ++ // print_hex_dump_debug("appleft ev: ", DUMP_PREFIX_OFFSET, 16, 1, data, ++ // size, false); ++ ++ if (data[0] != TRACKPAD2_USB_REPORT_ID) ++ return 0; ++ ++ /* Expect 46 bytes of prefix, and N * 30 bytes of touch data. */ ++ if (size < hdr_sz || ((size - hdr_sz) % touch_sz) != 0) ++ return 0; ++ ++ tp_hdr = (struct tp_header *)data; ++ ++ npoints = (size - hdr_sz) / touch_sz; ++ if (npoints < tp_hdr->num_fingers || npoints > MAX_CONTACTS) { ++ hid_warn(hdev, ++ "unexpected number of touches (%u) for " ++ "report\n", ++ npoints); ++ return 0; ++ } ++ ++ n = 0; ++ for (i = 0; i < tp_hdr->num_fingers; i++) { ++ f = (struct tp_finger *)(data + hdr_sz + i * touch_sz); ++ if (le16_to_int(f->touch_major) == 0) ++ continue; ++ ++ hid_dbg(hdev, "ev x:%04hx y:%04hx\n", le16_to_int(f->abs_x), ++ le16_to_int(f->abs_y)); ++ msc->pos[n].x = le16_to_int(f->abs_x); ++ msc->pos[n].y = -le16_to_int(f->abs_y); ++ map_contacs[n] = i; ++ n++; ++ } ++ ++ input_mt_assign_slots(input, msc->tracking_ids, msc->pos, n, 0); ++ ++ for (i = 0; i < n; i++) { ++ int idx = map_contacs[i]; ++ f = (struct tp_finger *)(data + hdr_sz + idx * touch_sz); ++ report_finger_data(input, msc->tracking_ids[i], &msc->pos[i], f); ++ } ++ ++ input_mt_sync_frame(input); ++ input_report_key(input, BTN_MOUSE, data[1] & 1); ++ ++ input_sync(input); ++ return 1; ++} ++ + static int magicmouse_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) + { +@@ -698,6 +861,79 @@ static int magicmouse_setup_input_usb(struct input_dev *input, + return 0; + } + ++static int magicmouse_setup_input_spi(struct input_dev *input, ++ struct hid_device *hdev) ++{ ++ int error; ++ int mt_flags = 0; ++ ++ __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); ++ __clear_bit(BTN_0, input->keybit); ++ __clear_bit(BTN_RIGHT, input->keybit); ++ __clear_bit(BTN_MIDDLE, input->keybit); ++ __clear_bit(EV_REL, input->evbit); ++ __clear_bit(REL_X, input->relbit); ++ __clear_bit(REL_Y, input->relbit); ++ ++ mt_flags = INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK; ++ ++ /* finger touch area */ ++ input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 5000, 0, 0); ++ input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 5000, 0, 0); ++ ++ /* finger approach area */ ++ input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 5000, 0, 0); ++ input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 5000, 0, 0); ++ ++ /* Note: Touch Y position from the device is inverted relative ++ * to how pointer motion is reported (and relative to how USB ++ * HID recommends the coordinates work). This driver keeps ++ * the origin at the same position, and just uses the additive ++ * inverse of the reported Y. ++ */ ++ ++ input_set_abs_params(input, ABS_MT_PRESSURE, 0, 6000, 0, 0); ++ ++ /* ++ * This makes libinput recognize this as a PressurePad and ++ * stop trying to use pressure for touch size. Pressure unit ++ * seems to be ~grams on these touchpads. ++ */ ++ input_abs_set_res(input, ABS_MT_PRESSURE, 1); ++ ++ /* finger orientation */ ++ input_set_abs_params(input, ABS_MT_ORIENTATION, -J314_TP_MAX_FINGER_ORIENTATION, ++ J314_TP_MAX_FINGER_ORIENTATION, 0, 0); ++ ++ /* finger position */ ++ input_set_abs_params(input, ABS_MT_POSITION_X, J314_TP_MIN_X, J314_TP_MAX_X, ++ 0, 0); ++ /* Y axis is inverted */ ++ input_set_abs_params(input, ABS_MT_POSITION_Y, -J314_TP_MAX_Y, -J314_TP_MIN_Y, ++ 0, 0); ++ ++ /* X/Y resolution */ ++ input_abs_set_res(input, ABS_MT_POSITION_X, J314_TP_RES_X); ++ input_abs_set_res(input, ABS_MT_POSITION_Y, J314_TP_RES_Y); ++ ++ input_set_events_per_packet(input, 60); ++ ++ /* touchpad button */ ++ input_set_capability(input, EV_KEY, BTN_MOUSE); ++ ++ /* ++ * hid-input may mark device as using autorepeat, but the trackpad does ++ * not actually want it. ++ */ ++ __clear_bit(EV_REP, input->evbit); ++ ++ error = input_mt_init_slots(input, MAX_CONTACTS, mt_flags); ++ if (error) ++ return error; ++ ++ return 0; ++} ++ + static int magicmouse_input_mapping(struct hid_device *hdev, + struct hid_input *hi, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, int *max) +@@ -753,6 +989,9 @@ static int magicmouse_enable_multitouch(struct hid_device *hdev) + feature_size = sizeof(feature_mt_trackpad2_usb); + feature = feature_mt_trackpad2_usb; + } ++ } else if (hdev->vendor == SPI_VENDOR_ID_APPLE) { ++ feature_size = sizeof(feature_mt_trackpad2_usb); ++ feature = feature_mt_trackpad2_usb; + } else if (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) { + feature_size = sizeof(feature_mt_mouse2); + feature = feature_mt_mouse2; +@@ -827,14 +1066,26 @@ static int magicmouse_probe(struct hid_device *hdev, + struct hid_report *report; + int ret; + ++ if (id->bus == BUS_SPI && id->vendor == SPI_VENDOR_ID_APPLE && ++ hdev->type != HID_TYPE_SPI_MOUSE) ++ return -ENODEV; ++ + msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL); + if (msc == NULL) { + hid_err(hdev, "can't alloc magicmouse descriptor\n"); + return -ENOMEM; + } + +- msc->input_ops.raw_event = magicmouse_raw_event_usb; +- msc->input_ops.setup_input = magicmouse_setup_input_usb; ++ // internal trackpad use a data format use input ops to avoid ++ // conflicts with the report ID. ++ if (id->vendor == SPI_VENDOR_ID_APPLE) { ++ msc->input_ops.raw_event = magicmouse_raw_event_spi; ++ msc->input_ops.setup_input = magicmouse_setup_input_spi; ++ ++ } else { ++ msc->input_ops.raw_event = magicmouse_raw_event_usb; ++ msc->input_ops.setup_input = magicmouse_setup_input_usb; ++ } + + msc->scroll_accel = SCROLL_ACCEL_DEFAULT; + msc->hdev = hdev; +@@ -884,6 +1135,8 @@ static int magicmouse_probe(struct hid_device *hdev, + else /* USB_VENDOR_ID_APPLE */ + report = hid_register_report(hdev, HID_INPUT_REPORT, + TRACKPAD2_USB_REPORT_ID, 0); ++ } else if (id->vendor == SPI_VENDOR_ID_APPLE) { ++ report = hid_register_report(hdev, HID_INPUT_REPORT, 2, 0); + } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ + report = hid_register_report(hdev, HID_INPUT_REPORT, + TRACKPAD_REPORT_ID, 0); +@@ -978,6 +1231,8 @@ static const struct hid_device_id magic_mice[] = { + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, ++ { HID_SPI_DEVICE(SPI_VENDOR_ID_APPLE, HID_ANY_ID), ++ .driver_data = 0 }, + { } + }; + MODULE_DEVICE_TABLE(hid, magic_mice); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0124-WIP-HID-transport-spi-add-Apple-SPI-transport.patch b/target/linux/silicon/patches-5.19/0124-WIP-HID-transport-spi-add-Apple-SPI-transport.patch new file mode 100644 index 000000000..8b27364b7 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0124-WIP-HID-transport-spi-add-Apple-SPI-transport.patch @@ -0,0 +1,1323 @@ +From 80d39405629267931171cbca14121b266e8d9152 Mon Sep 17 00:00:00 2001 +From: Janne Grunau +Date: Fri, 10 Dec 2021 19:38:43 +0100 +Subject: [PATCH 124/171] WIP: HID: transport: spi: add Apple SPI transport + +Keyboard and trackpad of Apple Sillicon SoCs (M1, M1 Pro/Max) laptops +are are HID devices connected via SPI. + +This is the same protocol as implemented by applespi.c. It was not +noticed that protocol is a transport for HID. Adding support for ACPI +based Intel MacBooks will be done in a separate commit. + +How HID is mapped in this protocol is not yet fully understood. + +Microsoft has a specification for HID over SPI [1] incompatible with the +transport protocol used by Apple. + +[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/hid-over-spi + +Signed-off-by: Janne Grunau +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/spi-hid/Kconfig | 26 + + drivers/hid/spi-hid/Makefile | 10 + + drivers/hid/spi-hid/spi-hid-apple-core.c | 1029 ++++++++++++++++++++++ + drivers/hid/spi-hid/spi-hid-apple-of.c | 138 +++ + drivers/hid/spi-hid/spi-hid-apple.h | 31 + + 7 files changed, 1238 insertions(+) + create mode 100644 drivers/hid/spi-hid/Kconfig + create mode 100644 drivers/hid/spi-hid/Makefile + create mode 100644 drivers/hid/spi-hid/spi-hid-apple-core.c + create mode 100644 drivers/hid/spi-hid/spi-hid-apple-of.c + create mode 100644 drivers/hid/spi-hid/spi-hid-apple.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index abaf704d5a81..1dd6697e7c59 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1322,4 +1322,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" + + source "drivers/hid/surface-hid/Kconfig" + ++source "drivers/hid/spi-hid/Kconfig" ++ + endmenu +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index cac2cbe26d11..a720e68fe1d7 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -156,3 +156,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++ ++obj-$(CONFIG_SPI_HID_APPLE_CORE) += spi-hid/ +diff --git a/drivers/hid/spi-hid/Kconfig b/drivers/hid/spi-hid/Kconfig +new file mode 100644 +index 000000000000..8e37f0fec28a +--- /dev/null ++++ b/drivers/hid/spi-hid/Kconfig +@@ -0,0 +1,26 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++menu "SPI HID support" ++ depends on SPI ++ ++config SPI_HID_APPLE_OF ++ tristate "HID over SPI transport layer for Apple Silicon SoCs" ++ default ARCH_APPLE ++ depends on SPI && INPUT && OF ++ help ++ Say Y here if you use Apple Silicon based laptop. The keyboard and ++ touchpad are HID based devices connected via SPI. ++ ++ If unsure, say N. ++ ++ This support is also available as a module. If so, the module ++ will be called spi-hid-apple-of. It will also build/depend on the ++ module spi-hid-apple. ++ ++endmenu ++ ++config SPI_HID_APPLE_CORE ++ tristate ++ default y if SPI_HID_APPLE_OF=y ++ default m if SPI_HID_APPLE_OF=m ++ select HID ++ select CRC16 +diff --git a/drivers/hid/spi-hid/Makefile b/drivers/hid/spi-hid/Makefile +new file mode 100644 +index 000000000000..f276ee12cb94 +--- /dev/null ++++ b/drivers/hid/spi-hid/Makefile +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# Makefile for SPI HID tarnsport drivers ++# ++ ++obj-$(CONFIG_SPI_HID_APPLE_CORE) += spi-hid-apple.o ++ ++spi-hid-apple-objs = spi-hid-apple-core.o ++ ++obj-$(CONFIG_SPI_HID_APPLE_OF) += spi-hid-apple-of.o +diff --git a/drivers/hid/spi-hid/spi-hid-apple-core.c b/drivers/hid/spi-hid/spi-hid-apple-core.c +new file mode 100644 +index 000000000000..56941430befa +--- /dev/null ++++ b/drivers/hid/spi-hid/spi-hid-apple-core.c +@@ -0,0 +1,1029 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0 ++ * ++ * Apple SPI HID transport driver ++ * ++ * Copyright (C) The Asahi Linux Contributors ++ * ++ * Based on: drivers/input/applespi.c ++ * ++ * MacBook (Pro) SPI keyboard and touchpad driver ++ * ++ * Copyright (c) 2015-2018 Federico Lorenzi ++ * Copyright (c) 2017-2018 Ronald Tschalär ++ * ++ */ ++ ++//#define DEBUG 2 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "spi-hid-apple.h" ++ ++#define SPIHID_DEF_WAIT msecs_to_jiffies(100) ++ ++#define SPIHID_MAX_INPUT_REPORT_SIZE 0x800 ++ ++/* support only keyboard, trackpad and management dev for now */ ++#define SPIHID_MAX_DEVICES 3 ++ ++#define SPIHID_DEVICE_ID_MNGT 0x0 ++#define SPIHID_DEVICE_ID_KBD 0x1 ++#define SPIHID_DEVICE_ID_TP 0x2 ++#define SPIHID_DEVICE_ID_INFO 0xd0 ++ ++#define SPIHID_READ_PACKET 0x20 ++#define SPIHID_WRITE_PACKET 0x40 ++ ++#define SPIHID_DESC_MAX 512 ++ ++#define SPIHID_SET_LEDS 0x0151 /* caps lock */ ++ ++#define SPI_RW_CHG_DELAY_US 200 /* 'Inter Stage Us'? */ ++ ++static const u8 spi_hid_apple_booted[4] = { 0xa0, 0x80, 0x00, 0x00 }; ++static const u8 spi_hid_apple_status_ok[4] = { 0xac, 0x27, 0x68, 0xd5 }; ++ ++struct spihid_interface { ++ struct hid_device *hid; ++ u8 *hid_desc; ++ u32 hid_desc_len; ++ u32 id; ++ unsigned country; ++ u32 max_control_report_len; ++ u32 max_input_report_len; ++ u32 max_output_report_len; ++ u8 name[32]; ++ bool ready; ++}; ++ ++struct spihid_input_report { ++ u8 *buf; ++ u32 length; ++ u32 offset; ++ u8 device; ++ u8 flags; ++}; ++ ++struct spihid_apple { ++ struct spi_device *spidev; ++ ++ struct spihid_apple_ops *ops; ++ ++ struct spihid_interface mngt; ++ struct spihid_interface kbd; ++ struct spihid_interface tp; ++ ++ wait_queue_head_t wait; ++ struct mutex tx_lock; //< protects against concurrent SPI writes ++ ++ struct spi_message rx_msg; ++ struct spi_message tx_msg; ++ struct spi_transfer rx_transfer; ++ struct spi_transfer tx_transfer; ++ struct spi_transfer status_transfer; ++ ++ u8 *rx_buf; ++ u8 *tx_buf; ++ u8 *status_buf; ++ ++ u8 vendor[32]; ++ u8 product[64]; ++ u8 serial[32]; ++ ++ u32 num_devices; ++ ++ u32 vendor_id; ++ u32 product_id; ++ u32 version_number; ++ ++ u8 msg_id; ++ ++ /* fragmented HID report */ ++ struct spihid_input_report report; ++ ++ /* state tracking flags */ ++ bool status_booted; ++}; ++ ++/** ++ * struct spihid_msg_hdr - common header of protocol messages. ++ * ++ * Each message begins with fixed header, followed by a message-type specific ++ * payload, and ends with a 16-bit crc. Because of the varying lengths of the ++ * payload, the crc is defined at the end of each payload struct, rather than ++ * in this struct. ++ * ++ * @unknown0: request type? output, input (0x10), feature, protocol ++ * @unknown1: maybe report id? ++ * @unknown2: mostly zero, in info request maybe device num ++ * @msgid: incremented on each message, rolls over after 255; there is a ++ * separate counter for each message type. ++ * @rsplen: response length (the exact nature of this field is quite ++ * speculative). On a request/write this is often the same as ++ * @length, though in some cases it has been seen to be much larger ++ * (e.g. 0x400); on a response/read this the same as on the ++ * request; for reads that are not responses it is 0. ++ * @length: length of the remainder of the data in the whole message ++ * structure (after re-assembly in case of being split over ++ * multiple spi-packets), minus the trailing crc. The total size ++ * of a message is therefore @length + 10. ++ */ ++ ++struct spihid_msg_hdr { ++ u8 unknown0; ++ u8 unknown1; ++ u8 unknown2; ++ u8 id; ++ __le16 rsplen; ++ __le16 length; ++}; ++ ++/** ++ * struct spihid_transfer_packet - a complete spi packet; always 256 bytes. This carries ++ * the (parts of the) message in the data. But note that this does not ++ * necessarily contain a complete message, as in some cases (e.g. many ++ * fingers pressed) the message is split over multiple packets (see the ++ * @offset, @remain, and @length fields). In general the data parts in ++ * spihid_transfer_packet's are concatenated until @remaining is 0, and the ++ * result is an message. ++ * ++ * @flags: 0x40 = write (to device), 0x20 = read (from device); note that ++ * the response to a write still has 0x40. ++ * @device: 1 = keyboard, 2 = touchpad ++ * @offset: specifies the offset of this packet's data in the complete ++ * message; i.e. > 0 indicates this is a continuation packet (in ++ * the second packet for a message split over multiple packets ++ * this would then be the same as the @length in the first packet) ++ * @remain: number of message bytes remaining in subsequents packets (in ++ * the first packet of a message split over two packets this would ++ * then be the same as the @length in the second packet) ++ * @length: length of the valid data in the @data in this packet ++ * @data: all or part of a message ++ * @crc16: crc over this whole structure minus this @crc16 field. This ++ * covers just this packet, even on multi-packet messages (in ++ * contrast to the crc in the message). ++ */ ++struct spihid_transfer_packet { ++ u8 flags; ++ u8 device; ++ __le16 offset; ++ __le16 remain; ++ __le16 length; ++ u8 data[246]; ++ __le16 crc16; ++}; ++ ++/* ++ * how HID is mapped onto the protocol is not fully clear. This are the known ++ * reports/request: ++ * ++ * pkt.flags pkt.dev? msg.u0 msg.u1 msg.u2 ++ * info 0x40 0xd0 0x20 0x01 0xd0 ++ * ++ * info mngt: 0x40 0xd0 0x20 0x10 0x00 ++ * info kbd: 0x40 0xd0 0x20 0x10 0x01 ++ * info tp: 0x40 0xd0 0x20 0x10 0x02 ++ * ++ * desc kbd: 0x40 0xd0 0x20 0x10 0x01 ++ * desc trackpad: 0x40 0xd0 0x20 0x10 0x02 ++ * ++ * mt mode: 0x40 0x02 0x52 0x02 0x00 set protocol? ++ * capslock led 0x40 0x01 0x51 0x01 0x00 output report ++ * ++ * report kbd: 0x20 0x01 0x10 0x01 0x00 input report ++ * report tp: 0x20 0x02 0x10 0x02 0x00 input report ++ * ++ */ ++ ++ ++static int spihid_apple_request(struct spihid_apple *spihid, u8 target, u8 unk0, ++ u8 unk1, u8 unk2, u16 resp_len, u8 *buf, ++ size_t len) ++{ ++ struct spihid_transfer_packet *pkt; ++ struct spihid_msg_hdr *hdr; ++ u16 crc; ++ int err; ++ ++ /* know reports are small enoug to fit in a single packet */ ++ if (len > sizeof(pkt->data) - sizeof(*hdr) - sizeof(__le16)) ++ return -EINVAL; ++ ++ err = mutex_lock_interruptible(&spihid->tx_lock); ++ if (err < 0) ++ return err; ++ ++ pkt = (struct spihid_transfer_packet *)spihid->tx_buf; ++ ++ memset(pkt, 0, sizeof(*pkt)); ++ pkt->flags = SPIHID_WRITE_PACKET; ++ pkt->device = target; ++ pkt->length = sizeof(*hdr) + len + sizeof(__le16); ++ ++ hdr = (struct spihid_msg_hdr *)&pkt->data[0]; ++ hdr->unknown0 = unk0; ++ hdr->unknown1 = unk1; ++ hdr->unknown2 = unk2; ++ hdr->id = spihid->msg_id++; ++ hdr->rsplen = cpu_to_le16(resp_len); ++ hdr->length = cpu_to_le16(len); ++ ++ if (len) ++ memcpy(pkt->data + sizeof(*hdr), buf, len); ++ crc = crc16(0, &pkt->data[0], sizeof(*hdr) + len); ++ put_unaligned_le16(crc, pkt->data + sizeof(*hdr) + len); ++ ++ pkt->crc16 = crc16(0, spihid->tx_buf, ++ offsetof(struct spihid_transfer_packet, crc16)); ++ ++ err = spi_sync(spihid->spidev, &spihid->tx_msg); ++ mutex_unlock(&spihid->tx_lock); ++ if (err < 0) ++ return err; ++ ++ return (int)len; ++} ++ ++struct spihid_apple *spihid_get_data(struct spihid_interface *idev) ++{ ++ switch (idev->id) { ++ case SPIHID_DEVICE_ID_KBD: ++ return container_of(idev, struct spihid_apple, kbd); ++ case SPIHID_DEVICE_ID_TP: ++ return container_of(idev, struct spihid_apple, tp); ++ default: ++ return NULL; ++ } ++} ++ ++static int apple_ll_start(struct hid_device *hdev) ++{ ++ /* no-op SPI transport is already setup */ ++ return 0; ++}; ++ ++static void apple_ll_stop(struct hid_device *hdev) ++{ ++ /* no-op, devices will be desstroyed on driver destruction */ ++} ++ ++static int apple_ll_open(struct hid_device *hdev) ++{ ++ struct spihid_apple *spihid; ++ struct spihid_interface *idev = hdev->driver_data; ++ ++ if (idev->hid_desc_len == 0) { ++ spihid = spihid_get_data(idev); ++ dev_warn(&spihid->spidev->dev, ++ "HID descriptor missing for dev %u", idev->id); ++ } else ++ idev->ready = true; ++ ++ return 0; ++} ++ ++static void apple_ll_close(struct hid_device *hdev) ++{ ++ struct spihid_interface *idev = hdev->driver_data; ++ idev->ready = false; ++} ++ ++static int apple_ll_parse(struct hid_device *hdev) ++{ ++ struct spihid_interface *idev = hdev->driver_data; ++ ++ return hid_parse_report(hdev, idev->hid_desc, idev->hid_desc_len); ++} ++ ++static int apple_ll_raw_request(struct hid_device *hdev, ++ unsigned char reportnum, __u8 *buf, size_t len, ++ unsigned char rtype, int reqtype) ++{ ++ struct spihid_interface *idev = hdev->driver_data; ++ struct spihid_apple *spihid = spihid_get_data(idev); ++ ++ dev_dbg(&spihid->spidev->dev, ++ "apple_ll_raw_request: device:%u reportnum:%hhu rtype:%hhu", ++ idev->id, reportnum, rtype); ++ ++ switch (reqtype) { ++ case HID_REQ_GET_REPORT: ++ return -EINVAL; // spihid_get_raw_report(); ++ case HID_REQ_SET_REPORT: ++ if (buf[0] != reportnum) ++ return -EINVAL; ++ if (reportnum != idev->id) { ++ dev_warn(&spihid->spidev->dev, ++ "device:%u reportnum:" ++ "%hhu mismatch", ++ idev->id, reportnum); ++ return -EINVAL; ++ } ++ return spihid_apple_request(spihid, idev->id, 0x52, reportnum, 0x00, 2, buf, len); ++ default: ++ return -EIO; ++ } ++} ++ ++static int apple_ll_output_report(struct hid_device *hdev, __u8 *buf, ++ size_t len) ++{ ++ struct spihid_interface *idev = hdev->driver_data; ++ struct spihid_apple *spihid = spihid_get_data(idev); ++ if (!spihid) ++ return -1; ++ ++ dev_dbg(&spihid->spidev->dev, ++ "apple_ll_output_report: device:%u len:%zu:", ++ idev->id, len); ++ // second idev->id should maybe be buf[0]? ++ return spihid_apple_request(spihid, idev->id, 0x51, idev->id, 0x00, 0, buf, len); ++} ++ ++static struct hid_ll_driver apple_hid_ll = { ++ .start = &apple_ll_start, ++ .stop = &apple_ll_stop, ++ .open = &apple_ll_open, ++ .close = &apple_ll_close, ++ .parse = &apple_ll_parse, ++ .raw_request = &apple_ll_raw_request, ++ .output_report = &apple_ll_output_report, ++}; ++ ++static struct spihid_interface *spihid_get_iface(struct spihid_apple *spihid, ++ u32 iface) ++{ ++ switch (iface) { ++ case SPIHID_DEVICE_ID_MNGT: ++ return &spihid->mngt; ++ case SPIHID_DEVICE_ID_KBD: ++ return &spihid->kbd; ++ case SPIHID_DEVICE_ID_TP: ++ return &spihid->tp; ++ default: ++ return NULL; ++ } ++} ++ ++static int spihid_verify_msg(struct spihid_apple *spihid, u8 *buf, size_t len) ++{ ++ u16 msg_crc, crc; ++ struct device *dev = &spihid->spidev->dev; ++ ++ crc = crc16(0, buf, len - sizeof(__le16)); ++ msg_crc = get_unaligned_le16(buf + len - sizeof(__le16)); ++ if (crc != msg_crc) { ++ dev_warn_ratelimited(dev, "Read message crc mismatch\n"); ++ return 0; ++ } ++ return 1; ++} ++ ++static bool spihid_status_report(struct spihid_apple *spihid, u8 *pl, ++ size_t len) ++{ ++ struct device *dev = &spihid->spidev->dev; ++ dev_dbg(dev, "%s: len: %zu", __func__, len); ++ if (len == 5 && pl[0] == 0xe0) ++ return true; ++ ++ return false; ++} ++ ++static bool spihid_process_input_report(struct spihid_apple *spihid, u32 device, ++ struct spihid_msg_hdr *hdr, u8 *payload, ++ size_t len) ++{ ++ //dev_dbg(&spihid>spidev->dev, "input report: req:%hx iface:%u ", hdr->unknown0, device); ++ if (hdr->unknown0 != 0x10) ++ return false; ++ ++ /* HID device as well but Vendor usage only, handle it internally for now */ ++ if (device == 0) { ++ if (hdr->unknown1 == 0xe0) { ++ return spihid_status_report(spihid, payload, len); ++ } ++ } else if (device < SPIHID_MAX_DEVICES) { ++ struct spihid_interface *iface = ++ spihid_get_iface(spihid, device); ++ if (iface && iface->hid && iface->ready) { ++ hid_input_report(iface->hid, HID_INPUT_REPORT, payload, ++ len, 1); ++ return true; ++ } ++ } else ++ dev_dbg(&spihid->spidev->dev, ++ "unexpected iface:%u for input report", device); ++ ++ return false; ++} ++ ++struct spihid_device_info { ++ __le16 u0[2]; ++ __le16 num_devices; ++ __le16 vendor_id; ++ __le16 product_id; ++ __le16 version_number; ++ __le16 vendor_str[2]; //< offset and string length ++ __le16 product_str[2]; //< offset and string length ++ __le16 serial_str[2]; //< offset and string length ++}; ++ ++static bool spihid_process_device_info(struct spihid_apple *spihid, u32 iface, ++ u8 *payload, size_t len) ++{ ++ struct device *dev = &spihid->spidev->dev; ++ ++ if (iface != SPIHID_DEVICE_ID_INFO) ++ return false; ++ ++ if (spihid->vendor_id == 0 && ++ len >= sizeof(struct spihid_device_info)) { ++ struct spihid_device_info *info = ++ (struct spihid_device_info *)payload; ++ u16 voff, vlen, poff, plen, soff, slen; ++ u32 num_devices; ++ ++ num_devices = __le16_to_cpu(info->num_devices); ++ ++ if (num_devices < SPIHID_MAX_DEVICES) { ++ dev_err(dev, ++ "Device info reports %u devices, expecting at least 3", ++ num_devices); ++ return false; ++ } ++ spihid->num_devices = num_devices; ++ ++ if (spihid->num_devices > SPIHID_MAX_DEVICES) { ++ dev_info( ++ dev, ++ "limiting the number of devices to mngt, kbd and mouse"); ++ spihid->num_devices = SPIHID_MAX_DEVICES; ++ } ++ ++ spihid->vendor_id = __le16_to_cpu(info->vendor_id); ++ spihid->product_id = __le16_to_cpu(info->product_id); ++ spihid->version_number = __le16_to_cpu(info->version_number); ++ ++ voff = __le16_to_cpu(info->vendor_str[0]); ++ vlen = __le16_to_cpu(info->vendor_str[1]); ++ ++ if (voff < len && vlen <= len - voff && ++ vlen < sizeof(spihid->vendor)) { ++ memcpy(spihid->vendor, payload + voff, vlen); ++ spihid->vendor[vlen] = '\0'; ++ } ++ ++ poff = __le16_to_cpu(info->product_str[0]); ++ plen = __le16_to_cpu(info->product_str[1]); ++ ++ if (poff < len && plen <= len - poff && ++ plen < sizeof(spihid->product)) { ++ memcpy(spihid->product, payload + poff, plen); ++ spihid->product[plen] = '\0'; ++ } ++ ++ soff = __le16_to_cpu(info->serial_str[0]); ++ slen = __le16_to_cpu(info->serial_str[1]); ++ ++ if (soff < len && slen <= len - soff && ++ slen < sizeof(spihid->serial)) { ++ memcpy(spihid->vendor, payload + soff, slen); ++ spihid->serial[slen] = '\0'; ++ } ++ ++ wake_up_interruptible(&spihid->wait); ++ } ++ return true; ++} ++ ++struct spihid_iface_info { ++ u8 u_0; ++ u8 interface_num; ++ u8 u_2; ++ u8 u_3; ++ u8 u_4; ++ u8 country_code; ++ __le16 max_input_report_len; ++ __le16 max_output_report_len; ++ __le16 max_control_report_len; ++ __le16 name_offset; ++ __le16 name_length; ++}; ++ ++static bool spihid_process_iface_info(struct spihid_apple *spihid, u32 num, ++ u8 *payload, size_t len) ++{ ++ struct spihid_iface_info *info; ++ struct spihid_interface *iface = spihid_get_iface(spihid, num); ++ u32 name_off, name_len; ++ ++ if (!iface) ++ return false; ++ ++ if (!iface->max_input_report_len) { ++ if (len < sizeof(*info)) ++ return false; ++ ++ info = (struct spihid_iface_info *)payload; ++ ++ iface->max_input_report_len = ++ le16_to_cpu(info->max_input_report_len); ++ iface->max_output_report_len = ++ le16_to_cpu(info->max_output_report_len); ++ iface->max_control_report_len = ++ le16_to_cpu(info->max_control_report_len); ++ iface->country = info->country_code; ++ ++ name_off = le16_to_cpu(info->name_offset); ++ name_len = le16_to_cpu(info->name_length); ++ ++ if (name_off < len && name_len <= len - name_off && ++ name_len < sizeof(iface->name)) { ++ memcpy(iface->name, payload + name_off, name_len); ++ iface->name[name_len] = '\0'; ++ } ++ ++ dev_dbg(&spihid->spidev->dev, "Info for %s, country code: 0x%x", ++ iface->name, iface->country); ++ ++ wake_up_interruptible(&spihid->wait); ++ } ++ ++ return true; ++} ++ ++static int spihid_register_hid_device(struct spihid_apple *spihid, ++ struct spihid_interface *idev, u8 device); ++ ++static bool spihid_process_iface_hid_report_desc(struct spihid_apple *spihid, ++ u32 num, u8 *payload, ++ size_t len) ++{ ++ struct spihid_interface *iface = spihid_get_iface(spihid, num); ++ ++ if (!iface) ++ return false; ++ ++ if (iface->hid_desc_len == 0) { ++ if (len > SPIHID_DESC_MAX) ++ return false; ++ memcpy(iface->hid_desc, payload, len); ++ iface->hid_desc_len = len; ++ ++ /* do not register the mngt iface as HID device */ ++ if (num > 0) ++ spihid_register_hid_device(spihid, iface, num); ++ ++ wake_up_interruptible(&spihid->wait); ++ } ++ return true; ++} ++ ++static bool spihid_process_response(struct spihid_apple *spihid, ++ struct spihid_msg_hdr *hdr, u8 *payload, ++ size_t len) ++{ ++ if (hdr->unknown0 == 0x20) { ++ switch (hdr->unknown1) { ++ case 0x01: ++ return spihid_process_device_info(spihid, hdr->unknown2, ++ payload, len); ++ case 0x02: ++ return spihid_process_iface_info(spihid, hdr->unknown2, ++ payload, len); ++ case 0x10: ++ return spihid_process_iface_hid_report_desc( ++ spihid, hdr->unknown2, payload, len); ++ default: ++ break; ++ } ++ } ++ ++ return false; ++} ++ ++static void spihid_process_message(struct spihid_apple *spihid, u8 *data, ++ size_t length, u8 device, u8 flags) ++{ ++ struct device *dev = &spihid->spidev->dev; ++ struct spihid_msg_hdr *hdr; ++ bool handled = false; ++ u8 *payload; ++ ++ if (!spihid_verify_msg(spihid, data, length)) ++ return; ++ ++ hdr = (struct spihid_msg_hdr *)data; ++ ++ if (hdr->length == 0) ++ return; ++ ++ payload = data + sizeof(struct spihid_msg_hdr); ++ ++ switch (flags) { ++ case SPIHID_READ_PACKET: ++ handled = spihid_process_input_report(spihid, device, hdr, ++ payload, hdr->length); ++ break; ++ case SPIHID_WRITE_PACKET: ++ handled = spihid_process_response(spihid, hdr, payload, ++ hdr->length); ++ break; ++ default: ++ break; ++ } ++ ++#if defined(DEBUG) && DEBUG > 1 ++ { ++ dev_dbg(dev, ++ "R msg: req:%02hhx rep:%02hhx dev:%02hhx id:%hu len:%hu\n", ++ hdr->unknown0, hdr->unknown1, hdr->unknown2, hdr->id, ++ hdr->length); ++ print_hex_dump_debug("spihid msg: ", DUMP_PREFIX_OFFSET, 16, 1, ++ payload, hdr->length, true); ++ } ++#else ++ if (!handled) { ++ dev_dbg(dev, ++ "R unhandled msg: req:%02hhx rep:%02hhx dev:%02hhx id:%hu len:%hu\n", ++ hdr->unknown0, hdr->unknown1, hdr->unknown2, hdr->id, ++ hdr->length); ++ print_hex_dump_debug("spihid msg: ", DUMP_PREFIX_OFFSET, 16, 1, ++ payload, hdr->length, true); ++ } ++#endif ++} ++ ++static void spihid_assemble_meesage(struct spihid_apple *spihid, ++ struct spihid_transfer_packet *pkt) ++{ ++ size_t length, offset, remain; ++ struct device *dev = &spihid->spidev->dev; ++ struct spihid_input_report *rep = &spihid->report; ++ ++ length = le16_to_cpu(pkt->length); ++ remain = le16_to_cpu(pkt->remain); ++ offset = le16_to_cpu(pkt->offset); ++ ++ if (offset + length + remain > U16_MAX) { ++ return; ++ } ++ ++ if (pkt->device != rep->device || pkt->flags != rep->flags || ++ pkt->offset != rep->offset) { ++ rep->device = 0; ++ rep->flags = 0; ++ rep->offset = 0; ++ rep->length = 0; ++ } ++ ++ if (pkt->offset == 0) { ++ if (rep->offset != 0) { ++ dev_warn(dev, "incomplete report off:%u len:%u", ++ rep->offset, rep->length); ++ } ++ memcpy(rep->buf, pkt->data, length); ++ rep->offset = length; ++ rep->length = length + pkt->remain; ++ rep->device = pkt->device; ++ rep->flags = pkt->flags; ++ } else if (pkt->offset == rep->offset) { ++ if (pkt->offset + length + pkt->remain != rep->length) { ++ dev_warn(dev, "incomplete report off:%u len:%u", ++ rep->offset, rep->length); ++ return; ++ } ++ memcpy(rep->buf + pkt->offset, pkt->data, pkt->length); ++ rep->offset += pkt->length; ++ ++ if (rep->offset == rep->length) { ++ spihid_process_message(spihid, rep->buf, rep->length, ++ rep->device, rep->flags); ++ rep->device = 0; ++ rep->flags = 0; ++ rep->offset = 0; ++ rep->length = 0; ++ } ++ } ++} ++ ++static void spihid_process_read(struct spihid_apple *spihid) ++{ ++ u16 crc; ++ size_t length; ++ struct device *dev = &spihid->spidev->dev; ++ struct spihid_transfer_packet *pkt; ++ ++ pkt = (struct spihid_transfer_packet *)spihid->rx_buf; ++ ++ /* check transfer packet crc */ ++ crc = crc16(0, spihid->rx_buf, ++ offsetof(struct spihid_transfer_packet, crc16)); ++ if (crc != pkt->crc16) { ++ dev_warn_ratelimited(dev, "Read package crc mismatch\n"); ++ return; ++ } ++ ++ length = le16_to_cpu(pkt->length); ++ ++ if (length < sizeof(struct spihid_msg_hdr) + 2) { ++ if (length == sizeof(spi_hid_apple_booted) && ++ !memcmp(pkt->data, spi_hid_apple_booted, length)) { ++ if (!spihid->status_booted) { ++ spihid->status_booted = true; ++ wake_up_interruptible(&spihid->wait); ++ } ++ } else { ++ dev_info(dev, "R short packet: len:%zu\n", length); ++ print_hex_dump_debug("spihid pkt:", DUMP_PREFIX_OFFSET, 16, 1, ++ pkt->data, length, false); ++ } ++ return; ++ } ++ ++#if defined(DEBUG) && DEBUG > 1 ++ dev_dbg(dev, ++ "R pkt: flags:%02hhx dev:%02hhx off:%hu remain:%hu, len:%zu\n", ++ pkt->flags, pkt->device, pkt->offset, pkt->remain, length); ++#if defined(DEBUG) && DEBUG > 2 ++ print_hex_dump_debug("spihid pkt: ", DUMP_PREFIX_OFFSET, 16, 1, ++ spihid->rx_buf, ++ sizeof(struct spihid_transfer_packet), true); ++#endif ++#endif ++ ++ if (length > sizeof(pkt->data)) { ++ dev_warn_ratelimited(dev, "Invalid pkt len:%zu", length); ++ return; ++ } ++ ++ /* short message */ ++ if (pkt->offset == 0 && pkt->remain == 0) { ++ spihid_process_message(spihid, pkt->data, length, pkt->device, ++ pkt->flags); ++ } else { ++ spihid_assemble_meesage(spihid, pkt); ++ } ++} ++ ++static void spihid_read_packet_sync(struct spihid_apple *spihid) ++{ ++ int err; ++ ++ err = spi_sync(spihid->spidev, &spihid->rx_msg); ++ if (!err) { ++ spihid_process_read(spihid); ++ } else { ++ dev_warn(&spihid->spidev->dev, "RX failed: %d\n", err); ++ } ++} ++ ++irqreturn_t spihid_apple_core_irq(int irq, void *data) ++{ ++ struct spi_device *spi = data; ++ struct spihid_apple *spihid = spi_get_drvdata(spi); ++ ++ spihid_read_packet_sync(spihid); ++ ++ return IRQ_HANDLED; ++} ++EXPORT_SYMBOL_GPL(spihid_apple_core_irq); ++ ++static void spihid_apple_setup_spi_msgs(struct spihid_apple *spihid) ++{ ++ memset(&spihid->rx_transfer, 0, sizeof(spihid->rx_transfer)); ++ ++ spihid->rx_transfer.rx_buf = spihid->rx_buf; ++ spihid->rx_transfer.len = sizeof(struct spihid_transfer_packet); ++ ++ spi_message_init(&spihid->rx_msg); ++ spi_message_add_tail(&spihid->rx_transfer, &spihid->rx_msg); ++ ++ memset(&spihid->tx_transfer, 0, sizeof(spihid->rx_transfer)); ++ memset(&spihid->status_transfer, 0, sizeof(spihid->status_transfer)); ++ ++ spihid->tx_transfer.tx_buf = spihid->tx_buf; ++ spihid->tx_transfer.len = sizeof(struct spihid_transfer_packet); ++ spihid->tx_transfer.delay.unit = SPI_DELAY_UNIT_USECS; ++ spihid->tx_transfer.delay.value = SPI_RW_CHG_DELAY_US; ++ ++ spihid->status_transfer.rx_buf = spihid->status_buf; ++ spihid->status_transfer.len = sizeof(spi_hid_apple_status_ok); ++ ++ spi_message_init(&spihid->tx_msg); ++ spi_message_add_tail(&spihid->tx_transfer, &spihid->tx_msg); ++ spi_message_add_tail(&spihid->status_transfer, &spihid->tx_msg); ++} ++ ++static int spihid_apple_setup_spi(struct spihid_apple *spihid) ++{ ++ spihid_apple_setup_spi_msgs(spihid); ++ ++ return spihid->ops->power_on(spihid->ops); ++} ++ ++static int spihid_register_hid_device(struct spihid_apple *spihid, ++ struct spihid_interface *iface, u8 device) ++{ ++ int ret; ++ struct hid_device *hid; ++ ++ iface->id = device; ++ ++ hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return PTR_ERR(hid); ++ ++ strscpy(hid->name, spihid->product, sizeof(hid->name)); ++ snprintf(hid->phys, sizeof(hid->phys), "%s (%hhx)", ++ dev_name(&spihid->spidev->dev), device); ++ strscpy(hid->uniq, spihid->serial, sizeof(hid->uniq)); ++ ++ hid->ll_driver = &apple_hid_ll; ++ hid->bus = BUS_SPI; ++ hid->vendor = spihid->vendor_id; ++ hid->product = spihid->product_id; ++ hid->version = spihid->version_number; ++ ++ if (device == SPIHID_DEVICE_ID_KBD) ++ hid->type = HID_TYPE_SPI_KEYBOARD; ++ else if (device == SPIHID_DEVICE_ID_TP) ++ hid->type = HID_TYPE_SPI_MOUSE; ++ ++ hid->country = iface->country; ++ hid->dev.parent = &spihid->spidev->dev; ++ hid->driver_data = iface; ++ ++ ret = hid_add_device(hid); ++ if (ret < 0) { ++ hid_destroy_device(hid); ++ dev_warn(&spihid->spidev->dev, ++ "Failed to register hid device %hhu", device); ++ return ret; ++ } ++ ++ iface->hid = hid; ++ ++ return 0; ++} ++ ++static void spihid_destroy_hid_device(struct spihid_interface *iface) ++{ ++ if (iface->hid) { ++ hid_destroy_device(iface->hid); ++ iface->hid = NULL; ++ } ++ iface->ready = false; ++} ++ ++int spihid_apple_core_probe(struct spi_device *spi, struct spihid_apple_ops *ops) ++{ ++ struct device *dev = &spi->dev; ++ struct spihid_apple *spihid; ++ int err, i; ++ ++ if (!ops || !ops->power_on || !ops->power_off || !ops->enable_irq || !ops->disable_irq) ++ return -EINVAL; ++ ++ spihid = devm_kzalloc(dev, sizeof(*spihid), GFP_KERNEL); ++ if (!spihid) ++ return -ENOMEM; ++ ++ spihid->ops = ops; ++ spihid->spidev = spi; ++ ++ // init spi ++ spi_set_drvdata(spi, spihid); ++ ++ /* allocate SPI buffers */ ++ spihid->rx_buf = devm_kmalloc( ++ &spi->dev, sizeof(struct spihid_transfer_packet), GFP_KERNEL); ++ spihid->tx_buf = devm_kmalloc( ++ &spi->dev, sizeof(struct spihid_transfer_packet), GFP_KERNEL); ++ spihid->status_buf = devm_kmalloc( ++ &spi->dev, sizeof(spi_hid_apple_status_ok), GFP_KERNEL); ++ ++ if (!spihid->rx_buf || !spihid->tx_buf || !spihid->status_buf) ++ return -ENOMEM; ++ ++ spihid->report.buf = ++ devm_kmalloc(dev, SPIHID_MAX_INPUT_REPORT_SIZE, GFP_KERNEL); ++ ++ spihid->kbd.hid_desc = devm_kmalloc(dev, SPIHID_DESC_MAX, GFP_KERNEL); ++ spihid->tp.hid_desc = devm_kmalloc(dev, SPIHID_DESC_MAX, GFP_KERNEL); ++ ++ if (!spihid->report.buf || !spihid->kbd.hid_desc || ++ !spihid->tp.hid_desc) ++ return -ENOMEM; ++ ++ init_waitqueue_head(&spihid->wait); ++ ++ mutex_init(&spihid->tx_lock); ++ ++ /* Init spi transfer buffers and power device on */ ++ err = spihid_apple_setup_spi(spihid); ++ if (err < 0) ++ goto error; ++ ++ /* enable HID irq */ ++ spihid->ops->enable_irq(spihid->ops); ++ ++ // wait for boot message ++ err = wait_event_interruptible_timeout(spihid->wait, ++ spihid->status_booted, ++ msecs_to_jiffies(1000)); ++ if (err == 0) ++ err = -ENODEV; ++ if (err < 0) { ++ dev_err(dev, "waiting for device boot failed: %d", err); ++ goto error; ++ } ++ ++ /* request device information */ ++ dev_dbg(dev, "request device info"); ++ spihid_apple_request(spihid, 0xd0, 0x20, 0x01, 0xd0, 0, NULL, 0); ++ err = wait_event_interruptible_timeout(spihid->wait, spihid->vendor_id, ++ SPIHID_DEF_WAIT); ++ if (err == 0) ++ err = -ENODEV; ++ if (err < 0) { ++ dev_err(dev, "waiting for device info failed: %d", err); ++ goto error; ++ } ++ ++ /* request interface information */ ++ for (i = 0; i < spihid->num_devices; i++) { ++ struct spihid_interface *iface = spihid_get_iface(spihid, i); ++ if (!iface) ++ continue; ++ dev_dbg(dev, "request interface info 0x%02x", i); ++ spihid_apple_request(spihid, 0xd0, 0x20, 0x02, i, ++ SPIHID_DESC_MAX, NULL, 0); ++ err = wait_event_interruptible_timeout( ++ spihid->wait, iface->max_input_report_len, ++ SPIHID_DEF_WAIT); ++ } ++ ++ /* request HID report descriptors */ ++ for (i = 1; i < spihid->num_devices; i++) { ++ struct spihid_interface *iface = spihid_get_iface(spihid, i); ++ if (!iface) ++ continue; ++ dev_dbg(dev, "request hid report desc 0x%02x", i); ++ spihid_apple_request(spihid, 0xd0, 0x20, 0x10, i, ++ SPIHID_DESC_MAX, NULL, 0); ++ wait_event_interruptible_timeout( ++ spihid->wait, iface->hid_desc_len, SPIHID_DEF_WAIT); ++ } ++ ++ return 0; ++error: ++ return err; ++} ++EXPORT_SYMBOL_GPL(spihid_apple_core_probe); ++ ++void spihid_apple_core_remove(struct spi_device *spi) ++{ ++ struct spihid_apple *spihid = spi_get_drvdata(spi); ++ ++ /* destroy input devices */ ++ ++ spihid_destroy_hid_device(&spihid->tp); ++ spihid_destroy_hid_device(&spihid->kbd); ++ ++ /* disable irq */ ++ spihid->ops->disable_irq(spihid->ops); ++ ++ /* power SPI device down */ ++ spihid->ops->power_off(spihid->ops); ++} ++EXPORT_SYMBOL_GPL(spihid_apple_core_remove); ++ ++void spihid_apple_core_shutdown(struct spi_device *spi) ++{ ++ struct spihid_apple *spihid = spi_get_drvdata(spi); ++ ++ /* disable irq */ ++ spihid->ops->disable_irq(spihid->ops); ++ ++ /* power SPI device down */ ++ spihid->ops->power_off(spihid->ops); ++} ++EXPORT_SYMBOL_GPL(spihid_apple_core_shutdown); ++ ++MODULE_DESCRIPTION("Apple SPI HID transport driver"); ++MODULE_AUTHOR("Janne Grunau "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/spi-hid/spi-hid-apple-of.c b/drivers/hid/spi-hid/spi-hid-apple-of.c +new file mode 100644 +index 000000000000..db76774eea7e +--- /dev/null ++++ b/drivers/hid/spi-hid/spi-hid-apple-of.c +@@ -0,0 +1,138 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0 ++ * ++ * Apple SPI HID transport driver - Open Firmware ++ * ++ * Copyright (C) The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "spi-hid-apple.h" ++ ++ ++struct spihid_apple_of { ++ struct spihid_apple_ops ops; ++ ++ struct gpio_desc *enable_gpio; ++ int irq; ++}; ++ ++int spihid_apple_of_power_on(struct spihid_apple_ops *ops) ++{ ++ struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); ++ ++ /* reset the controller on boot */ ++ gpiod_direction_output(sh_of->enable_gpio, 1); ++ msleep(5); ++ gpiod_direction_output(sh_of->enable_gpio, 0); ++ msleep(5); ++ /* turn SPI device on */ ++ gpiod_direction_output(sh_of->enable_gpio, 1); ++ msleep(50); ++ ++ return 0; ++} ++ ++int spihid_apple_of_power_off(struct spihid_apple_ops *ops) ++{ ++ struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); ++ ++ /* turn SPI device off */ ++ gpiod_direction_output(sh_of->enable_gpio, 0); ++ ++ return 0; ++} ++ ++int spihid_apple_of_enable_irq(struct spihid_apple_ops *ops) ++{ ++ struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); ++ ++ enable_irq(sh_of->irq); ++ ++ return 0; ++} ++ ++int spihid_apple_of_disable_irq(struct spihid_apple_ops *ops) ++{ ++ struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); ++ ++ disable_irq(sh_of->irq); ++ ++ return 0; ++} ++ ++static int spihid_apple_of_probe(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ struct spihid_apple_of *spihid_of; ++ int err; ++ ++ dev_warn(dev, "%s:%d", __func__, __LINE__); ++ ++ spihid_of = devm_kzalloc(dev, sizeof(*spihid_of), GFP_KERNEL); ++ if (!spihid_of) ++ return -ENOMEM; ++ ++ spihid_of->ops.power_on = spihid_apple_of_power_on; ++ spihid_of->ops.power_off = spihid_apple_of_power_off; ++ spihid_of->ops.enable_irq = spihid_apple_of_enable_irq; ++ spihid_of->ops.disable_irq = spihid_apple_of_disable_irq; ++ ++ spihid_of->enable_gpio = devm_gpiod_get_index(dev, "spien", 0, 0); ++ if (IS_ERR(spihid_of->enable_gpio)) { ++ err = PTR_ERR(spihid_of->enable_gpio); ++ dev_err(dev, "failed to get 'spien' gpio pin: %d", err); ++ return err; ++ } ++ ++ spihid_of->irq = of_irq_get(dev->of_node, 0); ++ if (spihid_of->irq < 0) { ++ err = spihid_of->irq; ++ dev_err(dev, "failed to get 'extended-irq': %d", err); ++ return err; ++ } ++ err = devm_request_threaded_irq(dev, spihid_of->irq, NULL, ++ spihid_apple_core_irq, IRQF_ONESHOT | IRQF_NO_AUTOEN, ++ "spi-hid-apple-irq", spi); ++ if (err < 0) { ++ dev_err(dev, "failed to request extended-irq %d: %d", ++ spihid_of->irq, err); ++ return err; ++ } ++ ++ return spihid_apple_core_probe(spi, &spihid_of->ops); ++} ++ ++static const struct of_device_id spihid_apple_of_match[] = { ++ { .compatible = "apple,spi-hid-transport" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, spihid_apple_of_match); ++ ++static struct spi_device_id spihid_apple_of_id[] = { ++ { "spi-hid-transport", 0 }, ++ {} ++}; ++MODULE_DEVICE_TABLE(spi, spihid_apple_of_id); ++ ++static struct spi_driver spihid_apple_of_driver = { ++ .driver = { ++ .name = "spi-hid-apple-of", ++ //.pm = &spi_hid_apple_of_pm, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(spihid_apple_of_match), ++ }, ++ ++ .id_table = spihid_apple_of_id, ++ .probe = spihid_apple_of_probe, ++ .remove = spihid_apple_core_remove, ++ .shutdown = spihid_apple_core_shutdown, ++}; ++ ++module_spi_driver(spihid_apple_of_driver); ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/spi-hid/spi-hid-apple.h b/drivers/hid/spi-hid/spi-hid-apple.h +new file mode 100644 +index 000000000000..2d9554e8a5f8 +--- /dev/null ++++ b/drivers/hid/spi-hid/spi-hid-apple.h +@@ -0,0 +1,31 @@ ++/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ ++ ++#ifndef SPI_HID_APPLE_H ++#define SPI_HID_APPLE_H ++ ++#include ++#include ++ ++/** ++ * struct spihid_apple_ops - Ops to control the device from the core driver. ++ * ++ * @power_on: reset and power the device on. ++ * @power_off: power the device off. ++ * @enable_irq: enable irq or ACPI gpe. ++ * @disable_irq: disable irq or ACPI gpe. ++ */ ++ ++struct spihid_apple_ops { ++ int (*power_on)(struct spihid_apple_ops *ops); ++ int (*power_off)(struct spihid_apple_ops *ops); ++ int (*enable_irq)(struct spihid_apple_ops *ops); ++ int (*disable_irq)(struct spihid_apple_ops *ops); ++}; ++ ++irqreturn_t spihid_apple_core_irq(int irq, void *data); ++ ++int spihid_apple_core_probe(struct spi_device *spi, struct spihid_apple_ops *ops); ++void spihid_apple_core_remove(struct spi_device *spi); ++void spihid_apple_core_shutdown(struct spi_device *spi); ++ ++#endif /* SPI_HID_APPLE_H */ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0125-HID-add-HOST-vendor-device-IDs-for-Apple-MTP-devices.patch b/target/linux/silicon/patches-5.19/0125-HID-add-HOST-vendor-device-IDs-for-Apple-MTP-devices.patch new file mode 100644 index 000000000..181e296b7 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0125-HID-add-HOST-vendor-device-IDs-for-Apple-MTP-devices.patch @@ -0,0 +1,38 @@ +From dce57a9616a44e9717b60366fc71d47c32d1b70b Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 8 Jul 2022 00:29:43 +0900 +Subject: [PATCH 125/171] HID: add HOST vendor/device IDs for Apple MTP devices + +Apple M2 chips have an embedded MTP processor that handles all HID +functions, and does not go over a traditional bus like SPI. The devices +still have real IDs, so add them here. + +Signed-off-by: Hector Martin +--- + drivers/hid/hid-ids.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 98f922774df9..7ecfa2622d53 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -90,6 +90,7 @@ + #define USB_VENDOR_ID_APPLE 0x05ac + #define BT_VENDOR_ID_APPLE 0x004c + #define SPI_VENDOR_ID_APPLE 0x05ac ++#define HOST_VENDOR_ID_APPLE 0x05ac + #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 + #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d + #define USB_DEVICE_ID_APPLE_MAGICMOUSE2 0x0269 +@@ -190,6 +191,8 @@ + #define SPI_DEVICE_ID_APPLE_MACBOOK_PRO13_2020 0x0341 + #define SPI_DEVICE_ID_APPLE_MACBOOK_PRO14_2021 0x0342 + #define SPI_DEVICE_ID_APPLE_MACBOOK_PRO16_2021 0x0343 ++#define HOST_DEVICE_ID_APPLE_MACBOOK_AIR13_2022 0x0351 ++#define HOST_DEVICE_ID_APPLE_MACBOOK_PRO13_2022 0x0354 + + #define USB_VENDOR_ID_ASUS 0x0486 + #define USB_DEVICE_ID_ASUS_T91MT 0x0185 +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0126-HID-core-Handle-HOST-bus-type-when-announcing-device.patch b/target/linux/silicon/patches-5.19/0126-HID-core-Handle-HOST-bus-type-when-announcing-device.patch new file mode 100644 index 000000000..af3e114e4 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0126-HID-core-Handle-HOST-bus-type-when-announcing-device.patch @@ -0,0 +1,28 @@ +From de6f500d1d4f98fc5b711ec88f916069c4206395 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 8 Jul 2022 02:06:15 +0900 +Subject: [PATCH 126/171] HID: core: Handle HOST bus type when announcing + devices + +Signed-off-by: Hector Martin +--- + drivers/hid/hid-core.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 22f313716a12..048f13b487b3 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -2222,6 +2222,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) + case BUS_SPI: + bus = "SPI"; + break; ++ case BUS_HOST: ++ bus = "HOST"; ++ break; + case BUS_VIRTUAL: + bus = "VIRTUAL"; + break; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0127-hid-apple-Bind-to-HOST-devices-for-MTP.patch b/target/linux/silicon/patches-5.19/0127-hid-apple-Bind-to-HOST-devices-for-MTP.patch new file mode 100644 index 000000000..88d18ae9b --- /dev/null +++ b/target/linux/silicon/patches-5.19/0127-hid-apple-Bind-to-HOST-devices-for-MTP.patch @@ -0,0 +1,59 @@ +From aaee021a970f5f5fadabc4378c8260aee692e8ec Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 8 Jul 2022 02:12:24 +0900 +Subject: [PATCH 127/171] hid: apple: Bind to HOST devices for MTP + +We use BUS_HOST for MTP HID subdevices + +Signed-off-by: Hector Martin +--- + drivers/hid/hid-apple.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c +index 6700cbac2575..7dc7b8a6aea2 100644 +--- a/drivers/hid/hid-apple.c ++++ b/drivers/hid/hid-apple.c +@@ -444,11 +444,16 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, + else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && + hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) + table = macbookair_fn_keys; +- else if (hid->vendor == SPI_VENDOR_ID_APPLE && +- hid->product == SPI_DEVICE_ID_APPLE_MACBOOK_PRO13_2020) +- table = apple_fn_keys_mbp13; +- else if (hid->vendor == SPI_VENDOR_ID_APPLE) +- table = apple_fn_keys_spi; ++ else if (hid->bus == BUS_HOST || hid->bus == BUS_SPI) ++ switch (hid->product) { ++ case SPI_DEVICE_ID_APPLE_MACBOOK_PRO13_2020: ++ case HOST_DEVICE_ID_APPLE_MACBOOK_PRO13_2022: ++ table = apple_fn_keys_mbp13; ++ break; ++ default: ++ table = apple_fn_keys_spi; ++ break; ++ } + else if (hid->product < 0x21d || hid->product >= 0x300) + table = powerbook_fn_keys; + else +@@ -834,7 +839,7 @@ static int apple_probe(struct hid_device *hdev, + struct apple_sc *asc; + int ret; + +- if (id->bus == BUS_SPI && id->vendor == SPI_VENDOR_ID_APPLE && ++ if ((id->bus == BUS_SPI || id->bus == BUS_HOST) && id->vendor == SPI_VENDOR_ID_APPLE && + hdev->type != HID_TYPE_SPI_KEYBOARD) + return -ENODEV; + +@@ -1081,6 +1086,8 @@ static const struct hid_device_id apple_devices[] = { + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_SPI_DEVICE(SPI_VENDOR_ID_APPLE, HID_ANY_ID), + .driver_data = APPLE_HAS_FN }, ++ { HID_DEVICE(BUS_HOST, HID_GROUP_ANY, HOST_VENDOR_ID_APPLE, ++ HID_ANY_ID), .driver_data = APPLE_HAS_FN }, + + { } + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0128-hid-magicmouse-Add-MTP-multi-touch-device-support.patch b/target/linux/silicon/patches-5.19/0128-hid-magicmouse-Add-MTP-multi-touch-device-support.patch new file mode 100644 index 000000000..3b65d726d --- /dev/null +++ b/target/linux/silicon/patches-5.19/0128-hid-magicmouse-Add-MTP-multi-touch-device-support.patch @@ -0,0 +1,174 @@ +From 5624d8c356fe43797e45c28af6faddc425e307aa Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 8 Jul 2022 02:12:57 +0900 +Subject: [PATCH 128/171] hid: magicmouse: Add MTP multi-touch device support + +Apple M2 devices expose the multi-touch device over the HID over +DockChannel transport, which we represent as the HOST bus type. The +report format is the same, except the legacy mouse header is gone and +there is no enable request needed. + +Signed-off-by: Hector Martin +--- + drivers/hid/hid-magicmouse.c | 67 ++++++++++++++++++++++++++---------- + 1 file changed, 49 insertions(+), 18 deletions(-) + +diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c +index 65c4b6307ce9..a951e8a8f085 100644 +--- a/drivers/hid/hid-magicmouse.c ++++ b/drivers/hid/hid-magicmouse.c +@@ -59,6 +59,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie + #define MOUSE_REPORT_ID 0x29 + #define MOUSE2_REPORT_ID 0x12 + #define DOUBLE_REPORT_ID 0xf7 ++#define SPI_REPORT_ID 0x02 ++#define MTP_REPORT_ID 0x75 + #define USB_BATTERY_TIMEOUT_MS 60000 + + #define MAX_CONTACTS 16 +@@ -570,25 +572,32 @@ struct tp_finger { + } __attribute__((packed, aligned(2))); + + /** +- * struct trackpad report ++ * vendor trackpad report + * +- * @report_id: reportid +- * @buttons: HID Usage Buttons 3 1-bit reports + * @num_fingers: the number of fingers being reported in @fingers +- * @clicked: same as @buttons ++ * @buttons: same as HID buttons + */ + struct tp_header { ++ // HID vendor part, up to 1751 bytes ++ u8 unknown[22]; ++ u8 num_fingers; ++ u8 buttons; ++ u8 unknown3[14]; ++}; ++ ++/** ++ * standard HID mouse report ++ * ++ * @report_id: reportid ++ * @buttons: HID Usage Buttons 3 1-bit reports ++ */ ++struct tp_mouse_report { + // HID mouse report + u8 report_id; + u8 buttons; + u8 rel_x; + u8 rel_y; + u8 padding[4]; +- // HID vendor part, up to 1751 bytes +- u8 unknown[22]; +- u8 num_fingers; +- u8 clicked; +- u8 unknown3[14]; + }; + + static inline int le16_to_int(__le16 x) +@@ -618,7 +627,7 @@ static void report_finger_data(struct input_dev *input, int slot, + input_report_abs(input, ABS_MT_POSITION_Y, pos->y); + } + +-static int magicmouse_raw_event_spi(struct hid_device *hdev, ++static int magicmouse_raw_event_mtp(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) + { + struct magicmouse_sc *msc = hid_get_drvdata(hdev); +@@ -635,9 +644,6 @@ static int magicmouse_raw_event_spi(struct hid_device *hdev, + // print_hex_dump_debug("appleft ev: ", DUMP_PREFIX_OFFSET, 16, 1, data, + // size, false); + +- if (data[0] != TRACKPAD2_USB_REPORT_ID) +- return 0; +- + /* Expect 46 bytes of prefix, and N * 30 bytes of touch data. */ + if (size < hdr_sz || ((size - hdr_sz) % touch_sz) != 0) + return 0; +@@ -676,12 +682,26 @@ static int magicmouse_raw_event_spi(struct hid_device *hdev, + } + + input_mt_sync_frame(input); +- input_report_key(input, BTN_MOUSE, data[1] & 1); ++ input_report_key(input, BTN_MOUSE, tp_hdr->buttons & 1); + + input_sync(input); + return 1; + } + ++static int magicmouse_raw_event_spi(struct hid_device *hdev, ++ struct hid_report *report, u8 *data, int size) ++{ ++ const size_t hdr_sz = sizeof(struct tp_mouse_report); ++ ++ if (size < hdr_sz) ++ return 0; ++ ++ if (data[0] != TRACKPAD2_USB_REPORT_ID) ++ return 0; ++ ++ return magicmouse_raw_event_mtp(hdev, report, data + hdr_sz, size - hdr_sz); ++} ++ + static int magicmouse_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) + { +@@ -1066,7 +1086,7 @@ static int magicmouse_probe(struct hid_device *hdev, + struct hid_report *report; + int ret; + +- if (id->bus == BUS_SPI && id->vendor == SPI_VENDOR_ID_APPLE && ++ if ((id->bus == BUS_SPI || id->bus == BUS_HOST) && id->vendor == SPI_VENDOR_ID_APPLE && + hdev->type != HID_TYPE_SPI_MOUSE) + return -ENODEV; + +@@ -1078,7 +1098,10 @@ static int magicmouse_probe(struct hid_device *hdev, + + // internal trackpad use a data format use input ops to avoid + // conflicts with the report ID. +- if (id->vendor == SPI_VENDOR_ID_APPLE) { ++ if (id->bus == BUS_HOST) { ++ msc->input_ops.raw_event = magicmouse_raw_event_mtp; ++ msc->input_ops.setup_input = magicmouse_setup_input_spi; ++ } else if (id->bus == BUS_SPI) { + msc->input_ops.raw_event = magicmouse_raw_event_spi; + msc->input_ops.setup_input = magicmouse_setup_input_spi; + +@@ -1135,8 +1158,10 @@ static int magicmouse_probe(struct hid_device *hdev, + else /* USB_VENDOR_ID_APPLE */ + report = hid_register_report(hdev, HID_INPUT_REPORT, + TRACKPAD2_USB_REPORT_ID, 0); +- } else if (id->vendor == SPI_VENDOR_ID_APPLE) { +- report = hid_register_report(hdev, HID_INPUT_REPORT, 2, 0); ++ } else if (id->bus == BUS_SPI) { ++ report = hid_register_report(hdev, HID_INPUT_REPORT, SPI_REPORT_ID, 0); ++ } else if (id->bus == BUS_HOST) { ++ report = hid_register_report(hdev, HID_INPUT_REPORT, MTP_REPORT_ID, 0); + } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ + report = hid_register_report(hdev, HID_INPUT_REPORT, + TRACKPAD_REPORT_ID, 0); +@@ -1151,6 +1176,10 @@ static int magicmouse_probe(struct hid_device *hdev, + } + report->size = 6; + ++ /* MTP devices do not need the MT enable, this is handled by the MTP driver */ ++ if (id->bus == BUS_HOST) ++ return 0; ++ + /* + * Some devices repond with 'invalid report id' when feature + * report switching it into multitouch mode is sent to it. +@@ -1233,6 +1262,8 @@ static const struct hid_device_id magic_mice[] = { + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, + { HID_SPI_DEVICE(SPI_VENDOR_ID_APPLE, HID_ANY_ID), + .driver_data = 0 }, ++ { HID_DEVICE(BUS_HOST, HID_GROUP_ANY, HOST_VENDOR_ID_APPLE, ++ HID_ANY_ID), .driver_data = 0 }, + { } + }; + MODULE_DEVICE_TABLE(hid, magic_mice); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0129-soc-apple-Add-DockChannel-driver.patch b/target/linux/silicon/patches-5.19/0129-soc-apple-Add-DockChannel-driver.patch new file mode 100644 index 000000000..e8e17d572 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0129-soc-apple-Add-DockChannel-driver.patch @@ -0,0 +1,501 @@ +From ffeb65333caa066616ee70e0257035fe99cf4205 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 8 Jul 2022 02:09:24 +0900 +Subject: [PATCH 129/171] soc: apple: Add DockChannel driver + +DockChannel is a simple FIFO interface used to communicate between SoC +blocks. Add a driver that represents the shared interrupt controller for +the DockChannel block, and then exposes probe and data transfer +functions that child device drivers can use to instantiate individual +FIFOs. + +Signed-off-by: Hector Martin +--- + drivers/soc/apple/Kconfig | 10 + + drivers/soc/apple/Makefile | 3 + + drivers/soc/apple/dockchannel.c | 407 ++++++++++++++++++++++++++ + include/linux/soc/apple/dockchannel.h | 26 ++ + 4 files changed, 446 insertions(+) + create mode 100644 drivers/soc/apple/dockchannel.c + create mode 100644 include/linux/soc/apple/dockchannel.h + +diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig +index a1596fefacff..9e93df0ac825 100644 +--- a/drivers/soc/apple/Kconfig ++++ b/drivers/soc/apple/Kconfig +@@ -41,6 +41,16 @@ config APPLE_SART + + Say 'y' here if you have an Apple SoC. + ++config APPLE_DOCKCHANNEL ++ tristate "Apple DockChannel FIFO" ++ depends on ARCH_APPLE || COMPILE_TEST ++ default ARCH_APPLE ++ help ++ DockChannel is a simple FIFO used on Apple SoCs for debug and inter-processor ++ communications. ++ ++ Say 'y' here if you have an Apple SoC. ++ + endmenu + + endif +diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile +index e293770cf66d..aa4203e02462 100644 +--- a/drivers/soc/apple/Makefile ++++ b/drivers/soc/apple/Makefile +@@ -6,3 +6,6 @@ apple-rtkit-y = rtkit.o rtkit-crashlog.o + + obj-$(CONFIG_APPLE_SART) += apple-sart.o + apple-sart-y = sart.o ++ ++obj-$(CONFIG_APPLE_DOCKCHANNEL) += apple-dockchannel.o ++apple-dockchannel-y = dockchannel.o +diff --git a/drivers/soc/apple/dockchannel.c b/drivers/soc/apple/dockchannel.c +new file mode 100644 +index 000000000000..c21ef7545e17 +--- /dev/null ++++ b/drivers/soc/apple/dockchannel.c +@@ -0,0 +1,407 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple DockChannel FIFO driver ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DOCKCHANNEL_MAX_IRQ 32 ++ ++#define DOCKCHANNEL_TX_TIMEOUT_MS 1000 ++#define DOCKCHANNEL_RX_TIMEOUT_MS 1000 ++ ++#define IRQ_MASK 0x0 ++#define IRQ_FLAG 0x4 ++ ++#define IRQ_TX BIT(0) ++#define IRQ_RX BIT(1) ++ ++#define CONFIG_TX_THRESH 0x0 ++#define CONFIG_RX_THRESH 0x4 ++ ++#define DATA_TX8 0x4 ++#define DATA_TX16 0x8 ++#define DATA_TX24 0xc ++#define DATA_TX32 0x10 ++#define DATA_TX_FREE 0x14 ++#define DATA_RX8 0x1c ++#define DATA_RX16 0x20 ++#define DATA_RX24 0x24 ++#define DATA_RX32 0x28 ++#define DATA_RX_COUNT 0x2c ++ ++struct dockchannel { ++ struct device *dev; ++ int tx_irq; ++ int rx_irq; ++ ++ void __iomem *config_base; ++ void __iomem *data_base; ++ ++ u32 fifo_size; ++ bool awaiting; ++ struct completion tx_comp; ++ struct completion rx_comp; ++ ++ void *cookie; ++ void (*data_available)(void *cookie, size_t avail); ++}; ++ ++struct dockchannel_common { ++ struct device *dev; ++ struct irq_domain *domain; ++ int irq; ++ ++ void __iomem *irq_base; ++}; ++ ++/* Dockchannel FIFO functions */ ++ ++static irqreturn_t dockchannel_tx_irq(int irq, void *data) ++{ ++ struct dockchannel *dockchannel = data; ++ ++ disable_irq_nosync(irq); ++ complete(&dockchannel->tx_comp); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t dockchannel_rx_irq(int irq, void *data) ++{ ++ struct dockchannel *dockchannel = data; ++ ++ disable_irq_nosync(irq); ++ ++ if (dockchannel->awaiting) { ++ return IRQ_WAKE_THREAD; ++ } else { ++ complete(&dockchannel->rx_comp); ++ return IRQ_HANDLED; ++ } ++} ++ ++static irqreturn_t dockchannel_rx_irq_thread(int irq, void *data) ++{ ++ struct dockchannel *dockchannel = data; ++ size_t avail = readl_relaxed(dockchannel->data_base + DATA_RX_COUNT); ++ ++ dockchannel->awaiting = false; ++ dockchannel->data_available(dockchannel->cookie, avail); ++ ++ return IRQ_HANDLED; ++} ++ ++int dockchannel_send(struct dockchannel *dockchannel, const void *buf, size_t count) ++{ ++ size_t left = count; ++ const u8 *p = buf; ++ ++ while (left > 0) { ++ size_t avail = readl_relaxed(dockchannel->data_base + DATA_TX_FREE); ++ size_t block = min(left, avail); ++ ++ if (avail == 0) { ++ size_t threshold = min((size_t)(dockchannel->fifo_size / 2), left); ++ ++ writel_relaxed(threshold, dockchannel->config_base + CONFIG_TX_THRESH); ++ reinit_completion(&dockchannel->tx_comp); ++ enable_irq(dockchannel->tx_irq); ++ ++ if (!wait_for_completion_timeout(&dockchannel->tx_comp, ++ msecs_to_jiffies(DOCKCHANNEL_TX_TIMEOUT_MS))) { ++ disable_irq(dockchannel->tx_irq); ++ return -ETIMEDOUT; ++ } ++ ++ continue; ++ } ++ ++ while (block >= 4) { ++ writel_relaxed(get_unaligned_le32(p), dockchannel->data_base + DATA_TX32); ++ p += 4; ++ left -= 4; ++ block -= 4; ++ } ++ while (block > 0) { ++ writeb_relaxed(*p++, dockchannel->data_base + DATA_TX8); ++ left--; ++ block--; ++ } ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(dockchannel_send); ++ ++int dockchannel_recv(struct dockchannel *dockchannel, void *buf, size_t count) ++{ ++ size_t left = count; ++ u8 *p = buf; ++ ++ while (left > 0) { ++ size_t avail = readl_relaxed(dockchannel->data_base + DATA_RX_COUNT); ++ size_t block = min(left, avail); ++ ++ if (avail == 0) { ++ size_t threshold = min((size_t)(dockchannel->fifo_size / 2), left); ++ ++ writel_relaxed(threshold, dockchannel->config_base + CONFIG_RX_THRESH); ++ reinit_completion(&dockchannel->rx_comp); ++ enable_irq(dockchannel->rx_irq); ++ ++ if (!wait_for_completion_timeout(&dockchannel->rx_comp, ++ msecs_to_jiffies(DOCKCHANNEL_RX_TIMEOUT_MS))) { ++ disable_irq(dockchannel->rx_irq); ++ return -ETIMEDOUT; ++ } ++ ++ continue; ++ } ++ ++ while (block >= 4) { ++ put_unaligned_le32(readl_relaxed(dockchannel->data_base + DATA_RX32), p); ++ p += 4; ++ left -= 4; ++ block -= 4; ++ } ++ while (block > 0) { ++ *p++ = readl_relaxed(dockchannel->data_base + DATA_RX8) >> 8; ++ left--; ++ block--; ++ } ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(dockchannel_recv); ++ ++int dockchannel_await(struct dockchannel *dockchannel, ++ void (*callback)(void *cookie, size_t avail), ++ void *cookie, size_t count) ++{ ++ size_t threshold = min((size_t)dockchannel->fifo_size, count); ++ ++ if (!count) { ++ dockchannel->awaiting = false; ++ disable_irq(dockchannel->rx_irq); ++ return 0; ++ } ++ ++ dockchannel->data_available = callback; ++ dockchannel->cookie = cookie; ++ dockchannel->awaiting = true; ++ writel_relaxed(threshold, dockchannel->config_base + CONFIG_RX_THRESH); ++ enable_irq(dockchannel->rx_irq); ++ ++ return threshold; ++} ++EXPORT_SYMBOL(dockchannel_await); ++ ++struct dockchannel *dockchannel_init(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct dockchannel *dockchannel; ++ int ret; ++ ++ dockchannel = devm_kzalloc(dev, sizeof(*dockchannel), GFP_KERNEL); ++ if (!dockchannel) ++ return ERR_PTR(-ENOMEM); ++ ++ dockchannel->dev = dev; ++ dockchannel->config_base = devm_platform_ioremap_resource_byname(pdev, "config"); ++ if (IS_ERR(dockchannel->config_base)) ++ return (void *)dockchannel->config_base; ++ ++ dockchannel->data_base = devm_platform_ioremap_resource_byname(pdev, "data"); ++ if (IS_ERR(dockchannel->data_base)) ++ return (void *)dockchannel->data_base; ++ ++ ret = of_property_read_u32(dev->of_node, "apple,fifo-size", &dockchannel->fifo_size); ++ if (ret) ++ return ERR_PTR(dev_err_probe(dev, ret, "Missing apple,fifo-size property")); ++ ++ init_completion(&dockchannel->tx_comp); ++ init_completion(&dockchannel->rx_comp); ++ ++ dockchannel->tx_irq = platform_get_irq_byname(pdev, "tx"); ++ if (dockchannel->tx_irq <= 0) { ++ return ERR_PTR(dev_err_probe(dev, dockchannel->tx_irq, ++ "Failed to get TX IRQ")); ++ } ++ ++ dockchannel->rx_irq = platform_get_irq_byname(pdev, "rx"); ++ if (dockchannel->rx_irq <= 0) { ++ return ERR_PTR(dev_err_probe(dev, dockchannel->rx_irq, ++ "Failed to get RX IRQ")); ++ } ++ ++ ret = devm_request_irq(dev, dockchannel->tx_irq, dockchannel_tx_irq, IRQF_NO_AUTOEN, ++ "apple-dockchannel-tx", dockchannel); ++ if (ret) ++ return ERR_PTR(dev_err_probe(dev, ret, "Failed to request TX IRQ")); ++ ++ ret = devm_request_threaded_irq(dev, dockchannel->rx_irq, dockchannel_rx_irq, ++ dockchannel_rx_irq_thread, IRQF_NO_AUTOEN, ++ "apple-dockchannel-rx", dockchannel); ++ if (ret) ++ return ERR_PTR(dev_err_probe(dev, ret, "Failed to request RX IRQ")); ++ ++ return dockchannel; ++} ++EXPORT_SYMBOL(dockchannel_init); ++ ++ ++/* Dockchannel IRQchip */ ++ ++static void dockchannel_irq(struct irq_desc *desc) ++{ ++ unsigned int irq = irq_desc_get_irq(desc); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ struct dockchannel_common *dcc = irq_get_handler_data(irq); ++ unsigned long flags = readl_relaxed(dcc->irq_base + IRQ_FLAG); ++ int bit; ++ ++ chained_irq_enter(chip, desc); ++ ++ for_each_set_bit(bit, &flags, DOCKCHANNEL_MAX_IRQ) ++ generic_handle_domain_irq(dcc->domain, bit); ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static void dockchannel_irq_ack(struct irq_data *data) ++{ ++ struct dockchannel_common *dcc = irq_data_get_irq_chip_data(data); ++ unsigned int hwirq = data->hwirq; ++ ++ writel_relaxed(BIT(hwirq), dcc->irq_base + IRQ_FLAG); ++} ++ ++static void dockchannel_irq_mask(struct irq_data *data) ++{ ++ struct dockchannel_common *dcc = irq_data_get_irq_chip_data(data); ++ unsigned int hwirq = data->hwirq; ++ u32 val = readl_relaxed(dcc->irq_base + IRQ_MASK); ++ ++ writel_relaxed(val & ~BIT(hwirq), dcc->irq_base + IRQ_MASK); ++} ++ ++static void dockchannel_irq_unmask(struct irq_data *data) ++{ ++ struct dockchannel_common *dcc = irq_data_get_irq_chip_data(data); ++ unsigned int hwirq = data->hwirq; ++ u32 val = readl_relaxed(dcc->irq_base + IRQ_MASK); ++ ++ writel_relaxed(val | BIT(hwirq), dcc->irq_base + IRQ_MASK); ++} ++ ++static const struct irq_chip dockchannel_irqchip = { ++ .name = "dockchannel-irqc", ++ .irq_ack = dockchannel_irq_ack, ++ .irq_mask = dockchannel_irq_mask, ++ .irq_unmask = dockchannel_irq_unmask, ++}; ++ ++static int dockchannel_irq_domain_map(struct irq_domain *d, unsigned int virq, ++ irq_hw_number_t hw) ++{ ++ irq_set_chip_data(virq, d->host_data); ++ irq_set_chip_and_handler(virq, &dockchannel_irqchip, handle_level_irq); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops dockchannel_irq_domain_ops = { ++ .xlate = irq_domain_xlate_twocell, ++ .map = dockchannel_irq_domain_map, ++}; ++ ++static int dockchannel_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct dockchannel_common *dcc; ++ struct device_node *child; ++ ++ dcc = devm_kzalloc(dev, sizeof(*dcc), GFP_KERNEL); ++ if (!dcc) ++ return -ENOMEM; ++ ++ dcc->dev = dev; ++ platform_set_drvdata(pdev, dcc); ++ ++ dcc->irq_base = devm_platform_ioremap_resource_byname(pdev, "irq"); ++ if (IS_ERR(dcc->irq_base)) ++ return PTR_ERR(dcc->irq_base); ++ ++ writel_relaxed(0, dcc->irq_base + IRQ_MASK); ++ writel_relaxed(~0, dcc->irq_base + IRQ_FLAG); ++ ++ dcc->domain = irq_domain_add_linear(dev->of_node, DOCKCHANNEL_MAX_IRQ, ++ &dockchannel_irq_domain_ops, dcc); ++ if (!dcc->domain) ++ return -ENOMEM; ++ ++ dcc->irq = platform_get_irq(pdev, 0); ++ if (dcc->irq <= 0) ++ return dev_err_probe(dev, dcc->irq, "Failed to get IRQ"); ++ ++ irq_set_handler_data(dcc->irq, dcc); ++ irq_set_chained_handler(dcc->irq, dockchannel_irq); ++ ++ for_each_child_of_node(dev->of_node, child) ++ of_platform_device_create(child, NULL, dev); ++ ++ return 0; ++} ++ ++static int dockchannel_remove(struct platform_device *pdev) ++{ ++ struct dockchannel_common *dcc = platform_get_drvdata(pdev); ++ int hwirq; ++ ++ device_for_each_child(&pdev->dev, NULL, of_platform_device_destroy); ++ ++ irq_set_chained_handler_and_data(dcc->irq, NULL, NULL); ++ ++ for (hwirq = 0; hwirq < DOCKCHANNEL_MAX_IRQ; hwirq++) ++ irq_dispose_mapping(irq_find_mapping(dcc->domain, hwirq)); ++ ++ irq_domain_remove(dcc->domain); ++ ++ writel_relaxed(0, dcc->irq_base + IRQ_MASK); ++ writel_relaxed(~0, dcc->irq_base + IRQ_FLAG); ++ ++ return 0; ++} ++ ++static const struct of_device_id dockchannel_of_match[] = { ++ { .compatible = "apple,dockchannel" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dockchannel_of_match); ++ ++static struct platform_driver dockchannel_driver = { ++ .driver = { ++ .name = "dockchannel", ++ .of_match_table = dockchannel_of_match, ++ }, ++ .probe = dockchannel_probe, ++ .remove = dockchannel_remove, ++}; ++module_platform_driver(dockchannel_driver); ++ ++MODULE_AUTHOR("Hector Martin "); ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple DockChannel driver"); +diff --git a/include/linux/soc/apple/dockchannel.h b/include/linux/soc/apple/dockchannel.h +new file mode 100644 +index 000000000000..0b7093935ddf +--- /dev/null ++++ b/include/linux/soc/apple/dockchannel.h +@@ -0,0 +1,26 @@ ++/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ ++/* ++ * Apple Dockchannel devices ++ * Copyright (C) The Asahi Linux Contributors ++ */ ++#ifndef _LINUX_APPLE_DOCKCHANNEL_H_ ++#define _LINUX_APPLE_DOCKCHANNEL_H_ ++ ++#include ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_APPLE_DOCKCHANNEL) ++ ++struct dockchannel; ++ ++struct dockchannel *dockchannel_init(struct platform_device *pdev); ++ ++int dockchannel_send(struct dockchannel *dockchannel, const void *buf, size_t count); ++int dockchannel_recv(struct dockchannel *dockchannel, void *buf, size_t count); ++int dockchannel_await(struct dockchannel *dockchannel, ++ void (*callback)(void *cookie, size_t avail), ++ void *cookie, size_t count); ++ ++#endif ++#endif +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0130-hid-Add-Apple-DockChannel-HID-transport-driver.patch b/target/linux/silicon/patches-5.19/0130-hid-Add-Apple-DockChannel-HID-transport-driver.patch new file mode 100644 index 000000000..a764b3eaa --- /dev/null +++ b/target/linux/silicon/patches-5.19/0130-hid-Add-Apple-DockChannel-HID-transport-driver.patch @@ -0,0 +1,1142 @@ +From 55af457be82d0853857bab148c649a328aa58ffa Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 8 Jul 2022 02:11:21 +0900 +Subject: [PATCH 130/171] hid: Add Apple DockChannel HID transport driver + +Apple M2 devices have an MTP coprocessor embedded in the SoC that +handles HID for the integrated touchpad/keyboard, and communicates +over the DockChannel interface. This driver implements this new +interface. + +Signed-off-by: Hector Martin +--- + drivers/hid/Kconfig | 2 + + drivers/hid/Makefile | 2 + + drivers/hid/dockchannel-hid/Kconfig | 14 + + drivers/hid/dockchannel-hid/Makefile | 6 + + drivers/hid/dockchannel-hid/dockchannel-hid.c | 1058 +++++++++++++++++ + 5 files changed, 1082 insertions(+) + create mode 100644 drivers/hid/dockchannel-hid/Kconfig + create mode 100644 drivers/hid/dockchannel-hid/Makefile + create mode 100644 drivers/hid/dockchannel-hid/dockchannel-hid.c + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 1dd6697e7c59..bd47caba1413 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1324,4 +1324,6 @@ source "drivers/hid/surface-hid/Kconfig" + + source "drivers/hid/spi-hid/Kconfig" + ++source "drivers/hid/dockchannel-hid/Kconfig" ++ + endmenu +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index a720e68fe1d7..2c90409d515c 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -158,3 +158,5 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + + obj-$(CONFIG_SPI_HID_APPLE_CORE) += spi-hid/ ++ ++obj-$(CONFIG_HID_DOCKCHANNEL) += dockchannel-hid/ +diff --git a/drivers/hid/dockchannel-hid/Kconfig b/drivers/hid/dockchannel-hid/Kconfig +new file mode 100644 +index 000000000000..8a81d551a83d +--- /dev/null ++++ b/drivers/hid/dockchannel-hid/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR MIT ++menu "DockChannel HID support" ++ depends on APPLE_DOCKCHANNEL ++ ++config HID_DOCKCHANNEL ++ tristate "HID over DockChannel transport layer for Apple Silicon SoCs" ++ default ARCH_APPLE ++ depends on APPLE_DOCKCHANNEL && INPUT && OF && HID ++ help ++ Say Y here if you use an M2 or later Apple Silicon based laptop. ++ The keyboard and touchpad are HID based devices connected via the ++ proprietary DockChannel interface. ++ ++endmenu +diff --git a/drivers/hid/dockchannel-hid/Makefile b/drivers/hid/dockchannel-hid/Makefile +new file mode 100644 +index 000000000000..7dba766b047f +--- /dev/null ++++ b/drivers/hid/dockchannel-hid/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR MIT ++# ++# Makefile for DockChannel HID transport drivers ++# ++ ++obj-$(CONFIG_HID_DOCKCHANNEL) += dockchannel-hid.o +diff --git a/drivers/hid/dockchannel-hid/dockchannel-hid.c b/drivers/hid/dockchannel-hid/dockchannel-hid.c +new file mode 100644 +index 000000000000..aaa7d357c6fa +--- /dev/null ++++ b/drivers/hid/dockchannel-hid/dockchannel-hid.c +@@ -0,0 +1,1058 @@ ++/* ++ * SPDX-License-Identifier: GPL-2.0 OR MIT ++ * ++ * Apple DockChannel HID transport driver ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../hid-ids.h" ++ ++#define COMMAND_TIMEOUT 1000 ++ ++#define MAX_INTERFACES 16 ++ ++/* Data + checksum */ ++#define MAX_PKT_SIZE (0xffff + 4) ++ ++#define DCHID_CHANNEL_CMD 0x11 ++#define DCHID_CHANNEL_REPORT 0x12 ++ ++struct dchid_hdr { ++ u8 hdr_len; ++ u8 channel; ++ __le16 length; ++ u8 seq; ++ u8 iface; ++ __le16 pad; ++} __packed; ++ ++#define IFACE_COMM 0 ++ ++#define FLAGS_GROUP GENMASK(7, 6) ++#define FLAGS_REQ GENMASK(5, 0) ++ ++#define GROUP_INPUT 0 ++#define GROUP_OUTPUT 1 ++#define GROUP_CMD 2 ++ ++#define REQ_SET_REPORT 0 ++#define REQ_GET_REPORT 1 ++ ++struct dchid_subhdr { ++ u8 flags; ++ u8 unk; ++ __le16 length; ++ __le32 retcode; ++} __packed; ++ ++#define EVENT_GPIO_CMD 0xa0 ++#define EVENT_INIT 0xf0 ++#define EVENT_READY 0xf1 ++ ++struct dchid_init_hdr { ++ u8 type; ++ u8 unk1; ++ u8 unk2; ++ u8 iface; ++ char name[16]; ++} __packed; ++ ++#define INIT_HID_DESCRIPTOR 0 ++#define INIT_GPIO_REQUEST 1 ++#define INIT_TERMINATOR 2 ++ ++#define CMD_RESET_INTERFACE 0x40 ++#define CMD_SEND_FIRMWARE 0x95 ++#define CMD_ENABLE_INTERFACE 0xb4 ++#define CMD_ACK_GPIO_CMD 0xa1 ++ ++struct dchid_init_block_hdr { ++ __le16 type; ++ __le16 subtype; ++ __le16 length; ++} __packed; ++ ++#define MAX_GPIO_NAME 32 ++ ++struct dchid_gpio_request { ++ __le16 unk; ++ __le16 id; ++ char name[MAX_GPIO_NAME]; ++} __packed; ++ ++struct dchid_gpio_cmd { ++ u8 type; ++ u8 iface; ++ u8 gpio; ++ u8 unk; ++ u8 cmd; ++} __packed; ++ ++struct dchid_gpio_ack { ++ u8 type; ++ __le32 retcode; ++ u8 cmd[]; ++} __packed; ++ ++#define STM_REPORT_ID 0x10 ++#define STM_REPORT_SERIAL 0x11 ++#define STM_REPORT_KEYBTYPE 0x14 ++ ++#define KEYBOARD_TYPE_ANSI 0 ++#define KEYBOARD_TYPE_ISO 1 ++#define KEYBOARD_TYPE_JIS 2 ++ ++struct dchid_stm_id { ++ u8 unk; ++ __le16 vendor_id; ++ __le16 product_id; ++ __le16 version_number; ++ u8 unk2; ++ u8 unk3; ++ u8 keyboard_type; ++ u8 serial_length; ++ /* Serial follows, but we grab it with a different report. */ ++} __packed; ++ ++#define FW_MAGIC 0x46444948 ++#define FW_VER 1 ++ ++struct fw_header { ++ __le32 magic; ++ __le32 version; ++ __le32 hdr_length; ++ __le32 data_length; ++ __le32 iface_offset; ++} __packed; ++ ++struct dchid_work { ++ struct work_struct work; ++ struct dchid_iface *iface; ++ ++ struct dchid_hdr hdr; ++ u8 data[]; ++}; ++ ++struct dchid_iface { ++ struct dockchannel_hid *dchid; ++ struct hid_device *hid; ++ ++ int index; ++ const char *name; ++ const struct device_node *of_node; ++ ++ uint8_t tx_seq; ++ uint8_t rx_seq; ++ bool deferred; ++ bool open; ++ ++ void *hid_desc; ++ size_t hid_desc_len; ++ ++ struct gpio_desc *gpio; ++ int gpio_id; ++ ++ struct mutex out_mutex; ++ u32 out_flags; ++ int out_report; ++ u32 retcode; ++ void *resp_buf; ++ size_t resp_size; ++ struct completion out_complete; ++}; ++ ++struct dockchannel_hid { ++ struct device *dev; ++ struct dockchannel *dc; ++ ++ bool id_ready; ++ struct dchid_stm_id device_id; ++ char serial[64]; ++ ++ struct dchid_iface *comm; ++ struct dchid_iface *ifaces[MAX_INTERFACES]; ++ ++ u8 pkt_buf[MAX_PKT_SIZE]; ++ ++ struct workqueue_struct *wq; ++}; ++ ++static struct dchid_iface * ++dchid_get_interface(struct dockchannel_hid *dchid, int index, const char *name) ++{ ++ struct dchid_iface *iface; ++ ++ if (index >= MAX_INTERFACES) { ++ dev_err(dchid->dev, "Interface index %d out of range\n", index); ++ return NULL; ++ } ++ ++ if (dchid->ifaces[index]) ++ return dchid->ifaces[index]; ++ ++ iface = devm_kzalloc(dchid->dev, sizeof(struct dchid_iface), GFP_KERNEL); ++ if (!iface) ++ return NULL; ++ ++ iface->index = index; ++ iface->name = devm_kstrdup(dchid->dev, name, GFP_KERNEL); ++ iface->dchid = dchid; ++ iface->out_report= -1; ++ init_completion(&iface->out_complete); ++ mutex_init(&iface->out_mutex); ++ ++ dev_info(dchid->dev, "Initializing interface %s\n", iface->name); ++ ++ /* Comm is not a HID subdevice */ ++ if (!strcmp(name, "comm")) { ++ dchid->ifaces[index] = iface; ++ return iface; ++ } ++ ++ iface->of_node = of_get_child_by_name(dchid->dev->of_node, name); ++ if (!iface->of_node) { ++ dev_warn(dchid->dev, "No OF node for subdevice %s, ignoring.", name); ++ return NULL; ++ } ++ ++ dchid->ifaces[index] = iface; ++ return iface; ++} ++ ++static u32 dchid_checksum(void *p, size_t length) ++{ ++ u32 sum = 0; ++ ++ while (length >= 4) { ++ sum += get_unaligned_le32(p); ++ p += 4; ++ length -= 4; ++ } ++ ++ WARN_ON_ONCE(length); ++ return sum; ++} ++ ++static int dchid_send(struct dchid_iface *iface, u32 flags, void *msg, size_t size) ++{ ++ u32 checksum = 0xffffffff; ++ size_t wsize = round_down(size, 4); ++ size_t tsize = size - wsize; ++ int ret; ++ struct { ++ struct dchid_hdr hdr; ++ struct dchid_subhdr sub; ++ } __packed h; ++ ++ memset(&h, 0, sizeof(h)); ++ h.hdr.hdr_len = sizeof(h.hdr); ++ h.hdr.channel = DCHID_CHANNEL_CMD; ++ h.hdr.length = round_up(size, 4) + sizeof(h.sub); ++ h.hdr.seq = iface->tx_seq; ++ h.hdr.iface = iface->index; ++ h.sub.flags = flags; ++ h.sub.length = size; ++ ++ ret = dockchannel_send(iface->dchid->dc, &h, sizeof(h)); ++ if (ret < 0) ++ return ret; ++ checksum -= dchid_checksum(&h, sizeof(h)); ++ ++ ret = dockchannel_send(iface->dchid->dc, msg, wsize); ++ if (ret < 0) ++ return ret; ++ checksum -= dchid_checksum(msg, wsize); ++ ++ if (tsize) { ++ u8 tail[4] = {0, 0, 0, 0}; ++ ++ memcpy(tail, msg + wsize, tsize); ++ ret = dockchannel_send(iface->dchid->dc, tail, sizeof(tail)); ++ if (ret < 0) ++ return ret; ++ checksum -= dchid_checksum(tail, sizeof(tail)); ++ } ++ ++ ret = dockchannel_send(iface->dchid->dc, &checksum, sizeof(checksum)); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int dchid_cmd(struct dchid_iface *iface, u32 type, u32 req, ++ void *data, size_t size, void *resp_buf, size_t resp_size) ++{ ++ int ret; ++ int report_id = *(u8*)data; ++ ++ mutex_lock(&iface->out_mutex); ++ ++ WARN_ON(iface->out_report != -1); ++ iface->out_report = report_id; ++ iface->out_flags = FIELD_PREP(FLAGS_GROUP, type) | FIELD_PREP(FLAGS_REQ, req); ++ iface->resp_buf = resp_buf; ++ iface->resp_size = resp_size; ++ reinit_completion(&iface->out_complete); ++ ++ ret = dchid_send(iface, iface->out_flags, data, size); ++ if (ret < 0) ++ goto done; ++ ++ if (!wait_for_completion_timeout(&iface->out_complete, msecs_to_jiffies(1000))) { ++ dev_err(iface->dchid->dev, "output report 0x%x to iface %d (%s) timed out\n", ++ report_id, iface->index, iface->name); ++ ret = -ETIMEDOUT; ++ goto done; ++ } ++ ++ ret = iface->resp_size; ++ if (iface->retcode) { ++ dev_err(iface->dchid->dev, ++ "output report 0x%x to iface %d (%s) failed with err 0x%x\n", ++ report_id, iface->index, iface->name, iface->retcode); ++ ret = -EIO; ++ } ++ ++done: ++ iface->tx_seq++; ++ iface->out_report = -1; ++ iface->out_flags = 0; ++ iface->resp_buf = NULL; ++ iface->resp_size = 0; ++ mutex_unlock(&iface->out_mutex); ++ return ret; ++} ++ ++static int dchid_comm_cmd(struct dockchannel_hid *dchid, void *cmd, size_t size) ++{ ++ return dchid_cmd(dchid->comm, GROUP_CMD, REQ_SET_REPORT, cmd, size, NULL, 0); ++} ++ ++static int dchid_enable_interface(struct dchid_iface *iface) ++{ ++ u8 msg[] = { CMD_ENABLE_INTERFACE, iface->index }; ++ ++ return dchid_comm_cmd(iface->dchid, msg, sizeof(msg)); ++} ++ ++static int dchid_reset_interface(struct dchid_iface *iface, int state) ++{ ++ u8 msg[] = { CMD_RESET_INTERFACE, 1, iface->index, state }; ++ ++ return dchid_comm_cmd(iface->dchid, msg, sizeof(msg)); ++} ++ ++static int dchid_send_firmware(struct dchid_iface *iface, void *firmware, size_t size) ++{ ++ struct { ++ u8 cmd; ++ u8 unk1; ++ u8 unk2; ++ u8 iface; ++ u64 addr; ++ u32 size; ++ } __packed msg = { ++ .cmd = CMD_SEND_FIRMWARE, ++ .unk1 = 2, ++ .unk2 = 0, ++ .iface = iface->index, ++ .size = size, ++ }; ++ dma_addr_t addr; ++ void *buf = dmam_alloc_coherent(iface->dchid->dev, size, &addr, GFP_KERNEL); ++ ++ if (IS_ERR_OR_NULL(buf)) ++ return buf ? PTR_ERR(buf) : -ENOMEM; ++ ++ msg.addr = addr; ++ memcpy(buf, firmware, size); ++ wmb(); ++ ++ return dchid_comm_cmd(iface->dchid, &msg, sizeof(msg)); ++} ++ ++static int dchid_get_firmware(struct dchid_iface *iface, void **firmware, size_t *size) ++{ ++ int ret; ++ const char *fw_name; ++ const struct firmware *fw; ++ struct fw_header *hdr; ++ u8 *fw_data; ++ ++ ret = of_property_read_string(iface->of_node, "firmware-name", &fw_name); ++ if (ret) { ++ /* Firmware is only for some devices */ ++ *firmware = NULL; ++ *size = 0; ++ return 0; ++ } ++ ++ ret = request_firmware(&fw, fw_name, iface->dchid->dev); ++ if (ret) ++ return ret; ++ ++ hdr = (struct fw_header *)fw->data; ++ ++ if (hdr->magic != FW_MAGIC || hdr->version != FW_VER || ++ hdr->hdr_length < sizeof(*hdr) || hdr->hdr_length > fw->size || ++ (hdr->hdr_length + (size_t)hdr->data_length) > fw->size || ++ hdr->iface_offset >= hdr->data_length) { ++ dev_warn(iface->dchid->dev, "%s: invalid firmware header\n", ++ fw_name); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ fw_data = devm_kmemdup(iface->dchid->dev, fw->data + hdr->hdr_length, ++ hdr->data_length, GFP_KERNEL); ++ if (!fw_data) { ++ ret = -ENOMEM; ++ goto done; ++ } ++ ++ if (hdr->iface_offset) ++ fw_data[hdr->iface_offset] = iface->index; ++ ++ *firmware = fw_data; ++ *size = hdr->data_length; ++ ++done: ++ release_firmware(fw); ++ return ret; ++} ++ ++ ++static int dchid_start(struct hid_device *hdev) ++{ ++ return 0; ++}; ++ ++static void dchid_stop(struct hid_device *hdev) ++{ ++ /* no-op, we don't know what the shutdown commands are, if any */ ++} ++ ++static int dchid_open(struct hid_device *hdev) ++{ ++ struct dchid_iface *iface = hdev->driver_data; ++ ++ iface->open = true; ++ return 0; ++} ++ ++static void dchid_close(struct hid_device *hdev) ++{ ++ struct dchid_iface *iface = hdev->driver_data; ++ ++ iface->open = false; ++} ++ ++static int dchid_parse(struct hid_device *hdev) ++{ ++ struct dchid_iface *iface = hdev->driver_data; ++ ++ return hid_parse_report(hdev, iface->hid_desc, iface->hid_desc_len); ++} ++ ++/* Note: buf excludes report number! For ease of fetching strings/etc. */ ++static int dchid_get_report_cmd(struct dchid_iface *iface, u8 reportnum, void *buf, size_t len) ++{ ++ int ret = dchid_cmd(iface, GROUP_CMD, REQ_GET_REPORT, &reportnum, 1, buf, len); ++ ++ return ret <= 0 ? ret : ret - 1; ++} ++ ++/* Note: buf includes report number! */ ++static int dchid_set_report(struct dchid_iface *iface, void *buf, size_t len) ++{ ++ return dchid_cmd(iface, GROUP_OUTPUT, REQ_SET_REPORT, buf, len, NULL, 0); ++} ++ ++static int dchid_raw_request(struct hid_device *hdev, ++ unsigned char reportnum, __u8 *buf, size_t len, ++ unsigned char rtype, int reqtype) ++{ ++ struct dchid_iface *iface = hdev->driver_data; ++ ++ switch (reqtype) { ++ case HID_REQ_GET_REPORT: ++ buf[0] = reportnum; ++ return dchid_cmd(iface, GROUP_OUTPUT, REQ_GET_REPORT, &reportnum, 1, buf + 1, len - 1); ++ case HID_REQ_SET_REPORT: ++ return dchid_set_report(iface, buf, len); ++ default: ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static struct hid_ll_driver dchid_ll = { ++ .start = &dchid_start, ++ .stop = &dchid_stop, ++ .open = &dchid_open, ++ .close = &dchid_close, ++ .parse = &dchid_parse, ++ .raw_request = &dchid_raw_request, ++}; ++ ++static void dchid_init_interface(struct dchid_iface *iface) ++{ ++ void *fw; ++ size_t size; ++ ++ iface->deferred = false; ++ ++ /* Enable interface (general) */ ++ if (dchid_enable_interface(iface) < 0) ++ return; ++ ++ /* Look to see if we need firmware */ ++ if (dchid_get_firmware(iface, &fw, &size) < 0) ++ return; ++ ++ /* Only multi-touch has firmware */ ++ if (!fw || !size) ++ return; ++ ++ /* Send it to the device */ ++ if (dchid_send_firmware(iface, fw, size) < 0) ++ return; ++ ++ /* After loading firmware, multi-touch needs a reset */ ++ dchid_reset_interface(iface, 0); ++ dchid_reset_interface(iface, 2); ++} ++ ++static void dchid_handle_descriptor(struct dchid_iface *iface, void *hid_desc, size_t desc_len) ++{ ++ if (iface->hid) { ++ dev_warn(iface->dchid->dev, "Tried to initialize already started interface %s!\n", ++ iface->name); ++ return; ++ } ++ ++ iface->hid_desc = devm_kmemdup(iface->dchid->dev, hid_desc, desc_len, GFP_KERNEL); ++ if (!iface->hid_desc) ++ return; ++ ++ iface->hid_desc_len = desc_len; ++ ++ /* We need to enable STM first, since it'll give us the device IDs */ ++ if (iface->dchid->id_ready || !strcmp(iface->name, "stm")) ++ dchid_init_interface(iface); ++ else ++ iface->deferred = true; ++} ++ ++static void dchid_handle_ready(struct dockchannel_hid *dchid, void *data, size_t length) ++{ ++ struct hid_device *hid; ++ struct dchid_iface *iface; ++ int ret; ++ u8 *pkt = data; ++ u8 index; ++ int i; ++ ++ if (length < 2) { ++ dev_err(dchid->dev, "Bad length for ready message: %ld\n", length); ++ return; ++ } ++ ++ index = pkt[1]; ++ ++ if (index >= MAX_INTERFACES) { ++ dev_err(dchid->dev, "Got ready notification for bad iface %d\n", index); ++ return; ++ } ++ ++ iface = dchid->ifaces[index]; ++ if (!iface) { ++ dev_err(dchid->dev, "Got ready notification for unknown iface %d\n", index); ++ return; ++ } ++ ++ if (iface->hid) { ++ dev_warn(iface->dchid->dev, "Interface %s already ready!\n", ++ iface->name); ++ return; ++ } ++ ++ /* When STM is ready, grab global device info */ ++ if (!strcmp(iface->name, "stm")) { ++ ret = dchid_get_report_cmd(iface, STM_REPORT_ID, &dchid->device_id, ++ sizeof(dchid->device_id)); ++ if (ret < sizeof(dchid->device_id)) { ++ dev_warn(iface->dchid->dev, "Failed to get device ID from STM!\n"); ++ /* Fake it and keep going. Things might still work... */ ++ memset(&dchid->device_id, 0, sizeof(dchid->device_id)); ++ dchid->device_id.vendor_id = HOST_VENDOR_ID_APPLE; ++ } ++ ret = dchid_get_report_cmd(iface, STM_REPORT_SERIAL, dchid->serial, ++ sizeof(dchid->serial) - 1); ++ if (ret < 0) { ++ dev_warn(iface->dchid->dev, "Failed to get serial from STM!\n"); ++ dchid->serial[0] = 0; ++ } ++ ++ dchid->id_ready = true; ++ for (i = 0; i < MAX_INTERFACES; i++) ++ if (dchid->ifaces[i] && dchid->ifaces[i]->deferred) ++ dchid_init_interface(dchid->ifaces[i]); ++ ++ } ++ ++ hid = hid_allocate_device(); ++ if (IS_ERR(hid)) ++ return; ++ ++ snprintf(hid->name, sizeof(hid->name), "Apple MTP %s", iface->name); ++ snprintf(hid->phys, sizeof(hid->phys), "%s.%d (%s)", ++ dev_name(iface->dchid->dev), iface->index, iface->name); ++ strscpy(hid->uniq, dchid->serial, sizeof(hid->uniq)); ++ ++ hid->ll_driver = &dchid_ll; ++ hid->bus = BUS_HOST; ++ hid->vendor = dchid->device_id.vendor_id; ++ hid->product = dchid->device_id.product_id; ++ hid->version = dchid->device_id.version_number; ++ hid->type = HID_TYPE_OTHER; ++ if (!strcmp(iface->name, "multi-touch")) { ++ hid->type = HID_TYPE_SPI_MOUSE; ++ } else if (!strcmp(iface->name, "keyboard")) { ++ hid->type = HID_TYPE_SPI_KEYBOARD; ++ ++ /* These country codes match what earlier Apple HID keyboards did */ ++ switch (dchid->device_id.keyboard_type) { ++ case KEYBOARD_TYPE_ANSI: ++ hid->country = 33; // US-English ++ break; ++ ++ case KEYBOARD_TYPE_ISO: ++ hid->country = 13; // ISO ++ break; ++ ++ case KEYBOARD_TYPE_JIS: ++ hid->country = 15; // Japan ++ break; ++ } ++ } ++ ++ hid->dev.parent = iface->dchid->dev; ++ hid->driver_data = iface; ++ ++ ret = hid_add_device(hid); ++ if (ret < 0) { ++ hid_destroy_device(hid); ++ dev_warn(iface->dchid->dev, "Failed to register hid device %s", iface->name); ++ return; ++ } ++ ++ iface->hid = hid; ++} ++ ++static void dchid_request_gpio(struct dchid_iface *iface, int id, const char *name) ++{ ++ char prop_name[MAX_GPIO_NAME + 16]; ++ ++ dev_info(iface->dchid->dev, "Requesting GPIO %s#%d: %s\n", iface->name, id, name); ++ ++ if (iface->gpio) { ++ dev_err(iface->dchid->dev, "Cannot request more than one GPIO per interface!\n"); ++ return; ++ } ++ ++ snprintf(prop_name, sizeof(prop_name), "apple,%s-gpios", name); ++ ++ iface->gpio = devm_gpiod_get_from_of_node(iface->dchid->dev, ++ iface->of_node, prop_name, 0, ++ GPIOD_OUT_LOW, name); ++ ++ if (IS_ERR_OR_NULL(iface->gpio)) { ++ dev_err(iface->dchid->dev, "Failed to request GPIO %s\n", prop_name); ++ iface->gpio = NULL; ++ return; ++ } ++ ++ iface->gpio_id = id; ++} ++ ++static void dchid_handle_init(struct dockchannel_hid *dchid, void *data, size_t length) ++{ ++ struct dchid_init_hdr *hdr = data; ++ struct dchid_iface *iface; ++ struct dchid_init_block_hdr *blk; ++ ++ if (length < sizeof(*hdr)) ++ return; ++ ++ iface = dchid_get_interface(dchid, hdr->iface, hdr->name); ++ if (!iface) ++ return; ++ ++ data += sizeof(*hdr); ++ length -= sizeof(*hdr); ++ ++ while (length > sizeof(*blk)) { ++ blk = data; ++ data += sizeof(*blk); ++ length -= sizeof(*blk); ++ ++ if (blk->length > length) ++ return; ++ switch (blk->type) { ++ case INIT_HID_DESCRIPTOR: ++ dchid_handle_descriptor(iface, data, blk->length); ++ break; ++ ++ case INIT_GPIO_REQUEST: { ++ struct dchid_gpio_request *req = data; ++ ++ if (sizeof(*req) > length) ++ return; ++ dchid_request_gpio(iface, req->id, req->name); ++ break; ++ } ++ ++ case INIT_TERMINATOR: ++ return; ++ } ++ ++ data += blk->length + sizeof(*blk); ++ length -= blk->length + sizeof(*blk); ++ } ++} ++ ++static void dchid_handle_gpio(struct dockchannel_hid *dchid, void *data, size_t length) ++{ ++ struct dchid_gpio_cmd *cmd = data; ++ struct dchid_iface *iface; ++ u32 retcode = 0xe000f00d; /* Give it a random Apple-style error code */ ++ struct dchid_gpio_ack *ack; ++ ++ if (length < sizeof(*cmd)) ++ return; ++ ++ if (cmd->iface >= MAX_INTERFACES || !(iface = dchid->ifaces[cmd->iface])) { ++ dev_err(dchid->dev, "Got GPIO command for bad inteface %d\n", cmd->iface); ++ goto err; ++ } ++ ++ if (!iface->gpio || cmd->gpio != iface->gpio_id) { ++ dev_err(dchid->dev, "Got GPIO command for bad GPIO %s#%d\n", ++ iface->name, cmd->gpio); ++ goto err; ++ } ++ ++ dev_info(dchid->dev, "GPIO command: %s#%d: %d\n", iface->name, cmd->gpio, cmd->cmd); ++ ++ switch (cmd->cmd) { ++ case 3: ++ /* Pulse. */ ++ gpiod_set_value_cansleep(iface->gpio, 1); ++ msleep(10); /* Random guess... */ ++ gpiod_set_value_cansleep(iface->gpio, 0); ++ retcode = 0; ++ break; ++ default: ++ dev_err(dchid->dev, "Unknown GPIO command %d\n", cmd->cmd ); ++ break; ++ } ++ ++err: ++ /* Ack it */ ++ ack = kzalloc(sizeof(*ack) + length, GFP_KERNEL); ++ if (!ack) ++ return; ++ ++ ack->type = CMD_ACK_GPIO_CMD; ++ ack->retcode = retcode; ++ memcpy(ack->cmd, data, length); ++ ++ if (dchid_comm_cmd(dchid, ack, sizeof(*ack) + length) < 0) ++ dev_err(dchid->dev, "Failed to ACK GPIO command\n"); ++ ++ kfree(ack); ++} ++ ++static void dchid_handle_event(struct dockchannel_hid *dchid, void *data, size_t length) ++{ ++ u8 *p = data; ++ switch (*p) { ++ case EVENT_INIT: ++ dchid_handle_init(dchid, data, length); ++ break; ++ case EVENT_READY: ++ dchid_handle_ready(dchid, data, length); ++ break; ++ case EVENT_GPIO_CMD: ++ dchid_handle_gpio(dchid, data, length); ++ break; ++ } ++} ++ ++static void dchid_handle_report(struct dchid_iface *iface, void *data, size_t length) ++{ ++ struct dockchannel_hid *dchid = iface->dchid; ++ ++ if (!iface->hid) { ++ dev_warn(dchid->dev, "Report received but %s is not initialized!\n", iface->name); ++ return; ++ } ++ ++ if (!iface->open) ++ return; ++ ++ hid_input_report(iface->hid, HID_INPUT_REPORT, data, length, 1); ++} ++ ++static void dchid_packet_work(struct work_struct *ws) ++{ ++ struct dchid_work *work = container_of(ws, struct dchid_work, work); ++ struct dchid_subhdr *shdr = (void *)work->data; ++ struct dockchannel_hid *dchid = work->iface->dchid; ++ int type = FIELD_GET(FLAGS_GROUP, shdr->flags); ++ u8 *payload = work->data + sizeof(*shdr); ++ ++ if (shdr->length + sizeof(*shdr) > work->hdr.length) { ++ dev_err(dchid->dev, "Bad sub header length (%d > %ld)\n", ++ shdr->length, work->hdr.length - sizeof(*shdr)); ++ return; ++ } ++ ++ switch (type) { ++ case GROUP_INPUT: ++ if (work->hdr.iface == IFACE_COMM) ++ dchid_handle_event(dchid, payload, shdr->length); ++ else ++ dchid_handle_report(work->iface, payload, shdr->length); ++ break; ++ default: ++ dev_err(dchid->dev, "Received unknown packet type %d\n", type); ++ break; ++ } ++ ++ kfree(work); ++} ++ ++static void dchid_handle_ack(struct dchid_iface *iface, struct dchid_hdr *hdr, void *data) ++{ ++ struct dchid_subhdr *shdr = (void *)data; ++ u8 *payload = data + sizeof(*shdr); ++ ++ if (shdr->length + sizeof(*shdr) > hdr->length) { ++ dev_err(iface->dchid->dev, "Bad sub header length (%d > %ld)\n", ++ shdr->length, hdr->length - sizeof(*shdr)); ++ return; ++ } ++ if (shdr->flags != iface->out_flags) { ++ dev_err(iface->dchid->dev, ++ "Received unexpected flags 0x%x on ACK channel (expected 0x%x)\n", ++ shdr->flags, iface->out_flags); ++ return; ++ } ++ ++ if (shdr->length < 1) { ++ dev_err(iface->dchid->dev, "Received length 0 output report ack\n"); ++ return; ++ } ++ if (iface->tx_seq != hdr->seq) { ++ dev_err(iface->dchid->dev, "Received ACK with bad seq (expected %d, got %d)\n", ++ iface->rx_seq, hdr->seq); ++ return; ++ } ++ if (iface->out_report != payload[0]) { ++ dev_err(iface->dchid->dev, "Received ACK with bad report (expected %d, got %d\n", ++ iface->out_report, payload[0]); ++ return; ++ } ++ ++ if (iface->resp_buf && iface->resp_size) ++ memcpy(iface->resp_buf, payload + 1, min((size_t)shdr->length - 1, iface->resp_size)); ++ ++ iface->resp_size = shdr->length; ++ iface->out_report = -1; ++ iface->retcode = shdr->retcode; ++ complete(&iface->out_complete); ++} ++ ++static void dchid_handle_packet(void *cookie, size_t avail) ++{ ++ struct dockchannel_hid *dchid = cookie; ++ struct dchid_hdr hdr; ++ struct dchid_work *work; ++ struct dchid_iface *iface; ++ u32 checksum; ++ ++ if (dockchannel_recv(dchid->dc, &hdr, sizeof(hdr)) != sizeof(hdr)) { ++ dev_err(dchid->dev, "Read failed (header)\n"); ++ return; ++ } ++ ++ if (hdr.hdr_len != sizeof(hdr)) { ++ dev_err(dchid->dev, "Bad header length %d\n", hdr.hdr_len); ++ goto done; ++ } ++ ++ if (dockchannel_recv(dchid->dc, dchid->pkt_buf, hdr.length + 4) != (hdr.length + 4)) { ++ dev_err(dchid->dev, "Read failed (body)\n"); ++ goto done; ++ } ++ ++ checksum = dchid_checksum(&hdr, sizeof(hdr)); ++ checksum += dchid_checksum(dchid->pkt_buf, hdr.length + 4); ++ ++ if (checksum != 0xffffffff) { ++ dev_err(dchid->dev, "Checksum mismatch (iface %d): 0x%08x != 0xffffffff\n", ++ hdr.iface, checksum); ++ goto done; ++ } ++ ++ ++ if (hdr.iface >= MAX_INTERFACES) { ++ dev_err(dchid->dev, "Bad iface %d\n", hdr.iface); ++ } ++ ++ iface = dchid->ifaces[hdr.iface]; ++ ++ if (!iface) { ++ dev_err(dchid->dev, "Received packet for uninitialized iface %d\n", hdr.iface); ++ goto done; ++ } ++ ++ switch (hdr.channel) { ++ case DCHID_CHANNEL_CMD: ++ dchid_handle_ack(iface, &hdr, dchid->pkt_buf); ++ goto done; ++ case DCHID_CHANNEL_REPORT: ++ break; ++ default: ++ dev_warn(dchid->dev, "Unknown channel 0x%x, treating as report...\n", ++ hdr.channel); ++ break; ++ } ++ ++ if (hdr.seq != iface->rx_seq) { ++ dev_err(dchid->dev, "Received packet out of sequence (expected %d, got %d)\n", ++ iface->rx_seq, hdr.seq); ++ goto done; ++ } ++ ++ iface->rx_seq++; ++ ++ work = kzalloc(sizeof(*work) + hdr.length, GFP_KERNEL); ++ if (!work) ++ return; ++ ++ work->hdr = hdr; ++ work->iface = iface; ++ memcpy(work->data, dchid->pkt_buf, hdr.length); ++ INIT_WORK(&work->work, dchid_packet_work); ++ ++ queue_work(dchid->wq, &work->work); ++ ++done: ++ dockchannel_await(dchid->dc, dchid_handle_packet, dchid, sizeof(struct dchid_hdr)); ++} ++ ++static int dockchannel_hid_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct dockchannel_hid *dchid; ++ struct device_node *child; ++ struct property *prop; ++ bool defer = false; ++ ++ /* ++ * First make sure all the GPIOs are available, in cased we need to defer. ++ * This is necessary because MTP will request them by name later, and by then ++ * it's too late to defer the probe. ++ */ ++ ++ for_each_child_of_node(dev->of_node, child) { ++ for_each_property_of_node(child, prop) { ++ size_t len = strlen(prop->name); ++ struct gpio_desc *gpio; ++ ++ if (len < 12 || strncmp("apple,", prop->name, 6) || ++ strcmp("-gpios", prop->name + len - 6)) ++ continue; ++ ++ gpio = gpiod_get_from_of_node(child, prop->name, 0, GPIOD_ASIS, ++ prop->name); ++ if (IS_ERR_OR_NULL(gpio)) { ++ if (PTR_ERR(gpio) == EPROBE_DEFER) { ++ defer = true; ++ of_node_put(child); ++ return -EPROBE_DEFER; ++ } ++ } else { ++ gpiod_put(gpio); ++ } ++ } ++ } ++ ++ dchid = devm_kzalloc(dev, sizeof(*dchid), GFP_KERNEL); ++ if (!dchid) ++ return -ENOMEM; ++ ++ ++ dchid->dev = &pdev->dev; ++ dchid->dc = dockchannel_init(pdev); ++ if (IS_ERR_OR_NULL(dchid->dc)) { ++ return -PTR_ERR(dchid->dc); ++ } ++ ++ dchid->comm = dchid_get_interface(dchid, IFACE_COMM, "comm"); ++ if (!dchid->comm) { ++ dev_err(dchid->dev, "Failed to initialize comm interface"); ++ return -EIO; ++ } ++ ++ dchid->wq = alloc_ordered_workqueue("dockchannel-hid-report", WQ_MEM_RECLAIM); ++ if (!dchid->wq) ++ return -ENOMEM; ++ ++ dev_info(dchid->dev, "initialized, awaiting packets\n"); ++ dockchannel_await(dchid->dc, dchid_handle_packet, dchid, sizeof(struct dchid_hdr)); ++ ++ return 0; ++} ++ ++static int dockchannel_hid_remove(struct platform_device *pdev) ++{ ++ BUG_ON(1); ++ return 0; ++} ++ ++static const struct of_device_id dockchannel_hid_of_match[] = { ++ { .compatible = "apple,dockchannel-hid" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dockchannel_hid_of_match); ++MODULE_FIRMWARE("apple/tpmtfw-*.bin"); ++ ++static struct platform_driver dockchannel_hid_driver = { ++ .driver = { ++ .name = "dockchannel-hid", ++ .of_match_table = dockchannel_hid_of_match, ++ }, ++ .probe = dockchannel_hid_probe, ++ .remove = dockchannel_hid_remove, ++}; ++module_platform_driver(dockchannel_hid_driver); ++ ++MODULE_DESCRIPTION("Apple DockChannel HID transport driver"); ++MODULE_AUTHOR("Hector Martin "); ++MODULE_LICENSE("Dual MIT/GPL"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0131-soc-apple-Add-RTKit-helper-driver.patch b/target/linux/silicon/patches-5.19/0131-soc-apple-Add-RTKit-helper-driver.patch new file mode 100644 index 000000000..9a718f001 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0131-soc-apple-Add-RTKit-helper-driver.patch @@ -0,0 +1,211 @@ +From 19e6fb36a68b5afbe7a603fda647fcd2214e191c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 3 Jul 2022 23:33:37 +0900 +Subject: [PATCH 131/171] soc: apple: Add RTKit helper driver + +This driver can be used for coprocessors that do some background task or +communicate out-of-band, and do not do any mailbox I/O beyond the +standard RTKit initialization. + +Signed-off-by: Hector Martin +--- + drivers/soc/apple/Kconfig | 14 +++ + drivers/soc/apple/Makefile | 3 + + drivers/soc/apple/rtkit-helper.c | 146 +++++++++++++++++++++++++++++++ + 3 files changed, 163 insertions(+) + create mode 100644 drivers/soc/apple/rtkit-helper.c + +diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig +index 9e93df0ac825..694a44968f76 100644 +--- a/drivers/soc/apple/Kconfig ++++ b/drivers/soc/apple/Kconfig +@@ -30,6 +30,20 @@ config APPLE_RTKIT + + Say 'y' here if you have an Apple SoC. + ++config APPLE_RTKIT_HELPER ++ tristate "Apple Generic RTKit helper co-processor" ++ depends on APPLE_RTKIT ++ depends on ARCH_APPLE || COMPILE_TEST ++ default ARCH_APPLE ++ help ++ Apple SoCs such as the M1 come with various co-processors running ++ their proprietary RTKit operating system. This option enables support ++ for a generic co-processor that does not implement any additional ++ in-band communications. It can be used for testing purposes, or for ++ coprocessors such as MTP that communicate over a different interface. ++ ++ Say 'y' here if you have an Apple SoC. ++ + config APPLE_SART + tristate "Apple SART DMA address filter" + depends on ARCH_APPLE || COMPILE_TEST +diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile +index aa4203e02462..07a95a883d3d 100644 +--- a/drivers/soc/apple/Makefile ++++ b/drivers/soc/apple/Makefile +@@ -4,6 +4,9 @@ obj-$(CONFIG_APPLE_PMGR_PWRSTATE) += apple-pmgr-pwrstate.o + obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o + apple-rtkit-y = rtkit.o rtkit-crashlog.o + ++obj-$(CONFIG_APPLE_RTKIT_HELPER) += apple-rtkit-helper.o ++apple-rtkit-helper-y = rtkit-helper.o ++ + obj-$(CONFIG_APPLE_SART) += apple-sart.o + apple-sart-y = sart.o + +diff --git a/drivers/soc/apple/rtkit-helper.c b/drivers/soc/apple/rtkit-helper.c +new file mode 100644 +index 000000000000..01c7f30e41e6 +--- /dev/null ++++ b/drivers/soc/apple/rtkit-helper.c +@@ -0,0 +1,146 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple Generic RTKit helper coprocessor ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define APPLE_ASC_CPU_CONTROL 0x44 ++#define APPLE_ASC_CPU_CONTROL_RUN BIT(4) ++ ++struct apple_rtkit_helper { ++ struct device *dev; ++ struct apple_rtkit *rtk; ++ ++ void __iomem *asc_base; ++ ++ struct resource *sram; ++ void __iomem *sram_base; ++}; ++ ++static int apple_rtkit_helper_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr) ++{ ++ struct apple_rtkit_helper *helper = cookie; ++ struct resource res = { ++ .start = bfr->iova, ++ .end = bfr->iova + bfr->size - 1, ++ .name = "rtkit_map", ++ .flags = helper->sram->flags, ++ }; ++ ++ if (!bfr->iova) { ++ bfr->buffer = dma_alloc_coherent(helper->dev, bfr->size, ++ &bfr->iova, GFP_KERNEL); ++ if (!bfr->buffer) ++ return -ENOMEM; ++ return 0; ++ } ++ ++ if (!helper->sram) { ++ dev_err(helper->dev, ++ "RTKit buffer request with no SRAM region: %pR", &res); ++ return -EFAULT; ++ } ++ ++ if (res.end < res.start || !resource_contains(helper->sram, &res)) { ++ dev_err(helper->dev, ++ "RTKit buffer request outside SRAM region: %pR", &res); ++ return -EFAULT; ++ } ++ ++ bfr->iomem = helper->sram_base + (res.start - helper->sram->start); ++ bfr->is_mapped = true; ++ ++ return 0; ++} ++ ++static void apple_rtkit_helper_shmem_destroy(void *cookie, struct apple_rtkit_shmem *bfr) ++{ ++ // no-op ++} ++ ++static const struct apple_rtkit_ops apple_rtkit_helper_ops = { ++ .shmem_setup = apple_rtkit_helper_shmem_setup, ++ .shmem_destroy = apple_rtkit_helper_shmem_destroy, ++}; ++ ++static int apple_rtkit_helper_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct apple_rtkit_helper *helper; ++ int ret; ++ ++ helper = devm_kzalloc(dev, sizeof(*helper), GFP_KERNEL); ++ if (!helper) ++ return -ENOMEM; ++ ++ helper->dev = dev; ++ platform_set_drvdata(pdev, helper); ++ ++ helper->asc_base = devm_platform_ioremap_resource_byname(pdev, "asc"); ++ if (IS_ERR(helper->asc_base)) ++ return PTR_ERR(helper->asc_base); ++ ++ helper->sram = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); ++ if (helper->sram) { ++ helper->sram_base = devm_ioremap_resource(dev, helper->sram); ++ if (IS_ERR(helper->sram_base)) ++ return dev_err_probe(dev, PTR_ERR(helper->sram_base), ++ "Failed to map SRAM region"); ++ } ++ ++ helper->rtk = ++ devm_apple_rtkit_init(dev, helper, NULL, 0, &apple_rtkit_helper_ops); ++ if (IS_ERR(helper->rtk)) ++ return dev_err_probe(dev, PTR_ERR(helper->rtk), ++ "Failed to intialize RTKit"); ++ ++ writel_relaxed(APPLE_ASC_CPU_CONTROL_RUN, ++ helper->asc_base + APPLE_ASC_CPU_CONTROL); ++ ++ /* Works for both wake and boot */ ++ ret = apple_rtkit_wake(helper->rtk); ++ if (ret != 0) ++ return dev_err_probe(dev, ret, "Failed to wake up coprocessor"); ++ ++ return 0; ++} ++ ++static int apple_rtkit_helper_remove(struct platform_device *pdev) ++{ ++ struct apple_rtkit_helper *helper = platform_get_drvdata(pdev); ++ ++ if (apple_rtkit_is_running(helper->rtk)) ++ apple_rtkit_quiesce(helper->rtk); ++ ++ writel_relaxed(0, helper->asc_base + APPLE_ASC_CPU_CONTROL); ++ ++ return 0; ++} ++ ++static const struct of_device_id apple_rtkit_helper_of_match[] = { ++ { .compatible = "apple,rtk-helper-asc4" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, apple_rtkit_helper_of_match); ++ ++static struct platform_driver apple_rtkit_helper_driver = { ++ .driver = { ++ .name = "rtkit-helper", ++ .of_match_table = apple_rtkit_helper_of_match, ++ }, ++ .probe = apple_rtkit_helper_probe, ++ .remove = apple_rtkit_helper_remove, ++}; ++module_platform_driver(apple_rtkit_helper_driver); ++ ++MODULE_AUTHOR("Hector Martin "); ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple RTKit helper driver"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0132-dockchannel-hid-Drop-incoming-packet-sequence-requir.patch b/target/linux/silicon/patches-5.19/0132-dockchannel-hid-Drop-incoming-packet-sequence-requir.patch new file mode 100644 index 000000000..011066faf --- /dev/null +++ b/target/linux/silicon/patches-5.19/0132-dockchannel-hid-Drop-incoming-packet-sequence-requir.patch @@ -0,0 +1,62 @@ +From 91667ca639d453c52047193fddc1c23b44dae6fc Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 17 Jul 2022 18:38:54 +0900 +Subject: [PATCH 132/171] dockchannel-hid: Drop incoming packet sequence + requirements + +Looks like this isn't reliable (suspected race condition in MTP +firmware...) + +Signed-off-by: Hector Martin +--- + drivers/hid/dockchannel-hid/dockchannel-hid.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/drivers/hid/dockchannel-hid/dockchannel-hid.c b/drivers/hid/dockchannel-hid/dockchannel-hid.c +index aaa7d357c6fa..07ac3a77c390 100644 +--- a/drivers/hid/dockchannel-hid/dockchannel-hid.c ++++ b/drivers/hid/dockchannel-hid/dockchannel-hid.c +@@ -152,7 +152,6 @@ struct dchid_iface { + const struct device_node *of_node; + + uint8_t tx_seq; +- uint8_t rx_seq; + bool deferred; + bool open; + +@@ -858,7 +857,7 @@ static void dchid_handle_ack(struct dchid_iface *iface, struct dchid_hdr *hdr, v + } + if (shdr->flags != iface->out_flags) { + dev_err(iface->dchid->dev, +- "Received unexpected flags 0x%x on ACK channel (expected 0x%x)\n", ++ "Received unexpected flags 0x%x on ACK channel (expFected 0x%x)\n", + shdr->flags, iface->out_flags); + return; + } +@@ -869,7 +868,7 @@ static void dchid_handle_ack(struct dchid_iface *iface, struct dchid_hdr *hdr, v + } + if (iface->tx_seq != hdr->seq) { + dev_err(iface->dchid->dev, "Received ACK with bad seq (expected %d, got %d)\n", +- iface->rx_seq, hdr->seq); ++ iface->tx_seq, hdr->seq); + return; + } + if (iface->out_report != payload[0]) { +@@ -943,14 +942,6 @@ static void dchid_handle_packet(void *cookie, size_t avail) + break; + } + +- if (hdr.seq != iface->rx_seq) { +- dev_err(dchid->dev, "Received packet out of sequence (expected %d, got %d)\n", +- iface->rx_seq, hdr.seq); +- goto done; +- } +- +- iface->rx_seq++; +- + work = kzalloc(sizeof(*work) + hdr.length, GFP_KERNEL); + if (!work) + return; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0133-dockchanel-hid-Send-interface-firmware-lazily.patch b/target/linux/silicon/patches-5.19/0133-dockchanel-hid-Send-interface-firmware-lazily.patch new file mode 100644 index 000000000..8ea3f854e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0133-dockchanel-hid-Send-interface-firmware-lazily.patch @@ -0,0 +1,393 @@ +From e478ad5114c801719d37cac1a2d53941ed124936 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 17 Jul 2022 20:47:37 +0900 +Subject: [PATCH 133/171] dockchanel-hid: Send interface firmware lazily + +Wait until the HID device is opened to send the multitouch firmware. +This avoids having to put it in the initramfs to get basic keyboard +functionality there. + +Signed-off-by: Hector Martin +--- + drivers/hid/dockchannel-hid/dockchannel-hid.c | 246 +++++++++++------- + 1 file changed, 157 insertions(+), 89 deletions(-) + +diff --git a/drivers/hid/dockchannel-hid/dockchannel-hid.c b/drivers/hid/dockchannel-hid/dockchannel-hid.c +index 07ac3a77c390..aeaeb60edf39 100644 +--- a/drivers/hid/dockchannel-hid/dockchannel-hid.c ++++ b/drivers/hid/dockchannel-hid/dockchannel-hid.c +@@ -17,7 +17,8 @@ + #include + #include "../hid-ids.h" + +-#define COMMAND_TIMEOUT 1000 ++#define COMMAND_TIMEOUT_MS 1000 ++#define START_TIMEOUT_MS 2000 + + #define MAX_INTERFACES 16 + +@@ -146,6 +147,10 @@ struct dchid_work { + struct dchid_iface { + struct dockchannel_hid *dchid; + struct hid_device *hid; ++ struct workqueue_struct *wq; ++ ++ bool creating; ++ struct work_struct create_work; + + int index; + const char *name; +@@ -153,7 +158,9 @@ struct dchid_iface { + + uint8_t tx_seq; + bool deferred; ++ bool starting; + bool open; ++ struct completion ready; + + void *hid_desc; + size_t hid_desc_len; +@@ -183,7 +190,8 @@ struct dockchannel_hid { + + u8 pkt_buf[MAX_PKT_SIZE]; + +- struct workqueue_struct *wq; ++ /* Workqueue to asynchronously create HID devices */ ++ struct workqueue_struct *new_iface_wq; + }; + + static struct dchid_iface * +@@ -208,9 +216,11 @@ dchid_get_interface(struct dockchannel_hid *dchid, int index, const char *name) + iface->dchid = dchid; + iface->out_report= -1; + init_completion(&iface->out_complete); ++ init_completion(&iface->ready); + mutex_init(&iface->out_mutex); +- +- dev_info(dchid->dev, "Initializing interface %s\n", iface->name); ++ iface->wq = alloc_ordered_workqueue("dchid-%s", WQ_MEM_RECLAIM, iface->name); ++ if (!iface->wq) ++ return NULL; + + /* Comm is not a HID subdevice */ + if (!strcmp(name, "comm")) { +@@ -308,7 +318,7 @@ static int dchid_cmd(struct dchid_iface *iface, u32 type, u32 req, + if (ret < 0) + goto done; + +- if (!wait_for_completion_timeout(&iface->out_complete, msecs_to_jiffies(1000))) { ++ if (!wait_for_completion_timeout(&iface->out_complete, msecs_to_jiffies(COMMAND_TIMEOUT_MS))) { + dev_err(iface->dchid->dev, "output report 0x%x to iface %d (%s) timed out\n", + report_id, iface->index, iface->name); + ret = -ETIMEDOUT; +@@ -431,6 +441,49 @@ static int dchid_get_firmware(struct dchid_iface *iface, void **firmware, size_t + return ret; + } + ++static int dchid_start_interface(struct dchid_iface *iface) ++{ ++ void *fw; ++ size_t size; ++ int ret; ++ ++ if (iface->starting) { ++ dev_warn(iface->dchid->dev, "Interface %s is already starting", iface->name); ++ return -EINPROGRESS; ++ } ++ ++ dev_info(iface->dchid->dev, "Starting interface %s\n", iface->name); ++ ++ iface->starting = true; ++ ++ /* Look to see if we need firmware */ ++ ret = dchid_get_firmware(iface, &fw, &size); ++ if (ret < 0) ++ goto err; ++ ++ /* Only multi-touch has firmware */ ++ if (fw && size) { ++ ++ /* Send firmware to the device */ ++ dev_info(iface->dchid->dev, "Sending firmware for %s\n", iface->name); ++ ret = dchid_send_firmware(iface, fw, size); ++ if (ret < 0) { ++ dev_err(iface->dchid->dev, "Failed to send %s firmwareS", iface->name); ++ goto err; ++ } ++ ++ /* After loading firmware, multi-touch needs a reset */ ++ dev_info(iface->dchid->dev, "Resetting %s\n", iface->name); ++ dchid_reset_interface(iface, 0); ++ dchid_reset_interface(iface, 2); ++ } ++ ++ return 0; ++ ++err: ++ iface->starting = false; ++ return ret; ++} + + static int dchid_start(struct hid_device *hdev) + { +@@ -445,6 +498,18 @@ static void dchid_stop(struct hid_device *hdev) + static int dchid_open(struct hid_device *hdev) + { + struct dchid_iface *iface = hdev->driver_data; ++ int ret; ++ ++ if (!completion_done(&iface->ready)) { ++ ret = dchid_start_interface(iface); ++ if (ret < 0) ++ return ret; ++ ++ if (!wait_for_completion_timeout(&iface->ready, msecs_to_jiffies(START_TIMEOUT_MS))) { ++ dev_err(iface->dchid->dev, "iface %s start timed out\n", iface->name); ++ return -ETIMEDOUT; ++ } ++ } + + iface->open = true; + return 0; +@@ -506,32 +571,87 @@ static struct hid_ll_driver dchid_ll = { + .raw_request = &dchid_raw_request, + }; + +-static void dchid_init_interface(struct dchid_iface *iface) ++static void dchid_create_interface_work(struct work_struct *ws) + { +- void *fw; +- size_t size; +- +- iface->deferred = false; ++ struct dchid_iface *iface = container_of(ws, struct dchid_iface, create_work); ++ struct dockchannel_hid *dchid = iface->dchid; ++ struct hid_device *hid; ++ int ret; + +- /* Enable interface (general) */ +- if (dchid_enable_interface(iface) < 0) ++ if (iface->hid) { ++ dev_warn(dchid->dev, "Interface %s already created!\n", ++ iface->name); + return; ++ } + +- /* Look to see if we need firmware */ +- if (dchid_get_firmware(iface, &fw, &size) < 0) +- return; ++ dev_info(dchid->dev, "New interface %s\n", iface->name); + +- /* Only multi-touch has firmware */ +- if (!fw || !size) ++ /* Start the interface. This is not the entire init process, as firmware is loaded later on device open. */ ++ ret = dchid_enable_interface(iface); ++ if (ret < 0) { ++ dev_warn(dchid->dev, "Failed to enable %s: %d\n", iface->name, ret); + return; ++ } + +- /* Send it to the device */ +- if (dchid_send_firmware(iface, fw, size) < 0) ++ iface->deferred = false; ++ ++ hid = hid_allocate_device(); ++ if (IS_ERR(hid)) + return; + +- /* After loading firmware, multi-touch needs a reset */ +- dchid_reset_interface(iface, 0); +- dchid_reset_interface(iface, 2); ++ snprintf(hid->name, sizeof(hid->name), "Apple MTP %s", iface->name); ++ snprintf(hid->phys, sizeof(hid->phys), "%s.%d (%s)", ++ dev_name(dchid->dev), iface->index, iface->name); ++ strscpy(hid->uniq, dchid->serial, sizeof(hid->uniq)); ++ ++ hid->ll_driver = &dchid_ll; ++ hid->bus = BUS_HOST; ++ hid->vendor = dchid->device_id.vendor_id; ++ hid->product = dchid->device_id.product_id; ++ hid->version = dchid->device_id.version_number; ++ hid->type = HID_TYPE_OTHER; ++ if (!strcmp(iface->name, "multi-touch")) { ++ hid->type = HID_TYPE_SPI_MOUSE; ++ } else if (!strcmp(iface->name, "keyboard")) { ++ hid->type = HID_TYPE_SPI_KEYBOARD; ++ ++ /* These country codes match what earlier Apple HID keyboards did */ ++ switch (dchid->device_id.keyboard_type) { ++ case KEYBOARD_TYPE_ANSI: ++ hid->country = 33; // US-English ++ break; ++ ++ case KEYBOARD_TYPE_ISO: ++ hid->country = 13; // ISO ++ break; ++ ++ case KEYBOARD_TYPE_JIS: ++ hid->country = 15; // Japan ++ break; ++ } ++ } ++ ++ hid->dev.parent = iface->dchid->dev; ++ hid->driver_data = iface; ++ ++ iface->hid = hid; ++ ++ ret = hid_add_device(hid); ++ if (ret < 0) { ++ iface->hid = NULL; ++ hid_destroy_device(hid); ++ dev_warn(iface->dchid->dev, "Failed to register hid device %s", iface->name); ++ } ++} ++ ++static int dchid_create_interface(struct dchid_iface *iface) ++{ ++ if (iface->creating) ++ return -EBUSY; ++ ++ iface->creating = true; ++ INIT_WORK(&iface->create_work, dchid_create_interface_work); ++ return queue_work(iface->dchid->new_iface_wq, &iface->create_work); + } + + static void dchid_handle_descriptor(struct dchid_iface *iface, void *hid_desc, size_t desc_len) +@@ -549,20 +669,19 @@ static void dchid_handle_descriptor(struct dchid_iface *iface, void *hid_desc, s + iface->hid_desc_len = desc_len; + + /* We need to enable STM first, since it'll give us the device IDs */ +- if (iface->dchid->id_ready || !strcmp(iface->name, "stm")) +- dchid_init_interface(iface); +- else ++ if (iface->dchid->id_ready || !strcmp(iface->name, "stm")) { ++ dchid_create_interface(iface); ++ } else { + iface->deferred = true; ++ } + } + + static void dchid_handle_ready(struct dockchannel_hid *dchid, void *data, size_t length) + { +- struct hid_device *hid; + struct dchid_iface *iface; +- int ret; + u8 *pkt = data; + u8 index; +- int i; ++ int i, ret; + + if (length < 2) { + dev_err(dchid->dev, "Bad length for ready message: %ld\n", length); +@@ -582,11 +701,8 @@ static void dchid_handle_ready(struct dockchannel_hid *dchid, void *data, size_t + return; + } + +- if (iface->hid) { +- dev_warn(iface->dchid->dev, "Interface %s already ready!\n", +- iface->name); +- return; +- } ++ dev_info(dchid->dev, "Inteface %s is now ready\n", iface->name); ++ complete_all(&iface->ready); + + /* When STM is ready, grab global device info */ + if (!strcmp(iface->name, "stm")) { +@@ -606,59 +722,12 @@ static void dchid_handle_ready(struct dockchannel_hid *dchid, void *data, size_t + } + + dchid->id_ready = true; +- for (i = 0; i < MAX_INTERFACES; i++) +- if (dchid->ifaces[i] && dchid->ifaces[i]->deferred) +- dchid_init_interface(dchid->ifaces[i]); +- +- } +- +- hid = hid_allocate_device(); +- if (IS_ERR(hid)) +- return; +- +- snprintf(hid->name, sizeof(hid->name), "Apple MTP %s", iface->name); +- snprintf(hid->phys, sizeof(hid->phys), "%s.%d (%s)", +- dev_name(iface->dchid->dev), iface->index, iface->name); +- strscpy(hid->uniq, dchid->serial, sizeof(hid->uniq)); +- +- hid->ll_driver = &dchid_ll; +- hid->bus = BUS_HOST; +- hid->vendor = dchid->device_id.vendor_id; +- hid->product = dchid->device_id.product_id; +- hid->version = dchid->device_id.version_number; +- hid->type = HID_TYPE_OTHER; +- if (!strcmp(iface->name, "multi-touch")) { +- hid->type = HID_TYPE_SPI_MOUSE; +- } else if (!strcmp(iface->name, "keyboard")) { +- hid->type = HID_TYPE_SPI_KEYBOARD; +- +- /* These country codes match what earlier Apple HID keyboards did */ +- switch (dchid->device_id.keyboard_type) { +- case KEYBOARD_TYPE_ANSI: +- hid->country = 33; // US-English +- break; +- +- case KEYBOARD_TYPE_ISO: +- hid->country = 13; // ISO +- break; +- +- case KEYBOARD_TYPE_JIS: +- hid->country = 15; // Japan +- break; ++ for (i = 0; i < MAX_INTERFACES; i++) { ++ if (!dchid->ifaces[i] || !dchid->ifaces[i]->deferred) ++ continue; ++ dchid_create_interface(dchid->ifaces[i]); + } + } +- +- hid->dev.parent = iface->dchid->dev; +- hid->driver_data = iface; +- +- ret = hid_add_device(hid); +- if (ret < 0) { +- hid_destroy_device(hid); +- dev_warn(iface->dchid->dev, "Failed to register hid device %s", iface->name); +- return; +- } +- +- iface->hid = hid; + } + + static void dchid_request_gpio(struct dchid_iface *iface, int id, const char *name) +@@ -951,7 +1020,7 @@ static void dchid_handle_packet(void *cookie, size_t avail) + memcpy(work->data, dchid->pkt_buf, hdr.length); + INIT_WORK(&work->work, dchid_packet_work); + +- queue_work(dchid->wq, &work->work); ++ queue_work(iface->wq, &work->work); + + done: + dockchannel_await(dchid->dc, dchid_handle_packet, dchid, sizeof(struct dchid_hdr)); +@@ -1004,6 +1073,9 @@ static int dockchannel_hid_probe(struct platform_device *pdev) + if (IS_ERR_OR_NULL(dchid->dc)) { + return -PTR_ERR(dchid->dc); + } ++ dchid->new_iface_wq = alloc_workqueue("dchid-new", WQ_MEM_RECLAIM, 0); ++ if (!dchid->new_iface_wq) ++ return -ENOMEM; + + dchid->comm = dchid_get_interface(dchid, IFACE_COMM, "comm"); + if (!dchid->comm) { +@@ -1011,10 +1083,6 @@ static int dockchannel_hid_probe(struct platform_device *pdev) + return -EIO; + } + +- dchid->wq = alloc_ordered_workqueue("dockchannel-hid-report", WQ_MEM_RECLAIM); +- if (!dchid->wq) +- return -ENOMEM; +- + dev_info(dchid->dev, "initialized, awaiting packets\n"); + dockchannel_await(dchid->dc, dchid_handle_packet, dchid, sizeof(struct dchid_hdr)); + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0134-dockchannel-hid-Handle-M2-Air-keyboard-types.patch b/target/linux/silicon/patches-5.19/0134-dockchannel-hid-Handle-M2-Air-keyboard-types.patch new file mode 100644 index 000000000..faba8f65b --- /dev/null +++ b/target/linux/silicon/patches-5.19/0134-dockchannel-hid-Handle-M2-Air-keyboard-types.patch @@ -0,0 +1,37 @@ +From 740efddf69b264d6439f9cf124d36acab812dd39 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 30 Jul 2022 16:16:45 +0900 +Subject: [PATCH 134/171] dockchannel-hid: Handle M2 Air keyboard types + +It looks like the keyboard type isn't just for the overall layout kind, +but also varies by device. Conjecture is that Apple always allocates +them sequentially in groups of 3 for the 3 available physical layout +groups, so just do % 3. + +Signed-off-by: Hector Martin +--- + drivers/hid/dockchannel-hid/dockchannel-hid.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/dockchannel-hid/dockchannel-hid.c b/drivers/hid/dockchannel-hid/dockchannel-hid.c +index aeaeb60edf39..ea9d57ed9fa4 100644 +--- a/drivers/hid/dockchannel-hid/dockchannel-hid.c ++++ b/drivers/hid/dockchannel-hid/dockchannel-hid.c +@@ -615,8 +615,12 @@ static void dchid_create_interface_work(struct work_struct *ws) + } else if (!strcmp(iface->name, "keyboard")) { + hid->type = HID_TYPE_SPI_KEYBOARD; + +- /* These country codes match what earlier Apple HID keyboards did */ +- switch (dchid->device_id.keyboard_type) { ++ /* ++ * These country codes match what earlier Apple HID keyboards did. ++ * Apple seems to allocate keyboard IDs in groups of 3 (for the 3 ++ * layout groups), hence the % 3. ++ */ ++ switch (dchid->device_id.keyboard_type % 3) { + case KEYBOARD_TYPE_ANSI: + hid->country = 33; // US-English + break; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0135-lib-vsprintf-Add-support-for-generic-FOURCCs-by-exte.patch b/target/linux/silicon/patches-5.19/0135-lib-vsprintf-Add-support-for-generic-FOURCCs-by-exte.patch new file mode 100644 index 000000000..a97609b7a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0135-lib-vsprintf-Add-support-for-generic-FOURCCs-by-exte.patch @@ -0,0 +1,136 @@ +From 5c8936e9fd03a27cce9ce1f2fe0a4e8ad7ea2369 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 1 Feb 2022 00:40:51 +0900 +Subject: [PATCH 135/171] lib/vsprintf: Add support for generic FOURCCs by + extending %p4cc + +%p4cc is designed for DRM/V4L2 FOURCCs with their specific quirks, but +it's useful to be able to print generic 4-character codes formatted as +an integer. Extend it to add format specifiers for printing generic +32-bit FOURCCs with various endian semantics: + +%p4ch Host-endian +%p4cl Little-endian +%p4cb Big-endian +%p4cr Reverse-endian + +The endianness determines how bytes are interpreted as a u32, and the +FOURCC is then always printed MSByte-first (this is the opposite of +V4L/DRM FOURCCs). This covers most practical cases, e.g. %p4cr would +allow printing LSByte-first FOURCCs stored in host endian order +(other than the hex form being in character order, not the integer +value). + +Signed-off-by: Hector Martin +--- + Documentation/core-api/printk-formats.rst | 32 +++++++++++++++++++++ + lib/vsprintf.c | 35 +++++++++++++++++++---- + 2 files changed, 61 insertions(+), 6 deletions(-) + +diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst +index 5e89497ba314..22c33398ec02 100644 +--- a/Documentation/core-api/printk-formats.rst ++++ b/Documentation/core-api/printk-formats.rst +@@ -625,6 +625,38 @@ Examples:: + %p4cc Y10 little-endian (0x20303159) + %p4cc NV12 big-endian (0xb231564e) + ++Generic FourCC code ++------------------- ++ ++:: ++ %p4c[hnbl] gP00 (0x67503030) ++ ++Print a generic FourCC code, as both ASCII characters and its numerical ++value as hexadecimal. ++ ++The additional ``h``, ``r``, ``b``, and ``l`` specifiers are used to specify ++host, reversed, big or little endian order data respectively. Host endian ++order means the data is interpreted as a 32-bit integer and the most ++significant byte is printed first; that is, the character code as printed ++matches the byte order stored in memory on big-endian systems, and is reversed ++on little-endian systems. ++ ++Passed by reference. ++ ++Examples for a little-endian machine, given &(u32)0x67503030:: ++ ++ %p4ch gP00 (0x67503030) ++ %p4cl gP00 (0x67503030) ++ %p4cb 00Pg (0x30305067) ++ %p4cr 00Pg (0x30305067) ++ ++Examples for a big-endian machine, given &(u32)0x67503030:: ++ ++ %p4ch gP00 (0x67503030) ++ %p4cl 00Pg (0x30305067) ++ %p4cb gP00 (0x67503030) ++ %p4cr 00Pg (0x30305067) ++ + Thanks + ====== + +diff --git a/lib/vsprintf.c b/lib/vsprintf.c +index 3c1853a9d1c0..31707499f90f 100644 +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -1757,27 +1757,50 @@ char *fourcc_string(char *buf, char *end, const u32 *fourcc, + char output[sizeof("0123 little-endian (0x01234567)")]; + char *p = output; + unsigned int i; ++ bool pix_fmt = false; + u32 orig, val; + +- if (fmt[1] != 'c' || fmt[2] != 'c') ++ if (fmt[1] != 'c') + return error_string(buf, end, "(%p4?)", spec); + + if (check_pointer(&buf, end, fourcc, spec)) + return buf; + + orig = get_unaligned(fourcc); +- val = orig & ~BIT(31); ++ switch (fmt[2]) { ++ case 'h': ++ val = orig; ++ break; ++ case 'r': ++ val = orig = swab32(orig); ++ break; ++ case 'l': ++ val = orig = le32_to_cpu(orig); ++ break; ++ case 'b': ++ val = orig = be32_to_cpu(orig); ++ break; ++ case 'c': ++ /* Pixel formats are printed LSB-first */ ++ val = swab32(orig & ~BIT(31)); ++ pix_fmt = true; ++ break; ++ default: ++ return error_string(buf, end, "(%p4?)", spec); ++ } + + for (i = 0; i < sizeof(u32); i++) { +- unsigned char c = val >> (i * 8); ++ unsigned char c = val >> ((3 - i) * 8); + + /* Print non-control ASCII characters as-is, dot otherwise */ + *p++ = isascii(c) && isprint(c) ? c : '.'; + } + +- *p++ = ' '; +- strcpy(p, orig & BIT(31) ? "big-endian" : "little-endian"); +- p += strlen(p); ++ if (pix_fmt) { ++ *p++ = ' '; ++ strcpy(p, orig & BIT(31) ? "big-endian" : "little-endian"); ++ p += strlen(p); ++ } + + *p++ = ' '; + *p++ = '('; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0136-soc-apple-rtkit-Add-apple_rtkit_poll.patch b/target/linux/silicon/patches-5.19/0136-soc-apple-rtkit-Add-apple_rtkit_poll.patch new file mode 100644 index 000000000..442a2a0ce --- /dev/null +++ b/target/linux/silicon/patches-5.19/0136-soc-apple-rtkit-Add-apple_rtkit_poll.patch @@ -0,0 +1,54 @@ +From 6ca3d4d94f429b7d0fcb991442ada6b2d34fc4c1 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 2 May 2022 15:55:51 +0900 +Subject: [PATCH 136/171] soc: apple: rtkit: Add apple_rtkit_poll + +This allows a client to receive messages in atomic context, by polling. + +Signed-off-by: Hector Martin +--- + drivers/soc/apple/rtkit.c | 6 ++++++ + include/linux/soc/apple/rtkit.h | 12 ++++++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c +index cf1129e9f76b..031ec4aa06d5 100644 +--- a/drivers/soc/apple/rtkit.c ++++ b/drivers/soc/apple/rtkit.c +@@ -660,6 +660,12 @@ int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message, + } + EXPORT_SYMBOL_GPL(apple_rtkit_send_message_wait); + ++int apple_rtkit_poll(struct apple_rtkit *rtk) ++{ ++ return mbox_client_peek_data(rtk->mbox_chan); ++} ++EXPORT_SYMBOL_GPL(apple_rtkit_poll); ++ + int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint) + { + u64 msg; +diff --git a/include/linux/soc/apple/rtkit.h b/include/linux/soc/apple/rtkit.h +index 88eb832eac7b..c9cabb679cd1 100644 +--- a/include/linux/soc/apple/rtkit.h ++++ b/include/linux/soc/apple/rtkit.h +@@ -152,4 +152,16 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, + int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message, + unsigned long timeout, bool atomic); + ++/* ++ * Process incoming messages in atomic context. ++ * This only guarantees that messages arrive as far as the recv_message_early ++ * callback; drivers expecting to handle incoming messages synchronously ++ * by calling this function must do it that way. ++ * Will return 1 if some data was processed, 0 if none was, or a ++ * negative error code on failure. ++ * ++ * @rtk: RTKit reference ++ */ ++int apple_rtkit_poll(struct apple_rtkit *rtk); ++ + #endif /* _LINUX_APPLE_RTKIT_H_ */ +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0137-soc-apple-rtkit-Get-rid-of-apple_rtkit_send_message_.patch b/target/linux/silicon/patches-5.19/0137-soc-apple-rtkit-Get-rid-of-apple_rtkit_send_message_.patch new file mode 100644 index 000000000..3125ed9ca --- /dev/null +++ b/target/linux/silicon/patches-5.19/0137-soc-apple-rtkit-Get-rid-of-apple_rtkit_send_message_.patch @@ -0,0 +1,89 @@ +From 0210c49f4d0e1b05db9d553f82b0c881fe3e7f08 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 5 May 2022 01:25:16 +0900 +Subject: [PATCH 137/171] soc: apple: rtkit: Get rid of + apple_rtkit_send_message_wait + +It is fundamentally broken and has no users. Just remove it. + +Signed-off-by: Hector Martin +--- + drivers/soc/apple/rtkit.c | 32 -------------------------------- + include/linux/soc/apple/rtkit.h | 18 ------------------ + 2 files changed, 50 deletions(-) + +diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c +index 031ec4aa06d5..0a449e95c22b 100644 +--- a/drivers/soc/apple/rtkit.c ++++ b/drivers/soc/apple/rtkit.c +@@ -628,38 +628,6 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, + } + EXPORT_SYMBOL_GPL(apple_rtkit_send_message); + +-int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message, +- unsigned long timeout, bool atomic) +-{ +- DECLARE_COMPLETION_ONSTACK(completion); +- int ret; +- long t; +- +- ret = apple_rtkit_send_message(rtk, ep, message, &completion, atomic); +- if (ret < 0) +- return ret; +- +- if (atomic) { +- ret = mbox_flush(rtk->mbox_chan, timeout); +- if (ret < 0) +- return ret; +- +- if (try_wait_for_completion(&completion)) +- return 0; +- +- return -ETIME; +- } else { +- t = wait_for_completion_interruptible_timeout( +- &completion, msecs_to_jiffies(timeout)); +- if (t < 0) +- return t; +- else if (t == 0) +- return -ETIME; +- return 0; +- } +-} +-EXPORT_SYMBOL_GPL(apple_rtkit_send_message_wait); +- + int apple_rtkit_poll(struct apple_rtkit *rtk) + { + return mbox_client_peek_data(rtk->mbox_chan); +diff --git a/include/linux/soc/apple/rtkit.h b/include/linux/soc/apple/rtkit.h +index c9cabb679cd1..2d837aa7b91f 100644 +--- a/include/linux/soc/apple/rtkit.h ++++ b/include/linux/soc/apple/rtkit.h +@@ -134,24 +134,6 @@ int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint); + int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, + struct completion *completion, bool atomic); + +-/* +- * Send a message to the given endpoint and wait until it has been submitted +- * to the hardware FIFO. +- * Will return zero on success and a negative error code on failure +- * (e.g. -ETIME when the message couldn't be written within the given +- * timeout) +- * +- * @rtk: RTKit reference +- * @ep: target endpoint +- * @message: message to be sent +- * @timeout: timeout in milliseconds to allow the message transmission +- * to be completed +- * @atomic: if set to true this function can be called from atomic +- * context. +- */ +-int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message, +- unsigned long timeout, bool atomic); +- + /* + * Process incoming messages in atomic context. + * This only guarantees that messages arrive as far as the recv_message_early +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0138-platform-apple-Add-new-Apple-Mac-SMC-driver.patch b/target/linux/silicon/patches-5.19/0138-platform-apple-Add-new-Apple-Mac-SMC-driver.patch new file mode 100644 index 000000000..027f79cfe --- /dev/null +++ b/target/linux/silicon/patches-5.19/0138-platform-apple-Add-new-Apple-Mac-SMC-driver.patch @@ -0,0 +1,969 @@ +From 97cb112f3f15d7fd60d75bdb09093d32dfa8cddc Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 4 Feb 2022 12:47:07 +0900 +Subject: [PATCH 138/171] platform/apple: Add new Apple Mac SMC driver + +This driver implements support for the SMC (System Management +Controller) in Apple Macs. In contrast to the existing applesmc driver, +it uses pluggable backends that allow it to support different SMC +implementations, and uses the MFD subsystem to expose the core SMC +functionality so that specific features (gpio, hwmon, battery, etc.) can +be implemented by separate drivers in their respective downstream +subsystems. + +The initial RTKit backend adds support for Apple Silicon Macs (M1 et +al). We hope a backend for T2 Macs will be written in the future +(since those are not supported by applesmc), and eventually an x86 +backend would allow us to fully deprecate applesmc in favor of this +driver. + +Signed-off-by: Hector Martin +--- + drivers/platform/Kconfig | 2 + + drivers/platform/Makefile | 1 + + drivers/platform/apple/Kconfig | 49 ++++ + drivers/platform/apple/Makefile | 11 + + drivers/platform/apple/smc.h | 28 ++ + drivers/platform/apple/smc_core.c | 249 ++++++++++++++++ + drivers/platform/apple/smc_rtkit.c | 451 +++++++++++++++++++++++++++++ + include/linux/mfd/macsmc.h | 86 ++++++ + 8 files changed, 877 insertions(+) + create mode 100644 drivers/platform/apple/Kconfig + create mode 100644 drivers/platform/apple/Makefile + create mode 100644 drivers/platform/apple/smc.h + create mode 100644 drivers/platform/apple/smc_core.c + create mode 100644 drivers/platform/apple/smc_rtkit.c + create mode 100644 include/linux/mfd/macsmc.h + +diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig +index 18fc6a08569e..d683a75fc972 100644 +--- a/drivers/platform/Kconfig ++++ b/drivers/platform/Kconfig +@@ -15,3 +15,5 @@ source "drivers/platform/mellanox/Kconfig" + source "drivers/platform/olpc/Kconfig" + + source "drivers/platform/surface/Kconfig" ++ ++source "drivers/platform/apple/Kconfig" +diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile +index 4de08ef4ec9d..3e5d5039a28c 100644 +--- a/drivers/platform/Makefile ++++ b/drivers/platform/Makefile +@@ -10,3 +10,4 @@ obj-$(CONFIG_OLPC_EC) += olpc/ + obj-$(CONFIG_GOLDFISH) += goldfish/ + obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ + obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ ++obj-$(CONFIG_APPLE_PLATFORMS) += apple/ +diff --git a/drivers/platform/apple/Kconfig b/drivers/platform/apple/Kconfig +new file mode 100644 +index 000000000000..42525aa9fbbe +--- /dev/null ++++ b/drivers/platform/apple/Kconfig +@@ -0,0 +1,49 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Apple Platform-Specific Drivers ++# ++ ++menuconfig APPLE_PLATFORMS ++ bool "Apple Mac Platform-Specific Device Drivers" ++ default y ++ help ++ Say Y here to get to see options for platform-specific device drivers ++ for Apple devices. This option alone does not add any kernel code. ++ ++ If you say N, all options in this submenu will be skipped and disabled. ++ ++if APPLE_PLATFORMS ++ ++config APPLE_SMC ++ tristate "Apple SMC Driver" ++ depends on ARCH_APPLE || COMPILE_TEST ++ default ARCH_APPLE ++ select MFD_CORE ++ help ++ Build support for the Apple System Management Controller present in ++ Apple Macs. This driver currently supports the SMC in Apple Silicon ++ Macs. For x86 Macs, see the applesmc driver (SENSORS_APPLESMC). ++ ++ Say Y here if you have an Apple Silicon Mac. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called macsmc. ++ ++if APPLE_SMC ++ ++config APPLE_SMC_RTKIT ++ tristate "RTKit (Apple Silicon) backend" ++ depends on ARCH_APPLE || COMPILE_TEST ++ depends on APPLE_RTKIT ++ default ARCH_APPLE ++ help ++ Build support for SMC communications via the RTKit backend. This is ++ required for Apple Silicon Macs. ++ ++ Say Y here if you have an Apple Silicon Mac. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called macsmc-rtkit. ++ ++endif ++endif +diff --git a/drivers/platform/apple/Makefile b/drivers/platform/apple/Makefile +new file mode 100644 +index 000000000000..79fac195398b +--- /dev/null ++++ b/drivers/platform/apple/Makefile +@@ -0,0 +1,11 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for linux/drivers/platform/apple ++# Apple Platform-Specific Drivers ++# ++ ++macsmc-y += smc_core.o ++macsmc-rtkit-y += smc_rtkit.o ++ ++obj-$(CONFIG_APPLE_SMC) += macsmc.o ++obj-$(CONFIG_APPLE_SMC_RTKIT) += macsmc-rtkit.o +diff --git a/drivers/platform/apple/smc.h b/drivers/platform/apple/smc.h +new file mode 100644 +index 000000000000..8ae51887b2c5 +--- /dev/null ++++ b/drivers/platform/apple/smc.h +@@ -0,0 +1,28 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC internal core definitions ++ * Copyright (C) The Asahi Linux Contributors ++ */ ++ ++#ifndef _SMC_H ++#define _SMC_H ++ ++#include ++ ++struct apple_smc_backend_ops { ++ int (*read_key)(void *cookie, smc_key key, void *buf, size_t size); ++ int (*write_key)(void *cookie, smc_key key, void *buf, size_t size); ++ int (*write_key_atomic)(void *cookie, smc_key key, void *buf, size_t size); ++ int (*rw_key)(void *cookie, smc_key key, void *wbuf, size_t wsize, ++ void *rbuf, size_t rsize); ++ int (*get_key_by_index)(void *cookie, int index, smc_key *key); ++ int (*get_key_info)(void *cookie, smc_key key, struct apple_smc_key_info *info); ++}; ++ ++struct apple_smc *apple_smc_probe(struct device *dev, const struct apple_smc_backend_ops *ops, ++ void *cookie); ++void *apple_smc_get_cookie(struct apple_smc *smc); ++int apple_smc_remove(struct apple_smc *smc); ++void apple_smc_event_received(struct apple_smc *smc, uint32_t event); ++ ++#endif +diff --git a/drivers/platform/apple/smc_core.c b/drivers/platform/apple/smc_core.c +new file mode 100644 +index 000000000000..daf029cd072f +--- /dev/null ++++ b/drivers/platform/apple/smc_core.c +@@ -0,0 +1,249 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC core framework ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include "smc.h" ++ ++struct apple_smc { ++ struct device *dev; ++ ++ void *be_cookie; ++ const struct apple_smc_backend_ops *be; ++ ++ struct mutex mutex; ++ ++ u32 key_count; ++ smc_key first_key; ++ smc_key last_key; ++ ++ struct blocking_notifier_head event_handlers; ++}; ++ ++static const struct mfd_cell apple_smc_devs[] = { ++ { ++ .name = "macsmc-gpio", ++ }, ++ { ++ .name = "macsmc-hid", ++ }, ++ { ++ .name = "macsmc-power", ++ }, ++ { ++ .name = "macsmc-reboot", ++ }, ++ { ++ .name = "macsmc-rtc", ++ }, ++}; ++ ++int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size) ++{ ++ int ret; ++ ++ mutex_lock(&smc->mutex); ++ ret = smc->be->read_key(smc->be_cookie, key, buf, size); ++ mutex_unlock(&smc->mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL(apple_smc_read); ++ ++int apple_smc_write(struct apple_smc *smc, smc_key key, void *buf, size_t size) ++{ ++ int ret; ++ ++ mutex_lock(&smc->mutex); ++ ret = smc->be->write_key(smc->be_cookie, key, buf, size); ++ mutex_unlock(&smc->mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL(apple_smc_write); ++ ++int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, void *buf, size_t size) ++{ ++ int ret; ++ ++ /* ++ * Will fail if SMC is busy. This is only used by SMC reboot/poweroff ++ * final calls, so it doesn't really matter at that point. ++ */ ++ if (!mutex_trylock(&smc->mutex)) ++ return -EBUSY; ++ ++ ret = smc->be->write_key_atomic(smc->be_cookie, key, buf, size); ++ mutex_unlock(&smc->mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL(apple_smc_write_atomic); ++ ++int apple_smc_rw(struct apple_smc *smc, smc_key key, void *wbuf, size_t wsize, ++ void *rbuf, size_t rsize) ++{ ++ int ret; ++ ++ mutex_lock(&smc->mutex); ++ ret = smc->be->rw_key(smc->be_cookie, key, wbuf, wsize, rbuf, rsize); ++ mutex_unlock(&smc->mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL(apple_smc_rw); ++ ++int apple_smc_get_key_by_index(struct apple_smc *smc, int index, smc_key *key) ++{ ++ int ret; ++ ++ mutex_lock(&smc->mutex); ++ ret = smc->be->get_key_by_index(smc->be_cookie, index, key); ++ mutex_unlock(&smc->mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL(apple_smc_get_key_by_index); ++ ++int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_key_info *info) ++{ ++ int ret; ++ ++ mutex_lock(&smc->mutex); ++ ret = smc->be->get_key_info(smc->be_cookie, key, info); ++ mutex_unlock(&smc->mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL(apple_smc_get_key_info); ++ ++int apple_smc_find_first_key_index(struct apple_smc *smc, smc_key key) ++{ ++ int start = 0, count = smc->key_count; ++ int ret; ++ ++ if (key <= smc->first_key) ++ return 0; ++ if (key > smc->last_key) ++ return smc->key_count; ++ ++ while (count > 1) { ++ int pivot = start + ((count - 1) >> 1); ++ smc_key pkey; ++ ++ ret = apple_smc_get_key_by_index(smc, pivot, &pkey); ++ if (ret < 0) ++ return ret; ++ ++ if (pkey == key) ++ return pivot; ++ ++ pivot++; ++ ++ if (pkey < key) { ++ count -= pivot - start; ++ start = pivot; ++ } else { ++ count = pivot - start; ++ } ++ } ++ ++ return start; ++} ++EXPORT_SYMBOL(apple_smc_find_first_key_index); ++ ++int apple_smc_get_key_count(struct apple_smc *smc) ++{ ++ return smc->key_count; ++} ++EXPORT_SYMBOL(apple_smc_get_key_count); ++ ++void apple_smc_event_received(struct apple_smc *smc, uint32_t event) ++{ ++ dev_dbg(smc->dev, "Event: 0x%08x\n", event); ++ blocking_notifier_call_chain(&smc->event_handlers, event, NULL); ++} ++EXPORT_SYMBOL(apple_smc_event_received); ++ ++int apple_smc_register_notifier(struct apple_smc *smc, struct notifier_block *n) ++{ ++ return blocking_notifier_chain_register(&smc->event_handlers, n); ++} ++EXPORT_SYMBOL(apple_smc_register_notifier); ++ ++int apple_smc_unregister_notifier(struct apple_smc *smc, struct notifier_block *n) ++{ ++ return blocking_notifier_chain_unregister(&smc->event_handlers, n); ++} ++EXPORT_SYMBOL(apple_smc_unregister_notifier); ++ ++void *apple_smc_get_cookie(struct apple_smc *smc) ++{ ++ return smc->be_cookie; ++} ++EXPORT_SYMBOL(apple_smc_get_cookie); ++ ++struct apple_smc *apple_smc_probe(struct device *dev, const struct apple_smc_backend_ops *ops, void *cookie) ++{ ++ struct apple_smc *smc; ++ u32 count; ++ int ret; ++ ++ smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL); ++ if (!smc) ++ return ERR_PTR(-ENOMEM); ++ ++ smc->dev = dev; ++ smc->be_cookie = cookie; ++ smc->be = ops; ++ mutex_init(&smc->mutex); ++ BLOCKING_INIT_NOTIFIER_HEAD(&smc->event_handlers); ++ ++ ret = apple_smc_read_u32(smc, SMC_KEY(#KEY), &count); ++ if (ret) ++ return ERR_PTR(dev_err_probe(dev, ret, "Failed to get key count")); ++ smc->key_count = be32_to_cpu(count); ++ ++ ret = apple_smc_get_key_by_index(smc, 0, &smc->first_key); ++ if (ret) ++ return ERR_PTR(dev_err_probe(dev, ret, "Failed to get first key")); ++ ++ ret = apple_smc_get_key_by_index(smc, smc->key_count - 1, &smc->last_key); ++ if (ret) ++ return ERR_PTR(dev_err_probe(dev, ret, "Failed to get last key")); ++ ++ /* Enable notifications */ ++ apple_smc_write_flag(smc, SMC_KEY(NTAP), 1); ++ ++ dev_info(dev, "Initialized (%d keys %p4ch..%p4ch)\n", ++ smc->key_count, &smc->first_key, &smc->last_key); ++ ++ dev_set_drvdata(dev, smc); ++ ++ ret = mfd_add_devices(dev, -1, apple_smc_devs, ARRAY_SIZE(apple_smc_devs), NULL, 0, NULL); ++ if (ret) ++ return ERR_PTR(dev_err_probe(dev, ret, "Subdevice initialization failed")); ++ ++ return smc; ++} ++EXPORT_SYMBOL(apple_smc_probe); ++ ++int apple_smc_remove(struct apple_smc *smc) ++{ ++ mfd_remove_devices(smc->dev); ++ ++ /* Disable notifications */ ++ apple_smc_write_flag(smc, SMC_KEY(NTAP), 1); ++ ++ return 0; ++} ++EXPORT_SYMBOL(apple_smc_remove); ++ ++MODULE_AUTHOR("Hector Martin "); ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple SMC core"); +diff --git a/drivers/platform/apple/smc_rtkit.c b/drivers/platform/apple/smc_rtkit.c +new file mode 100644 +index 000000000000..5b7c4c475bbb +--- /dev/null ++++ b/drivers/platform/apple/smc_rtkit.c +@@ -0,0 +1,451 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC RTKit backend ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "smc.h" ++ ++#define SMC_ENDPOINT 0x20 ++ ++/* Guess */ ++#define SMC_SHMEM_SIZE 0x1000 ++ ++#define SMC_MSG_READ_KEY 0x10 ++#define SMC_MSG_WRITE_KEY 0x11 ++#define SMC_MSG_GET_KEY_BY_INDEX 0x12 ++#define SMC_MSG_GET_KEY_INFO 0x13 ++#define SMC_MSG_INITIALIZE 0x17 ++#define SMC_MSG_NOTIFICATION 0x18 ++#define SMC_MSG_RW_KEY 0x20 ++ ++#define SMC_DATA GENMASK(63, 32) ++#define SMC_WSIZE GENMASK(31, 24) ++#define SMC_SIZE GENMASK(23, 16) ++#define SMC_ID GENMASK(15, 12) ++#define SMC_MSG GENMASK(7, 0) ++#define SMC_RESULT SMC_MSG ++ ++#define SMC_RECV_TIMEOUT 100 ++ ++struct apple_smc_rtkit { ++ struct device *dev; ++ struct apple_smc *core; ++ struct apple_rtkit *rtk; ++ ++ struct completion init_done; ++ bool initialized; ++ bool alive; ++ ++ struct resource *sram; ++ void __iomem *sram_base; ++ struct apple_rtkit_shmem shmem; ++ ++ unsigned int msg_id; ++ ++ bool atomic_pending; ++ struct completion cmd_done; ++ u64 cmd_ret; ++}; ++ ++static int apple_smc_rtkit_write_key_atomic(void *cookie, smc_key key, void *buf, size_t size) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ int ret; ++ u64 msg; ++ u8 result; ++ ++ if (size > SMC_SHMEM_SIZE || size == 0) ++ return -EINVAL; ++ ++ if (!smc->alive) ++ return -EIO; ++ ++ memcpy_toio(smc->shmem.iomem, buf, size); ++ smc->msg_id = (smc->msg_id + 1) & 0xf; ++ msg = (FIELD_PREP(SMC_MSG, SMC_MSG_WRITE_KEY) | ++ FIELD_PREP(SMC_SIZE, size) | ++ FIELD_PREP(SMC_ID, smc->msg_id) | ++ FIELD_PREP(SMC_DATA, key)); ++ smc->atomic_pending = true; ++ ++ ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, msg, NULL, true); ++ if (ret < 0) { ++ dev_err(smc->dev, "Failed to send command (%d)\n", ret); ++ return ret; ++ } ++ ++ while (smc->atomic_pending) { ++ ret = apple_rtkit_poll(smc->rtk); ++ if (ret < 0) { ++ dev_err(smc->dev, "RTKit poll failed (%llx)", msg); ++ return ret; ++ } ++ udelay(100); ++ } ++ ++ if (FIELD_GET(SMC_ID, smc->cmd_ret) != smc->msg_id) { ++ dev_err(smc->dev, "Command sequence mismatch (expected %d, got %d)\n", ++ smc->msg_id, (unsigned int)FIELD_GET(SMC_ID, smc->cmd_ret)); ++ return -EIO; ++ } ++ ++ result = FIELD_GET(SMC_RESULT, smc->cmd_ret); ++ if (result != 0) ++ return -result; ++ ++ return FIELD_GET(SMC_SIZE, smc->cmd_ret); ++} ++ ++static int apple_smc_cmd(struct apple_smc_rtkit *smc, u64 cmd, u64 arg, ++ u64 size, u64 wsize, u32 *ret_data) ++{ ++ int ret; ++ u64 msg; ++ u8 result; ++ ++ if (!smc->alive) ++ return -EIO; ++ ++ reinit_completion(&smc->cmd_done); ++ ++ smc->msg_id = (smc->msg_id + 1) & 0xf; ++ msg = (FIELD_PREP(SMC_MSG, cmd) | ++ FIELD_PREP(SMC_SIZE, size) | ++ FIELD_PREP(SMC_WSIZE, wsize) | ++ FIELD_PREP(SMC_ID, smc->msg_id) | ++ FIELD_PREP(SMC_DATA, arg)); ++ ++ ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, msg, NULL, false); ++ if (ret < 0) { ++ dev_err(smc->dev, "Failed to send command\n"); ++ return ret; ++ } ++ ++ do { ++ if (wait_for_completion_timeout(&smc->cmd_done, ++ msecs_to_jiffies(SMC_RECV_TIMEOUT)) == 0) { ++ dev_err(smc->dev, "Command timed out (%llx)", msg); ++ return -ETIMEDOUT; ++ } ++ if (FIELD_GET(SMC_ID, smc->cmd_ret) == smc->msg_id) ++ break; ++ dev_err(smc->dev, "Command sequence mismatch (expected %d, got %d)\n", ++ smc->msg_id, (unsigned int)FIELD_GET(SMC_ID, smc->cmd_ret)); ++ } while(1); ++ ++ result = FIELD_GET(SMC_RESULT, smc->cmd_ret); ++ if (result != 0) ++ return -result; ++ ++ if (ret_data) ++ *ret_data = FIELD_GET(SMC_DATA, smc->cmd_ret); ++ ++ return FIELD_GET(SMC_SIZE, smc->cmd_ret); ++} ++ ++static int _apple_smc_rtkit_read_key(struct apple_smc_rtkit *smc, smc_key key, ++ void *buf, size_t size, size_t wsize) ++{ ++ int ret; ++ u32 rdata; ++ u64 cmd; ++ ++ if (size > SMC_SHMEM_SIZE || size == 0) ++ return -EINVAL; ++ ++ cmd = wsize ? SMC_MSG_RW_KEY : SMC_MSG_READ_KEY; ++ ++ ret = apple_smc_cmd(smc, cmd, key, size, wsize, &rdata); ++ if (ret < 0) ++ return ret; ++ ++ if (size <= 4) ++ memcpy(buf, &rdata, size); ++ else ++ memcpy_fromio(buf, smc->shmem.iomem, size); ++ ++ return ret; ++} ++ ++static int apple_smc_rtkit_read_key(void *cookie, smc_key key, void *buf, size_t size) ++{ ++ return _apple_smc_rtkit_read_key(cookie, key, buf, size, 0); ++} ++ ++static int apple_smc_rtkit_write_key(void *cookie, smc_key key, void *buf, size_t size) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ ++ if (size > SMC_SHMEM_SIZE || size == 0) ++ return -EINVAL; ++ ++ memcpy_toio(smc->shmem.iomem, buf, size); ++ return apple_smc_cmd(smc, SMC_MSG_WRITE_KEY, key, size, 0, NULL); ++} ++ ++static int apple_smc_rtkit_rw_key(void *cookie, smc_key key, ++ void *wbuf, size_t wsize, void *rbuf, size_t rsize) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ ++ if (wsize > SMC_SHMEM_SIZE || wsize == 0) ++ return -EINVAL; ++ ++ memcpy_toio(smc->shmem.iomem, wbuf, wsize); ++ return _apple_smc_rtkit_read_key(smc, key, rbuf, rsize, wsize); ++} ++ ++static int apple_smc_rtkit_get_key_by_index(void *cookie, int index, smc_key *key) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ int ret; ++ ++ ret = apple_smc_cmd(smc, SMC_MSG_GET_KEY_BY_INDEX, index, 0, 0, key); ++ ++ *key = swab32(*key); ++ return ret; ++} ++ ++static int apple_smc_rtkit_get_key_info(void *cookie, smc_key key, struct apple_smc_key_info *info) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ u8 key_info[6]; ++ int ret; ++ ++ ret = apple_smc_cmd(smc, SMC_MSG_GET_KEY_INFO, key, 0, 0, NULL); ++ if (ret >= 0 && info) { ++ info->size = key_info[0]; ++ info->type_code = get_unaligned_be32(&key_info[1]); ++ info->flags = key_info[5]; ++ } ++ return ret; ++} ++ ++static const struct apple_smc_backend_ops apple_smc_rtkit_be_ops = { ++ .read_key = apple_smc_rtkit_read_key, ++ .write_key = apple_smc_rtkit_write_key, ++ .write_key_atomic = apple_smc_rtkit_write_key_atomic, ++ .rw_key = apple_smc_rtkit_rw_key, ++ .get_key_by_index = apple_smc_rtkit_get_key_by_index, ++ .get_key_info = apple_smc_rtkit_get_key_info, ++}; ++ ++static void apple_smc_rtkit_crashed(void *cookie) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ ++ dev_err(smc->dev, "SMC crashed! Your system will reboot in a few seconds...\n"); ++ smc->alive = false; ++} ++ ++static int apple_smc_rtkit_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ struct resource res = { ++ .start = bfr->iova, ++ .end = bfr->iova + bfr->size - 1, ++ .name = "rtkit_map", ++ .flags = smc->sram->flags, ++ }; ++ ++ if (!bfr->iova) { ++ dev_err(smc->dev, "RTKit wants a RAM buffer\n"); ++ return -EIO; ++ } ++ ++ if (res.end < res.start || !resource_contains(smc->sram, &res)) { ++ dev_err(smc->dev, ++ "RTKit buffer request outside SRAM region: %pR", &res); ++ return -EFAULT; ++ } ++ ++ bfr->iomem = smc->sram_base + (res.start - smc->sram->start); ++ bfr->is_mapped = true; ++ ++ return 0; ++} ++ ++static void apple_smc_rtkit_shmem_destroy(void *cookie, struct apple_rtkit_shmem *bfr) ++{ ++ // no-op ++} ++ ++static bool apple_smc_rtkit_recv_early(void *cookie, u8 endpoint, u64 message) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ ++ if (endpoint != SMC_ENDPOINT) { ++ dev_err(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint); ++ return false; ++ } ++ ++ if (!smc->initialized) { ++ int ret; ++ ++ smc->shmem.iova = message; ++ smc->shmem.size = SMC_SHMEM_SIZE; ++ ret = apple_smc_rtkit_shmem_setup(smc, &smc->shmem); ++ if (ret < 0) ++ dev_err(smc->dev, "Failed to initialize shared memory\n"); ++ else ++ smc->alive = true; ++ smc->initialized = true; ++ complete(&smc->init_done); ++ } else if (FIELD_GET(SMC_MSG, message) == SMC_MSG_NOTIFICATION) { ++ /* Handle these in the RTKit worker thread */ ++ return false; ++ } else { ++ smc->cmd_ret = message; ++ if (smc->atomic_pending) { ++ smc->atomic_pending = false; ++ } else { ++ complete(&smc->cmd_done); ++ } ++ } ++ ++ return true; ++} ++ ++static void apple_smc_rtkit_recv(void *cookie, u8 endpoint, u64 message) ++{ ++ struct apple_smc_rtkit *smc = cookie; ++ ++ if (endpoint != SMC_ENDPOINT) { ++ dev_err(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint); ++ return; ++ } ++ ++ if (FIELD_GET(SMC_MSG, message) != SMC_MSG_NOTIFICATION) { ++ dev_err(smc->dev, "Received unknown message from worker: 0x%llx\n", message); ++ return; ++ } ++ ++ apple_smc_event_received(smc->core, FIELD_GET(SMC_DATA, message)); ++} ++ ++static const struct apple_rtkit_ops apple_smc_rtkit_ops = { ++ .crashed = apple_smc_rtkit_crashed, ++ .recv_message = apple_smc_rtkit_recv, ++ .recv_message_early = apple_smc_rtkit_recv_early, ++ .shmem_setup = apple_smc_rtkit_shmem_setup, ++ .shmem_destroy = apple_smc_rtkit_shmem_destroy, ++}; ++ ++static int apple_smc_rtkit_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct apple_smc_rtkit *smc; ++ int ret; ++ ++ smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL); ++ if (!smc) ++ return -ENOMEM; ++ ++ smc->dev = dev; ++ ++ smc->sram = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); ++ if (!smc->sram) ++ return dev_err_probe(dev, EIO, ++ "No SRAM region"); ++ ++ smc->sram_base = devm_ioremap_resource(dev, smc->sram); ++ if (IS_ERR(smc->sram_base)) ++ return dev_err_probe(dev, PTR_ERR(smc->sram_base), ++ "Failed to map SRAM region"); ++ ++ smc->rtk = ++ devm_apple_rtkit_init(dev, smc, NULL, 0, &apple_smc_rtkit_ops); ++ if (IS_ERR(smc->rtk)) ++ return dev_err_probe(dev, PTR_ERR(smc->rtk), ++ "Failed to intialize RTKit"); ++ ++ ret = apple_rtkit_wake(smc->rtk); ++ if (ret != 0) ++ return dev_err_probe(dev, ret, ++ "Failed to wake up SMC"); ++ ++ ret = apple_rtkit_start_ep(smc->rtk, SMC_ENDPOINT); ++ if (ret != 0) { ++ dev_err(dev, "Failed to start endpoint"); ++ goto cleanup; ++ } ++ ++ init_completion(&smc->init_done); ++ init_completion(&smc->cmd_done); ++ ++ ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, ++ FIELD_PREP(SMC_MSG, SMC_MSG_INITIALIZE), NULL, false); ++ if (ret < 0) ++ return dev_err_probe(dev, ret, ++ "Failed to send init message"); ++ ++ if (wait_for_completion_timeout(&smc->init_done, ++ msecs_to_jiffies(SMC_RECV_TIMEOUT)) == 0) { ++ ret = -ETIMEDOUT; ++ dev_err(dev, "Timed out initializing SMC"); ++ goto cleanup; ++ } ++ ++ if (!smc->alive) { ++ ret = -EIO; ++ goto cleanup; ++ } ++ ++ smc->core = apple_smc_probe(dev, &apple_smc_rtkit_be_ops, smc); ++ if (IS_ERR(smc->core)) { ++ ret = PTR_ERR(smc->core); ++ goto cleanup; ++ } ++ ++ return 0; ++ ++cleanup: ++ /* Try to shut down RTKit, if it's not completely wedged */ ++ if (apple_rtkit_is_running(smc->rtk)) ++ apple_rtkit_quiesce(smc->rtk); ++ ++ return ret; ++} ++ ++static int apple_smc_rtkit_remove(struct platform_device *pdev) ++{ ++ struct apple_smc *core = platform_get_drvdata(pdev); ++ struct apple_smc_rtkit *smc = apple_smc_get_cookie(core); ++ ++ apple_smc_remove(core); ++ ++ if (apple_rtkit_is_running(smc->rtk)) ++ apple_rtkit_quiesce(smc->rtk); ++ ++ return 0; ++} ++ ++static const struct of_device_id apple_smc_rtkit_of_match[] = { ++ { .compatible = "apple,smc" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, apple_smc_rtkit_of_match); ++ ++static struct platform_driver apple_smc_rtkit_driver = { ++ .driver = { ++ .name = "macsmc-rtkit", ++ .owner = THIS_MODULE, ++ .of_match_table = apple_smc_rtkit_of_match, ++ }, ++ .probe = apple_smc_rtkit_probe, ++ .remove = apple_smc_rtkit_remove, ++}; ++module_platform_driver(apple_smc_rtkit_driver); ++ ++MODULE_AUTHOR("Hector Martin "); ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple SMC RTKit backend driver"); +diff --git a/include/linux/mfd/macsmc.h b/include/linux/mfd/macsmc.h +new file mode 100644 +index 000000000000..39b4dc4ca881 +--- /dev/null ++++ b/include/linux/mfd/macsmc.h +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC core definitions ++ * Copyright (C) The Asahi Linux Contributors ++ */ ++ ++#ifndef _LINUX_MFD_MACSMC_H ++#define _LINUX_MFD_MACSMC_H ++ ++struct apple_smc; ++ ++typedef u32 smc_key; ++ ++#define SMC_KEY(s) (smc_key)(_SMC_KEY(#s)) ++#define _SMC_KEY(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3]) ++ ++#define APPLE_SMC_READABLE BIT(7) ++#define APPLE_SMC_WRITABLE BIT(6) ++#define APPLE_SMC_FUNCTION BIT(4) ++ ++struct apple_smc_key_info { ++ u8 size; ++ u32 type_code; ++ u8 flags; ++}; ++ ++int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size); ++int apple_smc_write(struct apple_smc *smc, smc_key key, void *buf, size_t size); ++int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, void *buf, size_t size); ++int apple_smc_rw(struct apple_smc *smc, smc_key key, void *wbuf, size_t wsize, ++ void *rbuf, size_t rsize); ++ ++int apple_smc_get_key_count(struct apple_smc *smc); ++int apple_smc_find_first_key_index(struct apple_smc *smc, smc_key key); ++int apple_smc_get_key_by_index(struct apple_smc *smc, int index, smc_key *key); ++int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_key_info *info); ++ ++static inline bool apple_smc_key_exists(struct apple_smc *smc, smc_key key) ++{ ++ return apple_smc_get_key_info(smc, key, NULL) >= 0; ++} ++ ++#define APPLE_SMC_TYPE_OPS(type) \ ++ static inline int apple_smc_read_##type(struct apple_smc *smc, smc_key key, type *p) \ ++ { \ ++ int ret = apple_smc_read(smc, key, p, sizeof(*p)); \ ++ return (ret < 0) ? ret : ((ret != sizeof(*p)) ? -EINVAL : 0); \ ++ } \ ++ static inline int apple_smc_write_##type(struct apple_smc *smc, smc_key key, type p) \ ++ { \ ++ return apple_smc_write(smc, key, &p, sizeof(p)); \ ++ } \ ++ static inline int apple_smc_write_##type##_atomic(struct apple_smc *smc, smc_key key, type p) \ ++ { \ ++ return apple_smc_write_atomic(smc, key, &p, sizeof(p)); \ ++ } \ ++ static inline int apple_smc_rw_##type(struct apple_smc *smc, smc_key key, \ ++ type w, type *r) \ ++ { \ ++ int ret = apple_smc_rw(smc, key, &w, sizeof(w), r, sizeof(*r)); \ ++ return (ret < 0) ? ret : ((ret != sizeof(*r)) ? -EINVAL : 0); \ ++ } ++ ++APPLE_SMC_TYPE_OPS(u64) ++APPLE_SMC_TYPE_OPS(u32) ++APPLE_SMC_TYPE_OPS(u16) ++APPLE_SMC_TYPE_OPS(u8) ++APPLE_SMC_TYPE_OPS(s64) ++APPLE_SMC_TYPE_OPS(s32) ++APPLE_SMC_TYPE_OPS(s16) ++APPLE_SMC_TYPE_OPS(s8) ++ ++static inline int apple_smc_read_flag(struct apple_smc *smc, smc_key key) ++{ ++ u8 val; ++ int ret = apple_smc_read_u8(smc, key, &val); ++ if (ret < 0) ++ return ret; ++ return val ? 1 : 0; ++} ++#define apple_smc_write_flag apple_smc_write_u8 ++ ++int apple_smc_register_notifier(struct apple_smc *smc, struct notifier_block *n); ++int apple_smc_unregister_notifier(struct apple_smc *smc, struct notifier_block *n); ++ ++#endif +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0139-gpio-Add-new-gpio-macsmc-driver-for-Apple-Macs.patch b/target/linux/silicon/patches-5.19/0139-gpio-Add-new-gpio-macsmc-driver-for-Apple-Macs.patch new file mode 100644 index 000000000..fe5d87ef9 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0139-gpio-Add-new-gpio-macsmc-driver-for-Apple-Macs.patch @@ -0,0 +1,307 @@ +From ab3bf52a9b94de3d827d13bd6cfb1f1b6c6acc27 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 4 Feb 2022 12:52:52 +0900 +Subject: [PATCH 139/171] gpio: Add new gpio-macsmc driver for Apple Macs + +This driver implements the GPIO service on top of the SMC framework +on Apple Mac machines. In particular, these are the GPIOs present in the +PMU IC which are used to control power to certain on-board devices. + +Although the underlying hardware supports various pin config settings +(input/output, open drain, etc.), this driver does not implement that +functionality and leaves it up to the firmware to configure things +properly. We also don't yet support interrupts/events. This is +sufficient for device power control, which is the only thing we need to +support at this point. More features will be implemented when needed. + +To our knowledge, only Apple Silicon Macs implement this SMC feature. + +Signed-off-by: Hector Martin +--- + drivers/gpio/Kconfig | 11 ++ + drivers/gpio/Makefile | 1 + + drivers/gpio/gpio-macsmc.c | 238 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 250 insertions(+) + create mode 100644 drivers/gpio/gpio-macsmc.c + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index b01961999ced..fc35a7ca31dd 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -1282,6 +1282,17 @@ config GPIO_LP87565 + This driver can also be built as a module. If so, the module will be + called gpio-lp87565. + ++config GPIO_MACSMC ++ tristate "Apple Mac SMC GPIO" ++ depends on APPLE_SMC ++ default ARCH_APPLE ++ help ++ Support for GPIOs controlled by the SMC microcontroller on Apple Mac ++ systems. ++ ++ This driver can also be built as a module. If so, the module will be ++ called gpio-macsmc. ++ + config GPIO_MADERA + tristate "Cirrus Logic Madera class codecs" + depends on PINCTRL_MADERA +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index 14352f6dfe8e..5f7ec8fc6cdd 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -82,6 +82,7 @@ obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o + obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o + obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o + obj-$(CONFIG_GPIO_LPC32XX) += gpio-lpc32xx.o ++obj-$(CONFIG_GPIO_MACSMC) += gpio-macsmc.o + obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o + obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o + obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o +diff --git a/drivers/gpio/gpio-macsmc.c b/drivers/gpio/gpio-macsmc.c +new file mode 100644 +index 000000000000..ff9950afb69a +--- /dev/null ++++ b/drivers/gpio/gpio-macsmc.c +@@ -0,0 +1,238 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC GPIO driver ++ * Copyright The Asahi Linux Contributors ++ * ++ * This driver implements basic SMC PMU GPIO support that can read inputs ++ * and write outputs. Mode changes and IRQ config are not yet implemented. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_GPIO 64 ++ ++/* ++ * Commands 0-6 are, presumably, the intended API. ++ * Command 0xff lets you get/set the pin configuration in detail directly, ++ * but the bit meanings seem not to be stable between devices/PMU hardware ++ * versions. ++ * ++ * We're going to try to make do with the low commands for now. ++ * We don't implement pin mode changes at this time. ++ */ ++ ++#define CMD_ACTION (0 << 24) ++#define CMD_OUTPUT (1 << 24) ++#define CMD_INPUT (2 << 24) ++#define CMD_PINMODE (3 << 24) ++#define CMD_IRQ_ENABLE (4 << 24) ++#define CMD_IRQ_ACK (5 << 24) ++#define CMD_IRQ_MODE (6 << 24) ++#define CMD_CONFIG (0xff << 24) ++ ++#define MODE_INPUT 0 ++#define MODE_OUTPUT 1 ++#define MODE_VALUE_0 0 ++#define MODE_VALUE_1 2 ++ ++#define IRQ_MODE_HIGH 0 ++#define IRQ_MODE_LOW 1 ++#define IRQ_MODE_RISING 2 ++#define IRQ_MODE_FALLING 3 ++#define IRQ_MODE_BOTH 4 ++ ++#define CONFIG_MASK GENMASK(23, 16) ++#define CONFIG_VAL GENMASK(7, 0) ++ ++#define CONFIG_OUTMODE GENMASK(7, 6) ++#define CONFIG_IRQMODE GENMASK(5, 3) ++#define CONFIG_PULLDOWN BIT(2) ++#define CONFIG_PULLUP BIT(1) ++#define CONFIG_OUTVAL BIT(0) ++ ++/* ++ * output modes seem to differ depending on the PMU in use... ? ++ * j274 / M1 (Sera PMU): ++ * 0 = input ++ * 1 = output ++ * 2 = open drain ++ * 3 = disable ++ * j314 / M1Pro (Maverick PMU): ++ * 0 = input ++ * 1 = open drain ++ * 2 = output ++ * 3 = ? ++ */ ++ ++struct macsmc_gpio { ++ struct device *dev; ++ struct apple_smc *smc; ++ struct gpio_chip gc; ++ ++ int first_index; ++}; ++ ++static int macsmc_gpio_nr(smc_key key) ++{ ++ int low = hex_to_bin(key & 0xff); ++ int high = hex_to_bin((key >> 8) & 0xff); ++ ++ if (low < 0 || high < 0) ++ return -1; ++ ++ return low | (high << 4); ++} ++ ++static int macsmc_gpio_key(unsigned int offset) ++{ ++ return _SMC_KEY("gP\0\0") | (hex_asc_hi(offset) << 8) | hex_asc_lo(offset); ++} ++ ++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); ++ u32 val; ++ int ret; ++ ++ /* First try reading the explicit pin mode register */ ++ ret = apple_smc_rw_u32(smcgp->smc, key, CMD_PINMODE, &val); ++ if (!ret) ++ return (val & MODE_OUTPUT) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; ++ ++ /* ++ * Less common IRQ configs cause CMD_PINMODE to fail, and so does open drain mode. ++ * Fall back to reading IRQ mode, which will only succeed for inputs. ++ */ ++ ret = apple_smc_rw_u32(smcgp->smc, key, CMD_IRQ_MODE, &val); ++ return (!ret) ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; ++} ++ ++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); ++ u32 val; ++ int ret; ++ ++ ret = macsmc_gpio_get_direction(gc, offset); ++ if (ret < 0) ++ return ret; ++ ++ if (ret == GPIO_LINE_DIRECTION_OUT) ++ ret = apple_smc_rw_u32(smcgp->smc, key, CMD_OUTPUT, &val); ++ else ++ ret = apple_smc_rw_u32(smcgp->smc, key, CMD_INPUT, &val); ++ ++ if (ret < 0) ++ return ret; ++ ++ return val ? 1 : 0; ++} ++ ++static void 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); ++ int ret; ++ ++ value |= CMD_OUTPUT; ++ ret = apple_smc_write_u32(smcgp->smc, key, CMD_OUTPUT | value); ++ if (ret < 0) ++ dev_err(smcgp->dev, "GPIO set failed %p4ch = 0x%x\n", &key, value); ++} ++ ++static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc, ++ unsigned long *valid_mask, unsigned int ngpios) ++{ ++ struct macsmc_gpio *smcgp = gpiochip_get_data(gc); ++ int count = apple_smc_get_key_count(smcgp->smc) - smcgp->first_index; ++ int i; ++ ++ if (count > MAX_GPIO) ++ count = MAX_GPIO; ++ ++ bitmap_zero(valid_mask, ngpios); ++ ++ for (i = 0; i < count; i++) { ++ smc_key key; ++ int gpio_nr; ++ int ret = apple_smc_get_key_by_index(smcgp->smc, smcgp->first_index + i, &key); ++ ++ if (ret < 0) ++ return ret; ++ ++ if (key > SMC_KEY(gPff)) ++ break; ++ ++ gpio_nr = macsmc_gpio_nr(key); ++ if (gpio_nr < 0 || gpio_nr > MAX_GPIO) { ++ dev_err(smcgp->dev, "Bad GPIO key %p4ch\n", &key); ++ continue; ++ } ++ ++ set_bit(gpio_nr, valid_mask); ++ } ++ ++ return 0; ++} ++ ++static int macsmc_gpio_probe(struct platform_device *pdev) ++{ ++ struct macsmc_gpio *smcgp; ++ struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); ++ smc_key key; ++ int ret; ++ ++ smcgp = devm_kzalloc(&pdev->dev, sizeof(*smcgp), GFP_KERNEL); ++ if (!smcgp) ++ return -ENOMEM; ++ ++ pdev->dev.of_node = of_get_child_by_name(pdev->dev.parent->of_node, "gpio"); ++ ++ smcgp->dev = &pdev->dev; ++ smcgp->smc = smc; ++ smcgp->first_index = apple_smc_find_first_key_index(smc, SMC_KEY(gP00)); ++ ++ if (smcgp->first_index >= apple_smc_get_key_count(smc)) ++ return -ENODEV; ++ ++ ret = apple_smc_get_key_by_index(smc, smcgp->first_index, &key); ++ if (ret < 0) ++ return ret; ++ ++ if (key > macsmc_gpio_key(MAX_GPIO - 1)) ++ return -ENODEV; ++ ++ dev_info(smcgp->dev, "First GPIO key: %p4ch\n", &key); ++ ++ smcgp->gc.label = "macsmc-pmu-gpio"; ++ smcgp->gc.owner = THIS_MODULE; ++ smcgp->gc.get = macsmc_gpio_get; ++ smcgp->gc.set = macsmc_gpio_set; ++ smcgp->gc.get_direction = macsmc_gpio_get_direction; ++ smcgp->gc.init_valid_mask = macsmc_gpio_init_valid_mask; ++ smcgp->gc.can_sleep = true; ++ smcgp->gc.ngpio = MAX_GPIO; ++ smcgp->gc.base = -1; ++ smcgp->gc.parent = &pdev->dev; ++ ++ return devm_gpiochip_add_data(&pdev->dev, &smcgp->gc, smcgp); ++} ++ ++static struct platform_driver macsmc_gpio_driver = { ++ .driver = { ++ .name = "macsmc-gpio", ++ }, ++ .probe = macsmc_gpio_probe, ++}; ++module_platform_driver(macsmc_gpio_driver); ++ ++MODULE_AUTHOR("Hector Martin "); ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple SMC GPIO driver"); ++MODULE_ALIAS("platform:macsmc-gpio"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0140-power-supply-macsmc_power-Driver-for-Apple-SMC-power.patch b/target/linux/silicon/patches-5.19/0140-power-supply-macsmc_power-Driver-for-Apple-SMC-power.patch new file mode 100644 index 000000000..01b1cd008 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0140-power-supply-macsmc_power-Driver-for-Apple-SMC-power.patch @@ -0,0 +1,311 @@ +From 908ad4e5e4a9fbac940cc4f03f51e5adc6a01dbf Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 8 Feb 2022 02:30:16 +0900 +Subject: [PATCH 140/171] power: supply: macsmc_power: Driver for Apple SMC + power/battery stats + +This driver implements support for battery stats on top of the macsmc +framework, to support Apple M1 Mac machines. + +Co-authored-by: Joey Gouly +Signed-off-by: Hector Martin +--- + drivers/power/supply/Kconfig | 7 + + drivers/power/supply/Makefile | 1 + + drivers/power/supply/macsmc_power.c | 259 ++++++++++++++++++++++++++++ + 3 files changed, 267 insertions(+) + create mode 100644 drivers/power/supply/macsmc_power.c + +diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig +index 1aa8323ad9f6..780941701795 100644 +--- a/drivers/power/supply/Kconfig ++++ b/drivers/power/supply/Kconfig +@@ -897,4 +897,11 @@ config BATTERY_UG3105 + device is off or suspended, the functionality of this driver is + limited to reporting capacity only. + ++config CHARGER_MACSMC ++ tristate "Apple SMC Charger / Battery support" ++ depends on APPLE_SMC ++ help ++ Say Y here to enable support for the charger and battery controls on ++ Apple SMC controllers, as used on Apple Silicon Macs. ++ + endif # POWER_SUPPLY +diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile +index 7f02f36aea55..bba0c6ad4101 100644 +--- a/drivers/power/supply/Makefile ++++ b/drivers/power/supply/Makefile +@@ -108,3 +108,4 @@ obj-$(CONFIG_BATTERY_ACER_A500) += acer_a500_battery.o + obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o + obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o + obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o ++obj-$(CONFIG_CHARGER_MACSMC) += macsmc_power.o +diff --git a/drivers/power/supply/macsmc_power.c b/drivers/power/supply/macsmc_power.c +new file mode 100644 +index 000000000000..140526a963b6 +--- /dev/null ++++ b/drivers/power/supply/macsmc_power.c +@@ -0,0 +1,259 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC Power/Battery Management ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STRING_LENGTH 256 ++ ++struct macsmc_power { ++ struct device *dev; ++ struct apple_smc *smc; ++ struct power_supply *psy; ++ char model_name[MAX_STRING_LENGTH]; ++ char serial_number[MAX_STRING_LENGTH]; ++ ++ struct notifier_block nb; ++}; ++ ++static int macsmc_battery_get_status(struct macsmc_power *power) ++{ ++ u8 val; ++ int ret; ++ ++ ret = apple_smc_read_u8(power->smc, SMC_KEY(BSFC), &val); ++ if (ret) ++ return ret; ++ if (val == 1) ++ return POWER_SUPPLY_STATUS_FULL; ++ ++ ret = apple_smc_read_u8(power->smc, SMC_KEY(CHSC), &val); ++ if (ret) ++ return ret; ++ if (val == 1) ++ return POWER_SUPPLY_STATUS_CHARGING; ++ ++ ret = apple_smc_read_u8(power->smc, SMC_KEY(CHCC), &val); ++ if (ret) ++ return ret; ++ if (val == 0) ++ return POWER_SUPPLY_STATUS_DISCHARGING; ++ ++ ret = apple_smc_read_u8(power->smc, SMC_KEY(CHCE), &val); ++ if (ret) ++ return ret; ++ if (val == 0) ++ return POWER_SUPPLY_STATUS_DISCHARGING; ++ else ++ return POWER_SUPPLY_STATUS_NOT_CHARGING; ++ ++ ++} ++ ++static int macsmc_battery_get_property(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ struct macsmc_power *power = power_supply_get_drvdata(psy); ++ int ret = 0; ++ u16 vu16; ++ u32 vu32; ++ s16 vs16; ++ s32 vs32; ++ s64 vs64; ++ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_STATUS: ++ val->intval = macsmc_battery_get_status(power); ++ ret = val->intval < 0 ? val->intval : 0; ++ break; ++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0TE), &vu16); ++ val->intval = vu16 == 0xffff ? 0 : vu16 * 60; ++ break; ++ case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0TF), &vu16); ++ val->intval = vu16 == 0xffff ? 0 : vu16 * 60; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(BRSC), &vu16); ++ val->intval = vu16; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ ret = apple_smc_read_s16(power->smc, SMC_KEY(B0AC), &vs16); ++ val->intval = vs16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_POWER_NOW: ++ ret = apple_smc_read_s32(power->smc, SMC_KEY(B0AP), &vs32); ++ val->intval = vs32 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(BITV), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RC), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: ++ ret = apple_smc_read_u32(power->smc, SMC_KEY(CSIL), &vu32); ++ val->intval = vu32 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RI), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RV), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0DC), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0FC), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_NOW: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16); ++ val->intval = swab16(vu16) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_TEMP: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AT), &vu16); ++ val->intval = vu16 - 2732; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_COUNTER: ++ ret = apple_smc_read_s64(power->smc, SMC_KEY(BAAC), &vs64); ++ val->intval = vs64; ++ break; ++ case POWER_SUPPLY_PROP_MODEL_NAME: ++ val->strval = power->model_name; ++ break; ++ case POWER_SUPPLY_PROP_SERIAL_NUMBER: ++ val->strval = power->serial_number; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static enum power_supply_property macsmc_battery_props[] = { ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, ++ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_POWER_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, ++ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, ++ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, ++ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL, ++ POWER_SUPPLY_PROP_CHARGE_NOW, ++ POWER_SUPPLY_PROP_TEMP, ++ POWER_SUPPLY_PROP_CHARGE_COUNTER, ++ POWER_SUPPLY_PROP_MODEL_NAME, ++ POWER_SUPPLY_PROP_SERIAL_NUMBER, ++}; ++ ++static const struct power_supply_desc macsmc_battery_desc = { ++ .name = "macsmc-battery", ++ .type = POWER_SUPPLY_TYPE_BATTERY, ++ .get_property = macsmc_battery_get_property, ++ .properties = macsmc_battery_props, ++ .num_properties = ARRAY_SIZE(macsmc_battery_props), ++}; ++ ++static int macsmc_power_event(struct notifier_block *nb, unsigned long event, void *data) ++{ ++ struct macsmc_power *power = container_of(nb, struct macsmc_power, nb); ++ ++ if ((event & 0xffffff00) == 0x71010100) { ++ bool charging = (event & 0xff) != 0; ++ ++ dev_info(power->dev, "Charging: %d\n", charging); ++ power_supply_changed(power->psy); ++ ++ return NOTIFY_OK; ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static int macsmc_power_probe(struct platform_device *pdev) ++{ ++ struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); ++ struct power_supply_config psy_cfg = {}; ++ struct macsmc_power *power; ++ int ret; ++ ++ power = devm_kzalloc(&pdev->dev, sizeof(*power), GFP_KERNEL); ++ if (!power) ++ return -ENOMEM; ++ ++ power->dev = &pdev->dev; ++ power->smc = smc; ++ dev_set_drvdata(&pdev->dev, power); ++ ++ /* Ignore devices without a charger/battery */ ++ if (macsmc_battery_get_status(power) <= POWER_SUPPLY_STATUS_UNKNOWN) ++ return -ENODEV; ++ ++ /* Fetch string properties */ ++ apple_smc_read(smc, SMC_KEY(BMDN), power->model_name, sizeof(power->model_name) - 1); ++ apple_smc_read(smc, SMC_KEY(BMSN), power->serial_number, sizeof(power->serial_number) - 1); ++ ++ psy_cfg.drv_data = power; ++ power->psy = devm_power_supply_register(&pdev->dev, &macsmc_battery_desc, &psy_cfg); ++ if (IS_ERR(power->psy)) { ++ dev_err(&pdev->dev, "Failed to register power supply\n"); ++ ret = PTR_ERR(power->psy); ++ return ret; ++ } ++ ++ power->nb.notifier_call = macsmc_power_event; ++ apple_smc_register_notifier(power->smc, &power->nb); ++ ++ return 0; ++} ++ ++static int macsmc_power_remove(struct platform_device *pdev) ++{ ++ struct macsmc_power *power = dev_get_drvdata(&pdev->dev); ++ ++ apple_smc_unregister_notifier(power->smc, &power->nb); ++ ++ return 0; ++} ++ ++static struct platform_driver macsmc_power_driver = { ++ .driver = { ++ .name = "macsmc-power", ++ .owner = THIS_MODULE, ++ }, ++ .probe = macsmc_power_probe, ++ .remove = macsmc_power_remove, ++}; ++module_platform_driver(macsmc_power_driver); ++ ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple SMC battery and power management driver"); ++MODULE_AUTHOR("Hector Martin "); ++MODULE_ALIAS("platform:macsmc-power"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0141-power-supply-macsmc_power-Add-cycle-count-and-health.patch b/target/linux/silicon/patches-5.19/0141-power-supply-macsmc_power-Add-cycle-count-and-health.patch new file mode 100644 index 000000000..07a2a0385 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0141-power-supply-macsmc_power-Add-cycle-count-and-health.patch @@ -0,0 +1,43 @@ +From 69645c0ba065a4414d633f62fb100e9ae2471fbb Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 8 Feb 2022 02:51:35 +0900 +Subject: [PATCH 141/171] power: supply: macsmc_power: Add cycle count and + health props + +Signed-off-by: Hector Martin +--- + drivers/power/supply/macsmc_power.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/power/supply/macsmc_power.c b/drivers/power/supply/macsmc_power.c +index 140526a963b6..6c939371912a 100644 +--- a/drivers/power/supply/macsmc_power.c ++++ b/drivers/power/supply/macsmc_power.c +@@ -138,6 +138,15 @@ static int macsmc_battery_get_property(struct power_supply *psy, + ret = apple_smc_read_s64(power->smc, SMC_KEY(BAAC), &vs64); + val->intval = vs64; + break; ++ case POWER_SUPPLY_PROP_CYCLE_COUNT: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(B0CT), &vu16); ++ val->intval = vu16; ++ break; ++ case POWER_SUPPLY_PROP_HEALTH: ++ ret = apple_smc_read_flag(power->smc, SMC_KEY(BBAD)); ++ val->intval = ret == 1 ? POWER_SUPPLY_HEALTH_DEAD : POWER_SUPPLY_HEALTH_GOOD; ++ ret = ret < 0 ? ret : 0; ++ break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = power->model_name; + break; +@@ -169,6 +178,8 @@ static enum power_supply_property macsmc_battery_props[] = { + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CHARGE_COUNTER, ++ POWER_SUPPLY_PROP_CYCLE_COUNT, ++ POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_SERIAL_NUMBER, + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0142-power-supply-macsmc_power-Add-present-prop.patch b/target/linux/silicon/patches-5.19/0142-power-supply-macsmc_power-Add-present-prop.patch new file mode 100644 index 000000000..b2f65566f --- /dev/null +++ b/target/linux/silicon/patches-5.19/0142-power-supply-macsmc_power-Add-present-prop.patch @@ -0,0 +1,35 @@ +From 912e600cd309a1c3ddc6a5166c6d5585dee915ff Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 8 Feb 2022 11:01:17 +0900 +Subject: [PATCH 142/171] power: supply: macsmc_power: Add present prop + +Signed-off-by: Hector Martin +--- + drivers/power/supply/macsmc_power.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/power/supply/macsmc_power.c b/drivers/power/supply/macsmc_power.c +index 6c939371912a..aa67762144d8 100644 +--- a/drivers/power/supply/macsmc_power.c ++++ b/drivers/power/supply/macsmc_power.c +@@ -74,6 +74,9 @@ static int macsmc_battery_get_property(struct power_supply *psy, + val->intval = macsmc_battery_get_status(power); + ret = val->intval < 0 ? val->intval : 0; + break; ++ case POWER_SUPPLY_PROP_PRESENT: ++ val->intval = 1; ++ break; + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: + ret = apple_smc_read_u16(power->smc, SMC_KEY(B0TE), &vu16); + val->intval = vu16 == 0xffff ? 0 : vu16 * 60; +@@ -162,6 +165,7 @@ static int macsmc_battery_get_property(struct power_supply *psy, + + static enum power_supply_property macsmc_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_CAPACITY, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0143-power-supply-macsmc_power-Add-more-props-rework-othe.patch b/target/linux/silicon/patches-5.19/0143-power-supply-macsmc_power-Add-more-props-rework-othe.patch new file mode 100644 index 000000000..0cf845e53 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0143-power-supply-macsmc_power-Add-more-props-rework-othe.patch @@ -0,0 +1,334 @@ +From 2226f112885322e19b76f56acef517bea6bd399c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 02:20:20 +0900 +Subject: [PATCH 143/171] power: supply: macsmc_power: Add more props, rework + others + +Signed-off-by: Hector Martin +--- + drivers/power/supply/macsmc_power.c | 224 +++++++++++++++++++++++++--- + 1 file changed, 202 insertions(+), 22 deletions(-) + +diff --git a/drivers/power/supply/macsmc_power.c b/drivers/power/supply/macsmc_power.c +index aa67762144d8..2cb1644055f4 100644 +--- a/drivers/power/supply/macsmc_power.c ++++ b/drivers/power/supply/macsmc_power.c +@@ -4,6 +4,7 @@ + * Copyright The Asahi Linux Contributors + */ + ++#include + #include + #include + #include +@@ -19,50 +20,178 @@ struct macsmc_power { + struct power_supply *psy; + char model_name[MAX_STRING_LENGTH]; + char serial_number[MAX_STRING_LENGTH]; ++ char mfg_date[MAX_STRING_LENGTH]; + + struct notifier_block nb; + }; + ++#define CHNC_BATTERY_FULL BIT(0) ++#define CHNC_NO_CHARGER BIT(7) ++#define CHNC_NOCHG_CH0C BIT(14) ++#define CHNC_NOCHG_CH0B_CH0K BIT(15) ++#define CHNC_BATTERY_FULL_2 BIT(18) ++#define CHNC_BMS_BUSY BIT(23) ++#define CHNC_NOAC_CH0J BIT(53) ++#define CHNC_NOAC_CH0I BIT(54) ++ ++#define CH0R_LOWER_FLAGS GENMASK(15, 0) ++#define CH0R_NOAC_CH0I BIT(0) ++#define CH0R_NOAC_CH0J BIT(5) ++#define CH0R_BMS_BUSY BIT(8) ++#define CH0R_NOAC_CH0K BIT(9) ++ ++#define CH0X_CH0C BIT(0) ++#define CH0X_CH0B BIT(1) ++ + static int macsmc_battery_get_status(struct macsmc_power *power) + { +- u8 val; ++ u64 nocharge_flags; ++ u32 nopower_flags; ++ u16 ac_current; + int ret; + +- ret = apple_smc_read_u8(power->smc, SMC_KEY(BSFC), &val); +- if (ret) ++ /* ++ * Note: there are fallbacks in case some of these SMC keys disappear in the future ++ * or are not present on some machines. We treat the absence of the CHCE/CHCC/BSFC/CHSC ++ * flags as an error, since they are quite fundamental and simple booleans. ++ */ ++ ++ /* ++ * If power input is inhibited, we are definitely discharging. ++ * However, if the only reason is the BMS is doing a balancing cycle, ++ * go ahead and ignore that one to avoid spooking users. ++ */ ++ ret = apple_smc_read_u32(power->smc, SMC_KEY(CH0R), &nopower_flags); ++ if (!ret && (nopower_flags & CH0R_LOWER_FLAGS & ~CH0R_BMS_BUSY)) ++ return POWER_SUPPLY_STATUS_DISCHARGING; ++ ++ /* If no charger is present, we are definitely discharging. */ ++ ret = apple_smc_read_flag(power->smc, SMC_KEY(CHCE)); ++ if (ret < 0) ++ return ret; ++ else if (!ret) ++ return POWER_SUPPLY_STATUS_DISCHARGING; ++ ++ /* If AC is not charge capable, we are definitely discharging. */ ++ ret = apple_smc_read_flag(power->smc, SMC_KEY(CHCC)); ++ if (ret < 0) + return ret; +- if (val == 1) ++ else if (!ret) ++ return POWER_SUPPLY_STATUS_DISCHARGING; ++ ++ /* ++ * If the AC input current limit is tiny or 0, we are discharging no matter ++ * how much the BMS believes it can charge. ++ */ ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-i), &ac_current); ++ if (!ret && ac_current < 100) ++ return POWER_SUPPLY_STATUS_DISCHARGING; ++ ++ /* If the battery is full, report it as such. */ ++ ret = apple_smc_read_flag(power->smc, SMC_KEY(BSFC)); ++ if (ret < 0) ++ return ret; ++ else if (ret) + return POWER_SUPPLY_STATUS_FULL; + +- ret = apple_smc_read_u8(power->smc, SMC_KEY(CHSC), &val); +- if (ret) ++ /* If there are reasons we aren't charging... */ ++ ret = apple_smc_read_u64(power->smc, SMC_KEY(CHNC), &nocharge_flags); ++ if (!ret) { ++ /* Perhaps the battery is full after all */ ++ if (nocharge_flags & CHNC_BATTERY_FULL) ++ return POWER_SUPPLY_STATUS_FULL; ++ /* Or maybe the BMS is just busy doing something, if so call it charging anyway */ ++ else if (nocharge_flags == CHNC_BMS_BUSY) ++ return POWER_SUPPLY_STATUS_CHARGING; ++ /* If we have other reasons we aren't charging, say we aren't */ ++ else if (nocharge_flags) ++ return POWER_SUPPLY_STATUS_NOT_CHARGING; ++ /* Else we're either charging or about to charge */ ++ else ++ return POWER_SUPPLY_STATUS_CHARGING; ++ } ++ ++ /* As a fallback, use the system charging flag. */ ++ ret = apple_smc_read_flag(power->smc, SMC_KEY(CHSC)); ++ if (ret < 0) + return ret; +- if (val == 1) ++ if (!ret) ++ return POWER_SUPPLY_STATUS_NOT_CHARGING; ++ else + return POWER_SUPPLY_STATUS_CHARGING; ++} + +- ret = apple_smc_read_u8(power->smc, SMC_KEY(CHCC), &val); ++static int macsmc_battery_get_charge_behaviour(struct macsmc_power *power) ++{ ++ int ret; ++ u8 val; ++ ++ /* CH0I returns a bitmask like the low byte of CH0R */ ++ ret = apple_smc_read_u8(power->smc, SMC_KEY(CH0I), &val); + if (ret) + return ret; +- if (val == 0) +- return POWER_SUPPLY_STATUS_DISCHARGING; ++ if (val & CH0R_NOAC_CH0I) ++ return POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE; + +- ret = apple_smc_read_u8(power->smc, SMC_KEY(CHCE), &val); ++ /* CH0C returns a bitmask containing CH0B/CH0C flags */ ++ ret = apple_smc_read_u8(power->smc, SMC_KEY(CH0C), &val); + if (ret) + return ret; +- if (val == 0) +- return POWER_SUPPLY_STATUS_DISCHARGING; ++ if (val & CH0X_CH0C) ++ return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; + else +- return POWER_SUPPLY_STATUS_NOT_CHARGING; ++ return POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; ++} + +- ++static int macsmc_battery_set_charge_behaviour(struct macsmc_power *power, int val) ++{ ++ u8 ch0i, ch0c; ++ int ret; ++ ++ /* ++ * CH0I/CH0C are "hard" controls that will allow the battery to run down to 0. ++ * CH0K/CH0B are "soft" controls that are reset to 0 when SOC drops below 50%; ++ * we don't expose these yet. ++ */ ++ ++ switch (val) { ++ case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: ++ ch0i = ch0c = 0; ++ break; ++ case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: ++ ch0i = 0; ++ ch0c = 1; ++ break; ++ case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE: ++ ch0i = 1; ++ ch0c = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ret = apple_smc_write_u8(power->smc, SMC_KEY(CH0I), ch0i); ++ if (ret) ++ return ret; ++ return apple_smc_write_u8(power->smc, SMC_KEY(CH0C), ch0c); ++} ++ ++static int macsmc_battery_get_date(const char *s, int *out) ++{ ++ if (!isdigit(s[0]) || !isdigit(s[1])) ++ return -ENOTSUPP; ++ ++ *out = (s[0] - '0') * 10 + s[1] - '0'; ++ return 0; + } + + static int macsmc_battery_get_property(struct power_supply *psy, +- enum power_supply_property psp, +- union power_supply_propval *val) ++ enum power_supply_property psp, ++ union power_supply_propval *val) + { + struct macsmc_power *power = power_supply_get_drvdata(psy); + int ret = 0; ++ u8 vu8; + u16 vu16; + u32 vu32; + s16 vs16; +@@ -77,6 +206,10 @@ static int macsmc_battery_get_property(struct power_supply *psy, + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + break; ++ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: ++ val->intval = macsmc_battery_get_charge_behaviour(power); ++ ret = val->intval < 0 ? val->intval : 0; ++ break; + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: + ret = apple_smc_read_u16(power->smc, SMC_KEY(B0TE), &vu16); + val->intval = vu16 == 0xffff ? 0 : vu16 * 60; +@@ -145,6 +278,9 @@ static int macsmc_battery_get_property(struct power_supply *psy, + ret = apple_smc_read_u16(power->smc, SMC_KEY(B0CT), &vu16); + val->intval = vu16; + break; ++ case POWER_SUPPLY_PROP_SCOPE: ++ val->intval = POWER_SUPPLY_SCOPE_SYSTEM; ++ break; + case POWER_SUPPLY_PROP_HEALTH: + ret = apple_smc_read_flag(power->smc, SMC_KEY(BBAD)); + val->intval = ret == 1 ? POWER_SUPPLY_HEALTH_DEAD : POWER_SUPPLY_HEALTH_GOOD; +@@ -156,6 +292,16 @@ static int macsmc_battery_get_property(struct power_supply *psy, + case POWER_SUPPLY_PROP_SERIAL_NUMBER: + val->strval = power->serial_number; + break; ++ case POWER_SUPPLY_PROP_MANUFACTURE_YEAR: ++ ret = macsmc_battery_get_date(&power->mfg_date[0], &val->intval); ++ val->intval += 2000 - 8; /* -8 is a fixup for a firmware bug... */ ++ break; ++ case POWER_SUPPLY_PROP_MANUFACTURE_MONTH: ++ ret = macsmc_battery_get_date(&power->mfg_date[2], &val->intval); ++ break; ++ case POWER_SUPPLY_PROP_MANUFACTURE_DAY: ++ ret = macsmc_battery_get_date(&power->mfg_date[4], &val->intval); ++ break; + default: + return -EINVAL; + } +@@ -163,9 +309,36 @@ static int macsmc_battery_get_property(struct power_supply *psy, + return ret; + } + ++static int macsmc_battery_set_property(struct power_supply *psy, ++ enum power_supply_property psp, ++ const union power_supply_propval *val) ++{ ++ struct macsmc_power *power = power_supply_get_drvdata(psy); ++ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: ++ return macsmc_battery_set_charge_behaviour(power, val->intval); ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int macsmc_battery_property_is_writeable(struct power_supply *psy, ++ enum power_supply_property psp) ++{ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++ + static enum power_supply_property macsmc_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_CAPACITY, +@@ -183,17 +356,23 @@ static enum power_supply_property macsmc_battery_props[] = { + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_CYCLE_COUNT, ++ POWER_SUPPLY_PROP_SCOPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_SERIAL_NUMBER, ++ POWER_SUPPLY_PROP_MANUFACTURE_YEAR, ++ POWER_SUPPLY_PROP_MANUFACTURE_MONTH, ++ POWER_SUPPLY_PROP_MANUFACTURE_DAY, + }; + + static const struct power_supply_desc macsmc_battery_desc = { +- .name = "macsmc-battery", +- .type = POWER_SUPPLY_TYPE_BATTERY, +- .get_property = macsmc_battery_get_property, +- .properties = macsmc_battery_props, +- .num_properties = ARRAY_SIZE(macsmc_battery_props), ++ .name = "macsmc-battery", ++ .type = POWER_SUPPLY_TYPE_BATTERY, ++ .get_property = macsmc_battery_get_property, ++ .set_property = macsmc_battery_set_property, ++ .property_is_writeable = macsmc_battery_property_is_writeable, ++ .properties = macsmc_battery_props, ++ .num_properties = ARRAY_SIZE(macsmc_battery_props), + }; + + static int macsmc_power_event(struct notifier_block *nb, unsigned long event, void *data) +@@ -234,6 +413,7 @@ static int macsmc_power_probe(struct platform_device *pdev) + /* Fetch string properties */ + apple_smc_read(smc, SMC_KEY(BMDN), power->model_name, sizeof(power->model_name) - 1); + apple_smc_read(smc, SMC_KEY(BMSN), power->serial_number, sizeof(power->serial_number) - 1); ++ apple_smc_read(smc, SMC_KEY(BMDT), power->mfg_date, sizeof(power->mfg_date) - 1); + + psy_cfg.drv_data = power; + power->psy = devm_power_supply_register(&pdev->dev, &macsmc_battery_desc, &psy_cfg); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0144-power-supply-macsmc_power-Use-BUIC-instead-of-BRSC-f.patch b/target/linux/silicon/patches-5.19/0144-power-supply-macsmc_power-Use-BUIC-instead-of-BRSC-f.patch new file mode 100644 index 000000000..d17ff930c --- /dev/null +++ b/target/linux/silicon/patches-5.19/0144-power-supply-macsmc_power-Use-BUIC-instead-of-BRSC-f.patch @@ -0,0 +1,29 @@ +From 6ebbef164bb9db227e141d704f3e62fe98cfbea6 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 02:23:33 +0900 +Subject: [PATCH 144/171] power: supply: macsmc_power: Use BUIC instead of BRSC + for charge + +Signed-off-by: Hector Martin +--- + drivers/power/supply/macsmc_power.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/power/supply/macsmc_power.c b/drivers/power/supply/macsmc_power.c +index 2cb1644055f4..b9aa6af32104 100644 +--- a/drivers/power/supply/macsmc_power.c ++++ b/drivers/power/supply/macsmc_power.c +@@ -219,8 +219,8 @@ static int macsmc_battery_get_property(struct power_supply *psy, + val->intval = vu16 == 0xffff ? 0 : vu16 * 60; + break; + case POWER_SUPPLY_PROP_CAPACITY: +- ret = apple_smc_read_u16(power->smc, SMC_KEY(BRSC), &vu16); +- val->intval = vu16; ++ ret = apple_smc_read_u8(power->smc, SMC_KEY(BUIC), &vu8); ++ val->intval = vu8; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &vu16); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0145-power-supply-macsmc_power-Turn-off-OBC-flags-if-macO.patch b/target/linux/silicon/patches-5.19/0145-power-supply-macsmc_power-Turn-off-OBC-flags-if-macO.patch new file mode 100644 index 000000000..7ce68c191 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0145-power-supply-macsmc_power-Turn-off-OBC-flags-if-macO.patch @@ -0,0 +1,29 @@ +From ee6f25f23ff2820d11bc7a4afcf99518359e1c8d Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 02:24:13 +0900 +Subject: [PATCH 145/171] power: supply: macsmc_power: Turn off OBC flags if + macOS left them on + +Signed-off-by: Hector Martin +--- + drivers/power/supply/macsmc_power.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/power/supply/macsmc_power.c b/drivers/power/supply/macsmc_power.c +index b9aa6af32104..4a8a90b775dd 100644 +--- a/drivers/power/supply/macsmc_power.c ++++ b/drivers/power/supply/macsmc_power.c +@@ -415,6 +415,10 @@ static int macsmc_power_probe(struct platform_device *pdev) + apple_smc_read(smc, SMC_KEY(BMSN), power->serial_number, sizeof(power->serial_number) - 1); + apple_smc_read(smc, SMC_KEY(BMDT), power->mfg_date, sizeof(power->mfg_date) - 1); + ++ /* Turn off the "optimized battery charging" flags, in case macOS left them on */ ++ apple_smc_write_u8(power->smc, SMC_KEY(CH0K), 0); ++ apple_smc_write_u8(power->smc, SMC_KEY(CH0B), 0); ++ + psy_cfg.drv_data = power; + power->psy = devm_power_supply_register(&pdev->dev, &macsmc_battery_desc, &psy_cfg); + if (IS_ERR(power->psy)) { +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0146-power-supply-macsmc_power-Add-AC-power-supply.patch b/target/linux/silicon/patches-5.19/0146-power-supply-macsmc_power-Add-AC-power-supply.patch new file mode 100644 index 000000000..c5da0cefb --- /dev/null +++ b/target/linux/silicon/patches-5.19/0146-power-supply-macsmc_power-Add-AC-power-supply.patch @@ -0,0 +1,137 @@ +From 58a6709f62008f3210799c906767c7c51aec5e75 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 02:24:42 +0900 +Subject: [PATCH 146/171] power: supply: macsmc_power: Add AC power supply + +Signed-off-by: Hector Martin +--- + drivers/power/supply/macsmc_power.c | 74 +++++++++++++++++++++++++---- + 1 file changed, 66 insertions(+), 8 deletions(-) + +diff --git a/drivers/power/supply/macsmc_power.c b/drivers/power/supply/macsmc_power.c +index 4a8a90b775dd..dee48ee8b5a4 100644 +--- a/drivers/power/supply/macsmc_power.c ++++ b/drivers/power/supply/macsmc_power.c +@@ -17,11 +17,14 @@ + struct macsmc_power { + struct device *dev; + struct apple_smc *smc; +- struct power_supply *psy; ++ ++ struct power_supply *batt; + char model_name[MAX_STRING_LENGTH]; + char serial_number[MAX_STRING_LENGTH]; + char mfg_date[MAX_STRING_LENGTH]; + ++ struct power_supply *ac; ++ + struct notifier_block nb; + }; + +@@ -49,7 +52,7 @@ static int macsmc_battery_get_status(struct macsmc_power *power) + u32 nopower_flags; + u16 ac_current; + int ret; +- ++ + /* + * Note: there are fallbacks in case some of these SMC keys disappear in the future + * or are not present on some machines. We treat the absence of the CHCE/CHCC/BSFC/CHSC +@@ -334,7 +337,6 @@ static int macsmc_battery_property_is_writeable(struct power_supply *psy, + } + } + +- + static enum power_supply_property macsmc_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, +@@ -375,6 +377,54 @@ static const struct power_supply_desc macsmc_battery_desc = { + .num_properties = ARRAY_SIZE(macsmc_battery_props), + }; + ++static int macsmc_ac_get_property(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ struct macsmc_power *power = power_supply_get_drvdata(psy); ++ int ret = 0; ++ u16 vu16; ++ u32 vu32; ++ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_ONLINE: ++ ret = apple_smc_read_u32(power->smc, SMC_KEY(CHIS), &vu32); ++ val->intval = !!vu32; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-n), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: ++ ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-i), &vu16); ++ val->intval = vu16 * 1000; ++ break; ++ case POWER_SUPPLY_PROP_INPUT_POWER_LIMIT: ++ ret = apple_smc_read_u32(power->smc, SMC_KEY(ACPW), &vu32); ++ val->intval = vu32 * 1000; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static enum power_supply_property macsmc_ac_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, ++ POWER_SUPPLY_PROP_INPUT_POWER_LIMIT, ++}; ++ ++static const struct power_supply_desc macsmc_ac_desc = { ++ .name = "macsmc-ac", ++ .type = POWER_SUPPLY_TYPE_MAINS, ++ .get_property = macsmc_ac_get_property, ++ .properties = macsmc_ac_props, ++ .num_properties = ARRAY_SIZE(macsmc_ac_props), ++}; ++ + static int macsmc_power_event(struct notifier_block *nb, unsigned long event, void *data) + { + struct macsmc_power *power = container_of(nb, struct macsmc_power, nb); +@@ -383,7 +433,8 @@ static int macsmc_power_event(struct notifier_block *nb, unsigned long event, vo + bool charging = (event & 0xff) != 0; + + dev_info(power->dev, "Charging: %d\n", charging); +- power_supply_changed(power->psy); ++ power_supply_changed(power->batt); ++ power_supply_changed(power->ac); + + return NOTIFY_OK; + } +@@ -420,10 +471,17 @@ static int macsmc_power_probe(struct platform_device *pdev) + apple_smc_write_u8(power->smc, SMC_KEY(CH0B), 0); + + psy_cfg.drv_data = power; +- power->psy = devm_power_supply_register(&pdev->dev, &macsmc_battery_desc, &psy_cfg); +- if (IS_ERR(power->psy)) { +- dev_err(&pdev->dev, "Failed to register power supply\n"); +- ret = PTR_ERR(power->psy); ++ power->batt = devm_power_supply_register(&pdev->dev, &macsmc_battery_desc, &psy_cfg); ++ if (IS_ERR(power->batt)) { ++ dev_err(&pdev->dev, "Failed to register battery\n"); ++ ret = PTR_ERR(power->batt); ++ return ret; ++ } ++ ++ power->ac = devm_power_supply_register(&pdev->dev, &macsmc_ac_desc, &psy_cfg); ++ if (IS_ERR(power->ac)) { ++ dev_err(&pdev->dev, "Failed to register AC adapter\n"); ++ ret = PTR_ERR(power->ac); + return ret; + } + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0147-power-reset-macsmc-reboot-Add-driver-for-rebooting-v.patch b/target/linux/silicon/patches-5.19/0147-power-reset-macsmc-reboot-Add-driver-for-rebooting-v.patch new file mode 100644 index 000000000..a0a241148 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0147-power-reset-macsmc-reboot-Add-driver-for-rebooting-v.patch @@ -0,0 +1,397 @@ +From 32182ce79a348bf794c87dfa649fd1e492aa4ad1 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 8 Feb 2022 19:17:40 +0900 +Subject: [PATCH 147/171] power: reset: macsmc-reboot: Add driver for rebooting + via Apple SMC + +This driver implements the reboot/shutdown support exposed by the SMC +on Apple Silicon machines, such as Apple M1 Macs. + +Signed-off-by: Hector Martin +--- + drivers/power/reset/Kconfig | 12 + + drivers/power/reset/Makefile | 1 + + drivers/power/reset/macsmc-reboot.c | 336 ++++++++++++++++++++++++++++ + 3 files changed, 349 insertions(+) + create mode 100644 drivers/power/reset/macsmc-reboot.c + +diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig +index 4b563db3ab3e..94eeb910e5f9 100644 +--- a/drivers/power/reset/Kconfig ++++ b/drivers/power/reset/Kconfig +@@ -117,6 +117,18 @@ config POWER_RESET_LINKSTATION + + Say Y here if you have a Buffalo LinkStation LS421D/E. + ++config POWER_RESET_MACSMC ++ tristate "Apple SMC reset/power-off driver" ++ depends on ARCH_APPLE || COMPILE_TEST ++ depends on APPLE_SMC ++ depends on OF ++ default ARCH_APPLE ++ help ++ This driver supports reset and power-off on Apple Mac machines ++ that implement this functionality via the SMC. ++ ++ Say Y here if you have an Apple Silicon Mac. ++ + config POWER_RESET_MSM + bool "Qualcomm MSM power-off driver" + depends on ARCH_QCOM +diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile +index f606a2f60539..ba49b8c0d0c0 100644 +--- a/drivers/power/reset/Makefile ++++ b/drivers/power/reset/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o + obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o + obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o + obj-$(CONFIG_POWER_RESET_LINKSTATION) += linkstation-poweroff.o ++obj-$(CONFIG_POWER_RESET_MACSMC) += macsmc-reboot.o + obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o + obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o + obj-$(CONFIG_POWER_RESET_OXNAS) += oxnas-restart.o +diff --git a/drivers/power/reset/macsmc-reboot.c b/drivers/power/reset/macsmc-reboot.c +new file mode 100644 +index 000000000000..c33ba2a7852d +--- /dev/null ++++ b/drivers/power/reset/macsmc-reboot.c +@@ -0,0 +1,336 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC Reboot/Poweroff Handler ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct macsmc_reboot_nvmem { ++ struct nvmem_cell *shutdown_flag; ++ struct nvmem_cell *pm_setting; ++ struct nvmem_cell *boot_stage; ++ struct nvmem_cell *boot_error_count; ++ struct nvmem_cell *panic_count; ++}; ++ ++static const char *nvmem_names[] = { ++ "shutdown_flag", ++ "pm_setting", ++ "boot_stage", ++ "boot_error_count", ++ "panic_count", ++}; ++ ++enum boot_stage { ++ BOOT_STAGE_SHUTDOWN = 0x00, /* Clean shutdown */ ++ BOOT_STAGE_IBOOT_DONE = 0x2f, /* Last stage of bootloader */ ++ BOOT_STAGE_KERNEL_STARTED = 0x30, /* Normal OS booting */ ++}; ++ ++enum pm_setting { ++ PM_SETTING_AC_POWER_RESTORE = 0x02, ++ PM_SETTING_AC_POWER_OFF = 0x03, ++}; ++ ++static const char *ac_power_modes[] = { "off", "restore" }; ++ ++static int ac_power_mode_map[] = { ++ PM_SETTING_AC_POWER_OFF, ++ PM_SETTING_AC_POWER_RESTORE, ++}; ++ ++struct macsmc_reboot { ++ struct device *dev; ++ struct apple_smc *smc; ++ struct notifier_block reboot_notify; ++ ++ union { ++ struct macsmc_reboot_nvmem nvm; ++ struct nvmem_cell *nvm_cells[ARRAY_SIZE(nvmem_names)]; ++ }; ++}; ++ ++/* Helpers to read/write a u8 given a struct nvmem_cell */ ++static int nvmem_cell_get_u8(struct nvmem_cell *cell) ++{ ++ size_t len; ++ u8 val; ++ void *ret = nvmem_cell_read(cell, &len); ++ ++ if (IS_ERR(ret)) ++ return PTR_ERR(ret); ++ ++ if (len < 1) { ++ kfree(ret); ++ return -EINVAL; ++ } ++ ++ val = *(u8 *)ret; ++ kfree(ret); ++ return val; ++} ++ ++static int nvmem_cell_set_u8(struct nvmem_cell *cell, u8 val) ++{ ++ return nvmem_cell_write(cell, &val, sizeof(val)); ++} ++ ++static ssize_t macsmc_ac_power_mode_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t n) ++{ ++ struct macsmc_reboot *reboot = dev_get_drvdata(dev); ++ int mode; ++ int ret; ++ ++ mode = sysfs_match_string(ac_power_modes, buf); ++ if (mode < 0) ++ return mode; ++ ++ ret = nvmem_cell_set_u8(reboot->nvm.pm_setting, ac_power_mode_map[mode]); ++ if (ret < 0) ++ return ret; ++ ++ return n; ++} ++ ++static ssize_t macsmc_ac_power_mode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct macsmc_reboot *reboot = dev_get_drvdata(dev); ++ int len = 0; ++ int i; ++ int mode = nvmem_cell_get_u8(reboot->nvm.pm_setting); ++ ++ if (mode < 0) ++ return mode; ++ ++ for (i = 0; i < ARRAY_SIZE(ac_power_mode_map); i++) ++ if (mode == ac_power_mode_map[i]) ++ len += scnprintf(buf+len, PAGE_SIZE-len, ++ "[%s] ", ac_power_modes[i]); ++ else ++ len += scnprintf(buf+len, PAGE_SIZE-len, ++ "%s ", ac_power_modes[i]); ++ buf[len-1] = '\n'; ++ return len; ++} ++static DEVICE_ATTR(ac_power_mode, 0644, macsmc_ac_power_mode_show, ++ macsmc_ac_power_mode_store); ++ ++/* ++ * SMC 'MBSE' key actions: ++ * ++ * 'offw' - shutdown warning ++ * 'slpw' - sleep warning ++ * 'rest' - restart warning ++ * 'off1' - shutdown (needs PMU bit set to stay on) ++ * 'susp' - suspend ++ * 'phra' - restart ("PE Halt Restart Action"?) ++ * 'panb' - panic beginning ++ * 'pane' - panic end ++ */ ++ ++static int macsmc_power_off(struct sys_off_data *data) ++{ ++ struct macsmc_reboot *reboot = data->cb_data; ++ ++ dev_info(reboot->dev, "Issuing power off (off1)\n"); ++ ++ if (apple_smc_write_u32_atomic(reboot->smc, SMC_KEY(MBSE), SMC_KEY(off1)) < 0) { ++ dev_err(reboot->dev, "Failed to issue MBSE = off1 (power_off)\n"); ++ } else { ++ mdelay(100); ++ WARN_ON(1); ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static int macsmc_restart(struct sys_off_data *data) ++{ ++ struct macsmc_reboot *reboot = data->cb_data; ++ ++ dev_info(reboot->dev, "Issuing restart (phra)\n"); ++ ++ if (apple_smc_write_u32_atomic(reboot->smc, SMC_KEY(MBSE), SMC_KEY(phra)) < 0) { ++ dev_err(reboot->dev, "Failed to issue MBSE = phra (restart)\n"); ++ } else { ++ mdelay(100); ++ WARN_ON(1); ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static int macsmc_reboot_notify(struct notifier_block *this, unsigned long action, void *data) ++{ ++ struct macsmc_reboot *reboot = container_of(this, struct macsmc_reboot, reboot_notify); ++ u32 val; ++ u8 shutdown_flag; ++ ++ switch (action) { ++ case SYS_RESTART: ++ val = SMC_KEY(rest); ++ shutdown_flag = 0; ++ break; ++ case SYS_POWER_OFF: ++ val = SMC_KEY(offw); ++ shutdown_flag = 1; ++ break; ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ dev_info(reboot->dev, "Preparing for reboot (%p4ch)\n", &val); ++ ++ /* On the Mac Mini, this will turn off the LED for power off */ ++ if (apple_smc_write_u32(reboot->smc, SMC_KEY(MBSE), val) < 0) ++ dev_err(reboot->dev, "Failed to issue MBSE = %p4ch (reboot_prepare)\n", &val); ++ ++ /* Set the boot_stage to 0, which means we're doing a clean shutdown/reboot. */ ++ if (reboot->nvm.boot_stage && ++ nvmem_cell_set_u8(reboot->nvm.boot_stage, BOOT_STAGE_SHUTDOWN) < 0) ++ dev_err(reboot->dev, "Failed to write boot_stage\n"); ++ ++ /* ++ * Set the PMU flag to actually reboot into the off state. ++ * Without this, the device will just reboot. We make it optional in case it is no longer ++ * necessary on newer hardware. ++ */ ++ if (reboot->nvm.shutdown_flag && ++ nvmem_cell_set_u8(reboot->nvm.shutdown_flag, shutdown_flag) < 0) ++ dev_err(reboot->dev, "Failed to write shutdown_flag\n"); ++ ++ return NOTIFY_OK; ++} ++ ++static void macsmc_power_init_error_counts(struct macsmc_reboot *reboot) ++{ ++ int boot_error_count, panic_count; ++ ++ if (!reboot->nvm.boot_error_count || !reboot->nvm.panic_count) ++ return; ++ ++ boot_error_count = nvmem_cell_get_u8(reboot->nvm.boot_error_count); ++ if (boot_error_count < 0) { ++ dev_err(reboot->dev, "Failed to read boot_error_count (%d)\n", boot_error_count); ++ return; ++ } ++ ++ panic_count = nvmem_cell_get_u8(reboot->nvm.panic_count); ++ if (panic_count < 0) { ++ dev_err(reboot->dev, "Failed to read panic_count (%d)\n", panic_count); ++ return; ++ } ++ ++ if (!boot_error_count && !panic_count) ++ return; ++ ++ dev_warn(reboot->dev, "PMU logged %d boot error(s) and %d panic(s)\n", ++ boot_error_count, panic_count); ++ ++ if (nvmem_cell_set_u8(reboot->nvm.panic_count, 0) < 0) ++ dev_err(reboot->dev, "Failed to reset panic_count\n"); ++ if (nvmem_cell_set_u8(reboot->nvm.boot_error_count, 0) < 0) ++ dev_err(reboot->dev, "Failed to reset boot_error_count\n"); ++} ++ ++static int macsmc_reboot_probe(struct platform_device *pdev) ++{ ++ struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); ++ struct macsmc_reboot *reboot; ++ int ret, i; ++ ++ /* Ignore devices without this functionality */ ++ if (!apple_smc_key_exists(smc, SMC_KEY(MBSE))) ++ return -ENODEV; ++ ++ reboot = devm_kzalloc(&pdev->dev, sizeof(*reboot), GFP_KERNEL); ++ if (!reboot) ++ return -ENOMEM; ++ ++ reboot->dev = &pdev->dev; ++ reboot->smc = smc; ++ ++ platform_set_drvdata(pdev, reboot); ++ ++ pdev->dev.of_node = of_get_child_by_name(pdev->dev.parent->of_node, "reboot"); ++ ++ for (i = 0; i < ARRAY_SIZE(nvmem_names); i++) { ++ struct nvmem_cell *cell; ++ cell = devm_nvmem_cell_get(&pdev->dev, ++ nvmem_names[i]); ++ if (IS_ERR(cell)) { ++ if (PTR_ERR(cell) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ dev_warn(&pdev->dev, "Missing NVMEM cell %s (%ld)\n", ++ nvmem_names[i], PTR_ERR(cell)); ++ /* Non fatal, we'll deal with it */ ++ cell = NULL; ++ } ++ reboot->nvm_cells[i] = cell; ++ } ++ ++ /* Set the boot_stage to indicate we're running the OS kernel */ ++ if (reboot->nvm.boot_stage && ++ nvmem_cell_set_u8(reboot->nvm.boot_stage, BOOT_STAGE_KERNEL_STARTED) < 0) ++ dev_err(reboot->dev, "Failed to write boot_stage\n"); ++ ++ /* Display and clear the error counts */ ++ macsmc_power_init_error_counts(reboot); ++ ++ reboot->reboot_notify.notifier_call = macsmc_reboot_notify; ++ ++ ret = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_HIGH, ++ macsmc_power_off, reboot); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "Failed to register power-off handler\n"); ++ ++ ret = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_RESTART, SYS_OFF_PRIO_HIGH, ++ macsmc_restart, reboot); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "Failed to register restart handler\n"); ++ ++ ret = devm_register_reboot_notifier(&pdev->dev, &reboot->reboot_notify); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "Failed to register reboot notifier\n"); ++ ++ dev_info(&pdev->dev, "Handling reboot and poweroff requests via SMC\n"); ++ ++ if (device_create_file(&pdev->dev, &dev_attr_ac_power_mode)) ++ dev_warn(&pdev->dev, "could not create sysfs file\n"); ++ ++ return 0; ++} ++ ++static int macsmc_reboot_remove(struct platform_device *pdev) ++{ ++ device_remove_file(&pdev->dev, &dev_attr_ac_power_mode); ++ ++ return 0; ++} ++ ++ ++static struct platform_driver macsmc_reboot_driver = { ++ .driver = { ++ .name = "macsmc-reboot", ++ .owner = THIS_MODULE, ++ }, ++ .probe = macsmc_reboot_probe, ++ .remove = macsmc_reboot_remove, ++}; ++module_platform_driver(macsmc_reboot_driver); ++ ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple SMC reboot/poweroff driver"); ++MODULE_AUTHOR("Hector Martin "); ++MODULE_ALIAS("platform:macsmc-reboot"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0148-rtc-Add-new-rtc-macsmc-driver-for-Apple-Silicon-Macs.patch b/target/linux/silicon/patches-5.19/0148-rtc-Add-new-rtc-macsmc-driver-for-Apple-Silicon-Macs.patch new file mode 100644 index 000000000..9377c25cf --- /dev/null +++ b/target/linux/silicon/patches-5.19/0148-rtc-Add-new-rtc-macsmc-driver-for-Apple-Silicon-Macs.patch @@ -0,0 +1,202 @@ +From 41fdf7c140ec6b812b2e55a45d9446ba3e60612c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 18:47:13 +0900 +Subject: [PATCH 148/171] rtc: Add new rtc-macsmc driver for Apple Silicon Macs + +Apple Silicon Macs (M1, etc.) have an RTC that is part of the PMU IC, +but most of the PMU functionality is abstracted out by the SMC. +On T600x machines, the RTC counter must be accessed via the SMC to +get full functionality, and it seems likely that future machines +will move towards making SMC handle all RTC functionality. + +The SMC RTC counter access is implemented on all current machines +as of the time of this writing, on firmware 12.x. However, the RTC +offset (needed to set the time) is still only accessible via direct +PMU access. To handle this, we expose the RTC offset as an NVMEM +cell from the SPMI PMU device node, and this driver consumes that +cell and uses it to compute/set the current time. + +Alarm functionality is not yet implemented. This would also go via +the PMU today, but could change in the future. + +Signed-off-by: Hector Martin +--- + drivers/rtc/Kconfig | 13 ++++ + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-macsmc.c | 130 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 144 insertions(+) + create mode 100644 drivers/rtc/rtc-macsmc.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index a00f901b5c1d..8717f2d9381c 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1973,4 +1973,17 @@ config RTC_DRV_MSC313 + This driver can also be built as a module, if so, the module + will be called "rtc-msc313". + ++config RTC_DRV_MACSMC ++ tristate "Apple Mac SMC RTC" ++ depends on ARCH_APPLE || COMPILE_TEST ++ depends on APPLE_SMC ++ depends on OF ++ default ARCH_APPLE ++ help ++ If you say yes here you get support for RTC functions ++ inside Apple SPMI PMUs. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rtc-macsmc. ++ + endif # RTC_CLASS +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index fb04467b652d..68519801a320 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -89,6 +89,7 @@ obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o + obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o + obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o + obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o ++obj-$(CONFIG_RTC_DRV_MACSMC) += rtc-macsmc.o + obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o + obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o + obj-$(CONFIG_RTC_DRV_MAX6916) += rtc-max6916.o +diff --git a/drivers/rtc/rtc-macsmc.c b/drivers/rtc/rtc-macsmc.c +new file mode 100644 +index 000000000000..34730c925248 +--- /dev/null ++++ b/drivers/rtc/rtc-macsmc.c +@@ -0,0 +1,130 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC RTC driver ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 48-bit RTC */ ++#define RTC_BYTES 6 ++#define RTC_BITS (8 * RTC_BYTES) ++ ++/* 32768 Hz clock */ ++#define RTC_SEC_SHIFT 15 ++ ++struct macsmc_rtc { ++ struct device *dev; ++ struct apple_smc *smc; ++ struct rtc_device *rtc_dev; ++ struct nvmem_cell *rtc_offset; ++}; ++ ++static int macsmc_rtc_get_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct macsmc_rtc *rtc = dev_get_drvdata(dev); ++ u64 ctr = 0, off = 0; ++ time64_t now; ++ void *p_off; ++ size_t len; ++ int ret; ++ ++ ret = apple_smc_read(rtc->smc, SMC_KEY(CLKM), &ctr, RTC_BYTES); ++ if (ret != RTC_BYTES) ++ return ret < 0 ? ret : -EIO; ++ ++ p_off = nvmem_cell_read(rtc->rtc_offset, &len); ++ if (IS_ERR(p_off)) ++ return PTR_ERR(p_off); ++ if (len < RTC_BYTES) { ++ kfree(p_off); ++ return -EIO; ++ } ++ ++ memcpy(&off, p_off, RTC_BYTES); ++ kfree(p_off); ++ ++ /* Sign extend from 48 to 64 bits, then arithmetic shift right 15 bits to get seconds */ ++ now = sign_extend64(ctr + off, RTC_BITS - 1) >> RTC_SEC_SHIFT; ++ rtc_time64_to_tm(now, tm); ++ ++ return ret; ++} ++ ++static int macsmc_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct macsmc_rtc *rtc = dev_get_drvdata(dev); ++ u64 ctr = 0, off = 0; ++ int ret; ++ ++ ret = apple_smc_read(rtc->smc, SMC_KEY(CLKM), &ctr, RTC_BYTES); ++ if (ret != RTC_BYTES) ++ return ret < 0 ? ret : -EIO; ++ ++ /* This sets the offset such that the set second begins now */ ++ off = (rtc_tm_to_time64(tm) << RTC_SEC_SHIFT) - ctr; ++ return nvmem_cell_write(rtc->rtc_offset, &off, RTC_BYTES); ++} ++ ++static const struct rtc_class_ops macsmc_rtc_ops = { ++ .read_time = macsmc_rtc_get_time, ++ .set_time = macsmc_rtc_set_time, ++}; ++ ++static int macsmc_rtc_probe(struct platform_device *pdev) ++{ ++ struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); ++ struct macsmc_rtc *rtc; ++ ++ /* Ignore devices without this functionality */ ++ if (!apple_smc_key_exists(smc, SMC_KEY(CLKM))) ++ return -ENODEV; ++ ++ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); ++ if (!rtc) ++ return -ENOMEM; ++ ++ rtc->dev = &pdev->dev; ++ rtc->smc = smc; ++ ++ pdev->dev.of_node = of_get_child_by_name(pdev->dev.parent->of_node, "rtc"); ++ ++ rtc->rtc_offset = devm_nvmem_cell_get(&pdev->dev, "rtc_offset"); ++ if (IS_ERR(rtc->rtc_offset)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_offset), ++ "Failed to get rtc_offset NVMEM cell\n"); ++ ++ rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); ++ if (IS_ERR(rtc->rtc_dev)) ++ return PTR_ERR(rtc->rtc_dev); ++ ++ rtc->rtc_dev->ops = &macsmc_rtc_ops; ++ rtc->rtc_dev->range_min = S64_MIN >> (RTC_SEC_SHIFT + (64 - RTC_BITS)); ++ rtc->rtc_dev->range_max = S64_MAX >> (RTC_SEC_SHIFT + (64 - RTC_BITS)); ++ ++ platform_set_drvdata(pdev, rtc); ++ ++ return devm_rtc_register_device(rtc->rtc_dev); ++} ++ ++static struct platform_driver macsmc_rtc_driver = { ++ .driver = { ++ .name = "macsmc-rtc", ++ .owner = THIS_MODULE, ++ }, ++ .probe = macsmc_rtc_probe, ++}; ++module_platform_driver(macsmc_rtc_driver); ++ ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple SMC RTC driver"); ++MODULE_AUTHOR("Hector Martin "); ++MODULE_ALIAS("platform:macsmc-rtc"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0149-Input-macsmc-hid-New-driver-to-handle-the-Apple-Mac-.patch b/target/linux/silicon/patches-5.19/0149-Input-macsmc-hid-New-driver-to-handle-the-Apple-Mac-.patch new file mode 100644 index 000000000..39b360b0a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0149-Input-macsmc-hid-New-driver-to-handle-the-Apple-Mac-.patch @@ -0,0 +1,221 @@ +From 7c60cf26c675b90404782dcd54a91707ac100737 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Fri, 4 Mar 2022 19:21:19 +0900 +Subject: [PATCH 149/171] Input: macsmc-hid: New driver to handle the Apple Mac + SMC buttons/lid + +This driver implements power button and lid switch support for Apple Mac +devices using SMC controllers driven by the macsmc driver. + +In addition to basic input support, this also responds to the final +shutdown warning (when the power button is held down long enough) by +doing an emergency kernel poweroff. This allows the NVMe controller to +be cleanly shut down, which prevents data loss for in-cache data. + +Signed-off-by: Hector Martin +--- + drivers/input/misc/Kconfig | 12 +++ + drivers/input/misc/Makefile | 1 + + drivers/input/misc/macsmc-hid.c | 157 ++++++++++++++++++++++++++++++++ + 3 files changed, 170 insertions(+) + create mode 100644 drivers/input/misc/macsmc-hid.c + +diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig +index a18ab7358d8f..08e681473ae8 100644 +--- a/drivers/input/misc/Kconfig ++++ b/drivers/input/misc/Kconfig +@@ -902,4 +902,16 @@ config INPUT_STPMIC1_ONKEY + To compile this driver as a module, choose M here: the + module will be called stpmic1_onkey. + ++config INPUT_MACSMC_HID ++ tristate "Apple Mac SMC lid/buttons" ++ depends on APPLE_SMC ++ default ARCH_APPLE ++ help ++ Say Y here if you want to use the input events delivered via the ++ SMC controller on Apple Mac machines using the macsmc driver. ++ This includes lid open/close and the power button. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called macsmc-hid. ++ + endif +diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile +index 28dfc444f0a9..a607c6472d0a 100644 +--- a/drivers/input/misc/Makefile ++++ b/drivers/input/misc/Makefile +@@ -48,6 +48,7 @@ obj-$(CONFIG_INPUT_IQS7222) += iqs7222.o + obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o + obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o + obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o ++obj-$(CONFIG_INPUT_MACSMC_HID) += macsmc-hid.o + obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o + obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o + obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o +diff --git a/drivers/input/misc/macsmc-hid.c b/drivers/input/misc/macsmc-hid.c +new file mode 100644 +index 000000000000..1c0f7476081f +--- /dev/null ++++ b/drivers/input/misc/macsmc-hid.c +@@ -0,0 +1,157 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Apple SMC input event driver ++ * Copyright The Asahi Linux Contributors ++ * ++ * This driver exposes HID events from the SMC as an input device. ++ * This includes the lid open/close and power button notifications. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct macsmc_hid { ++ struct device *dev; ++ struct apple_smc *smc; ++ struct input_dev *input; ++ struct notifier_block nb; ++}; ++ ++#define SMC_EV_BTN 0x7201 ++#define SMC_EV_LID 0x7203 ++ ++#define BTN_POWER 0x06 ++#define BTN_POWER_HELD1 0xfe ++#define BTN_POWER_HELD2 0x00 ++ ++static int macsmc_hid_event(struct notifier_block *nb, unsigned long event, void *data) ++{ ++ struct macsmc_hid *smchid = container_of(nb, struct macsmc_hid, nb); ++ u16 type = event >> 16; ++ u8 d1 = (event >> 8) & 0xff; ++ u8 d2 = event & 0xff; ++ ++ switch (type) { ++ case SMC_EV_BTN: ++ switch (d1) { ++ case BTN_POWER: ++ input_report_key(smchid->input, KEY_POWER, d2); ++ input_sync(smchid->input); ++ break; ++ case BTN_POWER_HELD1: ++ /* ++ * TODO: is this pre-warning useful? ++ */ ++ if (d2) ++ dev_warn(smchid->dev, "Power button held down\n"); ++ break; ++ case BTN_POWER_HELD2: ++ /* ++ * If we get here, we have about 4 seconds before forced shutdown. ++ * Try to do an emergency shutdown to make sure the NVMe cache is ++ * flushed. macOS actually does this by panicing (!)... ++ */ ++ if (d2) { ++ dev_crit(smchid->dev, "Triggering forced shutdown!\n"); ++ if (kernel_can_power_off()) ++ kernel_power_off(); ++ else /* Missing macsmc-reboot driver? */ ++ kernel_restart("SMC power button triggered restart"); ++ } ++ break; ++ default: ++ dev_info(smchid->dev, "Unknown SMC button event: %02x %02x\n", d1, d2); ++ break; ++ } ++ return NOTIFY_OK; ++ case SMC_EV_LID: ++ input_report_switch(smchid->input, SW_LID, d1); ++ input_sync(smchid->input); ++ return NOTIFY_OK; ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static int macsmc_hid_probe(struct platform_device *pdev) ++{ ++ struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); ++ struct macsmc_hid *smchid; ++ bool have_lid, have_power; ++ int ret; ++ ++ have_lid = apple_smc_key_exists(smc, SMC_KEY(MSLD)); ++ have_power = apple_smc_key_exists(smc, SMC_KEY(bHLD)); ++ ++ if (!have_lid && !have_power) ++ return -ENODEV; ++ ++ smchid = devm_kzalloc(&pdev->dev, sizeof(*smchid), GFP_KERNEL); ++ if (!smchid) ++ return -ENOMEM; ++ ++ smchid->dev = &pdev->dev; ++ smchid->smc = smc; ++ ++ smchid->input = devm_input_allocate_device(&pdev->dev); ++ if (!smchid->input) ++ return -ENOMEM; ++ ++ smchid->input->phys = "macsmc-hid (0)"; ++ smchid->input->name = "Apple SMC power/lid events"; ++ ++ if (have_lid) ++ input_set_capability(smchid->input, EV_SW, SW_LID); ++ if (have_power) ++ input_set_capability(smchid->input, EV_KEY, KEY_POWER); ++ ++ ret = input_register_device(smchid->input); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register input device: %d\n", ret); ++ return ret; ++ } ++ ++ if (have_lid) { ++ u8 val; ++ ++ ret = apple_smc_read_u8(smc, SMC_KEY(MSLD), &val); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to read initial lid state\n"); ++ } else { ++ input_report_switch(smchid->input, SW_LID, val); ++ } ++ } ++ if (have_power) { ++ u32 val; ++ ++ ret = apple_smc_read_u32(smc, SMC_KEY(bHLD), &val); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to read initial power button state\n"); ++ } else { ++ input_report_key(smchid->input, KEY_POWER, val & 1); ++ } ++ } ++ ++ input_sync(smchid->input); ++ ++ smchid->nb.notifier_call = macsmc_hid_event; ++ apple_smc_register_notifier(smc, &smchid->nb); ++ ++ return 0; ++} ++ ++static struct platform_driver macsmc_hid_driver = { ++ .driver = { ++ .name = "macsmc-hid", ++ }, ++ .probe = macsmc_hid_probe, ++}; ++module_platform_driver(macsmc_hid_driver); ++ ++MODULE_AUTHOR("Hector Martin "); ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Apple SMC GPIO driver"); ++MODULE_ALIAS("platform:macsmc-hid"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0150-Input-macsmc-hid-Support-button-lid-wakeups.patch b/target/linux/silicon/patches-5.19/0150-Input-macsmc-hid-Support-button-lid-wakeups.patch new file mode 100644 index 000000000..8a27fa60a --- /dev/null +++ b/target/linux/silicon/patches-5.19/0150-Input-macsmc-hid-Support-button-lid-wakeups.patch @@ -0,0 +1,99 @@ +From f197789f0d78ce24b6032ac53ddc06d7722422fb Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 5 Mar 2022 01:08:04 +0900 +Subject: [PATCH 150/171] Input: macsmc-hid: Support button/lid wakeups + +Signed-off-by: Hector Martin +--- + drivers/input/misc/macsmc-hid.c | 41 +++++++++++++++++++++++++++++++-- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/drivers/input/misc/macsmc-hid.c b/drivers/input/misc/macsmc-hid.c +index 1c0f7476081f..c4c7440d4ee6 100644 +--- a/drivers/input/misc/macsmc-hid.c ++++ b/drivers/input/misc/macsmc-hid.c +@@ -18,6 +18,7 @@ struct macsmc_hid { + struct apple_smc *smc; + struct input_dev *input; + struct notifier_block nb; ++ bool wakeup_mode; + }; + + #define SMC_EV_BTN 0x7201 +@@ -38,8 +39,15 @@ static int macsmc_hid_event(struct notifier_block *nb, unsigned long event, void + case SMC_EV_BTN: + switch (d1) { + case BTN_POWER: +- input_report_key(smchid->input, KEY_POWER, d2); +- input_sync(smchid->input); ++ if (smchid->wakeup_mode) { ++ if (d2) { ++ dev_info(smchid->dev, "Button wakeup\n"); ++ pm_wakeup_hard_event(smchid->dev); ++ } ++ } else { ++ input_report_key(smchid->input, KEY_POWER, d2); ++ input_sync(smchid->input); ++ } + break; + case BTN_POWER_HELD1: + /* +@@ -68,6 +76,10 @@ static int macsmc_hid_event(struct notifier_block *nb, unsigned long event, void + } + return NOTIFY_OK; + case SMC_EV_LID: ++ if (smchid->wakeup_mode && !d1) { ++ dev_info(smchid->dev, "Lid wakeup\n"); ++ pm_wakeup_hard_event(smchid->dev); ++ } + input_report_switch(smchid->input, SW_LID, d1); + input_sync(smchid->input); + return NOTIFY_OK; +@@ -95,6 +107,7 @@ static int macsmc_hid_probe(struct platform_device *pdev) + + smchid->dev = &pdev->dev; + smchid->smc = smc; ++ platform_set_drvdata(pdev, smchid); + + smchid->input = devm_input_allocate_device(&pdev->dev); + if (!smchid->input) +@@ -140,12 +153,36 @@ static int macsmc_hid_probe(struct platform_device *pdev) + smchid->nb.notifier_call = macsmc_hid_event; + apple_smc_register_notifier(smc, &smchid->nb); + ++ device_init_wakeup(&pdev->dev, 1); ++ ++ return 0; ++} ++ ++static int macsmc_hid_pm_prepare(struct device *dev) ++{ ++ struct macsmc_hid *smchid = dev_get_drvdata(dev); ++ ++ smchid->wakeup_mode = true; + return 0; + } + ++static void macsmc_hid_pm_complete(struct device *dev) ++{ ++ struct macsmc_hid *smchid = dev_get_drvdata(dev); ++ ++ smchid->wakeup_mode = false; ++} ++ ++static const struct dev_pm_ops macsmc_hid_pm_ops = { ++ .prepare = macsmc_hid_pm_prepare, ++ .complete = macsmc_hid_pm_complete, ++}; ++ + static struct platform_driver macsmc_hid_driver = { + .driver = { + .name = "macsmc-hid", ++ .owner = THIS_MODULE, ++ .pm = &macsmc_hid_pm_ops, + }, + .probe = macsmc_hid_probe, + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0151-gpio-macsmc-Add-IRQ-support.patch b/target/linux/silicon/patches-5.19/0151-gpio-macsmc-Add-IRQ-support.patch new file mode 100644 index 000000000..3cb056e0d --- /dev/null +++ b/target/linux/silicon/patches-5.19/0151-gpio-macsmc-Add-IRQ-support.patch @@ -0,0 +1,212 @@ +From 958cf3ceb9eeeef363bc311794b69226f8827c07 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 5 May 2022 01:38:19 +0900 +Subject: [PATCH 151/171] gpio: macsmc: Add IRQ support + +Signed-off-by: Hector Martin +--- + drivers/gpio/gpio-macsmc.c | 151 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 151 insertions(+) + +diff --git a/drivers/gpio/gpio-macsmc.c b/drivers/gpio/gpio-macsmc.c +index ff9950afb69a..2f1f07ea3891 100644 +--- a/drivers/gpio/gpio-macsmc.c ++++ b/drivers/gpio/gpio-macsmc.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -68,10 +69,21 @@ + * 3 = ? + */ + ++#define SMC_EV_GPIO 0x7202 ++ + struct macsmc_gpio { + struct device *dev; + struct apple_smc *smc; + struct gpio_chip gc; ++ struct irq_chip ic; ++ struct notifier_block nb; ++ ++ struct mutex irq_mutex; ++ DECLARE_BITMAP(irq_supported, MAX_GPIO); ++ DECLARE_BITMAP(irq_enable_shadow, MAX_GPIO); ++ DECLARE_BITMAP(irq_enable, MAX_GPIO); ++ u32 irq_mode_shadow[MAX_GPIO]; ++ u32 irq_mode[MAX_GPIO]; + + int first_index; + }; +@@ -161,6 +173,7 @@ static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc, + for (i = 0; i < count; i++) { + smc_key key; + int gpio_nr; ++ u32 val; + int ret = apple_smc_get_key_by_index(smcgp->smc, smcgp->first_index + i, &key); + + if (ret < 0) +@@ -176,11 +189,128 @@ static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc, + } + + set_bit(gpio_nr, valid_mask); ++ ++ /* Check for IRQ support */ ++ ret = apple_smc_rw_u32(smcgp->smc, key, CMD_IRQ_MODE, &val); ++ if (!ret) ++ set_bit(gpio_nr, smcgp->irq_supported); ++ } ++ ++ return 0; ++} ++ ++static int macsmc_gpio_event(struct notifier_block *nb, unsigned long event, void *data) ++{ ++ struct macsmc_gpio *smcgp = container_of(nb, struct macsmc_gpio, nb); ++ u16 type = event >> 16; ++ u8 offset = (event >> 8) & 0xff; ++ smc_key key = macsmc_gpio_key(offset); ++ unsigned long flags; ++ int ret; ++ ++ if (type != SMC_EV_GPIO) ++ return NOTIFY_DONE; ++ ++ if (offset > MAX_GPIO) { ++ dev_err(smcgp->dev, "GPIO event index %d out of range\n", offset); ++ return NOTIFY_BAD; ++ } ++ ++ local_irq_save(flags); ++ ret = handle_irq_desc(irq_resolve_mapping(smcgp->gc.irq.domain, offset)); ++ local_irq_restore(flags); ++ ++ if (apple_smc_write_u32(smcgp->smc, key, CMD_IRQ_ACK | 1) < 0) ++ dev_err(smcgp->dev, "GPIO IRQ ack failed for %p4ch\n", &key); ++ ++ return (ret == 0) ? NOTIFY_OK : NOTIFY_DONE; ++} ++ ++static void macsmc_gpio_irq_enable(struct irq_data *d) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct macsmc_gpio *smcgp = gpiochip_get_data(gc); ++ ++ set_bit(irqd_to_hwirq(d), smcgp->irq_enable_shadow); ++} ++ ++static void macsmc_gpio_irq_disable(struct irq_data *d) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct macsmc_gpio *smcgp = gpiochip_get_data(gc); ++ ++ clear_bit(irqd_to_hwirq(d), smcgp->irq_enable_shadow); ++} ++ ++static int macsmc_gpio_irq_set_type(struct irq_data *d, unsigned int type) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct macsmc_gpio *smcgp = gpiochip_get_data(gc); ++ int offset = irqd_to_hwirq(d); ++ u32 mode; ++ ++ if (!test_bit(offset, smcgp->irq_supported)) ++ return -EINVAL; ++ ++ switch (type & IRQ_TYPE_SENSE_MASK) { ++ case IRQ_TYPE_LEVEL_HIGH: ++ mode = IRQ_MODE_HIGH; ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ mode = IRQ_MODE_LOW; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ mode = IRQ_MODE_RISING; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ mode = IRQ_MODE_FALLING; ++ break; ++ case IRQ_TYPE_EDGE_BOTH: ++ mode = IRQ_MODE_BOTH; ++ break; ++ default: ++ return -EINVAL; + } + ++ smcgp->irq_mode_shadow[offset] = mode; + return 0; + } + ++static void macsmc_gpio_irq_bus_lock(struct irq_data *d) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct macsmc_gpio *smcgp = gpiochip_get_data(gc); ++ ++ mutex_lock(&smcgp->irq_mutex); ++} ++ ++static void macsmc_gpio_irq_bus_sync_unlock(struct irq_data *d) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct macsmc_gpio *smcgp = gpiochip_get_data(gc); ++ smc_key key = macsmc_gpio_key(irqd_to_hwirq(d)); ++ int offset = irqd_to_hwirq(d); ++ bool val; ++ ++ if (smcgp->irq_mode_shadow[offset] != smcgp->irq_mode[offset]) { ++ u32 cmd = CMD_IRQ_MODE | smcgp->irq_mode_shadow[offset]; ++ if (apple_smc_write_u32(smcgp->smc, key, cmd) < 0) ++ dev_err(smcgp->dev, "GPIO IRQ config failed for %p4ch = 0x%x\n", &key, cmd); ++ else ++ smcgp->irq_mode_shadow[offset] = smcgp->irq_mode[offset]; ++ } ++ ++ val = test_bit(offset, smcgp->irq_enable_shadow); ++ if (test_bit(offset, smcgp->irq_enable) != val) { ++ if (apple_smc_write_u32(smcgp->smc, key, CMD_IRQ_ENABLE | val) < 0) ++ dev_err(smcgp->dev, "GPIO IRQ en/disable failed for %p4ch\n", &key); ++ else ++ change_bit(offset, smcgp->irq_enable); ++ } ++ ++ mutex_unlock(&smcgp->irq_mutex); ++} ++ + static int macsmc_gpio_probe(struct platform_device *pdev) + { + struct macsmc_gpio *smcgp; +@@ -221,6 +351,27 @@ static int macsmc_gpio_probe(struct platform_device *pdev) + smcgp->gc.base = -1; + smcgp->gc.parent = &pdev->dev; + ++ smcgp->ic.name = "macsmc-pmu-gpio"; ++ smcgp->ic.irq_mask = macsmc_gpio_irq_disable; ++ smcgp->ic.irq_unmask = macsmc_gpio_irq_enable; ++ smcgp->ic.irq_set_type = macsmc_gpio_irq_set_type; ++ smcgp->ic.irq_bus_lock = macsmc_gpio_irq_bus_lock; ++ smcgp->ic.irq_bus_sync_unlock = macsmc_gpio_irq_bus_sync_unlock; ++ smcgp->ic.irq_set_type = macsmc_gpio_irq_set_type; ++ smcgp->ic.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; ++ ++ smcgp->gc.irq.chip = &smcgp->ic; ++ smcgp->gc.irq.parent_handler = NULL; ++ smcgp->gc.irq.num_parents = 0; ++ smcgp->gc.irq.parents = NULL; ++ smcgp->gc.irq.default_type = IRQ_TYPE_NONE; ++ smcgp->gc.irq.handler = handle_simple_irq; ++ ++ mutex_init(&smcgp->irq_mutex); ++ ++ smcgp->nb.notifier_call = macsmc_gpio_event; ++ apple_smc_register_notifier(smc, &smcgp->nb); ++ + return devm_gpiochip_add_data(&pdev->dev, &smcgp->gc, smcgp); + } + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0152-spmi-add-a-first-basic-spmi-driver-for-Apple-SoC.patch b/target/linux/silicon/patches-5.19/0152-spmi-add-a-first-basic-spmi-driver-for-Apple-SoC.patch new file mode 100644 index 000000000..9f84be491 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0152-spmi-add-a-first-basic-spmi-driver-for-Apple-SoC.patch @@ -0,0 +1,249 @@ +From 69860806b247b72cc354ca35ea147c2d1538ea85 Mon Sep 17 00:00:00 2001 +From: Jean-Francois Bortolotti +Date: Fri, 4 Feb 2022 00:06:13 +0100 +Subject: [PATCH 152/171] spmi: add a first basic spmi driver for Apple SoC + +Signed-off-by: Jean-Francois Bortolotti +--- + drivers/spmi/Kconfig | 8 ++ + drivers/spmi/Makefile | 1 + + drivers/spmi/spmi-apple-controller.c | 201 +++++++++++++++++++++++++++ + 3 files changed, 210 insertions(+) + create mode 100644 drivers/spmi/spmi-apple-controller.c + +diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig +index 737802046314..96c73c5b5720 100644 +--- a/drivers/spmi/Kconfig ++++ b/drivers/spmi/Kconfig +@@ -45,4 +45,12 @@ config SPMI_MTK_PMIF + This is required for communicating with Mediatek PMICs and + other devices that have the SPMI interface. + ++config SPMI_APPLE ++ tristate "Apple SoC SPMI Controller platform driver" ++ depends on ARCH_APPLE || COMPILE_TEST ++ help ++ This enables basic support for the SPMI controller present on ++ many Apple SoCs, including the t8103 (M1) and t600x ++ (M1 Pro/Max). ++ + endif +diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile +index 9d974424c8c1..989b84bbca60 100644 +--- a/drivers/spmi/Makefile ++++ b/drivers/spmi/Makefile +@@ -7,3 +7,4 @@ obj-$(CONFIG_SPMI) += spmi.o + obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o + obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o + obj-$(CONFIG_SPMI_MTK_PMIF) += spmi-mtk-pmif.o ++obj-$(CONFIG_SPMI_APPLE) += spmi-apple-controller.o +diff --git a/drivers/spmi/spmi-apple-controller.c b/drivers/spmi/spmi-apple-controller.c +new file mode 100644 +index 000000000000..3b6de8069396 +--- /dev/null ++++ b/drivers/spmi/spmi-apple-controller.c +@@ -0,0 +1,201 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Apple SoC SPMI device driver ++ * ++ * Copyright The Asahi Linux Contributors ++ * ++ * Inspired by: ++ * OpenBSD support Copyright (c) 2021 Mark Kettenis ++ * Correllium support Copyright (C) 2021 Corellium LLC ++ * hisi-spmi-controller.c ++ * spmi-pmic-ard.c Copyright (c) 2021, The Linux Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* SPMI Controller Registers */ ++#define SPMI_STATUS_REG 0 ++#define SPMI_CMD_REG 0x4 ++#define SPMI_RSP_REG 0x8 ++ ++#define SPMI_RX_FIFO_EMPTY BIT(24) ++#define SPMI_TX_FIFO_EMPTY BIT(8) ++ ++/* Apple SPMI controler */ ++struct apple_spmi { ++ void __iomem *regs; ++ struct spmi_controller *ctrl; ++}; ++ ++static inline u32 read_reg(struct apple_spmi *spmi, int offset) ++{ ++ return(readl_relaxed(spmi->regs + offset)); ++} ++ ++static inline void write_reg(u32 value, struct apple_spmi *spmi, int offset) ++{ ++ writel_relaxed(value, spmi->regs + offset); ++} ++ ++static int spmi_read_cmd(struct spmi_controller *ctrl, ++ u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc) ++{ ++ struct apple_spmi *spmi; ++ u32 spmi_cmd = opc|slave_id<<8|slave_addr<<16|(bc-1)|(1<<15); ++ u32 rsp; ++ volatile u32 status; ++ size_t len_to_read; ++ u8 i; ++ ++ spmi = spmi_controller_get_drvdata(ctrl); ++ ++ write_reg(spmi_cmd, spmi, SPMI_CMD_REG); ++ ++ /* Wait for Rx FIFO to have something */ ++ /* Quite ugly msleep, need to find a better way to do it */ ++ i=0; ++ do { ++ status=read_reg(spmi, SPMI_STATUS_REG); ++ msleep(10); ++ i+=1; ++ } while ((status & SPMI_RX_FIFO_EMPTY) && i<5); ++ ++ if(i>=5){ ++ dev_err(&ctrl->dev,"spmi_read_cmd:took to long to get the status"); ++ return -1; ++ } ++ ++ /* Read SPMI reply status */ ++ rsp=read_reg(spmi, SPMI_RSP_REG); ++ ++ len_to_read = 0; ++ /* Read SPMI data reply */ ++ while (!( status & SPMI_RX_FIFO_EMPTY ) && (len_to_read < bc )) { ++ rsp=read_reg(spmi, SPMI_RSP_REG); ++ i=0; ++ while ((len_to_read>(8*i); ++ i+=1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int spmi_write_cmd(struct spmi_controller *ctrl, ++ u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc) ++{ ++ struct apple_spmi *spmi; ++ u32 spmi_cmd = opc|slave_id<<8|slave_addr<<16|(bc-1)|(1<<15); ++ volatile u32 rsp; ++ size_t i=0,j; ++ ++ spmi = spmi_controller_get_drvdata(ctrl); ++ ++ write_reg(spmi_cmd, spmi, SPMI_CMD_REG); ++ ++ while (idev, sizeof(struct apple_spmi)); ++ if (IS_ERR(ctrl)) { ++ dev_err_probe(&pdev->dev, PTR_ERR(ctrl), "Can't allocate spmi_controller data\n"); ++ return -ENOMEM; ++ } ++ ++ spmi = spmi_controller_get_drvdata(ctrl); ++ spmi->ctrl=ctrl; ++ platform_set_drvdata(pdev, ctrl); ++ ++ spmi->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(spmi->regs)) { ++ dev_err_probe(&pdev->dev, PTR_ERR(spmi->regs), "Can't get ioremap regs.\n"); ++ return PTR_ERR(spmi->regs); ++ } ++ ++ ctrl->dev.of_node = of_node_get(pdev->dev.of_node); ++ ++ /* Callbacks */ ++ ctrl->read_cmd = spmi_read_cmd; ++ ctrl->write_cmd = spmi_write_cmd; ++ ++ ret = spmi_controller_add(ctrl); ++ if (ret) { ++ dev_err(&pdev->dev, "spmi_controller_add failed with error %d!\n", ret); ++ goto err_put_controller; ++ } ++ ++ /* Let's look for other nodes in device tree like the rtc */ ++ ret = devm_of_platform_populate(&pdev->dev); ++ if (ret) { ++ dev_err(&pdev->dev, "spmi_controller_probe: devm_of_platform_populate failed with error %d!\n", ret); ++ goto err_devm_of_platform_populate; ++ } ++ ++ return 0; ++ ++err_put_controller: ++ spmi_controller_put(ctrl); ++err_devm_of_platform_populate: ++ return ret; ++} ++ ++static int spmi_del_controller(struct platform_device *pdev) ++{ ++ struct spmi_controller *ctrl = platform_get_drvdata(pdev); ++ ++ spmi_controller_remove(ctrl); ++ spmi_controller_put(ctrl); ++ return 0; ++} ++ ++static const struct of_device_id spmi_controller_match_table[] = { ++ {.compatible = "apple,spmi",}, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, spmi_controller_match_table); ++ ++static struct platform_driver spmi_controller_driver = { ++ .probe = spmi_controller_probe, ++ .remove = spmi_del_controller, ++ .driver = { ++ .name = "apple-spmi", ++ .owner = THIS_MODULE, ++ .of_match_table = spmi_controller_match_table, ++ }, ++}; ++module_platform_driver(spmi_controller_driver); ++ ++MODULE_AUTHOR("Jean-Francois Bortolotti "); ++MODULE_DESCRIPTION("Apple SoC SPMI driver"); ++MODULE_LICENSE("GPL"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0153-mfd-Add-a-simple-mfd-spmi-driver.patch b/target/linux/silicon/patches-5.19/0153-mfd-Add-a-simple-mfd-spmi-driver.patch new file mode 100644 index 000000000..639d2adf7 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0153-mfd-Add-a-simple-mfd-spmi-driver.patch @@ -0,0 +1,133 @@ +From 8d26f74c3cfe2457f40536a541a864e8567a9207 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 18:43:17 +0900 +Subject: [PATCH 153/171] mfd: Add a simple-mfd-spmi driver + +This is the SPMI counterpart to simple-mfd-i2c. It merely exposes the +SPMI register address space as an MFD device, such that different +aspects of a device can be managed by separate drivers. + +Signed-off-by: Hector Martin +--- + drivers/mfd/Kconfig | 28 ++++++++++++++++++++ + drivers/mfd/Makefile | 1 + + drivers/mfd/simple-mfd-spmi.c | 49 +++++++++++++++++++++++++++++++++++ + 3 files changed, 78 insertions(+) + create mode 100644 drivers/mfd/simple-mfd-spmi.c + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 3b59456f5545..e675aaf00bc8 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -51,6 +51,21 @@ config MFD_ACT8945A + linear regulators, along with a complete ActivePath battery + charger. + ++config MFD_APPLE_SPMI_PMU ++ tristate "Apple SPMI PMUs" ++ depends on SPMI ++ depends on ARCH_APPLE || COMPILE_TEST ++ default ARCH_APPLE ++ select MFD_SIMPLE_MFD_SPMI ++ help ++ Say yes here to enable support for Apple PMUs attached via the ++ SPMI bus. These can be found on Apple devices such as Apple ++ Silicon Macs. ++ ++ This driver itself only attaches to the core device, and relies ++ on subsystem drivers for individual device functions. You must ++ enable those for it to be useful. ++ + config MFD_SUN4I_GPADC + tristate "Allwinner sunxi platforms' GPADC MFD driver" + select MFD_CORE +@@ -1214,6 +1229,19 @@ config MFD_SIMPLE_MFD_I2C + sub-devices represented by child nodes in Device Tree will be + subsequently registered. + ++config MFD_SIMPLE_MFD_SPMI ++ tristate ++ depends on SPMI ++ select MFD_CORE ++ select REGMAP_SPMI ++ help ++ This driver creates a single register map with the intention for it ++ to be shared by all sub-devices. ++ ++ Once the register map has been successfully initialised, any ++ sub-devices represented by child nodes in Device Tree will be ++ subsequently registered. ++ + config MFD_SL28CPLD + tristate "Kontron sl28cpld Board Management Controller" + depends on I2C +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index 858cacf659d6..8d8abcd68351 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -266,6 +266,7 @@ obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o + + obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o + obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o ++obj-$(CONFIG_MFD_SIMPLE_MFD_SPMI) += simple-mfd-spmi.o + obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o + + obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o +diff --git a/drivers/mfd/simple-mfd-spmi.c b/drivers/mfd/simple-mfd-spmi.c +new file mode 100644 +index 000000000000..99f25751000a +--- /dev/null ++++ b/drivers/mfd/simple-mfd-spmi.c +@@ -0,0 +1,49 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Simple MFD - SPMI ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static const struct regmap_config spmi_regmap_config = { ++ .reg_bits = 16, ++ .val_bits = 8, ++ .max_register = 0xffff, ++}; ++ ++static int simple_spmi_probe(struct spmi_device *sdev) ++{ ++ struct regmap *regmap; ++ ++ regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config); ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ return devm_of_platform_populate(&sdev->dev); ++} ++ ++static const struct of_device_id simple_spmi_id_table[] = { ++ { .compatible = "apple,spmi-pmu" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, simple_spmi_id_table); ++ ++static struct spmi_driver pmic_spmi_driver = { ++ .probe = simple_spmi_probe, ++ .driver = { ++ .name = "simple-mfd-spmi", ++ .owner = THIS_MODULE, ++ .of_match_table = simple_spmi_id_table, ++ }, ++}; ++module_spmi_driver(pmic_spmi_driver); ++ ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_DESCRIPTION("Simple MFD - SPMI driver"); ++MODULE_AUTHOR("Hector Martin "); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0154-nvmem-Add-spmi-mfd-nvmem-driver.patch b/target/linux/silicon/patches-5.19/0154-nvmem-Add-spmi-mfd-nvmem-driver.patch new file mode 100644 index 000000000..2a69c6ca2 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0154-nvmem-Add-spmi-mfd-nvmem-driver.patch @@ -0,0 +1,163 @@ +From 7d8a1a4c3dddcdaa51aa354bf82074a86640794c Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 18:45:25 +0900 +Subject: [PATCH 154/171] nvmem: Add spmi-mfd-nvmem driver + +This driver exposes part of an SPMI MFD device as an NVMEM device. +It is intended to be used with e.g. PMUs/PMICs that are used to +hold power-management configuration, such as used on Apple Silicon +Macs. + +Signed-off-by: Hector Martin +--- + drivers/nvmem/Kconfig | 13 +++++ + drivers/nvmem/Makefile | 2 + + drivers/nvmem/spmi-mfd-nvmem.c | 99 ++++++++++++++++++++++++++++++++++ + 3 files changed, 114 insertions(+) + create mode 100644 drivers/nvmem/spmi-mfd-nvmem.c + +diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig +index 967d0084800e..577984390149 100644 +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -172,6 +172,19 @@ config NVMEM_BCM_OCOTP + This driver can also be built as a module. If so, the module + will be called nvmem-bcm-ocotp. + ++config NVMEM_SPMI_MFD ++ tristate "Generic SPMI MFD NVMEM" ++ depends on MFD_SIMPLE_MFD_SPMI || COMPILE_TEST ++ default ARCH_APPLE ++ help ++ Say y here to build a generic driver to expose an SPMI MFD device ++ as a NVMEM provider. This can be used for PMIC/PMU devices which ++ are used to store power and RTC-related settings on certain ++ platforms, such as Apple Silicon Macs. ++ ++ This driver can also be built as a module. If so, the module ++ will be called nvmem-spmi-mfd. ++ + config NVMEM_STM32_ROMEM + tristate "STMicroelectronics STM32 factory-programmed memory support" + depends on ARCH_STM32 || COMPILE_TEST +diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile +index 00e136a0a123..026eac4da53d 100644 +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -38,6 +38,8 @@ nvmem-rockchip-otp-y := rockchip-otp.o + obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o + nvmem_stm32_romem-y := stm32-romem.o + obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o ++nvmem_spmi_mfd-y := spmi-mfd-nvmem.o ++obj-$(CONFIG_NVMEM_SPMI_MFD) += nvmem_spmi_mfd.o + nvmem_sunxi_sid-y := sunxi_sid.o + obj-$(CONFIG_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o + nvmem-uniphier-efuse-y := uniphier-efuse.o +diff --git a/drivers/nvmem/spmi-mfd-nvmem.c b/drivers/nvmem/spmi-mfd-nvmem.c +new file mode 100644 +index 000000000000..284c93be2e18 +--- /dev/null ++++ b/drivers/nvmem/spmi-mfd-nvmem.c +@@ -0,0 +1,99 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Generic SPMI MFD NVMEM driver ++ * ++ * Copyright The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct spmi_mfd_nvmem { ++ struct regmap *regmap; ++ unsigned int base; ++}; ++ ++static int spmi_mfd_nvmem_read(void *priv, unsigned int offset, ++ void *val, size_t bytes) ++{ ++ struct spmi_mfd_nvmem *nvmem = priv; ++ ++ return regmap_bulk_read(nvmem->regmap, nvmem->base + offset, val, bytes); ++} ++ ++static int spmi_mfd_nvmem_write(void *priv, unsigned int offset, ++ void *val, size_t bytes) ++{ ++ struct spmi_mfd_nvmem *nvmem = priv; ++ ++ return regmap_bulk_write(nvmem->regmap, nvmem->base + offset, val, bytes); ++} ++ ++static int spmi_mfd_nvmem_probe(struct platform_device *pdev) ++{ ++ struct spmi_mfd_nvmem *nvmem; ++ const __be32 *addr; ++ int len; ++ struct nvmem_config nvmem_cfg = { ++ .dev = &pdev->dev, ++ .name = "spmi_mfd_nvmem", ++ .id = NVMEM_DEVID_AUTO, ++ .word_size = 1, ++ .stride = 1, ++ .reg_read = spmi_mfd_nvmem_read, ++ .reg_write = spmi_mfd_nvmem_write, ++ }; ++ ++ nvmem = devm_kzalloc(&pdev->dev, sizeof(*nvmem), GFP_KERNEL); ++ if (!nvmem) ++ return -ENOMEM; ++ ++ nvmem_cfg.priv = nvmem; ++ ++ nvmem->regmap = dev_get_regmap(pdev->dev.parent, NULL); ++ if (!nvmem->regmap) { ++ dev_err(&pdev->dev, "Parent regmap unavailable.\n"); ++ return -ENXIO; ++ } ++ ++ addr = of_get_property(pdev->dev.of_node, "reg", &len); ++ if (!addr) { ++ dev_err(&pdev->dev, "no reg property\n"); ++ return -EINVAL; ++ } ++ if (len != 2 * sizeof(u32)) { ++ dev_err(&pdev->dev, "invalid reg property\n"); ++ return -EINVAL; ++ } ++ ++ nvmem->base = be32_to_cpup(&addr[0]); ++ nvmem_cfg.size = be32_to_cpup(&addr[1]); ++ ++ return PTR_ERR_OR_ZERO(devm_nvmem_register(&pdev->dev, &nvmem_cfg)); ++} ++ ++static const struct of_device_id spmi_mfd_nvmem_id_table[] = { ++ { .compatible = "apple,spmi-pmu-nvmem" }, ++ { .compatible = "spmi-mfd-nvmem" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, spmi_mfd_nvmem_id_table); ++ ++static struct platform_driver spmi_mfd_nvmem_driver = { ++ .probe = spmi_mfd_nvmem_probe, ++ .driver = { ++ .name = "spmi-mfd-nvmem", ++ .owner = THIS_MODULE, ++ .of_match_table = spmi_mfd_nvmem_id_table, ++ }, ++}; ++ ++module_platform_driver(spmi_mfd_nvmem_driver); ++ ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_AUTHOR("Hector Martin "); ++MODULE_DESCRIPTION("SPMI MFD NVMEM driver"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0155-spmi-apple-Properly-wait-for-status-data-after-write.patch b/target/linux/silicon/patches-5.19/0155-spmi-apple-Properly-wait-for-status-data-after-write.patch new file mode 100644 index 000000000..1c6d2e726 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0155-spmi-apple-Properly-wait-for-status-data-after-write.patch @@ -0,0 +1,53 @@ +From 0324791a3cdc3e93df57f6293e2cfaaadc264aeb Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sat, 2 Jul 2022 00:24:15 +0900 +Subject: [PATCH 155/171] spmi: apple: Properly wait for status data after + write + +Signed-off-by: Hector Martin +--- + drivers/spmi/spmi-apple-controller.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/spmi/spmi-apple-controller.c b/drivers/spmi/spmi-apple-controller.c +index 3b6de8069396..5b49d6c609f5 100644 +--- a/drivers/spmi/spmi-apple-controller.c ++++ b/drivers/spmi/spmi-apple-controller.c +@@ -96,6 +96,7 @@ static int spmi_write_cmd(struct spmi_controller *ctrl, + struct apple_spmi *spmi; + u32 spmi_cmd = opc|slave_id<<8|slave_addr<<16|(bc-1)|(1<<15); + volatile u32 rsp; ++ volatile u32 status; + size_t i=0,j; + + spmi = spmi_controller_get_drvdata(ctrl); +@@ -111,12 +112,21 @@ static int spmi_write_cmd(struct spmi_controller *ctrl, + write_reg(spmi_cmd, spmi, SPMI_CMD_REG); + } + +- /* Read SPMI reply status */ +- /* do we need this while loop ? +- if yes what for ? */ ++ /* Wait for Rx FIFO to have something */ ++ /* Quite ugly msleep, need to find a better way to do it */ ++ i=0; + do { +- rsp=read_reg(spmi, SPMI_RSP_REG); +- } while (rsp==0); ++ status=read_reg(spmi, SPMI_STATUS_REG); ++ msleep(10); ++ i+=1; ++ } while ((status & SPMI_RX_FIFO_EMPTY) && i<5); ++ ++ if(i>=5){ ++ dev_err(&ctrl->dev,"spmi_write_cmd:took to long to get the status"); ++ return -1; ++ } ++ ++ rsp = read_reg(spmi, SPMI_RSP_REG); + + return 0; + } +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0156-MAINTAINERS-Add-entries-for-Apple-SoC-cpufreq-driver.patch b/target/linux/silicon/patches-5.19/0156-MAINTAINERS-Add-entries-for-Apple-SoC-cpufreq-driver.patch new file mode 100644 index 000000000..964e85ccc --- /dev/null +++ b/target/linux/silicon/patches-5.19/0156-MAINTAINERS-Add-entries-for-Apple-SoC-cpufreq-driver.patch @@ -0,0 +1,35 @@ +From 67f1aea2ba30aab3d8ceb0c711ab07da1469a37a Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 3 May 2022 00:39:01 +0900 +Subject: [PATCH 156/171] MAINTAINERS: Add entries for Apple SoC cpufreq driver + +Splitting this commit, as usual, to facilitate merges via the SoC tree. + +Signed-off-by: Hector Martin +--- + MAINTAINERS | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 64379c699903..d8cfa30457ac 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1833,6 +1833,7 @@ T: git https://github.com/AsahiLinux/linux.git + F: Documentation/devicetree/bindings/arm/apple.yaml + F: Documentation/devicetree/bindings/arm/apple/* + F: Documentation/devicetree/bindings/clock/apple,nco.yaml ++F: Documentation/devicetree/bindings/cpufreq/apple,soc-cpufreq.yaml + F: Documentation/devicetree/bindings/i2c/apple,i2c.yaml + F: Documentation/devicetree/bindings/interrupt-controller/apple,* + F: Documentation/devicetree/bindings/iommu/apple,dart.yaml +@@ -1846,6 +1847,7 @@ F: Documentation/devicetree/bindings/power/apple* + F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml + F: arch/arm64/boot/dts/apple/ + F: drivers/clk/clk-apple-nco.c ++F: drivers/cpufreq/apple-soc-cpufreq.c + F: drivers/i2c/busses/i2c-pasemi-core.c + F: drivers/i2c/busses/i2c-pasemi-platform.c + F: drivers/iommu/apple-dart.c +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0157-dt-bindings-cpufreq-apple-soc-cpufreq-Add-binding-fo.patch b/target/linux/silicon/patches-5.19/0157-dt-bindings-cpufreq-apple-soc-cpufreq-Add-binding-fo.patch new file mode 100644 index 000000000..209807ba9 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0157-dt-bindings-cpufreq-apple-soc-cpufreq-Add-binding-fo.patch @@ -0,0 +1,149 @@ +From 25e4cf1178f49d975a6fa0c50debeec42c1f98cf Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 2 May 2022 23:21:00 +0900 +Subject: [PATCH 157/171] dt-bindings: cpufreq: apple,soc-cpufreq: Add binding + for Apple SoC cpufreq + +This binding represents the cpufreq/DVFS hardware present in Apple SoCs. +The hardware has an independent controller per CPU cluster, but we +represent them as a single cpufreq node since there can only be one +systemwide cpufreq device (and since in the future, interactions with +memory controller performance states will also involve cooperation +between multiple frequency domains). + +Signed-off-by: Hector Martin +--- + .../bindings/cpufreq/apple,soc-cpufreq.yaml | 121 ++++++++++++++++++ + 1 file changed, 121 insertions(+) + create mode 100644 Documentation/devicetree/bindings/cpufreq/apple,soc-cpufreq.yaml + +diff --git a/Documentation/devicetree/bindings/cpufreq/apple,soc-cpufreq.yaml b/Documentation/devicetree/bindings/cpufreq/apple,soc-cpufreq.yaml +new file mode 100644 +index 000000000000..f398c1bd5de5 +--- /dev/null ++++ b/Documentation/devicetree/bindings/cpufreq/apple,soc-cpufreq.yaml +@@ -0,0 +1,121 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/cpufreq/apple,soc-cpufreq.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Apple SoC cpufreq device ++ ++maintainers: ++ - Hector Martin ++ ++description: | ++ Apple SoCs (e.g. M1) have a per-cpu-cluster DVFS controller that is part of ++ the cluster management register block. This binding uses the standard ++ operating-points-v2 table to define the CPU performance states, with the ++ opp-level property specifying the hardware p-state index for that level. ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - apple,t8103-soc-cpufreq ++ - apple,t6000-soc-cpufreq ++ - const: apple,soc-cpufreq ++ ++ reg: ++ minItems: 1 ++ maxItems: 6 ++ description: One register region per CPU cluster DVFS controller ++ ++ reg-names: ++ minItems: 1 ++ items: ++ - const: cluster0 ++ - const: cluster1 ++ - const: cluster2 ++ - const: cluster3 ++ - const: cluster4 ++ - const: cluster5 ++ ++ '#freq-domain-cells': ++ const: 1 ++ ++required: ++ - compatible ++ - reg ++ - reg-names ++ - '#freq-domain-cells' ++ ++additionalProperties: false ++ ++examples: ++ - | ++ // This example shows a single CPU per domain and 2 domains, ++ // with two p-states per domain. ++ // Shipping hardware has 2-4 CPUs per domain and 2-6 domains. ++ cpus { ++ #address-cells = <2>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ compatible = "apple,icestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x0>; ++ operating-points-v2 = <&ecluster_opp>; ++ apple,freq-domain = <&cpufreq_hw 0>; ++ }; ++ ++ cpu@10100 { ++ compatible = "apple,firestorm"; ++ device_type = "cpu"; ++ reg = <0x0 0x10100>; ++ operating-points-v2 = <&pcluster_opp>; ++ apple,freq-domain = <&cpufreq_hw 1>; ++ }; ++ }; ++ ++ ecluster_opp: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <7500>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <972000000>; ++ opp-level = <2>; ++ clock-latency-ns = <22000>; ++ }; ++ }; ++ ++ pcluster_opp: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <8000>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <828000000>; ++ opp-level = <2>; ++ clock-latency-ns = <19000>; ++ }; ++ }; ++ ++ soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ cpufreq_hw: cpufreq@210e20000 { ++ compatible = "apple,t8103-soc-cpufreq", "apple,soc-cpufreq"; ++ reg = <0x2 0x10e20000 0 0x1000>, ++ <0x2 0x11e20000 0 0x1000>; ++ reg-names = "cluster0", "cluster1"; ++ #freq-domain-cells = <1>; ++ }; ++ }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0158-cpufreq-apple-soc-Add-new-driver-to-control-Apple-So.patch b/target/linux/silicon/patches-5.19/0158-cpufreq-apple-soc-Add-new-driver-to-control-Apple-So.patch new file mode 100644 index 000000000..9e029ad79 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0158-cpufreq-apple-soc-Add-new-driver-to-control-Apple-So.patch @@ -0,0 +1,415 @@ +From f6dacf0c666b28f825c5c1f6cbe6792bf858f7cf Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 15 Feb 2022 21:33:32 +0900 +Subject: [PATCH 158/171] cpufreq: apple-soc: Add new driver to control Apple + SoC CPU P-states + +This driver implements CPU frequency scaling for Apple Silicon SoCs, +including M1 (t8103) and M1 Max/Pro/Ultra (t600x). + +Each CPU cluster has its own register set, and frequency management is +fully automated by the hardware; the driver only has to write one +register. There is boost frequency support, but the hardware will only +allow their use if only a subset of cores in a cluster are in +non-deep-idle. Since we don't support deep idle yet, these frequencies +are not achievable, but the driver supports them. They will remain +disabled in the device tree until deep idle is implemented, to avoid +confusing users. + +This driver does not yet implement the memory controller performance +state tuning that usually accompanies higher CPU p-states. This will be +done in a future patch. + +Signed-off-by: Hector Martin +--- + drivers/cpufreq/Kconfig.arm | 9 + + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/apple-soc-cpufreq.c | 330 +++++++++++++++++++++++++++ + drivers/cpufreq/cpufreq-dt-platdev.c | 2 + + 4 files changed, 342 insertions(+) + create mode 100644 drivers/cpufreq/apple-soc-cpufreq.c + +diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm +index 954749afb5fe..9a020a0bd9c4 100644 +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -41,6 +41,15 @@ config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM + To compile this driver as a module, choose M here: the + module will be called sun50i-cpufreq-nvmem. + ++config ARM_APPLE_SOC_CPUFREQ ++ tristate "Apple Silicon SoC CPUFreq support" ++ depends on ARCH_APPLE || COMPILE_TEST ++ select PM_OPP ++ default ARCH_APPLE ++ help ++ This adds the CPUFreq driver for Apple Silicon machines ++ (e.g. Apple M1). ++ + config ARM_ARMADA_37XX_CPUFREQ + tristate "Armada 37xx CPUFreq support" + depends on ARCH_MVEBU && CPUFREQ_DT +diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile +index 285de70af877..c0da6f2f6cd5 100644 +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -51,6 +51,7 @@ obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o + + ################################################################################## + # ARM SoC drivers ++obj-$(CONFIG_ARM_APPLE_SOC_CPUFREQ) += apple-soc-cpufreq.o + obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o + obj-$(CONFIG_ARM_ARMADA_8K_CPUFREQ) += armada-8k-cpufreq.o + obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o +diff --git a/drivers/cpufreq/apple-soc-cpufreq.c b/drivers/cpufreq/apple-soc-cpufreq.c +new file mode 100644 +index 000000000000..191eaae71744 +--- /dev/null ++++ b/drivers/cpufreq/apple-soc-cpufreq.c +@@ -0,0 +1,330 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Apple SoC CPU cluster performance state driver ++ * ++ * Copyright The Asahi Linux Contributors ++ * ++ * Based on scpi-cpufreq.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define APPLE_DVFS_CMD 0x20 ++#define APPLE_DVFS_CMD_BUSY BIT(31) ++#define APPLE_DVFS_CMD_SET BIT(25) ++#define APPLE_DVFS_CMD_PS2 GENMASK(15, 12) ++#define APPLE_DVFS_CMD_PS1 GENMASK(3, 0) ++ ++/* Same timebase as CPU counter (24MHz) */ ++#define APPLE_DVFS_LAST_CHG_TIME 0x38 ++ ++#define APPLE_DVFS_STATUS 0x50 ++#define APPLE_DVFS_STATUS_CUR_PS GENMASK(7, 4) ++#define APPLE_DVFS_STATUS_TGT_PS GENMASK(3, 0) ++ ++/* ++ * Div is +1, base clock is 12MHz on existing SoCs. ++ * For documentation purposes. We use the OPP table to ++ * get the frequency. ++ */ ++#define APPLE_DVFS_PLL_STATUS 0xc0 ++#define APPLE_DVFS_PLL_FACTOR 0xc8 ++#define APPLE_DVFS_PLL_FACTOR_MULT GENMASK(31, 16) ++#define APPLE_DVFS_PLL_FACTOR_DIV GENMASK(15, 0) ++ ++struct apple_cpu_priv { ++ struct device *cpu_dev; ++ void __iomem *reg_base; ++}; ++ ++struct apple_soc_cpufreq_priv { ++ struct device *dev; ++ void __iomem *reg_base; ++}; ++ ++#define APPLE_DVFS_TRANSITION_TIMEOUT 100 ++ ++static struct cpufreq_driver apple_soc_cpufreq_driver; ++ ++static unsigned int apple_soc_cpufreq_get_rate(unsigned int cpu) ++{ ++ struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); ++ struct apple_cpu_priv *priv = policy->driver_data; ++ u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS); ++ unsigned int pstate = FIELD_GET(APPLE_DVFS_STATUS_CUR_PS, reg); ++ unsigned int i; ++ ++ for (i = 0; policy->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) ++ if (policy->freq_table[i].driver_data == pstate) ++ return policy->freq_table[i].frequency; ++ ++ dev_err(priv->cpu_dev, "could not find frequency for pstate %d\n", ++ pstate); ++ return 0; ++} ++ ++static int apple_soc_cpufreq_set_target(struct cpufreq_policy *policy, ++ unsigned int index) ++{ ++ struct apple_cpu_priv *priv = policy->driver_data; ++ unsigned int pstate = policy->freq_table[index].driver_data; ++ u64 reg; ++ ++ if (readq_poll_timeout_atomic(priv->reg_base + APPLE_DVFS_CMD, reg, ++ !(reg & APPLE_DVFS_CMD_BUSY), 2, ++ APPLE_DVFS_TRANSITION_TIMEOUT)) { ++ return -EIO; ++ } ++ ++ reg &= ~(APPLE_DVFS_CMD_PS1 | APPLE_DVFS_CMD_PS2); ++ reg |= FIELD_PREP(APPLE_DVFS_CMD_PS1, pstate); ++ reg |= FIELD_PREP(APPLE_DVFS_CMD_PS2, pstate); ++ reg |= APPLE_DVFS_CMD_SET; ++ ++ writeq_relaxed(reg, priv->reg_base + APPLE_DVFS_CMD); ++ ++ return 0; ++} ++ ++static unsigned int apple_soc_cpufreq_fast_switch(struct cpufreq_policy *policy, ++ unsigned int target_freq) ++{ ++ if (apple_soc_cpufreq_set_target(policy, policy->cached_resolved_idx) < 0) ++ return 0; ++ ++ return policy->freq_table[policy->cached_resolved_idx].frequency; ++} ++ ++static int apple_soc_cpufreq_find_cluster(struct cpufreq_policy *policy, ++ void __iomem **reg_base) ++{ ++ struct of_phandle_args args; ++ struct device_node *cpu_np; ++ char name[32]; ++ int cpu, ret; ++ int index; ++ ++ cpu_np = of_cpu_device_node_get(policy->cpu); ++ if (!cpu_np) ++ return -EINVAL; ++ ++ ret = of_parse_phandle_with_args(cpu_np, "apple,freq-domain", ++ "#freq-domain-cells", 0, &args); ++ of_node_put(cpu_np); ++ if (ret) ++ return ret; ++ ++ index = args.args[0]; ++ ++ snprintf(name, sizeof(name), "cluster%d", index); ++ ret = of_property_match_string(args.np, "reg-names", name); ++ if (ret < 0) ++ return ret; ++ ++ *reg_base = of_iomap(args.np, ret); ++ if (IS_ERR(*reg_base)) ++ return PTR_ERR(*reg_base); ++ ++ for_each_possible_cpu(cpu) { ++ cpu_np = of_cpu_device_node_get(cpu); ++ if (!cpu_np) ++ continue; ++ ++ ret = of_parse_phandle_with_args(cpu_np, "apple,freq-domain", ++ "#freq-domain-cells", 0, &args); ++ of_node_put(cpu_np); ++ if (ret < 0) ++ continue; ++ ++ if (index == args.args[0]) ++ cpumask_set_cpu(cpu, policy->cpus); ++ } ++ ++ return 0; ++} ++ ++static struct freq_attr *apple_soc_cpufreq_hw_attr[] = { ++ &cpufreq_freq_attr_scaling_available_freqs, ++ NULL, ++ NULL, ++}; ++ ++static int apple_soc_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ int ret, i; ++ unsigned int transition_latency; ++ void __iomem *reg_base; ++ struct device *cpu_dev; ++ struct apple_cpu_priv *priv; ++ struct cpufreq_frequency_table *freq_table; ++ ++ cpu_dev = get_cpu_device(policy->cpu); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu%d device\n", policy->cpu); ++ return -ENODEV; ++ } ++ ++ ret = dev_pm_opp_of_add_table(cpu_dev); ++ if (ret < 0) { ++ dev_err(cpu_dev, "%s: failed to add OPP table: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ ret = apple_soc_cpufreq_find_cluster(policy, ®_base); ++ if (ret) { ++ dev_err(cpu_dev, "%s: failed to get cluster info: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) { ++ dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", __func__, ret); ++ goto out_iounmap; ++ } ++ ++ ret = dev_pm_opp_get_opp_count(cpu_dev); ++ if (ret <= 0) { ++ dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); ++ ret = -EPROBE_DEFER; ++ goto out_free_opp; ++ } ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto out_free_opp; ++ } ++ ++ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ++ if (ret) { ++ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); ++ goto out_free_priv; ++ } ++ ++ /* Get OPP levels (p-state indexes) and stash them in driver_data */ ++ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { ++ unsigned long rate = freq_table[i].frequency * 1000; ++ struct dev_pm_opp *opp = dev_pm_opp_find_freq_floor(cpu_dev, &rate); ++ ++ if (IS_ERR(opp)) { ++ ret = PTR_ERR(opp); ++ goto out_free_cpufreq_table; ++ } ++ freq_table[i].driver_data = dev_pm_opp_get_level(opp); ++ dev_pm_opp_put(opp); ++ } ++ ++ priv->cpu_dev = cpu_dev; ++ priv->reg_base = reg_base; ++ policy->driver_data = priv; ++ policy->freq_table = freq_table; ++ ++ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev); ++ if (!transition_latency) ++ transition_latency = CPUFREQ_ETERNAL; ++ ++ policy->cpuinfo.transition_latency = transition_latency; ++ policy->dvfs_possible_from_any_cpu = true; ++ policy->fast_switch_possible = true; ++ ++ if (policy_has_boost_freq(policy)) { ++ ret = cpufreq_enable_boost_support(); ++ if (ret) { ++ dev_warn(cpu_dev, "failed to enable boost: %d\n", ret); ++ } else { ++ apple_soc_cpufreq_hw_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs; ++ apple_soc_cpufreq_driver.boost_enabled = true; ++ } ++ } ++ ++ return 0; ++ ++out_free_cpufreq_table: ++ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); ++out_free_priv: ++ kfree(priv); ++out_free_opp: ++ dev_pm_opp_remove_all_dynamic(cpu_dev); ++out_iounmap: ++ iounmap(reg_base); ++ return ret; ++} ++ ++static int apple_soc_cpufreq_exit(struct cpufreq_policy *policy) ++{ ++ struct apple_cpu_priv *priv = policy->driver_data; ++ ++ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); ++ dev_pm_opp_remove_all_dynamic(priv->cpu_dev); ++ iounmap(priv->reg_base); ++ kfree(priv); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver apple_soc_cpufreq_driver = { ++ .name = "apple-cpufreq", ++ .flags = CPUFREQ_HAVE_GOVERNOR_PER_POLICY | ++ CPUFREQ_NEED_INITIAL_FREQ_CHECK | CPUFREQ_IS_COOLING_DEV, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .attr = cpufreq_generic_attr, ++ .get = apple_soc_cpufreq_get_rate, ++ .init = apple_soc_cpufreq_init, ++ .exit = apple_soc_cpufreq_exit, ++ .target_index = apple_soc_cpufreq_set_target, ++ .fast_switch = apple_soc_cpufreq_fast_switch, ++ .register_em = cpufreq_register_em_with_opp, ++ .attr = apple_soc_cpufreq_hw_attr, ++}; ++ ++static int apple_soc_cpufreq_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ ret = cpufreq_register_driver(&apple_soc_cpufreq_driver); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "registering cpufreq failed\n"); ++ ++ return 0; ++} ++ ++static int apple_soc_cpufreq_remove(struct platform_device *pdev) ++{ ++ cpufreq_unregister_driver(&apple_soc_cpufreq_driver); ++ ++ return 0; ++} ++ ++static const struct of_device_id apple_soc_cpufreq_of_match[] = { ++ { .compatible = "apple,soc-cpufreq" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, apple_soc_cpufreq_of_match); ++ ++static struct platform_driver apple_soc_cpufreq_plat_driver = { ++ .probe = apple_soc_cpufreq_probe, ++ .remove = apple_soc_cpufreq_remove, ++ .driver = { ++ .name = "apple-soc-cpufreq", ++ .of_match_table = apple_soc_cpufreq_of_match, ++ }, ++}; ++module_platform_driver(apple_soc_cpufreq_plat_driver); ++ ++MODULE_AUTHOR("Hector Martin "); ++MODULE_DESCRIPTION("Apple SoC CPU cluster DVFS driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c +index 2c96de3f2d83..12b203d67779 100644 +--- a/drivers/cpufreq/cpufreq-dt-platdev.c ++++ b/drivers/cpufreq/cpufreq-dt-platdev.c +@@ -103,6 +103,8 @@ static const struct of_device_id allowlist[] __initconst = { + static const struct of_device_id blocklist[] __initconst = { + { .compatible = "allwinner,sun50i-h6", }, + ++ { .compatible = "apple,arm-platform", }, ++ + { .compatible = "arm,vexpress", }, + + { .compatible = "calxeda,highbank", }, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0159-arm64-dts-apple-Add-CPU-topology-cpufreq-nodes-for-t.patch b/target/linux/silicon/patches-5.19/0159-arm64-dts-apple-Add-CPU-topology-cpufreq-nodes-for-t.patch new file mode 100644 index 000000000..50415c4fd --- /dev/null +++ b/target/linux/silicon/patches-5.19/0159-arm64-dts-apple-Add-CPU-topology-cpufreq-nodes-for-t.patch @@ -0,0 +1,313 @@ +From 88d527252dd22783add30df234725530fc5c4934 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 3 May 2022 00:08:56 +0900 +Subject: [PATCH 159/171] arm64: dts: apple: Add CPU topology & cpufreq nodes + for t8103 + +Add the missing CPU topology/capacity information and the cpufreq nodes, +so we can have CPU frequency scaling and the scheduler has the +information it needs to make the correct decisions. + +Boost states are commented out, as they are not yet available (that +requires CPU deep sleep support, to be eventually done via PSCI). +The driver supports them fine; the hardware will just refuse to ever +go into them at this time, so don't expose them to users until that's +done. + +Signed-off-by: Hector Martin +--- + arch/arm64/boot/dts/apple/t8103.dtsi | 203 +++++++++++++++++++++++++-- + 1 file changed, 193 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi +index 9f8f4145db88..3df126a5a7dd 100644 +--- a/arch/arm64/boot/dts/apple/t8103.dtsi ++++ b/arch/arm64/boot/dts/apple/t8103.dtsi +@@ -22,71 +22,245 @@ cpus { + #address-cells = <2>; + #size-cells = <0>; + +- cpu0: cpu@0 { ++ cpu-map { ++ cluster0 { ++ core0 { ++ cpu = <&cpu_e0>; ++ }; ++ core1 { ++ cpu = <&cpu_e1>; ++ }; ++ core2 { ++ cpu = <&cpu_e2>; ++ }; ++ core3 { ++ cpu = <&cpu_e3>; ++ }; ++ }; ++ ++ cluster1 { ++ core0 { ++ cpu = <&cpu_p0>; ++ }; ++ core1 { ++ cpu = <&cpu_p1>; ++ }; ++ core2 { ++ cpu = <&cpu_p2>; ++ }; ++ core3 { ++ cpu = <&cpu_p3>; ++ }; ++ }; ++ }; ++ ++ cpu_e0: cpu@0 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + +- cpu1: cpu@1 { ++ cpu_e1: cpu@1 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + +- cpu2: cpu@2 { ++ cpu_e2: cpu@2 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + +- cpu3: cpu@3 { ++ cpu_e3: cpu@3 { + compatible = "apple,icestorm"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&ecluster_opp>; ++ capacity-dmips-mhz = <714>; ++ apple,freq-domain = <&cpufreq_hw 0>; + }; + +- cpu4: cpu@10100 { ++ cpu_p0: cpu@10100 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + +- cpu5: cpu@10101 { ++ cpu_p1: cpu@10101 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + +- cpu6: cpu@10102 { ++ cpu_p2: cpu@10102 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10102>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; + }; + +- cpu7: cpu@10103 { ++ cpu_p3: cpu@10103 { + compatible = "apple,firestorm"; + device_type = "cpu"; + reg = <0x0 0x10103>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ ++ operating-points-v2 = <&pcluster_opp>; ++ capacity-dmips-mhz = <1024>; ++ apple,freq-domain = <&cpufreq_hw 1>; ++ }; ++ }; ++ ++ ecluster_opp: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <7500>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <972000000>; ++ opp-level = <2>; ++ clock-latency-ns = <22000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <1332000000>; ++ opp-level = <3>; ++ clock-latency-ns = <27000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-level = <4>; ++ clock-latency-ns = <33000>; ++ }; ++ opp05 { ++ opp-hz = /bits/ 64 <2064000000>; ++ opp-level = <5>; ++ clock-latency-ns = <50000>; + }; + }; + ++ pcluster_opp: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp01 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-level = <1>; ++ clock-latency-ns = <8000>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <828000000>; ++ opp-level = <2>; ++ clock-latency-ns = <19000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <1056000000>; ++ opp-level = <3>; ++ clock-latency-ns = <21000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <1284000000>; ++ opp-level = <4>; ++ clock-latency-ns = <23000>; ++ }; ++ opp05 { ++ opp-hz = /bits/ 64 <1500000000>; ++ opp-level = <5>; ++ clock-latency-ns = <24000>; ++ }; ++ opp06 { ++ opp-hz = /bits/ 64 <1728000000>; ++ opp-level = <6>; ++ clock-latency-ns = <29000>; ++ }; ++ opp07 { ++ opp-hz = /bits/ 64 <1956000000>; ++ opp-level = <7>; ++ clock-latency-ns = <31000>; ++ }; ++ opp08 { ++ opp-hz = /bits/ 64 <2184000000>; ++ opp-level = <8>; ++ clock-latency-ns = <34000>; ++ }; ++ opp09 { ++ opp-hz = /bits/ 64 <2388000000>; ++ opp-level = <9>; ++ clock-latency-ns = <36000>; ++ }; ++ opp10 { ++ opp-hz = /bits/ 64 <2592000000>; ++ opp-level = <10>; ++ clock-latency-ns = <51000>; ++ }; ++ opp11 { ++ opp-hz = /bits/ 64 <2772000000>; ++ opp-level = <11>; ++ clock-latency-ns = <54000>; ++ }; ++ opp12 { ++ opp-hz = /bits/ 64 <2988000000>; ++ opp-level = <12>; ++ clock-latency-ns = <55000>; ++ }; ++#if 0 ++ /* Not available until CPU deep sleep is implemented */ ++ opp13 { ++ opp-hz = /bits/ 64 <3096000000>; ++ opp-level = <13>; ++ clock-latency-ns = <55000>; ++ turbo-mode; ++ }; ++ opp14 { ++ opp-hz = /bits/ 64 <3144000000>; ++ opp-level = <14>; ++ clock-latency-ns = <56000>; ++ turbo-mode; ++ }; ++ opp15 { ++ opp-hz = /bits/ 64 <3204000000>; ++ opp-level = <15>; ++ clock-latency-ns = <56000>; ++ turbo-mode; ++ }; ++#endif ++ }; ++ + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; +@@ -124,6 +298,15 @@ soc { + ranges; + nonposted-mmio; + ++ cpufreq_hw: cpufreq@210e20000 { ++ compatible = "apple,t8103-soc-cpufreq", "apple,soc-cpufreq"; ++ reg = <0x2 0x10e20000 0 0x1000>, ++ <0x2 0x11e20000 0 0x1000>; ++ reg-names = "cluster0", "cluster1"; ++ ++ #freq-domain-cells = <1>; ++ }; ++ + i2c0: i2c@235010000 { + compatible = "apple,t8103-i2c", "apple,i2c"; + reg = <0x2 0x35010000 0x0 0x4000>; +@@ -229,12 +412,12 @@ aic: interrupt-controller@23b100000 { + affinities { + e-core-pmu-affinity { + apple,fiq-index = ; +- cpus = <&cpu0 &cpu1 &cpu2 &cpu3>; ++ cpus = <&cpu_e0 &cpu_e1 &cpu_e2 &cpu_e3>; + }; + + p-core-pmu-affinity { + apple,fiq-index = ; +- cpus = <&cpu4 &cpu5 &cpu6 &cpu7>; ++ cpus = <&cpu_p0 &cpu_p1 &cpu_p2 &cpu_p3>; + }; + }; + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0160-cpufreq-apple-soc-Add-T8112-support.patch b/target/linux/silicon/patches-5.19/0160-cpufreq-apple-soc-Add-T8112-support.patch new file mode 100644 index 000000000..dbab8bc58 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0160-cpufreq-apple-soc-Add-T8112-support.patch @@ -0,0 +1,180 @@ +From 0aea6b8ab572e33f5149915c7ae8259be48042e8 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 27 Jun 2022 21:51:01 +0900 +Subject: [PATCH 160/171] cpufreq: apple-soc: Add T8112 support + +Apple ran out of bits for the pstates in one of the registers, so we +unfortunately need SoC-specific tweaks now. + +Signed-off-by: Hector Martin +--- + drivers/cpufreq/apple-soc-cpufreq.c | 91 ++++++++++++++++++++++++----- + 1 file changed, 77 insertions(+), 14 deletions(-) + +diff --git a/drivers/cpufreq/apple-soc-cpufreq.c b/drivers/cpufreq/apple-soc-cpufreq.c +index 191eaae71744..a92f7e7c57b5 100644 +--- a/drivers/cpufreq/apple-soc-cpufreq.c ++++ b/drivers/cpufreq/apple-soc-cpufreq.c +@@ -23,19 +23,28 @@ + #include + #include + ++#define APPLE_DVFS_PSTATE_BITS_T8103 4 ++#define APPLE_DVFS_PSTATE_BITS_T8112 5 ++ + #define APPLE_DVFS_CMD 0x20 + #define APPLE_DVFS_CMD_BUSY BIT(31) + #define APPLE_DVFS_CMD_SET BIT(25) +-#define APPLE_DVFS_CMD_PS2 GENMASK(15, 12) +-#define APPLE_DVFS_CMD_PS1 GENMASK(3, 0) ++#define APPLE_DVFS_CMD_PS2 GENMASK(16, 12) ++#define APPLE_DVFS_CMD_PS1 GENMASK(4, 0) + + /* Same timebase as CPU counter (24MHz) */ + #define APPLE_DVFS_LAST_CHG_TIME 0x38 + +-#define APPLE_DVFS_STATUS 0x50 +-#define APPLE_DVFS_STATUS_CUR_PS GENMASK(7, 4) +-#define APPLE_DVFS_STATUS_TGT_PS GENMASK(3, 0) +- ++/* ++ * Apple ran out of bits and had to shift this in T8112... ++ */ ++#define APPLE_DVFS_STATUS 0x50 ++#define APPLE_DVFS_STATUS_CUR_PS_T8103 GENMASK(7, 4) ++#define APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8103 4 ++#define APPLE_DVFS_STATUS_TGT_PS_T8103 GENMASK(3, 0) ++#define APPLE_DVFS_STATUS_CUR_PS_T8112 GENMASK(9, 5) ++#define APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8112 5 ++#define APPLE_DVFS_STATUS_TGT_PS_T8112 GENMASK(4, 0) + /* + * Div is +1, base clock is 12MHz on existing SoCs. + * For documentation purposes. We use the OPP table to +@@ -46,14 +55,16 @@ + #define APPLE_DVFS_PLL_FACTOR_MULT GENMASK(31, 16) + #define APPLE_DVFS_PLL_FACTOR_DIV GENMASK(15, 0) + +-struct apple_cpu_priv { +- struct device *cpu_dev; +- void __iomem *reg_base; ++struct apple_soc_cpufreq_info { ++ u64 max_pstate; ++ u64 cur_pstate_mask; ++ u64 cur_pstate_shift; + }; + +-struct apple_soc_cpufreq_priv { +- struct device *dev; ++struct apple_cpu_priv { ++ struct device *cpu_dev; + void __iomem *reg_base; ++ const struct apple_soc_cpufreq_info *info; + }; + + #define APPLE_DVFS_TRANSITION_TIMEOUT 100 +@@ -64,10 +75,21 @@ static unsigned int apple_soc_cpufreq_get_rate(unsigned int cpu) + { + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + struct apple_cpu_priv *priv = policy->driver_data; +- u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS); +- unsigned int pstate = FIELD_GET(APPLE_DVFS_STATUS_CUR_PS, reg); ++ unsigned int pstate; + unsigned int i; + ++ if (priv->info->cur_pstate_mask) { ++ u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS); ++ pstate = (reg & priv->info->cur_pstate_mask) >> priv->info->cur_pstate_shift; ++ } else { ++ /* ++ * For the fallback case we might not know the layout of DVFS_STATUS, ++ * so just use the command register value (which ignores boost limitations). ++ */ ++ u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_CMD); ++ pstate = FIELD_GET(APPLE_DVFS_CMD_PS1, reg); ++ } ++ + for (i = 0; policy->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) + if (policy->freq_table[i].driver_data == pstate) + return policy->freq_table[i].frequency; +@@ -84,6 +106,10 @@ static int apple_soc_cpufreq_set_target(struct cpufreq_policy *policy, + unsigned int pstate = policy->freq_table[index].driver_data; + u64 reg; + ++ /* Fallback for newer SoCs */ ++ if (index > priv->info->max_pstate) ++ index = priv->info->max_pstate; ++ + if (readq_poll_timeout_atomic(priv->reg_base + APPLE_DVFS_CMD, reg, + !(reg & APPLE_DVFS_CMD_BUSY), 2, + APPLE_DVFS_TRANSITION_TIMEOUT)) { +@@ -171,6 +197,7 @@ static int apple_soc_cpufreq_init(struct cpufreq_policy *policy) + struct device *cpu_dev; + struct apple_cpu_priv *priv; + struct cpufreq_frequency_table *freq_table; ++ struct platform_device *pdev = cpufreq_get_driver_data(); + + cpu_dev = get_cpu_device(policy->cpu); + if (!cpu_dev) { +@@ -209,6 +236,12 @@ static int apple_soc_cpufreq_init(struct cpufreq_policy *policy) + goto out_free_opp; + } + ++ priv->info = of_device_get_match_data(&pdev->dev); ++ if (!priv->info) { ++ ret = -ENODEV; ++ goto out_free_opp; ++ } ++ + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); +@@ -295,6 +328,8 @@ static int apple_soc_cpufreq_probe(struct platform_device *pdev) + { + int ret; + ++ apple_soc_cpufreq_driver.driver_data = pdev; ++ + ret = cpufreq_register_driver(&apple_soc_cpufreq_driver); + if (ret) + return dev_err_probe(&pdev->dev, ret, "registering cpufreq failed\n"); +@@ -309,8 +344,36 @@ static int apple_soc_cpufreq_remove(struct platform_device *pdev) + return 0; + } + ++const struct apple_soc_cpufreq_info soc_t8103_info = { ++ .max_pstate = 15, ++ .cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_T8103, ++ .cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8103, ++}; ++ ++const struct apple_soc_cpufreq_info soc_t8112_info = { ++ .max_pstate = 31, ++ .cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_T8112, ++ .cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8112, ++}; ++ ++const struct apple_soc_cpufreq_info soc_default_info = { ++ .max_pstate = 15, ++ .cur_pstate_mask = 0, /* fallback */ ++}; ++ + static const struct of_device_id apple_soc_cpufreq_of_match[] = { +- { .compatible = "apple,soc-cpufreq" }, ++ { ++ .compatible = "apple,t8103-soc-cpufreq", ++ .data = &soc_t8103_info, ++ }, ++ { ++ .compatible = "apple,t8112-cpufreq", ++ .data = &soc_t8112_info, ++ }, ++ { ++ .compatible = "apple,soc-cpufreq", ++ .data = &soc_default_info, ++ }, + {} + }; + MODULE_DEVICE_TABLE(of, apple_soc_cpufreq_of_match); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0161-dt-bindings-pci-apple-pcie-Add-subnode-binding-pwren.patch b/target/linux/silicon/patches-5.19/0161-dt-bindings-pci-apple-pcie-Add-subnode-binding-pwren.patch new file mode 100644 index 000000000..fbcf5547c --- /dev/null +++ b/target/linux/silicon/patches-5.19/0161-dt-bindings-pci-apple-pcie-Add-subnode-binding-pwren.patch @@ -0,0 +1,111 @@ +From abe02ae2854e6679bf9b46ade3b6c6ddc379050f Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 2 May 2022 21:17:41 +0900 +Subject: [PATCH 161/171] dt-bindings: pci: apple,pcie: Add subnode binding, + pwren-gpios property + +We weren't properly validating root port subnodes, so let's do that. Then, +also add the new `pwren-gpios` property there to handle device power-up. + +Signed-off-by: Hector Martin +--- + .../devicetree/bindings/pci/apple,pcie.yaml | 51 +++++++++++++++++-- + 1 file changed, 48 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/pci/apple,pcie.yaml b/Documentation/devicetree/bindings/pci/apple,pcie.yaml +index aa38680aaaca..156f1777fc96 100644 +--- a/Documentation/devicetree/bindings/pci/apple,pcie.yaml ++++ b/Documentation/devicetree/bindings/pci/apple,pcie.yaml +@@ -71,6 +71,27 @@ properties: + power-domains: + maxItems: 1 + ++patternProperties: ++ "^pci@": ++ $ref: /schemas/pci/pci-bus.yaml# ++ type: object ++ description: A single PCI root port ++ ++ properties: ++ reg: ++ maxItems: 1 ++ ++ pwren-gpios: ++ description: Optional GPIO to power on the device ++ maxItems: 1 ++ ++ required: ++ - reset-gpios ++ - interrupt-controller ++ - "#interrupt-cells" ++ - interrupt-map-mask ++ - interrupt-map ++ + required: + - compatible + - reg +@@ -141,7 +162,7 @@ examples: + pinctrl-0 = <&pcie_pins>; + pinctrl-names = "default"; + +- pci@0,0 { ++ port00: pci@0,0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + reset-gpios = <&pinctrl_ap 152 0>; +@@ -149,9 +170,17 @@ examples: + #address-cells = <3>; + #size-cells = <2>; + ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port00 0 0 0 0>, ++ <0 0 0 2 &port00 0 0 0 1>, ++ <0 0 0 3 &port00 0 0 0 2>, ++ <0 0 0 4 &port00 0 0 0 3>; + }; + +- pci@1,0 { ++ port01: pci@1,0 { + device_type = "pci"; + reg = <0x800 0x0 0x0 0x0 0x0>; + reset-gpios = <&pinctrl_ap 153 0>; +@@ -159,9 +188,17 @@ examples: + #address-cells = <3>; + #size-cells = <2>; + ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port01 0 0 0 0>, ++ <0 0 0 2 &port01 0 0 0 1>, ++ <0 0 0 3 &port01 0 0 0 2>, ++ <0 0 0 4 &port01 0 0 0 3>; + }; + +- pci@2,0 { ++ port02: pci@2,0 { + device_type = "pci"; + reg = <0x1000 0x0 0x0 0x0 0x0>; + reset-gpios = <&pinctrl_ap 33 0>; +@@ -169,6 +206,14 @@ examples: + #address-cells = <3>; + #size-cells = <2>; + ranges; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &port02 0 0 0 0>, ++ <0 0 0 2 &port02 0 0 0 1>, ++ <0 0 0 3 &port02 0 0 0 2>, ++ <0 0 0 4 &port02 0 0 0 3>; + }; + }; + }; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0162-PCI-apple-Use-gpiod_set_value_cansleep-in-probe-flow.patch b/target/linux/silicon/patches-5.19/0162-PCI-apple-Use-gpiod_set_value_cansleep-in-probe-flow.patch new file mode 100644 index 000000000..e2ffd13d5 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0162-PCI-apple-Use-gpiod_set_value_cansleep-in-probe-flow.patch @@ -0,0 +1,41 @@ +From b86825a0013059fc20d720e140abbc8dbf1ec8f1 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Mon, 2 May 2022 21:22:46 +0900 +Subject: [PATCH 162/171] PCI: apple: Use gpiod_set_value_cansleep in probe + flow + +We're allowed to sleep here, so tell the GPIO core by using +gpiod_set_value_cansleep instead of gpiod_set_value. + +Fixes: 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up") +Acked-by: Marc Zyngier +Signed-off-by: Hector Martin +--- + drivers/pci/controller/pcie-apple.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c +index a2c3c207a04b..e6c34a0875b3 100644 +--- a/drivers/pci/controller/pcie-apple.c ++++ b/drivers/pci/controller/pcie-apple.c +@@ -541,7 +541,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, + rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK); + + /* Assert PERST# before setting up the clock */ +- gpiod_set_value(reset, 1); ++ gpiod_set_value_cansleep(reset, 1); + + ret = apple_pcie_setup_refclk(pcie, port); + if (ret < 0) +@@ -552,7 +552,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, + + /* Deassert PERST# */ + rmw_set(PORT_PERST_OFF, port->base + PORT_PERST); +- gpiod_set_value(reset, 0); ++ gpiod_set_value_cansleep(reset, 0); + + /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ + msleep(100); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0163-PCI-apple-Use-devm-managed-GPIO-getter.patch b/target/linux/silicon/patches-5.19/0163-PCI-apple-Use-devm-managed-GPIO-getter.patch new file mode 100644 index 000000000..96f15b8f7 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0163-PCI-apple-Use-devm-managed-GPIO-getter.patch @@ -0,0 +1,34 @@ +From 4d1d3b02286889607ae65fbbe9b4ac1b9a71e3b3 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 6 Feb 2022 21:13:17 +0900 +Subject: [PATCH 163/171] PCI: apple: Use devm managed GPIO getter + +Without this, if the driver fails to probe it will leak GPIO references. +Fix this by using the devm managed getter. + +Fixes: 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up") +Cc: stable@vger.kernel.org +Acked-by: Marc Zyngier +Signed-off-by: Hector Martin +--- + drivers/pci/controller/pcie-apple.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c +index e6c34a0875b3..e0c06c0ee731 100644 +--- a/drivers/pci/controller/pcie-apple.c ++++ b/drivers/pci/controller/pcie-apple.c +@@ -516,8 +516,8 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, + u32 stat, idx; + int ret, i; + +- reset = gpiod_get_from_of_node(np, "reset-gpios", 0, +- GPIOD_OUT_LOW, "PERST#"); ++ reset = devm_gpiod_get_from_of_node(pcie->dev, np, "reset-gpios", 0, ++ GPIOD_OUT_LOW, "PERST#"); + if (IS_ERR(reset)) + return PTR_ERR(reset); + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0164-PCI-apple-Probe-all-GPIOs-for-availability-first.patch b/target/linux/silicon/patches-5.19/0164-PCI-apple-Probe-all-GPIOs-for-availability-first.patch new file mode 100644 index 000000000..de3b07c86 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0164-PCI-apple-Probe-all-GPIOs-for-availability-first.patch @@ -0,0 +1,67 @@ +From 7a73f4e58f44b76abd4eeec2b84b09da515403c5 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 6 Feb 2022 21:15:39 +0900 +Subject: [PATCH 164/171] PCI: apple: Probe all GPIOs for availability first + +If we're probing the PCI controller and some GPIOs are not available and +cause a probe defer, we can end up leaving some ports initialized and +not others and making a mess. + +Check for PERST# GPIOs for all ports first, and just return +-EPROBE_DEFER if any are not ready yet, without bringing anything up. + +Fixes: 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up") +Cc: stable@vger.kernel.org +Acked-by: Marc Zyngier +Signed-off-by: Hector Martin +--- + drivers/pci/controller/pcie-apple.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c +index e0c06c0ee731..e3aa2d461739 100644 +--- a/drivers/pci/controller/pcie-apple.c ++++ b/drivers/pci/controller/pcie-apple.c +@@ -507,6 +507,20 @@ static u32 apple_pcie_rid2sid_write(struct apple_pcie_port *port, + return readl_relaxed(port->base + PORT_RID2SID(idx)); + } + ++static int apple_pcie_probe_port(struct device_node *np) ++{ ++ struct gpio_desc *gd; ++ ++ gd = gpiod_get_from_of_node(np, "reset-gpios", 0, ++ GPIOD_OUT_LOW, "PERST#"); ++ if (IS_ERR(gd)) { ++ return PTR_ERR(gd); ++ } ++ ++ gpiod_put(gd); ++ return 0; ++} ++ + static int apple_pcie_setup_port(struct apple_pcie *pcie, + struct device_node *np) + { +@@ -797,8 +811,18 @@ static int apple_pcie_init(struct pci_config_window *cfg) + + static int apple_pcie_probe(struct platform_device *pdev) + { ++ struct device *dev = &pdev->dev; ++ struct device_node *of_port; + int ret; + ++ /* Check for probe dependencies for all ports first */ ++ for_each_child_of_node(dev->of_node, of_port) { ++ ret = apple_pcie_probe_port(of_port); ++ of_node_put(of_port); ++ if (ret) ++ return dev_err_probe(dev, ret, "Port %pOF probe fail\n", of_port); ++ } ++ + ret = bus_register_notifier(&pci_bus_type, &apple_pcie_nb); + if (ret) + return ret; +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0165-PCI-apple-Add-support-for-optional-PWREN-GPIO.patch b/target/linux/silicon/patches-5.19/0165-PCI-apple-Add-support-for-optional-PWREN-GPIO.patch new file mode 100644 index 000000000..7fa4d26d9 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0165-PCI-apple-Add-support-for-optional-PWREN-GPIO.patch @@ -0,0 +1,88 @@ +From 6cb714273e04b6d82734c6c8a70907f3871e409b Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Sun, 6 Feb 2022 21:18:18 +0900 +Subject: [PATCH 165/171] PCI: apple: Add support for optional PWREN GPIO + +WiFi and SD card devices on M1 Macs have a separate power enable GPIO. +Add support for this to the PCIe controller. This is modeled after how +pcie-fu740 does it. + +Acked-by: Marc Zyngier +Signed-off-by: Hector Martin +--- + drivers/pci/controller/pcie-apple.c | 34 ++++++++++++++++++++++++++--- + 1 file changed, 31 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c +index e3aa2d461739..f26a617ea5c5 100644 +--- a/drivers/pci/controller/pcie-apple.c ++++ b/drivers/pci/controller/pcie-apple.c +@@ -518,6 +518,16 @@ static int apple_pcie_probe_port(struct device_node *np) + } + + gpiod_put(gd); ++ ++ gd = gpiod_get_from_of_node(np, "pwren-gpios", 0, ++ GPIOD_OUT_LOW, "PWREN"); ++ if (IS_ERR(gd)) { ++ if (PTR_ERR(gd) != -ENOENT) ++ return PTR_ERR(gd); ++ } else { ++ gpiod_put(gd); ++ } ++ + return 0; + } + +@@ -526,7 +536,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, + { + struct platform_device *platform = to_platform_device(pcie->dev); + struct apple_pcie_port *port; +- struct gpio_desc *reset; ++ struct gpio_desc *reset, *pwren = NULL; + u32 stat, idx; + int ret, i; + +@@ -535,6 +545,15 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, + if (IS_ERR(reset)) + return PTR_ERR(reset); + ++ pwren = devm_gpiod_get_from_of_node(pcie->dev, np, "pwren-gpios", 0, ++ GPIOD_OUT_LOW, "PWREN"); ++ if (IS_ERR(pwren)) { ++ if (PTR_ERR(pwren) == -ENOENT) ++ pwren = NULL; ++ else ++ return PTR_ERR(pwren); ++ } ++ + port = devm_kzalloc(pcie->dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; +@@ -557,12 +576,21 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, + /* Assert PERST# before setting up the clock */ + gpiod_set_value_cansleep(reset, 1); + ++ /* Power on the device if required */ ++ gpiod_set_value_cansleep(pwren, 1); ++ + ret = apple_pcie_setup_refclk(pcie, port); + if (ret < 0) + return ret; + +- /* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) */ +- usleep_range(100, 200); ++ /* ++ * The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) ++ * If powering up, the minimal Tpvperl is 100ms ++ */ ++ if (pwren) ++ msleep(100); ++ else ++ usleep_range(100, 200); + + /* Deassert PERST# */ + rmw_set(PORT_PERST_OFF, port->base + PORT_PERST); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0166-dt-bindings-net-Add-generic-Bluetooth-controller.patch b/target/linux/silicon/patches-5.19/0166-dt-bindings-net-Add-generic-Bluetooth-controller.patch new file mode 100644 index 000000000..90bb4cb2e --- /dev/null +++ b/target/linux/silicon/patches-5.19/0166-dt-bindings-net-Add-generic-Bluetooth-controller.patch @@ -0,0 +1,65 @@ +From 570cca032385f16aa24be9b226172d82bd153e25 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Mon, 1 Aug 2022 12:36:29 +0200 +Subject: [PATCH 166/171] dt-bindings: net: Add generic Bluetooth controller + +Bluetooth controllers share the common local-bd-address property. +Add a generic YAML schema to replace bluetooth.txt for those. + +Signed-off-by: Sven Peter +--- + .../bindings/net/bluetooth-controller.yaml | 30 +++++++++++++++++++ + .../devicetree/bindings/net/bluetooth.txt | 6 +--- + 2 files changed, 31 insertions(+), 5 deletions(-) + create mode 100644 Documentation/devicetree/bindings/net/bluetooth-controller.yaml + +diff --git a/Documentation/devicetree/bindings/net/bluetooth-controller.yaml b/Documentation/devicetree/bindings/net/bluetooth-controller.yaml +new file mode 100644 +index 000000000000..0ea8a20e30f9 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/bluetooth-controller.yaml +@@ -0,0 +1,30 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/bluetooth-controller.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Bluetooth Controller Generic Binding ++ ++maintainers: ++ - Marcel Holtmann ++ - Johan Hedberg ++ - Luiz Augusto von Dentz ++ ++properties: ++ $nodename: ++ pattern: "^bluetooth(@.*)?$" ++ ++ local-bd-address: ++ $ref: /schemas/types.yaml#/definitions/uint8-array ++ minItems: 6 ++ maxItems: 6 ++ description: ++ Specifies the BD address that was uniquely assigned to the Bluetooth ++ device. Formatted with least significant byte first (little-endian), e.g. ++ in order to assign the address 00:11:22:33:44:55 this property must have ++ the value [55 44 33 22 11 00]. ++ ++additionalProperties: true ++ ++... +diff --git a/Documentation/devicetree/bindings/net/bluetooth.txt b/Documentation/devicetree/bindings/net/bluetooth.txt +index 94797df751b8..3cb5a7b8e5ad 100644 +--- a/Documentation/devicetree/bindings/net/bluetooth.txt ++++ b/Documentation/devicetree/bindings/net/bluetooth.txt +@@ -1,5 +1 @@ +-The following properties are common to the Bluetooth controllers: +- +-- local-bd-address: array of 6 bytes, specifies the BD address that was +- uniquely assigned to the Bluetooth device, formatted with least significant +- byte first (little-endian). ++This file has been moved to bluetooth-controller.yaml. +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0167-dt-bindings-net-Add-Broadcom-BCM4377-family-PCI-Blue.patch b/target/linux/silicon/patches-5.19/0167-dt-bindings-net-Add-Broadcom-BCM4377-family-PCI-Blue.patch new file mode 100644 index 000000000..360f2b5ef --- /dev/null +++ b/target/linux/silicon/patches-5.19/0167-dt-bindings-net-Add-Broadcom-BCM4377-family-PCI-Blue.patch @@ -0,0 +1,116 @@ +From 595ee6d1d91d35bd9c461f6459458a8d91d70f3e Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Mon, 1 Aug 2022 12:36:30 +0200 +Subject: [PATCH 167/171] dt-bindings: net: Add Broadcom BCM4377 family PCI + Bluetooth + +These chips are combined Wi-Fi/Bluetooth radios which expose a +PCI subfunction for the Bluetooth part. +They are found in Apple machines such as the x86 models with the T2 +chip or the arm64 models with the M1 or M2 chips. + +Signed-off-by: Sven Peter +--- + .../bindings/net/brcm,bcm4377-bluetooth.yaml | 77 +++++++++++++++++++ + MAINTAINERS | 1 + + 2 files changed, 78 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/brcm,bcm4377-bluetooth.yaml + +diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4377-bluetooth.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4377-bluetooth.yaml +new file mode 100644 +index 000000000000..afe6ecebd939 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/brcm,bcm4377-bluetooth.yaml +@@ -0,0 +1,77 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/brcm,bcm4377-bluetooth.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom BCM4377 family PCI Bluetooth Chips ++ ++allOf: ++ - $ref: bluetooth-controller.yaml# ++ ++maintainers: ++ - Sven Peter ++ ++description: ++ This binding describes Broadcom BCM4377 family PCI-attached bluetooth chips ++ usually found in Apple machines. The Wi-Fi part of the chip is described in ++ bindings/net/wireless/brcm,bcm4329-fmac.yaml. ++ ++properties: ++ compatible: ++ enum: ++ - pci14e4,5fa0 # BCM4377 ++ - pci14e4,5f69 # BCM4378 ++ - pci14e4,5f71 # BCM4387 ++ ++ reg: ++ description: PCI device identifier. ++ ++ brcm,board-type: ++ $ref: /schemas/types.yaml#/definitions/string ++ description: Board type of the Bluetooth chip. This is used to decouple ++ the overall system board from the Bluetooth module and used to construct ++ firmware and calibration data filenames. ++ On Apple platforms, this should be the Apple module-instance codename ++ prefixed by "apple,", e.g. "apple,atlantisb". ++ ++ brcm,taurus-cal-blob: ++ $ref: /schemas/types.yaml#/definitions/uint8-array ++ description: A per-device calibration blob for the Bluetooth radio. This ++ should be filled in by the bootloader from platform configuration ++ data, if necessary, and will be uploaded to the device. ++ This blob is used if the chip stepping of the Bluetooth module does not ++ support beamforming. ++ ++ brcm,taurus-bf-cal-blob: ++ $ref: /schemas/types.yaml#/definitions/uint8-array ++ description: A per-device calibration blob for the Bluetooth radio. This ++ should be filled in by the bootloader from platform configuration ++ data, if necessary, and will be uploaded to the device. ++ This blob is used if the chip stepping of the Bluetooth module supports ++ beamforming. ++ ++ local-bd-address: true ++ ++required: ++ - compatible ++ - reg ++ - local-bd-address ++ - brcm,board-type ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pci0 { ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bluetooth@0,1 { ++ compatible = "pci14e4,5f69"; ++ reg = <0x10100 0x0 0x0 0x0 0x0>; ++ brcm,board-type = "apple,honshu"; ++ /* To be filled by the bootloader */ ++ local-bd-address = [00 00 00 00 00 00]; ++ }; ++ }; +diff --git a/MAINTAINERS b/MAINTAINERS +index 64379c699903..d7b1496dd880 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1838,6 +1838,7 @@ F: Documentation/devicetree/bindings/interrupt-controller/apple,* + F: Documentation/devicetree/bindings/iommu/apple,dart.yaml + F: Documentation/devicetree/bindings/iommu/apple,sart.yaml + F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml ++F: Documentation/devicetree/bindings/net/brcm,bcm4377-bluetooth.yaml + F: Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml + F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml + F: Documentation/devicetree/bindings/pci/apple,pcie.yaml +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0168-Bluetooth-hci_event-Add-quirk-to-ignore-byte-in-LE-E.patch b/target/linux/silicon/patches-5.19/0168-Bluetooth-hci_event-Add-quirk-to-ignore-byte-in-LE-E.patch new file mode 100644 index 000000000..801e4fe6b --- /dev/null +++ b/target/linux/silicon/patches-5.19/0168-Bluetooth-hci_event-Add-quirk-to-ignore-byte-in-LE-E.patch @@ -0,0 +1,94 @@ +From 9745530da3fcf89629df2cadaf712e7f77363a78 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Mon, 1 Aug 2022 12:36:31 +0200 +Subject: [PATCH 168/171] Bluetooth: hci_event: Add quirk to ignore byte in LE + Extended Adv Report + +Broadcom controllers present on Apple Silicon devices use the upper +8 bits of the event type in the LE Extended Advertising Report for +the channel on which the frame has been received. +Add a quirk to drop the upper byte to ensure that the advertising +results are parsed correctly. + +The following except from a btmon trace shows a report received on +channel 37 by these controllers: + +> HCI Event: LE Meta Event (0x3e) plen 55 #1 [hci0] 0.912271 + LE Extended Advertising Report (0x0d) + Num reports: 1 + Entry 0 + Event type: 0x2513 + Props: 0x0013 + Connectable + Scannable + Use legacy advertising PDUs + Data status: Complete + Reserved (0x2500) + Legacy PDU Type: Reserved (0x2513) + Address type: Public (0x00) + Address: XX:XX:XX:XX:XX:XX (Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd) + Primary PHY: LE 1M + Secondary PHY: No packets + SID: no ADI field (0xff) + TX power: 127 dBm + RSSI: -76 dBm (0xb4) + Periodic advertising interval: 0.00 msec (0x0000) + Direct address type: Public (0x00) + Direct address: 00:00:00:00:00:00 (OUI 00-00-00) + Data length: 0x1d + 02 01 18 09 ff 57 00 31 1f 01 3c 86 ab 03 16 df .....W.1..<..... + fd 0b 09 4a 42 4c 20 46 6c 69 70 20 35 ...JBL Flip 5 + Flags: 0x18 + Simultaneous LE and BR/EDR (Controller) + Simultaneous LE and BR/EDR (Host) + Company: Harman International Industries, Inc. (87) + Data: 311f013c86ab + Service Data (UUID 0xfddf): + Name (complete): JBL Flip 5 + +Signed-off-by: Sven Peter +--- + include/net/bluetooth/hci.h | 11 +++++++++++ + net/bluetooth/hci_event.c | 4 ++++ + 2 files changed, 15 insertions(+) + +diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h +index fe7935be7dc4..47e1ee6f275d 100644 +--- a/include/net/bluetooth/hci.h ++++ b/include/net/bluetooth/hci.h +@@ -274,6 +274,17 @@ enum { + * during the hdev->setup vendor callback. + */ + HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, ++ ++ /* ++ * When this quirk is set, the upper 8 bits of the evt_type field of ++ * the LE Extended Advertising Report events are discarded. ++ * Some Broadcom controllers found in Apple machines put the channel ++ * the report was received on into these reserved bits. ++ * ++ * This quirk can be set before hci_register_dev is called or ++ * during the hdev->setup vendor callback. ++ */ ++ HCI_QUIRK_FIXUP_LE_EXT_ADV_REPORT_EVT_TYPE, + }; + + /* HCI device flags */ +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index af17dfb20e01..0b5d70aeea93 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -6237,6 +6237,10 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, void *data, + break; + + evt_type = __le16_to_cpu(info->type); ++ if (test_bit(HCI_QUIRK_FIXUP_LE_EXT_ADV_REPORT_EVT_TYPE, ++ &hdev->quirks)) ++ evt_type &= 0xff; ++ + legacy_evt_type = ext_evt_type_to_legacy(hdev, evt_type); + if (legacy_evt_type != LE_ADV_INVALID) { + process_adv_report(hdev, legacy_evt_type, &info->bdaddr, +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0169-Bluetooth-Add-quirk-to-disable-extended-scanning.patch b/target/linux/silicon/patches-5.19/0169-Bluetooth-Add-quirk-to-disable-extended-scanning.patch new file mode 100644 index 000000000..9c57212f0 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0169-Bluetooth-Add-quirk-to-disable-extended-scanning.patch @@ -0,0 +1,77 @@ +From c1dacaf4f9ff59463b2c48edf78b39f5308f7ff5 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Mon, 1 Aug 2022 12:36:32 +0200 +Subject: [PATCH 169/171] Bluetooth: Add quirk to disable extended scanning + +Broadcom 4377 controllers found in Apple x86 Macs with the T2 chip +claim to support extended scanning when querying supported states, + +< HCI Command: LE Read Supported St.. (0x08|0x001c) plen 0 #27 [hci0] 2.971839 +> HCI Event: Command Complete (0x0e) plen 12 #28 [hci0] 2.972730 + LE Read Supported States (0x08|0x001c) ncmd 1 + Status: Success (0x00) + States: 0x000003ffffffffff +[...] + LE Set Extended Scan Parameters (Octet 37 - Bit 5) + LE Set Extended Scan Enable (Octet 37 - Bit 6) +[...] + +, but then fail to actually implement the extended scanning: + +< HCI Command: LE Set Extended Sca.. (0x08|0x0041) plen 8 #105 [hci0] 5.460776 + Own address type: Random (0x01) + Filter policy: Accept all advertisement (0x00) + PHYs: 0x01 + Entry 0: LE 1M + Type: Active (0x01) + Interval: 11.250 msec (0x0012) + Window: 11.250 msec (0x0012) +> HCI Event: Command Complete (0x0e) plen 4 #106 [hci0] 5.461777 + LE Set Extended Scan Parameters (0x08|0x0041) ncmd 1 + Status: Unknown HCI Command (0x01) + +Signed-off-by: Sven Peter +--- + include/net/bluetooth/hci.h | 10 ++++++++++ + include/net/bluetooth/hci_core.h | 4 +++- + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h +index 47e1ee6f275d..dd275842b9b2 100644 +--- a/include/net/bluetooth/hci.h ++++ b/include/net/bluetooth/hci.h +@@ -285,6 +285,16 @@ enum { + * during the hdev->setup vendor callback. + */ + HCI_QUIRK_FIXUP_LE_EXT_ADV_REPORT_EVT_TYPE, ++ ++ /* ++ * When this quirk is set, the HCI_OP_LE_SET_EXT_SCAN_ENABLE command is ++ * disabled. This is required for some Broadcom controllers which ++ * erroneously claim to support extended scanning. ++ * ++ * This quirk can be set before hci_register_dev is called or ++ * during the hdev->setup vendor callback. ++ */ ++ HCI_QUIRK_BROKEN_EXT_SCAN, + }; + + /* HCI device flags */ +diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h +index c0ea2a4892b1..149b9a10f52f 100644 +--- a/include/net/bluetooth/hci_core.h ++++ b/include/net/bluetooth/hci_core.h +@@ -1501,7 +1501,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn); + + /* Use ext scanning if set ext scan param and ext scan enable is supported */ + #define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \ +- ((dev)->commands[37] & 0x40)) ++ ((dev)->commands[37] & 0x40) && \ ++ !test_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &(dev)->quirks)) ++ + /* Use ext create connection if command is supported */ + #define use_ext_conn(dev) ((dev)->commands[37] & 0x80) + +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0170-Bluetooth-hci_bcm4377-Add-new-driver-for-BCM4377-PCI.patch b/target/linux/silicon/patches-5.19/0170-Bluetooth-hci_bcm4377-Add-new-driver-for-BCM4377-PCI.patch new file mode 100644 index 000000000..ce08518c8 --- /dev/null +++ b/target/linux/silicon/patches-5.19/0170-Bluetooth-hci_bcm4377-Add-new-driver-for-BCM4377-PCI.patch @@ -0,0 +1,2541 @@ +From 3adec24c1778d6911ddbdbe1d3425c6421e3ef38 Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Mon, 1 Aug 2022 12:36:33 +0200 +Subject: [PATCH 170/171] Bluetooth: hci_bcm4377: Add new driver for BCM4377 + PCI boards + +Broadcom BCM4377/4378/4387 are dual WiFi/Bluetooth boards found in Apple +machines. This driver adds support for the Bluetooth function which +exposes a shared memory IPC protocol over PCIe to tunnel HCI traffic. + +Signed-off-by: Sven Peter +--- + MAINTAINERS | 1 + + drivers/bluetooth/Kconfig | 12 + + drivers/bluetooth/Makefile | 1 + + drivers/bluetooth/hci_bcm4377.c | 2466 +++++++++++++++++++++++++++++++ + 4 files changed, 2480 insertions(+) + create mode 100644 drivers/bluetooth/hci_bcm4377.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index d7b1496dd880..346f9f95673f 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1846,6 +1846,7 @@ F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml + F: Documentation/devicetree/bindings/power/apple* + F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml + F: arch/arm64/boot/dts/apple/ ++F: drivers/bluetooth/hci_bcm4377.c + F: drivers/clk/clk-apple-nco.c + F: drivers/i2c/busses/i2c-pasemi-core.c + F: drivers/i2c/busses/i2c-pasemi-platform.c +diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig +index e30707405455..47f7baf20bb8 100644 +--- a/drivers/bluetooth/Kconfig ++++ b/drivers/bluetooth/Kconfig +@@ -274,6 +274,18 @@ config BT_HCIBCM203X + Say Y here to compile support for HCI BCM203x devices into the + kernel or say M to compile it as module (bcm203x). + ++ ++config BT_HCIBCM4377 ++ tristate "HCI BCM4377/4378/4387 PCIe driver" ++ depends on PCI ++ select FW_LOADER ++ help ++ Support for Broadcom BCM4377/4378/4387 bluetooth chipsets attached via ++ PCIe. These are usually found in Apple machines. ++ ++ Say Y here to compile support for HCI BCM4377 family devices into the ++ kernel or say M to compile it as module (hci_bcm4377). ++ + config BT_HCIBPA10X + tristate "HCI BPA10x USB driver" + depends on USB +diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile +index 3321a8aea4a0..e0b261f24fc9 100644 +--- a/drivers/bluetooth/Makefile ++++ b/drivers/bluetooth/Makefile +@@ -6,6 +6,7 @@ + obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o + obj-$(CONFIG_BT_HCIUART) += hci_uart.o + obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o ++obj-$(CONFIG_BT_HCIBCM4377) += hci_bcm4377.o + obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o + obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o + obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o +diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c +new file mode 100644 +index 000000000000..e5db0ac8a81b +--- /dev/null ++++ b/drivers/bluetooth/hci_bcm4377.c +@@ -0,0 +1,2466 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR MIT ++/* ++ * Bluetooth HCI driver for Broadcom 4377/4378/4387 devices attached via PCIe ++ * ++ * Copyright (C) The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++enum bcm4377_chip { ++ BCM4377 = 0, ++ BCM4378, ++ BCM4387, ++}; ++ ++#define BCM4377_DEVICE_ID 0x5fa0 ++#define BCM4378_DEVICE_ID 0x5f69 ++#define BCM4387_DEVICE_ID 0x5f71 ++ ++#define BCM4377_TIMEOUT 1000 ++ ++/* ++ * These devices only support DMA transactions inside a 32bit window ++ * (possibly to avoid 64 bit arithmetic). The window size cannot exceed ++ * 0xffffffff but is always aligned down to the previous 0x200 byte boundary ++ * which effectively limits the window to [start, start+0xfffffe00]. ++ * We just limit the DMA window to [0, 0xfffffe00] to make sure we don't ++ * run into this limitation. ++ */ ++#define BCM4377_DMA_MASK 0xfffffe00 ++ ++#define BCM4377_PCIECFG_BAR0_WINDOW1 0x80 ++#define BCM4377_PCIECFG_BAR0_WINDOW2 0x70 ++#define BCM4377_PCIECFG_BAR0_CORE2_WINDOW1 0x74 ++#define BCM4377_PCIECFG_BAR0_CORE2_WINDOW2 0x78 ++#define BCM4377_PCIECFG_BAR2_WINDOW 0x84 ++ ++#define BCM4377_PCIECFG_BAR0_CORE2_WINDOW1_DEFAULT 0x18011000 ++#define BCM4377_PCIECFG_BAR2_WINDOW_DEFAULT 0x19000000 ++ ++#define BCM4377_PCIECFG_SUBSYSTEM_CTRL 0x88 ++ ++#define BCM4377_BAR0_FW_DOORBELL 0x140 ++#define BCM4377_BAR0_RTI_CONTROL 0x144 ++ ++#define BCM4377_BAR0_SLEEP_CONTROL 0x150 ++#define BCM4377_BAR0_SLEEP_CONTROL_AWAKE 2 ++#define BCM4377_BAR0_SLEEP_CONTROL_QUIESCED 3 ++ ++#define BCM4377_BAR0_DOORBELL 0x174 ++#define BCM4377_BAR0_DOORBELL_VALUE GENMASK(31, 16) ++#define BCM4377_BAR0_DOORBELL_IDX GENMASK(15, 8) ++#define BCM4377_BAR0_DOORBELL_RING BIT(5) ++ ++#define BCM4377_BAR0_HOST_WINDOW_LO 0x590 ++#define BCM4377_BAR0_HOST_WINDOW_HI 0x594 ++#define BCM4377_BAR0_HOST_WINDOW_SIZE 0x598 ++ ++#define BCM4377_BAR2_BOOTSTAGE 0x200454 ++ ++#define BCM4377_BAR2_FW_LO 0x200478 ++#define BCM4377_BAR2_FW_HI 0x20047c ++#define BCM4377_BAR2_FW_SIZE 0x200480 ++ ++#define BCM4377_BAR2_CONTEXT_ADDR_LO 0x20048c ++#define BCM4377_BAR2_CONTEXT_ADDR_HI 0x200450 ++ ++#define BCM4377_BAR2_RTI_STATUS 0x20045c ++#define BCM4377_BAR2_RTI_WINDOW_LO 0x200494 ++#define BCM4377_BAR2_RTI_WINDOW_HI 0x200498 ++#define BCM4377_BAR2_RTI_WINDOW_SIZE 0x20049c ++ ++#define BCM4377_OTP_SIZE 0xe0 ++#define BCM4377_OTP_SYS_VENDOR 0x15 ++#define BCM4377_OTP_CIS 0x80 ++#define BCM4377_OTP_VENDOR_HDR 0x00000008 ++#define BCM4377_OTP_MAX_PARAM_LEN 16 ++ ++#define BCM4377_N_TRANSFER_RINGS 9 ++#define BCM4377_N_COMPLETION_RINGS 6 ++ ++#define BCM4377_MAX_RING_SIZE 256 ++ ++#define BCM4377_MSGID_GENERATION GENMASK(15, 8) ++#define BCM4377_MSGID_ID GENMASK(7, 0) ++ ++#define BCM4377_RING_N_ENTRIES 128 ++ ++#define BCM4377_CONTROL_MSG_SIZE 0x34 ++#define BCM4377_XFER_RING_MAX_INPLACE_PAYLOAD_SIZE (4 * 0xff) ++ ++#define MAX_ACL_PAYLOAD_SIZE (HCI_MAX_FRAME_SIZE + HCI_ACL_HDR_SIZE) ++#define MAX_SCO_PAYLOAD_SIZE (HCI_MAX_SCO_SIZE + HCI_SCO_HDR_SIZE) ++#define MAX_EVENT_PAYLOAD_SIZE (HCI_MAX_EVENT_SIZE + HCI_EVENT_HDR_SIZE) ++ ++enum bcm4377_otp_params_type { ++ BCM4377_OTP_BOARD_PARAMS, ++ BCM4377_OTP_CHIP_PARAMS ++}; ++ ++enum bcm4377_transfer_ring_id { ++ BCM4377_XFER_RING_CONTROL = 0, ++ BCM4377_XFER_RING_HCI_H2D = 1, ++ BCM4377_XFER_RING_HCI_D2H = 2, ++ BCM4377_XFER_RING_SCO_H2D = 3, ++ BCM4377_XFER_RING_SCO_D2H = 4, ++ BCM4377_XFER_RING_ACL_H2D = 5, ++ BCM4377_XFER_RING_ACL_D2H = 6, ++}; ++ ++enum bcm4377_completion_ring_id { ++ BCM4377_ACK_RING_CONTROL = 0, ++ BCM4377_ACK_RING_HCI_ACL = 1, ++ BCM4377_EVENT_RING_HCI_ACL = 2, ++ BCM4377_ACK_RING_SCO = 3, ++ BCM4377_EVENT_RING_SCO = 4, ++}; ++ ++enum bcm4377_doorbell { ++ BCM4377_DOORBELL_CONTROL = 0, ++ BCM4377_DOORBELL_HCI_H2D = 1, ++ BCM4377_DOORBELL_HCI_D2H = 2, ++ BCM4377_DOORBELL_ACL_H2D = 3, ++ BCM4377_DOORBELL_ACL_D2H = 4, ++ BCM4377_DOORBELL_SCO = 6, ++}; ++ ++/* ++ * Transfer ring entry ++ * ++ * flags: Flags to indicate if the payload is appended or mapped ++ * len: Payload length ++ * payload: Optional payload DMA address ++ * id: Message id to recognize the answer in the completion ring entry ++ */ ++struct bcm4377_xfer_ring_entry { ++#define BCM4377_XFER_RING_FLAG_PAYLOAD_MAPPED BIT(0) ++#define BCM4377_XFER_RING_FLAG_PAYLOAD_IN_FOOTER BIT(1) ++ u8 flags; ++ __le16 len; ++ u8 _unk0; ++ __le64 payload; ++ __le16 id; ++ u8 _unk1[2]; ++} __packed; ++static_assert(sizeof(struct bcm4377_xfer_ring_entry) == 0x10); ++ ++/* ++ * Completion ring entry ++ * ++ * flags: Flags to indicate if the payload is appended or mapped. If the payload ++ * is mapped it can be found in the buffer of the corresponding transfer ++ * ring message. ++ * ring_id: Transfer ring ID which required this message ++ * msg_id: Message ID specified in transfer ring entry ++ * len: Payload length ++ */ ++struct bcm4377_completion_ring_entry { ++ u8 flags; ++ u8 _unk0; ++ __le16 ring_id; ++ __le16 msg_id; ++ __le32 len; ++ u8 _unk1[6]; ++} __packed; ++static_assert(sizeof(struct bcm4377_completion_ring_entry) == 0x10); ++ ++enum bcm4377_control_message_type { ++ BCM4377_CONTROL_MSG_CREATE_XFER_RING = 1, ++ BCM4377_CONTROL_MSG_CREATE_COMPLETION_RING = 2, ++ BCM4377_CONTROL_MSG_DESTROY_XFER_RING = 3, ++ BCM4377_CONTROL_MSG_DESTROY_COMPLETION_RING = 4, ++}; ++ ++/* ++ * Control message used to create a completion ring ++ * ++ * msg_type: Must be BCM4377_CONTROL_MSG_CREATE_COMPLETION_RING ++ * header_size: Unknown, but probably reserved space in front of the entry ++ * footer_size: Number of 32 bit words reserved for payloads after the entry ++ * id/id_again: Completion ring index ++ * ring_iova: DMA address of the ring buffer ++ * n_elements: Number of elements inside the ring buffer ++ * msi: MSI index, doesn't work for all rings though and should be zero ++ * intmod_delay: Unknown delay ++ * intmod_bytes: Unknown ++ */ ++struct bcm4377_create_completion_ring_msg { ++ u8 msg_type; ++ u8 header_size; ++ u8 footer_size; ++ u8 _unk0; ++ __le16 id; ++ __le16 id_again; ++ __le64 ring_iova; ++ __le16 n_elements; ++ __le32 unk; ++ u8 _unk1[6]; ++ __le16 msi; ++ __le16 intmod_delay; ++ __le32 intmod_bytes; ++ __le16 _unk2; ++ __le32 _unk3; ++ u8 _unk4[10]; ++} __packed; ++static_assert(sizeof(struct bcm4377_create_completion_ring_msg) == ++ BCM4377_CONTROL_MSG_SIZE); ++ ++/* ++ * Control ring message used to destroy a completion ring ++ * ++ * msg_type: Must be BCM4377_CONTROL_MSG_DESTROY_COMPLETION_RING ++ * ring_id: Completion ring to be destroyed ++ */ ++struct bcm4377_destroy_completion_ring_msg { ++ u8 msg_type; ++ u8 _pad0; ++ __le16 ring_id; ++ u8 _pad1[48]; ++} __packed; ++static_assert(sizeof(struct bcm4377_destroy_completion_ring_msg) == ++ BCM4377_CONTROL_MSG_SIZE); ++ ++/* ++ * Control message used to create a transfer ring ++ * ++ * msg_type: Must be BCM4377_CONTROL_MSG_CREATE_XFER_RING ++ * header_size: Number of 32 bit words reserved for unknown content before the ++ * entry ++ * footer_size: Number of 32 bit words reserved for payloads after the entry ++ * ring_id/ring_id_again: Transfer ring index ++ * ring_iova: DMA address of the ring buffer ++ * n_elements: Number of elements inside the ring buffer ++ * completion_ring_id: Completion ring index for acknowledgements and events ++ * doorbell: Doorbell index used to notify device of new entries ++ * flags: Transfer ring flags ++ * - virtual: set if there is no associated shared memory and only the ++ * corresponding completion ring is used ++ * - sync: only set for the SCO rings ++ */ ++struct bcm4377_create_transfer_ring_msg { ++ u8 msg_type; ++ u8 header_size; ++ u8 footer_size; ++ u8 _unk0; ++ __le16 ring_id; ++ __le16 ring_id_again; ++ __le64 ring_iova; ++ u8 _unk1[8]; ++ __le16 n_elements; ++ __le16 completion_ring_id; ++ __le16 doorbell; ++#define BCM4377_XFER_RING_FLAG_VIRTUAL BIT(7) ++#define BCM4377_XFER_RING_FLAG_SYNC BIT(8) ++ __le16 flags; ++ u8 _unk2[20]; ++} __packed; ++static_assert(sizeof(struct bcm4377_create_transfer_ring_msg) == ++ BCM4377_CONTROL_MSG_SIZE); ++ ++/* ++ * Control ring message used to destroy a transfer ring ++ * ++ * msg_type: Must be BCM4377_CONTROL_MSG_DESTROY_XFER_RING ++ * ring_id: Transfer ring to be destroyed ++ */ ++struct bcm4377_destroy_transfer_ring_msg { ++ u8 msg_type; ++ u8 _pad0; ++ __le16 ring_id; ++ u8 _pad1[48]; ++} __packed; ++static_assert(sizeof(struct bcm4377_destroy_transfer_ring_msg) == ++ BCM4377_CONTROL_MSG_SIZE); ++ ++/* ++ * "Converged IPC" context struct used to make the device aware of all other ++ * shared memory structures. A pointer to this structure is configured inside a ++ * MMIO register. ++ * ++ * version: Protocol version, must be 2. ++ * size: Size of this structure, must be 0x68. ++ * enabled_caps: Enabled capabilities. Unknown bitfield but should be 2. ++ * peripheral_info_addr: DMA address for a 0x20 buffer to which the device will ++ * write unknown contents ++ * {completion,xfer}_ring_{tails,heads}_addr: DMA pointers to ring heads/tails ++ * n_completion_rings: Number of completion rings, the firmware only works if ++ * this is set to BCM4377_N_COMPLETION_RINGS. ++ * n_xfer_rings: Number of transfer rings, the firmware only works if ++ * this is set to BCM4377_N_TRANSFER_RINGS. ++ * control_completion_ring_addr: Control completion ring buffer DMA address ++ * control_xfer_ring_addr: Control transfer ring buffer DMA address ++ * control_xfer_ring_n_entries: Number of control transfer ring entries ++ * control_completion_ring_n_entries: Number of control completion ring entries ++ * control_xfer_ring_doorbell: Control transfer ring doorbell ++ * control_completion_ring_doorbell: Control completion ring doorbell, ++ * must be set to 0xffff ++ * control_xfer_ring_msi: Control completion ring MSI index, must be 0 ++ * control_completion_ring_msi: Control completion ring MSI index, must be 0. ++ * control_xfer_ring_header_size: Number of 32 bit words reserved in front of ++ * every control transfer ring entry ++ * control_xfer_ring_footer_size: Number of 32 bit words reserved after every ++ * control transfer ring entry ++ * control_completion_ring_header_size: Number of 32 bit words reserved in front ++ * of every control completion ring entry ++ * control_completion_ring_footer_size: Number of 32 bit words reserved after ++ * every control completion ring entry ++ * scratch_pad: Optional scratch pad DMA address ++ * scratch_pad_size: Scratch pad size ++ */ ++struct bcm4377_context { ++ __le16 version; ++ __le16 size; ++ __le32 enabled_caps; ++ ++ __le64 peripheral_info_addr; ++ ++ /* ring heads and tails */ ++ __le64 completion_ring_heads_addr; ++ __le64 xfer_ring_tails_addr; ++ __le64 completion_ring_tails_addr; ++ __le64 xfer_ring_heads_addr; ++ __le16 n_completion_rings; ++ __le16 n_xfer_rings; ++ ++ /* control ring configuration */ ++ __le64 control_completion_ring_addr; ++ __le64 control_xfer_ring_addr; ++ __le16 control_xfer_ring_n_entries; ++ __le16 control_completion_ring_n_entries; ++ __le16 control_xfer_ring_doorbell; ++ __le16 control_completion_ring_doorbell; ++ __le16 control_xfer_ring_msi; ++ __le16 control_completion_ring_msi; ++ u8 control_xfer_ring_header_size; ++ u8 control_xfer_ring_footer_size; ++ u8 control_completion_ring_header_size; ++ u8 control_completion_ring_footer_size; ++ ++ __le16 _unk0; ++ __le16 _unk1; ++ ++ __le64 scratch_pad; ++ __le32 scratch_pad_size; ++ ++ __le32 _unk3; ++} __packed; ++static_assert(sizeof(struct bcm4377_context) == 0x68); ++ ++#define BCM4378_CALIBRATION_CHUNK_SIZE 0xe6 ++struct bcm4378_hci_send_calibration_cmd { ++ u8 unk; ++ __le16 blocks_left; ++ u8 data[BCM4378_CALIBRATION_CHUNK_SIZE]; ++} __packed; ++ ++#define BCM4378_PTB_CHUNK_SIZE 0xcf ++struct bcm4378_hci_send_ptb_cmd { ++ __le16 blocks_left; ++ u8 data[BCM4378_PTB_CHUNK_SIZE]; ++} __packed; ++ ++/* ++ * Shared memory structure used to store the ring head and tail pointers. ++ */ ++struct bcm4377_ring_state { ++ __le16 completion_ring_head[BCM4377_N_COMPLETION_RINGS]; ++ __le16 completion_ring_tail[BCM4377_N_COMPLETION_RINGS]; ++ __le16 xfer_ring_head[BCM4377_N_TRANSFER_RINGS]; ++ __le16 xfer_ring_tail[BCM4377_N_TRANSFER_RINGS]; ++}; ++ ++/* ++ * A transfer ring can be used in two configurations: ++ * 1) Send control or HCI messages to the device which are then acknowledged ++ * in the corresponding completion ring ++ * 2) Receiving HCI frames from the devices. In this case the transfer ring ++ * itself contains empty messages that are acknowledged once data is ++ * available from the device. If the payloads fit inside the footers ++ * of the completion ring the transfer ring can be configured to be ++ * virtual such that it has no ring buffer. ++ * ++ * ring_id: ring index hardcoded in the firmware ++ * doorbell: doorbell index to notify device of new entries ++ * payload_size: optional in-place payload size ++ * mapped_payload_size: optional out-of-place payload size ++ * completion_ring: index of corresponding completion ring ++ * n_entries: number of entries inside this ring ++ * generation: ring generation; incremented on hci_open to detect stale messages ++ * sync: set to true for SCO rings ++ * virtual: set to true if this ring has no entries and is just required to ++ * setup a corresponding completion ring for device->host messages ++ * d2h_buffers_only: set to true if this ring is only used to provide large ++ * buffers used by device->host messages in the completion ++ * ring ++ * allow_wait: allow to wait for messages to be acknowledged ++ * enabled: true once the ring has been created and can be used ++ * ring: ring buffer for entries (struct bcm4377_xfer_ring_entry) ++ * ring_dma: DMA address for ring entry buffer ++ * payloads: payload buffer for mapped_payload_size payloads ++ * payloads_dma:DMA address for payload buffer ++ * events: pointer to array of completions if waiting is allowed ++ * msgids: bitmap to keep track of used message ids ++ * lock: Spinlock to protect access to ring structurs used in the irq handler ++ */ ++struct bcm4377_transfer_ring { ++ enum bcm4377_transfer_ring_id ring_id; ++ enum bcm4377_doorbell doorbell; ++ size_t payload_size; ++ size_t mapped_payload_size; ++ u8 completion_ring; ++ u16 n_entries; ++ u8 generation; ++ ++ bool sync; ++ bool virtual; ++ bool d2h_buffers_only; ++ bool allow_wait; ++ bool enabled; ++ ++ void *ring; ++ dma_addr_t ring_dma; ++ ++ void *payloads; ++ dma_addr_t payloads_dma; ++ ++ struct completion **events; ++ DECLARE_BITMAP(msgids, BCM4377_MAX_RING_SIZE); ++ spinlock_t lock; ++}; ++ ++/* ++ * A completion ring can be either used to either acknowledge messages sent in ++ * the corresponding transfer ring or to receive messages associated with the ++ * transfer ring. When used to receive messages the transfer ring either ++ * has no ring buffer and is only advanced ("virtual transfer ring") or it ++ * only contains empty DMA buffers to be used for the payloads. ++ * ++ * ring_id: completion ring id, hardcoded in firmware ++ * payload_size: optional payload size after each entry ++ * delay: unknown delay ++ * n_entries: number of entries in this ring ++ * enabled: true once the ring has been created and can be used ++ * ring: ring buffer for entries (struct bcm4377_completion_ring_entry) ++ * ring_dma: DMA address of ring buffer ++ * transfer_rings: bitmap of corresponding transfer ring ids ++ */ ++struct bcm4377_completion_ring { ++ enum bcm4377_completion_ring_id ring_id; ++ u16 payload_size; ++ u16 delay; ++ u16 n_entries; ++ bool enabled; ++ ++ void *ring; ++ dma_addr_t ring_dma; ++ ++ unsigned long transfer_rings; ++}; ++ ++struct bcm4377_data; ++ ++/* ++ * Chip-specific configuration struct ++ * ++ * id: Chip id (e.g. 0x4377 for BCM4377) ++ * otp_offset: Offset to the start of the OTP inside BAR0 ++ * bar0_window1: Backplane address mapped to the first window in BAR0 ++ * bar0_window2: Backplane address mapped to the second window in BAR0 ++ * bar0_core2_window2: Optional backplane address mapped to the second core's ++ * second window in BAR0 ++ * has_bar0_core2_window2: Set to true if this chip requires the second core's ++ * second window to be configured ++ * clear_pciecfg_subsystem_ctrl_bit19: Set to true if bit 19 in the ++ * vendor-specific subsystem control ++ * register has to be cleared ++ * disable_aspm: Set to true if ASPM must be disabled due to hardware errata ++ * broken_ext_scan: Set to true if the chip erroneously claims to support ++ * extended scanning ++ * fixup_le_ext_adv_report_evt_type: Set to true if the upper byte of evt_type ++ * field of the LE Advanced Report has to be ++ * cleared ++ * board_type: Default board type, used for non-DT platforms ++ * send_calibration: Optional callback to send calibration data ++ * send_ptb: Callback to send "PTB" regulatory/calibration data ++ */ ++struct bcm4377_hw { ++ unsigned int id; ++ ++ u32 otp_offset; ++ ++ u32 bar0_window1; ++ u32 bar0_window2; ++ u32 bar0_core2_window2; ++ ++ unsigned long has_bar0_core2_window2 : 1; ++ unsigned long clear_pciecfg_subsystem_ctrl_bit19 : 1; ++ unsigned long disable_aspm : 1; ++ unsigned long broken_ext_scan : 1; ++ unsigned long fixup_le_ext_adv_report_evt_type : 1; ++ ++ const char *board_type; ++ ++ int (*send_calibration)(struct bcm4377_data *bcm4377); ++ int (*send_ptb)(struct bcm4377_data *bcm4377, ++ const struct firmware *fw); ++}; ++ ++static const struct bcm4377_hw bcm4377_hw_variants[]; ++ ++/* ++ * Private struct associated with each device containing global state ++ * ++ * pdev: Pointer to associated struct pci_dev ++ * hdev: Pointer to associated strucy hci_dev ++ * bar0: iomem pointing to BAR0 ++ * bar1: iomem pointing to BAR2 ++ * bootstage: Current value of the bootstage ++ * rti_status: Current "RTI" status value ++ * hw: Pointer to chip-specific struct bcm4377_hw ++ * taurus_cal_blob: "Taurus" calibration blob used for some chips ++ * taurus_cal_size: "Taurus" calibration blob size ++ * taurus_beamforming_cal_blob: "Taurus" beamforming calibration blob used for ++ * some chips ++ * taurus_beamforming_cal_size: "Taurus" beamforming calibration blob size ++ * stepping: Chip stepping read from OTP; used for firmware selection ++ * vendor: Antenna vendor read from OTP; used for firmware selection ++ * board_type: Board type read from FDT; used for firmware selection ++ * event: Event for changed bootstage or rti_status; used for booting firmware ++ * ctx: "Converged IPC" context ++ * ctx_dma: "Converged IPC" context DMA address ++ * ring_state: Shared memory buffer containing ring head and tail indexes ++ * ring_state_dma: DMA address for ring_state ++ * {control,hci_acl,sco}_ack_ring: Completion rings used to acknowledge messages ++ * {hci_acl,sco}_event_ring: Completion rings used for device->host messages ++ * control_h2d_ring: Transfer ring used for control messages ++ * {hci,sco,acl}_h2d_ring: Transfer ring used to transfer HCI frames ++ * {hci,sco,acl}_d2h_ring: Transfer ring used to receive HCI frames in the ++ * corresponding completion ring ++ */ ++struct bcm4377_data { ++ struct pci_dev *pdev; ++ struct hci_dev *hdev; ++ ++ void __iomem *bar0; ++ void __iomem *bar2; ++ ++ u32 bootstage; ++ u32 rti_status; ++ ++ const struct bcm4377_hw *hw; ++ ++ const void *taurus_cal_blob; ++ int taurus_cal_size; ++ const void *taurus_beamforming_cal_blob; ++ int taurus_beamforming_cal_size; ++ ++ char stepping[BCM4377_OTP_MAX_PARAM_LEN]; ++ char vendor[BCM4377_OTP_MAX_PARAM_LEN]; ++ const char *board_type; ++ ++ struct completion event; ++ ++ struct bcm4377_context *ctx; ++ dma_addr_t ctx_dma; ++ ++ struct bcm4377_ring_state *ring_state; ++ dma_addr_t ring_state_dma; ++ ++ /* ++ * The HCI and ACL rings have to be merged because this structure is ++ * hardcoded in the firmware. ++ */ ++ struct bcm4377_completion_ring control_ack_ring; ++ struct bcm4377_completion_ring hci_acl_ack_ring; ++ struct bcm4377_completion_ring hci_acl_event_ring; ++ struct bcm4377_completion_ring sco_ack_ring; ++ struct bcm4377_completion_ring sco_event_ring; ++ ++ struct bcm4377_transfer_ring control_h2d_ring; ++ struct bcm4377_transfer_ring hci_h2d_ring; ++ struct bcm4377_transfer_ring hci_d2h_ring; ++ struct bcm4377_transfer_ring sco_h2d_ring; ++ struct bcm4377_transfer_ring sco_d2h_ring; ++ struct bcm4377_transfer_ring acl_h2d_ring; ++ struct bcm4377_transfer_ring acl_d2h_ring; ++}; ++ ++static void bcm4377_ring_doorbell(struct bcm4377_data *bcm4377, u8 doorbell, ++ u16 val) ++{ ++ u32 db = 0; ++ ++ db |= FIELD_PREP(BCM4377_BAR0_DOORBELL_VALUE, val); ++ db |= FIELD_PREP(BCM4377_BAR0_DOORBELL_IDX, doorbell); ++ db |= BCM4377_BAR0_DOORBELL_RING; ++ ++ dev_dbg(&bcm4377->pdev->dev, "write %d to doorbell #%d (0x%x)\n", val, ++ doorbell, db); ++ iowrite32(db, bcm4377->bar0 + BCM4377_BAR0_DOORBELL); ++} ++ ++static int bcm4377_extract_msgid(struct bcm4377_data *bcm4377, ++ struct bcm4377_transfer_ring *ring, ++ u16 raw_msgid, u8 *msgid) ++{ ++ u8 generation = FIELD_GET(BCM4377_MSGID_GENERATION, raw_msgid); ++ *msgid = FIELD_GET(BCM4377_MSGID_ID, raw_msgid); ++ ++ if (generation != ring->generation) { ++ dev_warn( ++ &bcm4377->pdev->dev, ++ "invalid message generation %d should be %d in entry for ring %d\n", ++ generation, ring->generation, ring->ring_id); ++ return -EINVAL; ++ } ++ ++ if (*msgid >= ring->n_entries) { ++ dev_warn(&bcm4377->pdev->dev, ++ "invalid message id in entry for ring %d: %d > %d\n", ++ ring->ring_id, *msgid, ring->n_entries); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void bcm4377_handle_event(struct bcm4377_data *bcm4377, ++ struct bcm4377_transfer_ring *ring, ++ u16 raw_msgid, u8 entry_flags, u8 type, ++ void *payload, size_t len) ++{ ++ struct sk_buff *skb; ++ u16 head; ++ u8 msgid; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ring->lock, flags); ++ if (!ring->enabled) { ++ dev_warn(&bcm4377->pdev->dev, ++ "event for disabled transfer ring %d\n", ++ ring->ring_id); ++ goto out; ++ } ++ ++ if (ring->d2h_buffers_only && ++ entry_flags & BCM4377_XFER_RING_FLAG_PAYLOAD_MAPPED) { ++ if (bcm4377_extract_msgid(bcm4377, ring, raw_msgid, &msgid)) ++ goto out; ++ ++ if (len > ring->mapped_payload_size) { ++ dev_warn( ++ &bcm4377->pdev->dev, ++ "invalid payload len in event for ring %d: %zu > %zu\n", ++ ring->ring_id, len, ring->mapped_payload_size); ++ goto out; ++ } ++ ++ payload = ring->payloads + msgid * ring->mapped_payload_size; ++ } ++ ++ skb = bt_skb_alloc(len, GFP_ATOMIC); ++ if (!skb) ++ goto out; ++ ++ memcpy(skb_put(skb, len), payload, len); ++ hci_skb_pkt_type(skb) = type; ++ hci_recv_frame(bcm4377->hdev, skb); ++ ++out: ++ head = le16_to_cpu(bcm4377->ring_state->xfer_ring_head[ring->ring_id]); ++ head = (head + 1) % ring->n_entries; ++ bcm4377->ring_state->xfer_ring_head[ring->ring_id] = cpu_to_le16(head); ++ ++ bcm4377_ring_doorbell(bcm4377, ring->doorbell, head); ++ ++ spin_unlock_irqrestore(&ring->lock, flags); ++} ++ ++static void bcm4377_handle_ack(struct bcm4377_data *bcm4377, ++ struct bcm4377_transfer_ring *ring, ++ u16 raw_msgid) ++{ ++ unsigned long flags; ++ u8 msgid; ++ ++ spin_lock_irqsave(&ring->lock, flags); ++ ++ if (bcm4377_extract_msgid(bcm4377, ring, raw_msgid, &msgid)) ++ goto unlock; ++ ++ if (!test_bit(msgid, ring->msgids)) { ++ dev_warn( ++ &bcm4377->pdev->dev, ++ "invalid message id in ack for ring %d: %d is not used\n", ++ ring->ring_id, msgid); ++ goto unlock; ++ } ++ ++ if (ring->allow_wait && ring->events[msgid]) { ++ complete(ring->events[msgid]); ++ ring->events[msgid] = NULL; ++ } ++ ++ bitmap_release_region(ring->msgids, msgid, ring->n_entries); ++ ++unlock: ++ spin_unlock_irqrestore(&ring->lock, flags); ++} ++ ++static void bcm4377_handle_completion(struct bcm4377_data *bcm4377, ++ struct bcm4377_completion_ring *ring, ++ u16 pos) ++{ ++ struct bcm4377_completion_ring_entry *entry; ++ u16 msg_id, transfer_ring; ++ size_t entry_size, data_len; ++ void *data; ++ ++ if (pos >= ring->n_entries) { ++ dev_warn(&bcm4377->pdev->dev, ++ "invalid offset %d for completion ring %d\n", pos, ++ ring->ring_id); ++ return; ++ } ++ ++ entry_size = sizeof(*entry) + ring->payload_size; ++ entry = ring->ring + pos * entry_size; ++ data = ring->ring + pos * entry_size + sizeof(*entry); ++ data_len = le32_to_cpu(entry->len); ++ msg_id = le16_to_cpu(entry->msg_id); ++ transfer_ring = le16_to_cpu(entry->ring_id); ++ ++ if ((ring->transfer_rings & BIT(transfer_ring)) == 0) { ++ dev_warn( ++ &bcm4377->pdev->dev, ++ "invalid entry at offset %d for transfer ring %d in completion ring %d\n", ++ pos, transfer_ring, ring->ring_id); ++ return; ++ } ++ ++ dev_dbg(&bcm4377->pdev->dev, ++ "entry in completion ring %d for transfer ring %d with msg_id %d\n", ++ ring->ring_id, transfer_ring, msg_id); ++ ++ switch (transfer_ring) { ++ case BCM4377_XFER_RING_CONTROL: ++ bcm4377_handle_ack(bcm4377, &bcm4377->control_h2d_ring, msg_id); ++ break; ++ case BCM4377_XFER_RING_HCI_H2D: ++ bcm4377_handle_ack(bcm4377, &bcm4377->hci_h2d_ring, msg_id); ++ break; ++ case BCM4377_XFER_RING_SCO_H2D: ++ bcm4377_handle_ack(bcm4377, &bcm4377->sco_h2d_ring, msg_id); ++ break; ++ case BCM4377_XFER_RING_ACL_H2D: ++ bcm4377_handle_ack(bcm4377, &bcm4377->acl_h2d_ring, msg_id); ++ break; ++ ++ case BCM4377_XFER_RING_HCI_D2H: ++ bcm4377_handle_event(bcm4377, &bcm4377->hci_d2h_ring, msg_id, ++ entry->flags, HCI_EVENT_PKT, data, ++ data_len); ++ break; ++ case BCM4377_XFER_RING_SCO_D2H: ++ bcm4377_handle_event(bcm4377, &bcm4377->sco_d2h_ring, msg_id, ++ entry->flags, HCI_SCODATA_PKT, data, ++ data_len); ++ break; ++ case BCM4377_XFER_RING_ACL_D2H: ++ bcm4377_handle_event(bcm4377, &bcm4377->acl_d2h_ring, msg_id, ++ entry->flags, HCI_ACLDATA_PKT, data, ++ data_len); ++ break; ++ ++ default: ++ dev_warn( ++ &bcm4377->pdev->dev, ++ "entry in completion ring %d for unknown transfer ring %d with msg_id %d\n", ++ ring->ring_id, transfer_ring, msg_id); ++ } ++} ++ ++static void bcm4377_poll_completion_ring(struct bcm4377_data *bcm4377, ++ struct bcm4377_completion_ring *ring) ++{ ++ u16 tail; ++ __le16 *heads = bcm4377->ring_state->completion_ring_head; ++ __le16 *tails = bcm4377->ring_state->completion_ring_tail; ++ ++ if (!ring->enabled) ++ return; ++ ++ tail = le16_to_cpu(tails[ring->ring_id]); ++ dev_dbg(&bcm4377->pdev->dev, ++ "completion ring #%d: head: %d, tail: %d\n", ring->ring_id, ++ le16_to_cpu(heads[ring->ring_id]), tail); ++ ++ while (tail != le16_to_cpu(READ_ONCE(heads[ring->ring_id]))) { ++ /* ++ * ensure the CPU doesn't speculate through the comparison. ++ * otherwise it might already read the (empty) queue entry ++ * before the updated head has been loaded and checked. ++ */ ++ dma_rmb(); ++ ++ bcm4377_handle_completion(bcm4377, ring, tail); ++ ++ tail = (tail + 1) % ring->n_entries; ++ tails[ring->ring_id] = cpu_to_le16(tail); ++ } ++} ++ ++static irqreturn_t bcm4377_irq(int irq, void *data) ++{ ++ struct bcm4377_data *bcm4377 = data; ++ u32 bootstage, rti_status; ++ ++ bootstage = ioread32(bcm4377->bar2 + BCM4377_BAR2_BOOTSTAGE); ++ rti_status = ioread32(bcm4377->bar2 + BCM4377_BAR2_RTI_STATUS); ++ ++ if (bootstage != bcm4377->bootstage || ++ rti_status != bcm4377->rti_status) { ++ dev_dbg(&bcm4377->pdev->dev, ++ "bootstage = %d -> %d, rti state = %d -> %d\n", ++ bcm4377->bootstage, bootstage, bcm4377->rti_status, ++ rti_status); ++ complete(&bcm4377->event); ++ bcm4377->bootstage = bootstage; ++ bcm4377->rti_status = rti_status; ++ } ++ ++ bcm4377_poll_completion_ring(bcm4377, &bcm4377->control_ack_ring); ++ bcm4377_poll_completion_ring(bcm4377, &bcm4377->hci_acl_event_ring); ++ bcm4377_poll_completion_ring(bcm4377, &bcm4377->hci_acl_ack_ring); ++ bcm4377_poll_completion_ring(bcm4377, &bcm4377->sco_ack_ring); ++ bcm4377_poll_completion_ring(bcm4377, &bcm4377->sco_event_ring); ++ ++ return IRQ_HANDLED; ++} ++ ++static int bcm4377_enqueue(struct bcm4377_data *bcm4377, ++ struct bcm4377_transfer_ring *ring, void *data, ++ size_t len, bool wait) ++{ ++ unsigned long flags; ++ struct bcm4377_xfer_ring_entry *entry; ++ void *payload; ++ size_t offset; ++ u16 head, tail, new_head; ++ u16 raw_msgid; ++ int ret, msgid; ++ DECLARE_COMPLETION_ONSTACK(event); ++ ++ if (len > ring->payload_size && len > ring->mapped_payload_size) { ++ dev_warn( ++ &bcm4377->pdev->dev, ++ "payload len %zu is too large for ring %d (max is %zu or %zu)\n", ++ len, ring->ring_id, ring->payload_size, ++ ring->mapped_payload_size); ++ return -EINVAL; ++ } ++ if (wait && !ring->allow_wait) ++ return -EINVAL; ++ if (ring->virtual) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&ring->lock, flags); ++ ++ head = le16_to_cpu(bcm4377->ring_state->xfer_ring_head[ring->ring_id]); ++ tail = le16_to_cpu(bcm4377->ring_state->xfer_ring_tail[ring->ring_id]); ++ ++ new_head = (head + 1) % ring->n_entries; ++ ++ if (new_head == tail) { ++ dev_warn(&bcm4377->pdev->dev, ++ "can't send message because ring %d is full\n", ++ ring->ring_id); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ msgid = bitmap_find_free_region(ring->msgids, ring->n_entries, 0); ++ if (msgid < 0) { ++ dev_warn(&bcm4377->pdev->dev, ++ "can't find message id for ring %d\n", ring->ring_id); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ raw_msgid = FIELD_PREP(BCM4377_MSGID_GENERATION, ring->generation); ++ raw_msgid |= FIELD_PREP(BCM4377_MSGID_ID, msgid); ++ ++ offset = head * (sizeof(*entry) + ring->payload_size); ++ entry = ring->ring + offset; ++ ++ memset(entry, 0, sizeof(*entry)); ++ entry->id = cpu_to_le16(raw_msgid); ++ entry->len = cpu_to_le16(len); ++ ++ if (len <= ring->payload_size) { ++ entry->flags = BCM4377_XFER_RING_FLAG_PAYLOAD_IN_FOOTER; ++ payload = ring->ring + offset + sizeof(*entry); ++ } else { ++ entry->flags = BCM4377_XFER_RING_FLAG_PAYLOAD_MAPPED; ++ entry->payload = cpu_to_le64(ring->payloads_dma + ++ msgid * ring->mapped_payload_size); ++ payload = ring->payloads + msgid * ring->mapped_payload_size; ++ } ++ ++ memcpy(payload, data, len); ++ ++ if (wait) ++ ring->events[msgid] = &event; ++ ++ /* ++ * The 4377 chips stop responding to any commands as soon as they ++ * have been idle for a while. Poking the sleep control register here ++ * makes them come alive again. ++ */ ++ iowrite32(BCM4377_BAR0_SLEEP_CONTROL_AWAKE, ++ bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL); ++ ++ dev_dbg(&bcm4377->pdev->dev, ++ "updating head for transfer queue #%d to %d\n", ring->ring_id, ++ new_head); ++ bcm4377->ring_state->xfer_ring_head[ring->ring_id] = ++ cpu_to_le16(new_head); ++ ++ if (!ring->sync) ++ bcm4377_ring_doorbell(bcm4377, ring->doorbell, new_head); ++ ret = 0; ++ ++out: ++ spin_unlock_irqrestore(&ring->lock, flags); ++ ++ if (ret == 0 && wait) { ++ ret = wait_for_completion_interruptible_timeout( ++ &event, BCM4377_TIMEOUT); ++ if (ret == 0) ++ ret = -ETIMEDOUT; ++ else if (ret > 0) ++ ret = 0; ++ ++ spin_lock_irqsave(&ring->lock, flags); ++ ring->events[msgid] = NULL; ++ spin_unlock_irqrestore(&ring->lock, flags); ++ } ++ ++ return ret; ++} ++ ++static int bcm4377_create_completion_ring(struct bcm4377_data *bcm4377, ++ struct bcm4377_completion_ring *ring) ++{ ++ struct bcm4377_create_completion_ring_msg msg; ++ int ret; ++ ++ if (ring->enabled) { ++ dev_warn(&bcm4377->pdev->dev, ++ "completion ring %d already enabled\n", ring->ring_id); ++ return 0; ++ } ++ ++ memset(ring->ring, 0, ++ ring->n_entries * (sizeof(struct bcm4377_completion_ring_entry) + ++ ring->payload_size)); ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_type = BCM4377_CONTROL_MSG_CREATE_COMPLETION_RING; ++ msg.id = cpu_to_le16(ring->ring_id); ++ msg.id_again = cpu_to_le16(ring->ring_id); ++ msg.ring_iova = cpu_to_le64(ring->ring_dma); ++ msg.n_elements = cpu_to_le16(ring->n_entries); ++ msg.intmod_bytes = cpu_to_le32(0xffffffff); ++ msg.unk = cpu_to_le32(0xffffffff); ++ msg.intmod_delay = cpu_to_le16(ring->delay); ++ msg.footer_size = ring->payload_size / 4; ++ ++ ret = bcm4377_enqueue(bcm4377, &bcm4377->control_h2d_ring, &msg, ++ sizeof(msg), true); ++ if (!ret) ++ ring->enabled = true; ++ ++ return ret; ++} ++ ++static int bcm4377_destroy_completion_ring(struct bcm4377_data *bcm4377, ++ struct bcm4377_completion_ring *ring) ++{ ++ struct bcm4377_destroy_completion_ring_msg msg; ++ int ret; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_type = BCM4377_CONTROL_MSG_DESTROY_COMPLETION_RING; ++ msg.ring_id = cpu_to_le16(ring->ring_id); ++ ++ ret = bcm4377_enqueue(bcm4377, &bcm4377->control_h2d_ring, &msg, ++ sizeof(msg), true); ++ if (ret) ++ dev_warn(&bcm4377->pdev->dev, ++ "failed to destroy completion ring %d\n", ++ ring->ring_id); ++ ++ ring->enabled = false; ++ return ret; ++} ++ ++static int bcm4377_create_transfer_ring(struct bcm4377_data *bcm4377, ++ struct bcm4377_transfer_ring *ring) ++{ ++ struct bcm4377_create_transfer_ring_msg msg; ++ u16 flags = 0; ++ int ret, i; ++ unsigned long spinlock_flags; ++ ++ if (ring->virtual) ++ flags |= BCM4377_XFER_RING_FLAG_VIRTUAL; ++ if (ring->sync) ++ flags |= BCM4377_XFER_RING_FLAG_SYNC; ++ ++ spin_lock_irqsave(&ring->lock, spinlock_flags); ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_type = BCM4377_CONTROL_MSG_CREATE_XFER_RING; ++ msg.ring_id = cpu_to_le16(ring->ring_id); ++ msg.ring_id_again = cpu_to_le16(ring->ring_id); ++ msg.ring_iova = cpu_to_le64(ring->ring_dma); ++ msg.n_elements = cpu_to_le16(ring->n_entries); ++ msg.completion_ring_id = cpu_to_le16(ring->completion_ring); ++ msg.doorbell = cpu_to_le16(ring->doorbell); ++ msg.flags = cpu_to_le16(flags); ++ msg.footer_size = ring->payload_size / 4; ++ ++ bcm4377->ring_state->xfer_ring_head[ring->ring_id] = 0; ++ bcm4377->ring_state->xfer_ring_tail[ring->ring_id] = 0; ++ ring->generation++; ++ spin_unlock_irqrestore(&ring->lock, spinlock_flags); ++ ++ ret = bcm4377_enqueue(bcm4377, &bcm4377->control_h2d_ring, &msg, ++ sizeof(msg), true); ++ ++ spin_lock_irqsave(&ring->lock, spinlock_flags); ++ ++ if (ring->d2h_buffers_only) { ++ for (i = 0; i < ring->n_entries; ++i) { ++ struct bcm4377_xfer_ring_entry *entry = ++ ring->ring + i * sizeof(*entry); ++ u16 raw_msgid = FIELD_PREP(BCM4377_MSGID_GENERATION, ++ ring->generation); ++ raw_msgid |= FIELD_PREP(BCM4377_MSGID_ID, i); ++ ++ memset(entry, 0, sizeof(*entry)); ++ entry->id = cpu_to_le16(raw_msgid); ++ entry->len = cpu_to_le16(ring->mapped_payload_size); ++ entry->flags = BCM4377_XFER_RING_FLAG_PAYLOAD_MAPPED; ++ entry->payload = ++ cpu_to_le64(ring->payloads_dma + ++ i * ring->mapped_payload_size); ++ } ++ } ++ ++ /* ++ * send some messages if this is a device->host ring to allow the device ++ * to reply by acknowledging them in the completion ring ++ */ ++ if (ring->virtual || ring->d2h_buffers_only) { ++ bcm4377->ring_state->xfer_ring_head[ring->ring_id] = ++ cpu_to_le16(0xf); ++ bcm4377_ring_doorbell(bcm4377, ring->doorbell, 0xf); ++ } ++ ++ ring->enabled = true; ++ spin_unlock_irqrestore(&ring->lock, spinlock_flags); ++ ++ return ret; ++} ++ ++static int bcm4377_destroy_transfer_ring(struct bcm4377_data *bcm4377, ++ struct bcm4377_transfer_ring *ring) ++{ ++ struct bcm4377_destroy_transfer_ring_msg msg; ++ int ret; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_type = BCM4377_CONTROL_MSG_DESTROY_XFER_RING; ++ msg.ring_id = cpu_to_le16(ring->ring_id); ++ ++ ret = bcm4377_enqueue(bcm4377, &bcm4377->control_h2d_ring, &msg, ++ sizeof(msg), true); ++ if (ret) ++ dev_warn(&bcm4377->pdev->dev, ++ "failed to destroy transfer ring %d\n", ring->ring_id); ++ ++ ring->enabled = false; ++ return ret; ++} ++ ++static int __bcm4378_send_calibration_chunk(struct bcm4377_data *bcm4377, ++ const void *data, size_t data_len, ++ u16 blocks_left) ++{ ++ struct bcm4378_hci_send_calibration_cmd cmd; ++ struct sk_buff *skb; ++ ++ if (data_len > sizeof(cmd.data)) ++ return -EINVAL; ++ ++ memset(&cmd, 0, sizeof(cmd)); ++ cmd.unk = 0x03; ++ cmd.blocks_left = cpu_to_le16(blocks_left); ++ memcpy(cmd.data, data, data_len); ++ ++ skb = __hci_cmd_sync(bcm4377->hdev, 0xfd97, sizeof(cmd), &cmd, ++ HCI_INIT_TIMEOUT); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int __bcm4378_send_calibration(struct bcm4377_data *bcm4377, ++ const void *data, size_t data_size) ++{ ++ int ret; ++ size_t i, left, transfer_len; ++ size_t blocks = ++ DIV_ROUND_UP(data_size, (size_t)BCM4378_CALIBRATION_CHUNK_SIZE); ++ ++ if (!data) { ++ dev_err(&bcm4377->pdev->dev, ++ "no calibration data available.\n"); ++ return -ENOENT; ++ } ++ ++ for (i = 0, left = data_size; i < blocks; ++i, left -= transfer_len) { ++ transfer_len = ++ min_t(size_t, left, BCM4378_CALIBRATION_CHUNK_SIZE); ++ ++ ret = __bcm4378_send_calibration_chunk( ++ bcm4377, data + i * BCM4378_CALIBRATION_CHUNK_SIZE, ++ transfer_len, blocks - i - 1); ++ if (ret) { ++ dev_err(&bcm4377->pdev->dev, ++ "send calibration chunk failed with %d\n", ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int bcm4378_send_calibration(struct bcm4377_data *bcm4377) ++{ ++ if ((strcmp(bcm4377->stepping, "b1") == 0) || ++ strcmp(bcm4377->stepping, "b3") == 0) ++ return __bcm4378_send_calibration( ++ bcm4377, bcm4377->taurus_beamforming_cal_blob, ++ bcm4377->taurus_beamforming_cal_size); ++ else ++ return __bcm4378_send_calibration(bcm4377, ++ bcm4377->taurus_cal_blob, ++ bcm4377->taurus_cal_size); ++} ++ ++static int bcm4387_send_calibration(struct bcm4377_data *bcm4377) ++{ ++ if (strcmp(bcm4377->stepping, "c2") == 0) ++ return __bcm4378_send_calibration( ++ bcm4377, bcm4377->taurus_beamforming_cal_blob, ++ bcm4377->taurus_beamforming_cal_size); ++ else ++ return __bcm4378_send_calibration(bcm4377, ++ bcm4377->taurus_cal_blob, ++ bcm4377->taurus_cal_size); ++} ++ ++static const struct firmware *bcm4377_request_blob(struct bcm4377_data *bcm4377, ++ const char *suffix) ++{ ++ const struct firmware *fw; ++ char name0[64], name1[64]; ++ int ret; ++ ++ snprintf(name0, sizeof(name0), "brcm/brcmbt%04x%s-%s-%s.%s", ++ bcm4377->hw->id, bcm4377->stepping, bcm4377->board_type, ++ bcm4377->vendor, suffix); ++ snprintf(name1, sizeof(name1), "brcm/brcmbt%04x%s-%s.%s", ++ bcm4377->hw->id, bcm4377->stepping, bcm4377->board_type, ++ suffix); ++ dev_dbg(&bcm4377->pdev->dev, "Trying to load firmware: '%s' or '%s'\n", ++ name0, name1); ++ ++ ret = firmware_request_nowarn(&fw, name0, &bcm4377->pdev->dev); ++ if (!ret) ++ return fw; ++ ret = firmware_request_nowarn(&fw, name1, &bcm4377->pdev->dev); ++ if (!ret) ++ return fw; ++ ++ dev_err(&bcm4377->pdev->dev, ++ "Unable to load firmware; tried '%s' and '%s'\n", name0, name1); ++ return NULL; ++} ++ ++static int bcm4377_send_ptb(struct bcm4377_data *bcm4377, ++ const struct firmware *fw) ++{ ++ struct sk_buff *skb; ++ int ret = 0; ++ ++ skb = __hci_cmd_sync(bcm4377->hdev, 0xfd98, fw->size, fw->data, ++ HCI_INIT_TIMEOUT); ++ if (IS_ERR(skb)) { ++ ret = PTR_ERR(skb); ++ dev_err(&bcm4377->pdev->dev, "sending ptb failed (%d)", ret); ++ return ret; ++ } ++ ++ kfree_skb(skb); ++ return ret; ++} ++ ++static int bcm4378_send_ptb_chunk(struct bcm4377_data *bcm4377, ++ const void *data, size_t data_len, ++ u16 blocks_left) ++{ ++ struct bcm4378_hci_send_ptb_cmd cmd; ++ struct sk_buff *skb; ++ ++ if (data_len > BCM4378_PTB_CHUNK_SIZE) ++ return -EINVAL; ++ ++ memset(&cmd, 0, sizeof(cmd)); ++ cmd.blocks_left = cpu_to_le16(blocks_left); ++ memcpy(cmd.data, data, data_len); ++ ++ skb = __hci_cmd_sync(bcm4377->hdev, 0xfe0d, sizeof(cmd), &cmd, ++ HCI_INIT_TIMEOUT); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int bcm4378_send_ptb(struct bcm4377_data *bcm4377, ++ const struct firmware *fw) ++{ ++ size_t chunks = DIV_ROUND_UP(fw->size, (size_t)BCM4378_PTB_CHUNK_SIZE); ++ size_t i, left, transfer_len; ++ int ret; ++ ++ for (i = 0, left = fw->size; i < chunks; ++i, left -= transfer_len) { ++ transfer_len = min_t(size_t, left, BCM4378_PTB_CHUNK_SIZE); ++ ++ dev_dbg(&bcm4377->pdev->dev, "sending ptb chunk %zu/%zu\n", ++ i + 1, chunks); ++ ret = bcm4378_send_ptb_chunk( ++ bcm4377, fw->data + i * BCM4378_PTB_CHUNK_SIZE, ++ transfer_len, chunks - i - 1); ++ if (ret) { ++ dev_err(&bcm4377->pdev->dev, ++ "sending ptb chunk %zu failed (%d)", i, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int bcm4377_hci_open(struct hci_dev *hdev) ++{ ++ struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); ++ int ret; ++ ++ dev_dbg(&bcm4377->pdev->dev, "creating rings\n"); ++ ++ ret = bcm4377_create_completion_ring(bcm4377, ++ &bcm4377->hci_acl_ack_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_create_completion_ring(bcm4377, ++ &bcm4377->hci_acl_event_ring); ++ if (ret) ++ goto destroy_hci_acl_ack; ++ ret = bcm4377_create_completion_ring(bcm4377, &bcm4377->sco_ack_ring); ++ if (ret) ++ goto destroy_hci_acl_event; ++ ret = bcm4377_create_completion_ring(bcm4377, &bcm4377->sco_event_ring); ++ if (ret) ++ goto destroy_sco_ack; ++ dev_dbg(&bcm4377->pdev->dev, ++ "all completion rings successfully created!\n"); ++ ++ ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->hci_h2d_ring); ++ if (ret) ++ goto destroy_sco_event; ++ ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->hci_d2h_ring); ++ if (ret) ++ goto destroy_hci_h2d; ++ ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->sco_h2d_ring); ++ if (ret) ++ goto destroy_hci_d2h; ++ ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->sco_d2h_ring); ++ if (ret) ++ goto destroy_sco_h2d; ++ ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->acl_h2d_ring); ++ if (ret) ++ goto destroy_sco_d2h; ++ ret = bcm4377_create_transfer_ring(bcm4377, &bcm4377->acl_d2h_ring); ++ if (ret) ++ goto destroy_acl_h2d; ++ dev_dbg(&bcm4377->pdev->dev, ++ "all transfer rings successfully created!\n"); ++ ++ return 0; ++ ++destroy_acl_h2d: ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->acl_h2d_ring); ++destroy_sco_d2h: ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->sco_d2h_ring); ++destroy_sco_h2d: ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->sco_h2d_ring); ++destroy_hci_d2h: ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->hci_h2d_ring); ++destroy_hci_h2d: ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->hci_d2h_ring); ++destroy_sco_event: ++ bcm4377_destroy_completion_ring(bcm4377, &bcm4377->sco_event_ring); ++destroy_sco_ack: ++ bcm4377_destroy_completion_ring(bcm4377, &bcm4377->sco_ack_ring); ++destroy_hci_acl_event: ++ bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_event_ring); ++destroy_hci_acl_ack: ++ bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_ack_ring); ++ ++ dev_err(&bcm4377->pdev->dev, "Creating rings failed with %d\n", ret); ++ return ret; ++} ++ ++static int bcm4377_hci_close(struct hci_dev *hdev) ++{ ++ struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); ++ ++ dev_dbg(&bcm4377->pdev->dev, "destroying rings in hci_close\n"); ++ ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->acl_d2h_ring); ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->acl_h2d_ring); ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->sco_d2h_ring); ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->sco_h2d_ring); ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->hci_d2h_ring); ++ bcm4377_destroy_transfer_ring(bcm4377, &bcm4377->hci_h2d_ring); ++ ++ bcm4377_destroy_completion_ring(bcm4377, &bcm4377->sco_event_ring); ++ bcm4377_destroy_completion_ring(bcm4377, &bcm4377->sco_ack_ring); ++ bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_event_ring); ++ bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_ack_ring); ++ ++ return 0; ++} ++ ++static bool bcm4377_is_valid_bdaddr(struct bcm4377_data *bcm4377, ++ bdaddr_t *addr) ++{ ++ if (addr->b[0] != 0x93) ++ return true; ++ if (addr->b[1] != 0x76) ++ return true; ++ if (addr->b[2] != 0x00) ++ return true; ++ if (addr->b[4] != (bcm4377->hw->id & 0xff)) ++ return true; ++ if (addr->b[5] != (bcm4377->hw->id >> 8)) ++ return true; ++ return false; ++} ++ ++static int bcm4377_check_bdaddr(struct bcm4377_data *bcm4377) ++{ ++ struct hci_rp_read_bd_addr *bda; ++ struct sk_buff *skb; ++ ++ skb = __hci_cmd_sync(bcm4377->hdev, HCI_OP_READ_BD_ADDR, 0, NULL, ++ HCI_INIT_TIMEOUT); ++ if (IS_ERR(skb)) { ++ int err = PTR_ERR(skb); ++ ++ dev_err(&bcm4377->pdev->dev, "HCI_OP_READ_BD_ADDR failed (%d)", ++ err); ++ return err; ++ } ++ ++ if (skb->len != sizeof(*bda)) { ++ dev_err(&bcm4377->pdev->dev, ++ "HCI_OP_READ_BD_ADDR reply length invalid"); ++ kfree_skb(skb); ++ return -EIO; ++ } ++ ++ bda = (struct hci_rp_read_bd_addr *)skb->data; ++ if (!bcm4377_is_valid_bdaddr(bcm4377, &bda->bdaddr)) ++ set_bit(HCI_QUIRK_INVALID_BDADDR, &bcm4377->hdev->quirks); ++ ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int bcm4377_hci_setup(struct hci_dev *hdev) ++{ ++ struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); ++ const struct firmware *fw; ++ int ret; ++ ++ if (bcm4377->hw->send_calibration) { ++ ret = bcm4377->hw->send_calibration(bcm4377); ++ if (ret) ++ return ret; ++ } ++ ++ fw = bcm4377_request_blob(bcm4377, "ptb"); ++ if (!fw) { ++ dev_err(&bcm4377->pdev->dev, "failed to load PTB data"); ++ return -ENOENT; ++ } ++ ++ ret = bcm4377->hw->send_ptb(bcm4377, fw); ++ release_firmware(fw); ++ if (ret) ++ return ret; ++ ++ return bcm4377_check_bdaddr(bcm4377); ++} ++ ++static int bcm4377_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); ++ struct bcm4377_transfer_ring *ring; ++ int ret; ++ ++ switch (hci_skb_pkt_type(skb)) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ ring = &bcm4377->hci_h2d_ring; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ ring = &bcm4377->acl_h2d_ring; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ ring = &bcm4377->sco_h2d_ring; ++ break; ++ ++ default: ++ return -EILSEQ; ++ } ++ ++ ret = bcm4377_enqueue(bcm4377, ring, skb->data, skb->len, false); ++ if (ret < 0) { ++ hdev->stat.err_tx++; ++ return ret; ++ } ++ ++ hdev->stat.byte_tx += skb->len; ++ kfree_skb(skb); ++ return ret; ++} ++ ++static int bcm4377_hci_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) ++{ ++ struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev); ++ struct sk_buff *skb; ++ int err; ++ ++ skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); ++ if (IS_ERR(skb)) { ++ err = PTR_ERR(skb); ++ dev_err(&bcm4377->pdev->dev, ++ "Change address command failed (%d)", err); ++ return err; ++ } ++ kfree_skb(skb); ++ ++ return 0; ++} ++ ++static int bcm4377_alloc_transfer_ring(struct bcm4377_data *bcm4377, ++ struct bcm4377_transfer_ring *ring) ++{ ++ size_t entry_size; ++ ++ spin_lock_init(&ring->lock); ++ ring->payload_size = ALIGN(ring->payload_size, 4); ++ ring->mapped_payload_size = ALIGN(ring->mapped_payload_size, 4); ++ ++ if (ring->payload_size > BCM4377_XFER_RING_MAX_INPLACE_PAYLOAD_SIZE) ++ return -EINVAL; ++ if (ring->n_entries > BCM4377_MAX_RING_SIZE) ++ return -EINVAL; ++ if (ring->virtual && ring->allow_wait) ++ return -EINVAL; ++ ++ if (ring->d2h_buffers_only) { ++ if (ring->virtual) ++ return -EINVAL; ++ if (ring->payload_size) ++ return -EINVAL; ++ if (!ring->mapped_payload_size) ++ return -EINVAL; ++ } ++ if (ring->virtual) ++ return 0; ++ ++ entry_size = ++ ring->payload_size + sizeof(struct bcm4377_xfer_ring_entry); ++ ring->ring = dmam_alloc_coherent(&bcm4377->pdev->dev, ++ ring->n_entries * entry_size, ++ &ring->ring_dma, GFP_KERNEL); ++ if (!ring->ring) ++ return -ENOMEM; ++ ++ if (ring->allow_wait) { ++ ring->events = devm_kcalloc(&bcm4377->pdev->dev, ++ ring->n_entries, ++ sizeof(*ring->events), GFP_KERNEL); ++ if (!ring->events) ++ return -ENOMEM; ++ } ++ ++ if (ring->mapped_payload_size) { ++ ring->payloads = dmam_alloc_coherent( ++ &bcm4377->pdev->dev, ++ ring->n_entries * ring->mapped_payload_size, ++ &ring->payloads_dma, GFP_KERNEL); ++ if (!ring->payloads) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int bcm4377_alloc_completion_ring(struct bcm4377_data *bcm4377, ++ struct bcm4377_completion_ring *ring) ++{ ++ size_t entry_size; ++ ++ ring->payload_size = ALIGN(ring->payload_size, 4); ++ if (ring->payload_size > BCM4377_XFER_RING_MAX_INPLACE_PAYLOAD_SIZE) ++ return -EINVAL; ++ if (ring->n_entries > BCM4377_MAX_RING_SIZE) ++ return -EINVAL; ++ ++ entry_size = ring->payload_size + ++ sizeof(struct bcm4377_completion_ring_entry); ++ ++ ring->ring = dmam_alloc_coherent(&bcm4377->pdev->dev, ++ ring->n_entries * entry_size, ++ &ring->ring_dma, GFP_KERNEL); ++ if (!ring->ring) ++ return -ENOMEM; ++ return 0; ++} ++ ++static int bcm4377_init_context(struct bcm4377_data *bcm4377) ++{ ++ struct device *dev = &bcm4377->pdev->dev; ++ dma_addr_t peripheral_info_dma; ++ ++ bcm4377->ctx = dmam_alloc_coherent(dev, sizeof(*bcm4377->ctx), ++ &bcm4377->ctx_dma, GFP_KERNEL); ++ if (!bcm4377->ctx) ++ return -ENOMEM; ++ memset(bcm4377->ctx, 0, sizeof(*bcm4377->ctx)); ++ ++ bcm4377->ring_state = ++ dmam_alloc_coherent(dev, sizeof(*bcm4377->ring_state), ++ &bcm4377->ring_state_dma, GFP_KERNEL); ++ if (!bcm4377->ring_state) ++ return -ENOMEM; ++ memset(bcm4377->ring_state, 0, sizeof(*bcm4377->ring_state)); ++ ++ bcm4377->ctx->version = cpu_to_le16(1); ++ bcm4377->ctx->size = cpu_to_le16(sizeof(*bcm4377->ctx)); ++ bcm4377->ctx->enabled_caps = cpu_to_le16(2); ++ ++ /* ++ * The BT device will write 0x20 bytes of data to this buffer but ++ * the exact contents are unknown. It only needs to exist for BT ++ * to work such that we can just allocate and then ignore it. ++ */ ++ if (!dmam_alloc_coherent(&bcm4377->pdev->dev, 0x20, ++ &peripheral_info_dma, GFP_KERNEL)) ++ return -ENOMEM; ++ bcm4377->ctx->peripheral_info_addr = cpu_to_le64(peripheral_info_dma); ++ ++ bcm4377->ctx->xfer_ring_heads_addr = cpu_to_le64( ++ bcm4377->ring_state_dma + ++ offsetof(struct bcm4377_ring_state, xfer_ring_head)); ++ bcm4377->ctx->xfer_ring_tails_addr = cpu_to_le64( ++ bcm4377->ring_state_dma + ++ offsetof(struct bcm4377_ring_state, xfer_ring_tail)); ++ bcm4377->ctx->completion_ring_heads_addr = cpu_to_le64( ++ bcm4377->ring_state_dma + ++ offsetof(struct bcm4377_ring_state, completion_ring_head)); ++ bcm4377->ctx->completion_ring_tails_addr = cpu_to_le64( ++ bcm4377->ring_state_dma + ++ offsetof(struct bcm4377_ring_state, completion_ring_tail)); ++ ++ bcm4377->ctx->n_completion_rings = ++ cpu_to_le16(BCM4377_N_COMPLETION_RINGS); ++ bcm4377->ctx->n_xfer_rings = cpu_to_le16(BCM4377_N_TRANSFER_RINGS); ++ ++ bcm4377->ctx->control_completion_ring_addr = ++ cpu_to_le64(bcm4377->control_ack_ring.ring_dma); ++ bcm4377->ctx->control_completion_ring_n_entries = ++ cpu_to_le16(bcm4377->control_ack_ring.n_entries); ++ bcm4377->ctx->control_completion_ring_doorbell = cpu_to_le16(0xffff); ++ bcm4377->ctx->control_completion_ring_msi = 0; ++ bcm4377->ctx->control_completion_ring_header_size = 0; ++ bcm4377->ctx->control_completion_ring_footer_size = 0; ++ ++ bcm4377->ctx->control_xfer_ring_addr = ++ cpu_to_le64(bcm4377->control_h2d_ring.ring_dma); ++ bcm4377->ctx->control_xfer_ring_n_entries = ++ cpu_to_le16(bcm4377->control_h2d_ring.n_entries); ++ bcm4377->ctx->control_xfer_ring_doorbell = ++ cpu_to_le16(bcm4377->control_h2d_ring.doorbell); ++ bcm4377->ctx->control_xfer_ring_msi = 0; ++ bcm4377->ctx->control_xfer_ring_header_size = 0; ++ bcm4377->ctx->control_xfer_ring_footer_size = ++ bcm4377->control_h2d_ring.payload_size / 4; ++ ++ dev_dbg(&bcm4377->pdev->dev, "context initialized at IOVA %pad", ++ &bcm4377->ctx_dma); ++ ++ return 0; ++} ++ ++static int bcm4377_prepare_rings(struct bcm4377_data *bcm4377) ++{ ++ int ret; ++ ++ /* ++ * Even though many of these settings appear to be configurable ++ * when sending the "create ring" messages most of these are ++ * actually hardcoded in some (and quite possibly all) firmware versions ++ * and changing them on the host has no effect. ++ * Specifically, this applies to at least the doorbells, the transfer ++ * and completion ring ids and their mapping (e.g. both HCI and ACL ++ * entries will always be queued in completion rings 1 and 2 no matter ++ * what we configure here). ++ */ ++ bcm4377->control_ack_ring.ring_id = BCM4377_ACK_RING_CONTROL; ++ bcm4377->control_ack_ring.n_entries = 32; ++ bcm4377->control_ack_ring.transfer_rings = ++ BIT(BCM4377_XFER_RING_CONTROL); ++ ++ bcm4377->hci_acl_ack_ring.ring_id = BCM4377_ACK_RING_HCI_ACL; ++ bcm4377->hci_acl_ack_ring.n_entries = 2 * BCM4377_RING_N_ENTRIES; ++ bcm4377->hci_acl_ack_ring.transfer_rings = ++ BIT(BCM4377_XFER_RING_HCI_H2D) | BIT(BCM4377_XFER_RING_ACL_H2D); ++ bcm4377->hci_acl_ack_ring.delay = 1000; ++ ++ /* ++ * A payload size of MAX_EVENT_PAYLOAD_SIZE is enough here since large ++ * ACL packets will be transmitted inside buffers mapped via ++ * acl_d2h_ring anyway. ++ */ ++ bcm4377->hci_acl_event_ring.ring_id = BCM4377_EVENT_RING_HCI_ACL; ++ bcm4377->hci_acl_event_ring.payload_size = MAX_EVENT_PAYLOAD_SIZE; ++ bcm4377->hci_acl_event_ring.n_entries = 2 * BCM4377_RING_N_ENTRIES; ++ bcm4377->hci_acl_event_ring.transfer_rings = ++ BIT(BCM4377_XFER_RING_HCI_D2H) | BIT(BCM4377_XFER_RING_ACL_D2H); ++ bcm4377->hci_acl_event_ring.delay = 1000; ++ ++ bcm4377->sco_ack_ring.ring_id = BCM4377_ACK_RING_SCO; ++ bcm4377->sco_ack_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ bcm4377->sco_ack_ring.transfer_rings = BIT(BCM4377_XFER_RING_SCO_H2D); ++ ++ bcm4377->sco_event_ring.ring_id = BCM4377_EVENT_RING_SCO; ++ bcm4377->sco_event_ring.payload_size = MAX_SCO_PAYLOAD_SIZE; ++ bcm4377->sco_event_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ bcm4377->sco_event_ring.transfer_rings = BIT(BCM4377_XFER_RING_SCO_D2H); ++ ++ bcm4377->control_h2d_ring.ring_id = BCM4377_XFER_RING_CONTROL; ++ bcm4377->control_h2d_ring.doorbell = BCM4377_DOORBELL_CONTROL; ++ bcm4377->control_h2d_ring.payload_size = BCM4377_CONTROL_MSG_SIZE; ++ bcm4377->control_h2d_ring.completion_ring = BCM4377_ACK_RING_CONTROL; ++ bcm4377->control_h2d_ring.allow_wait = true; ++ bcm4377->control_h2d_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ ++ bcm4377->hci_h2d_ring.ring_id = BCM4377_XFER_RING_HCI_H2D; ++ bcm4377->hci_h2d_ring.doorbell = BCM4377_DOORBELL_HCI_H2D; ++ bcm4377->hci_h2d_ring.payload_size = MAX_EVENT_PAYLOAD_SIZE; ++ bcm4377->hci_h2d_ring.completion_ring = BCM4377_ACK_RING_HCI_ACL; ++ bcm4377->hci_h2d_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ ++ bcm4377->hci_d2h_ring.ring_id = BCM4377_XFER_RING_HCI_D2H; ++ bcm4377->hci_d2h_ring.doorbell = BCM4377_DOORBELL_HCI_D2H; ++ bcm4377->hci_d2h_ring.completion_ring = BCM4377_EVENT_RING_HCI_ACL; ++ bcm4377->hci_d2h_ring.virtual = true; ++ bcm4377->hci_d2h_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ ++ bcm4377->sco_h2d_ring.ring_id = BCM4377_XFER_RING_SCO_H2D; ++ bcm4377->sco_h2d_ring.doorbell = BCM4377_DOORBELL_SCO; ++ bcm4377->sco_h2d_ring.payload_size = MAX_SCO_PAYLOAD_SIZE; ++ bcm4377->sco_h2d_ring.completion_ring = BCM4377_ACK_RING_SCO; ++ bcm4377->sco_h2d_ring.sync = true; ++ bcm4377->sco_h2d_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ ++ bcm4377->sco_d2h_ring.ring_id = BCM4377_XFER_RING_SCO_D2H; ++ bcm4377->sco_d2h_ring.doorbell = BCM4377_DOORBELL_SCO; ++ bcm4377->sco_d2h_ring.completion_ring = BCM4377_EVENT_RING_SCO; ++ bcm4377->sco_d2h_ring.virtual = true; ++ bcm4377->sco_d2h_ring.sync = true; ++ bcm4377->sco_d2h_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ ++ /* ++ * This ring has to use mapped_payload_size because the largest ACL ++ * packet doesn't fit inside the largest possible footer ++ */ ++ bcm4377->acl_h2d_ring.ring_id = BCM4377_XFER_RING_ACL_H2D; ++ bcm4377->acl_h2d_ring.doorbell = BCM4377_DOORBELL_ACL_H2D; ++ bcm4377->acl_h2d_ring.mapped_payload_size = MAX_ACL_PAYLOAD_SIZE; ++ bcm4377->acl_h2d_ring.completion_ring = BCM4377_ACK_RING_HCI_ACL; ++ bcm4377->acl_h2d_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ ++ /* ++ * This ring only contains empty buffers to be used by incoming ++ * ACL packets that do not fit inside the footer of hci_acl_event_ring ++ */ ++ bcm4377->acl_d2h_ring.ring_id = BCM4377_XFER_RING_ACL_D2H; ++ bcm4377->acl_d2h_ring.doorbell = BCM4377_DOORBELL_ACL_D2H; ++ bcm4377->acl_d2h_ring.completion_ring = BCM4377_EVENT_RING_HCI_ACL; ++ bcm4377->acl_d2h_ring.d2h_buffers_only = true; ++ bcm4377->acl_d2h_ring.mapped_payload_size = MAX_ACL_PAYLOAD_SIZE; ++ bcm4377->acl_d2h_ring.n_entries = BCM4377_RING_N_ENTRIES; ++ ++ /* ++ * no need for any cleanup since this is only called from _probe ++ * and only devres-managed allocations are used ++ */ ++ ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->control_h2d_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->hci_h2d_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->hci_d2h_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->sco_h2d_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->sco_d2h_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->acl_h2d_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_transfer_ring(bcm4377, &bcm4377->acl_d2h_ring); ++ if (ret) ++ return ret; ++ ++ ret = bcm4377_alloc_completion_ring(bcm4377, ++ &bcm4377->control_ack_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_completion_ring(bcm4377, ++ &bcm4377->hci_acl_ack_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_completion_ring(bcm4377, ++ &bcm4377->hci_acl_event_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_completion_ring(bcm4377, &bcm4377->sco_ack_ring); ++ if (ret) ++ return ret; ++ ret = bcm4377_alloc_completion_ring(bcm4377, &bcm4377->sco_event_ring); ++ if (ret) ++ return ret; ++ ++ dev_dbg(&bcm4377->pdev->dev, "all rings allocated and prepared\n"); ++ ++ return 0; ++} ++ ++static int bcm4377_boot(struct bcm4377_data *bcm4377) ++{ ++ const struct firmware *fw; ++ void *bfr; ++ dma_addr_t fw_dma; ++ int ret = 0; ++ u32 bootstage, rti_status; ++ ++ bootstage = ioread32(bcm4377->bar2 + BCM4377_BAR2_BOOTSTAGE); ++ rti_status = ioread32(bcm4377->bar2 + BCM4377_BAR2_RTI_STATUS); ++ ++ if (bootstage != 0) { ++ dev_err(&bcm4377->pdev->dev, "bootstage is %d and not 0\n", ++ bootstage); ++ return -EINVAL; ++ } ++ ++ if (rti_status != 0) { ++ dev_err(&bcm4377->pdev->dev, "RTI status is %d and not 0\n", ++ rti_status); ++ return -EINVAL; ++ } ++ ++ fw = bcm4377_request_blob(bcm4377, "bin"); ++ if (!fw) { ++ dev_err(&bcm4377->pdev->dev, "Failed to load firmware\n"); ++ return -ENOENT; ++ } ++ ++ bfr = dma_alloc_coherent(&bcm4377->pdev->dev, fw->size, &fw_dma, ++ GFP_KERNEL); ++ if (!bfr) { ++ ret = -ENOMEM; ++ goto out_release_fw; ++ } ++ ++ memcpy(bfr, fw->data, fw->size); ++ ++ iowrite32(0, bcm4377->bar0 + BCM4377_BAR0_HOST_WINDOW_LO); ++ iowrite32(0, bcm4377->bar0 + BCM4377_BAR0_HOST_WINDOW_HI); ++ iowrite32(BCM4377_DMA_MASK, ++ bcm4377->bar0 + BCM4377_BAR0_HOST_WINDOW_SIZE); ++ ++ iowrite32(lower_32_bits(fw_dma), bcm4377->bar2 + BCM4377_BAR2_FW_LO); ++ iowrite32(upper_32_bits(fw_dma), bcm4377->bar2 + BCM4377_BAR2_FW_HI); ++ iowrite32(fw->size, bcm4377->bar2 + BCM4377_BAR2_FW_SIZE); ++ iowrite32(0, bcm4377->bar0 + BCM4377_BAR0_FW_DOORBELL); ++ ++ dev_dbg(&bcm4377->pdev->dev, "waiting for firmware to boot\n"); ++ ++ ret = wait_for_completion_interruptible_timeout(&bcm4377->event, ++ BCM4377_TIMEOUT); ++ if (ret == 0) { ++ ret = -ETIMEDOUT; ++ goto out_dma_free; ++ } else if (ret < 0) { ++ goto out_dma_free; ++ } ++ ++ if (bcm4377->bootstage != 2) { ++ dev_err(&bcm4377->pdev->dev, "boostage %d != 2\n", ++ bcm4377->bootstage); ++ ret = -ENXIO; ++ goto out_dma_free; ++ } ++ ++ dev_dbg(&bcm4377->pdev->dev, "firmware has booted (stage = %x)\n", ++ bcm4377->bootstage); ++ ret = 0; ++ ++out_dma_free: ++ dma_free_coherent(&bcm4377->pdev->dev, fw->size, bfr, fw_dma); ++out_release_fw: ++ release_firmware(fw); ++ return ret; ++} ++ ++static int bcm4377_setup_rti(struct bcm4377_data *bcm4377) ++{ ++ int ret; ++ ++ dev_dbg(&bcm4377->pdev->dev, "starting RTI\n"); ++ iowrite32(1, bcm4377->bar0 + BCM4377_BAR0_RTI_CONTROL); ++ ++ ret = wait_for_completion_interruptible_timeout(&bcm4377->event, ++ BCM4377_TIMEOUT); ++ if (ret == 0) { ++ dev_err(&bcm4377->pdev->dev, ++ "timed out while waiting for RTI to transition to state 1"); ++ return -ETIMEDOUT; ++ } else if (ret < 0) { ++ return ret; ++ } ++ ++ if (bcm4377->rti_status != 1) { ++ dev_err(&bcm4377->pdev->dev, "RTI did not ack state 1 (%d)\n", ++ bcm4377->rti_status); ++ return -ENODEV; ++ } ++ dev_dbg(&bcm4377->pdev->dev, "RTI is in state 1\n"); ++ ++ /* allow access to the entire IOVA space again */ ++ iowrite32(0, bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_LO); ++ iowrite32(0, bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_HI); ++ iowrite32(BCM4377_DMA_MASK, ++ bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_SIZE); ++ ++ /* setup "Converged IPC" context */ ++ iowrite32(lower_32_bits(bcm4377->ctx_dma), ++ bcm4377->bar2 + BCM4377_BAR2_CONTEXT_ADDR_LO); ++ iowrite32(upper_32_bits(bcm4377->ctx_dma), ++ bcm4377->bar2 + BCM4377_BAR2_CONTEXT_ADDR_HI); ++ iowrite32(2, bcm4377->bar0 + BCM4377_BAR0_RTI_CONTROL); ++ ++ ret = wait_for_completion_interruptible_timeout(&bcm4377->event, ++ BCM4377_TIMEOUT); ++ if (ret == 0) { ++ dev_err(&bcm4377->pdev->dev, ++ "timed out while waiting for RTI to transition to state 2"); ++ return -ETIMEDOUT; ++ } else if (ret < 0) { ++ return ret; ++ } ++ ++ if (bcm4377->rti_status != 2) { ++ dev_err(&bcm4377->pdev->dev, "RTI did not ack state 2 (%d)\n", ++ bcm4377->rti_status); ++ return -ENODEV; ++ } ++ ++ dev_dbg(&bcm4377->pdev->dev, ++ "RTI is in state 2; control ring is ready\n"); ++ bcm4377->control_ack_ring.enabled = true; ++ ++ return 0; ++} ++ ++static int bcm4377_parse_otp_board_params(struct bcm4377_data *bcm4377, ++ char tag, const char *val, size_t len) ++{ ++ if (tag != 'V') ++ return 0; ++ if (len >= sizeof(bcm4377->vendor)) ++ return -EINVAL; ++ ++ strscpy(bcm4377->vendor, val, len + 1); ++ return 0; ++} ++ ++static int bcm4377_parse_otp_chip_params(struct bcm4377_data *bcm4377, char tag, ++ const char *val, size_t len) ++{ ++ size_t idx = 0; ++ ++ if (tag != 's') ++ return 0; ++ if (len >= sizeof(bcm4377->stepping)) ++ return -EINVAL; ++ ++ while (len != 0) { ++ bcm4377->stepping[idx] = tolower(val[idx]); ++ if (val[idx] == '\0') ++ return 0; ++ ++ idx++; ++ len--; ++ } ++ ++ bcm4377->stepping[idx] = '\0'; ++ return 0; ++} ++ ++static int bcm4377_parse_otp_str(struct bcm4377_data *bcm4377, const u8 *str, ++ enum bcm4377_otp_params_type type) ++{ ++ const char *p; ++ int ret; ++ ++ p = skip_spaces(str); ++ while (*p) { ++ char tag = *p++; ++ const char *end; ++ size_t len; ++ ++ if (*p++ != '=') /* implicit NUL check */ ++ return -EINVAL; ++ ++ /* *p might be NUL here, if so end == p and len == 0 */ ++ end = strchrnul(p, ' '); ++ len = end - p; ++ ++ /* leave 1 byte for NUL in destination string */ ++ if (len > (BCM4377_OTP_MAX_PARAM_LEN - 1)) ++ return -EINVAL; ++ ++ switch (type) { ++ case BCM4377_OTP_BOARD_PARAMS: ++ ret = bcm4377_parse_otp_board_params(bcm4377, tag, p, ++ len); ++ break; ++ case BCM4377_OTP_CHIP_PARAMS: ++ ret = bcm4377_parse_otp_chip_params(bcm4377, tag, p, ++ len); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (ret) ++ return ret; ++ ++ /* Skip to next arg, if any */ ++ p = skip_spaces(end); ++ } ++ ++ return 0; ++} ++ ++static int bcm4377_parse_otp_sys_vendor(struct bcm4377_data *bcm4377, u8 *otp, ++ size_t size) ++{ ++ int idx = 4; ++ const char *chip_params; ++ const char *board_params; ++ int ret; ++ ++ /* 4-byte header and two empty strings */ ++ if (size < 6) ++ return -EINVAL; ++ ++ if (get_unaligned_le32(otp) != BCM4377_OTP_VENDOR_HDR) ++ return -EINVAL; ++ ++ chip_params = &otp[idx]; ++ ++ /* Skip first string, including terminator */ ++ idx += strnlen(chip_params, size - idx) + 1; ++ if (idx >= size) ++ return -EINVAL; ++ ++ board_params = &otp[idx]; ++ ++ /* Skip to terminator of second string */ ++ idx += strnlen(board_params, size - idx); ++ if (idx >= size) ++ return -EINVAL; ++ ++ /* At this point both strings are guaranteed NUL-terminated */ ++ dev_dbg(&bcm4377->pdev->dev, ++ "OTP: chip_params='%s' board_params='%s'\n", chip_params, ++ board_params); ++ ++ ret = bcm4377_parse_otp_str(bcm4377, chip_params, ++ BCM4377_OTP_CHIP_PARAMS); ++ if (ret) ++ return ret; ++ ++ ret = bcm4377_parse_otp_str(bcm4377, board_params, ++ BCM4377_OTP_BOARD_PARAMS); ++ if (ret) ++ return ret; ++ ++ if (!bcm4377->stepping[0] || !bcm4377->vendor[0]) ++ return -EINVAL; ++ ++ dev_dbg(&bcm4377->pdev->dev, "OTP: stepping=%s, vendor=%s\n", ++ bcm4377->stepping, bcm4377->vendor); ++ return 0; ++} ++ ++static int bcm4377_parse_otp(struct bcm4377_data *bcm4377) ++{ ++ u8 otp[BCM4377_OTP_SIZE]; ++ int i; ++ int ret = -ENOENT; ++ ++ for (i = 0; i < BCM4377_OTP_SIZE; ++i) ++ otp[i] = ioread8(bcm4377->bar0 + bcm4377->hw->otp_offset + i); ++ ++ i = 0; ++ while (i < (BCM4377_OTP_SIZE - 1)) { ++ u8 type = otp[i]; ++ u8 length = otp[i + 1]; ++ ++ if (type == 0) ++ break; ++ ++ if ((i + 2 + length) > BCM4377_OTP_SIZE) ++ break; ++ ++ switch (type) { ++ case BCM4377_OTP_SYS_VENDOR: ++ dev_dbg(&bcm4377->pdev->dev, ++ "OTP @ 0x%x (%d): SYS_VENDOR", i, length); ++ ret = bcm4377_parse_otp_sys_vendor(bcm4377, &otp[i + 2], ++ length); ++ break; ++ case BCM4377_OTP_CIS: ++ dev_dbg(&bcm4377->pdev->dev, "OTP @ 0x%x (%d): CIS", i, ++ length); ++ break; ++ default: ++ dev_dbg(&bcm4377->pdev->dev, "OTP @ 0x%x (%d): unknown", ++ i, length); ++ break; ++ } ++ ++ i += 2 + length; ++ } ++ ++ return ret; ++} ++ ++static int bcm4377_init_cfg(struct bcm4377_data *bcm4377) ++{ ++ int ret; ++ u32 ctrl; ++ ++ ret = pci_write_config_dword(bcm4377->pdev, ++ BCM4377_PCIECFG_BAR0_WINDOW1, ++ bcm4377->hw->bar0_window1); ++ if (ret) ++ return ret; ++ ++ ret = pci_write_config_dword(bcm4377->pdev, ++ BCM4377_PCIECFG_BAR0_WINDOW2, ++ bcm4377->hw->bar0_window2); ++ if (ret) ++ return ret; ++ ++ ret = pci_write_config_dword( ++ bcm4377->pdev, BCM4377_PCIECFG_BAR0_CORE2_WINDOW1, ++ BCM4377_PCIECFG_BAR0_CORE2_WINDOW1_DEFAULT); ++ if (ret) ++ return ret; ++ ++ if (bcm4377->hw->has_bar0_core2_window2) { ++ ret = pci_write_config_dword(bcm4377->pdev, ++ BCM4377_PCIECFG_BAR0_CORE2_WINDOW2, ++ bcm4377->hw->bar0_core2_window2); ++ if (ret) ++ return ret; ++ } ++ ++ ret = pci_write_config_dword(bcm4377->pdev, BCM4377_PCIECFG_BAR2_WINDOW, ++ BCM4377_PCIECFG_BAR2_WINDOW_DEFAULT); ++ if (ret) ++ return ret; ++ ++ ret = pci_read_config_dword(bcm4377->pdev, ++ BCM4377_PCIECFG_SUBSYSTEM_CTRL, &ctrl); ++ if (ret) ++ return ret; ++ ++ if (bcm4377->hw->clear_pciecfg_subsystem_ctrl_bit19) ++ ctrl &= ~BIT(19); ++ ctrl |= BIT(16); ++ ++ return pci_write_config_dword(bcm4377->pdev, ++ BCM4377_PCIECFG_SUBSYSTEM_CTRL, ctrl); ++} ++ ++static int bcm4377_probe_of(struct bcm4377_data *bcm4377) ++{ ++ struct device_node *np = bcm4377->pdev->dev.of_node; ++ int ret; ++ ++ if (!np) ++ return 0; ++ ++ ret = of_property_read_string(np, "brcm,board-type", ++ &bcm4377->board_type); ++ if (ret) { ++ dev_err(&bcm4377->pdev->dev, "no brcm,board-type property\n"); ++ return ret; ++ } ++ ++ bcm4377->taurus_beamforming_cal_blob = ++ of_get_property(np, "brcm,taurus-bf-cal-blob", ++ &bcm4377->taurus_beamforming_cal_size); ++ if (!bcm4377->taurus_beamforming_cal_blob) { ++ dev_err(&bcm4377->pdev->dev, ++ "no brcm,taurus-bf-cal-blob property\n"); ++ return -ENOENT; ++ } ++ bcm4377->taurus_cal_blob = of_get_property(np, "brcm,taurus-cal-blob", ++ &bcm4377->taurus_cal_size); ++ if (!bcm4377->taurus_cal_blob) { ++ dev_err(&bcm4377->pdev->dev, ++ "no brcm,taurus-cal-blob property\n"); ++ return -ENOENT; ++ } ++ ++ return 0; ++} ++ ++static void bcm4377_disable_aspm(struct bcm4377_data *bcm4377) ++{ ++ pci_disable_link_state(bcm4377->pdev, ++ PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); ++ ++ /* ++ * pci_disable_link_state can fail if either CONFIG_PCIEASPM is disabled ++ * or if the BIOS hasn't handed over control to us. We must *always* ++ * disable ASPM for this device due to hardware errata though. ++ */ ++ pcie_capability_clear_word(bcm4377->pdev, PCI_EXP_LNKCTL, ++ PCI_EXP_LNKCTL_ASPMC); ++} ++ ++static void bcm4377_pci_free_irq_vectors(void *data) ++{ ++ pci_free_irq_vectors(data); ++} ++ ++static void bcm4377_hci_free_dev(void *data) ++{ ++ hci_free_dev(data); ++} ++ ++static void bcm4377_hci_unregister_dev(void *data) ++{ ++ hci_unregister_dev(data); ++} ++ ++static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ struct bcm4377_data *bcm4377; ++ struct hci_dev *hdev; ++ int ret, irq; ++ ++ ret = dma_set_mask_and_coherent(&pdev->dev, BCM4377_DMA_MASK); ++ if (ret) ++ return ret; ++ ++ bcm4377 = devm_kzalloc(&pdev->dev, sizeof(*bcm4377), GFP_KERNEL); ++ if (!bcm4377) ++ return -ENOMEM; ++ ++ bcm4377->pdev = pdev; ++ bcm4377->hw = &bcm4377_hw_variants[id->driver_data]; ++ init_completion(&bcm4377->event); ++ ++ ret = bcm4377_prepare_rings(bcm4377); ++ if (ret) ++ return ret; ++ ++ ret = bcm4377_init_context(bcm4377); ++ if (ret) ++ return ret; ++ ++ bcm4377->board_type = bcm4377->hw->board_type; ++ ret = bcm4377_probe_of(bcm4377); ++ if (ret) ++ return ret; ++ if (!bcm4377->board_type) { ++ dev_err(&pdev->dev, "unable to determine board type\n"); ++ return ret; ++ } ++ ++ ret = pci_reset_function_locked(pdev); ++ if (ret) ++ dev_warn( ++ &pdev->dev, ++ "function level reset failed with %d; trying to continue anyway\n", ++ ret); ++ ++ /* ++ * If this number is too low and we try to access any BAR too ++ * early the device will crash. Experiments have shown that ++ * approximately 50 msec is the minimum amount we have to wait. ++ * Let's double that to be safe. ++ */ ++ msleep(100); ++ ++ if (bcm4377->hw->disable_aspm) ++ bcm4377_disable_aspm(bcm4377); ++ ++ ret = pci_enable_device(pdev); ++ if (ret) ++ return ret; ++ pci_set_master(pdev); ++ ++ ret = bcm4377_init_cfg(bcm4377); ++ if (ret) ++ return ret; ++ ++ bcm4377->bar0 = pcim_iomap(pdev, 0, 0); ++ if (!bcm4377->bar0) ++ return -EBUSY; ++ bcm4377->bar2 = pcim_iomap(pdev, 2, 0); ++ if (!bcm4377->bar2) ++ return -EBUSY; ++ ++ ret = bcm4377_parse_otp(bcm4377); ++ if (ret) { ++ dev_err(&pdev->dev, "Reading OTP failed with %d\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Legacy interrupts result in an IRQ storm because we don't know where ++ * the interrupt mask and status registers for these chips are. ++ * MSIs are acked automatically instead. ++ */ ++ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); ++ if (ret < 0) ++ return -ENODEV; ++ ret = devm_add_action_or_reset(&pdev->dev, bcm4377_pci_free_irq_vectors, ++ pdev); ++ if (ret) ++ return ret; ++ ++ irq = pci_irq_vector(pdev, 0); ++ if (irq <= 0) ++ return -ENODEV; ++ ++ ret = devm_request_irq(&pdev->dev, irq, bcm4377_irq, 0, "bcm4377", ++ bcm4377); ++ if (ret) ++ return ret; ++ ++ hdev = hci_alloc_dev(); ++ if (!hdev) ++ return -ENOMEM; ++ ret = devm_add_action_or_reset(&pdev->dev, bcm4377_hci_free_dev, hdev); ++ if (ret) ++ return ret; ++ ++ bcm4377->hdev = hdev; ++ ++ hdev->bus = HCI_PCI; ++ hdev->dev_type = HCI_PRIMARY; ++ hdev->open = bcm4377_hci_open; ++ hdev->close = bcm4377_hci_close; ++ hdev->send = bcm4377_hci_send_frame; ++ hdev->set_bdaddr = bcm4377_hci_set_bdaddr; ++ hdev->setup = bcm4377_hci_setup; ++ ++ set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); ++ if (bcm4377->hw->broken_ext_scan) ++ set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks); ++ if (bcm4377->hw->fixup_le_ext_adv_report_evt_type) ++ set_bit(HCI_QUIRK_FIXUP_LE_EXT_ADV_REPORT_EVT_TYPE, ++ &hdev->quirks); ++ ++ pci_set_drvdata(pdev, bcm4377); ++ hci_set_drvdata(hdev, bcm4377); ++ SET_HCIDEV_DEV(hdev, &pdev->dev); ++ ++ ret = bcm4377_boot(bcm4377); ++ if (ret) ++ return ret; ++ ++ ret = bcm4377_setup_rti(bcm4377); ++ if (ret) ++ return ret; ++ ++ ret = hci_register_dev(hdev); ++ if (ret) ++ return ret; ++ return devm_add_action_or_reset(&pdev->dev, bcm4377_hci_unregister_dev, ++ hdev); ++} ++ ++static int bcm4377_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev); ++ int ret; ++ ++ ret = hci_suspend_dev(bcm4377->hdev); ++ if (ret) ++ return ret; ++ ++ iowrite32(BCM4377_BAR0_SLEEP_CONTROL_QUIESCED, ++ bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL); ++ ++ return 0; ++} ++ ++static int bcm4377_resume(struct pci_dev *pdev) ++{ ++ struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev); ++ ++ iowrite32(BCM4377_BAR0_SLEEP_CONTROL_AWAKE, ++ bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL); ++ ++ return hci_resume_dev(bcm4377->hdev); ++} ++ ++static const struct bcm4377_hw bcm4377_hw_variants[] = { ++ [BCM4377] = { ++ .id = 0x4377, ++ .otp_offset = 0x4120, ++ .bar0_window1 = 0x1800b000, ++ .bar0_window2 = 0x1810c000, ++ .board_type = "apple,formosa", ++ .disable_aspm = true, ++ .broken_ext_scan = true, ++ .send_ptb = bcm4377_send_ptb, ++ }, ++ ++ [BCM4378] = { ++ .id = 0x4378, ++ .otp_offset = 0x4120, ++ .bar0_window1 = 0x18002000, ++ .bar0_window2 = 0x1810a000, ++ .bar0_core2_window2 = 0x18107000, ++ .has_bar0_core2_window2 = true, ++ .fixup_le_ext_adv_report_evt_type = true, ++ .send_calibration = bcm4378_send_calibration, ++ .send_ptb = bcm4378_send_ptb, ++ }, ++ ++ [BCM4387] = { ++ .id = 0x4387, ++ .otp_offset = 0x413c, ++ .bar0_window1 = 0x18002000, ++ .bar0_window2 = 0x18109000, ++ .bar0_core2_window2 = 0x18106000, ++ .has_bar0_core2_window2 = true, ++ .clear_pciecfg_subsystem_ctrl_bit19 = true, ++ .fixup_le_ext_adv_report_evt_type = true, ++ .send_calibration = bcm4387_send_calibration, ++ .send_ptb = bcm4378_send_ptb, ++ }, ++}; ++ ++#define BCM4377_DEVID_ENTRY(id) \ ++ { \ ++ PCI_VENDOR_ID_BROADCOM, BCM##id##_DEVICE_ID, PCI_ANY_ID, \ ++ PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \ ++ BCM##id \ ++ } ++ ++static const struct pci_device_id bcm4377_devid_table[] = { ++ BCM4377_DEVID_ENTRY(4377), ++ BCM4377_DEVID_ENTRY(4378), ++ BCM4377_DEVID_ENTRY(4387), ++ {}, ++}; ++MODULE_DEVICE_TABLE(pci, bcm4377_devid_table); ++ ++static struct pci_driver bcm4377_pci_driver = { ++ .name = "hci_bcm4377", ++ .id_table = bcm4377_devid_table, ++ .probe = bcm4377_probe, ++ .suspend = bcm4377_suspend, ++ .resume = bcm4377_resume, ++}; ++module_pci_driver(bcm4377_pci_driver); ++ ++MODULE_AUTHOR("Sven Peter "); ++MODULE_DESCRIPTION("Bluetooth support for Broadcom 4377/4378/4387 PCIe devices"); ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_FIRMWARE("brcm/brcmbt4377*.bin"); ++MODULE_FIRMWARE("brcm/brcmbt4377*.ptb"); ++MODULE_FIRMWARE("brcm/brcmbt4378*.bin"); ++MODULE_FIRMWARE("brcm/brcmbt4378*.ptb"); ++MODULE_FIRMWARE("brcm/brcmbt4387*.bin"); ++MODULE_FIRMWARE("brcm/brcmbt4387*.ptb"); +-- +2.34.1 + diff --git a/target/linux/silicon/patches-5.19/0171-Makefile-Add-asahi-EXTRAVERSION.patch b/target/linux/silicon/patches-5.19/0171-Makefile-Add-asahi-EXTRAVERSION.patch new file mode 100644 index 000000000..fc43aae1d --- /dev/null +++ b/target/linux/silicon/patches-5.19/0171-Makefile-Add-asahi-EXTRAVERSION.patch @@ -0,0 +1,26 @@ +From 487be23db1706c5e323031169e0ec79995513928 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Thu, 2 Dec 2021 20:37:25 +0900 +Subject: [PATCH 171/171] Makefile: Add -asahi EXTRAVERSION + +Signed-off-by: Hector Martin +--- + Makefile | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Makefile b/Makefile +index df92892325ae..548debd24182 100644 +--- a/Makefile ++++ b/Makefile +@@ -18,6 +18,8 @@ $(if $(filter __%, $(MAKECMDGOALS)), \ + PHONY := __all + __all: + ++EXTRAVERSION := $(EXTRAVERSION)-asahi ++ + # We are using a recursive build, so we need to do a little thinking + # to get the ordering right. + # +-- +2.34.1 +