diff --git a/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml b/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml index 5d9f55c3e5899..b059430cee63d 100644 --- a/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml +++ b/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml @@ -45,6 +45,7 @@ properties: - apple,t8132-pmgr - apple,t8140-pmgr - apple,t8142-pmgr + - apple,t8152-pmgr - const: apple,t8103-pmgr - const: syscon - const: simple-mfd diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml index 64d80cd5f4bcd..17e3f37e673c5 100644 --- a/Documentation/devicetree/bindings/dma/apple,admac.yaml +++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml @@ -44,6 +44,7 @@ properties: - items: - const: apple,t6041-admac - const: apple,t8132-admac + - const: apple,t8152-admac reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/i2c/apple,i2c.yaml b/Documentation/devicetree/bindings/i2c/apple,i2c.yaml index 5c827af153cb5..f117341886ca5 100644 --- a/Documentation/devicetree/bindings/i2c/apple,i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/apple,i2c.yaml @@ -30,6 +30,7 @@ properties: - apple,t8122-i2c - apple,t8132-i2c - apple,t8140-i2c + - apple,t8152-i2c - const: apple,t8103-i2c - items: - enum: diff --git a/Documentation/devicetree/bindings/iommu/apple,dart.yaml b/Documentation/devicetree/bindings/iommu/apple,dart.yaml index 514b17641bf5b..9968b519a6db7 100644 --- a/Documentation/devicetree/bindings/iommu/apple,dart.yaml +++ b/Documentation/devicetree/bindings/iommu/apple,dart.yaml @@ -169,6 +169,17 @@ properties: and filtering state without a separate page-table root. Source and destination must differ, and both must exist on the controller. + apple,retain-translation: + type: boolean + description: > + The bootloader hands this DART over translating, with stream page + tables that a co-processor's firmware keeps using, but without setting + the hardware lock. The operating system then treats the DART as locked: + it does not reset it or replace the inherited stream roots, adds its + own mappings only in root entries that are empty at handoff, and on + detach clears only the entries it added. The entries present at handoff + stay owned by the firmware, which may keep using them at any time. + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/iommu/apple,sart.yaml b/Documentation/devicetree/bindings/iommu/apple,sart.yaml index e6482453d6dac..021fb3eb5b8f5 100644 --- a/Documentation/devicetree/bindings/iommu/apple,sart.yaml +++ b/Documentation/devicetree/bindings/iommu/apple,sart.yaml @@ -26,6 +26,9 @@ description: SART3, first seen in M1 Pro/Max, extends both the address space and filter entry size to 42 bit. + SART4, found in T8152 (M6), moves the configuration, address and size + registers into separate arrays. + properties: compatible: oneOf: @@ -45,6 +48,7 @@ properties: - apple,t6000-sart - apple,t8015-sart - apple,t8103-sart + - apple,t8152-sart reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml b/Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml index cd19124e724c3..5c112f77a53a2 100644 --- a/Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml +++ b/Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml @@ -27,6 +27,12 @@ properties: masking provided by the interrupt controller. const: apple,t8152-smc-mailbox + - description: + T8152 ASC wrapper (v8) mailbox of the AOP, with the counted + FIFOs of the SMC mailbox, described with its send-empty and + recv-not-empty interrupts. + const: apple,t8152-ascwrap-v8-mailbox + - description: ASC mailboxes are the most common variant found on the M1 used for example for the display controller, the system management @@ -75,6 +81,11 @@ properties: AOP setup-port mailbox with a separate register layout. const: apple,t8140-aop-setup-mailbox + - description: + T8152 ANS post-office mailbox, a 0x80 window in the post-office + bank. No interrupts are described for it; the host polls it. + const: apple,t8152-ans-mailbox + - description: An older ASC mailbox interface found on T2 and A11 that is also used for the NVMe coprocessor and the system management @@ -137,7 +148,9 @@ allOf: properties: compatible: contains: - const: apple,t8152-smc-mailbox + enum: + - apple,t8152-ascwrap-v8-mailbox + - apple,t8152-smc-mailbox then: properties: interrupts: @@ -148,6 +161,20 @@ allOf: - const: send-empty - const: recv-not-empty + - if: + properties: + compatible: + contains: + const: apple,t8152-ans-mailbox + then: + properties: + interrupts: false + interrupt-names: false + else: + required: + - interrupts + - interrupt-names + - if: properties: compatible: @@ -196,6 +223,8 @@ allOf: - apple,t6021-ane-mailbox - apple,t8112-ane-mailbox - apple,t8140-aop-setup-mailbox + - apple,t8152-ans-mailbox + - apple,t8152-ascwrap-v8-mailbox - apple,t8152-smc-mailbox then: properties: @@ -211,8 +240,6 @@ allOf: required: - compatible - reg - - interrupts - - interrupt-names - "#mbox-cells" additionalProperties: false diff --git a/Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml b/Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml index a6dafcf594289..b0f21ee126b01 100644 --- a/Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml +++ b/Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml @@ -22,6 +22,7 @@ properties: - apple,t8122-nvme-ans2 - const: apple,t8103-nvme-ans2 - const: apple,t8132-nvme-ans2 + - const: apple,t8152-nvme-ans2 - items: - const: apple,t8132-nvme-ans2 - const: apple,t8103-nvme-ans2 @@ -110,6 +111,18 @@ properties: buffers must remain reserved and protected by the SART. allOf: + - if: + properties: + compatible: + not: + contains: + const: apple,t8152-nvme-ans2 + then: + required: + - resets + - power-domains + - power-domain-names + - if: properties: compatible: @@ -170,9 +183,6 @@ required: - compatible - reg - reg-names - - resets - - power-domains - - power-domain-names - mboxes - interrupts - apple,sart diff --git a/Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml b/Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml index fe8b2001f4fa5..4a2ba5158b0f6 100644 --- a/Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml +++ b/Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml @@ -28,6 +28,7 @@ properties: - apple,simetra-pmic - apple,stowe-pmic - apple,vale-pmic + - apple,woodcote-pmic - const: apple,spmi-nvmem reg: diff --git a/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml b/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml index 1c3bd5a5b5d2c..eeaf5f20827f9 100644 --- a/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml +++ b/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml @@ -69,6 +69,7 @@ properties: - apple,t8132-pmgr-pwrstate - apple,t8140-pmgr-pwrstate - apple,t8142-pmgr-pwrstate + - apple,t8152-pmgr-pwrstate - const: apple,t8103-pmgr-pwrstate reg: diff --git a/Documentation/devicetree/bindings/spmi/apple,spmi.yaml b/Documentation/devicetree/bindings/spmi/apple,spmi.yaml index ac2e7407ef780..e504ed9a8871a 100644 --- a/Documentation/devicetree/bindings/spmi/apple,spmi.yaml +++ b/Documentation/devicetree/bindings/spmi/apple,spmi.yaml @@ -38,6 +38,11 @@ properties: - apple,t8132-spmi - apple,t8140-spmi - const: apple,t8103-spmi + - description: + The gen-4 controller of T8152, with its FIFO registers at 0x200. + items: + - const: apple,t8152-spmi + - const: apple,t8142-spmi reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml index 00b0f2ec2bdb4..0a21eb27ad083 100644 --- a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml @@ -24,6 +24,7 @@ properties: - apple,t8122-wdt - apple,t8132-wdt - apple,t8140-wdt + - apple,t8152-wdt - const: apple,t8103-wdt - items: - enum: diff --git a/arch/arm64/boot/dts/apple/t8152-j873-audio.dtsi b/arch/arm64/boot/dts/apple/t8152-j873-audio.dtsi new file mode 100644 index 0000000000000..72bfb845022b8 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8152-j873-audio.dtsi @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * J873g audio: the AOP (always-on processor) owns the audio fabric, as + * on T8140. iBoot loads the AOP firmware (j873gaop) and leaves the CPU + * stopped; Linux starts it. The jack codec (CS42L84) and the speaker amp + * (SN012776) are on AP I2C buses; their data goes through AOP services on + * the base-ns ADMAC. Resources are from the 26A434 ADT: aop, dart-sbr, + * admac-base-ns, iop-audio-controller, i2c1, i2c3, pmgr. + */ +#include + +/* + * ADT dart-sbr (sbr_dart in t8152-peripherals.dtsi), shared with the PMP: + * mapper-aop 0, mapper-admac-base-ns 42. iBoot leaves streams 0, 1 and 42 + * translating (root slot 16 owned by the firmware) without setting the + * lock bit. + */ +&sbr_dart { + apple,retain-translation; + status = "okay"; +}; + +/ { + soc { + /* + * ADT aop: iop,ascwrap-v8, msgbox-mailbox-num 0, using-alias, + * not post-office: mailbox 0, aperture 1 of the bank at reg[2] + * (0x310740000) = 0x310740080. ADT interrupts [627, 626, 628]; + * the first two in the SMC order (send-empty, recv-not-empty). + */ + aop_mbox: mailbox@310740080 { + compatible = "apple,t8152-ascwrap-v8-mailbox"; + reg = <0x3 0x10740080 0x0 0x80>; + interrupts = , + ; + interrupt-names = "send-empty", "recv-not-empty"; + #mbox-cells = <0>; + }; + + /* + * ADT admac-base-ns (admac-evolution,t8152): 13 TX and 13 RX + * channels, interrupt destination 0, dart-sbr stream 42. + */ + admac_base_ns: dma-controller@313900000 { + compatible = "apple,t8152-admac"; + reg = <0x3 0x13900000 0x0 0xb4000>; + dma-channels = <26>; + interrupts-extended = <&aic AIC_IRQ 640 IRQ_TYPE_LEVEL_HIGH>, + <0>, <0>, <0>; + #dma-cells = <1>; + iommus = <&sbr_dart 42>; + /* slot 17: slot 16 of stream 42 belongs to the firmware */ + apple,dma-range = <0x110 0x0 0x0 0x10000000>; + }; + + /* + * The AOP's PMGR (ADT pmgr devices AUDIO_MCA0_M..AUDIO_MCA5_M at + * 0x308284400 + 0x20 * N). Their parent audio_p is the + * firmware's: it is up while a service is in pw0 or pwrd. + */ + pmgr_aop: power-management@308284000 { + compatible = "apple,t8152-pmgr", "apple,t8103-pmgr", + "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x3 0x08284000 0x0 0x1000>; + + ps_audio_mca0_m: power-controller@400 { + compatible = "apple,t8152-pmgr-pwrstate", + "apple,t8103-pmgr-pwrstate"; + reg = <0x400 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "audio_mca0_m"; + }; + + ps_audio_mca1_m: power-controller@420 { + compatible = "apple,t8152-pmgr-pwrstate", + "apple,t8103-pmgr-pwrstate"; + reg = <0x420 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "audio_mca1_m"; + }; + + ps_audio_mca2_m: power-controller@440 { + compatible = "apple,t8152-pmgr-pwrstate", + "apple,t8103-pmgr-pwrstate"; + reg = <0x440 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "audio_mca2_m"; + }; + + ps_audio_mca3_m: power-controller@460 { + compatible = "apple,t8152-pmgr-pwrstate", + "apple,t8103-pmgr-pwrstate"; + reg = <0x460 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "audio_mca3_m"; + }; + + ps_audio_mca4_m: power-controller@480 { + compatible = "apple,t8152-pmgr-pwrstate", + "apple,t8103-pmgr-pwrstate"; + reg = <0x480 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "audio_mca4_m"; + }; + + ps_audio_mca5_m: power-controller@4a0 { + compatible = "apple,t8152-pmgr-pwrstate", + "apple,t8103-pmgr-pwrstate"; + reg = <0x4a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "audio_mca5_m"; + }; + }; + + /* ADT i2c1: the CS42L84 jack codec (and the aqc NIC's EEPROM). */ + i2c1: i2c@331014000 { + compatible = "apple,t8152-i2c", "apple,t8103-i2c"; + reg = <0x3 0x31014000 0x0 0x4000>; + clocks = <&clkref>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&ps_i2c1>; + + /* + * ADT audio-codec-output: function-reset GPIO 0xcc, + * interrupt on gpio0 pin 203. + */ + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_ap 204 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 203 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + sound-name-prefix = "Jack"; + }; + }; + + /* ADT i2c3: the SN012776 speaker amplifier. */ + i2c3: i2c@33101c000 { + compatible = "apple,t8152-i2c", "apple,t8103-i2c"; + reg = <0x3 0x3101c000 0x0 0x4000>; + clocks = <&clkref>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&ps_i2c3>; + + /* + * ADT audio-speaker: function-reset GPIO 0xca, interrupt + * on gpio0 pin 193, speaker-config rx_slot 0, + * vsense_slot 0, isense_slot 2. + */ + speaker_amp: codec@38 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x38>; + shutdown-gpios = <&pinctrl_ap 202 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 193 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + ti,imon-slot-no = <2>; + ti,vmon-slot-no = <0>; + /* the AOP's speaker frame: 250 BCLKs at 12 MHz */ + ti,bclk-ratio = <250>; + }; + }; + + aop: aop@310c00000 { + compatible = "apple,t8152-aop"; + reg = <0x3 0x10c00000 0x0 0x1e0000>, + <0x3 0x10600000 0x0 0x4000>; + reg-names = "mmio", "asc"; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&sbr_dart 0>; + /* slot 17: slot 16 belongs to the firmware */ + apple,dma-range = <0x110 0x0 0x10 0x0>; + + /* + * Bound by name to the firmware's "audio" EPIC service. + * ADT iop-audio-controller: cout/cin on base-ns TX5/RX5, + * spkr on TX1 with its sense data on RX1; Linux ADMAC + * channel = 2 * N for TX N, 2 * N + 1 for RX N. + */ + aop_audio: audio { + compatible = "apple,t8152-aop-audio"; + dmas = <&admac_base_ns 10>, <&admac_base_ns 11>, + <&admac_base_ns 2>, <&admac_base_ns 3>; + dma-names = "cout", "cin", "spkr", "sense"; + power-domains = <&ps_audio_mca0_m>, <&ps_audio_mca1_m>, + <&ps_audio_mca2_m>, <&ps_audio_mca3_m>, + <&ps_audio_mca4_m>, <&ps_audio_mca5_m>; + power-domain-names = "mca0", "mca1", "mca2", + "mca3", "mca4", "mca5"; + #sound-dai-cells = <1>; + }; + }; + }; + + sound { + compatible = "apple,j873-macaudio", "apple,macaudio"; + model = "Mac mini J873"; + #address-cells = <1>; + #size-cells = <0>; + + dai-link@0 { + reg = <0>; + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&aop_audio 0>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + + dai-link@1 { + reg = <1>; + link-name = "Speaker"; + + cpu { + sound-dai = <&aop_audio 3>; + }; + codec { + sound-dai = <&speaker_amp>; + }; + }; + }; +}; + +/* The I2C power states (PMGR, parent SIO_CPU is always on). */ +&pmgr { + ps_i2c1: power-controller@cc0 { + compatible = "apple,t8152-pmgr-pwrstate", + "apple,t8103-pmgr-pwrstate"; + reg = <0xcc0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c1"; + }; + + ps_i2c3: power-controller@d00 { + compatible = "apple,t8152-pmgr-pwrstate", + "apple,t8103-pmgr-pwrstate"; + reg = <0xd00 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c3"; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8152-j873-ethernet.dtsi b/arch/arm64/boot/dts/apple/t8152-j873-ethernet.dtsi new file mode 100644 index 0000000000000..8b4f0f007df54 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8152-j873-ethernet.dtsi @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * J873g internal PCIe (apcie) port 2: the on-board 10GbE NIC (ADT + * /arm-io/apcie/pci-bridge2/lan0; the ADT names an aqc107, the device has + * PCI ID 10ec:8127 and identifies as a Realtek RTL8125CP, XID 0x708). + * iBoot leaves the APCIE power domains on and + * the root complex enabled, but the AUS5 PHY gated and the lanes assigned + * to port 0; the loader ungates the PHY, writes the ADT lane-cfg and applies + * the dart-apcie2 tunables first. Port setup follows the T602x/T8122 + * register layout. Port 0 (N1) is bus 1, port 2 is bus 2. + * Resources are from the 26A434 ADT: apcie, dart-apcie2, gpio0. + */ +#include + +/ { + aliases { + ethernet0 = ðernet0; + }; +}; + +/* + * dart-apcie2, described in t8152-peripherals.dtsi. The ADT window is + * 0x20000; keep the 0xc000 this port was brought up with, the size that + * pcie0_dart has in t8152-j873-n1.dtsi. + */ +&pcie2_dart { + reg = <0x3 0x8a000000 0x0 0xc000>; + status = "okay"; +}; + +&pcie { + reg = <0x1c 0xb0000000 0x0 0x1000000>, /* config */ + <0x3 0x8c000000 0x0 0x4000>, /* rc */ + <0x3 0x88028000 0x0 0x4000>, /* port0 */ + <0x3 0x8f010000 0x0 0x4000>, /* phy0 */ + <0x3 0x8a028000 0x0 0x4000>, /* port2 */ + <0x3 0x8f018000 0x0 0x4000>; /* phy2 */ + reg-names = "config", "rc", "port0", "phy0", "port2", "phy2"; + /* One per root port, indexed by the port number. */ + interrupts = , + , + ; + iommu-map = <0x100 &pcie0_dart 1 1>, + <0x101 &pcie0_dart 2 1>, + <0x102 &pcie0_dart 3 1>, + <0x200 &pcie2_dart 1 1>; + bus-range = <0 7>; + + port02: pci@2,0 { + device_type = "pci"; + reg = <0x1000 0x0 0x0 0x0 0x0>; + reset-gpios = <&pinctrl_ap 5 GPIO_ACTIVE_LOW>; + bus-range = <2 2>; + #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>; + + ethernet0: ethernet@0,0 { + reg = <0x20000 0x0 0x0 0x0 0x0>; + /* Filled in by the loader from the ADT. */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8152-j873-nvme.dtsi b/arch/arm64/boot/dts/apple/t8152-j873-nvme.dtsi new file mode 100644 index 0000000000000..c53059ab55d34 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8152-j873-nvme.dtsi @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * J873g ANS2 NVMe. + * iBoot leaves the ANS firmware running with the NVMe controller disabled; + * the driver wakes it with a fresh RTKit handshake (as m1n1 does). NVMe + * registers and NVMMU share the 0x325cc0000 window. The mailbox is the ANS + * post-office window (msgbox-mailbox-num 3, no alias: 0x316000000 + + * 0x10300). No PMGR power or reset yet. + * Resources are from the 26A434 ADT: ans, sart-ans. + */ + +/ { + soc { + ans_mbox: mailbox@316010300 { + compatible = "apple,t8152-ans-mailbox"; + reg = <0x3 0x16010300 0x0 0x80>; + #mbox-cells = <0>; + }; + + sart: iommu@325c50000 { + compatible = "apple,t8152-sart"; + reg = <0x3 0x25c50000 0x0 0xc000>; + }; + + nvme: nvme@325cc0000 { + compatible = "apple,t8152-nvme-ans2"; + reg = <0x3 0x25cc0000 0x0 0x60000>, + <0x3 0x21600000 0x0 0x4000>; + reg-names = "nvme", "ans"; + interrupts = ; + mboxes = <&ans_mbox>; + apple,sart = <&sart>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8152-j873g.dts b/arch/arm64/boot/dts/apple/t8152-j873g.dts index 00fe5207a1956..d4900374f1470 100644 --- a/arch/arm64/boot/dts/apple/t8152-j873g.dts +++ b/arch/arm64/boot/dts/apple/t8152-j873g.dts @@ -10,6 +10,7 @@ #include #include +#include / { compatible = "apple,j873g", "apple,t8152", "apple,arm-platform"; @@ -205,6 +206,15 @@ opp-level = <3>; }; }; + + /* The 24 MHz timebase (ADT timebase-frequency), as on T8103. */ + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + timer { compatible = "arm,armv8-timer"; interrupts = , @@ -241,6 +251,62 @@ #performance-domain-cells = <0>; }; + /* + * ADT /arm-io/nub-spmi0 (gen 4) and its primary PMU, pmu-main + * ("woodcote", slave 0xe). The boot flags live in the legacy + * scratchpad (info-leg_scrpad = 0xf800), laid out as on T8103 + * and T8140; boot_stage read 0x30 (kernel started) here. + */ + nub_spmi0: spmi@308714000 { + /* + * Gen 4: FIFO registers at 0x200 (the block is 0x4000 + * long); polled, so no interrupts are described yet. + */ + compatible = "apple,t8152-spmi", "apple,t8142-spmi"; + reg = <0x3 0x08714000 0x0 0x4000>; + #address-cells = <2>; + #size-cells = <0>; + + pmic@e { + compatible = "apple,woodcote-pmic", "apple,spmi-nvmem"; + reg = <0xe SPMI_USID>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + boot_stage: boot-stage@f801 { + reg = <0xf801 0x1>; + }; + + boot_error_count: boot-error-count@f802,0 { + reg = <0xf802 0x1>; + bits = <0 4>; + }; + + panic_count: panic-count@f802,4 { + reg = <0xf802 0x1>; + bits = <4 4>; + }; + + /* Set before off1, or the machine powers back on. */ + shutdown_flag: shutdown-flag@f80f,3 { + reg = <0xf80f 0x1>; + bits = <3 1>; + }; + }; + }; + }; + + /* ADT /arm-io/wdt (wdt,t8152): restart fallback and /dev/watchdog. */ + wdt: watchdog@3082b0000 { + compatible = "apple,t8152-wdt", "apple,t8103-wdt"; + reg = <3 0x082b0000 0 0x4000>; + clocks = <&clkref>; + interrupts = ; + }; + smc_mbox: mailbox@30c710080 { compatible = "apple,t8152-smc-mailbox"; reg = <3 0x0c710080 0 0x80>; @@ -257,6 +323,15 @@ reg-names = "smc", "sram"; mboxes = <&smc_mbox>; + /* Power off (MBSE = off1) and restart (MBSE = phra). */ + smc_reboot: reboot { + compatible = "apple,smc-reboot"; + nvmem-cells = <&shutdown_flag>, <&boot_stage>, + <&boot_error_count>, <&panic_count>; + nvmem-cell-names = "shutdown_flag", "boot_stage", + "boot_error_count", "panic_count"; + }; + hwmon { compatible = "apple,smc-hwmon"; apple,discover-temperatures; @@ -265,6 +340,8 @@ apple,key-id = "F0Ac"; apple,fan-minimum = "F0Mn"; apple,fan-maximum = "F0Mx"; + apple,fan-target = "F0Tg"; + apple,fan-mode = "F0md"; label = "Fan"; }; }; @@ -430,3 +507,11 @@ reg = <0x3 0x83020000 0x0 0xc000>, <0x3 0x83040000 0x0 0xc000>; }; + +/* + * The J873g fragments enable and refine nodes of t8152-peripherals.dtsi + * (the apcie port 2 and dart-sbr DARTs), so they come after it. + */ +#include "t8152-j873-nvme.dtsi" +#include "t8152-j873-ethernet.dtsi" +#include "t8152-j873-audio.dtsi" diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index 60b8c04530634..bdafb0ff4aecb 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -70,13 +70,29 @@ */ #define REG_CHAN_BASE_LEGACY(ch) (0x8000 + (ch) * 0x200) #define REG_CHAN_BASE_EVOLVED(ch) (((ch) & 1 ? 0xc000 : 0x8000) + ((ch) / 2) * 0x200) -#define REG_CHAN_BASE(ad, ch) ((ad)->evolved_layout ? \ +/* + * T8152 (ADT admac-evolution,t8152; the macOS AudioDMAController-T8152 + * driver): the same per-channel block, 0x4000 apart, TX at 0x40000 and RX + * at 0x80000, and a channel has to be put in state 2 (+0x30 bits 3:0) + * before it is started. The descriptor and report FIFO ports are the legacy + * ones (the RX descriptor port answers at 0x14000 + 4n, not at the ADT's + * 0x10040 + 4n). + */ +#define REG_CHAN_BASE_T8152(ch) (((ch) & 1 ? 0x80000 : 0x40000) + ((ch) / 2) * 0x4000) +#define REG_CHAN_BASE(ad, ch) ((ad)->t8152_layout ? REG_CHAN_BASE_T8152(ch) : \ + (ad)->evolved_layout ? \ REG_CHAN_BASE_EVOLVED(ch) : REG_CHAN_BASE_LEGACY(ch)) #define REG_CHAN_CTL(ad, ch) (REG_CHAN_BASE(ad, ch) + 0x00) #define REG_CHAN_CTL_RST_RINGS BIT(0) #define REG_CHAN_CONFIG(ad, ch) (REG_CHAN_BASE(ad, ch) + 0x04) +/* macOS writes this for the T8152 base-ns channels before every start */ +#define CHAN_CONFIG_T8152 0x029b0000 #define REG_CHAN_BURST(ad, ch) (REG_CHAN_BASE(ad, ch) + 0x30) +/* T8152: the low nibble of the same register is the channel state */ +#define REG_CHAN_STATE(ad, ch) REG_CHAN_BURST(ad, ch) +#define CHAN_STATE_MASK GENMASK(3, 0) +#define CHAN_STATE_READY 2 #define REG_DESC_RING(ad, ch) (REG_CHAN_BASE(ad, ch) + 0x70) #define REG_REPORT_RING(ad, ch) (REG_CHAN_BASE(ad, ch) + 0x74) @@ -104,6 +120,11 @@ #define REG_DESC_WRITE(ch) (0x10000 + ((ch) / 2) * 0x4 + ((ch) & 1) * 0x4000) #define REG_REPORT_READ(ch) (0x10100 + ((ch) / 2) * 0x4 + ((ch) & 1) * 0x4000) +/* T8152: the AP's share of each SRAM pool starts above the firmware's. */ +#define T8152_SRAM_BASE 0x1000 +#define T8152_SRAM_BLOCK 1024 +#define SRAM_SIZE_MASK GENMASK(15, 0) + #define REG_TX_INTSTATE(idx) (0x0030 + (idx) * 4) #define REG_RX_INTSTATE(idx) (0x0040 + (idx) * 4) #define REG_GLOBAL_INTSTATE(idx) (0x0050 + (idx) * 4) @@ -124,6 +145,8 @@ struct admac_chan { struct tasklet_struct tasklet; u32 carveout; + /* T8152: transfer descriptor id, 1..255 */ + u8 desc_id; spinlock_t lock; struct admac_tx *current_tx; @@ -164,6 +187,7 @@ struct admac_data { bool set_unk28; bool evolved_layout; bool split_channels; + bool t8152_layout; bool ctl_programmed; int irq; int irq_index; @@ -193,6 +217,7 @@ struct admac_hw { bool set_unk28; bool evolved_layout; bool split_channels; + bool t8152_layout; }; static int admac_alloc_sram_carveout(struct admac_data *ad, @@ -201,6 +226,8 @@ static int admac_alloc_sram_carveout(struct admac_data *ad, { struct admac_sram *sram; int i, ret = 0, nblocks; + u32 first = 0, block = SRAM_BLOCK; + ad->txcache.size = readl_relaxed(ad->base + REG_TX_SRAM_SIZE); ad->rxcache.size = readl_relaxed(ad->base + REG_RX_SRAM_SIZE); /* T8132 reports channel metadata in the upper half of these words. */ @@ -208,6 +235,13 @@ static int admac_alloc_sram_carveout(struct admac_data *ad, ad->txcache.size &= GENMASK(15, 0); ad->rxcache.size &= GENMASK(15, 0); } + if (ad->t8152_layout) { + /* bits 31:24 are the channel count */ + ad->txcache.size &= SRAM_SIZE_MASK; + ad->rxcache.size &= SRAM_SIZE_MASK; + first = T8152_SRAM_BASE; + block = T8152_SRAM_BLOCK; + } if (dir == DMA_MEM_TO_DEV) sram = &ad->txcache; @@ -216,14 +250,14 @@ static int admac_alloc_sram_carveout(struct admac_data *ad, mutex_lock(&ad->cache_alloc_lock); - nblocks = sram->size / SRAM_BLOCK; + nblocks = sram->size > first ? (sram->size - first) / block : 0; for (i = ad->split_channels ? 1 : 0; i < nblocks; i++) if (!(sram->allocated & BIT(i))) break; if (i < nblocks) { - *out = FIELD_PREP(CHAN_SRAM_CARVEOUT_BASE, i * SRAM_BLOCK) | - FIELD_PREP(CHAN_SRAM_CARVEOUT_SIZE, SRAM_BLOCK); + *out = FIELD_PREP(CHAN_SRAM_CARVEOUT_BASE, first + i * block) | + FIELD_PREP(CHAN_SRAM_CARVEOUT_SIZE, block); sram->allocated |= BIT(i); } else { ret = -EBUSY; @@ -240,18 +274,24 @@ static void admac_free_sram_carveout(struct admac_data *ad, { struct admac_sram *sram; u32 base = FIELD_GET(CHAN_SRAM_CARVEOUT_BASE, carveout); + u32 first = 0, block = SRAM_BLOCK; int i; + if (ad->t8152_layout) { + first = T8152_SRAM_BASE; + block = T8152_SRAM_BLOCK; + } + if (dir == DMA_MEM_TO_DEV) sram = &ad->txcache; else sram = &ad->rxcache; - if (WARN_ON(base >= sram->size)) + if (WARN_ON(base < first || base >= sram->size)) return; mutex_lock(&ad->cache_alloc_lock); - i = base / SRAM_BLOCK; + i = (base - first) / block; sram->allocated &= ~BIT(i); mutex_unlock(&ad->cache_alloc_lock); } @@ -354,7 +394,19 @@ static void admac_write_hw_desc(struct admac_data *ad, int channo, writel_relaxed(lower_32_bits(addr), ad->base + REG_DESC_WRITE(channo)); writel_relaxed(upper_32_bits(addr), ad->base + REG_DESC_WRITE(channo)); writel_relaxed(len, ad->base + REG_DESC_WRITE(channo)); - writel_relaxed(FLAG_DESC_NOTIFY, ad->base + REG_DESC_WRITE(channo)); + if (ad->t8152_layout) { + /* + * T8152: the low byte of the last word is a descriptor id, + * which macOS counts 1..255 and never leaves at 0. + */ + struct admac_chan *adchan = &ad->channels[channo]; + + adchan->desc_id = adchan->desc_id == 255 ? 1 : adchan->desc_id + 1; + writel_relaxed(FLAG_DESC_NOTIFY | adchan->desc_id, + ad->base + REG_DESC_WRITE(channo)); + } else { + writel_relaxed(FLAG_DESC_NOTIFY, ad->base + REG_DESC_WRITE(channo)); + } } /* @@ -570,6 +622,11 @@ static void admac_start_chan(struct admac_chan *adchan) ad->base + REG_CHAN_INTSTATUS(ad, adchan->no, ad->irq_index)); writel_relaxed(STATUS_DESC_DONE | STATUS_ERR, ad->base + REG_CHAN_INTMASK(ad, adchan->no, ad->irq_index)); + if (ad->t8152_layout) { + writel_relaxed(CHAN_CONFIG_T8152, ad->base + REG_CHAN_CONFIG(ad, adchan->no)); + admac_modify(ad, REG_CHAN_STATE(ad, adchan->no), CHAN_STATE_MASK, + CHAN_STATE_READY); + } switch (admac_chan_direction(adchan->no)) { case DMA_MEM_TO_DEV: @@ -1091,7 +1148,8 @@ static int admac_device_config(struct dma_chan *chan, * of words position in a frame. That's where the importance of this control * comes from. */ - switch (is_tx ? config->dst_port_window_size : config->src_port_window_size) { + switch (ad->t8152_layout ? 0 : + is_tx ? config->dst_port_window_size : config->src_port_window_size) { case 0 ... 1: break; case 2: @@ -1202,6 +1260,7 @@ static int admac_probe(struct platform_device *pdev) ad->set_unk28 = hw->set_unk28; ad->evolved_layout = hw->evolved_layout; ad->split_channels = hw->split_channels; + ad->t8152_layout = hw->t8152_layout; mutex_init(&ad->cache_alloc_lock); /* @@ -1353,7 +1412,12 @@ static const struct admac_hw admac_t8140_hw = { .evolved_layout = true, }; +static const struct admac_hw admac_t8152_hw = { + .t8152_layout = true, +}; + static const struct of_device_id admac_of_match[] = { + { .compatible = "apple,t8152-admac", .data = &admac_t8152_hw }, { .compatible = "apple,t8140-admac", .data = &admac_t8140_hw }, { .compatible = "apple,t8132-admac", .data = &admac_t8132_hw }, { .compatible = "apple,t8122-admac", .data = &admac_t8122_hw }, diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 8efb8f32ce0ff..423dfd85ebebb 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -3976,6 +3976,14 @@ static irqreturn_t apple_dart_irq(int irq, void *dev) static bool apple_dart_is_locked(struct apple_dart *dart) { + /* + * apple,retain-translation: the bootloader left live stream tables + * that a co-processor's firmware depends on, but did not set the lock + * bit (T8152 dart-sbr: AOP and audio ADMAC streams). Treat it as + * locked so the tables are inherited rather than reset. + */ + if (of_property_read_bool(dart->dev->of_node, "apple,retain-translation")) + return true; return !!(apple_dart_readl(dart, dart->hw->lock) & dart->hw->lock_bit); } diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c index 546e5cdbb72ad..2050127a98c57 100644 --- a/drivers/mfd/macsmc.c +++ b/drivers/mfd/macsmc.c @@ -63,9 +63,15 @@ static const struct mfd_cell apple_smc_devs[] = { static const struct mfd_cell apple_smc_low_gpio_dev = MFD_CELL_OF("macsmc-low-gpio", NULL, NULL, 0, 0, "apple,smc-low-gpio"); -/* T8152 currently exposes read-only telemetry; firmware owns fan control. */ +/* + * T8152: temperatures and fans (hwmon; the fan keys are read-only unless the + * unsafe fan_control parameter is set) and power off/restart (reboot, which + * only writes the MBSE key). Notifications, GPIO and the power supply are not + * qualified there yet. + */ static const struct mfd_cell apple_smc_telemetry_devs[] = { MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"), + MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"), }; static void apple_smc_read_sram(struct apple_smc *smc, void *buf, size_t size) @@ -546,7 +552,7 @@ static int apple_smc_probe(struct platform_device *pdev) return dev_err_probe(smc->dev, ret, "Failed to get key count"); smc->key_count = be32_to_cpu(count); - /* Notifications, GPIO and power management are not qualified on T8152. */ + /* T8152: key reads and writes are qualified; notifications and GPIO are not. */ if (of_device_is_compatible(dev->of_node, "apple,t8152-smc")) return devm_mfd_add_devices(smc->dev, PLATFORM_DEVID_NONE, apple_smc_telemetry_devs, diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index 732d7b63be3d4..78581d310ab92 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -67,6 +67,15 @@ #define APPLE_ANS_LINEAR_ASQ_DB 0x2490c #define APPLE_ANS_LINEAR_IOSQ_DB 0x24910 +/* + * ADT nvme-secure-reg-layout (T8152, macOS AppleANS2NVMeController with its + * 0x92a flag set): AQA/ASQ/ACQ and the I/O queue registers move up by + * 0x4000 and LINEAR_SQ_CTRL moves into the NVMMU block. CC/CSTS, the + * doorbells and the NVMMU TCB registers stay where they are. + */ +#define APPLE_ANS_SECURE_QREG_SHIFT 0x4000 +#define APPLE_ANS_SECURE_LINEAR_SQ_CTRL 0x2813c + #define APPLE_NVMMU_NUM_TCBS 0x28100 #define APPLE_NVMMU_ASQ_TCB_BASE 0x28108 #define APPLE_NVMMU_IOSQ_TCB_BASE 0x28110 @@ -210,6 +219,11 @@ struct apple_nvme_hw { bool needs_ioq_registers; /* T8132 needs a PMGR reset when starting a stopped coprocessor. */ bool cold_reset; + /* No reset provider yet; only an adopted live session can come up. */ + bool optional_reset; + bool secure_reg_layout; + /* Also send the NVMe shutdown notification (CC.SHN) on removal. */ + bool shutdown_notify; u32 max_queue_depth; unsigned long quirks; }; @@ -381,6 +395,17 @@ static int apple_nvme_read_handoff(struct apple_nvme *anv) return apple_nvme_can_adopt_rtkit(anv) ? 0 : -EIO; } +static u32 apple_nvme_qreg(const struct apple_nvme *anv, u32 reg) +{ + return anv->hw->secure_reg_layout ? reg + APPLE_ANS_SECURE_QREG_SHIFT : reg; +} + +static u32 apple_nvme_lsq_ctrl(const struct apple_nvme *anv) +{ + return anv->hw->secure_reg_layout ? APPLE_ANS_SECURE_LINEAR_SQ_CTRL : + APPLE_ANS_LINEAR_SQ_CTRL; +} + static inline struct apple_nvme *queue_to_apple_nvme(struct apple_nvme_queue *q) { if (q->is_adminq) @@ -1357,10 +1382,13 @@ static int apple_nvme_disable_locked(struct apple_nvme *anv, bool shutdown) * The final system shutdown is the exception for SHN: without it the * controller counts every Linux shutdown as unsafe (SMART * unsafe_shutdowns) and recovers on the next start, which slows the - * loader and the first seconds of I/O. A failed SHN changes nothing: - * the CC.EN clear below still runs. + * loader and the first seconds of I/O. Where the firmware handles it, + * removal sends it too. A failed SHN changes nothing: the CC.EN clear + * below still runs. */ - if (READ_ONCE(anv->final_shutdown) && !apple_rtkit_is_crashed(anv->rtk)) { + if ((READ_ONCE(anv->final_shutdown) || + (shutdown && anv->hw->shutdown_notify && READ_ONCE(anv->removing))) && + !apple_rtkit_is_crashed(anv->rtk)) { ret = nvme_disable_ctrl(&anv->ctrl, true); if (ret) dev_warn(anv->dev, "shutdown notification failed: %d\n", ret); @@ -1790,10 +1818,10 @@ static void apple_nvme_reset_work(struct work_struct *work) */ if (!anv->lsq_in_nvmmu) { writel(APPLE_ANS_LINEAR_SQ_EN, - anv->mmio_nvme + APPLE_ANS_LINEAR_SQ_CTRL); + anv->mmio_nvme + apple_nvme_lsq_ctrl(anv)); if (anv->hw->needs_ioq_registers) { u32 lsq_ctrl = readl(anv->mmio_nvme + - APPLE_ANS_LINEAR_SQ_CTRL); + apple_nvme_lsq_ctrl(anv)); if (!(lsq_ctrl & APPLE_ANS_LINEAR_SQ_EN)) { dev_err(anv->dev, @@ -1816,9 +1844,11 @@ static void apple_nvme_reset_work(struct work_struct *work) if (anv->hw->needs_ioq_registers) ioqa_depth--; ioqa = ioqa_depth | (ioqa_depth << 16); - writel(ioqa, anv->mmio_nvme + APPLE_ANS_MAX_PEND_CMDS_CTRL); + writel(ioqa, anv->mmio_nvme + + apple_nvme_qreg(anv, APPLE_ANS_MAX_PEND_CMDS_CTRL)); if (anv->hw->needs_ioq_registers && - readl(anv->mmio_nvme + APPLE_ANS_MAX_PEND_CMDS_CTRL) != ioqa) { + readl(anv->mmio_nvme + + apple_nvme_qreg(anv, APPLE_ANS_MAX_PEND_CMDS_CTRL)) != ioqa) { dev_err(anv->dev, "failed to program I/O queue aperture\n"); ret = -EIO; goto out; @@ -1832,11 +1862,11 @@ static void apple_nvme_reset_work(struct work_struct *work) /* Setup the admin queue */ aqa = APPLE_NVME_AQ_DEPTH - 1; aqa |= aqa << 16; - writel(aqa, anv->mmio_nvme + NVME_REG_AQA); + writel(aqa, anv->mmio_nvme + apple_nvme_qreg(anv, NVME_REG_AQA)); apple_nvme_writeq(anv, anv->adminq.sq_dma_addr, - anv->mmio_nvme + NVME_REG_ASQ); + anv->mmio_nvme + apple_nvme_qreg(anv, NVME_REG_ASQ)); apple_nvme_writeq(anv, anv->adminq.cq_dma_addr, - anv->mmio_nvme + NVME_REG_ACQ); + anv->mmio_nvme + apple_nvme_qreg(anv, NVME_REG_ACQ)); if (anv->hw->has_lsq_nvmmu) { /* Setup NVMMU for both queues */ @@ -1903,10 +1933,10 @@ static void apple_nvme_reset_work(struct work_struct *work) * dedicated registers. Without them it crashes and its crash log * reports null I/O SQ and CQ addresses. */ - apple_nvme_writeq(anv, anv->ioq.cq_dma_addr, - anv->mmio_nvme + APPLE_ANS_IOCQ_REGISTER); - apple_nvme_writeq(anv, anv->ioq.sq_dma_addr, - anv->mmio_nvme + APPLE_ANS_IOSQ_REGISTER); + apple_nvme_writeq(anv, anv->ioq.cq_dma_addr, anv->mmio_nvme + + apple_nvme_qreg(anv, APPLE_ANS_IOCQ_REGISTER)); + apple_nvme_writeq(anv, anv->ioq.sq_dma_addr, anv->mmio_nvme + + apple_nvme_qreg(anv, APPLE_ANS_IOSQ_REGISTER)); } nr_io_queues = 1; if (anv->hw->has_queue_count) { @@ -2407,7 +2437,10 @@ static struct apple_nvme *apple_nvme_alloc(struct platform_device *pdev) goto out_detach_genpd; } - anv->reset = devm_reset_control_array_get_exclusive(anv->dev); + if (anv->hw->optional_reset) + anv->reset = devm_reset_control_array_get_optional_exclusive(anv->dev); + else + anv->reset = devm_reset_control_array_get_exclusive(anv->dev); if (IS_ERR(anv->reset)) { ret = dev_err_probe(dev, PTR_ERR(anv->reset), "Failed to get reset control"); @@ -2776,6 +2809,22 @@ static const struct apple_nvme_hw apple_nvme_t6040_hw = { .quirks = NVME_QUIRK_NO_APST, }; +/* + * T8152 uses the post-M4 queue setup, but its NVMe registers and NVMMU share + * one window (0x325cc0000 on J873) like T8103, with the secure register + * layout. There is no T8152 PMGR driver yet, so the controller has no reset + * line in the DT. + */ +static const struct apple_nvme_hw apple_nvme_t8152_hw = { + .has_lsq_nvmmu = true, + .needs_ioq_registers = true, + .optional_reset = true, + .secure_reg_layout = true, + .shutdown_notify = true, + .max_queue_depth = 64, + .quirks = NVME_QUIRK_BROKEN_FUA, +}; + static const struct of_device_id apple_nvme_of_match[] = { { .compatible = "apple,t6041-nvme-ans2", .data = &apple_nvme_t6040_hw }, { .compatible = "apple,t8015-nvme-ans2", .data = &apple_nvme_t8015_hw }, @@ -2783,6 +2832,7 @@ static const struct of_device_id apple_nvme_of_match[] = { { .compatible = "apple,t8132-nvme-ans2", .data = &apple_nvme_t8132_hw }, { .compatible = "apple,t8140-nvme-ans2", .data = &apple_nvme_t8140_hw }, { .compatible = "apple,t8142-nvme-ans2", .data = &apple_nvme_t8142_hw }, + { .compatible = "apple,t8152-nvme-ans2", .data = &apple_nvme_t8152_hw }, { .compatible = "apple,nvme-ans2", .data = &apple_nvme_t8103_hw }, {}, }; diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 3173186c85209..a378955bb922c 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -224,6 +224,12 @@ struct hw_info { * lane PIPE reset status, then release PORT_T8152_PIPE_RST. */ bool pipe_rst; + /* + * Keep endpoints at their reset Max_Read_Request_Size (512 bytes). + * On T8152 an RTL8127 at MRRS 4096 (what r8169 asks for) transmits + * 9000-byte frames at 7.0 Gbit/s; at 512 it reaches 9.93. + */ + bool no_inc_mrrs; }; static const struct hw_info t8103_hw = { @@ -279,6 +285,7 @@ static const struct hw_info t8152_hw = { .max_rid2sid = 512, .refbuf_off = true, .pipe_rst = true, + .no_inc_mrrs = true, }; static const struct hw_info t8103_pciec_hw = { @@ -3116,6 +3123,7 @@ static int apple_pcie_probe(struct platform_device *pdev) pcie = pci_host_bridge_priv(bridge); pcie->dev = dev; pcie->hw = hw; + bridge->no_inc_mrrs = hw->no_inc_mrrs; if (of_property_present(dev->of_node, "apple,managed-sids")) { u32 ids[15]; int count = of_property_count_u32_elems(dev->of_node, "apple,managed-sids"); diff --git a/drivers/soc/apple/mailbox.c b/drivers/soc/apple/mailbox.c index c13c03f9d92ab..4f39be303968a 100644 --- a/drivers/soc/apple/mailbox.c +++ b/drivers/soc/apple/mailbox.c @@ -220,6 +220,10 @@ struct apple_mbox_hw { unsigned int num_ascwrap_v6_roles; /* T8152 GPU ASCWrap v8: wrapper + iop-vbar + post-office window + PSD. */ bool is_ascwrap_v8; + /* No interrupts are described; receive and send are polled. */ + bool rx_poll_required; + /* J873 post-office window a polled provider must sit at. */ + u64 j873_window; /* Status word counts RX occupancy and free TX slots; paired transfers. */ bool counted_fifo; bool ap_initializes_mailboxes; @@ -251,7 +255,7 @@ struct apple_mbox_priv { struct apple_mbox mbox; /* ASCWrap v8 only: the provider's PMGR2 PSD service block (read-only). */ void __iomem *psd_regs; - /* ASCWrap v8 only: receive by polling; fixed at probe. */ + /* ASCWrap v8 and polled providers: receive by polling; fixed at probe. */ bool rx_poll_only; /* rx_lock: recv interrupt enabled and not yet disabled again. */ bool rx_irq_live; @@ -270,7 +274,7 @@ static struct apple_mbox_priv *apple_mbox_to_priv(struct apple_mbox *mbox) /* Only providers allocated by apple_mbox_probe() have a receive poller. */ static bool apple_mbox_has_rx_poller(const struct apple_mbox *mbox) { - return mbox->hw->is_ascwrap_v8; + return mbox->hw->is_ascwrap_v8 || mbox->hw->rx_poll_required; } /* Both ASCWrap generations share the consumer lifecycle API below. */ @@ -1038,12 +1042,17 @@ EXPORT_SYMBOL(apple_mbox_stop); void apple_mbox_hold_rx(struct apple_mbox *mbox) { + /* A polled provider claims no receive interrupt. */ + if (mbox->hw->rx_poll_required) + return; disable_irq(mbox->irq_recv_not_empty); } EXPORT_SYMBOL(apple_mbox_hold_rx); void apple_mbox_release_rx(struct apple_mbox *mbox) { + if (mbox->hw->rx_poll_required) + return; enable_irq(mbox->irq_recv_not_empty); } EXPORT_SYMBOL(apple_mbox_release_rx); @@ -1105,7 +1114,8 @@ static void apple_mbox_quiesce(void *data) if (mbox->irq_send_empty >= 0) synchronize_irq(mbox->irq_send_empty); complete_all(&mbox->tx_empty); - synchronize_irq(mbox->irq_recv_not_empty); + if (mbox->irq_recv_not_empty >= 0) + synchronize_irq(mbox->irq_recv_not_empty); spin_lock_irqsave(&mbox->rx_lock, flags); had_rx = mbox->rx; @@ -1369,6 +1379,16 @@ static int apple_mbox_probe(struct platform_device *pdev) return ret; } else { res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + /* + * A polled provider must be exactly its own 0x80-byte window of + * the J873 post-office bank; the rest belongs to other roles. + */ + if (mbox->hw->rx_poll_required && + (!of_machine_is_compatible("apple,j873g") || !res || + res->start != mbox->hw->j873_window || + resource_size(res) != APPLE_ASCWRAP_V8_MBOX_SIZE)) + return dev_err_probe(dev, -EINVAL, + "post-office window does not match the J873 profile\n"); if (!res || resource_size(res) < mbox->hw->reg_offset + mbox->hw->i2a_recv1 + sizeof(u64)) return dev_err_probe(dev, -EINVAL, @@ -1380,6 +1400,21 @@ static int apple_mbox_probe(struct platform_device *pdev) mbox->regs = (u8 __iomem *)mbox->regs + mbox->hw->reg_offset; } + if (mbox->hw->rx_poll_required) { + mbox->rx_util_min = -1; + mbox->rx_util_min_applied = -1; + spin_lock_init(&mbox->rx_lock); + spin_lock_init(&mbox->tx_lock); + mutex_init(&mbox->lifecycle_lock); + init_completion(&mbox->tx_empty); + priv->rx_poll_only = true; + INIT_DELAYED_WORK(&priv->rx_poll_work, apple_mbox_v8_rx_poll_work); + mbox->irq_recv_not_empty = -ENXIO; + mbox->irq_send_empty = -ENXIO; + dev_info(dev, "J873 post-office: paired transfers, bounded polling, no IRQ claim\n"); + goto setup_pm; + } + mbox->irq_recv_not_empty = platform_get_irq_byname(pdev, "recv-not-empty"); if (mbox->irq_recv_not_empty < 0) @@ -1431,6 +1466,7 @@ static int apple_mbox_probe(struct platform_device *pdev) return ret; } +setup_pm: ret = devm_pm_runtime_enable(dev); if (ret) return ret; @@ -1706,8 +1742,31 @@ static const struct apple_mbox_hw apple_mbox_t8152_smc_hw = { .has_irq_controls = false, }; +/* + * T8152 ANS: msgbox-mailbox-num 3 in the non-alias post-office bank, the + * same counted FIFO as the SMC mailbox. Its interrupt ordering is not known, + * so no interrupt is described and both directions are polled. + */ +static const struct apple_mbox_hw apple_mbox_t8152_ans_hw = { + .rx_poll_required = true, + .j873_window = 0x316010300ULL, + .counted_fifo = true, + .control_full = GENMASK(11, 8), /* free TX slots */ + .control_empty = GENMASK(3, 0), /* RX occupancy */ + .a2i_control = 0x20, + .a2i_send0 = 0x10, + .a2i_send1 = 0x18, + .i2a_control = 0x20, + .i2a_recv0 = 0x00, + .i2a_recv1 = 0x08, + .has_irq_controls = false, +}; + static const struct of_device_id apple_mbox_of_match[] = { { .compatible = "apple,t8152-smc-mailbox", .data = &apple_mbox_t8152_smc_hw }, + /* The AOP's ASC wrapper mailbox has the SMC mailbox's counted FIFOs. */ + { .compatible = "apple,t8152-ascwrap-v8-mailbox", .data = &apple_mbox_t8152_smc_hw }, + { .compatible = "apple,t8152-ans-mailbox", .data = &apple_mbox_t8152_ans_hw }, { .compatible = "apple,t6031-agx-asc-mailbox", .data = &apple_mbox_asc_hw }, { .compatible = "apple,t8122-agx-asc-mailbox", .data = &apple_mbox_asc_hw }, { .compatible = "apple,t8152-gfx-ascwrap-v8", .data = &apple_mbox_t8152_gfx_ascwrap_v8_hw }, diff --git a/drivers/soc/apple/sart.c b/drivers/soc/apple/sart.c index 6cedcb867c61b..c44b14c655be8 100644 --- a/drivers/soc/apple/sart.c +++ b/drivers/soc/apple/sart.c @@ -195,6 +195,43 @@ static void sart3_set_entry(struct apple_sart *sart, int index, u8 flags, writel(flags, sart->regs + APPLE_SART3_CONFIG(index)); } +#define APPLE_SART4_CONFIG(idx) (0x00 + 4 * (idx)) +#define APPLE_SART4_PADDR(idx) (0x60 + 4 * (idx)) +#define APPLE_SART4_PADDR_SHIFT 12 +#define APPLE_SART4_SIZE(idx) (0xc0 + 4 * (idx)) +#define APPLE_SART4_SIZE_SHIFT 12 +#define APPLE_SART4_SIZE_MAX GENMASK(29, 0) +#define APPLE_SART4_FLAGS_ALLOW 0xff + +/* T8152 "coastguard" SART (ADT sart-version 4), layout as m1n1 src/sart.c. */ +static void sart4_get_entry(struct apple_sart *sart, int index, u8 *flags, + phys_addr_t *paddr, size_t *size) +{ + phys_addr_t paddr_ = readl(sart->regs + APPLE_SART4_PADDR(index)); + size_t size_ = readl(sart->regs + APPLE_SART4_SIZE(index)); + + *flags = readl(sart->regs + APPLE_SART4_CONFIG(index)); + *size = size_ << APPLE_SART4_SIZE_SHIFT; + *paddr = paddr_ << APPLE_SART4_PADDR_SHIFT; +} + +static void sart4_set_entry(struct apple_sart *sart, int index, u8 flags, + phys_addr_t paddr_shifted, size_t size_shifted) +{ + writel(paddr_shifted, sart->regs + APPLE_SART4_PADDR(index)); + writel(size_shifted, sart->regs + APPLE_SART4_SIZE(index)); + writel(flags, sart->regs + APPLE_SART4_CONFIG(index)); +} + +static struct apple_sart_ops sart_ops_v4 = { + .get_entry = sart4_get_entry, + .set_entry = sart4_set_entry, + .flags_allow = APPLE_SART4_FLAGS_ALLOW, + .size_shift = APPLE_SART4_SIZE_SHIFT, + .paddr_shift = APPLE_SART4_PADDR_SHIFT, + .size_max = APPLE_SART4_SIZE_MAX, +}; + static struct apple_sart_ops sart_ops_v3 = { .get_entry = sart3_get_entry, .set_entry = sart3_set_entry, @@ -409,6 +446,10 @@ static void apple_sart_shutdown(struct platform_device *pdev) } static const struct of_device_id apple_sart_of_match[] = { + { + .compatible = "apple,t8152-sart", + .data = &sart_ops_v4, + }, { .compatible = "apple,t6000-sart", .data = &sart_ops_v3,