diff --git a/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml b/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml index 91ae5a3ce1bca..e2e75a8c29f13 100644 --- a/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml +++ b/Documentation/devicetree/bindings/arm/apple/apple,pmgr.yaml @@ -46,6 +46,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 d445faceda863..e472332dc97e7 100644 --- a/Documentation/devicetree/bindings/dma/apple,admac.yaml +++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml @@ -53,6 +53,7 @@ properties: - items: - const: apple,t6041-admac - const: apple,t8132-admac + - const: apple,t8152-admac - items: - const: apple,t6050-admac - const: apple,t8140-admac diff --git a/Documentation/devicetree/bindings/i2c/apple,i2c.yaml b/Documentation/devicetree/bindings/i2c/apple,i2c.yaml index f2e16482d9218..c3a306b0c8ea4 100644 --- a/Documentation/devicetree/bindings/i2c/apple,i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/apple,i2c.yaml @@ -31,6 +31,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 3f0a7adf403d8..a5acfb9f36753 100644 --- a/Documentation/devicetree/bindings/iommu/apple,dart.yaml +++ b/Documentation/devicetree/bindings/iommu/apple,dart.yaml @@ -282,6 +282,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 19ffe1bf167f7..a545bddf78d80 100644 --- a/Documentation/devicetree/bindings/iommu/apple,sart.yaml +++ b/Documentation/devicetree/bindings/iommu/apple,sart.yaml @@ -26,8 +26,8 @@ description: SART3, first seen in M1 Pro/Max, extends both the address space and filter entry size to 42 bit. - SART4, seen on M5 Ultra (T6050), keeps SART3's entries but moves the - address and size arrays, so it has no SART3 fallback. + SART4, seen on M5 Ultra (T6050) and M6 (T8152), keeps SART3's entries but + moves the address and size arrays, so it has no SART3 fallback. properties: compatible: @@ -49,6 +49,7 @@ properties: - apple,t6050-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 8afd38261fe30..9dc9c7d7f0b88 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 @@ -92,6 +98,11 @@ properties: - apple,t8142-aop-setup-mailbox - 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 @@ -155,7 +166,9 @@ allOf: properties: compatible: contains: - const: apple,secure-rtbuddy-proxy + enum: + - apple,secure-rtbuddy-proxy + - apple,t8152-ans-mailbox then: required: - interrupts @@ -164,7 +177,9 @@ allOf: properties: compatible: contains: - const: apple,t8152-smc-mailbox + enum: + - apple,t8152-ascwrap-v8-mailbox + - apple,t8152-smc-mailbox then: properties: interrupts: @@ -175,6 +190,16 @@ allOf: - const: send-empty - const: recv-not-empty + - if: + properties: + compatible: + contains: + const: apple,t8152-ans-mailbox + then: + properties: + interrupts: false + interrupt-names: false + - if: properties: compatible: @@ -223,6 +248,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: diff --git a/Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml b/Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml index 7f289a02d4b21..22e7bf14e9529 100644 --- a/Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml +++ b/Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml @@ -23,6 +23,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 @@ -111,6 +112,20 @@ properties: buffers must remain reserved and protected by the SART. allOf: + - if: + properties: + compatible: + not: + contains: + enum: + - apple,t6050-nvme-ans2 + - apple,t8152-nvme-ans2 + then: + required: + - resets + - power-domains + - power-domain-names + - if: properties: compatible: @@ -183,11 +198,6 @@ allOf: resets: false power-domains: false power-domain-names: false - else: - required: - - resets - - power-domains - - power-domain-names required: - compatible 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/phy/apple,t8152-aciophy-usb3.yaml b/Documentation/devicetree/bindings/phy/apple,t8152-aciophy-usb3.yaml new file mode 100644 index 0000000000000..6e0625ec57cae --- /dev/null +++ b/Documentation/devicetree/bindings/phy/apple,t8152-aciophy-usb3.yaml @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/apple,t8152-aciophy-usb3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple T8152 ACIOPHY in USB3 mode + +maintainers: + - Thomas Glanzmann + +description: + The Type-C PHY (ACIOPHY) of the Apple T8152 (M6) SoC, used as the USB3 PHY + of a port that is wired to a fixed USB3 device instead of a Type-C + connector, such as the on-board hub behind the Mac mini (2026) front ports. + The PHY also switches the PIPE handler of its DWC3 controller between the + controller's dummy PHY and the ACIOPHY. + +$defs: + apple,tunable: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + minItems: 1 + maxItems: 512 + items: + items: + - description: Register offset into the ATC PHY block + - description: Mask to be applied to the register value + - description: Bits to be set after applying the mask + description: + List of (register offset, mask, value) tuples from the PHY's node in + Apple's device tree. These values can differ between devices of the + same model and likely contain calibration values. + +properties: + compatible: + const: apple,t8152-aciophy-usb3 + + reg: + items: + - description: ATC PHY block + - description: PIPE handler of the DWC3 controller + - description: PMGR power states of the ATC's DP_0, DP_1 and USB_AON + - description: PMGR2 PSD service block of the ATC's common domain + + reg-names: + items: + - const: atc + - const: pipehandler + - const: atc-ps + - const: atc-psd + + "#phy-cells": + const: 0 + + apple,tunable-pre: + $ref: "#/$defs/apple,tunable" + description: + Register settings applied after the PHY power-up, before the lane + crossbar is set up. + + apple,tunable-post: + $ref: "#/$defs/apple,tunable" + description: + Register settings applied after the lane crossbar is set up, including + those of the USB3 lane. + +required: + - compatible + - reg + - reg-names + - "#phy-cells" + - apple,tunable-pre + - apple,tunable-post + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + phy@383000000 { + compatible = "apple,t8152-aciophy-usb3"; + reg = <0x3 0x83000000 0x0 0x84000>, + <0x3 0x82414000 0x0 0x4000>, + <0x3 0x08290080 0x0 0x104>, + <0x3 0x03a13900 0x0 0xc0>; + reg-names = "atc", "pipehandler", "atc-ps", "atc-psd"; + #phy-cells = <0>; + apple,tunable-pre = <0x00800 0x00fc0000 0x00fc0000>; + apple,tunable-post = <0x6c12c 0x0000801f 0x00000004>; + }; + }; diff --git a/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml b/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml index 420f47e4522bc..efdd71a9c6521 100644 --- a/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml +++ b/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml @@ -84,6 +84,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/sound/apple,t8152-aop-audio.yaml b/Documentation/devicetree/bindings/sound/apple,t8152-aop-audio.yaml index 9c14c3fff2e41..b23e734de9206 100644 --- a/Documentation/devicetree/bindings/sound/apple,t8152-aop-audio.yaml +++ b/Documentation/devicetree/bindings/sound/apple,t8152-aop-audio.yaml @@ -26,6 +26,7 @@ properties: - const: apple,t8142-aop-audio - const: apple,t8152-aop-audio - const: apple,t6050-aop-audio + - const: apple,t8152-aop-audio dmas: minItems: 4 diff --git a/Documentation/devicetree/bindings/spmi/apple,spmi.yaml b/Documentation/devicetree/bindings/spmi/apple,spmi.yaml index 48706095da208..14d037a00aedd 100644 --- a/Documentation/devicetree/bindings/spmi/apple,spmi.yaml +++ b/Documentation/devicetree/bindings/spmi/apple,spmi.yaml @@ -41,6 +41,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/usb/apple,dwc3.yaml b/Documentation/devicetree/bindings/usb/apple,dwc3.yaml index 6612a5370ee36..6bc0c202dceec 100644 --- a/Documentation/devicetree/bindings/usb/apple,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/apple,dwc3.yaml @@ -13,6 +13,12 @@ description: Apple Silicon SoCs use a Synopsys DesignWare DWC3 based controller for each of their Type-C ports. + On T8152 the bootloader can hand a controller over already running, powered + and with the USB2 side of its ATC PHY set up for host mode. Such a controller + is described by its DWC3 core region, as a host. Its PHY reset and power + domain, and on a Type-C port its USB role switch, exist but are left to the + bootloader, so they are optional. + allOf: - $ref: snps,dwc3-common.yaml# - if: @@ -20,11 +26,37 @@ allOf: compatible: not: contains: - const: apple,t8132-dwc3 + enum: + - apple,t8132-dwc3 + - apple,t8152-dwc3 then: required: - power-domains - if: + properties: + compatible: + contains: + const: apple,t8152-dwc3 + then: + properties: + dr_mode: + const: host + required: + - dr_mode + else: + properties: + reg: + minItems: 2 + reg-names: + minItems: 2 + required: + - reg-names + - if: + properties: + compatible: + not: + contains: + const: apple,t8152-dwc3 not: properties: status: @@ -85,9 +117,10 @@ properties: - const: apple,t8103-dwc3 - const: apple,t8103-dwc3 - const: apple,t8132-dwc3 + - const: apple,t8152-dwc3 reg: - minItems: 2 + minItems: 1 items: - description: Core DWC3 region - description: Apple-specific DWC3 region @@ -96,7 +129,7 @@ properties: - description: AUSBC debug block (T6050) reg-names: - minItems: 2 + minItems: 1 items: - const: dwc3-core - const: dwc3-apple @@ -160,7 +193,6 @@ properties: required: - compatible - reg - - reg-names - interrupts - iommus @@ -183,3 +215,18 @@ examples: usb-role-switch; }; + + - | + #include + #include + + usb@82430000 { + compatible = "apple,t8152-dwc3"; + reg = <0x82430000 0xcd00>; + interrupts = ; + iommus = <&dwc3_2_dart_0 0>, <&dwc3_2_dart_1 1>; + dr_mode = "host"; + maximum-speed = "high-speed"; + snps,dis_u2_susphy_quirk; + snps,dis_u3_susphy_quirk; + }; diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml index e321ee28733d1..9a6634e146d75 100644 --- a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml @@ -26,6 +26,7 @@ properties: - apple,t8132-wdt - apple,t8140-wdt - apple,t8142-wdt + - apple,t8152-wdt - const: apple,t8103-wdt - items: - enum: diff --git a/MAINTAINERS b/MAINTAINERS index 75080a2b87f5c..41c0fac593d69 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2748,6 +2748,7 @@ F: Documentation/devicetree/bindings/nvmem/apple,spmi-nvmem.yaml F: Documentation/devicetree/bindings/opp/operating-points-v2-apple-dram.yaml F: Documentation/devicetree/bindings/pci/apple,pcie.yaml F: Documentation/devicetree/bindings/phy/apple,atcphy.yaml +F: Documentation/devicetree/bindings/phy/apple,t8152-aciophy-usb3.yaml F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml F: Documentation/devicetree/bindings/power/apple* F: Documentation/devicetree/bindings/power/reset/apple,smc-reboot.yaml 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-j873-usb.dtsi b/arch/arm64/boot/dts/apple/t8152-j873-usb.dtsi new file mode 100644 index 0000000000000..9a8d546fe1a7b --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8152-j873-usb.dtsi @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * J873g USB host bring-up: usb-drd1 (back-left port, USB2) and usb-drd2 + * (front ports via the on-board hub, USB2 and USB3). + * The loader powers the controllers and sets up the USB2 side of their ATC + * PHYs for host mode before Linux starts (there is no T8152 USB power-domain, + * USB2 PHY or Type-C support yet). + * The controllers are described by their DWC3 core region, as hosts behind + * their two DARTs (apple,t8152-dwc3); their PHY reset and power domain, and on + * the Type-C port the role switch, exist but are left to the loader. + * usb-drd2's hub is wired to ATC2's PHY without a Type-C mux, so Linux brings + * that PHY up in USB3 mode (atc2_phy). + * Resources are from the 26A434 ADT: dart-usb1/2, usb-drd1/2, atc-phy2. + * + * dart-usb1 and dart-usb2 each have two DART instances (ADT reg[0] and + * reg[1], 0xc000 each, sharing one interrupt). t8152-peripherals.dtsi lists + * both windows on one node (dwc3_1_dart, dwc3_2_dart), but the DART driver + * drives one instance per node and the binding reads a second reg entry as + * DAPF or auxiliary registers. Keep instance 0 on the shared node, with its + * own window only, and describe instance 1 as a node of its own. + */ + +&dwc3_1_dart { + reg = <0x4 0x0b020000 0x0 0xc000>; + status = "okay"; +}; + +&dwc3_2_dart { + reg = <0x3 0x83020000 0x0 0xc000>; + status = "okay"; +}; + +/ { + soc { + dwc3_1_dart_1: iommu@40b040000 { + compatible = "apple,t8152-dart", "apple,t8110-dart"; + reg = <0x4 0x0b040000 0x0 0xc000>; + interrupts = ; + #iommu-cells = <1>; + }; + + usb1: usb@40a430000 { + compatible = "apple,t8152-dwc3"; + reg = <0x4 0x0a430000 0x0 0xcd00>; + interrupts = ; + dr_mode = "host"; + maximum-speed = "high-speed"; + iommus = <&dwc3_1_dart 0>, <&dwc3_1_dart_1 1>; + snps,dis_u2_susphy_quirk; + snps,dis_u3_susphy_quirk; + }; + + dwc3_2_dart_1: iommu@383040000 { + compatible = "apple,t8152-dart", "apple,t8110-dart"; + reg = <0x3 0x83040000 0x0 0xc000>; + interrupts = ; + #iommu-cells = <1>; + }; + + /* + * ADT atc-phy2 in USB3 mode for usb-drd2: the hub is wired to the + * PHY directly. PS: the ATC's DP_0, DP_1 and USB_AON power states + * (+0, +0x20, +0x100), PSD: its common domain (clock-gates 57). + * The tunables are the atc-phy2 tunable_* groups of the 26A434 ADT + * that macOS applies for USB3 on lane 0, in its order. + */ + atc2_phy: phy@383000000 { + compatible = "apple,t8152-aciophy-usb3"; + reg = <0x3 0x83000000 0x0 0x84000>, + <0x3 0x82414000 0x0 0x4000>, + <0x3 0x08290080 0x0 0x104>, + <0x3 0x03a13900 0x0 0xc0>; + reg-names = "atc", "pipehandler", "atc-ps", "atc-psd"; + #phy-cells = <0>; + apple,tunable-pre = + /* ACIOPHY_CMN_DFLT */ + <0x00800 0x00fc0000 0x00fc0000>, + <0x0084c 0x000ff800 0x000ff800>, + <0x0085c 0x000000ff 0x00000080>, + <0x00860 0x007fffff 0x0052bc27>, + <0x00864 0x02c00000 0x00800000>, + /* CIOPLL_CORE_DFLT */ + <0x01614 0x0003ffc0 0x0001e5c0>, + <0x01640 0x00000007 0x00000003>, + <0x01668 0x00000ffc 0x000005f0>; + apple,tunable-post = + /* ATC_FABRIC */ + <0x6c004 0x003f003f 0x00200020>, + <0x6c00c 0x000000f1 0x000000a1>, + <0x6c010 0x0000801f 0x00000004>, + <0x6c018 0x003f003f 0x00200020>, + <0x6c020 0x000000f1 0x000000a1>, + <0x6c024 0x0000801f 0x00000004>, + <0x6c02c 0x007f007f 0x00410041>, + <0x6c034 0x000000f1 0x00000071>, + <0x6c038 0x0000801f 0x00000004>, + <0x6c040 0x0000001f 0x00000010>, + <0x6c048 0x0000801f 0x00000004>, + <0x6c050 0x007f007f 0x00450045>, + <0x6c058 0x000000f1 0x00000051>, + <0x6c05c 0x0000801f 0x00000004>, + <0x6c064 0x0000003f 0x00000020>, + <0x6c06c 0x0000801f 0x00000004>, + <0x6c074 0x00000001 0x00000001>, + <0x6c078 0x0000801f 0x00000004>, + <0x6c080 0x001f001f 0x00100010>, + <0x6c084 0x000000f1 0x00000011>, + <0x6c088 0x00000001 0x00000001>, + <0x6c08c 0x00000001 0x00000001>, + <0x6c090 0x0000801f 0x00000004>, + <0x6c098 0x001f001f 0x00100010>, + <0x6c09c 0x000000f1 0x00000011>, + <0x6c0a0 0x0000801f 0x00000004>, + <0x6c0a8 0x000000ff 0x000000a0>, + <0x6c0ac 0x0000801f 0x00000004>, + <0x6c0b4 0x0000003f 0x00000020>, + <0x6c0bc 0x0000801f 0x00000004>, + <0x6c0c4 0x0000003f 0x00000020>, + <0x6c0cc 0x0000801f 0x00000004>, + <0x6c0d4 0x0000000f 0x00000008>, + <0x6c0d8 0x0000801f 0x00000004>, + <0x6c0e0 0x001f001f 0x00180018>, + <0x6c0e4 0x0000801f 0x00000004>, + <0x6c0ec 0x001f001f 0x00180018>, + <0x6c0f0 0x0000801f 0x00000004>, + <0x6c0f8 0x001f001f 0x00180018>, + <0x6c0fc 0x0000801f 0x00000004>, + <0x6c104 0x001f001f 0x00180018>, + <0x6c108 0x0000801f 0x00000004>, + <0x6c110 0x00000001 0x00000001>, + <0x6c114 0x0000801f 0x00000004>, + <0x6c11c 0x0000801f 0x00000004>, + <0x6c124 0x0000801f 0x00000004>, + <0x6c12c 0x0000801f 0x00000004>, + <0x6c134 0x0000801f 0x00000004>, + <0x6c13c 0xffffffff 0x01010101>, + <0x6c140 0x0000801f 0x00000004>, + <0x6c148 0x0000801f 0x00000004>, + <0x6c150 0xffffffff 0x01010101>, + <0x6c154 0x0000ffff 0x00000101>, + <0x6c158 0x0000801f 0x00000004>, + <0x6c160 0x0000801f 0x00000004>, + <0x6c168 0x0000801f 0x00000004>, + <0x6c170 0x0000801f 0x00000004>, + <0x6c178 0x0000801f 0x00000004>, + <0x6c180 0xffffffff 0x01010101>, + <0x6c184 0x0000801f 0x00000004>, + <0x6c18c 0x0000801f 0x00000004>, + <0x6c194 0x0000801f 0x00000004>, + /* DPPLL_CORE_DFLT */ + <0x01040 0x0000000c 0x00000008>, + <0x01060 0x0001c000 0x0000c000>, + <0x01098 0x00000f00 0x00000800>, + <0x0109c 0x000fe000 0x000fe000>, + <0x01108 0x07c00000 0x04000000>, + <0x0110c 0x0000007c 0x00000010>, + /* DPPLL_TOP_DFLT */ + <0x00e8c 0x0000007f 0x0000003c>, + <0x00e9c 0x0000007f 0x00000032>, + <0x00eac 0x0000007f 0x00000032>, + <0x00ebc 0x0000007f 0x0000005a>, + /* CIOPLL_TOP_DFLT */ + <0x01488 0x000001ff 0x00000128>, + <0x01494 0x00000100 0x00000100>, + /* ACIOPHY_USBC0_DFLT */ + <0x15c04 0x0f000000 0x00000000>, + <0x15c0c 0x0007c000 0x00020000>, + /* ACIOPHY_USBC0_USB */ + <0x15c50 0x60000000 0x00000000>, + /* LN0_ARBITER_REGS_DFLT */ + <0x082d8 0xf0000000 0x70000000>, + <0x082dc 0x0000000f 0x00000007>, + /* LN0_RX_TOP_REGS_DFLT */ + <0x08cf4 0x00000020 0x00000020>, + /* LN0_RX_DFE_REGS_DFLT */ + <0x077c4 0x0003ff00 0x0000fa00>, + /* LN0_SMGR_REGS_DFLT */ + <0x07dbc 0x00000078 0x00000030>, + <0x07dd8 0x000003f0 0x00000000>, + <0x07de8 0x00000003 0x00000003>, + <0x07dec 0x00000002 0x00000002>, + /* LN0_RXAEQ_TOP_REGS_DFLT */ + <0x07a00 0x000000f0 0x00000010>, + <0x07a08 0x00000fff 0x00000001>, + <0x07a28 0x0ff00000 0x0cf00000>, + <0x07a40 0x07ffffff 0x028154a5>, + <0x07a7c 0x20000000 0x00000000>, + <0x07a80 0x0000001f 0x00000002>, + <0x07b98 0x3f00003f 0x31000014>, + <0x07b9c 0x0003ffff 0x0000ef4b>, + <0x07ba8 0x0fc1f800 0x05005000>, + <0x07bac 0x07ffffe0 0x013f0e40>, + <0x07bbc 0x000001c7 0x00000145>, + <0x07bc8 0x000007f8 0x00000018>, + /* LN0_RX_SHM_REGS_DFLT */ + <0x08728 0x0000010f 0x0000010f>, + <0x0878c 0xfc000000 0xfc000000>, + <0x08790 0x00000001 0x00000001>, + <0x087b4 0x0e018000 0x06008000>, + <0x08708 0x40000000 0x40000000>, + /* LN0_TXSEQ_REGS_DFLT */ + <0x04c80 0x3f800000 0x00000000>, + <0x04c88 0x001fffff 0x00000000>, + /* LN0_TX_SHM_AHB_DFLT */ + <0x04fd4 0x03800000 0x02800000>, + /* LN0_TX_TXSPL_CM_DFLT */ + <0x04e20 0x00fff000 0x00723000>, + /* LN0_ASDC_TXSPL_CM_DFLT */ + <0x08980 0x00fff000 0x00723000>, + /* LN0_DIV40_REGS_DFLT */ + <0x085e4 0x00000004 0x00000000>, + /* LN0_RX_PCTRL_REGS_DFLT */ + <0x08628 0x00000ff0 0x00000660>, + <0x0862c 0x00000ff0 0x00000ea0>, + /* LN0_CTLE_EQ_REGS_DFLT */ + <0x08000 0x0000000a 0x00000000>, + <0x08014 0x000003ff 0x00000042>, + /* L0_RXCALACC_HALFUI_DFLT */ + <0x07304 0x0000000f 0x00000006>, + <0x07334 0x01ffffff 0x001004ea>, + /* L0_RXCALACC_EDSKEW_DFLT */ + <0x07284 0x0000000f 0x00000006>, + <0x072cc 0x0003ffff 0x000004ea>, + /* LN0_TXSPL_TXDCC_DFLT */ + <0x04d84 0x001c0000 0x00000000>, + /* LN0_SMGR_REGS_USB */ + <0x07d88 0x000000f0 0x00000030>, + <0x07da8 0xff000000 0x44000000>, + <0x07dd8 0x00003000 0x00003000>, + /* LN0_DETECTOR_REGS_USB */ + <0x0848c 0x00008000 0x00000000>, + /* LN0_DIV40_REGS_USB */ + <0x08594 0x00000001 0x00000001>, + <0x085b0 0x0000ffff 0x00001010>, + <0x085b8 0x0000ffff 0x00001010>, + <0x085cc 0x68100000 0x00000000>, + <0x085d0 0x68100000 0x00000000>, + /* LN0_CTLE_EQ_REGS_USB */ + <0x07fdc 0x000001ff 0x000000b4>, + <0x07fe0 0x000001ff 0x000000aa>, + /* LN0_RXAEQ_TOP_REGS_USB */ + <0x07a1c 0x00000ff8 0x00000578>, + <0x07a2c 0x0003ffff 0x000154b4>, + <0x07bb8 0x00007000 0x00000000>, + /* LN0_TXSEQ_REGS_USB */ + <0x04ca0 0x00000002 0x00000000>; + }; + + /* usb-drd2: on-board VL822 hub behind the two front USB-C ports. */ + usb2: usb@382430000 { + compatible = "apple,t8152-dwc3"; + reg = <0x3 0x82430000 0x0 0xcd00>; + interrupts = ; + dr_mode = "host"; + phys = <&atc2_phy>; + phy-names = "usb3-phy"; + iommus = <&dwc3_2_dart 0>, <&dwc3_2_dart_1 1>; + snps,dis_u2_susphy_quirk; + snps,dis_u3_susphy_quirk; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8152-j873g.dts b/arch/arm64/boot/dts/apple/t8152-j873g.dts index 00fe5207a1956..0f98b07748b01 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"; }; }; @@ -295,12 +372,6 @@ <0x4 0x3040000 0x0 0xc000>; }; -/* Retain the register view published by this board's live hardware capture. */ -&dwc3_1_dart { - reg = <0x4 0xb020000 0x0 0xc000>, - <0x4 0xb040000 0x0 0xc000>; -}; - /* Retain the register view published by this board's live hardware capture. */ &dwc3_3_dart { reg = <0x4 0x13020000 0x0 0xc000>, @@ -423,10 +494,11 @@ <0x3 0xa0000000 0x0 0x8000>; }; -/* Unexposed chassis port instances remain described and disabled. */ - -/* Retain the register view published by this board's live hardware capture. */ -&dwc3_2_dart { - reg = <0x3 0x83020000 0x0 0xc000>, - <0x3 0x83040000 0x0 0xc000>; -}; +/* + * The J873g fragments enable and refine nodes of t8152-peripherals.dtsi + * (the USB, apcie port 2 and dart-sbr DARTs), so they come after it. + */ +#include "t8152-j873-nvme.dtsi" +#include "t8152-j873-usb.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 e330bb9300975..cc57d9c76847e 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -78,13 +78,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) @@ -112,6 +128,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) @@ -163,6 +184,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; @@ -214,6 +237,7 @@ struct admac_data { bool evolved_layout; bool split_channels; bool display; + bool t8152_layout; bool ctl_programmed; /* Display ADMAC: its control block's two windows and their tunables */ void __iomem *control[2]; @@ -247,6 +271,7 @@ struct admac_hw { bool evolved_layout; bool split_channels; bool display; + bool t8152_layout; }; static int admac_alloc_sram_carveout(struct admac_data *ad, @@ -255,6 +280,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. */ @@ -262,6 +289,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; @@ -270,14 +304,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; @@ -294,18 +328,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); } @@ -409,6 +449,15 @@ static void admac_write_hw_desc(struct admac_data *ad, int channo, adchan->seq = adchan->seq == 0xff ? 1 : adchan->seq + 1; flags = DISPLAY_FLAG_DESC_REPORT | adchan->seq; + } else 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; + flags = FLAG_DESC_NOTIFY | adchan->desc_id; } dev_dbg(ad->dev, "ch%d descriptor: addr=0x%pad len=0x%zx flags=0x%x\n", @@ -671,6 +720,11 @@ static void admac_start_chan(struct admac_chan *adchan) 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: @@ -1445,7 +1499,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: @@ -1467,6 +1522,15 @@ static int admac_device_config(struct dma_chan *chan, adchan->realign_bytes = admac_config_realign_bytes(config); + /* + * Optional: a u32 frame size in bytes, which a paused capture is + * restarted aligned to on resume (see admac_cyclic_realign()). + */ + if (config->peripheral_config && config->peripheral_size == sizeof(u32)) + adchan->realign_bytes = *(u32 *)config->peripheral_config; + else + adchan->realign_bytes = 0; + /* * By FIFOCTL_LIMIT we seem to set the maximal number of bytes allowed to be * held in controller's per-channel FIFO. Transfers seem to be triggered @@ -1588,6 +1652,7 @@ static int admac_probe(struct platform_device *pdev) ad->evolved_layout = hw->evolved_layout; ad->split_channels = hw->split_channels; ad->display = hw->display; + ad->t8152_layout = hw->t8152_layout; mutex_init(&ad->cache_alloc_lock); if (ad->display) { @@ -1751,8 +1816,13 @@ static const struct admac_hw admac_t6050_display_hw = { .display = true, }; +static const struct admac_hw admac_t8152_hw = { + .t8152_layout = true, +}; + static const struct of_device_id admac_of_match[] = { { .compatible = "apple,t6050-display-admac", .data = &admac_t6050_display_hw }, + { .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 fb2a96284262f..b5df6afaafb8e 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -4507,6 +4507,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 7c525b6c7b2e1..99940afa2cc65 100644 --- a/drivers/mfd/macsmc.c +++ b/drivers/mfd/macsmc.c @@ -111,9 +111,15 @@ static int apple_smc_add_described_devices(struct apple_smc *smc, const struct m return 0; } -/* 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) @@ -615,7 +621,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 f0892f4986b94..41ce8b6ef7274 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -72,6 +72,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 @@ -225,6 +234,9 @@ struct apple_nvme_hw { u32 sleep_shn; /* The ANS is never reset through PMGR here, so no reset is named. */ bool reset_optional; + bool secure_reg_layout; + /* Also send the NVMe shutdown notification (CC.SHN) on removal. */ + bool shutdown_notify; u32 max_queue_depth; unsigned long quirks; }; @@ -407,6 +419,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) @@ -1383,10 +1406,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); @@ -1922,10 +1948,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, @@ -1948,9 +1974,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; @@ -1964,11 +1992,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 */ @@ -2035,10 +2063,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) { @@ -3189,6 +3217,22 @@ static const struct apple_nvme_hw apple_nvme_t6050_hw = { .quirks = NVME_QUIRK_NO_APST | NVME_QUIRK_BROKEN_FUA, }; +/* + * 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, + .reset_optional = 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,t6050-nvme-ans2", .data = &apple_nvme_t6050_hw }, @@ -3197,6 +3241,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 dec95de353ca9..6419c05577818 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -267,6 +267,12 @@ struct hw_info { bool pipe_rst; bool no_port_reset; bool mps_timers; + /* + * 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 = { @@ -322,6 +328,7 @@ static const struct hw_info t8152_hw = { .max_rid2sid = 512, .refbuf_off = true, .pipe_rst = true, + .no_inc_mrrs = true, }; /* @@ -4859,6 +4866,7 @@ static int apple_pcie_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to attach power domains\n"); + 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/phy/apple/Kconfig b/drivers/phy/apple/Kconfig index 381c830e63978..27e88ea8da0f1 100644 --- a/drivers/phy/apple/Kconfig +++ b/drivers/phy/apple/Kconfig @@ -86,3 +86,15 @@ config PHY_APPLE_T6050_DP Fixed HDMI bridges and Type-C USB host/DisplayPort alternate mode. One owner coordinates the shared PHY, firmware, PIPE and USB2 state. Requires named register banks, power domains and firmware tunables. + +config PHY_APPLE_ACIOPHY_USB3 + tristate "Apple T8152 ACIOPHY USB3 PHY" + depends on ARCH_APPLE || COMPILE_TEST + select GENERIC_PHY + select APPLE_TUNABLE + help + Enable this for USB3 on an Apple T8152 (M6) Type-C PHY that is wired + to a fixed USB3 device instead of a Type-C port, such as the + on-board hub behind the Mac mini (2026) front ports. + + If M is selected the module will be called 'phy-apple-aciophy-usb3'. diff --git a/drivers/phy/apple/Makefile b/drivers/phy/apple/Makefile index e0b94bb1dcaa5..5e541d70691fb 100644 --- a/drivers/phy/apple/Makefile +++ b/drivers/phy/apple/Makefile @@ -10,3 +10,6 @@ obj-$(CONFIG_PHY_APPLE_DPTX) += phy-apple-dptx.o phy-apple-dptx-y += dptx.o obj-$(CONFIG_PHY_APPLE_T6050_DP) += atc-t6050-dp.o + +obj-$(CONFIG_PHY_APPLE_ACIOPHY_USB3) += phy-apple-aciophy-usb3.o +phy-apple-aciophy-usb3-y := aciophy-usb3.o diff --git a/drivers/phy/apple/aciophy-usb3.c b/drivers/phy/apple/aciophy-usb3.c new file mode 100644 index 0000000000000..55dd1bbefeef4 --- /dev/null +++ b/drivers/phy/apple/aciophy-usb3.c @@ -0,0 +1,462 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * T8152 ACIOPHY in USB3 mode, for an ATC port wired to a fixed USB3 device: + * the J873g front ports' on-board hub, with no Type-C mux in between. + * + * Reverse engineered from macOS 26A434: AppleT8152TypeCPhy::initACIO (mode 1: + * powerup_rst, efuse_load, xbar_config, apply_tunables, deassert reset) and + * aciophy_pipe_bist_override, AppleT8152USBXHCI::setUSB3Mode for the PIPE + * handler between the DWC3 and the PHY. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACIOPHY_TIMEOUT_US 10000 + +/* ATCPHY_CFG_BLK */ +#define CFG 0x60000 +#define CFG_PWRDN_CTRL0 (CFG + 0x00) +#define CTRL0_SLEEP_SML BIT(0) +#define CTRL0_SLEEP_BIG BIT(1) +#define CTRL0_CLAMP_EN BIT(2) +#define CTRL0_AHB_RESET_N BIT(3) +#define CTRL0_RESET_N BIT(4) +#define CFG_PWRDN_CTRL1 (CFG + 0x04) +#define CFG_SPARE0 (CFG + 0x08) +#define SPARE0_LN_SWAP BIT(1) +#define CFG_S2R_AON_SYNC_RST_N (CFG + 0x30) + +/* ACIOPHY_TOP_AON_BLK */ +#define AON_CFG_LANE0 0x1e18 +#define LANE_CLAMP_EN BIT(0) +#define LANE_SLEEP_SML BIT(1) +#define LANE_SLEEP_BIG BIT(2) +#define LANE_AHB_RESET_N BIT(5) +#define AON_CORE2MC_SLP_CTRL_2 0x1e24 +#define RXA_LFPS_SML_LN0 BIT(12) +#define RXA_LFPS_BIG_LN0 BIT(16) + +/* ACIOPHY_TOP_BLK_CFG0_XBAR */ +#define XBAR 0x4c +#define XBAR_MODE GENMASK(16, 0) +#define XBAR_MODE_USB3 0x110 + +/* ACIOPHY_BIST_BLK */ +#define BIST 0x2400 +#define BIST_CFG0 (BIST + 0x00) +#define BIST_CLOCK_EN BIT(0) +#define BIST_USB_REGSYNC BIT(6) +#define BIST_CFG2 (BIST + 0x0c) +#define BIST_PHY_STATUS_RE BIT(0) +#define BIST_STATUS1 (BIST + 0xa0) +#define STATUS1_PHY_STATUS BIT(6) +#define STATUS1_PHY_STATUS_2 BIT(7) +#define BIST_OV1 (BIST + 0xb0) +#define OV1_PIPE_RESET_N_VAL BIT(0) +#define OV1_PWR_DOWN_VAL GENMASK(8, 5) +#define BIST_OV2 (BIST + 0xb8) +#define OV2_PIPE_RESET_N BIT(5) +#define OV2_PWR_DOWN BIT(9) +#define OV2_MASK 0x660 + +/* AUSBC_PIPE_HANDLER_BLK */ +#define PIPE_OVERRIDE 0x00 +#define OVERRIDE_RXVALID BIT(0) +#define OVERRIDE_RXDETECT BIT(2) +#define PIPE_OVERRIDE_VALUES 0x04 +#define OVERRIDE_VALUES_RXDETECT GENMASK(3, 1) +#define PIPE_MUX 0x0c +#define MUX_MODE GENMASK(1, 0) +#define MUX_MODE_USB3 0 +#define MUX_MODE_DUMMY 2 +#define MUX_CLK GENMASK(6, 4) +#define MUX_CLK_OFF 0 +#define MUX_CLK_USB3 1 +#define MUX_CLK_DUMMY 4 +#define PIPE_LOCK_REQ 0x10 +#define PIPE_LOCK_ACK 0x14 +#define PIPE_AON_GEN 0x1c +#define AON_GEN_DWC3_RESET_N BIT(0) +#define PIPE_NONSELECTED 0x20 +#define NONSELECTED_POWER_DOWN GENMASK(3, 0) +#define NONSELECTED_NATIVE_RESET BIT(12) + +/* The ATC's PMGR dependencies: USB_AON, the common PSD, DP_0 and DP_1. */ +#define PSD_STATE 0x80 +#define PSD_TARGET 0x90 +static const u32 ps_offset[] = { 0x100, 0, 0x0, 0x20 }; +static const u32 ps_idle[] = { 0x300, 6, 0x244, 0x244 }; + +struct aciophy { + struct device *dev; + void __iomem *base; + void __iomem *pipe; + void __iomem *ps; + void __iomem *psd; + struct apple_tunable *tunable_pre; + struct apple_tunable *tunable_post; + /* the dependencies this driver powered up */ + u8 owned; +}; + +static void aciophy_update(void __iomem *reg, u32 mask, u32 value) +{ + writel((readl(reg) & ~mask) | value, reg); +} + +static int aciophy_gate(struct aciophy *phy, unsigned int i, bool on) +{ + u32 value = on ? (ps_idle[i] & 0xfffffcf0) | 15 : ps_idle[i]; + u32 reg; + + if (on && (i == 1 ? !(readl(phy->psd + PSD_STATE) & 7) : + (readl(phy->ps + ps_offset[i]) & 0xf0) == 0xf0)) + return 0; + if (on) + phy->owned |= BIT(i); + else + phy->owned &= ~BIT(i); + if (i == 1) { + writel(on ? 0 : ps_idle[i], phy->psd + PSD_TARGET); + return readl_poll_timeout(phy->psd + PSD_STATE, reg, + (reg & 7) == (on ? 0 : ps_idle[i]), 1, + ACIOPHY_TIMEOUT_US); + } + writel(value, phy->ps + ps_offset[i]); + return readl_poll_timeout(phy->ps + ps_offset[i], reg, + (reg & 0xf0) == ((value & 15) << 4), 1, + ACIOPHY_TIMEOUT_US); +} + +static void aciophy_gates_off(struct aciophy *phy) +{ + for (int i = ARRAY_SIZE(ps_idle) - 1; i >= 0; i--) + if ((phy->owned & BIT(i)) && aciophy_gate(phy, i, false)) + dev_warn(phy->dev, "power state %d stuck on\n", i); +} + +/* + * aciophy_lane_pwrup_seq_sub for lane 0. macOS runs it for the USB3+DP mode + * only; in USB3 mode the lane registers otherwise stay in reset and drop the + * lane tunables. + */ +static void aciophy_lane_up(struct aciophy *phy) +{ + void __iomem *lane = phy->base + AON_CFG_LANE0; + + aciophy_update(phy->base + AON_CORE2MC_SLP_CTRL_2, 0, RXA_LFPS_SML_LN0); + udelay(1); + aciophy_update(phy->base + AON_CORE2MC_SLP_CTRL_2, 0, RXA_LFPS_BIG_LN0); + udelay(1); + aciophy_update(lane, 0, LANE_SLEEP_SML); + udelay(1); + aciophy_update(lane, 0, LANE_SLEEP_BIG); + udelay(1); + aciophy_update(lane, LANE_CLAMP_EN, 0); + udelay(1); + aciophy_update(lane, 0, LANE_AHB_RESET_N); + udelay(1); +} + +/* aciophy_mc_pwrdn_seq_sub for lane 0 */ +static void aciophy_lane_down(struct aciophy *phy) +{ + void __iomem *lane = phy->base + AON_CFG_LANE0; + + aciophy_update(lane, LANE_AHB_RESET_N, 0); + udelay(1); + aciophy_update(lane, 0, LANE_CLAMP_EN); + udelay(1); + aciophy_update(lane, LANE_SLEEP_BIG, 0); + udelay(1); + aciophy_update(lane, LANE_SLEEP_SML, 0); + udelay(1); +} + +/* aciophy_phy_powerup_rst, efuse_load, partB and deassert reset, mode 1. */ +static int aciophy_phy_up(struct aciophy *phy) +{ + void __iomem *cfg = phy->base + CFG_PWRDN_CTRL0; + u32 reg; + + if (readl(cfg) != CTRL0_CLAMP_EN) + return -EBUSY; + aciophy_update(phy->base + CFG_S2R_AON_SYNC_RST_N, 0, BIT(0)); + udelay(1); + aciophy_update(cfg, 0, CTRL0_SLEEP_SML); + if (readl_poll_timeout(phy->base + CFG_PWRDN_CTRL1, reg, reg & CTRL0_SLEEP_SML, + 1, ACIOPHY_TIMEOUT_US)) + return -ETIMEDOUT; + aciophy_update(cfg, 0, CTRL0_SLEEP_BIG); + if (readl_poll_timeout(phy->base + CFG_PWRDN_CTRL1, reg, reg & CTRL0_SLEEP_BIG, + 1, ACIOPHY_TIMEOUT_US)) + return -ETIMEDOUT; + aciophy_update(cfg, CTRL0_CLAMP_EN, 0); + udelay(1); + aciophy_update(cfg, 0, CTRL0_AHB_RESET_N); + + apple_tunable_apply(phy->base, phy->tunable_pre); + aciophy_lane_up(phy); + aciophy_update(phy->base + XBAR, XBAR_MODE, XBAR_MODE_USB3); + apple_tunable_apply(phy->base, phy->tunable_post); + aciophy_update(phy->base + CFG_SPARE0, SPARE0_LN_SWAP, 0); + aciophy_update(cfg, 0, CTRL0_RESET_N); + return 0; +} + +static void aciophy_phy_down(struct aciophy *phy) +{ + void __iomem *cfg = phy->base + CFG_PWRDN_CTRL0; + u32 reg; + + aciophy_update(cfg, CTRL0_RESET_N, 0); + aciophy_lane_down(phy); + udelay(1); + aciophy_update(cfg, CTRL0_AHB_RESET_N, 0); + aciophy_update(cfg, 0, CTRL0_CLAMP_EN); + aciophy_update(cfg, CTRL0_SLEEP_BIG, 0); + if (readl_poll_timeout(phy->base + CFG_PWRDN_CTRL1, reg, !(reg & CTRL0_SLEEP_BIG), + 1, ACIOPHY_TIMEOUT_US)) + dev_warn(phy->dev, "big-sleep entry timeout\n"); + aciophy_update(cfg, CTRL0_SLEEP_SML, 0); + if (readl_poll_timeout(phy->base + CFG_PWRDN_CTRL1, reg, !(reg & CTRL0_SLEEP_SML), + 1, ACIOPHY_TIMEOUT_US)) + dev_warn(phy->dev, "small-sleep entry timeout\n"); + aciophy_update(phy->base + CFG_S2R_AON_SYNC_RST_N, BIT(0), 0); +} + +static void aciophy_bist_regsync(struct aciophy *phy) +{ + aciophy_update(phy->base + BIST_CFG0, 0, BIST_USB_REGSYNC); + readl(phy->base + BIST_CFG0); + aciophy_update(phy->base + BIST_CFG0, BIST_USB_REGSYNC, 0); +} + +static void aciophy_bist_status_ack(struct aciophy *phy) +{ + aciophy_update(phy->base + BIST_CFG2, 0, BIST_PHY_STATUS_RE); + aciophy_update(phy->base + BIST_CFG2, BIST_PHY_STATUS_RE, 0); +} + +/* + * aciophy_pipe_bist_override: while the PIPE handler switches, hold the + * MAC's PIPE reset and power-down, stepping power-down from P2 to P3. + */ +static void aciophy_bist_override(struct aciophy *phy, bool enable) +{ + void __iomem *status = phy->base + BIST_STATUS1; + u32 reg; + + if (!enable) { + aciophy_update(phy->base + BIST_OV2, OV2_MASK, 0); + aciophy_bist_regsync(phy); + aciophy_update(phy->base + BIST_CFG0, BIST_CLOCK_EN, 0); + return; + } + aciophy_update(phy->base + BIST_CFG0, 0, BIST_CLOCK_EN); + aciophy_update(phy->base + BIST_OV1, OV1_PWR_DOWN_VAL, + OV1_PIPE_RESET_N_VAL | FIELD_PREP(OV1_PWR_DOWN_VAL, 2)); + aciophy_update(phy->base + BIST_OV2, OV2_MASK, OV2_PIPE_RESET_N | OV2_PWR_DOWN); + aciophy_bist_regsync(phy); + if (readl_poll_timeout(status, reg, !(reg & STATUS1_PHY_STATUS_2), 1, 20000)) + dev_warn(phy->dev, "PIPE P2: PHY status stuck\n"); + aciophy_bist_status_ack(phy); + aciophy_update(phy->base + BIST_OV1, OV1_PWR_DOWN_VAL, FIELD_PREP(OV1_PWR_DOWN_VAL, 3)); + aciophy_update(phy->base + BIST_OV2, OV2_PWR_DOWN | BIT(10), OV2_PWR_DOWN); + aciophy_bist_regsync(phy); + if (readl_poll_timeout(status, reg, reg & STATUS1_PHY_STATUS, 1, 130000)) + dev_warn(phy->dev, "PIPE P3: no PHY status\n"); + if (readl_poll_timeout(status, reg, !(reg & STATUS1_PHY_STATUS_2), 1, 1000)) + dev_warn(phy->dev, "PIPE P3: PHY status stuck\n"); + aciophy_bist_status_ack(phy); +} + +static int aciophy_pipe_lock(struct aciophy *phy, bool lock) +{ + u32 reg; + + aciophy_update(phy->pipe + PIPE_LOCK_REQ, BIT(0), lock); + return readl_poll_timeout(phy->pipe + PIPE_LOCK_ACK, reg, (reg & BIT(0)) == lock, + 500, 150000); +} + +static void aciophy_pipe_mux(struct aciophy *phy, u32 mode, u32 clk) +{ + aciophy_update(phy->pipe + PIPE_MUX, MUX_CLK, FIELD_PREP(MUX_CLK, MUX_CLK_OFF)); + udelay(5); + aciophy_update(phy->pipe + PIPE_MUX, MUX_MODE, FIELD_PREP(MUX_MODE, mode)); + aciophy_update(phy->pipe + PIPE_MUX, MUX_CLK, FIELD_PREP(MUX_CLK, clk)); +} + +/* setUSB3Mode: the dummy PHY's PIPE to the ACIOPHY's, or back. */ +static int aciophy_pipe_select(struct aciophy *phy, bool usb3) +{ + bool running = readl(phy->pipe + PIPE_AON_GEN) & AON_GEN_DWC3_RESET_N; + u32 nonsel = usb3 ? 3 : (2 | NONSELECTED_NATIVE_RESET); + u32 reg; + int ret; + + if (readl(phy->pipe + PIPE_LOCK_ACK) & BIT(0)) + dev_warn(phy->dev, "PIPE interface already locked\n"); + aciophy_update(phy->pipe + PIPE_OVERRIDE_VALUES, OVERRIDE_VALUES_RXDETECT, 0); + aciophy_update(phy->pipe + PIPE_OVERRIDE, 0, + OVERRIDE_RXVALID | (usb3 ? 0 : OVERRIDE_RXDETECT)); + /* Without the controller up the lock is not acknowledged; harmless. */ + if (running && aciophy_pipe_lock(phy, true)) + dev_dbg(phy->dev, "PIPE lock not acknowledged\n"); + if (usb3) + aciophy_bist_override(phy, true); + aciophy_update(phy->pipe + PIPE_NONSELECTED, + NONSELECTED_POWER_DOWN | NONSELECTED_NATIVE_RESET, nonsel); + ret = readl_poll_timeout(phy->pipe + PIPE_NONSELECTED, reg, + (reg & (NONSELECTED_POWER_DOWN | NONSELECTED_NATIVE_RESET)) == + nonsel, 5, 1000); + if (ret) + dev_err(phy->dev, "PIPE non-selected override: %#x\n", reg); + if (usb3) + aciophy_bist_override(phy, false); + if (usb3) + aciophy_pipe_mux(phy, MUX_MODE_USB3, MUX_CLK_USB3); + else + aciophy_pipe_mux(phy, MUX_MODE_DUMMY, MUX_CLK_DUMMY); + aciophy_update(phy->pipe + PIPE_OVERRIDE, OVERRIDE_RXVALID | OVERRIDE_RXDETECT, 0); + if (running && aciophy_pipe_lock(phy, false)) + dev_dbg(phy->dev, "PIPE unlock not acknowledged\n"); + return ret; +} + +static int aciophy_power_on(struct phy *gphy) +{ + struct aciophy *phy = phy_get_drvdata(gphy); + int ret; + + for (unsigned int i = 0; i < ARRAY_SIZE(ps_idle); i++) { + ret = aciophy_gate(phy, i, true); + if (ret) { + dev_err(phy->dev, "power state %u: %d\n", i, ret); + goto fail; + } + } + ret = aciophy_phy_up(phy); + if (ret) { + dev_err(phy->dev, "PHY power-up: %d (cfg %#x/%#x)\n", ret, + readl(phy->base + CFG_PWRDN_CTRL0), readl(phy->base + CFG_PWRDN_CTRL1)); + goto fail; + } + ret = aciophy_pipe_select(phy, true); + if (ret) { + aciophy_pipe_select(phy, false); + aciophy_phy_down(phy); + goto fail; + } + dev_info(phy->dev, "USB3 up\n"); + return 0; +fail: + aciophy_gates_off(phy); + return ret; +} + +static int aciophy_power_off(struct phy *gphy) +{ + struct aciophy *phy = phy_get_drvdata(gphy); + + aciophy_pipe_select(phy, false); + aciophy_phy_down(phy); + aciophy_gates_off(phy); + return 0; +} + +static const struct phy_ops aciophy_ops = { + .power_on = aciophy_power_on, + .power_off = aciophy_power_off, + .owner = THIS_MODULE, +}; + +/* + * Not requested: the ATC window also holds the USB controller's DARTs, and + * the PMGR power states of the four ATCs are interleaved, so the "atc-ps" + * window covers registers of the other ATCs as well. + */ +static void __iomem *aciophy_map(struct platform_device *pdev, const char *name) +{ + struct resource *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + void __iomem *base; + + if (!res) + return IOMEM_ERR_PTR(-EINVAL); + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + return base ?: IOMEM_ERR_PTR(-ENOMEM); +} + +static int aciophy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *provider; + struct resource *atc; + struct aciophy *phy; + struct phy *gphy; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + phy->dev = dev; + phy->base = aciophy_map(pdev, "atc"); + if (IS_ERR(phy->base)) + return PTR_ERR(phy->base); + phy->pipe = devm_platform_ioremap_resource_byname(pdev, "pipehandler"); + if (IS_ERR(phy->pipe)) + return PTR_ERR(phy->pipe); + phy->ps = aciophy_map(pdev, "atc-ps"); + if (IS_ERR(phy->ps)) + return PTR_ERR(phy->ps); + phy->psd = aciophy_map(pdev, "atc-psd"); + if (IS_ERR(phy->psd)) + return PTR_ERR(phy->psd); + + /* The tunables are offsets into the ATC block. */ + atc = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atc"); + phy->tunable_pre = devm_apple_tunable_parse(dev, dev->of_node, + "apple,tunable-pre", atc); + if (IS_ERR(phy->tunable_pre)) + return dev_err_probe(dev, PTR_ERR(phy->tunable_pre), + "invalid apple,tunable-pre\n"); + phy->tunable_post = devm_apple_tunable_parse(dev, dev->of_node, + "apple,tunable-post", atc); + if (IS_ERR(phy->tunable_post)) + return dev_err_probe(dev, PTR_ERR(phy->tunable_post), + "invalid apple,tunable-post\n"); + + gphy = devm_phy_create(dev, NULL, &aciophy_ops); + if (IS_ERR(gphy)) + return PTR_ERR(gphy); + phy_set_drvdata(gphy, phy); + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id aciophy_of_match[] = { + { .compatible = "apple,t8152-aciophy-usb3" }, + {} +}; +MODULE_DEVICE_TABLE(of, aciophy_of_match); + +static struct platform_driver aciophy_driver = { + .probe = aciophy_probe, + .driver = { + .name = "apple-aciophy-usb3", + .of_match_table = aciophy_of_match, + }, +}; +module_platform_driver(aciophy_driver); + +MODULE_DESCRIPTION("Apple T8152 ACIOPHY USB3 PHY"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/apple/mailbox.c b/drivers/soc/apple/mailbox.c index b73e7da0b2b59..caea0c70ae8ff 100644 --- a/drivers/soc/apple/mailbox.c +++ b/drivers/soc/apple/mailbox.c @@ -238,6 +238,10 @@ struct apple_mbox_hw { bool is_ascwrap_v8; /* The mailbox interrupt never reaches the AIC: receive by polling. */ bool rx_poll_only; + /* 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; @@ -271,7 +275,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; @@ -293,7 +297,8 @@ 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 || mbox->hw->rx_poll_only; + return mbox->hw->is_ascwrap_v8 || mbox->hw->rx_poll_only || + mbox->hw->rx_poll_required; } /* Both ASCWrap generations share the consumer lifecycle API below. */ @@ -1614,6 +1619,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, @@ -1625,6 +1640,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; + } + if (mbox->hw->polled) { mbox->irq_recv_not_empty = -ENXIO; mbox->irq_send_empty = -ENXIO; @@ -1684,6 +1714,7 @@ static int apple_mbox_probe(struct platform_device *pdev) return ret; } +setup_pm: ret = devm_pm_runtime_enable(dev); if (ret) return ret; @@ -1979,8 +2010,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 4fa31a0e54f47..a19468673fcdf 100644 --- a/drivers/soc/apple/sart.c +++ b/drivers/soc/apple/sart.c @@ -505,6 +505,10 @@ static const struct of_device_id apple_sart_of_match[] = { .compatible = "apple,t6050-sart", .data = &sart_ops_v4, }, + { + .compatible = "apple,t8152-sart", + .data = &sart_ops_v4, + }, { .compatible = "apple,t6000-sart", .data = &sart_ops_v3, diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 7f68eba95e1f1..3566533dda5a2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -2962,6 +2962,10 @@ static const struct of_device_id of_dwc3_match[] = { { .compatible = "synopsys,dwc3" }, + { + /* Handed over in host mode by the bootloader, see apple,dwc3.yaml */ + .compatible = "apple,t8152-dwc3" + }, { }, }; MODULE_DEVICE_TABLE(of, of_dwc3_match);