From b1a6287c96d3e8a7bb68e9d6f60459a5a380b900 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 11 Nov 2021 21:31:21 +0100 Subject: [PATCH 001/352] arm64: dts: apple: j31[46]: Add keyboard nodes Enables keyboard and touchpad input on MacBook Pro (14/16-inch, M1 Pro/Max, 2021). Signed-off-by: Janne Grunau --- .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index acd43bd86a4072..e9515a3885aefb 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -173,6 +173,27 @@ clock-frequency = <1068000000>; }; +&spi3 { + status = "okay"; + + hid-transport@0 { + compatible = "apple,spi-hid-transport"; + reg = <0>; + spi-max-frequency = <8000000>; + /* + * Apple's ADT specifies 20us CS change delays, and the + * SPI HID interface metadata specifies 45us. Using either + * seems not to be reliable, but adding both works, so + * best guess is they are cumulative. + */ + spi-cs-setup-delay-ns = <65000>; + spi-cs-hold-delay-ns = <65000>; + spi-cs-inactive-delay-ns = <250000>; + spien-gpios = <&pinctrl_ap 194 0>; + interrupts-extended = <&pinctrl_nub 6 IRQ_TYPE_LEVEL_LOW>; + }; +}; + /* PCIe devices */ &port00 { /* WLAN */ From eb07fbdc64e8eb6690275c072e0240da25a82a2d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 2 Feb 2023 11:15:35 +0100 Subject: [PATCH 002/352] arm64: dts: apple: t8112: Add mtp device nodes for j413/j493 Those provide trackpad and keyboard for j413/j493. Add keyboard alias & layout props for t8112 laptops Signed-off-by: Hector Martin Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j413.dts | 36 ++++++++++++ arch/arm64/boot/dts/apple/t8112-j415.dts | 36 ++++++++++++ arch/arm64/boot/dts/apple/t8112-j493.dts | 36 ++++++++++++ arch/arm64/boot/dts/apple/t8112.dtsi | 73 ++++++++++++++++++++++++ 4 files changed, 181 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts index 67ee47d3818cad..ba94990a995f11 100644 --- a/arch/arm64/boot/dts/apple/t8112-j413.dts +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts @@ -20,6 +20,7 @@ aliases { bluetooth0 = &bluetooth0; + keyboard = &keyboard; wifi0 = &wifi0; }; @@ -92,3 +93,38 @@ &fpwm1 { status = "okay"; }; + +&mtp { + status = "okay"; +}; +&mtp_mbox { + status = "okay"; +}; +&mtp_dart { + status = "okay"; +}; +&mtp_dockchannel { + status = "okay"; +}; +&mtp_hid { + apple,afe-reset-gpios = <&smc_gpio 8 GPIO_ACTIVE_LOW>; + apple,stm-reset-gpios = <&smc_gpio 24 GPIO_ACTIVE_LOW>; + + multi-touch { + firmware-name = "apple/tpmtfw-j413.bin"; + }; + + keyboard: keyboard { + hid-country-code = <0>; + apple,keyboard-layout-id = <0>; + }; + + stm { + }; + + actuator { + }; + + tp_accel { + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts index 4f146043bca2d3..bc8b533677df84 100644 --- a/arch/arm64/boot/dts/apple/t8112-j415.dts +++ b/arch/arm64/boot/dts/apple/t8112-j415.dts @@ -20,6 +20,7 @@ aliases { bluetooth0 = &bluetooth0; + keyboard = &keyboard; wifi0 = &wifi0; }; @@ -92,3 +93,38 @@ &fpwm1 { status = "okay"; }; + +&mtp { + status = "okay"; +}; +&mtp_mbox { + status = "okay"; +}; +&mtp_dart { + status = "okay"; +}; +&mtp_dockchannel { + status = "okay"; +}; +&mtp_hid { + apple,afe-reset-gpios = <&smc_gpio 8 GPIO_ACTIVE_LOW>; + apple,stm-reset-gpios = <&smc_gpio 24 GPIO_ACTIVE_LOW>; + + multi-touch { + firmware-name = "apple/tpmtfw-j415.bin"; + }; + + keyboard: keyboard { + hid-country-code = <0>; + apple,keyboard-layout-id = <0>; + }; + + stm { + }; + + actuator { + }; + + tp_accel { + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts index 74adcd90974f52..40e241b8e2d57b 100644 --- a/arch/arm64/boot/dts/apple/t8112-j493.dts +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts @@ -24,6 +24,7 @@ */ aliases { bluetooth0 = &bluetooth0; + keyboard = &keyboard; touchbar0 = &touchbar0; wifi0 = &wifi0; }; @@ -147,3 +148,38 @@ touchscreen-inverted-y; }; }; + +&mtp { + status = "okay"; +}; +&mtp_mbox { + status = "okay"; +}; +&mtp_dart { + status = "okay"; +}; +&mtp_dockchannel { + status = "okay"; +}; +&mtp_hid { + apple,afe-reset-gpios = <&smc_gpio 8 GPIO_ACTIVE_LOW>; + apple,stm-reset-gpios = <&smc_gpio 24 GPIO_ACTIVE_LOW>; + + multi-touch { + firmware-name = "apple/tpmtfw-j493.bin"; + }; + + keyboard: keyboard { + hid-country-code = <0>; + apple,keyboard-layout-id = <0>; + }; + + stm { + }; + + actuator { + }; + + tp_accel { + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 85c47422d4e8e3..d439e429bf6835 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -983,6 +983,79 @@ ; }; + mtp: mtp@24e400000 { + compatible = "apple,t8112-mtp", "apple,t8112-rtk-helper-asc4", "apple,mtp", "apple,rtk-helper-asc4"; + reg = <0x2 0x4e400000 0x0 0x4000>, + <0x2 0x4ec00000 0x0 0x100000>; + reg-names = "asc", "sram"; + mboxes = <&mtp_mbox>; + iommus = <&mtp_dart 1>; + #helper-cells = <0>; + + status = "disabled"; + }; + + mtp_mbox: mbox@24e408000 { + compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x4e408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + + status = "disabled"; + }; + + mtp_dart: iommu@24e808000 { + compatible = "apple,t8112-dart", "apple,t8110-dart"; + reg = <0x2 0x4e808000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = ; + #iommu-cells = <1>; + + status = "disabled"; + }; + + mtp_dockchannel: fifo@24eb14000 { + compatible = "apple,t8112-dockchannel", "apple,dockchannel"; + reg = <0x2 0x4eb14000 0x0 0x4000>; + reg-names = "irq"; + interrupt-parent = <&aic>; + interrupts = ; + + ranges = <0 0x2 0x4eb28000 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + + interrupt-controller; + #interrupt-cells = <2>; + + status = "disabled"; + + mtp_hid: input@8000 { + compatible = "apple,dockchannel-hid"; + reg = <0x8000 0x4000>, + <0xc000 0x4000>, + <0x0000 0x4000>, + <0x4000 0x4000>; + reg-names = "config", "data", + "rmt-config", "rmt-data"; + iommus = <&mtp_dart 1>; + interrupt-parent = <&mtp_dockchannel>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, + <3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tx", "rx"; + + apple,fifo-size = <0x800>; + apple,helper-cpu = <&mtp>; + }; + + }; + ans_mbox: mbox@277408000 { compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; reg = <0x2 0x77408000 0x0 0x4000>; From 5dc78fd2ce2900ade4cfa9910bc668b999ef72eb Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 9 Apr 2023 23:49:01 +0900 Subject: [PATCH 003/352] arm64: dts: apple: Fix t600x mca IRQs Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index f715b19efd1679..f40d752d69a4a1 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -333,10 +333,10 @@ "tx2a", "rx2a", "tx2b", "rx2b", "tx3a", "rx3a", "tx3b", "rx3b"; interrupt-parent = <&aic>; - interrupts = , + interrupts = , + , , - , - ; + ; power-domains = <&ps_audio_p>, <&ps_mca0>, <&ps_mca1>, <&ps_mca2>, <&ps_mca3>; resets = <&ps_audio_p>; From 9a3ca198f1c6fc26d56a36f2caf73522b1c505ab Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 12 Oct 2023 23:20:26 +0900 Subject: [PATCH 004/352] arm64: dts: apple: t600x: Mark MCA power states as externally-clocked Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index 0bd44753b76a0c..cc2627eafc899d 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -1113,6 +1113,7 @@ #reset-cells = <0>; label = DIE_LABEL(mca0); power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + apple,externally-clocked; }; DIE_NODE(ps_mca1): power-controller@290 { @@ -1122,6 +1123,7 @@ #reset-cells = <0>; label = DIE_LABEL(mca1); power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + apple,externally-clocked; }; DIE_NODE(ps_mca2): power-controller@298 { @@ -1131,6 +1133,7 @@ #reset-cells = <0>; label = DIE_LABEL(mca2); power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + apple,externally-clocked; }; DIE_NODE(ps_mca3): power-controller@2a0 { @@ -1140,6 +1143,7 @@ #reset-cells = <0>; label = DIE_LABEL(mca3); power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + apple,externally-clocked; }; DIE_NODE(ps_dpa0): power-controller@2a8 { From 335826794cf5bee58755a74ff4265dc99aa1c89e Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 12 Oct 2023 23:20:47 +0900 Subject: [PATCH 005/352] arm64: dts: apple: t8103: Mark MCA power states as externally-clocked Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi index a55b1fd2b52cc8..9bddd5bf866000 100644 --- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi @@ -493,6 +493,7 @@ #reset-cells = <0>; label = "mca0"; power-domains = <&ps_audio_p>, <&ps_sio_adma>; + apple,externally-clocked; }; ps_mca1: power-controller@2c0 { @@ -502,6 +503,7 @@ #reset-cells = <0>; label = "mca1"; power-domains = <&ps_audio_p>, <&ps_sio_adma>; + apple,externally-clocked; }; ps_mca2: power-controller@2c8 { @@ -511,6 +513,7 @@ #reset-cells = <0>; label = "mca2"; power-domains = <&ps_audio_p>, <&ps_sio_adma>; + apple,externally-clocked; }; ps_mca3: power-controller@2d0 { @@ -520,6 +523,7 @@ #reset-cells = <0>; label = "mca3"; power-domains = <&ps_audio_p>, <&ps_sio_adma>; + apple,externally-clocked; }; ps_mca4: power-controller@2d8 { @@ -529,6 +533,7 @@ #reset-cells = <0>; label = "mca4"; power-domains = <&ps_audio_p>, <&ps_sio_adma>; + apple,externally-clocked; }; ps_mca5: power-controller@2e0 { @@ -538,6 +543,7 @@ #reset-cells = <0>; label = "mca5"; power-domains = <&ps_audio_p>, <&ps_sio_adma>; + apple,externally-clocked; }; ps_dpa0: power-controller@2e8 { From 93d4d040bfba583056e6bff94ad2f52db90db1f0 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 12 Oct 2023 23:20:56 +0900 Subject: [PATCH 006/352] arm64: dts: apple: t8112: Mark MCA power states as externally-clocked Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t8112-pmgr.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi index 118694dd9b5f06..8b3297d75992d3 100644 --- a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi @@ -465,6 +465,7 @@ #reset-cells = <0>; label = "mca0"; power-domains = <&ps_sio_adma>, <&ps_audio_p>; + apple,externally-clocked; }; ps_mca1: power-controller@2c8 { @@ -474,6 +475,7 @@ #reset-cells = <0>; label = "mca1"; power-domains = <&ps_sio_adma>, <&ps_audio_p>; + apple,externally-clocked; }; ps_mca2: power-controller@2d0 { @@ -483,6 +485,7 @@ #reset-cells = <0>; label = "mca2"; power-domains = <&ps_sio_adma>, <&ps_audio_p>; + apple,externally-clocked; }; ps_mca3: power-controller@2d8 { @@ -492,6 +495,7 @@ #reset-cells = <0>; label = "mca3"; power-domains = <&ps_sio_adma>, <&ps_audio_p>; + apple,externally-clocked; }; ps_mca4: power-controller@2e0 { @@ -501,6 +505,7 @@ #reset-cells = <0>; label = "mca4"; power-domains = <&ps_sio_adma>, <&ps_audio_p>; + apple,externally-clocked; }; ps_mca5: power-controller@2e8 { @@ -510,6 +515,7 @@ #reset-cells = <0>; label = "mca5"; power-domains = <&ps_sio_adma>, <&ps_audio_p>; + apple,externally-clocked; }; ps_mcc: power-controller@2f0 { From d8a95033bb852ff2e46965d19dc6c63ee4a5ede2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 19 Feb 2022 09:49:59 +0100 Subject: [PATCH 007/352] arm64: dts: apple: t8103*: Put in audio nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm64: dts: apple: t8103-j274: Add speaker I/V sense slots Specify TDM slots for the speaker amp IC to transmit I/V sense measurements in. arm64: dts: apple: j293/j313: Model SDZ GPIO as a regulator Signed-off-by: Martin Povišer Co-developed-by: Hector Martin Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t8103-j274.dts | 53 ++++++++++++ arch/arm64/boot/dts/apple/t8103-j293.dts | 106 +++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8103-j313.dts | 79 +++++++++++++++++ arch/arm64/boot/dts/apple/t8103-j456.dts | 31 +++++++ arch/arm64/boot/dts/apple/t8103-j457.dts | 31 +++++++ 5 files changed, 300 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts index 52965258200da3..f3b7204618c8ce 100644 --- a/arch/arm64/boot/dts/apple/t8103-j274.dts +++ b/arch/arm64/boot/dts/apple/t8103-j274.dts @@ -71,6 +71,59 @@ status = "okay"; }; +&i2c1 { + speaker_amp: codec@31 { + compatible = "ti,tas5770l", "ti,tas2770"; + reg = <0x31>; + shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + ti,sdout-zero-fill; + }; +}; + &i2c2 { status = "okay"; + + jack_codec: codec@48 { + compatible = "cirrus,cs42l83"; + reg = <0x48>; + reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&pinctrl_ap>; + interrupts = <183 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + cirrus,ts-inv = <1>; + sound-name-prefix = "Jack"; + }; +}; + +/ { + sound { + compatible = "apple,j274-macaudio", "apple,macaudio"; + model = "Mac mini J274"; + + dai-link@0 { + link-name = "Speaker"; + + cpu { + sound-dai = <&mca 0>; + }; + codec { + sound-dai = <&speaker_amp>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + + }; }; diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts index c23de799024abb..753c9c4d9adefc 100644 --- a/arch/arm64/boot/dts/apple/t8103-j293.dts +++ b/arch/arm64/boot/dts/apple/t8103-j293.dts @@ -80,8 +80,84 @@ }; }; +/* Virtual regulator representing the shared shutdown GPIO */ +/ { + speaker_sdz: fixed-regulator-tas5770-sdz { + compatible = "regulator-fixed"; + regulator-name = "tas5770-sdz"; + startup-delay-us = <5000>; + gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&i2c1 { + speaker_left_rear: codec@31 { + compatible = "ti,tas5770l", "ti,tas2770"; + reg = <0x31>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Rear"; + interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <8>; + ti,vmon-slot-no = <10>; + ti,pdm-slot-no = <12>; + }; + + speaker_left_front: codec@32 { + compatible = "ti,tas5770l", "ti,tas2770"; + reg = <0x32>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Front"; + interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + ti,pdm-slot-no = <4>; + ti,sdout-pull-down; + }; +}; + &i2c2 { status = "okay"; + + jack_codec: codec@48 { + compatible = "cirrus,cs42l83"; + reg = <0x48>; + reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&pinctrl_ap>; + interrupts = <183 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + cirrus,ts-inv = <1>; + sound-name-prefix = "Jack"; + }; +}; + +&i2c3 { + speaker_right_rear: codec@34 { + compatible = "ti,tas5770l", "ti,tas2770"; + reg = <0x34>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Rear"; + interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <12>; + ti,vmon-slot-no = <14>; + ti,pdm-slot-no = <16>; + }; + + speaker_right_front: codec@35 { + compatible = "ti,tas5770l", "ti,tas2770"; + reg = <0x35>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Front"; + interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <4>; + ti,vmon-slot-no = <6>; + ti,pdm-slot-no = <8>; + ti,sdout-pull-down; + }; }; &i2c4 { @@ -153,3 +229,33 @@ &displaydfr_dart { status = "okay"; }; + +/ { + sound { + compatible = "apple,j293-macaudio", "apple,macaudio"; + model = "MacBook Pro J293"; + + dai-link@0 { + link-name = "Speakers"; + + cpu { + sound-dai = <&mca 0>, <&mca 1>; + }; + codec { + sound-dai = <&speaker_left_front>, <&speaker_left_rear>, + <&speaker_right_front>, <&speaker_right_rear>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts index 9c9547e922a676..43620b57a63d2e 100644 --- a/arch/arm64/boot/dts/apple/t8103-j313.dts +++ b/arch/arm64/boot/dts/apple/t8103-j313.dts @@ -75,3 +75,82 @@ interrupts-extended = <&pinctrl_nub 13 IRQ_TYPE_LEVEL_LOW>; }; }; + +/* Virtual regulator representing the shared shutdown GPIO */ +/ { + speaker_sdz: fixed-regulator-tas5770-sdz { + compatible = "regulator-fixed"; + regulator-name = "tas5770-sdz"; + startup-delay-us = <5000>; + gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&i2c1 { + speaker_left: codec@31 { + compatible = "ti,tas5770l", "ti,tas2770"; + reg = <0x31>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left"; + interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + ti,sdout-zero-fill; + }; +}; + +&i2c3 { + speaker_right: codec@34 { + compatible = "ti,tas5770l", "ti,tas2770"; + reg = <0x34>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right"; + interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <4>; + ti,vmon-slot-no = <6>; + ti,sdout-zero-fill; + }; + + jack_codec: codec@48 { + compatible = "cirrus,cs42l83"; + reg = <0x48>; + reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&pinctrl_ap>; + interrupts = <183 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + cirrus,ts-inv = <1>; + sound-name-prefix = "Jack"; + }; +}; + +/ { + sound { + compatible = "apple,j313-macaudio", "apple,macaudio"; + model = "MacBook Air J313"; + + dai-link@0 { + link-name = "Speakers"; + + cpu { + sound-dai = <&mca 0>, <&mca 1>; + }; + codec { + sound-dai = <&speaker_left>, <&speaker_right>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts index 090c97bb781b32..d277704b988bcc 100644 --- a/arch/arm64/boot/dts/apple/t8103-j456.dts +++ b/arch/arm64/boot/dts/apple/t8103-j456.dts @@ -88,3 +88,34 @@ &pcie0_dart_2 { status = "okay"; }; + +&i2c1 { + jack_codec: codec@48 { + compatible = "cirrus,cs42l83"; + reg = <0x48>; + reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&pinctrl_ap>; + interrupts = <183 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + cirrus,ts-inv = <1>; + sound-name-prefix = "Jack"; + }; +}; + +/ { + sound { + compatible = "apple,j456-macaudio", "apple,macaudio"; + model = "iMac J456"; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts index ebddde75455c69..2e7d344f88a54f 100644 --- a/arch/arm64/boot/dts/apple/t8103-j457.dts +++ b/arch/arm64/boot/dts/apple/t8103-j457.dts @@ -69,3 +69,34 @@ &pcie0_dart_2 { status = "okay"; }; + +&i2c1 { + jack_codec: codec@48 { + compatible = "cirrus,cs42l83"; + reg = <0x48>; + reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&pinctrl_ap>; + interrupts = <183 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + cirrus,ts-inv = <1>; + sound-name-prefix = "Jack"; + }; +}; + +/ { + sound { + compatible = "apple,j457-macaudio", "apple,macaudio"; + model = "iMac J457"; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; From 8ff638a207afe53511e71a4f731131ce3d2b9f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 11 Mar 2022 22:16:25 +0100 Subject: [PATCH 008/352] arm64: dts: apple: t600x-jxxx: Put in audio nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm64: dts: apple: t600x-j314-j316: Add speaker I/V sense slots Specify TDM slots for the speaker amp IC to transmit I/V sense measurements in. Make sure the channel order mirrors that of the playback PCM. arm64: dts: apple: t600x-j314-j316: Zero out unused speaker sense slots Make one left codec and one right codec zero out the unused slots on their respective speaker sense buses. Internally, inside the SoC, the left and right sense buses are ORed, and zeroing-out the unused slots on one bus is required so as not to corrupt the data on the other. arm64: dts: apple: t600x: describe shared SDZ GPIO for tas2764 machines with the tas2764 amp codec share a GPIO line for asserting/deasserting the SDZ pin on the chips. describe this as a regulator to facilitate chip reset on suspend/resume Signed-off-by: Martin Povišer Co-developed-by: Hector Martin Signed-off-by: Hector Martin Co-developed-by: James Calligeros Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/t6000-j314s.dts | 5 + arch/arm64/boot/dts/apple/t6000-j316s.dts | 5 + arch/arm64/boot/dts/apple/t6001-j314c.dts | 5 + arch/arm64/boot/dts/apple/t6001-j316c.dts | 5 + arch/arm64/boot/dts/apple/t6001-j375c.dts | 5 + arch/arm64/boot/dts/apple/t6002-j375d.dts | 5 + .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 133 ++++++++++++++++++ arch/arm64/boot/dts/apple/t600x-j375.dtsi | 56 ++++++++ 8 files changed, 219 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6000-j314s.dts b/arch/arm64/boot/dts/apple/t6000-j314s.dts index 1430b91ff1b152..dab8e99fa32496 100644 --- a/arch/arm64/boot/dts/apple/t6000-j314s.dts +++ b/arch/arm64/boot/dts/apple/t6000-j314s.dts @@ -24,3 +24,8 @@ &bluetooth0 { brcm,board-type = "apple,maldives"; }; + +&sound { + compatible = "apple,j314-macaudio", "apple,macaudio"; + model = "MacBook Pro J314"; +}; diff --git a/arch/arm64/boot/dts/apple/t6000-j316s.dts b/arch/arm64/boot/dts/apple/t6000-j316s.dts index da0cbe7d96736b..2cdfac3c40c842 100644 --- a/arch/arm64/boot/dts/apple/t6000-j316s.dts +++ b/arch/arm64/boot/dts/apple/t6000-j316s.dts @@ -24,3 +24,8 @@ &bluetooth0 { brcm,board-type = "apple,madagascar"; }; + +&sound { + compatible = "apple,j316-macaudio", "apple,macaudio"; + model = "MacBook Pro J316"; +}; diff --git a/arch/arm64/boot/dts/apple/t6001-j314c.dts b/arch/arm64/boot/dts/apple/t6001-j314c.dts index c37097dcfdb304..7495698beb0258 100644 --- a/arch/arm64/boot/dts/apple/t6001-j314c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j314c.dts @@ -24,3 +24,8 @@ &bluetooth0 { brcm,board-type = "apple,maldives"; }; + +&sound { + compatible = "apple,j314-macaudio", "apple,macaudio"; + model = "MacBook Pro J314"; +}; diff --git a/arch/arm64/boot/dts/apple/t6001-j316c.dts b/arch/arm64/boot/dts/apple/t6001-j316c.dts index 3bc6e0c3294cf9..6622b6e225a600 100644 --- a/arch/arm64/boot/dts/apple/t6001-j316c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j316c.dts @@ -24,3 +24,8 @@ &bluetooth0 { brcm,board-type = "apple,madagascar"; }; + +&sound { + compatible = "apple,j316-macaudio", "apple,macaudio"; + model = "MacBook Pro J316"; +}; diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts index 2e7c23714d4d00..a8694a94fa2793 100644 --- a/arch/arm64/boot/dts/apple/t6001-j375c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts @@ -24,3 +24,8 @@ &bluetooth0 { brcm,board-type = "apple,okinawa"; }; + +&sound { + compatible = "apple,j375-macaudio", "apple,macaudio"; + model = "Mac Studio J375"; +}; diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts index a2a24d028cbbf5..65743fea3f1068 100644 --- a/arch/arm64/boot/dts/apple/t6002-j375d.dts +++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts @@ -21,6 +21,11 @@ }; }; +&sound { + compatible = "apple,j375-macaudio", "apple,macaudio"; + model = "Mac Studio J375"; +}; + /* USB Type C */ &i2c0 { /* front-right */ diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index e9515a3885aefb..6ebaabe49a8130 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -169,6 +169,106 @@ }; }; +/* Virtual regulator representing the shared shutdown GPIO */ +/ { + speaker_sdz: fixed-regulator-sn012776-sdz { + compatible = "regulator-fixed"; + regulator-name = "sn012776-sdz"; + startup-delay-us = <5000>; + gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&i2c1 { + status = "okay"; + + speaker_left_tweet: codec@3a { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3a>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Tweeter"; + interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <8>; + ti,vmon-slot-no = <10>; + }; + + speaker_left_woof1: codec@38 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x38>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Woofer 1"; + interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + ti,sdout-force-zero-mask = <0xf0f0f0>; + }; + + speaker_left_woof2: codec@39 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x39>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Woofer 2"; + interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <16>; + ti,vmon-slot-no = <18>; + }; +}; + +&i2c2 { + status = "okay"; + + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>; + sound-name-prefix = "Jack"; + }; +}; + +&i2c3 { + status = "okay"; + + speaker_right_tweet: codec@3d { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3d>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Tweeter"; + interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <12>; + ti,vmon-slot-no = <14>; + }; + + speaker_right_woof1: codec@3b { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3b>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Woofer 1"; + interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <4>; + ti,vmon-slot-no = <6>; + ti,sdout-force-zero-mask = <0x0f0f0f>; + }; + + speaker_right_woof2: codec@3c { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3c>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Woofer 2"; + interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <20>; + ti,vmon-slot-no = <22>; + }; +}; + &nco_clkref { clock-frequency = <1068000000>; }; @@ -389,4 +489,37 @@ status = "disabled"; }; +/ { + sound: sound { + /* compatible is set per machine */ + + dai-link@0 { + link-name = "Speakers"; + + cpu { + sound-dai = <&mca 0>, <&mca 1>; + }; + codec { + sound-dai = <&speaker_left_woof1>, + <&speaker_left_tweet>, + <&speaker_left_woof2>, + <&speaker_right_woof1>, + <&speaker_right_tweet>, + <&speaker_right_woof2>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; + #include "spi1-nvram.dtsi" diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi index d2c8977bc01532..65b2abd521b10c 100644 --- a/arch/arm64/boot/dts/apple/t600x-j375.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi @@ -349,10 +349,66 @@ }; }; +/* Audio */ +&i2c1 { + status = "okay"; + + speaker: codec@38 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x38>; + shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + }; +}; + +&i2c2 { + status = "okay"; + + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>; + sound-name-prefix = "Jack"; + }; +}; + &nco_clkref { clock-frequency = <1068000000>; }; +/ { + sound: sound { + /* compatible is set per machine */ + + dai-link@0 { + link-name = "Speaker"; + + cpu { + sound-dai = <&mca 0>; + }; + codec { + sound-dai = <&speaker>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; + /* PCIe devices */ &port00 { /* WLAN */ From dcbaaa9357412fe447d9d899d767c6d650284395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 19 Feb 2022 09:49:59 +0100 Subject: [PATCH 009/352] arm64: dts: apple: t8112: Put in audio nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm64: dts: apple: t8112: describe shared SDZ GPIO for tas2764 machines with the tas2764 amp codec share a GPIO line for asserting/deasserting the SDZ pin on the chips. describe this as a regulator to facilitate chip reset on suspend/resume Co-developed-by: Hector Martin Signed-off-by: Hector Martin Co-developed-by: James Calligeros Signed-off-by: James Calligeros Signed-off-by: Martin Povišer --- arch/arm64/boot/dts/apple/t8112-j413.dts | 100 ++++++++++++++++++ arch/arm64/boot/dts/apple/t8112-j415.dts | 126 +++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8112-j473.dts | 54 ++++++++++ arch/arm64/boot/dts/apple/t8112-j493.dts | 100 ++++++++++++++++++ 4 files changed, 380 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts index ba94990a995f11..f6450ef3a0c6e1 100644 --- a/arch/arm64/boot/dts/apple/t8112-j413.dts +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts @@ -86,6 +86,76 @@ }; }; +/* Virtual regulator representing the shared shutdown GPIO */ +/ { + speaker_sdz: fixed-regulator-sn012776-sdz { + compatible = "regulator-fixed"; + regulator-name = "sn012776-sdz"; + startup-delay-us = <5000>; + gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&i2c1 { + speaker_left_woof: codec@38 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x38>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Woofer"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + ti,sdout-force-zero-mask = <0xf0f0>; + }; + + speaker_left_tweet: codec@39 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x39>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Tweeter"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <8>; + ti,vmon-slot-no = <10>; + }; +}; + +&i2c3 { + speaker_right_woof: codec@3b { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3b>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Woofer"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <4>; + ti,vmon-slot-no = <6>; + ti,sdout-force-zero-mask = <0x0f0f>; + }; + + speaker_right_tweet: codec@3c { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3c>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Tweeter"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <12>; + ti,vmon-slot-no = <14>; + }; + + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_nub 12 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + interrupts-extended = <&pinctrl_ap 149 IRQ_TYPE_LEVEL_LOW>; + sound-name-prefix = "Jack"; + }; +}; + &i2c4 { status = "okay"; }; @@ -94,6 +164,36 @@ status = "okay"; }; +/ { + sound { + compatible = "apple,j413-macaudio", "apple,macaudio"; + model = "MacBook Air J413"; + + dai-link@0 { + link-name = "Speakers"; + + cpu { + sound-dai = <&mca 0>, <&mca 1>; + }; + codec { + sound-dai = <&speaker_left_woof>, <&speaker_left_tweet>, + <&speaker_right_woof>, <&speaker_right_tweet>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; + &mtp { status = "okay"; }; diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts index bc8b533677df84..2c969eb767a7d8 100644 --- a/arch/arm64/boot/dts/apple/t8112-j415.dts +++ b/arch/arm64/boot/dts/apple/t8112-j415.dts @@ -86,6 +86,98 @@ }; }; +/* Virtual regulator representing the shared shutdown GPIO */ +/ { + speaker_sdz: fixed-regulator-sn012776-sdz { + compatible = "regulator-fixed"; + regulator-name = "sn012776-sdz"; + startup-delay-us = <5000>; + gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&i2c1 { + speaker_left_woof1: codec@38 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x38>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Woofer 1"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + ti,sdout-force-zero-mask = <0xf0f0f0>; + }; + + speaker_left_tweet: codec@39 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x39>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Tweeter"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <8>; + ti,vmon-slot-no = <10>; + }; + + speaker_left_woof2: codec@3a { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3a>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Woofer 2"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <16>; + ti,vmon-slot-no = <18>; + }; +}; + +&i2c3 { + speaker_right_woof1: codec@3b { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3b>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Woofer 1"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <4>; + ti,vmon-slot-no = <6>; + ti,sdout-force-zero-mask = <0x0f0f0f>; + }; + + speaker_right_tweet: codec@3c { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3c>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Tweeter"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <12>; + ti,vmon-slot-no = <14>; + }; + + speaker_right_woof2: codec@3d { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3d>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Woofer 2"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <20>; + ti,vmon-slot-no = <22>; + }; + + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_nub 12 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + interrupts-extended = <&pinctrl_ap 149 IRQ_TYPE_LEVEL_LOW>; + sound-name-prefix = "Jack"; + }; +}; + &i2c4 { status = "okay"; }; @@ -94,6 +186,40 @@ status = "okay"; }; +/ { + sound { + compatible = "apple,j415-macaudio", "apple,macaudio"; + model = "MacBook Air J415"; + + dai-link@0 { + link-name = "Speakers"; + + cpu { + sound-dai = <&mca 0>, <&mca 1>; + }; + codec { + sound-dai = <&speaker_left_woof1>, + <&speaker_left_tweet>, + <&speaker_left_woof2>, + <&speaker_right_woof1>, + <&speaker_right_tweet>, + <&speaker_right_woof2>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; + &mtp { status = "okay"; }; diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts index 320178e7ddfe8b..effdfae8646949 100644 --- a/arch/arm64/boot/dts/apple/t8112-j473.dts +++ b/arch/arm64/boot/dts/apple/t8112-j473.dts @@ -104,3 +104,57 @@ &typec1 { label = "USB-C Back-right"; }; + +&i2c1 { + speaker_amp: codec@38 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x38>; + shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + interrupt-parent = <&pinctrl_ap>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + }; + + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_nub 12 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&pinctrl_ap>; + interrupts = <149 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + cirrus,ts-inv = <1>; + sound-name-prefix = "Jack"; + }; +}; + +/ { + sound { + compatible = "apple,j473-macaudio", "apple,macaudio"; + model = "Mac mini J473"; + + dai-link@0 { + link-name = "Speaker"; + + cpu { + sound-dai = <&mca 0>; + }; + codec { + sound-dai = <&speaker_amp>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts index 40e241b8e2d57b..d25794fd88e355 100644 --- a/arch/arm64/boot/dts/apple/t8112-j493.dts +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts @@ -123,6 +123,76 @@ label = "USB-C Left-front"; }; +/* Virtual regulator representing the shared shutdown GPIO */ +/ { + speaker_sdz: fixed-regulator-sn012776-sdz { + compatible = "regulator-fixed"; + regulator-name = "sn012776-sdz"; + startup-delay-us = <5000>; + gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&i2c1 { + speaker_left_rear: codec@38 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x38>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Rear"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <8>; + ti,vmon-slot-no = <10>; + }; + + speaker_left_front: codec@39 { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x39>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Front"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; + ti,sdout-force-zero-mask = <0xf0f0>; + }; +}; + +&i2c3 { + speaker_right_rear: codec@3b { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3b>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Rear"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <12>; + ti,vmon-slot-no = <14>; + }; + + speaker_right_front: codec@3c { + compatible = "ti,sn012776", "ti,tas2764"; + reg = <0x3c>; + SDZ-supply = <&speaker_sdz>; + #sound-dai-cells = <0>; + sound-name-prefix = "Right Front"; + interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <4>; + ti,vmon-slot-no = <6>; + ti,sdout-force-zero-mask = <0x0f0f>; + }; + + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_nub 12 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + interrupts-extended = <&pinctrl_ap 149 IRQ_TYPE_LEVEL_LOW>; + sound-name-prefix = "Jack"; + }; +}; + &i2c4 { status = "okay"; }; @@ -149,6 +219,36 @@ }; }; +/ { + sound { + compatible = "apple,j493-macaudio", "apple,macaudio"; + model = "MacBook Pro J493"; + + dai-link@0 { + link-name = "Speakers"; + + cpu { + sound-dai = <&mca 0>, <&mca 1>; + }; + codec { + sound-dai = <&speaker_left_front>, <&speaker_left_rear>, + <&speaker_right_front>, <&speaker_right_rear>; + }; + }; + + dai-link@1 { + link-name = "Headphone Jack"; + + cpu { + sound-dai = <&mca 2>; + }; + codec { + sound-dai = <&jack_codec>; + }; + }; + }; +}; + &mtp { status = "okay"; }; From c109006e71d3ac3b5b7ab23b548a1cd67766de64 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 17 Oct 2022 18:29:28 +0900 Subject: [PATCH 010/352] arm64: dts: apple: t6001-j375c: Add USB3 hub GPIO initialization The Mac Studio M1 Max (t6001) model has a built-in USB3 hub. This hub has a firmware flash which is also connected to an AP SPI controller. The hub starts out in reset and the host is expected to bring it out of reset, potentially after upgrading/validating the firmware. We won't be doing anything with the firmware, so just use gpio-hog to flip the two GPIOs needed to bring up the hub chip. Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t6001-j375c.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts index a8694a94fa2793..fb7213e6f996ea 100644 --- a/arch/arm64/boot/dts/apple/t6001-j375c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts @@ -29,3 +29,19 @@ compatible = "apple,j375-macaudio", "apple,macaudio"; model = "Mac Studio J375"; }; + +&pinctrl_ap { + usb_hub_oe-hog { + gpio-hog; + gpios = <230 0>; + input; + line-name = "usb-hub-oe"; + }; + + usb_hub_rst-hog { + gpio-hog; + gpios = <231 GPIO_ACTIVE_LOW>; + output-low; + line-name = "usb-hub-rst"; + }; +}; From c934f13d9c18d3fc865df159321b648c6314e3a6 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 25 Jan 2022 21:50:59 +0100 Subject: [PATCH 011/352] arm64: apple: Add missing power state deps for display The dcp co-processor crashes on HDMI unplug while it apparently tries to notify pmp. Handle "notify_pmp" as a parent dependency for "ps_disp0_fe" and "ps_dispext_fe". Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi index 9bddd5bf866000..1969123490770c 100644 --- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi @@ -651,7 +651,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = "disp0_fe"; - power-domains = <&ps_rmx>; + power-domains = <&ps_rmx>, <&ps_pmp>; apple,always-on; /* TODO: figure out if we can enable PM here */ }; @@ -661,7 +661,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = "dispext_fe"; - power-domains = <&ps_rmx>; + power-domains = <&ps_rmx>, <&ps_pmp>; }; ps_dispext_cpu0: power-controller@378 { From f6a2a52e731d0f82b94c99513646d111734e8aca Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 24 Apr 2022 11:20:31 +0200 Subject: [PATCH 012/352] arm64: apple: t600x: Mark PCIe node as "dma-coherent" Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index f40d752d69a4a1..f35c109bcc3073 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -448,6 +448,8 @@ pinctrl-0 = <&pcie_pins>; pinctrl-names = "default"; + dma-coherent; + port00: pci@0,0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; From ccef05486ed08d6e50b8476bcda356e6eb277a17 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 19 Sep 2025 20:32:09 +0200 Subject: [PATCH 013/352] arm64: dts: apple: t8103: Mark pcie node as dma-coherent Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index da774096b6674b..892eb17cc7c6b5 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -1183,6 +1183,8 @@ pinctrl-0 = <&pcie_pins>; pinctrl-names = "default"; + dma-coherent; + port00: pci@0,0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; From b576a427af7b27c6d49c3a1bc0f094f742268d13 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 19 Sep 2025 20:32:09 +0200 Subject: [PATCH 014/352] arm64: dts: apple: t8112: Mark pcie node as dma-coherent Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index d439e429bf6835..2a69c6f1adad51 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1271,6 +1271,8 @@ pinctrl-0 = <&pcie_pins>; pinctrl-names = "default"; + dma-coherent; + port00: pci@0,0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; From ddf825af71263a77ff3288797f8f1a6d26997709 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 20 Sep 2021 02:27:09 +0900 Subject: [PATCH 015/352] arm64: apple: t8103: Add display controller related device tree nodes The display system is initialized by the bootloader to provide a simple framebuffer at startup. Memory for the framebuffer and heap for the display co-processor are alreay mapped through the IOMMU. IOMMU intialization must preserve this mappings to avoid crashing the display co-processor. The exisitng mappings are caried in the devicetree. They are applied during device attach to ensure the IOMMU framework is aware of these mapping. Mappings are filled by m1n1 during boot. Based on https://lore.kernel.org/asahi/20220923123557.866972-1-thierry.reding@gmail.com arch: arm64: apple: t8103: Add connector type property for DCP* arch: arm64: apple: Add dcp panel node for t8103 based laptops and imacs The panel node will contain among other properties backlight control related properties from the "backlight" node in the ADT. arm64: dts: apple: t8103: Add "ps_disp0_cpu0" as resets for dcp Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103-j274.dts | 4 ++ arch/arm64/boot/dts/apple/t8103-j293.dts | 14 ++++ arch/arm64/boot/dts/apple/t8103-j313.dts | 14 ++++ arch/arm64/boot/dts/apple/t8103-j456.dts | 14 ++++ arch/arm64/boot/dts/apple/t8103-j457.dts | 14 ++++ arch/arm64/boot/dts/apple/t8103-jxxx.dtsi | 10 +++ arch/arm64/boot/dts/apple/t8103.dtsi | 86 +++++++++++++++++++++++ 7 files changed, 156 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts index f3b7204618c8ce..2768a1d9ed7af0 100644 --- a/arch/arm64/boot/dts/apple/t8103-j274.dts +++ b/arch/arm64/boot/dts/apple/t8103-j274.dts @@ -22,6 +22,10 @@ }; }; +&dcp { + apple,connector-type = "HDMI-A"; +}; + &bluetooth0 { brcm,board-type = "apple,atlantisb"; }; diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts index 753c9c4d9adefc..50043beb65db0a 100644 --- a/arch/arm64/boot/dts/apple/t8103-j293.dts +++ b/arch/arm64/boot/dts/apple/t8103-j293.dts @@ -39,6 +39,20 @@ }; }; +&dcp { + panel: panel { + compatible = "apple,panel-j293", "apple,panel"; + width-mm = <286>; + height-mm = <179>; + apple,max-brightness = <525>; + }; +}; + +&framebuffer0 { + panel = <&panel>; + post-init-providers = <&panel>; +}; + &bluetooth0 { brcm,board-type = "apple,honshu"; }; diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts index 43620b57a63d2e..7e77fe091c6345 100644 --- a/arch/arm64/boot/dts/apple/t8103-j313.dts +++ b/arch/arm64/boot/dts/apple/t8103-j313.dts @@ -31,6 +31,20 @@ }; }; +&dcp { + panel: panel { + compatible = "apple,panel-j313", "apple,panel"; + width-mm = <286>; + height-mm = <179>; + apple,max-brightness = <420>; + }; +}; + +&framebuffer0 { + panel = <&panel>; + post-init-providers = <&panel>; +}; + &bluetooth0 { brcm,board-type = "apple,shikoku"; }; diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts index d277704b988bcc..0b89b44b12e6da 100644 --- a/arch/arm64/boot/dts/apple/t8103-j456.dts +++ b/arch/arm64/boot/dts/apple/t8103-j456.dts @@ -22,6 +22,20 @@ }; }; +&dcp { + panel: panel { + compatible = "apple,panel-j456", "apple,panel"; + width-mm = <522>; + height-mm = <294>; + apple,max-brightness = <525>; + }; +}; + +&framebuffer0 { + panel = <&panel>; + post-init-providers = <&panel>; +}; + &bluetooth0 { brcm,board-type = "apple,capri"; }; diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts index 2e7d344f88a54f..c1007dc4385e7c 100644 --- a/arch/arm64/boot/dts/apple/t8103-j457.dts +++ b/arch/arm64/boot/dts/apple/t8103-j457.dts @@ -22,6 +22,20 @@ }; }; +&dcp { + panel: panel { + compatible = "apple,panel-j457", "apple,panel"; + width-mm = <522>; + height-mm = <294>; + apple,max-brightness = <525>; + }; +}; + +&framebuffer0 { + panel = <&panel>; + post-init-providers = <&panel>; +}; + /* * Adjust pcie0's iommu-map to account for the disabled port01. */ diff --git a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi index 96121fdb8468c4..59558d9a511ae4 100644 --- a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi @@ -12,6 +12,9 @@ / { aliases { bluetooth0 = &bluetooth0; + dcp = &dcp; + disp0 = &display; + disp0_piodma = &disp0_piodma; serial0 = &serial0; serial2 = &serial2; wifi0 = &wifi0; @@ -34,6 +37,13 @@ }; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + /* To be filled by loader */ + }; + memory@800000000 { device_type = "memory"; reg = <0x8 0 0x2 0>; /* To be filled by loader */ diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 892eb17cc7c6b5..0e2591451f105d 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -346,6 +346,14 @@ clock-output-names = "clk_200m"; }; + /* Pixel clock? frequency in Hz (compare: 4K@60 VGA clock 533.250 MHz) */ + clk_disp0: clock-disp0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <533333328>; + clock-output-names = "clk_disp0"; + }; + /* * This is a fabulated representation of the input clock * to NCO since we don't know the true clock tree. @@ -493,6 +501,76 @@ }; }; + disp0_dart: iommu@231304000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x31304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + dcp_dart: iommu@23130c000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x3130c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + dcp_mbox: mbox@231c08000 { + compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x31c08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + resets = <&ps_disp0_cpu0>; + }; + + dcp: dcp@231c00000 { + compatible = "apple,t8103-dcp", "apple,dcp"; + mboxes = <&dcp_mbox>; + mbox-names = "mbox"; + iommus = <&dcp_dart 0>; + + reg-names = "coproc", "disp-0", "disp-1", "disp-2", + "disp-3", "disp-4"; + reg = <0x2 0x31c00000 0x0 0x4000>, + <0x2 0x30000000 0x0 0x3e8000>, + <0x2 0x31320000 0x0 0x4000>, + <0x2 0x31344000 0x0 0x4000>, + <0x2 0x31800000 0x0 0x800000>, + <0x2 0x3b3d0000 0x0 0x4000>; + apple,bw-scratch = <&pmgr_dcp 0 5 0x14>; + apple,bw-doorbell = <&pmgr_dcp 1 6>; + power-domains = <&ps_disp0_cpu0>; + resets = <&ps_disp0_cpu0>; + clocks = <&clk_disp0>; + apple,asc-dram-mask = <0xf 0x00000000>; + phandle = <&dcp>; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + disp0_piodma: piodma { + iommus = <&disp0_dart 4>; + phandle = <&disp0_piodma>; + }; + }; + + display: display-subsystem { + compatible = "apple,display-subsystem"; + iommus = <&disp0_dart 0>; + /* generate phandle explicitly for use in loader */ + phandle = <&display>; + }; + sio_dart: iommu@235004000 { compatible = "apple,t8103-dart"; reg = <0x2 0x35004000 0x0 0x4000>; @@ -730,6 +808,14 @@ reg = <0x2 0x3b700000 0 0x14000>; }; + pmgr_dcp: power-management@23b738000 { + reg = <0x2 0x3b738000 0x0 0x1000>, + <0x2 0x3bc3c000 0x0 0x1000>; + reg-names = "dcp-bw-scratch", "dcp-bw-doorbell"; + #apple,bw-scratch-cells = <3>; + #apple,bw-doorbell-cells = <2>; + }; + pinctrl_ap: pinctrl@23c100000 { compatible = "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x2 0x3c100000 0x0 0x100000>; From 550efbce91057eff915d508d7da581794dc1e50b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 11 Mar 2022 22:14:52 +0100 Subject: [PATCH 016/352] arm64: apple: t600x: Add display controller related device tree nodes The display system is initialized by the bootloader to provide a simple framebuffer at startup. Memory for the framebuffer and heap for the display co-processor are alreay mapped through the IOMMU. IOMMU intialization must preserve this mappings to avoid crashing the display co-processor. The exisitng mappings are caried in the devicetree. They are applied during device attach to ensure the IOMMU framework is aware of these mapping. Mappings are filled by m1n1 during boot. Based on https://lore.kernel.org/asahi/20220923123557.866972-1-thierry.reding@gmail.com arch: arm64: apple: t600x: Add connector type property for DCP* arch: arm64: apple: Add dcp panel node for t600x based laptops The panel node will contain among other properties backlight control related properties from the "backlight" node in the ADT. arm64: dts: apple: t600x: Add "ps_disp0_cpu0" as resets for dcp Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6000-j314s.dts | 7 ++ arch/arm64/boot/dts/apple/t6000-j316s.dts | 7 ++ arch/arm64/boot/dts/apple/t6001-j314c.dts | 7 ++ arch/arm64/boot/dts/apple/t6001-j316c.dts | 7 ++ arch/arm64/boot/dts/apple/t600x-common.dtsi | 6 ++ arch/arm64/boot/dts/apple/t600x-die0.dtsi | 72 +++++++++++++++++++ .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 10 +++ arch/arm64/boot/dts/apple/t600x-j375.dtsi | 7 ++ 8 files changed, 123 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6000-j314s.dts b/arch/arm64/boot/dts/apple/t6000-j314s.dts index dab8e99fa32496..ae79e3236614be 100644 --- a/arch/arm64/boot/dts/apple/t6000-j314s.dts +++ b/arch/arm64/boot/dts/apple/t6000-j314s.dts @@ -25,6 +25,13 @@ brcm,board-type = "apple,maldives"; }; +&panel { + compatible = "apple,panel-j314", "apple,panel-mini-led", "apple,panel"; + width-mm = <302>; + height-mm = <196>; + adj-height-mm = <189>; +}; + &sound { compatible = "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J314"; diff --git a/arch/arm64/boot/dts/apple/t6000-j316s.dts b/arch/arm64/boot/dts/apple/t6000-j316s.dts index 2cdfac3c40c842..272fa1c1712479 100644 --- a/arch/arm64/boot/dts/apple/t6000-j316s.dts +++ b/arch/arm64/boot/dts/apple/t6000-j316s.dts @@ -25,6 +25,13 @@ brcm,board-type = "apple,madagascar"; }; +&panel { + compatible = "apple,panel-j316", "apple,panel-mini-led", "apple,panel"; + width-mm = <346>; + height-mm = <223>; + adj-height-mm = <216>; +}; + &sound { compatible = "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J316"; diff --git a/arch/arm64/boot/dts/apple/t6001-j314c.dts b/arch/arm64/boot/dts/apple/t6001-j314c.dts index 7495698beb0258..81d34507ed81ff 100644 --- a/arch/arm64/boot/dts/apple/t6001-j314c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j314c.dts @@ -25,6 +25,13 @@ brcm,board-type = "apple,maldives"; }; +&panel { + compatible = "apple,panel-j314", "apple,panel-mini-led", "apple,panel"; + width-mm = <302>; + height-mm = <196>; + adj-height-mm = <189>; +}; + &sound { compatible = "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J314"; diff --git a/arch/arm64/boot/dts/apple/t6001-j316c.dts b/arch/arm64/boot/dts/apple/t6001-j316c.dts index 6622b6e225a600..564d927f2fecbd 100644 --- a/arch/arm64/boot/dts/apple/t6001-j316c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j316c.dts @@ -25,6 +25,13 @@ brcm,board-type = "apple,madagascar"; }; +&panel { + compatible = "apple,panel-j316", "apple,panel-mini-led", "apple,panel"; + width-mm = <346>; + height-mm = <223>; + adj-height-mm = <216>; +}; + &sound { compatible = "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J316"; diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi index e20234ef213538..186f0459d6b7e6 100644 --- a/arch/arm64/boot/dts/apple/t600x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi @@ -373,6 +373,12 @@ clock-output-names = "clk_200m"; }; + clk_disp0: clock-disp0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <237333328>; + clock-output-names = "clk_disp0"; + }; /* * This is a fabulated representation of the input clock * to NCO since we don't know the true clock tree. diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index f35c109bcc3073..519a099ffccf7d 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -24,6 +24,12 @@ power-domains = <&ps_aic>; }; + pmgr_dcp: power-management@28e3d0000 { + reg = <0x2 0x8e3d0000 0x0 0x4000>; + reg-names = "dcp-fw-pmgr"; + #apple,bw-scratch-cells = <3>; + }; + smc: smc@290400000 { compatible = "apple,t6000-smc", "apple,smc"; reg = <0x2 0x90400000 0x0 0x4000>, @@ -151,6 +157,72 @@ interrupts = ; }; + disp0_dart: iommu@38b304000 { + compatible = "apple,t6000-dart"; + reg = <0x3 0x8b304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + dcp_dart: iommu@38b30c000 { + compatible = "apple,t6000-dart"; + reg = <0x3 0x8b30c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + dcp_mbox: mbox@38bc08000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x8bc08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + }; + + dcp: dcp@38bc00000 { + compatible = "apple,t6000-dcp", "apple,dcp"; + mboxes = <&dcp_mbox>; + mbox-names = "mbox"; + iommus = <&dcp_dart 0>; + + reg-names = "coproc", "disp-0", "disp-1", "disp-2", "disp-3"; + reg = <0x3 0x8bc00000 0x0 0x4000>, + <0x3 0x8a000000 0x0 0x3000000>, + <0x3 0x8b320000 0x0 0x4000>, + <0x3 0x8b344000 0x0 0x4000>, + <0x3 0x8b800000 0x0 0x800000>; + apple,bw-scratch = <&pmgr_dcp 0 4 0x988>; + power-domains = <&ps_disp0_cpu0>; + resets = <&ps_disp0_cpu0>; + clocks = <&clk_disp0>; + apple,asc-dram-mask = <0x1f0 0x00000000>; + phandle = <&dcp>; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + disp0_piodma: piodma { + iommus = <&disp0_dart 4>; + phandle = <&disp0_piodma>; + }; + }; + + display: display-subsystem { + compatible = "apple,display-subsystem"; + iommus = <&disp0_dart 0>; + /* generate phandle explicitly for use in loader */ + phandle = <&display>; + }; + sio_dart_0: iommu@39b004000 { compatible = "apple,t6000-dart"; reg = <0x3 0x9b004000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 6ebaabe49a8130..a6530d5db4d872 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -20,6 +20,9 @@ atcphy2 = &atcphy2; atcphy3 = &atcphy3; bluetooth0 = &bluetooth0; + dcp = &dcp; + disp0 = &display; + disp0_piodma = &disp0_piodma; serial0 = &serial0; wifi0 = &wifi0; }; @@ -36,6 +39,7 @@ reg = <0 0 0 0>; /* To be filled by loader */ /* Format properties will be added by loader */ status = "disabled"; + panel = &panel; }; }; @@ -61,6 +65,12 @@ status = "okay"; }; +&dcp { + panel: panel { + apple,max-brightness = <500>; + }; +}; + /* USB Type C */ &i2c0 { hpm0: usb-pd@38 { diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi index 65b2abd521b10c..0bd2ae5bd802b1 100644 --- a/arch/arm64/boot/dts/apple/t600x-j375.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi @@ -18,6 +18,9 @@ atcphy2 = &atcphy2; atcphy3 = &atcphy3; bluetooth0 = &bluetooth0; + dcp = &dcp; + disp0 = &display; + disp0_piodma = &disp0_piodma; ethernet0 = ðernet0; serial0 = &serial0; wifi0 = &wifi0; @@ -48,6 +51,10 @@ status = "okay"; }; +&dcp { + apple,connector-type = "HDMI-A"; +}; + /* USB Type C */ &i2c0 { hpm0: usb-pd@38 { From 09860b16c1f43ab4c68ab08ae5afdb3e60e13412 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 20 Nov 2022 20:22:57 +0100 Subject: [PATCH 017/352] arm64: dts: apple: t8112: Add dcp/disp0 nodes arm64: dts: apple: t8112: Add "ps_disp0_cpu0" as resets for dcp arm64: dts: apple: t8112-j473: Add dptx-phy power-domain The HDMI output used by framebuffer0 requires the display controller and external DP phy power-domains to remain active. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j413.dts | 15 ++++ arch/arm64/boot/dts/apple/t8112-j415.dts | 15 ++++ arch/arm64/boot/dts/apple/t8112-j473.dts | 9 +++ arch/arm64/boot/dts/apple/t8112-j493.dts | 14 ++++ arch/arm64/boot/dts/apple/t8112-jxxx.dtsi | 3 + arch/arm64/boot/dts/apple/t8112.dtsi | 83 +++++++++++++++++++++++ 6 files changed, 139 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts index f6450ef3a0c6e1..0077ce45cc5154 100644 --- a/arch/arm64/boot/dts/apple/t8112-j413.dts +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts @@ -37,6 +37,21 @@ }; }; +&dcp { + panel: panel { + compatible = "apple,panel-j413", "apple,panel"; + width-mm = <290>; + height-mm = <189>; + adj-height-mm = <181>; + apple,max-brightness = <525>; + }; +}; + +&framebuffer0 { + panel = <&panel>; + post-init-providers = <&panel>; +}; + /* * Force the bus number assignments so that we can declare some of the * on-board devices and properties that are populated by the bootloader diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts index 2c969eb767a7d8..09387fc5ca46f0 100644 --- a/arch/arm64/boot/dts/apple/t8112-j415.dts +++ b/arch/arm64/boot/dts/apple/t8112-j415.dts @@ -37,6 +37,21 @@ }; }; +&dcp { + panel: panel { + compatible = "apple,panel-j415", "apple,panel"; + width-mm = <327>; + height-mm = <211>; + adj-height-mm = <204>; + apple,max-brightness = <500>; + }; +}; + +&framebuffer0 { + panel = <&panel>; + post-init-providers = <&panel>; +}; + /* * Force the bus number assignments so that we can declare some of the * on-board devices and properties that are populated by the bootloader diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts index effdfae8646949..6d8eb2114415c6 100644 --- a/arch/arm64/boot/dts/apple/t8112-j473.dts +++ b/arch/arm64/boot/dts/apple/t8112-j473.dts @@ -24,6 +24,15 @@ }; }; +&framebuffer0 { + power-domains = <&ps_disp0_cpu0>, <&ps_dptx_ext_phy>; +}; + +/* disable dcp until it is supported */ +&dcp { + status = "disabled"; +}; + /* * Keep the power-domains used for the HDMI port on. */ diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts index d25794fd88e355..03cb807cf59d71 100644 --- a/arch/arm64/boot/dts/apple/t8112-j493.dts +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts @@ -52,6 +52,20 @@ apple,always-on; }; +&dcp { + panel: panel { + compatible = "apple,panel-j493", "apple,panel"; + width-mm = <286>; + height-mm = <179>; + apple,max-brightness = <525>; + }; +}; + +&framebuffer0 { + panel = <&panel>; + post-init-providers = <&panel>; +}; + &display_dfr { status = "okay"; }; diff --git a/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi index 562e7a25a1e884..98f2d6af828d2d 100644 --- a/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi @@ -13,6 +13,9 @@ aliases { atcphy0 = &atcphy0; atcphy1 = &atcphy1; + dcp = &dcp; + disp0 = &display; + disp0_piodma = &disp0_piodma; serial0 = &serial0; serial2 = &serial2; }; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 2a69c6f1adad51..c447203540e6e3 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -371,6 +371,14 @@ clock-output-names = "nco_ref"; }; + /* Pixel clock? frequency in Hz (compare: 4K@60 VGA clock 533.250 MHz) */ + clk_disp0: clock-disp0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <533333328>; + clock-output-names = "clk_disp0"; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -508,6 +516,75 @@ }; }; + disp0_dart: iommu@231304000 { + compatible = "apple,t8112-dart", "apple,t8110-dart"; + reg = <0x2 0x31304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + dcp_dart: iommu@23130c000 { + compatible = "apple,t8112-dart", "apple,t8110-dart"; + reg = <0x2 0x3130c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + dcp_mbox: mbox@231c08000 { + compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x31c08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + resets = <&ps_disp0_cpu0>; + }; + + dcp: dcp@231c00000 { + compatible = "apple,t8112-dcp", "apple,dcp"; + mboxes = <&dcp_mbox>; + mbox-names = "mbox"; + iommus = <&dcp_dart 5>; + + /* the ADT has 2 additional regs which seems to be unused */ + reg-names = "coproc", "disp-0", "disp-1", "disp-2", "disp-3"; + reg = <0x2 0x31c00000 0x0 0x4000>, + <0x2 0x30000000 0x0 0x61c000>, + <0x2 0x31320000 0x0 0x4000>, + <0x2 0x31344000 0x0 0x4000>, + <0x2 0x31800000 0x0 0x800000>; + apple,bw-scratch = <&pmgr_dcp 0 4 0x5d8>; + power-domains = <&ps_disp0_cpu0>; + resets = <&ps_disp0_cpu0>; + clocks = <&clk_disp0>; + apple,asc-dram-mask = <0x0 0x0>; + phandle = <&dcp>; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + disp0_piodma: piodma { + iommus = <&disp0_dart 4>; + phandle = <&disp0_piodma>; + }; + }; + + display: display-subsystem { + compatible = "apple,display-subsystem"; + /* disp_dart0 must be 1st since it is locked */ + iommus = <&disp0_dart 0>; + /* generate phandle explicitly for use in loader */ + phandle = <&display>; + }; + sio_dart: iommu@235004000 { compatible = "apple,t8110-dart"; reg = <0x2 0x35004000 0x0 0x4000>; @@ -729,6 +806,12 @@ }; }; + pmgr_dcp: power-management@23b3d0000 { + reg = <0x2 0x3b3d0000 0x0 0x4000>; + reg-names = "dcp-bw-scratch"; + #apple,bw-scratch-cells = <3>; + }; + pmgr: power-management@23b700000 { compatible = "apple,t8112-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; From 57718405518b799baaeccb01e7d74ccbc085f977 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 13 Dec 2022 00:17:35 +0900 Subject: [PATCH 018/352] arm64: dts: apple: t600x: Add DCP power domain to missing devices Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 2 ++ arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 4 +++- arch/arm64/boot/dts/apple/t600x-j375.dtsi | 1 + arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 2 -- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 519a099ffccf7d..f8d5dde1bf6c42 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -164,6 +164,7 @@ interrupt-parent = <&aic>; interrupts = ; status = "disabled"; + power-domains = <&ps_disp0_cpu0>; }; dcp_dart: iommu@38b30c000 { @@ -172,6 +173,7 @@ #iommu-cells = <1>; interrupt-parent = <&aic>; interrupts = ; + power-domains = <&ps_disp0_cpu0>; }; dcp_mbox: mbox@38bc08000 { diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index a6530d5db4d872..c17a77bacd43ed 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -39,7 +39,9 @@ reg = <0 0 0 0>; /* To be filled by loader */ /* Format properties will be added by loader */ status = "disabled"; - panel = &panel; + panel = <&panel>; + post-init-providers = <&panel>; + power-domains = <&ps_disp0_cpu0>; }; }; diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi index 0bd2ae5bd802b1..30d549bc32f820 100644 --- a/arch/arm64/boot/dts/apple/t600x-j375.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi @@ -38,6 +38,7 @@ reg = <0 0 0 0>; /* To be filled by loader */ /* Format properties will be added by loader */ status = "disabled"; + power-domains = <&ps_disp0_cpu0>; }; }; diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index cc2627eafc899d..3f507cbc65f0c8 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -1297,7 +1297,6 @@ #reset-cells = <0>; label = DIE_LABEL(disp0_fe); power-domains = <&DIE_NODE(ps_afnc2_lw0)>; - apple,always-on; /* TODO: figure out if we can enable PM here */ }; DIE_NODE(ps_disp0_cpu0): power-controller@350 { @@ -1307,7 +1306,6 @@ #reset-cells = <0>; label = DIE_LABEL(disp0_cpu0); power-domains = <&DIE_NODE(ps_disp0_fe)>; - apple,always-on; /* TODO: figure out if we can enable PM here */ apple,min-state = <4>; }; From c14a75114b4857242f2d416593df06de0deb86b4 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 13 Dec 2022 00:17:35 +0900 Subject: [PATCH 019/352] arm64: dts: apple: t8103: Add DCP power domain to missing devices Removes the "apple,always-on" property from ps_disp0_fe/cpu0. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103-jxxx.dtsi | 1 + arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 2 -- arch/arm64/boot/dts/apple/t8103.dtsi | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi index 59558d9a511ae4..7ca9da15c8171d 100644 --- a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi @@ -32,6 +32,7 @@ framebuffer0: framebuffer@0 { compatible = "apple,simple-framebuffer", "simple-framebuffer"; reg = <0 0 0 0>; /* To be filled by loader */ + power-domains = <&ps_disp0_cpu0>; /* Format properties will be added by loader */ status = "disabled"; }; diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi index 1969123490770c..f0ae11bf6ce688 100644 --- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi @@ -652,7 +652,6 @@ #reset-cells = <0>; label = "disp0_fe"; power-domains = <&ps_rmx>, <&ps_pmp>; - apple,always-on; /* TODO: figure out if we can enable PM here */ }; ps_dispext_fe: power-controller@368 { @@ -1008,7 +1007,6 @@ #reset-cells = <0>; label = "disp0_cpu0"; power-domains = <&ps_disp0_fe>; - apple,always-on; /* TODO: figure out if we can enable PM here */ apple,min-state = <4>; }; }; diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 0e2591451f105d..416c9d42040587 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -507,6 +507,7 @@ #iommu-cells = <1>; interrupt-parent = <&aic>; interrupts = ; + power-domains = <&ps_disp0_cpu0>; status = "disabled"; }; @@ -516,6 +517,7 @@ #iommu-cells = <1>; interrupt-parent = <&aic>; interrupts = ; + power-domains = <&ps_disp0_cpu0>; }; dcp_mbox: mbox@231c08000 { From 975f5a9e702253f820de12be89b92d1de8def55f Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 13 Dec 2022 00:17:35 +0900 Subject: [PATCH 020/352] arm64: dts: apple: t8112: Add DCP power domain to missing devices Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-jxxx.dtsi | 1 + arch/arm64/boot/dts/apple/t8112-pmgr.dtsi | 2 -- arch/arm64/boot/dts/apple/t8112.dtsi | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi index 98f2d6af828d2d..35565dbf535381 100644 --- a/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi @@ -30,6 +30,7 @@ framebuffer0: framebuffer@0 { compatible = "apple,simple-framebuffer", "simple-framebuffer"; reg = <0 0 0 0>; /* To be filled by loader */ + power-domains = <&ps_disp0_cpu0>; /* Format properties will be added by loader */ status = "disabled"; }; diff --git a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi index 8b3297d75992d3..276f1ab35f06a3 100644 --- a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi @@ -669,7 +669,6 @@ #reset-cells = <0>; label = "disp0_sys"; power-domains = <&ps_rmx1>; - apple,always-on; /* TODO: figure out if we can enable PM here */ }; ps_disp0_fe: power-controller@378 { @@ -679,7 +678,6 @@ #reset-cells = <0>; label = "disp0_fe"; power-domains = <&ps_disp0_sys>, <&ps_pmp>; - apple,always-on; /* TODO: figure out if we can enable PM here */ }; ps_dispext_sys: power-controller@380 { diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index c447203540e6e3..e406f616eeb550 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -522,6 +522,7 @@ #iommu-cells = <1>; interrupt-parent = <&aic>; interrupts = ; + power-domains = <&ps_disp0_cpu0>; status = "disabled"; }; @@ -531,6 +532,7 @@ #iommu-cells = <1>; interrupt-parent = <&aic>; interrupts = ; + power-domains = <&ps_disp0_cpu0>; }; dcp_mbox: mbox@231c08000 { From f251c862aee45222a2abf14ce01868285d7bde6b Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 2 Nov 2022 15:58:07 +0900 Subject: [PATCH 021/352] scripts/dtc: Add support for floating-point literals Signed-off-by: Asahi Lina --- scripts/dtc/data.c | 27 +++++++++++++++++++++++++++ scripts/dtc/dtc-lexer.l | 22 ++++++++++++++++++++++ scripts/dtc/dtc-parser.y | 16 ++++++++++++++++ scripts/dtc/dtc.h | 1 + 4 files changed, 66 insertions(+) diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index 5b25aa06041613..ce449824c80a06 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -184,6 +184,33 @@ struct data data_append_integer(struct data d, uint64_t value, int bits) } } +struct data data_append_float(struct data d, double value, int bits) +{ + float f32; + uint32_t u32; + double f64; + uint64_t u64; + fdt32_t value_32; + fdt64_t value_64; + + switch (bits) { + case 32: + f32 = value; + memcpy(&u32, &f32, sizeof(u32)); + value_32 = cpu_to_fdt32(u32); + return data_append_data(d, &value_32, 4); + + case 64: + f64 = value; + memcpy(&u64, &f64, sizeof(u64)); + value_64 = cpu_to_fdt64(u64); + return data_append_data(d, &value_64, 8); + + default: + die("Invalid literal size (%d)\n", bits); + } +} + struct data data_append_re(struct data d, uint64_t address, uint64_t size) { struct fdt_reserve_entry re; diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index 15d585c8079802..bd750717aa3a54 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -151,6 +151,28 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); return DT_LABEL; } +[-+]?(([0-9]+\.[0-9]*)|([0-9]*\.[0-9]+))(e[-+]?[0-9]+)?f? { + char *e; + DPRINT("Floating-point Literal: '%s'\n", yytext); + + errno = 0; + yylval.floating = strtod(yytext, &e); + + if (*e && (*e != 'f' || e[1])) { + lexical_error("Bad floating-point literal '%s'", + yytext); + } + + if (errno == ERANGE) + lexical_error("Floating-point literal '%s' out of range", + yytext); + else + /* ERANGE is the only strtod error triggerable + * by strings matching the pattern */ + assert(errno == 0); + return DT_FP_LITERAL; + } + {LABEL} { /* Missed includes or macro definitions while * preprocessing can lead to unexpected identifiers in diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 4d5eece5262434..225a6b41b14fcf 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -48,6 +48,7 @@ static bool is_ref_relative(const char *ref) struct node *nodelist; struct reserve_info *re; uint64_t integer; + double floating; unsigned int flags; } @@ -61,6 +62,7 @@ static bool is_ref_relative(const char *ref) %token DT_OMIT_NO_REF %token DT_PROPNODENAME %token DT_LITERAL +%token DT_FP_LITERAL %token DT_CHAR_LITERAL %token DT_BYTE %token DT_STRING @@ -86,6 +88,7 @@ static bool is_ref_relative(const char *ref) %type subnode %type subnodes +%type floating_prim %type integer_prim %type integer_unary %type integer_mul @@ -395,6 +398,15 @@ arrayprefix: $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL); $$.bits = 32; } + | arrayprefix floating_prim + { + if ($1.bits < 32) { + ERROR(&@2, "Floating-point values must be" + " 32-bit or 64-bit"); + } + + $$.data = data_append_float($1.data, $2, $1.bits); + } | arrayprefix integer_prim { if ($1.bits < 64) { @@ -439,6 +451,10 @@ arrayprefix: } ; +floating_prim: + DT_FP_LITERAL + ; + integer_prim: DT_LITERAL | DT_CHAR_LITERAL diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 7231200e5d02cc..6f29281e12305d 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -177,6 +177,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m, struct data data_merge(struct data d1, struct data d2); struct data data_append_cell(struct data d, cell_t word); struct data data_append_integer(struct data d, uint64_t word, int bits); +struct data data_append_float(struct data d, double value, int bits); struct data data_append_re(struct data d, uint64_t address, uint64_t size); struct data data_append_addr(struct data d, uint64_t addr); struct data data_append_byte(struct data d, uint8_t byte); From a7b5f88e02052b00bf92bace09941ba0888513fa Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Thu, 18 Aug 2022 02:15:43 +0900 Subject: [PATCH 022/352] arm64: dts: apple: t8103: Add downstream gpu properties to be dropped Signed-off-by: Asahi Lina --- arch/arm64/boot/dts/apple/t8103-j274.dts | 4 ++ arch/arm64/boot/dts/apple/t8103-j456.dts | 4 ++ arch/arm64/boot/dts/apple/t8103-j457.dts | 4 ++ arch/arm64/boot/dts/apple/t8103.dtsi | 86 ++++++++++++++++++++++-- 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts index 2768a1d9ed7af0..9396c8a010ab3d 100644 --- a/arch/arm64/boot/dts/apple/t8103-j274.dts +++ b/arch/arm64/boot/dts/apple/t8103-j274.dts @@ -131,3 +131,7 @@ }; }; + +&gpu { + apple,perf-base-pstate = <3>; +}; diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts index 0b89b44b12e6da..c384d4dfd19a36 100644 --- a/arch/arm64/boot/dts/apple/t8103-j456.dts +++ b/arch/arm64/boot/dts/apple/t8103-j456.dts @@ -133,3 +133,7 @@ }; }; }; + +&gpu { + apple,perf-base-pstate = <3>; +}; diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts index c1007dc4385e7c..28e3eedfc35bf6 100644 --- a/arch/arm64/boot/dts/apple/t8103-j457.dts +++ b/arch/arm64/boot/dts/apple/t8103-j457.dts @@ -114,3 +114,7 @@ }; }; }; + +&gpu { + apple,perf-base-pstate = <3>; +}; diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 416c9d42040587..748724a2a9c1a7 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -303,6 +303,50 @@ #endif }; + gpu_opp: opp-table-gpu { + compatible = "operating-points-v2"; + + /* + * NOTE: The voltage and power values are device-specific and + * must be filled in by the bootloader. + */ + opp00 { + opp-hz = /bits/ 64 <0>; + opp-microvolt = <400000>; + opp-microwatt = <0>; + }; + opp01 { + opp-hz = /bits/ 64 <396000000>; + opp-microvolt = <603000>; + opp-microwatt = <3714690>; + }; + opp02 { + opp-hz = /bits/ 64 <528000000>; + opp-microvolt = <640000>; + opp-microwatt = <5083260>; + }; + opp03 { + opp-hz = /bits/ 64 <720000000>; + opp-microvolt = <690000>; + opp-microwatt = <7429380>; + }; + opp04 { + opp-hz = /bits/ 64 <924000000>; + opp-microvolt = <784000>; + opp-microwatt = <11730600>; + }; + opp05 { + opp-hz = /bits/ 64 <1128000000>; + opp-microvolt = <862000>; + opp-microwatt = <17009370>; + }; + opp06 { + opp-hz = /bits/ 64 <1278000000>; + opp-microvolt = <931000>; + opp-microwatt = <19551000>; + }; + }; + timer { compatible = "arm,armv8-timer"; interrupt-parent = <&aic>; @@ -382,15 +426,15 @@ }; uat_handoff: uat-handoff { - status = "disabled"; + reg = <0 0 0 0>; }; uat_pagetables: uat-pagetables { - status = "disabled"; + reg = <0 0 0 0>; }; uat_ttbs: uat-ttbs { - status = "disabled"; + reg = <0 0 0 0>; }; }; @@ -403,7 +447,7 @@ nonposted-mmio; gpu: gpu@206400000 { - compatible = "apple,agx-g13g"; + compatible = "apple,agx-t8103", "apple,agx-g13g"; reg = <0x2 0x6400000 0 0x40000>, <0x2 0x4000000 0 0x1000000>; reg-names = "asc", "sgx"; @@ -415,6 +459,40 @@ "hw-cal-a", "hw-cal-b", "globals"; apple,firmware-abi = <0 0 0>; + + apple,firmware-version = <12 3 0>; + apple,firmware-compat = <12 3 0>; + + operating-points-v2 = <&gpu_opp>; + apple,perf-base-pstate = <1>; + apple,min-sram-microvolt = <850000>; + apple,avg-power-filter-tc-ms = <1000>; + apple,avg-power-ki-only = <7.5>; + apple,avg-power-kp = <4.0>; + apple,avg-power-min-duty-cycle = <40>; + apple,avg-power-target-filter-tc = <125>; + apple,fast-die0-integral-gain = <200.0>; + apple,fast-die0-proportional-gain = <5.0>; + apple,perf-filter-drop-threshold = <0>; + apple,perf-filter-time-constant = <5>; + apple,perf-filter-time-constant2 = <50>; + apple,perf-integral-gain2 = <0.197392>; + apple,perf-integral-min-clamp = <0>; + apple,perf-proportional-gain2 = <6.853981>; + apple,perf-tgt-utilization = <85>; + apple,power-sample-period = <8>; + apple,power-zones = <30000 100 6875>; + apple,ppm-filter-time-constant-ms = <100>; + apple,ppm-ki = <91.5>; + apple,ppm-kp = <6.9>; + apple,pwr-filter-time-constant = <313>; + apple,pwr-integral-gain = <0.0202129>; + apple,pwr-integral-min-clamp = <0>; + apple,pwr-min-duty-cycle = <40>; + apple,pwr-proportional-gain = <5.2831855>; + + apple,core-leak-coef = <1000.0>; + apple,sram-leak-coef = <45.0>; }; agx_mbox: mbox@206408000 { From 062e975c4b48235c34879792559703520e459f2d Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Thu, 3 Nov 2022 01:03:44 +0900 Subject: [PATCH 023/352] arm64: dts: apple: t600x: Add downstream gpu properties to be dropped Signed-off-by: Asahi Lina --- arch/arm64/boot/dts/apple/t6000.dtsi | 4 +- arch/arm64/boot/dts/apple/t6001-j375c.dts | 9 ++++ arch/arm64/boot/dts/apple/t6001.dtsi | 6 ++- arch/arm64/boot/dts/apple/t6002-j375d.dts | 9 ++++ arch/arm64/boot/dts/apple/t6002.dtsi | 6 ++- arch/arm64/boot/dts/apple/t600x-common.dtsi | 50 +++++++++++++++++++-- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 37 +++++++++++++++ 7 files changed, 115 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6000.dtsi b/arch/arm64/boot/dts/apple/t6000.dtsi index 0ad77c98073fe6..c9e4e52d9aac92 100644 --- a/arch/arm64/boot/dts/apple/t6000.dtsi +++ b/arch/arm64/boot/dts/apple/t6000.dtsi @@ -9,6 +9,8 @@ /* This chip is just a cut down version of t6001, so include it and disable the missing parts */ +#define GPU_REPEAT(x) + #include "t6001.dtsi" / { @@ -18,5 +20,5 @@ /delete-node/ &pmgr_south; &gpu { - compatible = "apple,agx-g13s"; + compatible = "apple,agx-t6000", "apple,agx-g13x"; }; diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts index fb7213e6f996ea..68e2b120117840 100644 --- a/arch/arm64/boot/dts/apple/t6001-j375c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts @@ -45,3 +45,12 @@ line-name = "usb-hub-rst"; }; }; + +&gpu { + apple,avg-power-ki-only = <0.6375>; + apple,avg-power-kp = <0.58>; + apple,avg-power-target-filter-tc = <1>; + apple,perf-base-pstate = <3>; + apple,ppm-ki = <5.8>; + apple,ppm-kp = <0.355>; +}; diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi index 6dcb71a1d65a8d..9dffa61db0cef5 100644 --- a/arch/arm64/boot/dts/apple/t6001.dtsi +++ b/arch/arm64/boot/dts/apple/t6001.dtsi @@ -16,6 +16,10 @@ #include "multi-die-cpp.h" +#ifndef GPU_REPEAT +# define GPU_REPEAT(x) +#endif + #include "t600x-common.dtsi" / { @@ -65,5 +69,5 @@ }; &gpu { - compatible = "apple,agx-g13c", "apple,agx-g13s"; + compatible = "apple,agx-t6001", "apple,agx-g13c", "apple,agx-g13s"; }; diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts index 65743fea3f1068..c04597225b6ade 100644 --- a/arch/arm64/boot/dts/apple/t6002-j375d.dts +++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts @@ -211,3 +211,12 @@ /delete-node/ &ps_disp0_cpu0_die1; /delete-node/ &ps_disp0_fe_die1; + +&gpu { + apple,avg-power-ki-only = <0.6375>; + apple,avg-power-kp = <0.58>; + apple,avg-power-target-filter-tc = <1>; + apple,perf-base-pstate = <3>; + apple,ppm-ki = <5.8>; + apple,ppm-kp = <0.355>; +}; diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi index a532e5401c4ec4..ce88211c0c22da 100644 --- a/arch/arm64/boot/dts/apple/t6002.dtsi +++ b/arch/arm64/boot/dts/apple/t6002.dtsi @@ -16,6 +16,10 @@ #include "multi-die-cpp.h" +#ifndef GPU_REPEAT +# define GPU_REPEAT(x) +#endif + #include "t600x-common.dtsi" / { @@ -303,5 +307,5 @@ }; &gpu { - compatible = "apple,agx-g13d", "apple,agx-g13s"; + compatible = "apple,agx-t6002", "apple,agx-g13d", "apple,agx-g13s"; }; diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi index 186f0459d6b7e6..5e54b03cf142f0 100644 --- a/arch/arm64/boot/dts/apple/t600x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi @@ -337,6 +337,50 @@ */ }; + gpu_opp: opp-table-gpu { + compatible = "operating-points-v2"; + + /* + * NOTE: The voltage and power values are device-specific and + * must be filled in by the bootloader. + */ + opp00 { + opp-hz = /bits/ 64 <0>; + opp-microvolt = GPU_REPEAT(400000); + opp-microwatt = <0>; + }; + opp01 { + opp-hz = /bits/ 64 <388800000>; + opp-microvolt = GPU_REPEAT(634000); + opp-microwatt = <25011450>; + }; + opp02 { + opp-hz = /bits/ 64 <486000000>; + opp-microvolt = GPU_REPEAT(650000); + opp-microwatt = <31681170>; + }; + opp03 { + opp-hz = /bits/ 64 <648000000>; + opp-microvolt = GPU_REPEAT(668000); + opp-microwatt = <41685750>; + }; + opp04 { + opp-hz = /bits/ 64 <777600000>; + opp-microvolt = GPU_REPEAT(715000); + opp-microwatt = <56692620>; + }; + opp05 { + opp-hz = /bits/ 64 <972000000>; + opp-microvolt = GPU_REPEAT(778000); + opp-microwatt = <83371500>; + }; + opp06 { + opp-hz = /bits/ 64 <1296000000>; + opp-microvolt = GPU_REPEAT(903000); + opp-microwatt = <166743000>; + }; + }; + pmu-e { compatible = "apple,icestorm-pmu"; interrupt-parent = <&aic>; @@ -407,15 +451,15 @@ }; uat_handoff: uat-handoff { - status = "disabled"; + reg = <0 0 0 0>; }; uat_pagetables: uat-pagetables { - status = "disabled"; + reg = <0 0 0 0>; }; uat_ttbs: uat-ttbs { - status = "disabled"; + reg = <0 0 0 0>; }; }; }; diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index f8d5dde1bf6c42..f5b4d85a61186a 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -430,6 +430,43 @@ "hw-cal-a", "hw-cal-b", "globals"; apple,firmware-abi = <0 0 0>; + + apple,firmware-version = <12 3 0>; + apple,firmware-compat = <12 3 0>; + + operating-points-v2 = <&gpu_opp>; + apple,perf-base-pstate = <1>; + apple,min-sram-microvolt = <790000>; + apple,avg-power-filter-tc-ms = <1000>; + apple,avg-power-ki-only = <2.4>; + apple,avg-power-kp = <1.5>; + apple,avg-power-min-duty-cycle = <40>; + apple,avg-power-target-filter-tc = <125>; + apple,fast-die0-integral-gain = <500.0>; + apple,fast-die0-proportional-gain = <72.0>; + apple,perf-boost-ce-step = <50>; + apple,perf-boost-min-util = <90>; + apple,perf-filter-drop-threshold = <0>; + apple,perf-filter-time-constant = <5>; + apple,perf-filter-time-constant2 = <50>; + apple,perf-integral-gain = <6.3>; + apple,perf-integral-gain2 = <0.197392>; + apple,perf-integral-min-clamp = <0>; + apple,perf-proportional-gain = <15.75>; + apple,perf-proportional-gain2 = <6.853981>; + apple,perf-tgt-utilization = <85>; + apple,power-sample-period = <8>; + apple,ppm-filter-time-constant-ms = <100>; + apple,ppm-ki = <30.0>; + apple,ppm-kp = <1.5>; + apple,pwr-filter-time-constant = <313>; + apple,pwr-integral-gain = <0.0202129>; + apple,pwr-integral-min-clamp = <0>; + apple,pwr-min-duty-cycle = <40>; + apple,pwr-proportional-gain = <5.2831855>; + + apple,core-leak-coef = GPU_REPEAT(1200.0); + apple,sram-leak-coef = GPU_REPEAT(20.0); }; agx_mbox: mbox@406408000 { From b508a223270b8be14eb61525ce5f67eb8290f1d2 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 25 Nov 2022 23:06:59 +0900 Subject: [PATCH 024/352] arm64: dts: apple: t8112: Add downstream gpu properties to be dropped Signed-off-by: Asahi Lina --- arch/arm64/boot/dts/apple/t8112-j473.dts | 4 + arch/arm64/boot/dts/apple/t8112.dtsi | 93 +++++++++++++++++++++++- 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts index 6d8eb2114415c6..cf24579ca7b325 100644 --- a/arch/arm64/boot/dts/apple/t8112-j473.dts +++ b/arch/arm64/boot/dts/apple/t8112-j473.dts @@ -167,3 +167,7 @@ }; }; + +&gpu { + apple,perf-base-pstate = <3>; +}; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index e406f616eeb550..7d9027a966f8c4 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -325,6 +325,60 @@ #endif }; + gpu_opp: opp-table-gpu { + compatible = "operating-points-v2"; + + /* + * NOTE: The voltage and power values are device-specific and + * must be filled in by the bootloader. + */ + opp00 { + opp-hz = /bits/ 64 <0>; + opp-microvolt = <400000>; + opp-microwatt = <0>; + }; + opp01 { + opp-hz = /bits/ 64 <444000000>; + opp-microvolt = <603000>; + opp-microwatt = <4295000>; + }; + opp02 { + opp-hz = /bits/ 64 <612000000>; + opp-microvolt = <675000>; + opp-microwatt = <6251000>; + }; + opp03 { + opp-hz = /bits/ 64 <808000000>; + opp-microvolt = <710000>; + opp-microwatt = <8625000>; + }; + opp04 { + opp-hz = /bits/ 64 <968000000>; + opp-microvolt = <775000>; + opp-microwatt = <11948000>; + }; + opp05 { + opp-hz = /bits/ 64 <1110000000>; + opp-microvolt = <820000>; + opp-microwatt = <15071000>; + }; + opp06 { + opp-hz = /bits/ 64 <1236000000>; + opp-microvolt = <875000>; + opp-microwatt = <18891000>; + }; + opp07 { + opp-hz = /bits/ 64 <1338000000>; + opp-microvolt = <915000>; + opp-microwatt = <21960000>; + }; + opp08 { + opp-hz = /bits/ 64 <1398000000>; + opp-microvolt = <950000>; + opp-microwatt = <22800000>; + }; + }; + timer { compatible = "arm,armv8-timer"; interrupt-parent = <&aic>; @@ -397,15 +451,15 @@ }; uat_handoff: uat-handoff { - status = "disabled"; + reg = <0 0 0 0>; }; uat_pagetables: uat-pagetables { - status = "disabled"; + reg = <0 0 0 0>; }; uat_ttbs: uat-ttbs { - status = "disabled"; + reg = <0 0 0 0>; }; }; @@ -418,7 +472,7 @@ nonposted-mmio; gpu: gpu@206400000 { - compatible = "apple,agx-g14g"; + compatible = "apple,agx-t8112", "apple,agx-g14g"; reg = <0x2 0x6400000 0 0x40000>, <0x2 0x4000000 0 0x1000000>; reg-names = "asc", "sgx"; @@ -430,6 +484,37 @@ "hw-cal-a", "hw-cal-b", "globals"; apple,firmware-abi = <0 0 0>; + apple,firmware-version = <12 4 0>; + apple,firmware-compat = <12 4 0>; + + operating-points-v2 = <&gpu_opp>; + apple,perf-base-pstate = <1>; + apple,min-sram-microvolt = <780000>; + apple,avg-power-filter-tc-ms = <300>; + apple,avg-power-ki-only = <9.375>; + apple,avg-power-kp = <3.22>; + apple,avg-power-min-duty-cycle = <40>; + apple,avg-power-target-filter-tc = <1>; + apple,fast-die0-integral-gain = <200.0>; + apple,fast-die0-proportional-gain = <5.0>; + apple,perf-boost-ce-step = <50>; + apple,perf-boost-min-util = <90>; + apple,perf-filter-drop-threshold = <0>; + apple,perf-filter-time-constant = <5>; + apple,perf-filter-time-constant2 = <200>; + apple,perf-integral-gain = <5.94>; + apple,perf-integral-gain2 = <5.94>; + apple,perf-integral-min-clamp = <0>; + apple,perf-proportional-gain = <14.85>; + apple,perf-proportional-gain2 = <14.85>; + apple,perf-tgt-utilization = <85>; + apple,power-sample-period = <8>; + apple,ppm-filter-time-constant-ms = <34>; + apple,ppm-ki = <205.0>; + apple,ppm-kp = <0.75>; + apple,pwr-min-duty-cycle = <40>; + apple,core-leak-coef = <1920.0>; + apple,sram-leak-coef = <74.0>; }; agx_mbox: mbox@206408000 { From 8d2e4c0483bba8986622cf7c936e41ab2f15f0ae Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 24 Apr 2023 23:27:52 +0900 Subject: [PATCH 025/352] arm64: dts: apple: t600x: Remove obsolete comment in ans2 power domain Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index 3f507cbc65f0c8..3315b392b21d72 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -1387,12 +1387,6 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(ans2); - /* - * The ADT makes ps_apcie_st[1]_sys depend on ps_ans2 instead, - * but we'd rather have a single power domain for the downstream - * device to depend on, so use this node as the child. - * This makes more sense anyway (since ANS2 uses APCIE_ST). - */ power-domains = <&DIE_NODE(ps_afnc2_lw0)>; }; From 7fed4cb807bf805b06defd42f2528098cf1636f7 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 27 Apr 2023 13:53:35 +0900 Subject: [PATCH 026/352] arm64: dts: apple: t600x: Enable turbo CPU p-states These should work now that we have cpuidle. Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t600x-common.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi index 5e54b03cf142f0..f434d724096e58 100644 --- a/arch/arm64/boot/dts/apple/t600x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi @@ -315,7 +315,6 @@ opp-level = <12>; clock-latency-ns = <56000>; }; - /* Not available until CPU deep sleep is implemented opp13 { opp-hz = /bits/ 64 <3132000000>; opp-level = <13>; @@ -334,7 +333,6 @@ clock-latency-ns = <56000>; turbo-mode; }; - */ }; gpu_opp: opp-table-gpu { From 6654379db0dcf60387c759b7e96e049a31f56222 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 27 Apr 2023 13:54:17 +0900 Subject: [PATCH 027/352] arm64: dts: apple: t8103: Enable turbo CPU p-states These should work now that we have cpuidle. Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t8103.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 748724a2a9c1a7..13997c0934e2d7 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -280,7 +280,6 @@ opp-level = <12>; clock-latency-ns = <55000>; }; -#if 0 /* Not available until CPU deep sleep is implemented */ opp13 { opp-hz = /bits/ 64 <3096000000>; @@ -300,7 +299,6 @@ clock-latency-ns = <56000>; turbo-mode; }; -#endif }; gpu_opp: opp-table-gpu { From 9f67a7690cd2f541d9edce8c06c7db1aa6a6aa2c Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 27 Apr 2023 13:54:30 +0900 Subject: [PATCH 028/352] arm64: dts: apple: t8112: Enable turbo CPU p-states These should work now that we have cpuidle. Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t8112.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 7d9027a966f8c4..9cf097356d3d2d 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -302,8 +302,6 @@ opp-level = <14>; clock-latency-ns = <46000>; }; - /* Not available until CPU deep sleep is implemented */ -#if 0 opp15 { opp-hz = /bits/ 64 <3324000000>; opp-level = <15>; @@ -322,7 +320,6 @@ clock-latency-ns = <62000>; turbo-mode; }; -#endif }; gpu_opp: opp-table-gpu { From 9b801081c2ca92e6a27f7ab3e1ac8b0519907bc2 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 11 Apr 2023 02:34:01 +0900 Subject: [PATCH 029/352] arm64: dts: apple: Add identity dma-ranges mapping Without this, the OF core ends up limiting all DMA masks to the default 32-bit, since that runs before drivers set up the proper DMA mask. Skipping the highest page because it is impossible to express a full 64-bit range in the DT. Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t6001.dtsi | 2 ++ arch/arm64/boot/dts/apple/t6002.dtsi | 4 ++++ arch/arm64/boot/dts/apple/t8103.dtsi | 2 ++ arch/arm64/boot/dts/apple/t8112.dtsi | 2 ++ 4 files changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi index 9dffa61db0cef5..3ac838c9b803b6 100644 --- a/arch/arm64/boot/dts/apple/t6001.dtsi +++ b/arch/arm64/boot/dts/apple/t6001.dtsi @@ -32,6 +32,8 @@ ranges; nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; // filled via templated includes at the end of the file }; diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi index ce88211c0c22da..04265fa3ea1ec1 100644 --- a/arch/arm64/boot/dts/apple/t6002.dtsi +++ b/arch/arm64/boot/dts/apple/t6002.dtsi @@ -240,6 +240,8 @@ <0x5 0x80000000 0x5 0x80000000 0x1 0x80000000>, <0x7 0x0 0x7 0x0 0xf 0x80000000>; nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; // filled via templated includes at the end of the file }; @@ -251,6 +253,8 @@ ranges = <0x2 0x0 0x22 0x0 0x4 0x0>, <0x7 0x0 0x27 0x0 0xf 0x80000000>; nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; // filled via templated includes at the end of the file }; diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 13997c0934e2d7..be7de3ba16c0b0 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -443,6 +443,8 @@ ranges; nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; gpu: gpu@206400000 { compatible = "apple,agx-t8103", "apple,agx-g13g"; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 9cf097356d3d2d..38a09dafaab03f 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -467,6 +467,8 @@ ranges; nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; gpu: gpu@206400000 { compatible = "apple,agx-t8112", "apple,agx-g14g"; From 9e3410c2bcd316fb952094c6ce509f327384e952 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 9 Apr 2023 23:48:38 +0900 Subject: [PATCH 030/352] arm64: dts: apple: t602x: Add missing devices Still contains the downstream commits: arm64: dts: apple: t6022: Disable dcp thouroughly Also disables "display" until it can be supported via dispext*. arm64: dts: apple: t602x: Add initial Mac Studio (2023) device trees They use the same GPIO pins and interrupts as the Mac Mini (M2 Pro, 2023) so use a common .dtsi for those definitions. Squashed commits to ease rebasing onto upstream t602x device trees which contains changes from above commits but reordered them in hindsight of knowing the full rooster of t602x devices. Signed-off-by: Hector Martin Co-developed-by: Asahi Lina Signed-off-by: Asahi Lina Co-developed-by: Janne Grunau Signed-off-by: Janne Grunau --- .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 7 + arch/arm64/boot/dts/apple/t600x-j375.dtsi | 2 + arch/arm64/boot/dts/apple/t6020-j414s.dts | 12 ++ arch/arm64/boot/dts/apple/t6020-j416s.dts | 12 ++ arch/arm64/boot/dts/apple/t6020-j474s.dts | 22 +++ arch/arm64/boot/dts/apple/t6020.dtsi | 11 +- arch/arm64/boot/dts/apple/t6021-j414c.dts | 12 ++ arch/arm64/boot/dts/apple/t6021-j416c.dts | 32 ++++ arch/arm64/boot/dts/apple/t6021-j475c.dts | 30 ++++ arch/arm64/boot/dts/apple/t6021.dtsi | 16 +- arch/arm64/boot/dts/apple/t6022-j180d.dts | 12 +- arch/arm64/boot/dts/apple/t6022-j475d.dts | 8 + arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi | 13 ++ arch/arm64/boot/dts/apple/t6022.dtsi | 22 ++- arch/arm64/boot/dts/apple/t602x-common.dtsi | 138 ++++++++++++++++++ arch/arm64/boot/dts/apple/t602x-die0.dtsi | 138 +++++++++++++++++- .../arm64/boot/dts/apple/t602x-j414-j416.dtsi | 46 ++++++ .../arm64/boot/dts/apple/t602x-j474-j475.dtsi | 25 ++++ arch/arm64/boot/dts/apple/t602x-pmgr.dtsi | 3 + 19 files changed, 555 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index c17a77bacd43ed..37024d1d5c9c37 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -285,6 +285,7 @@ clock-frequency = <1068000000>; }; +#ifndef NO_SPI_TRACKPAD &spi3 { status = "okay"; @@ -305,6 +306,7 @@ interrupts-extended = <&pinctrl_nub 6 IRQ_TYPE_LEVEL_LOW>; }; }; +#endif /* PCIe devices */ &port00 { @@ -331,6 +333,7 @@ /* SD card reader */ bus-range = <2 2>; pwren-gpios = <&smc_gpio 26 GPIO_ACTIVE_HIGH>; + status = "okay"; sdhci0: mmc@0,0 { compatible = "pci17a0,9755"; reg = <0x20000 0x0 0x0 0x0 0x0>; @@ -343,6 +346,10 @@ status = "okay"; }; +&pcie0_dart_1 { + status = "okay"; +}; + /* USB controllers */ &dwc3_0 { ports { diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi index 30d549bc32f820..ce962404b2581d 100644 --- a/arch/arm64/boot/dts/apple/t600x-j375.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi @@ -18,9 +18,11 @@ atcphy2 = &atcphy2; atcphy3 = &atcphy3; bluetooth0 = &bluetooth0; + #ifndef NO_DCP dcp = &dcp; disp0 = &display; disp0_piodma = &disp0_piodma; + #endif ethernet0 = ðernet0; serial0 = &serial0; wifi0 = &wifi0; diff --git a/arch/arm64/boot/dts/apple/t6020-j414s.dts b/arch/arm64/boot/dts/apple/t6020-j414s.dts index 631c54c5f03dee..18cc67a3076def 100644 --- a/arch/arm64/boot/dts/apple/t6020-j414s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j414s.dts @@ -24,3 +24,15 @@ &bluetooth0 { brcm,board-type = "apple,tokara"; }; + +&panel { + compatible = "apple,panel-j414", "apple,panel-mini-led", "apple,panel"; + width-mm = <302>; + height-mm = <196>; + adj-height-mm = <189>; +}; + +&sound { + compatible = "apple,j414-macaudio", "apple,j314-macaudio", "apple,macaudio"; + model = "MacBook Pro J414"; +}; diff --git a/arch/arm64/boot/dts/apple/t6020-j416s.dts b/arch/arm64/boot/dts/apple/t6020-j416s.dts index c277ed5889a214..b9e0973ba37c30 100644 --- a/arch/arm64/boot/dts/apple/t6020-j416s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j416s.dts @@ -24,3 +24,15 @@ &bluetooth0 { brcm,board-type = "apple,amami"; }; + +&panel { + compatible = "apple,panel-j416", "apple,panel-mini-led", "apple,panel"; + width-mm = <346>; + height-mm = <223>; + adj-height-mm = <216>; +}; + +&sound { + compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio"; + model = "MacBook Pro J416"; +}; diff --git a/arch/arm64/boot/dts/apple/t6020-j474s.dts b/arch/arm64/boot/dts/apple/t6020-j474s.dts index 7c7ad5b8ad189e..17c72b0bb87721 100644 --- a/arch/arm64/boot/dts/apple/t6020-j474s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j474s.dts @@ -45,3 +45,25 @@ <0x200 &pcie0_dart_2 1 1>, <0x300 &pcie0_dart_3 1 1>; }; + +&port02 { + bus-range = <2 2>; +}; + +ðernet0 { + reg = <0x20000 0x0 0x0 0x0 0x0>; +}; + +&port03 { + bus-range = <3 3>; +}; + +&sound { + compatible = "apple,j474-macaudio", "apple,j473-macaudio", "apple,macaudio"; + model = "Mac mini J474"; +}; + +&gpu { + /* Apple does not do this, but they probably should */ + apple,perf-base-pstate = <3>; +}; diff --git a/arch/arm64/boot/dts/apple/t6020.dtsi b/arch/arm64/boot/dts/apple/t6020.dtsi index bffa66a3ffff3f..482a1e5f53d0a6 100644 --- a/arch/arm64/boot/dts/apple/t6020.dtsi +++ b/arch/arm64/boot/dts/apple/t6020.dtsi @@ -9,6 +9,8 @@ /* This chip is just a cut down version of t6021, so include it and disable the missing parts */ +#define GPU_REPEAT(x) + #include "t6021.dtsi" / { @@ -18,5 +20,12 @@ /delete-node/ &pmgr_south; &gpu { - compatible = "apple,agx-g14s"; + compatible = "apple,agx-t6020", "apple,agx-g14x", "apple,agx-g14s"; + + apple,avg-power-filter-tc-ms = <302>; + apple,avg-power-ki-only = <2.6375>; + apple,avg-power-kp = <0.18>; + apple,fast-die0-integral-gain = <1350.0>; + apple,ppm-filter-time-constant-ms = <32>; + apple,ppm-ki = <28.0>; }; diff --git a/arch/arm64/boot/dts/apple/t6021-j414c.dts b/arch/arm64/boot/dts/apple/t6021-j414c.dts index cdcf0740714dcf..b173caf0df0fce 100644 --- a/arch/arm64/boot/dts/apple/t6021-j414c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j414c.dts @@ -24,3 +24,15 @@ &bluetooth0 { brcm,board-type = "apple,tokara"; }; + +&panel { + compatible = "apple,panel-j414", "apple,panel-mini-led", "apple,panel"; + width-mm = <302>; + height-mm = <196>; + adj-height-mm = <189>; +}; + +&sound { + compatible = "apple,j414-macaudio", "apple,j314-macaudio", "apple,macaudio"; + model = "MacBook Pro J414"; +}; diff --git a/arch/arm64/boot/dts/apple/t6021-j416c.dts b/arch/arm64/boot/dts/apple/t6021-j416c.dts index 6d8146b9417036..2fbb00b364c72b 100644 --- a/arch/arm64/boot/dts/apple/t6021-j416c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j416c.dts @@ -17,6 +17,26 @@ model = "Apple MacBook Pro (16-inch, M2 Max, 2023)"; }; +/* This machine model (only) has two extra boost CPU P-states * + * Disabled: Only the highest CPU bin (38 GPU cores) has this. + * Keep this disabled until m1n1 learns how to remove these OPPs + * for unsupported machines, otherwise it breaks cpufreq. +&avalanche_opp { + opp18 { + opp-hz = /bits/ 64 <3528000000>; + opp-level = <18>; + clock-latency-ns = <67000>; + turbo-mode; + }; + opp19 { + opp-hz = /bits/ 64 <3696000000>; + opp-level = <19>; + clock-latency-ns = <67000>; + turbo-mode; + }; +}; +*/ + &wifi0 { brcm,board-type = "apple,amami"; }; @@ -24,3 +44,15 @@ &bluetooth0 { brcm,board-type = "apple,amami"; }; + +&panel { + compatible = "apple,panel-j416", "apple,panel-mini-led", "apple,panel"; + width-mm = <346>; + height-mm = <223>; + adj-height-mm = <216>; +}; + +&sound { + compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio"; + model = "MacBook Pro J416"; +}; diff --git a/arch/arm64/boot/dts/apple/t6021-j475c.dts b/arch/arm64/boot/dts/apple/t6021-j475c.dts index 533e3577487469..ebc3ec8c387b30 100644 --- a/arch/arm64/boot/dts/apple/t6021-j475c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j475c.dts @@ -29,9 +29,39 @@ /* enable PCIe port01 with SDHCI */ &port01 { + pwren-gpios = <&smc_gpio 22 GPIO_ACTIVE_HIGH>; status = "okay"; }; &pcie0_dart_1 { status = "okay"; }; + +&pinctrl_ap { + usb_hub_oe-hog { + gpio-hog; + gpios = <231 0>; + input; + line-name = "usb-hub-oe"; + }; + + usb_hub_rst-hog { + gpio-hog; + gpios = <232 GPIO_ACTIVE_LOW>; + output-low; + line-name = "usb-hub-rst"; + }; +}; + +&sound { + compatible = "apple,j475-macaudio", "apple,j375-macaudio", "apple,macaudio"; + model = "Mac Studio J475"; +}; + +&gpu { + apple,idleoff-standby-timer = <3000>; + apple,perf-base-pstate = <5>; + apple,perf-boost-ce-step = <100>; + apple,perf-boost-min-util = <75>; + apple,perf-tgt-utilization = <70>; +}; diff --git a/arch/arm64/boot/dts/apple/t6021.dtsi b/arch/arm64/boot/dts/apple/t6021.dtsi index 62907ad6a54683..1205a43da383f7 100644 --- a/arch/arm64/boot/dts/apple/t6021.dtsi +++ b/arch/arm64/boot/dts/apple/t6021.dtsi @@ -16,6 +16,13 @@ #include "multi-die-cpp.h" +#ifndef GPU_REPEAT +# define GPU_REPEAT(x) +#endif +#ifndef GPU_DIE_REPEAT +# define GPU_DIE_REPEAT(x) +#endif + #include "t602x-common.dtsi" / { @@ -65,5 +72,12 @@ }; &gpu { - compatible = "apple,agx-g14c", "apple,agx-g14s"; + compatible = "apple,agx-t6021", "apple,agx-g14x", "apple,agx-g14c", "apple,agx-g14s"; + + apple,avg-power-filter-tc-ms = <300>; + apple,avg-power-ki-only = <1.5125>; + apple,avg-power-kp = <0.38>; + apple,fast-die0-integral-gain = <700.0>; + apple,ppm-filter-time-constant-ms = <34>; + apple,ppm-ki = <18.0>; }; diff --git a/arch/arm64/boot/dts/apple/t6022-j180d.dts b/arch/arm64/boot/dts/apple/t6022-j180d.dts index 7d92505e3fd232..59e5825a0368fa 100644 --- a/arch/arm64/boot/dts/apple/t6022-j180d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j180d.dts @@ -26,8 +26,11 @@ atcphy5 = &atcphy1_die1; atcphy6 = &atcphy2_die1; atcphy7 = &atcphy3_die1; - nvram = &nvram; + //bluetooth0 = &bluetooth0; + //ethernet0 = ðernet0; + //ethernet1 = ðernet1; serial0 = &serial0; + //wifi0 = &wifi0; }; chosen { @@ -46,6 +49,13 @@ }; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + /* To be filled by loader */ + }; + memory@10000000000 { device_type = "memory"; reg = <0x100 0 0x2 0>; /* To be filled by loader */ diff --git a/arch/arm64/boot/dts/apple/t6022-j475d.dts b/arch/arm64/boot/dts/apple/t6022-j475d.dts index 31f24bbda9689b..141c8497b8890b 100644 --- a/arch/arm64/boot/dts/apple/t6022-j475d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j475d.dts @@ -9,6 +9,8 @@ /dts-v1/; +#define NO_DCP + #include "t6022.dtsi" #include "t602x-j474-j475.dtsi" #include "t6022-jxxxd.dtsi" @@ -29,6 +31,7 @@ /* enable PCIe port01 with SDHCI */ &port01 { + pwren-gpios = <&smc_gpio 22 GPIO_ACTIVE_HIGH>; status = "okay"; }; @@ -71,3 +74,8 @@ compatible = "pci14e4,5f72"; brcm,board-type = "apple,canary"; }; + +&sound { + compatible = "apple,j475-macaudio", "apple,j375-macaudio", "apple,macaudio"; + model = "Mac Studio J475"; +}; diff --git a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi index dc877bd604f827..5b7b41ce07c3d8 100644 --- a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi +++ b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi @@ -9,6 +9,19 @@ * Copyright The Asahi Linux Contributors */ +/* disable unused display node */ + +&display { + status = "disabled"; + iommus = <>; /* <&dispext0_dart_die1 0>; */ +}; + +/* delete missing dcp0/disp0 */ +/delete-node/ &disp0_dart; +/delete-node/ &dcp_dart; +/delete-node/ &dcp_mbox; +/delete-node/ &dcp; + /* delete power-domains for missing disp0 / disp0_die1 */ /delete-node/ &ps_disp0_cpu0; /delete-node/ &ps_disp0_fe; diff --git a/arch/arm64/boot/dts/apple/t6022.dtsi b/arch/arm64/boot/dts/apple/t6022.dtsi index e73bf2f7510ae2..bc05cddf68f4f7 100644 --- a/arch/arm64/boot/dts/apple/t6022.dtsi +++ b/arch/arm64/boot/dts/apple/t6022.dtsi @@ -16,6 +16,13 @@ #include "multi-die-cpp.h" +#ifndef GPU_REPEAT +# define GPU_REPEAT(x) +#endif +#ifndef GPU_DIE_REPEAT +# define GPU_DIE_REPEAT(x) +#endif + #include "t602x-common.dtsi" / { @@ -345,5 +352,18 @@ }; &gpu { - compatible = "apple,agx-g14d", "apple,agx-g14s"; + compatible = "apple,agx-t6022", "apple,agx-g14x", "apple,agx-g14d", "apple,agx-g14s"; + + apple,avg-power-filter-tc-ms = <302>; + apple,avg-power-ki-only = <1.0125>; + apple,avg-power-kp = <0.15>; + apple,fast-die0-integral-gain = <9.6>; + apple,fast-die0-proportional-gain = <24.0>; + apple,idleoff-standby-timer = <3000>; + apple,perf-base-pstate = <5>; + apple,perf-boost-ce-step = <100>; + apple,perf-boost-min-util = <75>; + apple,perf-tgt-utilization = <70>; + apple,ppm-ki = <11.0>; + apple,ppm-kp = <0.15>; }; diff --git a/arch/arm64/boot/dts/apple/t602x-common.dtsi b/arch/arm64/boot/dts/apple/t602x-common.dtsi index 9c800a391e7e87..3eeb5139fcde05 100644 --- a/arch/arm64/boot/dts/apple/t602x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-common.dtsi @@ -387,6 +387,134 @@ }; }; + gpu_opp: opp-table-gpu { + compatible = "operating-points-v2"; + + /* + * NOTE: The voltage and power values are device-specific and + * must be filled in by the bootloader. + */ + opp00 { + opp-hz = /bits/ 64 <0>; + opp-microvolt = GPU_REPEAT(400000); + opp-microwatt = <0>; + }; + opp01 { + opp-hz = /bits/ 64 <444000000>; + opp-microvolt = GPU_REPEAT(637000); + opp-microwatt = <4295000>; + }; + opp02 { + opp-hz = /bits/ 64 <612000000>; + opp-microvolt = GPU_REPEAT(656000); + opp-microwatt = <6251000>; + }; + opp03 { + opp-hz = /bits/ 64 <808000000>; + opp-microvolt = GPU_REPEAT(687000); + opp-microwatt = <8625000>; + }; + opp04 { + opp-hz = /bits/ 64 <968000000>; + opp-microvolt = GPU_REPEAT(725000); + opp-microwatt = <11948000>; + }; + opp05 { + opp-hz = /bits/ 64 <1110000000>; + opp-microvolt = GPU_REPEAT(790000); + opp-microwatt = <15071000>; + }; + opp06 { + opp-hz = /bits/ 64 <1236000000>; + opp-microvolt = GPU_REPEAT(843000); + opp-microwatt = <18891000>; + }; + opp07 { + opp-hz = /bits/ 64 <1338000000>; + opp-microvolt = GPU_REPEAT(887000); + opp-microwatt = <21960000>; + }; + opp08 { + opp-hz = /bits/ 64 <1398000000>; + opp-microvolt = GPU_REPEAT(918000); + opp-microwatt = <22800000>; + }; + }; + + gpu_cs_opp: opp-table-gpu-cs { + compatible = "operating-points-v2"; + + /* + * NOTE: The voltage and power values are device-specific and + * must be filled in by the bootloader. + */ + opp00 { + opp-hz = /bits/ 64 <24>; + opp-microvolt = GPU_DIE_REPEAT(668000); + }; + opp01 { + opp-hz = /bits/ 64 <444000000>; + opp-microvolt = GPU_DIE_REPEAT(668000); + }; + opp02 { + opp-hz = /bits/ 64 <612000000>; + opp-microvolt = GPU_DIE_REPEAT(678000); + }; + opp03 { + opp-hz = /bits/ 64 <808000000>; + opp-microvolt = GPU_DIE_REPEAT(737000); + }; + opp04 { + opp-hz = /bits/ 64 <1024000000>; + opp-microvolt = GPU_DIE_REPEAT(815000); + }; + opp05 { + opp-hz = /bits/ 64 <1140000000>; + opp-microvolt = GPU_DIE_REPEAT(862000); + }; + opp06 { + opp-hz = /bits/ 64 <1236000000>; + opp-microvolt = GPU_DIE_REPEAT(893000); + }; + }; + + gpu_afr_opp: opp-table-gpu-afr { + compatible = "operating-points-v2"; + + /* + * NOTE: The voltage and power values are device-specific and + * must be filled in by the bootloader. + */ + opp00 { + opp-hz = /bits/ 64 <24>; + opp-microvolt = GPU_DIE_REPEAT(668000); + }; + opp01 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = GPU_DIE_REPEAT(668000); + }; + opp02 { + opp-hz = /bits/ 64 <552000000>; + opp-microvolt = GPU_DIE_REPEAT(678000); + }; + opp03 { + opp-hz = /bits/ 64 <760000000>; + opp-microvolt = GPU_DIE_REPEAT(737000); + }; + opp04 { + opp-hz = /bits/ 64 <980000000>; + opp-microvolt = GPU_DIE_REPEAT(815000); + }; + opp05 { + opp-hz = /bits/ 64 <1098000000>; + opp-microvolt = GPU_DIE_REPEAT(862000); + }; + opp06 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = GPU_DIE_REPEAT(893000); + }; + }; + pmu-e { compatible = "apple,blizzard-pmu"; interrupt-parent = <&aic>; @@ -423,6 +551,13 @@ clock-output-names = "clk_200m"; }; + clk_disp0: clock-disp0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <257142848>; /* TODO: check */ + clock-output-names = "clk_disp0"; + }; + /* * This is a fabulated representation of the input clock * to NCO since we don't know the true clock tree. @@ -452,14 +587,17 @@ uat_handoff: uat-handoff { status = "disabled"; + reg = <0 0 0 0>; }; uat_pagetables: uat-pagetables { status = "disabled"; + reg = <0 0 0 0>; }; uat_ttbs: uat-ttbs { status = "disabled"; + reg = <0 0 0 0>; }; }; }; diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 8622ddea7b4453..19b628309ed80c 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -23,6 +23,12 @@ power-domains = <&ps_aic>; }; + pmgr_dcp: power-management@28e3d0000 { + reg = <0x2 0x8e3d0000 0x0 0x4000>; + reg-names = "dcp-fw-pmgr"; + #apple,bw-scratch-cells = <3>; + }; + nub_spmi0: spmi@29e114000 { compatible = "apple,t6020-spmi", "apple,t8103-spmi"; reg = <0x2 0x9e114000 0x0 0x100>; @@ -117,9 +123,9 @@ smc_reboot: reboot { compatible = "apple,smc-reboot"; nvmem-cells = <&shutdown_flag>, <&boot_stage>, - <&boot_error_count>, <&panic_count>; + <&boot_error_count>, <&panic_count>, <&pm_setting>; nvmem-cell-names = "shutdown_flag", "boot_stage", - "boot_error_count", "panic_count"; + "boot_error_count", "panic_count", "pm_setting"; }; rtc { @@ -150,6 +156,75 @@ ; }; + disp0_dart: iommu@389304000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x89304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + power-domains = <&ps_disp0_cpu0>; + apple,dma-range = <0x100 0x0 0x10 0x0>; + }; + + dcp_dart: iommu@38930c000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x8930c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_disp0_cpu0>; + apple,dma-range = <0x100 0x0 0x10 0x0>; + }; + + dcp_mbox: mbox@389c08000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x89c08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + }; + + dcp: dcp@389c00000 { + compatible = "apple,t6020-dcp", "apple,dcp"; + mboxes = <&dcp_mbox>; + mbox-names = "mbox"; + iommus = <&dcp_dart 5>; + + reg-names = "coproc", "disp-0", "disp-1", "disp-2", "disp-3"; + reg = <0x3 0x89c00000 0x0 0x4000>, // check? + <0x3 0x88000000 0x0 0x61c000>, + <0x3 0x89320000 0x0 0x4000>, + <0x3 0x89344000 0x0 0x4000>, + <0x3 0x89800000 0x0 0x800000>; + apple,bw-scratch = <&pmgr_dcp 0 4 0x1208>; + power-domains = <&ps_disp0_cpu0>; + resets = <&ps_disp0_cpu0>; + clocks = <&clk_disp0>; + phandle = <&dcp>; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + disp0_piodma: piodma { + iommus = <&disp0_dart 4>; + phandle = <&disp0_piodma>; + }; + }; + + display: display-subsystem { + compatible = "apple,display-subsystem"; + iommus = <&disp0_dart 0>; + /* generate phandle explicitly for use in loader */ + phandle = <&display>; + }; + sio_dart: iommu@39b008000 { compatible = "apple,t6020-dart", "apple,t8110-dart"; reg = <0x3 0x9b008000 0x0 0x8000>; @@ -394,6 +469,14 @@ reg = <0x4 0x6400000 0 0x40000>, <0x4 0x4000000 0 0x1000000>; reg-names = "asc", "sgx"; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; mboxes = <&agx_mbox>; power-domains = <&ps_gfx>; memory-region = <&uat_ttbs>, <&uat_pagetables>, <&uat_handoff>, @@ -402,6 +485,55 @@ "hw-cal-a", "hw-cal-b", "globals"; apple,firmware-abi = <0 0 0>; + apple,firmware-version = <0 0 0>; + apple,firmware-compat = <0 0 0>; + + operating-points-v2 = <&gpu_opp>; + apple,cs-opp = <&gpu_cs_opp>; + apple,afr-opp = <&gpu_afr_opp>; + + apple,min-sram-microvolt = <790000>; + apple,csafr-min-sram-microvolt = <812000>; + apple,perf-base-pstate = <1>; + + apple,avg-power-min-duty-cycle = <40>; + apple,avg-power-target-filter-tc = <1>; + apple,fast-die0-proportional-gain = <34.0>; + apple,perf-boost-ce-step = <50>; + apple,perf-boost-min-util = <90>; + apple,perf-filter-drop-threshold = <0>; + apple,perf-filter-time-constant = <5>; + apple,perf-filter-time-constant2 = <200>; + apple,perf-integral-gain = <1.62>; + apple,perf-integral-gain2 = <1.62>; + apple,perf-integral-min-clamp = <0>; + apple,perf-proportional-gain2 = <5.4>; + apple,perf-proportional-gain = <5.4>; + apple,perf-tgt-utilization = <85>; + apple,power-sample-period = <8>; + apple,ppm-filter-time-constant-ms = <34>; + apple,ppm-ki = <18.0>; + apple,ppm-kp = <0.1>; + apple,pwr-filter-time-constant = <313>; + apple,pwr-integral-gain = <0.0202129>; + apple,pwr-integral-min-clamp = <0>; + apple,pwr-min-duty-cycle = <40>; + apple,pwr-proportional-gain = <5.2831855>; + apple,pwr-sample-period-aic-clks = <200000>; + apple,se-engagement-criteria = <700>; + apple,se-filter-time-constant = <9>; + apple,se-filter-time-constant-1 = <3>; + apple,se-inactive-threshold = <2500>; + apple,se-ki = <-50.0>; + apple,se-ki-1 = <-100.0>; + apple,se-kp = <-5.0>; + apple,se-kp-1 = <-10.0>; + apple,se-reset-criteria = <50>; + + apple,core-leak-coef = GPU_REPEAT(1200.0); + apple,sram-leak-coef = GPU_REPEAT(20.0); + apple,cs-leak-coef = GPU_DIE_REPEAT(400.0); + apple,afr-leak-coef = GPU_DIE_REPEAT(200.0); }; agx_mbox: mbox@406408000 { @@ -461,6 +593,8 @@ pinctrl-0 = <&pcie_pins>; pinctrl-names = "default"; + dma-coherent; + port00: pci@0,0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; diff --git a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi index 0e806d8ddf81b1..b0fa34282681de 100644 --- a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi @@ -14,8 +14,15 @@ * the GPIO indices. */ +#define NO_SPI_TRACKPAD #include "t600x-j314-j316.dtsi" +/ { + aliases { + keyboard = &keyboard; + }; +}; + &framebuffer0 { power-domains = <&ps_disp0_cpu0>, <&ps_dptx_phy_ps>; }; @@ -36,6 +43,41 @@ interrupts = <44 IRQ_TYPE_LEVEL_LOW>; }; +&speaker_left_tweet { + shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; +}; + +&speaker_left_woof1 { + shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; +}; + +&speaker_left_woof2 { + shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; +}; + +&speaker_right_tweet { + shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; +}; + +&speaker_right_woof1 { + shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; +}; + +&speaker_right_woof2 { + shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; +}; + +&jack_codec { + reset-gpios = <&pinctrl_nub 8 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 59 IRQ_TYPE_LEVEL_LOW>; +}; + &wifi0 { compatible = "pci14e4,4434"; }; @@ -43,3 +85,7 @@ &bluetooth0 { compatible = "pci14e4,5f72"; }; + +&port01 { + pwren-gpios = <&smc_gpio 22 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi b/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi index ee12fea5b12cb3..25c0e6bf41724b 100644 --- a/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi @@ -21,6 +21,11 @@ power-domains = <&ps_dispext0_cpu0>, <&ps_dptx_phy_ps>; }; +/* disable dcp until it is supported */ +&dcp { + status = "disabled"; +}; + &hpm0 { interrupts = <44 IRQ_TYPE_LEVEL_LOW>; }; @@ -36,3 +41,23 @@ &hpm3 { interrupts = <44 IRQ_TYPE_LEVEL_LOW>; }; + +/* PCIe devices */ +&port00 { + pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; +}; + +&port03 { + /* USB xHCI */ + pwren-gpios = <&smc_gpio 19 GPIO_ACTIVE_HIGH>; +}; + +&speaker { + shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; +}; + +&jack_codec { + reset-gpios = <&pinctrl_nub 8 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pinctrl_ap 59 IRQ_TYPE_LEVEL_LOW>; +}; diff --git a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi index f5382a2faf0b25..5fa2a93ad9ec20 100644 --- a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi @@ -447,6 +447,7 @@ power-domains = <&DIE_NODE(ps_dispext0_sys)>; }; + /* PMP is only present on die 0 of the M2 Ultra */ DIE_NODE(ps_pmp): power-controller@2c8 { compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; reg = <0x2c8 4>; @@ -1449,6 +1450,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(dptx_phy_ps); + apple,always-on; power-domains = <&DIE_NODE(ps_sio)>; }; @@ -1853,6 +1855,7 @@ #reset-cells = <0>; label = DIE_LABEL(isp_cpu); /* power-domains = <&DIE_NODE(ps_isp_sys)>; */ + apple,force-disable; }; DIE_NODE(ps_isp_fe): power-controller@4008 { From 407fc7aaca731ff89be828ba50d30d6a66c434ce Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 16 Nov 2025 13:06:48 +0100 Subject: [PATCH 031/352] HACK: arm64: dts: apple: t602x: Add generic compatibility Upstream disliked the generic "apple,*" compatibility strings so the t602x device trees upstream submission did not use them. m1n1 will add them back but carry them for 6.18 and 6.19 based downstream kernels. Drop with 6.18 + 2 Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t602x-die0.dtsi | 38 +- arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 6 +- arch/arm64/boot/dts/apple/t602x-nvme.dtsi | 2 +- arch/arm64/boot/dts/apple/t602x-pmgr.dtsi | 490 +++++++++++----------- 4 files changed, 268 insertions(+), 268 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 19b628309ed80c..922ae4368978b0 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -7,7 +7,7 @@ */ nco: clock-controller@28e03c000 { - compatible = "apple,t6020-nco", "apple,t8103-nco"; + compatible = "apple,t6020-nco", "apple,t8103-nco", "apple,nco"; reg = <0x2 0x8e03c000 0x0 0x14000>; clocks = <&nco_clkref>; #clock-cells = <1>; @@ -30,7 +30,7 @@ }; nub_spmi0: spmi@29e114000 { - compatible = "apple,t6020-spmi", "apple,t8103-spmi"; + compatible = "apple,t6020-spmi", "apple,t8103-spmi", "apple,spmi"; reg = <0x2 0x9e114000 0x0 0x100>; #address-cells = <2>; #size-cells = <0>; @@ -87,7 +87,7 @@ }; wdt: watchdog@29e2c4000 { - compatible = "apple,t6020-wdt", "apple,t8103-wdt"; + compatible = "apple,t6020-wdt", "apple,t8103-wdt", "apple,wdt"; reg = <0x2 0x9e2c4000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -108,7 +108,7 @@ }; smc: smc@2a2400000 { - compatible = "apple,t6020-smc", "apple,t8103-smc"; + compatible = "apple,t6020-smc", "apple,t8103-smc", "apple,smc"; reg = <0x2 0xa2400000 0x0 0x4000>, <0x2 0xa3e00000 0x0 0x100000>; reg-names = "smc", "sram"; @@ -136,7 +136,7 @@ }; pinctrl_smc: pinctrl@2a2820000 { - compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl"; + compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x2 0xa2820000 0x0 0x4000>; gpio-controller; @@ -244,7 +244,7 @@ }; i2c0: i2c@39b040000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b040000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -257,7 +257,7 @@ }; i2c1: i2c@39b044000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b044000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -271,7 +271,7 @@ }; i2c2: i2c@39b048000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b048000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -285,7 +285,7 @@ }; i2c3: i2c@39b04c000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b04c000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -299,7 +299,7 @@ }; i2c4: i2c@39b050000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b050000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -313,7 +313,7 @@ }; i2c5: i2c@39b054000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b054000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -327,7 +327,7 @@ }; i2c6: i2c@39b054000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b054000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -341,7 +341,7 @@ }; i2c7: i2c@39b054000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b054000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -355,7 +355,7 @@ }; i2c8: i2c@39b054000 { - compatible = "apple,t6020-i2c", "apple,t8103-i2c"; + compatible = "apple,t6020-i2c", "apple,t8103-i2c", "apple,i2c"; reg = <0x3 0x9b054000 0x0 0x4000>; clocks = <&clkref>; interrupt-parent = <&aic>; @@ -369,7 +369,7 @@ }; spi1: spi@39b104000 { - compatible = "apple,t6020-spi", "apple,t8103-spi"; + compatible = "apple,t6020-spi", "apple,t8103-spi", "apple,spi"; reg = <0x3 0x9b104000 0x0 0x4000>; interrupt-parent = <&aic>; interrupts = ; @@ -383,7 +383,7 @@ }; spi2: spi@39b108000 { - compatible = "apple,t6020-spi", "apple,t8103-spi"; + compatible = "apple,t6020-spi", "apple,t8103-spi", "apple,spi"; reg = <0x3 0x9b108000 0x0 0x4000>; interrupt-parent = <&aic>; interrupts = ; @@ -397,7 +397,7 @@ }; spi4: spi@39b110000 { - compatible = "apple,t6020-spi", "apple,t8103-spi"; + compatible = "apple,t6020-spi", "apple,t8103-spi", "apple,spi"; reg = <0x3 0x9b110000 0x0 0x4000>; interrupt-parent = <&aic>; interrupts = ; @@ -427,7 +427,7 @@ }; admac: dma-controller@39b400000 { - compatible = "apple,t6020-admac", "apple,t8103-admac"; + compatible = "apple,t6020-admac", "apple,t8103-admac", "apple,admac"; reg = <0x3 0x9b400000 0x0 0x34000>; #dma-cells = <1>; dma-channels = <16>; @@ -441,7 +441,7 @@ }; mca: mca@39b600000 { - compatible = "apple,t6020-mca", "apple,t8103-mca"; + compatible = "apple,t6020-mca", "apple,t8103-mca", "apple,mca"; reg = <0x3 0x9b600000 0x0 0x10000>, <0x3 0x9b500000 0x0 0x20000>; clocks = <&nco 0>, <&nco 1>, <&nco 2>, <&nco 3>; diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi index ae3d535c5acb37..0e77c1cbf8a5c2 100644 --- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi @@ -45,7 +45,7 @@ }; DIE_NODE(pinctrl_nub): pinctrl@29e1f0000 { - compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl"; + compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x2 0x9e1f0000 0x0 0x4000>; power-domains = <&DIE_NODE(ps_nub_gpio)>; @@ -74,7 +74,7 @@ }; DIE_NODE(pinctrl_aop): pinctrl@2a6820000 { - compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl"; + compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x2 0xa6820000 0x0 0x4000>; gpio-controller; @@ -95,7 +95,7 @@ }; DIE_NODE(pinctrl_ap): pinctrl@39b028000 { - compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl"; + compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x3 0x9b028000 0x0 0x4000>; interrupt-parent = <&aic>; diff --git a/arch/arm64/boot/dts/apple/t602x-nvme.dtsi b/arch/arm64/boot/dts/apple/t602x-nvme.dtsi index 590cec8ac804c0..eb8c4e359079e5 100644 --- a/arch/arm64/boot/dts/apple/t602x-nvme.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-nvme.dtsi @@ -26,7 +26,7 @@ }; DIE_NODE(nvme): nvme@34bcc0000 { - compatible = "apple,t6020-nvme-ans2", "apple,t8103-nvme-ans2"; + compatible = "apple,t6020-nvme-ans2", "apple,t8103-nvme-ans2", "apple,nvme-ans2"; reg = <0x3 0x4bcc0000 0x0 0x40000>, <0x3 0x47400000 0x0 0x4000>; reg-names = "nvme", "ans"; interrupt-parent = <&aic>; diff --git a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi index 5fa2a93ad9ec20..f5ebd5bc19b33a 100644 --- a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi @@ -7,7 +7,7 @@ &DIE_NODE(pmgr) { DIE_NODE(ps_afi): power-controller@100 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x100 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -16,7 +16,7 @@ }; DIE_NODE(ps_aic): power-controller@108 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x108 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -25,7 +25,7 @@ }; DIE_NODE(ps_dwi): power-controller@110 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x110 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -33,7 +33,7 @@ }; DIE_NODE(ps_pms): power-controller@118 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x118 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -42,7 +42,7 @@ }; DIE_NODE(ps_gpio): power-controller@120 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x120 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -51,7 +51,7 @@ }; DIE_NODE(ps_soc_dpe): power-controller@128 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x128 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -60,7 +60,7 @@ }; DIE_NODE(ps_pms_c1ppt): power-controller@130 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x130 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -69,7 +69,7 @@ }; DIE_NODE(ps_pmgr_soc_ocla): power-controller@138 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x138 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -78,7 +78,7 @@ }; DIE_NODE(ps_amcc0): power-controller@168 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x168 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -87,7 +87,7 @@ }; DIE_NODE(ps_amcc2): power-controller@170 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x170 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -96,7 +96,7 @@ }; DIE_NODE(ps_dcs_00): power-controller@178 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x178 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -105,7 +105,7 @@ }; DIE_NODE(ps_dcs_01): power-controller@180 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x180 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -114,7 +114,7 @@ }; DIE_NODE(ps_dcs_02): power-controller@188 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x188 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -123,7 +123,7 @@ }; DIE_NODE(ps_dcs_03): power-controller@190 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x190 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -132,7 +132,7 @@ }; DIE_NODE(ps_dcs_08): power-controller@198 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x198 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -141,7 +141,7 @@ }; DIE_NODE(ps_dcs_09): power-controller@1a0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1a0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -150,7 +150,7 @@ }; DIE_NODE(ps_dcs_10): power-controller@1a8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1a8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -159,7 +159,7 @@ }; DIE_NODE(ps_dcs_11): power-controller@1b0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1b0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -168,7 +168,7 @@ }; DIE_NODE(ps_afnc1_ioa): power-controller@1b8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1b8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -178,7 +178,7 @@ }; DIE_NODE(ps_afc): power-controller@1d0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1d0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -187,7 +187,7 @@ }; DIE_NODE(ps_afnc0_ioa): power-controller@1e8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1e8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -197,7 +197,7 @@ }; DIE_NODE(ps_afnc1_ls): power-controller@1f0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1f0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -207,7 +207,7 @@ }; DIE_NODE(ps_afnc0_ls): power-controller@1f8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1f8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -217,7 +217,7 @@ }; DIE_NODE(ps_afnc1_lw0): power-controller@200 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x200 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -227,7 +227,7 @@ }; DIE_NODE(ps_afnc1_lw1): power-controller@208 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x208 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -237,7 +237,7 @@ }; DIE_NODE(ps_afnc1_lw2): power-controller@210 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x210 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -247,7 +247,7 @@ }; DIE_NODE(ps_afnc0_lw0): power-controller@218 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x218 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -257,7 +257,7 @@ }; DIE_NODE(ps_scodec): power-controller@220 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x220 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -266,7 +266,7 @@ }; DIE_NODE(ps_atc0_common): power-controller@228 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x228 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -275,7 +275,7 @@ }; DIE_NODE(ps_atc1_common): power-controller@230 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x230 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -284,7 +284,7 @@ }; DIE_NODE(ps_atc2_common): power-controller@238 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x238 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -293,7 +293,7 @@ }; DIE_NODE(ps_atc3_common): power-controller@240 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x240 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -302,7 +302,7 @@ }; DIE_NODE(ps_dispext1_sys): power-controller@248 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x248 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -311,7 +311,7 @@ }; DIE_NODE(ps_pms_bridge): power-controller@250 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x250 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -321,7 +321,7 @@ }; DIE_NODE(ps_dispext0_sys): power-controller@258 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x258 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -330,7 +330,7 @@ }; DIE_NODE(ps_ane_sys): power-controller@260 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x260 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -339,7 +339,7 @@ }; DIE_NODE(ps_avd_sys): power-controller@268 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x268 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -348,7 +348,7 @@ }; DIE_NODE(ps_atc0_cio): power-controller@270 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x270 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -357,7 +357,7 @@ }; DIE_NODE(ps_atc0_pcie): power-controller@278 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x278 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -366,7 +366,7 @@ }; DIE_NODE(ps_atc1_cio): power-controller@280 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x280 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -375,7 +375,7 @@ }; DIE_NODE(ps_atc1_pcie): power-controller@288 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x288 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -384,7 +384,7 @@ }; DIE_NODE(ps_atc2_cio): power-controller@290 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x290 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -393,7 +393,7 @@ }; DIE_NODE(ps_atc2_pcie): power-controller@298 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x298 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -402,7 +402,7 @@ }; DIE_NODE(ps_atc3_cio): power-controller@2a0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2a0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -411,7 +411,7 @@ }; DIE_NODE(ps_atc3_pcie): power-controller@2a8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2a8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -420,7 +420,7 @@ }; DIE_NODE(ps_dispext1_fe): power-controller@2b0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2b0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -429,7 +429,7 @@ }; DIE_NODE(ps_dispext1_cpu0): power-controller@2b8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2b8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -439,7 +439,7 @@ }; DIE_NODE(ps_dispext0_fe): power-controller@2c0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2c0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -449,7 +449,7 @@ /* PMP is only present on die 0 of the M2 Ultra */ DIE_NODE(ps_pmp): power-controller@2c8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2c8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -457,7 +457,7 @@ }; DIE_NODE(ps_pms_sram): power-controller@2d0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2d0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -465,7 +465,7 @@ }; DIE_NODE(ps_dispext0_cpu0): power-controller@2d8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2d8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -475,7 +475,7 @@ }; DIE_NODE(ps_ane_cpu): power-controller@2e0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2e0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -484,7 +484,7 @@ }; DIE_NODE(ps_atc0_cio_pcie): power-controller@2e8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2e8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -493,7 +493,7 @@ }; DIE_NODE(ps_atc0_cio_usb): power-controller@2f0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2f0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -502,7 +502,7 @@ }; DIE_NODE(ps_atc1_cio_pcie): power-controller@2f8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2f8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -511,7 +511,7 @@ }; DIE_NODE(ps_atc1_cio_usb): power-controller@300 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x300 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -520,7 +520,7 @@ }; DIE_NODE(ps_atc2_cio_pcie): power-controller@308 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x308 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -529,7 +529,7 @@ }; DIE_NODE(ps_atc2_cio_usb): power-controller@310 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x310 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -538,7 +538,7 @@ }; DIE_NODE(ps_atc3_cio_pcie): power-controller@318 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x318 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -547,7 +547,7 @@ }; DIE_NODE(ps_atc3_cio_usb): power-controller@320 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x320 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -556,7 +556,7 @@ }; DIE_NODE(ps_trace_fab): power-controller@390 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x390 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -564,7 +564,7 @@ }; DIE_NODE(ps_ane_sys_mpm): power-controller@4000 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4000 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -573,7 +573,7 @@ }; DIE_NODE(ps_ane_td): power-controller@4008 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4008 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -582,7 +582,7 @@ }; DIE_NODE(ps_ane_base): power-controller@4010 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4010 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -591,7 +591,7 @@ }; DIE_NODE(ps_ane_set1): power-controller@4018 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4018 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -600,7 +600,7 @@ }; DIE_NODE(ps_ane_set2): power-controller@4020 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4020 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -609,7 +609,7 @@ }; DIE_NODE(ps_ane_set3): power-controller@4028 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4028 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -618,7 +618,7 @@ }; DIE_NODE(ps_ane_set4): power-controller@4030 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4030 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -629,7 +629,7 @@ &DIE_NODE(pmgr_south) { DIE_NODE(ps_amcc4): power-controller@100 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x100 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -638,7 +638,7 @@ }; DIE_NODE(ps_amcc5): power-controller@108 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x108 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -647,7 +647,7 @@ }; DIE_NODE(ps_amcc6): power-controller@110 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x110 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -656,7 +656,7 @@ }; DIE_NODE(ps_amcc7): power-controller@118 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x118 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -665,7 +665,7 @@ }; DIE_NODE(ps_dcs_16): power-controller@120 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x120 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -674,7 +674,7 @@ }; DIE_NODE(ps_dcs_17): power-controller@128 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x128 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -683,7 +683,7 @@ }; DIE_NODE(ps_dcs_18): power-controller@130 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x130 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -692,7 +692,7 @@ }; DIE_NODE(ps_dcs_19): power-controller@138 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x138 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -701,7 +701,7 @@ }; DIE_NODE(ps_dcs_20): power-controller@140 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x140 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -710,7 +710,7 @@ }; DIE_NODE(ps_dcs_21): power-controller@148 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x148 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -719,7 +719,7 @@ }; DIE_NODE(ps_dcs_22): power-controller@150 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x150 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -728,7 +728,7 @@ }; DIE_NODE(ps_dcs_23): power-controller@158 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x158 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -737,7 +737,7 @@ }; DIE_NODE(ps_dcs_24): power-controller@160 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x160 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -746,7 +746,7 @@ }; DIE_NODE(ps_dcs_25): power-controller@168 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x168 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -755,7 +755,7 @@ }; DIE_NODE(ps_dcs_26): power-controller@170 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x170 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -764,7 +764,7 @@ }; DIE_NODE(ps_dcs_27): power-controller@178 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x178 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -773,7 +773,7 @@ }; DIE_NODE(ps_dcs_28): power-controller@180 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x180 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -782,7 +782,7 @@ }; DIE_NODE(ps_dcs_29): power-controller@188 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x188 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -791,7 +791,7 @@ }; DIE_NODE(ps_dcs_30): power-controller@190 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x190 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -800,7 +800,7 @@ }; DIE_NODE(ps_dcs_31): power-controller@198 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x198 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -809,7 +809,7 @@ }; DIE_NODE(ps_afnc4_ioa): power-controller@1a0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1a0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -819,7 +819,7 @@ }; DIE_NODE(ps_afnc4_ls): power-controller@1a8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1a8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -829,7 +829,7 @@ }; DIE_NODE(ps_afnc4_lw0): power-controller@1b0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1b0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -839,7 +839,7 @@ }; DIE_NODE(ps_afnc5_ioa): power-controller@1b8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1b8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -849,7 +849,7 @@ }; DIE_NODE(ps_afnc5_ls): power-controller@1c0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1c0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -859,7 +859,7 @@ }; DIE_NODE(ps_afnc5_lw0): power-controller@1c8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1c8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -869,7 +869,7 @@ }; DIE_NODE(ps_dispext2_sys): power-controller@1d0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1d0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -877,7 +877,7 @@ }; DIE_NODE(ps_msr1): power-controller@1d8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1d8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -885,7 +885,7 @@ }; DIE_NODE(ps_dispext2_fe): power-controller@1e0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1e0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -894,7 +894,7 @@ }; DIE_NODE(ps_dispext2_cpu0): power-controller@1e8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1e8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -904,7 +904,7 @@ }; DIE_NODE(ps_msr1_ase_core): power-controller@1f0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1f0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -913,7 +913,7 @@ }; DIE_NODE(ps_dispext3_sys): power-controller@220 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x220 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -921,7 +921,7 @@ }; DIE_NODE(ps_venc1_sys): power-controller@228 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x228 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -929,7 +929,7 @@ }; DIE_NODE(ps_dispext3_fe): power-controller@230 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x230 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -938,7 +938,7 @@ }; DIE_NODE(ps_dispext3_cpu0): power-controller@238 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x238 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -948,7 +948,7 @@ }; DIE_NODE(ps_venc1_dma): power-controller@4000 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4000 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -957,7 +957,7 @@ }; DIE_NODE(ps_venc1_pipe4): power-controller@4008 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4008 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -966,7 +966,7 @@ }; DIE_NODE(ps_venc1_pipe5): power-controller@4010 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4010 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -975,7 +975,7 @@ }; DIE_NODE(ps_venc1_me0): power-controller@4018 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4018 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -984,7 +984,7 @@ }; DIE_NODE(ps_venc1_me1): power-controller@4020 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4020 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -995,7 +995,7 @@ &DIE_NODE(pmgr_east) { DIE_NODE(ps_clvr_spmi0): power-controller@100 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x100 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1004,7 +1004,7 @@ }; DIE_NODE(ps_clvr_spmi1): power-controller@108 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x108 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1013,7 +1013,7 @@ }; DIE_NODE(ps_clvr_spmi2): power-controller@110 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x110 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1022,7 +1022,7 @@ }; DIE_NODE(ps_clvr_spmi3): power-controller@118 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x118 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1031,7 +1031,7 @@ }; DIE_NODE(ps_clvr_spmi4): power-controller@120 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x120 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1040,7 +1040,7 @@ }; DIE_NODE(ps_ispsens0): power-controller@128 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x128 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1048,7 +1048,7 @@ }; DIE_NODE(ps_ispsens1): power-controller@130 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x130 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1056,7 +1056,7 @@ }; DIE_NODE(ps_ispsens2): power-controller@138 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x138 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1064,7 +1064,7 @@ }; DIE_NODE(ps_ispsens3): power-controller@140 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x140 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1072,7 +1072,7 @@ }; DIE_NODE(ps_afnc6_ioa): power-controller@148 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x148 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1082,7 +1082,7 @@ }; DIE_NODE(ps_afnc6_ls): power-controller@150 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x150 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1092,7 +1092,7 @@ }; DIE_NODE(ps_afnc6_lw0): power-controller@158 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x158 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1102,7 +1102,7 @@ }; DIE_NODE(ps_afnc2_ioa): power-controller@160 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x160 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1112,7 +1112,7 @@ }; DIE_NODE(ps_afnc2_ls): power-controller@168 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x168 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1122,7 +1122,7 @@ }; DIE_NODE(ps_afnc2_lw0): power-controller@170 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x170 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1132,7 +1132,7 @@ }; DIE_NODE(ps_afnc2_lw1): power-controller@178 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x178 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1142,7 +1142,7 @@ }; DIE_NODE(ps_afnc3_ioa): power-controller@180 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x180 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1152,7 +1152,7 @@ }; DIE_NODE(ps_afnc3_ls): power-controller@188 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x188 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1162,7 +1162,7 @@ }; DIE_NODE(ps_afnc3_lw0): power-controller@190 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x190 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1172,7 +1172,7 @@ }; DIE_NODE(ps_apcie_gp): power-controller@198 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x198 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1181,7 +1181,7 @@ }; DIE_NODE(ps_apcie_st): power-controller@1a0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1a0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1190,7 +1190,7 @@ }; DIE_NODE(ps_ans2): power-controller@1a8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1a8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1199,7 +1199,7 @@ }; DIE_NODE(ps_disp0_sys): power-controller@1b0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1b0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1208,7 +1208,7 @@ }; DIE_NODE(ps_jpg): power-controller@1b8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1b8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1217,7 +1217,7 @@ }; DIE_NODE(ps_sio): power-controller@1c0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1c0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1226,7 +1226,7 @@ }; DIE_NODE(ps_isp_sys): power-controller@1c8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1c8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1236,7 +1236,7 @@ }; DIE_NODE(ps_disp0_fe): power-controller@1d0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1d0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1245,7 +1245,7 @@ }; DIE_NODE(ps_disp0_cpu0): power-controller@1d8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1d8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1255,7 +1255,7 @@ }; DIE_NODE(ps_sio_cpu): power-controller@1e0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1e0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1264,7 +1264,7 @@ }; DIE_NODE(ps_fpwm0): power-controller@1e8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1e8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1273,7 +1273,7 @@ }; DIE_NODE(ps_fpwm1): power-controller@1f0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1f0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1282,7 +1282,7 @@ }; DIE_NODE(ps_fpwm2): power-controller@1f8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x1f8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1291,7 +1291,7 @@ }; DIE_NODE(ps_i2c0): power-controller@200 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x200 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1300,7 +1300,7 @@ }; DIE_NODE(ps_i2c1): power-controller@208 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x208 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1309,7 +1309,7 @@ }; DIE_NODE(ps_i2c2): power-controller@210 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x210 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1318,7 +1318,7 @@ }; DIE_NODE(ps_i2c3): power-controller@218 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x218 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1327,7 +1327,7 @@ }; DIE_NODE(ps_i2c4): power-controller@220 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x220 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1336,7 +1336,7 @@ }; DIE_NODE(ps_i2c5): power-controller@228 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x228 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1345,7 +1345,7 @@ }; DIE_NODE(ps_i2c6): power-controller@230 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x230 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1354,7 +1354,7 @@ }; DIE_NODE(ps_i2c7): power-controller@238 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x238 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1363,7 +1363,7 @@ }; DIE_NODE(ps_i2c8): power-controller@240 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x240 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1372,7 +1372,7 @@ }; DIE_NODE(ps_spi_p): power-controller@248 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x248 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1381,7 +1381,7 @@ }; DIE_NODE(ps_sio_spmi0): power-controller@250 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x250 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1390,7 +1390,7 @@ }; DIE_NODE(ps_sio_spmi1): power-controller@258 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x258 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1399,7 +1399,7 @@ }; DIE_NODE(ps_sio_spmi2): power-controller@260 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x260 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1408,7 +1408,7 @@ }; DIE_NODE(ps_uart_p): power-controller@268 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x268 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1417,7 +1417,7 @@ }; DIE_NODE(ps_audio_p): power-controller@270 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x270 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1426,7 +1426,7 @@ }; DIE_NODE(ps_sio_adma): power-controller@278 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x278 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1435,7 +1435,7 @@ }; DIE_NODE(ps_aes): power-controller@280 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x280 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1445,7 +1445,7 @@ }; DIE_NODE(ps_dptx_phy_ps): power-controller@288 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x288 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1455,7 +1455,7 @@ }; DIE_NODE(ps_spi0): power-controller@2d8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2d8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1464,7 +1464,7 @@ }; DIE_NODE(ps_spi1): power-controller@2e0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2e0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1473,7 +1473,7 @@ }; DIE_NODE(ps_spi2): power-controller@2e8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2e8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1482,7 +1482,7 @@ }; DIE_NODE(ps_spi3): power-controller@2f0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2f0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1491,7 +1491,7 @@ }; DIE_NODE(ps_spi4): power-controller@2f8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x2f8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1500,7 +1500,7 @@ }; DIE_NODE(ps_spi5): power-controller@300 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x300 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1509,7 +1509,7 @@ }; DIE_NODE(ps_uart_n): power-controller@308 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x308 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1518,7 +1518,7 @@ }; DIE_NODE(ps_uart0): power-controller@310 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x310 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1527,7 +1527,7 @@ }; DIE_NODE(ps_amcc1): power-controller@318 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x318 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1536,7 +1536,7 @@ }; DIE_NODE(ps_amcc3): power-controller@320 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x320 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1545,7 +1545,7 @@ }; DIE_NODE(ps_dcs_04): power-controller@328 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x328 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1554,7 +1554,7 @@ }; DIE_NODE(ps_dcs_05): power-controller@330 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x330 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1563,7 +1563,7 @@ }; DIE_NODE(ps_dcs_06): power-controller@338 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x338 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1572,7 +1572,7 @@ }; DIE_NODE(ps_dcs_07): power-controller@340 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x340 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1581,7 +1581,7 @@ }; DIE_NODE(ps_dcs_12): power-controller@348 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x348 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1590,7 +1590,7 @@ }; DIE_NODE(ps_dcs_13): power-controller@350 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x350 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1599,7 +1599,7 @@ }; DIE_NODE(ps_dcs_14): power-controller@358 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x358 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1608,7 +1608,7 @@ }; DIE_NODE(ps_dcs_15): power-controller@360 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x360 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1617,7 +1617,7 @@ }; DIE_NODE(ps_uart1): power-controller@368 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x368 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1626,7 +1626,7 @@ }; DIE_NODE(ps_uart2): power-controller@370 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x370 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1635,7 +1635,7 @@ }; DIE_NODE(ps_uart3): power-controller@378 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x378 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1644,7 +1644,7 @@ }; DIE_NODE(ps_uart4): power-controller@380 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x380 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1653,7 +1653,7 @@ }; DIE_NODE(ps_uart5): power-controller@388 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x388 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1662,7 +1662,7 @@ }; DIE_NODE(ps_uart6): power-controller@390 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x390 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1671,7 +1671,7 @@ }; DIE_NODE(ps_mca0): power-controller@398 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x398 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1680,7 +1680,7 @@ }; DIE_NODE(ps_mca1): power-controller@3a0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3a0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1689,7 +1689,7 @@ }; DIE_NODE(ps_mca2): power-controller@3a8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3a8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1698,7 +1698,7 @@ }; DIE_NODE(ps_mca3): power-controller@3b0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3b0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1707,7 +1707,7 @@ }; DIE_NODE(ps_dpa0): power-controller@3b8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3b8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1716,7 +1716,7 @@ }; DIE_NODE(ps_dpa1): power-controller@3c0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3c0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1725,7 +1725,7 @@ }; DIE_NODE(ps_dpa2): power-controller@3c8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3c8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1734,7 +1734,7 @@ }; DIE_NODE(ps_dpa3): power-controller@3d0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3d0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1743,7 +1743,7 @@ }; DIE_NODE(ps_msr0): power-controller@3d8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3d8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1751,7 +1751,7 @@ }; DIE_NODE(ps_venc_sys): power-controller@3e0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3e0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1759,7 +1759,7 @@ }; DIE_NODE(ps_dpa4): power-controller@3e8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3e8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1768,7 +1768,7 @@ }; DIE_NODE(ps_msr0_ase_core): power-controller@3f0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3f0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1777,7 +1777,7 @@ }; DIE_NODE(ps_apcie_gpshr_sys): power-controller@3f8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x3f8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1786,7 +1786,7 @@ }; DIE_NODE(ps_apcie_st_sys): power-controller@408 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x408 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1795,7 +1795,7 @@ }; DIE_NODE(ps_apcie_st1_sys): power-controller@410 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x410 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1804,7 +1804,7 @@ }; DIE_NODE(ps_apcie_gp_sys): power-controller@418 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x418 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1814,7 +1814,7 @@ }; DIE_NODE(ps_apcie_ge_sys): power-controller@420 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x420 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1823,7 +1823,7 @@ }; DIE_NODE(ps_apcie_phy_sw): power-controller@428 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x428 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1832,7 +1832,7 @@ }; DIE_NODE(ps_sep): power-controller@c00 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xc00 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1849,7 +1849,7 @@ * have to enable/disable everything in the per-model DTs. */ DIE_NODE(ps_isp_cpu): power-controller@4000 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4000 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1859,7 +1859,7 @@ }; DIE_NODE(ps_isp_fe): power-controller@4008 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4008 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1868,7 +1868,7 @@ }; DIE_NODE(ps_dprx): power-controller@4010 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4010 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1877,7 +1877,7 @@ }; DIE_NODE(ps_isp_vis): power-controller@4018 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4018 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1886,7 +1886,7 @@ }; DIE_NODE(ps_isp_be): power-controller@4020 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4020 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1895,7 +1895,7 @@ }; DIE_NODE(ps_isp_raw): power-controller@4028 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4028 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1904,7 +1904,7 @@ }; DIE_NODE(ps_isp_clr): power-controller@4030 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x4030 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1913,7 +1913,7 @@ }; DIE_NODE(ps_venc_dma): power-controller@8000 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x8000 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1922,7 +1922,7 @@ }; DIE_NODE(ps_venc_pipe4): power-controller@8008 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x8008 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1931,7 +1931,7 @@ }; DIE_NODE(ps_venc_pipe5): power-controller@8010 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x8010 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1940,7 +1940,7 @@ }; DIE_NODE(ps_venc_me0): power-controller@8018 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x8018 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1949,7 +1949,7 @@ }; DIE_NODE(ps_venc_me1): power-controller@8020 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x8020 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1958,7 +1958,7 @@ }; DIE_NODE(ps_prores): power-controller@c000 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xc000 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1969,7 +1969,7 @@ &DIE_NODE(pmgr_mini) { DIE_NODE(ps_debug): power-controller@58 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x58 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1978,7 +1978,7 @@ }; DIE_NODE(ps_nub_spmi0): power-controller@60 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x60 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1987,7 +1987,7 @@ }; DIE_NODE(ps_nub_spmi1): power-controller@68 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x68 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -1996,7 +1996,7 @@ }; DIE_NODE(ps_nub_aon): power-controller@70 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x70 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2005,7 +2005,7 @@ }; DIE_NODE(ps_msg): power-controller@78 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x78 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2014,7 +2014,7 @@ }; DIE_NODE(ps_nub_gpio): power-controller@80 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x80 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2023,7 +2023,7 @@ }; DIE_NODE(ps_nub_fabric): power-controller@88 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x88 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2032,7 +2032,7 @@ }; DIE_NODE(ps_atc0_usb_aon): power-controller@90 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x90 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2041,7 +2041,7 @@ }; DIE_NODE(ps_atc1_usb_aon): power-controller@98 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x98 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2050,7 +2050,7 @@ }; DIE_NODE(ps_atc2_usb_aon): power-controller@a0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xa0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2059,7 +2059,7 @@ }; DIE_NODE(ps_atc3_usb_aon): power-controller@a8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xa8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2068,7 +2068,7 @@ }; DIE_NODE(ps_mtp_fabric): power-controller@b0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xb0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2079,7 +2079,7 @@ }; DIE_NODE(ps_nub_sram): power-controller@b8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xb8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2088,7 +2088,7 @@ }; DIE_NODE(ps_debug_switch): power-controller@c0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xc0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2097,7 +2097,7 @@ }; DIE_NODE(ps_atc0_usb): power-controller@c8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xc8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2106,7 +2106,7 @@ }; DIE_NODE(ps_atc1_usb): power-controller@d0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xd0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2115,7 +2115,7 @@ }; DIE_NODE(ps_atc2_usb): power-controller@d8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xd8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2124,7 +2124,7 @@ }; DIE_NODE(ps_atc3_usb): power-controller@e0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xe0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2135,7 +2135,7 @@ #if 0 /* MTP stuff is self-managed */ DIE_NODE(ps_mtp_gpio): power-controller@e8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xe8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2145,7 +2145,7 @@ }; DIE_NODE(ps_mtp_base): power-controller@f0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xf0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2155,7 +2155,7 @@ }; DIE_NODE(ps_mtp_periph): power-controller@f8 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0xf8 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2165,7 +2165,7 @@ }; DIE_NODE(ps_mtp_spi0): power-controller@100 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x100 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2175,7 +2175,7 @@ }; DIE_NODE(ps_mtp_i2cm0): power-controller@108 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x108 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2185,7 +2185,7 @@ }; DIE_NODE(ps_mtp_uart0): power-controller@110 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x110 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2195,7 +2195,7 @@ }; DIE_NODE(ps_mtp_cpu): power-controller@118 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x118 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2205,7 +2205,7 @@ }; DIE_NODE(ps_mtp_scm_fabric): power-controller@120 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x120 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2215,7 +2215,7 @@ }; DIE_NODE(ps_mtp_sram): power-controller@128 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x128 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2225,7 +2225,7 @@ }; DIE_NODE(ps_mtp_dma): power-controller@130 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x130 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2238,7 +2238,7 @@ &DIE_NODE(pmgr_gfx) { DIE_NODE(ps_gpx): power-controller@0 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x0 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2248,7 +2248,7 @@ }; DIE_NODE(ps_afr): power-controller@100 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x100 4>; #power-domain-cells = <0>; #reset-cells = <0>; @@ -2258,7 +2258,7 @@ }; DIE_NODE(ps_gfx): power-controller@108 { - compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + compatible = "apple,t6020-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x108 4>; #power-domain-cells = <0>; #reset-cells = <0>; From 059089db1fe33680c66e928b66ec8c6b94972506 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 10 Apr 2023 18:15:33 +0900 Subject: [PATCH 032/352] arm64: dts: apple: Add MTP nodes to t6020x Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t6020-j414s.dts | 4 + arch/arm64/boot/dts/apple/t6020-j416s.dts | 4 + arch/arm64/boot/dts/apple/t6021-j414c.dts | 4 + arch/arm64/boot/dts/apple/t6021-j416c.dts | 4 + arch/arm64/boot/dts/apple/t602x-die0.dtsi | 76 +++++++++++++++++++ .../arm64/boot/dts/apple/t602x-j414-j416.dtsi | 42 ++++++++++ arch/arm64/boot/dts/apple/t8112.dtsi | 1 + 7 files changed, 135 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6020-j414s.dts b/arch/arm64/boot/dts/apple/t6020-j414s.dts index 18cc67a3076def..5dd97df71efc4b 100644 --- a/arch/arm64/boot/dts/apple/t6020-j414s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j414s.dts @@ -36,3 +36,7 @@ compatible = "apple,j414-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J414"; }; + +&mtp_mt { + firmware-name = "apple/tpmtfw-j414s.bin"; +}; diff --git a/arch/arm64/boot/dts/apple/t6020-j416s.dts b/arch/arm64/boot/dts/apple/t6020-j416s.dts index b9e0973ba37c30..56ddf7c61de634 100644 --- a/arch/arm64/boot/dts/apple/t6020-j416s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j416s.dts @@ -36,3 +36,7 @@ compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J416"; }; + +&mtp_mt { + firmware-name = "apple/tpmtfw-j416s.bin"; +}; diff --git a/arch/arm64/boot/dts/apple/t6021-j414c.dts b/arch/arm64/boot/dts/apple/t6021-j414c.dts index b173caf0df0fce..6905c7d39db0ce 100644 --- a/arch/arm64/boot/dts/apple/t6021-j414c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j414c.dts @@ -36,3 +36,7 @@ compatible = "apple,j414-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J414"; }; + +&mtp_mt { + firmware-name = "apple/tpmtfw-j414c.bin"; +}; diff --git a/arch/arm64/boot/dts/apple/t6021-j416c.dts b/arch/arm64/boot/dts/apple/t6021-j416c.dts index 2fbb00b364c72b..786ac2393d7535 100644 --- a/arch/arm64/boot/dts/apple/t6021-j416c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j416c.dts @@ -56,3 +56,7 @@ compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J416"; }; + +&mtp_mt { + firmware-name = "apple/tpmtfw-j416c.bin"; +}; diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 922ae4368978b0..a57fd27626a3b6 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -156,6 +156,82 @@ ; }; + mtp: mtp@2a9400000 { + compatible = "apple,t6020-mtp", "apple,t6020-rtk-helper-asc4", "apple,mtp", "apple,rtk-helper-asc4"; + reg = <0x2 0xa9400000 0x0 0x4000>, + <0x2 0xa9c00000 0x0 0x100000>; + reg-names = "asc", "sram"; + mboxes = <&mtp_mbox>; + iommus = <&mtp_dart 1>; + #helper-cells = <0>; + + status = "disabled"; + }; + + mtp_mbox: mbox@2a9408000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0xa9408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + + status = "disabled"; + }; + + mtp_dart: iommu@2a9808000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x2 0xa9808000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = ; + #iommu-cells = <1>; + + apple,dma-range = <0x100 0x0 0x1 0x0>; + + status = "disabled"; + }; + + mtp_dockchannel: fifo@2a9b14000 { + compatible = "apple,t6020-dockchannel", "apple,dockchannel"; + reg = <0x2 0xa9b14000 0x0 0x4000>; + reg-names = "irq"; + interrupt-parent = <&aic>; + interrupts = ; + + ranges = <0 0x2 0xa9b28000 0x20000>; + nonposted-mmio; + #address-cells = <1>; + #size-cells = <1>; + + interrupt-controller; + #interrupt-cells = <2>; + + status = "disabled"; + + mtp_hid: input@8000 { + compatible = "apple,dockchannel-hid"; + reg = <0x8000 0x4000>, + <0xc000 0x4000>, + <0x0000 0x4000>, + <0x4000 0x4000>; + reg-names = "config", "data", + "rmt-config", "rmt-data"; + iommus = <&mtp_dart 1>; + interrupt-parent = <&mtp_dockchannel>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, + <3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tx", "rx"; + + apple,fifo-size = <0x800>; + apple,helper-cpu = <&mtp>; + }; + + }; + disp0_dart: iommu@389304000 { compatible = "apple,t6020-dart", "apple,t8110-dart"; reg = <0x3 0x89304000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi index b0fa34282681de..5df64390ef6812 100644 --- a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi @@ -89,3 +89,45 @@ &port01 { pwren-gpios = <&smc_gpio 22 GPIO_ACTIVE_HIGH>; }; + +&ps_mtp_fabric { + status = "okay"; +}; + +&mtp { + status = "okay"; +}; + +&mtp_mbox { + status = "okay"; +}; + +&mtp_dart { + status = "okay"; +}; + +&mtp_dockchannel { + status = "okay"; +}; + +&mtp_hid { + apple,afe-reset-gpios = <&smc_gpio 25 GPIO_ACTIVE_LOW>; + apple,stm-reset-gpios = <&smc_gpio 26 GPIO_ACTIVE_LOW>; + + mtp_mt: multi-touch { + }; + + keyboard: keyboard { + hid-country-code = <0>; + apple,keyboard-layout-id = <0>; + }; + + stm { + }; + + actuator { + }; + + tp_accel { + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 38a09dafaab03f..e479495b733b07 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1197,6 +1197,7 @@ interrupts = ; ranges = <0 0x2 0x4eb28000 0x20000>; + nonposted-mmio; #address-cells = <1>; #size-cells = <1>; From ad763c08c9a04abf6af3757b723fe32d05375a0c Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 12 Oct 2023 23:20:39 +0900 Subject: [PATCH 033/352] arm64: dts: apple: t602x: Mark MCA power states as externally-clocked Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t602x-pmgr.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi index f5ebd5bc19b33a..8633a939592a86 100644 --- a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi @@ -1677,6 +1677,7 @@ #reset-cells = <0>; label = DIE_LABEL(mca0); power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + apple,externally-clocked; }; DIE_NODE(ps_mca1): power-controller@3a0 { @@ -1686,6 +1687,7 @@ #reset-cells = <0>; label = DIE_LABEL(mca1); power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + apple,externally-clocked; }; DIE_NODE(ps_mca2): power-controller@3a8 { @@ -1695,6 +1697,7 @@ #reset-cells = <0>; label = DIE_LABEL(mca2); power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + apple,externally-clocked; }; DIE_NODE(ps_mca3): power-controller@3b0 { @@ -1704,6 +1707,7 @@ #reset-cells = <0>; label = DIE_LABEL(mca3); power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + apple,externally-clocked; }; DIE_NODE(ps_dpa0): power-controller@3b8 { From 5c01b37543d5ae408f7e88a4b252a76c74fb4054 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 29 Oct 2023 08:55:40 +1000 Subject: [PATCH 034/352] arm64: dts: apple: t602x: describe shared SDZ GPIO for tas2764 machines with the tas2764 amp codec share a GPIO line for asserting/deasserting the SDZ pin on the chips. describe this as a regulator to facilitate chip reset on suspend/resume Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi index 5df64390ef6812..37d1d523d1cdec 100644 --- a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi @@ -43,33 +43,32 @@ interrupts = <44 IRQ_TYPE_LEVEL_LOW>; }; +/* Redefine GPIO for SDZ */ +&speaker_sdz { + gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; +}; + &speaker_left_tweet { - shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; }; &speaker_left_woof1 { - shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; }; &speaker_left_woof2 { - shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; }; &speaker_right_tweet { - shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; }; &speaker_right_woof1 { - shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; }; &speaker_right_woof2 { - shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>; interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; }; From 36c28faad69f600e68c782b641d2c031cc68e4b2 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 13 Oct 2023 01:37:23 +0900 Subject: [PATCH 035/352] arm64: dts: apple: t602x-j180d: Add I/VMON slots to amps Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t6022-j180d.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6022-j180d.dts b/arch/arm64/boot/dts/apple/t6022-j180d.dts index 59e5825a0368fa..c0674aad5c49c9 100644 --- a/arch/arm64/boot/dts/apple/t6022-j180d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j180d.dts @@ -542,6 +542,8 @@ #sound-dai-cells = <0>; sound-name-prefix = "Tweeter"; interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <4>; + ti,vmon-slot-no = <6>; }; speaker_woofer: codec@39 { @@ -551,6 +553,8 @@ #sound-dai-cells = <0>; sound-name-prefix = "Woofer"; interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>; + ti,imon-slot-no = <0>; + ti,vmon-slot-no = <2>; }; }; From ab400af2d596a159f8bf0cb37b0237e2571713ae Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 11 Apr 2023 02:34:01 +0900 Subject: [PATCH 036/352] arm64: dts: apple: t602x: Add identity dma-ranges mapping Without this, the OF core ends up limiting all DMA masks to the default 32-bit, since that runs before drivers set up the proper DMA mask. Skipping the highest page because it is impossible to express a full 64-bit range in the DT. Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t6021.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6021.dtsi b/arch/arm64/boot/dts/apple/t6021.dtsi index 1205a43da383f7..bb0e66851f1b59 100644 --- a/arch/arm64/boot/dts/apple/t6021.dtsi +++ b/arch/arm64/boot/dts/apple/t6021.dtsi @@ -35,6 +35,8 @@ ranges; nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; // filled via templated includes at the end of the file }; From 037454b809aa850fd2cb29d919adb91046db6bb7 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 18 Apr 2023 05:05:57 +0900 Subject: [PATCH 037/352] arm64: dts: apple: Add pmgr-misc nodes to t60xx --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 10 ++++++++++ arch/arm64/boot/dts/apple/t602x-die0.dtsi | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index f5b4d85a61186a..caecc1e3f3fac1 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -24,6 +24,16 @@ power-domains = <&ps_aic>; }; + pmgr_misc: power-management@28e20c000 { + compatible = "apple,t6000-pmgr-misc"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2 0x8e20c000 0 0x400>, + <0x2 0x8e20c800 0 0x400>; + reg-names = "fabric-ps", "dcs-ps"; + apple,dcs-min-ps = <7>; + }; + pmgr_dcp: power-management@28e3d0000 { reg = <0x2 0x8e3d0000 0x0 0x4000>; reg-names = "dcp-fw-pmgr"; diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index a57fd27626a3b6..4d6d682ca0038e 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -23,6 +23,15 @@ power-domains = <&ps_aic>; }; + pmgr_misc: power-management@28e20c000 { + compatible = "apple,t6020-pmgr-misc", "apple,t6000-pmgr-misc"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2 0x8e20c000 0 0x400>, + <0x2 0x8e20c400 0 0x400>; + reg-names = "fabric-ps", "dcs-ps"; + }; + pmgr_dcp: power-management@28e3d0000 { reg = <0x2 0x8e3d0000 0x0 0x4000>; reg-names = "dcp-fw-pmgr"; From 0bf5d12e3b192690fd240ff7913828155d763df5 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 26 Apr 2023 02:17:26 +0900 Subject: [PATCH 038/352] arm64: dts: apple: Make ps_msg always-on Apple has it that way, and it might be important. Let's not risk it. Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 1 + arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 1 + arch/arm64/boot/dts/apple/t8112-pmgr.dtsi | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index 3315b392b21d72..84d5e126e2320e 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -1877,6 +1877,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(msg); + apple,always-on; /* Core AON device? */ }; DIE_NODE(ps_nub_gpio): power-controller@80 { diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi index f0ae11bf6ce688..a97d64b665730f 100644 --- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi @@ -1101,6 +1101,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = "msg"; + apple,always-on; /* Core AON device? */ }; ps_atc0_usb_aon: power-controller@88 { diff --git a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi index 276f1ab35f06a3..7ff5052d1cdcbc 100644 --- a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi @@ -1067,6 +1067,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = "msg"; + apple,always-on; /* Core AON device? */ }; ps_nub_gpio: power-controller@80 { From c4cd5edcb335da673bb08dcd6200f8660f5d99c0 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 7 Aug 2023 19:53:50 +0900 Subject: [PATCH 039/352] arm64: dts: apple: t6022: Add APCIE-GE nodes arm64: dts: apple: t6022-j180d: Add node for built-in PCIe devices Currently only the two ethernet controllers and the SATA-AHCI are detected. The USB controller (internal USB-A port and USB-A ports on the I/O board) are missing code to toggle the reset gpio pin. The Broadcom Wlan/BT device needs in addition the SMC power enable GPIO. The "bluetooth0" and "wifi0" aliases can not be added since the ADT misses calibration data for Wlan and BT. arm64: dts: apple: Move PCIe-GE nodes intro their own file These are only used on the Mac Pro (M2 Ultra, 2023) so do not bloat all other DTBs. Signed-off-by: Hector Martin Co-developed-by: Janne Grunau Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6022-j180d.dts | 352 +++++++++++++++++- arch/arm64/boot/dts/apple/t6022-pcie-ge.dtsi | 27 ++ arch/arm64/boot/dts/apple/t6022.dtsi | 6 + .../arm64/boot/dts/apple/t602x-gpio-pins.dtsi | 4 + arch/arm64/boot/dts/apple/t602x-pcie-ge.dtsi | 87 +++++ 5 files changed, 472 insertions(+), 4 deletions(-) create mode 100644 arch/arm64/boot/dts/apple/t6022-pcie-ge.dtsi create mode 100644 arch/arm64/boot/dts/apple/t602x-pcie-ge.dtsi diff --git a/arch/arm64/boot/dts/apple/t6022-j180d.dts b/arch/arm64/boot/dts/apple/t6022-j180d.dts index c0674aad5c49c9..e22dd039bbae85 100644 --- a/arch/arm64/boot/dts/apple/t6022-j180d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j180d.dts @@ -11,6 +11,7 @@ #include "t6022.dtsi" #include "t6022-jxxxd.dtsi" +#include "t6022-pcie-ge.dtsi" / { compatible = "apple,j180d", "apple,t6022", "apple,arm-platform"; @@ -26,11 +27,11 @@ atcphy5 = &atcphy1_die1; atcphy6 = &atcphy2_die1; atcphy7 = &atcphy3_die1; - //bluetooth0 = &bluetooth0; - //ethernet0 = ðernet0; - //ethernet1 = ðernet1; + bluetooth0 = &bluetooth0; + ethernet0 = ðernet0; + ethernet1 = ðernet1; serial0 = &serial0; - //wifi0 = &wifi0; + wifi0 = &wifi0; }; chosen { @@ -611,6 +612,349 @@ }; }; +/* PCIe devices */ +&port_ge00 { + bus-range = <0x01 0x09>; + + pci@0,0 { + // compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x10000 0x00 0x00 0x00 0x00>; + bus-range = <0x02 0x07>; + + #address-cells = <0x03>; + #size-cells = <0x02>; + ranges = <0x82010000 0x00 0x80000000 0x82010000 0x00 0x80000000 0x00 0x500000>, + <0xc3010000 0x18 0x00000000 0xc3010000 0x18 0x00000000 0x00 0x500000>; + + #interrupt-cells = <0x01>; + interrupt-map-mask = <0xffff00 0x00 0x00 0x07>; + interrupt-map = <0x20000 0x00 0x00 0x01 &port_ge00 0x00 0x00 0x00 0x00>, + <0x20000 0x00 0x00 0x02 &port_ge00 0x00 0x00 0x00 0x01>, + <0x20000 0x00 0x00 0x03 &port_ge00 0x00 0x00 0x00 0x02>, + <0x20000 0x00 0x00 0x04 &port_ge00 0x00 0x00 0x00 0x03>, + <0x20800 0x00 0x00 0x01 &port_ge00 0x00 0x00 0x00 0x01>, + <0x20800 0x00 0x00 0x02 &port_ge00 0x00 0x00 0x00 0x02>, + <0x20800 0x00 0x00 0x03 &port_ge00 0x00 0x00 0x00 0x03>, + <0x20800 0x00 0x00 0x04 &port_ge00 0x00 0x00 0x00 0x00>, + <0x21000 0x00 0x00 0x01 &port_ge00 0x00 0x00 0x00 0x02>, + <0x21000 0x00 0x00 0x02 &port_ge00 0x00 0x00 0x00 0x03>, + <0x21000 0x00 0x00 0x03 &port_ge00 0x00 0x00 0x00 0x00>, + <0x21000 0x00 0x00 0x04 &port_ge00 0x00 0x00 0x00 0x01>, + <0x21800 0x00 0x00 0x01 &port_ge00 0x00 0x00 0x00 0x03>, + <0x21800 0x00 0x00 0x02 &port_ge00 0x00 0x00 0x00 0x00>, + <0x21800 0x00 0x00 0x03 &port_ge00 0x00 0x00 0x00 0x01>, + <0x21800 0x00 0x00 0x04 &port_ge00 0x00 0x00 0x00 0x02>, + <0x22000 0x00 0x00 0x01 &port_ge00 0x00 0x00 0x00 0x00>, + <0x22000 0x00 0x00 0x02 &port_ge00 0x00 0x00 0x00 0x01>, + <0x22000 0x00 0x00 0x03 &port_ge00 0x00 0x00 0x00 0x02>, + <0x22000 0x00 0x00 0x04 &port_ge00 0x00 0x00 0x00 0x03>; + + /* pci-slot1-dsp, PCIe slot-1 */ + pci@0,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x20000 0x00 0x00 0x00 0x00>; + bus-range = <0x03 0x03>; + + #address-cells = <0x03>; + #size-cells = <0x02>; + ranges; + }; + + /* pci-slot2-dsp, PCIe slot-2 */ + pci@1,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x20800 0x00 0x00 0x00 0x00>; + bus-range = <0x04 0x04>; + + #address-cells = <0x03>; + #size-cells = <0x02>; + ranges; + }; + + /* pci-slot3-dsp, PCIe slot-3 */ + pci@2,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x21000 0x00 0x00 0x00 0x00>; + bus-range = <0x05 0x05>; + + #address-cells = <0x03>; + #size-cells = <0x02>; + ranges; + }; + + /* pci-slot4-dsp, PCIe slot-4 */ + pci@3,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x21800 0x00 0x00 0x00 0x00>; + bus-range = <0x06 0x06>; + + #address-cells = <0x03>; + #size-cells = <0x02>; + ranges; + }; + + /* pci-slot5-dsp, PCIe slot-5 */ + pci@4,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x22000 0x00 0x00 0x00 0x00>; + bus-range = <0x07 0x07>; + + #address-cells = <0x03>; + #size-cells = <0x02>; + ranges; + }; + + }; +}; + +&port_ge00_die1 { + bus-range = <0x01 0x09>; + + /* + * Add mulptiple "reset-gpios" since there is no mechanismen to access + * PERST# for devices behind the PCIe switch. + * The "pwren" GPIO is from the wifi/bt chip which faces the same + * problem without pci-pwrctrl integration. + */ + reset-gpios = <&pinctrl_ap 4 GPIO_ACTIVE_LOW>, + <&pinctrl_ap 6 GPIO_ACTIVE_LOW>, + <&pinctrl_ap 7 GPIO_ACTIVE_LOW>, + <&pinctrl_ap_die1 9 GPIO_ACTIVE_LOW>; + pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; + + pci@0,0 { + device_type = "pci"; + reg = <0x10000 0x00 0x00 0x00 0x00>; + bus-range = <0x02 0x09>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + interrupt-controller; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffff00 0x00 0x00 0x07>; + interrupt-map = <0x20000 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x20000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x20000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x20000 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x03>, + <0x20800 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x20800 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x20800 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x03>, + <0x20800 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x21000 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x21000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x03>, + <0x21000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x21000 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x21800 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x03>, + <0x21800 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x21800 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x21800 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x22000 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x22000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x22000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x22000 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x03>, + <0x22800 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x22800 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x22800 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x03>, + <0x22800 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x23000 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x23000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x03>, + <0x23000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x23000 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x01>; + + /* pci-usba-dsp, internal USB-A port */ + pci@0,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x20000 0x00 0x00 0x00 0x00>; + bus-range = <0x03 0x03>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + interrupt-controller; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x30000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x30000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x30000 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x02>; + + /* temporarily handled in the root port */ + // reset-gpios = <&pinctrl_ap 6 GPIO_ACTIVE_LOW>; + }; + + /* pci-sata-dsp, internal AHCI controller */ + pci@1,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x20800 0x00 0x00 0x00 0x00>; + bus-range = <0x04 0x04>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + interrupt-controller; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x40000 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x40000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x40000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x02>; + }; + + /* pci-bio-dsp, I/O board USB-A ports */ + pci@2,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x21000 0x00 0x00 0x00 0x00>; + bus-range = <0x05 0x05>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + interrupt-controller; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x50000 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x50000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x50000 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x00>; + + /* temporarily handled in the root port */ + // reset-gpios = <&pinctrl_ap 7 GPIO_ACTIVE_LOW>; + }; + + /* pci-lan-dsp, Qtion AQC113 10G etherner controller (0) */ + pci@3,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x21800 0x00 0x00 0x00 0x00>; + bus-range = <0x06 0x06>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + interrupt-controller; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x60000 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x60000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x60000 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x01>; + + ethernet0: ethernet@0,0 { + reg = <0x60000 0x0 0x0 0x0 0x0>; + /* To be filled by the loader */ + local-mac-address = [00 10 18 00 00 00]; + }; + }; + + /* pci-lan-b-dsp, Qtion AQC113 10G etherner controller (1) */ + pci@4,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x22000 0x00 0x00 0x00 0x00>; + bus-range = <0x07 0x07>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + interrupt-controller; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x70000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x70000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x70000 0x00 0x00 0x04 &port_ge00_die1 0x00 0x00 0x00 0x02>; + + ethernet1: ethernet@0,0 { + reg = <0x70000 0x0 0x0 0x0 0x0>; + /* To be filled by the loader */ + local-mac-address = [00 10 18 00 00 00]; + }; + }; + + /* pci-wifibt-dsp, Broadcom BCM4388 Wlan/BT */ + pci@5,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x22800 0x00 0x00 0x00 0x00>; + bus-range = <0x08 0x08>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + interrupt-controller; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x80000 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x80000 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x80000 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x02>, + <0x80100 0x00 0x00 0x01 &port_ge00_die1 0x00 0x00 0x00 0x00>, + <0x80100 0x00 0x00 0x02 &port_ge00_die1 0x00 0x00 0x00 0x01>, + <0x80100 0x00 0x00 0x03 &port_ge00_die1 0x00 0x00 0x00 0x02>; + + /* temporarily handled in the root port */ + // reset-gpios = <&pinctrl_ap 4 GPIO_ACTIVE_LOW>; + // pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; + + wifi0: wifi@0,0 { + reg = <0x80000 0x0 0x0 0x0 0x0>; + compatible = "pci14e4,4433"; + brcm,board-type = "apple,sumatra"; + apple,antenna-sku = "XX"; + /* To be filled by the loader */ + local-mac-address = [00 10 18 00 00 10]; + }; + + bluetooth0: network@0,1 { + compatible = "pci14e4,5f71"; + brcm,board-type = "apple,sumatra"; + // reg = <0x80100 0x0 0x0 0x0 0x0>; + /* To be filled by the loader */ + local-bd-address = [00 00 00 00 00 00]; + }; + }; + + /* pci-slot6-dsp, PCIe slot-6 */ + pci@6,0 { + compatible = "pci11f8,4000", "pciclass,060400", "pciclass,0604"; + device_type = "pci"; + reg = <0x23000 0x00 0x00 0x00 0x00>; + bus-range = <0x09 0x09>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + }; + }; +}; + +&pcie_ge { + status = "ok"; +}; + +&pcie_ge_dart { + status = "ok"; +}; + +&pcie_ge_die1 { + status = "ok"; +}; + +&pcie_ge_dart_die1 { + status = "ok"; +}; + /* * Delete unused PCIe nodes, the Mac Pro uses slightly different PCIe * controllers with a single port connected to a PM40100 PCIe switch diff --git a/arch/arm64/boot/dts/apple/t6022-pcie-ge.dtsi b/arch/arm64/boot/dts/apple/t6022-pcie-ge.dtsi new file mode 100644 index 00000000000000..f78c483c29133f --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6022-pcie-ge.dtsi @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Include PCIe-GE nodes presen on both dies of T6022 (M2 Ultra) in the + * Mac Pro (2023). + * + * Copyright The Asahi Linux Contributors + */ + +#define DIE +#define DIE_NO 0 + +&die0 { + #include "t602x-pcie-ge.dtsi" +}; + +#undef DIE +#undef DIE_NO + +#define DIE _die1 +#define DIE_NO 1 + +&die1 { + #include "t602x-pcie-ge.dtsi" +}; + +#undef DIE +#undef DIE_NO diff --git a/arch/arm64/boot/dts/apple/t6022.dtsi b/arch/arm64/boot/dts/apple/t6022.dtsi index bc05cddf68f4f7..b7d13dafc7a265 100644 --- a/arch/arm64/boot/dts/apple/t6022.dtsi +++ b/arch/arm64/boot/dts/apple/t6022.dtsi @@ -367,3 +367,9 @@ apple,ppm-ki = <11.0>; apple,ppm-kp = <0.15>; }; + +&pinctrl_ap_die1 { + pcie_ge_pins_die1: pcie-ge1-pins { + pinmux = ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t602x-gpio-pins.dtsi b/arch/arm64/boot/dts/apple/t602x-gpio-pins.dtsi index e41b6475f79218..c5de99bd2e5cf3 100644 --- a/arch/arm64/boot/dts/apple/t602x-gpio-pins.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-gpio-pins.dtsi @@ -78,4 +78,8 @@ , ; }; + + pcie_ge_pins: pcie-ge-pins { + pinmux = ; + }; }; diff --git a/arch/arm64/boot/dts/apple/t602x-pcie-ge.dtsi b/arch/arm64/boot/dts/apple/t602x-pcie-ge.dtsi new file mode 100644 index 00000000000000..4a509cae0e5766 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t602x-pcie-ge.dtsi @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * PCIe-GE Nodes present on both dies of a T6022 (M2 Ultra) and M2 Pro/Max but + * only used on T6022 in the Mac Pro (2023). + * + * Copyright The Asahi Linux Contributors + */ + + DIE_NODE(pcie_ge): pcie@1680000000 { + compatible = "apple,t6020-pcie-ge", "apple,t6020-pcie"; + device_type = "pci"; + + reg = <0x16 0x80000000 0x0 0x1000000>, /* config */ + <0x16 0x91000000 0x0 0x4000>, /* rc */ + <0x16 0x94008000 0x0 0x4000>, /* port0 */ + <0x16 0x9e01c000 0x0 0x4000>, /* phy0 */ + <0x16 0x9401c000 0x0 0x1000>; /* ltssm0 */ + reg-names = "config", "rc", "port0", "phy0", "ltssm0"; + + interrupt-parent = <&aic>; + interrupts = ; + + msi-controller; + msi-parent = <&DIE_NODE(pcie_ge)>; + msi-ranges = <&aic AIC_IRQ DIE_NO 1672 IRQ_TYPE_EDGE_RISING 128>; + + iommu-map = <0x000 &DIE_NODE(pcie_ge_dart) 0 0>, + <0x100 &DIE_NODE(pcie_ge_dart) 1 1>, + <0x200 &DIE_NODE(pcie_ge_dart) 2 2>, + <0x300 &DIE_NODE(pcie_ge_dart) 3 3>, + <0x400 &DIE_NODE(pcie_ge_dart) 4 4>, + <0x500 &DIE_NODE(pcie_ge_dart) 5 5>, + <0x600 &DIE_NODE(pcie_ge_dart) 6 6>, + <0x700 &DIE_NODE(pcie_ge_dart) 7 7>, + <0x800 &DIE_NODE(pcie_ge_dart) 8 8>, + <0x900 &DIE_NODE(pcie_ge_dart) 9 9>, + <0xa00 &DIE_NODE(pcie_ge_dart) 10 10>, + <0xb00 &DIE_NODE(pcie_ge_dart) 11 11>, + <0xc00 &DIE_NODE(pcie_ge_dart) 12 12>, + <0xd00 &DIE_NODE(pcie_ge_dart) 13 13>, + <0xe00 &DIE_NODE(pcie_ge_dart) 14 14>, + <0xf00 &DIE_NODE(pcie_ge_dart) 15 15>; + iommu-map-mask = <0xff00>; + + bus-range = <0 15>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x43000000 0x18 0x00000000 0x18 0x00000000 0x4 0x00000000>, + <0x02000000 0x00 0x80000000 0x17 0x80000000 0x0 0x80000000>; + + power-domains = <&DIE_NODE(ps_apcie_ge_sys)>; + pinctrl-0 = <&DIE_NODE(pcie_ge_pins)>; + pinctrl-names = "default"; + + dma-coherent; + + status = "disabled"; + + DIE_NODE(port_ge00): pci@0,0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + reset-gpios = <&DIE_NODE(pinctrl_ap) 9 GPIO_ACTIVE_LOW>; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &DIE_NODE(port_ge00) 0 0 0 0>, + <0 0 0 2 &DIE_NODE(port_ge00) 0 0 0 1>, + <0 0 0 3 &DIE_NODE(port_ge00) 0 0 0 2>, + <0 0 0 4 &DIE_NODE(port_ge00) 0 0 0 3>; + }; + }; + + DIE_NODE(pcie_ge_dart): iommu@1694000000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x16 0x94000000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_apcie_ge_sys)>; + status = "disabled"; + }; From cdbe68fb9c61a7e29d2f4d3c43b3651eff506039 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 25 Sep 2023 19:55:58 +0200 Subject: [PATCH 040/352] arm64: dts: apple: t6020x: Mark dptx_phy_ps only on laptops always-on The desktops will need to handle this on their own. On laptops it is a little weird since dcp seems to handle the programming of the phy which is apparently used for the internal display. It might be possible to move this to the panel node once dcp is upstream ready. The chosen.framebuffer node should reference the panel then. In the meantime keep it always-on on notebooks. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi | 7 +++++++ arch/arm64/boot/dts/apple/t602x-pmgr.dtsi | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi index 37d1d523d1cdec..5aff7936721375 100644 --- a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi @@ -27,6 +27,13 @@ power-domains = <&ps_disp0_cpu0>, <&ps_dptx_phy_ps>; }; +/* HACK: keep dptx_phy_ps power-domain always-on + * it is unclear how to sequence with dcp for the integrated display + */ +&ps_dptx_phy_ps { + apple,always-on; +}; + &hpm0 { interrupts = <44 IRQ_TYPE_LEVEL_LOW>; }; diff --git a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi index 8633a939592a86..7d70e8bb08185a 100644 --- a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi @@ -1450,7 +1450,6 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(dptx_phy_ps); - apple,always-on; power-domains = <&DIE_NODE(ps_sio)>; }; From 25ed7ab95f771424a1b70d1166ab46f8d21fb987 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Mon, 6 Nov 2023 20:33:51 +1000 Subject: [PATCH 041/352] arm64: dts: apple: add opp-microwatt to t8103/t600x This patch adds measured opp-microwatt values for the Firestorm and Icestorm application cores found in Apple's T8103 (M1), T6000 (M1 Pro), T6001 (M1 Max) and T6002 (M1 Ultra) SoCs. Values were measured from the System Management Controller's core cluster power meter. A version of freqbench modified to read this power meter was used to orchestrate testing, running 1,000,000 iterations of coremark on a single core from each cluster at each operating point. The bulk of the testing was done on a T6000. Note that Apple calibrates voltage regulator settings for each SoC as they come off the assembly line, introducing some natural variance between machines. Testing across multiple machines with identical SoCs reveals no measurable impact on the accuracy of the EM subsystem's cost calculations. Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/t600x-common.dtsi | 20 ++++++++++++++++++++ arch/arm64/boot/dts/apple/t8103.dtsi | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi index f434d724096e58..58a535fd707d4d 100644 --- a/arch/arm64/boot/dts/apple/t600x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi @@ -229,26 +229,31 @@ opp-hz = /bits/ 64 <600000000>; opp-level = <1>; clock-latency-ns = <7500>; + opp-microwatt = <47296>; }; opp02 { opp-hz = /bits/ 64 <972000000>; opp-level = <2>; clock-latency-ns = <23000>; + opp-microwatt = <99715>; }; opp03 { opp-hz = /bits/ 64 <1332000000>; opp-level = <3>; clock-latency-ns = <29000>; + opp-microwatt = <188860>; }; opp04 { opp-hz = /bits/ 64 <1704000000>; opp-level = <4>; clock-latency-ns = <40000>; + opp-microwatt = <288891>; }; opp05 { opp-hz = /bits/ 64 <2064000000>; opp-level = <5>; clock-latency-ns = <50000>; + opp-microwatt = <412979>; }; }; @@ -259,78 +264,93 @@ opp-hz = /bits/ 64 <600000000>; opp-level = <1>; clock-latency-ns = <8000>; + opp-microwatt = <290230>; }; opp02 { opp-hz = /bits/ 64 <828000000>; opp-level = <2>; clock-latency-ns = <18000>; + opp-microwatt = <449013>; }; opp03 { opp-hz = /bits/ 64 <1056000000>; opp-level = <3>; clock-latency-ns = <19000>; + opp-microwatt = <647097>; }; opp04 { opp-hz = /bits/ 64 <1296000000>; opp-level = <4>; clock-latency-ns = <23000>; + opp-microwatt = <865620>; }; opp05 { opp-hz = /bits/ 64 <1524000000>; opp-level = <5>; clock-latency-ns = <24000>; + opp-microwatt = <1112838>; }; opp06 { opp-hz = /bits/ 64 <1752000000>; opp-level = <6>; clock-latency-ns = <28000>; + opp-microwatt = <1453271>; }; opp07 { opp-hz = /bits/ 64 <1980000000>; opp-level = <7>; clock-latency-ns = <31000>; + opp-microwatt = <1776667>; }; opp08 { opp-hz = /bits/ 64 <2208000000>; opp-level = <8>; clock-latency-ns = <45000>; + opp-microwatt = <2366690>; }; opp09 { opp-hz = /bits/ 64 <2448000000>; opp-level = <9>; clock-latency-ns = <49000>; + opp-microwatt = <2892193>; }; opp10 { opp-hz = /bits/ 64 <2676000000>; opp-level = <10>; clock-latency-ns = <53000>; + opp-microwatt = <3475417>; }; opp11 { opp-hz = /bits/ 64 <2904000000>; opp-level = <11>; clock-latency-ns = <56000>; + opp-microwatt = <3959410>; }; opp12 { opp-hz = /bits/ 64 <3036000000>; opp-level = <12>; clock-latency-ns = <56000>; + opp-microwatt = <4540620>; }; opp13 { opp-hz = /bits/ 64 <3132000000>; opp-level = <13>; clock-latency-ns = <56000>; + opp-microwatt = <4745031>; turbo-mode; }; opp14 { opp-hz = /bits/ 64 <3168000000>; opp-level = <14>; clock-latency-ns = <56000>; + opp-microwatt = <4822390>; turbo-mode; }; opp15 { opp-hz = /bits/ 64 <3228000000>; opp-level = <15>; clock-latency-ns = <56000>; + opp-microwatt = <4951324>; turbo-mode; }; }; diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index be7de3ba16c0b0..fb8261fde2b860 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -194,26 +194,31 @@ opp-hz = /bits/ 64 <600000000>; opp-level = <1>; clock-latency-ns = <7500>; + opp-microwatt = <47296>; }; opp02 { opp-hz = /bits/ 64 <972000000>; opp-level = <2>; clock-latency-ns = <22000>; + opp-microwatt = <99715>; }; opp03 { opp-hz = /bits/ 64 <1332000000>; opp-level = <3>; clock-latency-ns = <27000>; + opp-microwatt = <188860>; }; opp04 { opp-hz = /bits/ 64 <1704000000>; opp-level = <4>; clock-latency-ns = <33000>; + opp-microwatt = <288891>; }; opp05 { opp-hz = /bits/ 64 <2064000000>; opp-level = <5>; clock-latency-ns = <50000>; + opp-microwatt = <412979>; }; }; @@ -224,79 +229,94 @@ opp-hz = /bits/ 64 <600000000>; opp-level = <1>; clock-latency-ns = <8000>; + opp-microwatt = <290230>; }; opp02 { opp-hz = /bits/ 64 <828000000>; opp-level = <2>; clock-latency-ns = <19000>; + opp-microwatt = <449013>; }; opp03 { opp-hz = /bits/ 64 <1056000000>; opp-level = <3>; clock-latency-ns = <21000>; + opp-microwatt = <647097>; }; opp04 { opp-hz = /bits/ 64 <1284000000>; opp-level = <4>; clock-latency-ns = <23000>; + opp-microwatt = <865620>; }; opp05 { opp-hz = /bits/ 64 <1500000000>; opp-level = <5>; clock-latency-ns = <24000>; + opp-microwatt = <1112838>; }; opp06 { opp-hz = /bits/ 64 <1728000000>; opp-level = <6>; clock-latency-ns = <29000>; + opp-microwatt = <1453271>; }; opp07 { opp-hz = /bits/ 64 <1956000000>; opp-level = <7>; clock-latency-ns = <31000>; + opp-microwatt = <1776667>; }; opp08 { opp-hz = /bits/ 64 <2184000000>; opp-level = <8>; clock-latency-ns = <34000>; + opp-microwatt = <2366690>; }; opp09 { opp-hz = /bits/ 64 <2388000000>; opp-level = <9>; clock-latency-ns = <36000>; + opp-microwatt = <2892193>; }; opp10 { opp-hz = /bits/ 64 <2592000000>; opp-level = <10>; clock-latency-ns = <51000>; + opp-microwatt = <3475417>; }; opp11 { opp-hz = /bits/ 64 <2772000000>; opp-level = <11>; clock-latency-ns = <54000>; + opp-microwatt = <3959410>; }; opp12 { opp-hz = /bits/ 64 <2988000000>; opp-level = <12>; clock-latency-ns = <55000>; + opp-microwatt = <4540620>; }; /* Not available until CPU deep sleep is implemented */ opp13 { opp-hz = /bits/ 64 <3096000000>; opp-level = <13>; clock-latency-ns = <55000>; + opp-microwatt = <4745031>; turbo-mode; }; opp14 { opp-hz = /bits/ 64 <3144000000>; opp-level = <14>; clock-latency-ns = <56000>; + opp-microwatt = <4822390>; turbo-mode; }; opp15 { opp-hz = /bits/ 64 <3204000000>; opp-level = <15>; clock-latency-ns = <56000>; + opp-microwatt = <4951324>; turbo-mode; }; }; From 471a0fbf88f8709b2a637d0f9e5f4be430346189 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 3 Sep 2023 16:41:27 +1000 Subject: [PATCH 042/352] arm64: dts: apple: t8112: add opp-microwatt props to avalanche/blizzard Enable energy-aware scheduling on devices with the Apple M2 SoC (T8112) by adding experimentally measured opp-microwatt values to the application core OPP tables. Values are an approximation calculated by the System Management Controller, and collected using freqbench. Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/t8112.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index e479495b733b07..ad2da1b49830aa 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -195,36 +195,43 @@ opp-hz = /bits/ 64 <600000000>; opp-level = <1>; clock-latency-ns = <7500>; + opp-microwatt = <26000>; }; opp02 { opp-hz = /bits/ 64 <912000000>; opp-level = <2>; clock-latency-ns = <20000>; + opp-microwatt = <56000>; }; opp03 { opp-hz = /bits/ 64 <1284000000>; opp-level = <3>; clock-latency-ns = <22000>; + opp-microwatt = <88000>; }; opp04 { opp-hz = /bits/ 64 <1752000000>; opp-level = <4>; clock-latency-ns = <30000>; + opp-microwatt = <155000>; }; opp05 { opp-hz = /bits/ 64 <2004000000>; opp-level = <5>; clock-latency-ns = <35000>; + opp-microwatt = <231000>; }; opp06 { opp-hz = /bits/ 64 <2256000000>; opp-level = <6>; clock-latency-ns = <39000>; + opp-microwatt = <254000>; }; opp07 { opp-hz = /bits/ 64 <2424000000>; opp-level = <7>; clock-latency-ns = <53000>; + opp-microwatt = <351000>; }; }; @@ -236,88 +243,105 @@ opp-hz = /bits/ 64 <660000000>; opp-level = <1>; clock-latency-ns = <9000>; + opp-microwatt = <133000>; }; opp02 { opp-hz = /bits/ 64 <924000000>; opp-level = <2>; clock-latency-ns = <19000>; + opp-microwatt = <212000>; }; opp03 { opp-hz = /bits/ 64 <1188000000>; opp-level = <3>; clock-latency-ns = <22000>; + opp-microwatt = <261000>; }; opp04 { opp-hz = /bits/ 64 <1452000000>; opp-level = <4>; clock-latency-ns = <24000>; + opp-microwatt = <345000>; }; opp05 { opp-hz = /bits/ 64 <1704000000>; opp-level = <5>; clock-latency-ns = <26000>; + opp-microwatt = <441000>; }; opp06 { opp-hz = /bits/ 64 <1968000000>; opp-level = <6>; clock-latency-ns = <28000>; + opp-microwatt = <619000>; }; opp07 { opp-hz = /bits/ 64 <2208000000>; opp-level = <7>; clock-latency-ns = <30000>; + opp-microwatt = <740000>; }; opp08 { opp-hz = /bits/ 64 <2400000000>; opp-level = <8>; clock-latency-ns = <33000>; + opp-microwatt = <855000>; }; opp09 { opp-hz = /bits/ 64 <2568000000>; opp-level = <9>; clock-latency-ns = <34000>; + opp-microwatt = <1006000>; }; opp10 { opp-hz = /bits/ 64 <2724000000>; opp-level = <10>; clock-latency-ns = <36000>; + opp-microwatt = <1217000>; }; opp11 { opp-hz = /bits/ 64 <2868000000>; opp-level = <11>; clock-latency-ns = <41000>; + opp-microwatt = <1534000>; }; opp12 { opp-hz = /bits/ 64 <2988000000>; opp-level = <12>; clock-latency-ns = <42000>; + opp-microwatt = <1714000>; }; opp13 { opp-hz = /bits/ 64 <3096000000>; opp-level = <13>; clock-latency-ns = <44000>; + opp-microwatt = <1877000>; }; opp14 { opp-hz = /bits/ 64 <3204000000>; opp-level = <14>; clock-latency-ns = <46000>; + opp-microwatt = <2159000>; }; opp15 { opp-hz = /bits/ 64 <3324000000>; opp-level = <15>; clock-latency-ns = <62000>; + opp-microwatt = <2393000>; turbo-mode; }; opp16 { opp-hz = /bits/ 64 <3408000000>; opp-level = <16>; clock-latency-ns = <62000>; + opp-microwatt = <2497000>; turbo-mode; }; opp17 { opp-hz = /bits/ 64 <3504000000>; opp-level = <17>; clock-latency-ns = <62000>; + opp-microwatt = <2648000>; turbo-mode; }; }; From c8358f8d5f8fab7c8c17922b2aca45dd6650bd3f Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 31 Aug 2023 19:10:27 +0900 Subject: [PATCH 043/352] arm64: dts: apple: t8103: Add ISP nodes Signed-off-by: Eileen Yoon --- arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 117 ++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8103.dtsi | 55 ++++++++++ 2 files changed, 172 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi index a97d64b665730f..4d1422d7e8b5b4 100644 --- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi @@ -1009,6 +1009,123 @@ power-domains = <&ps_disp0_fe>; apple,min-state = <4>; }; + + /* There is a dependency tree involved with these PDs, + * but we do not express it here since the ISP driver + * is supposed to sequence them in the right order anyway + * (and we do not know the exact tree structure). + * + * This also works around spurious parent PD activation + * on machines with ISP disabled (desktops). + */ + ps_isp_set0: power-controller@4000 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4000 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set0"; + apple,force-disable; + }; + + ps_isp_set1: power-controller@4008 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4008 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set1"; + apple,force-disable; + apple,force-reset; + }; + + ps_isp_set2: power-controller@4010 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4010 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set2"; + apple,force-disable; + apple,force-reset; + }; + + ps_isp_fe: power-controller@4018 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4018 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_fe"; + }; + + ps_isp_set4: power-controller@4020 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4020 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set4"; + }; + + ps_isp_set5: power-controller@4028 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4028 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set5"; + }; + + ps_isp_set6: power-controller@4030 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4030 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set6"; + }; + + ps_isp_set7: power-controller@4038 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4038 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set7"; + }; + + ps_isp_set8: power-controller@4040 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4040 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set8"; + }; + + ps_isp_set9: power-controller@4048 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4048 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set9"; + }; + + ps_isp_set10: power-controller@4050 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4050 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set10"; + }; + + ps_isp_set11: power-controller@4058 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4058 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set11"; + }; + + ps_isp_set12: power-controller@4060 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4060 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set12"; + }; }; &pmgr_mini { diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index fb8261fde2b860..20f758b64fbaa0 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -671,6 +671,61 @@ phandle = <&display>; }; + isp_dart0: iommu@22c0e8000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x2c0e8000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + + status = "disabled"; + }; + + isp_dart1: iommu@22c0f4000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x2c0f4000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + + status = "disabled"; + }; + + isp_dart2: iommu@22c0fc000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x2c0fc000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + + status = "disabled"; + }; + + isp: isp@22a000000 { + compatible = "apple,t8103-isp", "apple,isp"; + iommus = <&isp_dart0 0>, <&isp_dart1 0>, <&isp_dart2 0>; + reg-names = "coproc", "mbox", "gpio", "mbox2"; + reg = <0x2 0x2a000000 0x0 0x2000000>, + <0x2 0x2c104000 0x0 0x100>, + <0x2 0x2c104170 0x0 0x100>, + <0x2 0x2c1043f0 0x0 0x100>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>, <&ps_isp_set0>, + <&ps_isp_set1>, <&ps_isp_set2>, <&ps_isp_fe>, + <&ps_isp_set4>, <&ps_isp_set5>, <&ps_isp_set6>, + <&ps_isp_set7>, <&ps_isp_set8>, <&ps_isp_set9>, + <&ps_isp_set10>, <&ps_isp_set11>, + <&ps_isp_set12>; + + apple,dart-vm-size = <0x0 0xa0000000>; + + status = "disabled"; + }; + sio_dart: iommu@235004000 { compatible = "apple,t8103-dart"; reg = <0x2 0x35004000 0x0 0x4000>; From e204bc44557746bff80fd928fc4cb72a5c4de3ed Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sat, 2 Sep 2023 01:39:10 +0900 Subject: [PATCH 044/352] arm64: dts: apple: t6000: Add ISP nodes Signed-off-by: Eileen Yoon --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 49 ++++++++++++++ arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 80 +++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index caecc1e3f3fac1..1f33fcc00d9194 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -492,6 +492,55 @@ #mbox-cells = <0>; }; + isp_dart0: iommu@3860e8000 { + compatible = "apple,t6000-dart"; + reg = <0x3 0x860e8000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + isp_dart1: iommu@3860f4000 { + compatible = "apple,t6000-dart"; + reg = <0x3 0x860f4000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + isp_dart2: iommu@3860fc000 { + compatible = "apple,t6000-dart"; + reg = <0x3 0x860fc000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + isp: isp@384000000 { + compatible = "apple,t6000-isp", "apple,isp"; + iommus = <&isp_dart0 0>, <&isp_dart1 0>, <&isp_dart2 0>; + reg-names = "coproc", "mbox", "gpio", "mbox2"; + reg = <0x3 0x84000000 0x0 0x2000000>, + <0x3 0x86104000 0x0 0x100>, + <0x3 0x86104170 0x0 0x100>, + <0x3 0x861043f0 0x0 0x100>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>, <&ps_isp_set0>, + <&ps_isp_set1>, <&ps_isp_fe>, <&ps_isp_set3>, + <&ps_isp_set4>, <&ps_isp_set5>, <&ps_isp_set6>, + <&ps_isp_set7>, <&ps_isp_set8>; + apple,dart-vm-size = <0x0 0xa0000000>; + + status = "disabled"; + }; + pcie0_dart_0: iommu@581008000 { compatible = "apple,t6000-dart"; reg = <0x5 0x81008000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index 84d5e126e2320e..b6a46662358a50 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -1452,6 +1452,86 @@ label = DIE_LABEL(venc_me1); power-domains = <&DIE_NODE(ps_venc_me0)>; }; + + /* There is a dependency tree involved with these PDs, + * but we do not express it here since the ISP driver + * is supposed to sequence them in the right order anyway + * (and we do not know the exact tree structure). + * + * This also works around spurious parent PD activation + * on machines with ISP disabled (desktops). + */ + DIE_NODE(ps_isp_set0): power-controller@4000 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4000 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_set0); + }; + + DIE_NODE(ps_isp_set1): power-controller@4010 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4010 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_set1); + }; + + DIE_NODE(ps_isp_fe): power-controller@4008 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4008 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ps_isp_fe); + }; + + DIE_NODE(ps_isp_set3): power-controller@4028 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4028 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_set3); + }; + + DIE_NODE(ps_isp_set4): power-controller@4020 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4020 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_set4); + }; + + DIE_NODE(ps_isp_set5): power-controller@4030 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4030 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_set5); + }; + + DIE_NODE(ps_isp_set6): power-controller@4018 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4018 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_set6); + }; + + DIE_NODE(ps_isp_set7): power-controller@4038 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4038 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_set7); + }; + + DIE_NODE(ps_isp_set8): power-controller@4040 { + compatible = "apple,t6000-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4040 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_set8); + }; }; &DIE_NODE(pmgr_south) { From 3ec2ec0ab7ee401f123a7f6320e8848ba639821a Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 8 Sep 2023 00:46:11 +0900 Subject: [PATCH 045/352] arm64: dts: apple: t8112: Add ISP nodes Co-developed-by: Janne Grunau Signed-off-by: Janne Grunau Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/t8112-pmgr.dtsi | 117 ++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8112.dtsi | 51 ++++++++++ 2 files changed, 168 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi index 7ff5052d1cdcbc..9ed831031ae6f0 100644 --- a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi @@ -967,6 +967,123 @@ apple,always-on; }; + /* There is a dependency tree involved with these PDs, + * but we do not express it here since the ISP driver + * is supposed to sequence them in the right order anyway + * (and we do not know the exact tree structure). + * + * This also works around spurious parent PD activation + * on machines with ISP disabled (desktops). + */ + ps_isp_set0: power-controller@4000 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4000 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set0"; + apple,force-disable; + }; + + ps_isp_set1: power-controller@4008 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4008 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set1"; + apple,force-disable; + apple,force-reset; + }; + + ps_isp_set2: power-controller@4010 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4010 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set2"; + apple,force-disable; + apple,force-reset; + }; + + ps_isp_fe: power-controller@4018 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4018 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_fe"; + }; + + ps_isp_set4: power-controller@4020 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4020 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set4"; + }; + + ps_isp_set5: power-controller@4028 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4028 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set5"; + }; + + ps_isp_set6: power-controller@4030 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4030 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set6"; + }; + + ps_isp_set7: power-controller@4038 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4038 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set7"; + }; + + ps_isp_set8: power-controller@4040 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4040 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set8"; + }; + + ps_isp_set9: power-controller@4048 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4048 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set9"; + }; + + ps_isp_set12: power-controller@4050 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4050 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set10"; + }; + + ps_isp_set10: power-controller@4058 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4058 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set11"; + }; + + ps_isp_set11: power-controller@4060 { + compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate"; + reg = <0x4060 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_set12"; + }; + ps_venc_dma: power-controller@8000 { compatible = "apple,t8112-pmgr-pwrstate", "apple,pmgr-pwrstate"; reg = <0x8000 4>; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index ad2da1b49830aa..6fe3d47fb7000e 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -624,6 +624,57 @@ }; }; + isp_dart0: iommu@22c4a8000 { + compatible = "apple,t8110-dart"; + reg = <0x2 0x2c4a8000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + isp_dart1: iommu@22c4b4000 { + compatible = "apple,t8110-dart"; + reg = <0x2 0x2c4b4000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + isp_dart2: iommu@22c4bc000 { + compatible = "apple,t8110-dart"; + reg = <0x2 0x2c4bc000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + isp: isp@22a000000 { + compatible = "apple,t8112-isp", "apple,isp"; + iommus = <&isp_dart0 0>, <&isp_dart1 0>, <&isp_dart2 0>; + reg-names = "coproc", "mbox", "gpio", "mbox2"; + reg = <0x2 0x2a000000 0x0 0x2000000>, + <0x2 0x2c4c4000 0x0 0x100>, + <0x2 0x2c4c41b0 0x0 0x100>, + <0x2 0x2c4c4430 0x0 0x100>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>, <&ps_isp_set0>, + <&ps_isp_set1>, <&ps_isp_set2>, <&ps_isp_fe>, + <&ps_isp_set4>, <&ps_isp_set5>, <&ps_isp_set6>, + <&ps_isp_set7>, <&ps_isp_set8>, <&ps_isp_set9>, + <&ps_isp_set10>, <&ps_isp_set11>, + <&ps_isp_set12>; + + apple,dart-vm-size = <0x0 0xa0000000>; + status = "disabled"; + }; + disp0_dart: iommu@231304000 { compatible = "apple,t8112-dart", "apple,t8110-dart"; reg = <0x2 0x31304000 0x0 0x4000>; From 8e067cf1ac929a4b70ae781cb79cc31114aed324 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sun, 24 Sep 2023 01:01:10 +0900 Subject: [PATCH 046/352] arm64: dts: apple: t602x: Add ISP nodes Signed-off-by: Asahi Lina --- arch/arm64/boot/dts/apple/t602x-die0.dtsi | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 4d6d682ca0038e..84ab8e250df6e7 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -241,6 +241,60 @@ }; + isp_dart0: iommu@3860e8000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x860e8000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + + apple,dma-range = <0x100 0x0 0x1 0x0>; + status = "disabled"; + }; + + isp_dart1: iommu@3860f4000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x860f4000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + + apple,dma-range = <0x100 0x0 0x1 0x0>; + status = "disabled"; + }; + + isp_dart2: iommu@3860fc000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x860fc000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_sys>; + + apple,dma-range = <0x100 0x0 0x1 0x0>; + status = "disabled"; + }; + + isp: isp@384000000 { + compatible = "apple,t6020-isp", "apple,isp"; + iommus = <&isp_dart0 0>, <&isp_dart1 0>, <&isp_dart2 0>; + reg-names = "coproc", "mbox", "gpio", "mbox2"; + reg = <0x3 0x84000000 0x0 0x2000000>, + <0x3 0x86104000 0x0 0x100>, + <0x3 0x86104170 0x0 0x100>, + <0x3 0x861043f0 0x0 0x100>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_isp_cpu>, <&ps_isp_fe>, + <&ps_dprx>, <&ps_isp_vis>, <&ps_isp_be>, + <&ps_isp_clr>, <&ps_isp_raw>; + apple,dart-vm-size = <0x0 0xa0000000>; + + status = "disabled"; + }; + disp0_dart: iommu@389304000 { compatible = "apple,t6020-dart", "apple,t8110-dart"; reg = <0x3 0x89304000 0x0 0x4000>; From 3de8224db9a24dc6af5569faa05c498731150375 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Thu, 28 Sep 2023 02:02:43 +0900 Subject: [PATCH 047/352] arm64: dts: ISP platform configs Signed-off-by: Asahi Lina --- arch/arm64/boot/dts/apple/isp-common.dtsi | 43 +++++++++ arch/arm64/boot/dts/apple/isp-imx248.dtsi | 22 +++++ arch/arm64/boot/dts/apple/isp-imx364.dtsi | 71 ++++++++++++++ .../arm64/boot/dts/apple/isp-imx558-cfg0.dtsi | 92 +++++++++++++++++++ arch/arm64/boot/dts/apple/isp-imx558.dtsi | 50 ++++++++++ .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 6 ++ .../arm64/boot/dts/apple/t602x-j414-j416.dtsi | 7 ++ arch/arm64/boot/dts/apple/t8103-j293.dts | 6 ++ arch/arm64/boot/dts/apple/t8103-j313.dts | 6 ++ arch/arm64/boot/dts/apple/t8103-j456.dts | 6 ++ arch/arm64/boot/dts/apple/t8103-j457.dts | 6 ++ arch/arm64/boot/dts/apple/t8112-j413.dts | 7 ++ arch/arm64/boot/dts/apple/t8112-j415.dts | 7 ++ arch/arm64/boot/dts/apple/t8112-j493.dts | 6 ++ 14 files changed, 335 insertions(+) create mode 100644 arch/arm64/boot/dts/apple/isp-common.dtsi create mode 100644 arch/arm64/boot/dts/apple/isp-imx248.dtsi create mode 100644 arch/arm64/boot/dts/apple/isp-imx364.dtsi create mode 100644 arch/arm64/boot/dts/apple/isp-imx558-cfg0.dtsi create mode 100644 arch/arm64/boot/dts/apple/isp-imx558.dtsi diff --git a/arch/arm64/boot/dts/apple/isp-common.dtsi b/arch/arm64/boot/dts/apple/isp-common.dtsi new file mode 100644 index 00000000000000..bf406772469b67 --- /dev/null +++ b/arch/arm64/boot/dts/apple/isp-common.dtsi @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Common ISP configuration for Apple silicon platforms. + * + * Copyright The Asahi Linux Contributors + */ + +/ { + aliases { + isp = &isp; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + isp_heap: isp-heap { + compatible = "apple,asc-mem"; + /* Filled in by bootloder */ + reg = <0 0 0 0>; + no-map; + }; + }; +}; + +&isp { + memory-region = <&isp_heap>; + memory-region-names = "heap"; + status = "okay"; +}; + +&isp_dart0 { + status = "okay"; +}; + +&isp_dart1 { + status = "okay"; +}; + +&isp_dart2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/isp-imx248.dtsi b/arch/arm64/boot/dts/apple/isp-imx248.dtsi new file mode 100644 index 00000000000000..acad3ecf0331ef --- /dev/null +++ b/arch/arm64/boot/dts/apple/isp-imx248.dtsi @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * ISP configuration for platforms with IMX248 sensor. + * + * Copyright The Asahi Linux Contributors + */ + +#include "isp-common.dtsi" + +&isp { + apple,temporal-filter = <0>; + + sensor-presets { + /* 1280x720 */ + preset0 { + apple,config-index = <0>; + apple,input-size = <1296 736>; + apple,output-size = <1280 720>; + apple,crop = <8 8 1280 720>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/isp-imx364.dtsi b/arch/arm64/boot/dts/apple/isp-imx364.dtsi new file mode 100644 index 00000000000000..55484d86523657 --- /dev/null +++ b/arch/arm64/boot/dts/apple/isp-imx364.dtsi @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * ISP configuration for platforms with IMX364 sensor. + * + * Copyright The Asahi Linux Contributors + */ + +#include "isp-common.dtsi" + +&isp { + apple,temporal-filter = <0>; + + sensor-presets { + /* 1920x1080 */ + preset0 { + apple,config-index = <0>; + apple,input-size = <1920 1080>; + apple,output-size = <1920 1080>; + apple,crop = <0 0 1920 1080>; + }; + /* 1440x720 (4:3) */ + preset1 { + apple,config-index = <0>; + apple,input-size = <1920 1080>; + apple,output-size = <1440 1080>; + apple,crop = <240 0 1440 1080>; + }; + /* 1280x720 (16:9) */ + preset2 { + apple,config-index = <0>; + apple,input-size = <1920 1080>; + apple,output-size = <1280 720>; + apple,crop = <0 0 1920 1080>; + }; + /* 960x720 (4:3) */ + preset3{ + apple,config-index = <0>; + apple,input-size = <1920 1080>; + apple,output-size = <960 720>; + apple,crop = <240 0 1440 1080>; + }; + /* 960x540 (16:9) */ + preset4 { + apple,config-index = <0>; + apple,input-size = <1920 1080>; + apple,output-size = <960 540>; + apple,crop = <0 0 1920 1080>; + }; + /* 640x480 (4:3) */ + preset5 { + apple,config-index = <0>; + apple,input-size = <1920 1080>; + apple,output-size = <640 480>; + apple,crop = <240 0 1440 1080>; + }; + /* 640x360 (16:9) */ + preset6 { + apple,config-index = <0>; + apple,input-size = <1920 1080>; + apple,output-size = <640 360>; + apple,crop = <0 0 1920 1080>; + }; + /* 320x180 (16:9) */ + preset7 { + apple,config-index = <0>; + apple,input-size = <1920 1080>; + apple,output-size = <320 180>; + apple,crop = <0 0 1920 1080>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/isp-imx558-cfg0.dtsi b/arch/arm64/boot/dts/apple/isp-imx558-cfg0.dtsi new file mode 100644 index 00000000000000..729b97829cbb7e --- /dev/null +++ b/arch/arm64/boot/dts/apple/isp-imx558-cfg0.dtsi @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * ISP configuration for platforms with IMX558 sensor in + * config #0 mode. + * + * These platforms enable MLVNR for all configs except + * #0, which we don't support. Config #0 is an uncropped + * square 1920x1920 sensor, with dark corners. + * Therefore, we synthesize common resolutions by using + * crop/scale while always choosing config #0. + * + * Copyright The Asahi Linux Contributors + */ + +#include "isp-common.dtsi" + +&isp { + apple,temporal-filter = <0>; + + sensor-presets { + /* 1920x1080 */ + preset0 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <1920 1080>; + apple,crop = <0 420 1920 1080>; + }; + /* 1080x1920 */ + preset1 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <1080 1920>; + apple,crop = <420 0 1080 1920>; + }; + /* 1920x1440 */ + preset2 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <1920 1440>; + apple,crop = <0 240 1920 1440>; + }; + /* 1440x1920 */ + preset3 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <1440 1920>; + apple,crop = <240 0 1440 1920>; + }; + /* 1280x720 */ + preset4 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <1280 720>; + apple,crop = <0 420 1920 1080>; + }; + /* 720x1280 */ + preset5 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <720 1280>; + apple,crop = <420 0 1080 1920>; + }; + /* 1280x960 */ + preset6 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <1280 960>; + apple,crop = <0 240 1920 1440>; + }; + /* 960x1280 */ + preset7 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <960 1280>; + apple,crop = <240 0 1440 1920>; + }; + /* 640x480 */ + preset8 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <640 480>; + apple,crop = <0 240 1920 1440>; + }; + /* 480x640 */ + preset9 { + apple,config-index = <0>; + apple,input-size = <1920 1920>; + apple,output-size = <480 640>; + apple,crop = <240 0 1440 1920>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/isp-imx558.dtsi b/arch/arm64/boot/dts/apple/isp-imx558.dtsi new file mode 100644 index 00000000000000..a23785b7d5e65a --- /dev/null +++ b/arch/arm64/boot/dts/apple/isp-imx558.dtsi @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * ISP configuration for platforms with IMX558 sensor. + * + * Copyright The Asahi Linux Contributors + */ + +#include "isp-common.dtsi" + +&isp { + apple,temporal-filter = <0>; + + sensor-presets { + /* 1920x1080 */ + preset0 { + apple,config-index = <1>; + apple,input-size = <1920 1080>; + apple,output-size = <1920 1080>; + apple,crop = <0 0 1920 1080>; + }; + /* 1080x1920 */ + preset1 { + apple,config-index = <2>; + apple,input-size = <1080 1920>; + apple,output-size = <1080 1920>; + apple,crop = <0 0 1080 1920>; + }; + /* 1760x1328 */ + preset2 { + apple,config-index = <3>; + apple,input-size = <1760 1328>; + apple,output-size = <1760 1328>; + apple,crop = <0 0 1760 1328>; + }; + /* 1328x1760 */ + preset3 { + apple,config-index = <4>; + apple,input-size = <1328 1760>; + apple,output-size = < 1328 1760>; + apple,crop = <0 0 1328 1760>; + }; + /* 1152x1152 */ + preset4 { + apple,config-index = <5>; + apple,input-size = <1152 1152>; + apple,output-size = <1152 1152>; + apple,crop = <0 0 1152 1152>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 37024d1d5c9c37..187e132d77281b 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -542,3 +542,9 @@ }; #include "spi1-nvram.dtsi" + +#include "isp-imx558.dtsi" + +&isp { + apple,platform-id = <3>; +}; diff --git a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi index 5aff7936721375..b9aee8ec432b9a 100644 --- a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi @@ -137,3 +137,10 @@ tp_accel { }; }; + +&isp { + apple,platform-id = <7>; + /delete-node/ sensor-presets; /* Override j31[46] below */ +}; + +#include "isp-imx558-cfg0.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts index 50043beb65db0a..a113b9a57e1a6e 100644 --- a/arch/arm64/boot/dts/apple/t8103-j293.dts +++ b/arch/arm64/boot/dts/apple/t8103-j293.dts @@ -273,3 +273,9 @@ }; }; }; + +#include "isp-imx248.dtsi" + +&isp { + apple,platform-id = <1>; +}; diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts index 7e77fe091c6345..52940e43db9155 100644 --- a/arch/arm64/boot/dts/apple/t8103-j313.dts +++ b/arch/arm64/boot/dts/apple/t8103-j313.dts @@ -168,3 +168,9 @@ }; }; }; + +#include "isp-imx248.dtsi" + +&isp { + apple,platform-id = <1>; +}; diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts index c384d4dfd19a36..a3638871f3660e 100644 --- a/arch/arm64/boot/dts/apple/t8103-j456.dts +++ b/arch/arm64/boot/dts/apple/t8103-j456.dts @@ -137,3 +137,9 @@ &gpu { apple,perf-base-pstate = <3>; }; + +#include "isp-imx364.dtsi" + +&isp { + apple,platform-id = <2>; +}; diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts index 28e3eedfc35bf6..4c1adb310ba91f 100644 --- a/arch/arm64/boot/dts/apple/t8103-j457.dts +++ b/arch/arm64/boot/dts/apple/t8103-j457.dts @@ -118,3 +118,9 @@ &gpu { apple,perf-base-pstate = <3>; }; + +#include "isp-imx364.dtsi" + +&isp { + apple,platform-id = <2>; +}; diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts index 0077ce45cc5154..5c0cb7fc235ad5 100644 --- a/arch/arm64/boot/dts/apple/t8112-j413.dts +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts @@ -243,3 +243,10 @@ tp_accel { }; }; + +#include "isp-imx558-cfg0.dtsi" + +&isp { + apple,platform-id = <14>; + apple,temporal-filter = <1>; +}; diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts index 09387fc5ca46f0..7e39a477728e3f 100644 --- a/arch/arm64/boot/dts/apple/t8112-j415.dts +++ b/arch/arm64/boot/dts/apple/t8112-j415.dts @@ -269,3 +269,10 @@ tp_accel { }; }; + +#include "isp-imx558-cfg0.dtsi" + +&isp { + apple,platform-id = <15>; + apple,temporal-filter = <1>; +}; diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts index 03cb807cf59d71..b6c60ec51b4a1a 100644 --- a/arch/arm64/boot/dts/apple/t8112-j493.dts +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts @@ -297,3 +297,9 @@ tp_accel { }; }; + +#include "isp-imx248.dtsi" + +&isp { + apple,platform-id = <6>; +}; From e04726e62dab18e657234581bd3b9032e75c8ee6 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 4 Nov 2023 22:44:17 +0100 Subject: [PATCH 048/352] arm64: dts: apple: Disable ps_isp_sys unless it is used Seems to be fuxed off on t602x devices without camera and causes annoying kernel log splat. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/isp-common.dtsi | 4 ++++ arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 1 + arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 1 + arch/arm64/boot/dts/apple/t8112-pmgr.dtsi | 1 + 4 files changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/apple/isp-common.dtsi b/arch/arm64/boot/dts/apple/isp-common.dtsi index bf406772469b67..739e6e9e66e740 100644 --- a/arch/arm64/boot/dts/apple/isp-common.dtsi +++ b/arch/arm64/boot/dts/apple/isp-common.dtsi @@ -41,3 +41,7 @@ &isp_dart2 { status = "okay"; }; + +&ps_isp_sys { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index b6a46662358a50..cf274aaf632c91 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -1370,6 +1370,7 @@ #reset-cells = <0>; label = DIE_LABEL(isp_sys); power-domains = <&DIE_NODE(ps_afnc2_lw1)>; + status = "disabled"; }; DIE_NODE(ps_venc_sys): power-controller@3b0 { diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi index 4d1422d7e8b5b4..10facd0c01e420 100644 --- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi @@ -812,6 +812,7 @@ #reset-cells = <0>; label = "isp_sys"; power-domains = <&ps_rmx>; + status = "disabled"; }; ps_venc_sys: power-controller@408 { diff --git a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi index 9ed831031ae6f0..102ff3ad0535d0 100644 --- a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi @@ -821,6 +821,7 @@ #reset-cells = <0>; label = "isp_sys"; power-domains = <&ps_rmx1>; + status = "disabled"; }; ps_venc_sys: power-controller@440 { From 06b4b78f3c2ec901039984d57c18b2890559e28c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 7 Oct 2023 00:38:24 +0200 Subject: [PATCH 049/352] arm64: dts: apple: imx248: Add scaled and cropped presets Adds following resolution presets: - 960x720 (4:3) - 960x540 (16:9) - 640x480 (4:3) - 640x360 (16:9) - 320x180 (16:9) Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/isp-imx248.dtsi | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm64/boot/dts/apple/isp-imx248.dtsi b/arch/arm64/boot/dts/apple/isp-imx248.dtsi index acad3ecf0331ef..0a4ac1a0152c2c 100644 --- a/arch/arm64/boot/dts/apple/isp-imx248.dtsi +++ b/arch/arm64/boot/dts/apple/isp-imx248.dtsi @@ -18,5 +18,40 @@ apple,output-size = <1280 720>; apple,crop = <8 8 1280 720>; }; + /* 960x720 (4:3) */ + preset1 { + apple,config-index = <0>; + apple,input-size = <1296 736>; + apple,output-size = <960 720>; + apple,crop = <168 8 960 720>; + }; + /* 960x540 (16:9) */ + preset2 { + apple,config-index = <0>; + apple,input-size = <1296 736>; + apple,output-size = <960 540>; + apple,crop = <8 8 1280 720>; + }; + /* 640x480 (4:3) */ + preset3 { + apple,config-index = <0>; + apple,input-size = <1296 736>; + apple,output-size = <640 480>; + apple,crop = <168 8 960 720>; + }; + /* 640x360 (16:9) */ + preset4 { + apple,config-index = <0>; + apple,input-size = <1296 736>; + apple,output-size = <640 360>; + apple,crop = <8 8 1280 720>; + }; + /* 320x180 (16:9) */ + preset5 { + apple,config-index = <0>; + apple,input-size = <1296 736>; + apple,output-size = <320 180>; + apple,crop = <8 8 1280 720>; + }; }; }; From a41212ff35485b93db61b54ef766f8d22c72cc1f Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 8 Oct 2023 19:53:27 +0900 Subject: [PATCH 050/352] arm64: dts: apple: imx558: Add downscaled resolution presets To match those from cfg0. The 4:3 crops are different and this also has a 1:1 config, so we might want to unify things at some point... Signed-off-by: Hector Martin --- arch/arm64/boot/dts/apple/isp-imx558.dtsi | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm64/boot/dts/apple/isp-imx558.dtsi b/arch/arm64/boot/dts/apple/isp-imx558.dtsi index a23785b7d5e65a..d55854c883f5b6 100644 --- a/arch/arm64/boot/dts/apple/isp-imx558.dtsi +++ b/arch/arm64/boot/dts/apple/isp-imx558.dtsi @@ -46,5 +46,47 @@ apple,output-size = <1152 1152>; apple,crop = <0 0 1152 1152>; }; + /* 1280x720 */ + preset5 { + apple,config-index = <1>; + apple,input-size = <1920 1080>; + apple,output-size = <1280 720>; + apple,crop = <0 0 1920 1080>; + }; + /* 720x1280 */ + preset6 { + apple,config-index = <2>; + apple,input-size = <1080 1920>; + apple,output-size = <720 1280>; + apple,crop = <0 0 1080 1920>; + }; + /* 1280x960 */ + preset7 { + apple,config-index = <3>; + apple,input-size = <1760 1328>; + apple,output-size = <1280 960>; + apple,crop = <0 4 1760 1320>; + }; + /* 960x1280 */ + preset8 { + apple,config-index = <4>; + apple,input-size = <1328 1760>; + apple,output-size = <960 1280>; + apple,crop = <4 0 1320 1760>; + }; + /* 640x480 */ + preset9 { + apple,config-index = <3>; + apple,input-size = <1760 1328>; + apple,output-size = <640 480>; + apple,crop = <0 4 1760 1320>; + }; + /* 480x640 */ + preset10 { + apple,config-index = <4>; + apple,input-size = <1328 1760>; + apple,output-size = <480 640>; + apple,crop = <4 0 1320 1760>; + }; }; }; From 81bdf3628745a444bf265a3d11b91a3bf663c3a6 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 00:51:53 +0100 Subject: [PATCH 051/352] arm64: dts: apple: t600x: Switch to apple,dma-range Obsoletes the use of "apple,asc-dram-mask" in the device tree and the dcp driver. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 1f33fcc00d9194..af47346967d80e 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -175,6 +175,7 @@ interrupts = ; status = "disabled"; power-domains = <&ps_disp0_cpu0>; + apple,dma-range = <0x0 0x0 0x0 0xfc000000>; }; dcp_dart: iommu@38b30c000 { @@ -184,6 +185,7 @@ interrupt-parent = <&aic>; interrupts = ; power-domains = <&ps_disp0_cpu0>; + apple,dma-range = <0x1f0 0x0 0x0 0xfc000000>; }; dcp_mbox: mbox@38bc08000 { @@ -216,7 +218,6 @@ power-domains = <&ps_disp0_cpu0>; resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; - apple,asc-dram-mask = <0x1f0 0x00000000>; phandle = <&dcp>; // required bus properties for 'piodma' subdevice #address-cells = <2>; From 6ac5582f41501e9bd341777510810fa8d2894927 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 00:51:53 +0100 Subject: [PATCH 052/352] arm64: dts: apple: t8103: Switch to apple,dma-range Obsoletes the use of "apple,asc-dram-mask" in the device tree and the dcp driver. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 20f758b64fbaa0..613f546d8b66c7 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -606,6 +606,7 @@ interrupt-parent = <&aic>; interrupts = ; power-domains = <&ps_disp0_cpu0>; + apple,dma-range = <0x0 0x0 0x0 0xfc000000>; status = "disabled"; }; @@ -615,6 +616,7 @@ #iommu-cells = <1>; interrupt-parent = <&aic>; interrupts = ; + apple,dma-range = <0xf 0x00000000 0x0 0xfc000000>; power-domains = <&ps_disp0_cpu0>; }; @@ -652,7 +654,6 @@ power-domains = <&ps_disp0_cpu0>; resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; - apple,asc-dram-mask = <0xf 0x00000000>; phandle = <&dcp>; // required bus properties for 'piodma' subdevice #address-cells = <2>; From 95d54172cdb49589836bb19c01cedc52bfe2f3c0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 20:04:09 +0100 Subject: [PATCH 053/352] arm64: dts: apple: t8112: Switch to apple,dma-range Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 6fe3d47fb7000e..915fe6c9b6d6ec 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -682,6 +682,7 @@ interrupt-parent = <&aic>; interrupts = ; power-domains = <&ps_disp0_cpu0>; + apple,dma-range = <0x0 0x0 0xf 0xffff0000>; status = "disabled"; }; @@ -692,6 +693,7 @@ interrupt-parent = <&aic>; interrupts = ; power-domains = <&ps_disp0_cpu0>; + apple,dma-range = <0x8 0x00000000 0x7 0xffff0000>; }; dcp_mbox: mbox@231c08000 { @@ -726,7 +728,6 @@ power-domains = <&ps_disp0_cpu0>; resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; - apple,asc-dram-mask = <0x0 0x0>; phandle = <&dcp>; // required bus properties for 'piodma' subdevice #address-cells = <2>; From 11b77f867dffeed03d89b243507d3296d414117f Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 00:46:53 +0100 Subject: [PATCH 054/352] arm64: dts: apple: t600x: Add "apple,min-state" to ps_dispextN_cpu0 DCP ASC co-processors do not come back up from lower power states. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index cf274aaf632c91..a8f85e41baa4fe 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -396,6 +396,7 @@ #reset-cells = <0>; label = DIE_LABEL(dispext0_cpu0); power-domains = <&DIE_NODE(ps_dispext0_fe)>; + apple,min-state = <4>; }; DIE_NODE(ps_dispext1_cpu0): power-controller@2a8 { @@ -405,6 +406,7 @@ #reset-cells = <0>; label = DIE_LABEL(dispext1_cpu0); power-domains = <&DIE_NODE(ps_dispext1_fe)>; + apple,min-state = <4>; }; DIE_NODE(ps_ane_sys_cpu): power-controller@2c8 { @@ -1792,6 +1794,7 @@ #reset-cells = <0>; label = DIE_LABEL(dispext2_cpu0); power-domains = <&DIE_NODE(ps_dispext2_fe)>; + apple,min-state = <4>; }; DIE_NODE(ps_dispext3_fe): power-controller@210 { @@ -1810,6 +1813,7 @@ #reset-cells = <0>; label = DIE_LABEL(dispext3_cpu0); power-domains = <&DIE_NODE(ps_dispext3_fe)>; + apple,min-state = <4>; }; DIE_NODE(ps_msr1): power-controller@250 { From e2d658173d8d0380275589a0d417641645ed70b5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 30 Sep 2022 22:30:13 +0200 Subject: [PATCH 055/352] arm64: dts: apple: t8103: Add dcpext/dispext0 nodes Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103.dtsi | 77 ++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 613f546d8b66c7..df241a52dbcefd 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -416,6 +416,14 @@ clock-output-names = "clk_disp0"; }; + /* Pixel clock? frequency in Hz (compare: 4K@60 VGA clock 533.250 MHz) */ + clk_dispext0: clock-dispext0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext0"; + }; + /* * This is a fabulated representation of the input clock * to NCO since we don't know the true clock tree. @@ -667,6 +675,7 @@ display: display-subsystem { compatible = "apple,display-subsystem"; + /* disp_dart0 must be 1st since it is locked */ iommus = <&disp0_dart 0>; /* generate phandle explicitly for use in loader */ phandle = <&display>; @@ -1222,6 +1231,74 @@ ; }; + dispext0_dart: iommu@271304000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x71304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_dispext_cpu0>; + apple,dma-range = <0x0 0x0 0x0 0xfc000000>; + status = "disabled"; + }; + + dcpext_dart: iommu@27130c000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x7130c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_dispext_cpu0>; + apple,dma-range = <0xf 0x00000000 0x0 0xfc000000>; + status = "disabled"; + }; + + dcpext_mbox: mbox@271c08000 { + compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x71c08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_dispext_cpu0>; + resets = <&ps_dispext_cpu0>; + status = "disabled"; + }; + + dcpext: dcp@271c00000 { + compatible = "apple,t8103-dcpext", "apple,dcpext"; + mboxes = <&dcpext_mbox>; + mbox-names = "mbox"; + iommus = <&dcpext_dart 0>; + phandle = <&dcpext>; + + reg-names = "coproc", "disp-0", "disp-1", "disp-2", + "disp-3", "disp-4"; + reg = <0x2 0x71c00000 0x0 0x4000>, + <0x2 0x70000000 0x0 0x118000>, + <0x2 0x71320000 0x0 0x4000>, + <0x2 0x71344000 0x0 0x4000>, + <0x2 0x71800000 0x0 0x800000>, + <0x2 0x3b3d0000 0x0 0x4000>; + apple,bw-scratch = <&pmgr_dcp 0 5 0x18>; + apple,bw-doorbell = <&pmgr_dcp 1 6>; + power-domains = <&ps_dispext_cpu0>; + resets = <&ps_dispext_cpu0>; + clocks = <&clk_dispext0>; + status = "disabled"; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + piodma { + iommus = <&dispext0_dart 4>; + }; + }; + ans_mbox: mbox@277408000 { compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; reg = <0x2 0x77408000 0x0 0x4000>; From b4935ee047058c00d7de2d9268028baf61365e19 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 3 Dec 2022 22:12:25 +0100 Subject: [PATCH 056/352] arm64: dts: apple: t8112: Add dcpext/dispext0 nodes Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112.dtsi | 75 ++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 915fe6c9b6d6ec..332494f0213cdb 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -454,6 +454,14 @@ clock-output-names = "clk_disp0"; }; + /* Pixel clock? frequency in Hz (compare: 4K@60 VGA clock 533.250 MHz) */ + clk_dispext0: clock-dispext0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext0"; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -1302,6 +1310,73 @@ }; + dispext0_dart: iommu@271304000 { + compatible = "apple,t8112-dart", "apple,t8110-dart"; + reg = <0x2 0x71304000 0x0 0x4000>; + #iommu-cells = <1>; + apple,dma-range = <0x0 0x0 0xf 0xffff0000>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_dispext_cpu0>; + status = "disabled"; + }; + + dcpext_dart: iommu@27130c000 { + compatible = "apple,t8112-dart", "apple,t8110-dart"; + reg = <0x2 0x7130c000 0x0 0x4000>; + #iommu-cells = <1>; + apple,dma-range = <0x8 0x0 0x7 0xffff0000>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_dispext_cpu0>; + status = "disabled"; + }; + + dcpext_mbox: mbox@271c08000 { + compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x71c08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_dispext_cpu0>; + resets = <&ps_dispext_cpu0>; + status = "disabled"; + }; + + dcpext: dcp@271c00000 { + compatible = "apple,t8112-dcpext", "apple,dcpext"; + mboxes = <&dcpext_mbox>; + mbox-names = "mbox"; + iommus = <&dcpext_dart 5>; + phandle = <&dcpext>; + + /* the ADT has 2 additional regs which seems to be unused */ + reg-names = "coproc", "disp-0", "disp-1", "disp-2", "disp-3"; + reg = <0x2 0x71c00000 0x0 0x4000>, + <0x2 0x70000000 0x0 0x61C000>, + <0x2 0x71320000 0x0 0x4000>, + <0x2 0x71344000 0x0 0x4000>, + <0x2 0x71800000 0x0 0x800000>; + apple,bw-scratch = <&pmgr_dcp 0 4 0x5e0>; + power-domains = <&ps_dispext_cpu0>; + resets = <&ps_dispext_cpu0>; + clocks = <&clk_dispext0>; + apple,dcp-index = <1>; + status = "disabled"; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + piodma { + iommus = <&dispext0_dart 4>; + }; + }; + ans_mbox: mbox@277408000 { compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; reg = <0x2 0x77408000 0x0 0x4000>; From 4f61c39a3b45e7e6ef4e22f3aa9d4cab80c4867a Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 20 Oct 2022 20:44:02 +0200 Subject: [PATCH 057/352] arm64: dts: apple: t600x: Add t6000 dispext device nodes While thunderbolt and DP-altmode are not working 2 dispext/dcpext devices are enough. "dispext0" will be used for the HDMI output and dispext1 can be used for DP-altmopde experiments. All nodes are disabled and have be enabled explicitly in device .dts or .dtsi. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6002.dtsi | 10 ++ arch/arm64/boot/dts/apple/t600x-common.dtsi | 28 +++++ arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 132 ++++++++++++++++++++ 3 files changed, 170 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi index 04265fa3ea1ec1..9bf333e0cf2d66 100644 --- a/arch/arm64/boot/dts/apple/t6002.dtsi +++ b/arch/arm64/boot/dts/apple/t6002.dtsi @@ -305,6 +305,16 @@ }; }; +&dcpext0_die1 { + // TODO: verify + apple,bw-scratch = <&pmgr_dcp 0 4 0x9c0>; +}; + +&dcpext1_die1 { + // TODO: verify + apple,bw-scratch = <&pmgr_dcp 0 4 0x9c8>; +}; + &ps_gfx { // On t6002, the die0 GPU power domain needs both AFR power domains power-domains = <&ps_afr>, <&ps_afr_die1>; diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi index 58a535fd707d4d..f37feaea4c2191 100644 --- a/arch/arm64/boot/dts/apple/t600x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi @@ -441,6 +441,34 @@ clock-frequency = <237333328>; clock-output-names = "clk_disp0"; }; + + clk_dispext0: clock-dispext0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext0"; + }; + + clk_dispext0_die1: clock-dispext0_die1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext0_die1"; + }; + + clk_dispext1: clock-dispext1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext1"; + }; + + clk_dispext1_die1: clock-dispext1_die1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext1_die1"; + }; /* * This is a fabulated representation of the input clock * to NCO since we don't know the true clock tree. diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi index 9676d5127039b7..aa6261aeda8363 100644 --- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi @@ -24,6 +24,138 @@ #performance-domain-cells = <0>; }; + DIE_NODE(dispext0_dart): iommu@289304000 { + compatible = "apple,t6000-dart"; + reg = <0x2 0x89304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + apple,dma-range = <0x0 0x0 0x0 0xfc000000>; + status = "disabled"; + }; + + DIE_NODE(dcpext0_dart): iommu@28930c000 { + compatible = "apple,t6000-dart"; + reg = <0x2 0x8930c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + apple,dma-range = <0x1f0 0x0 0x0 0xfc000000>; + status = "disabled"; + }; + + DIE_NODE(dcpext0_mbox): mbox@289c08000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x89c08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + resets = <&DIE_NODE(ps_dispext0_cpu0)>; + status = "disabled"; + }; + + DIE_NODE(dcpext0): dcp@289c00000 { + compatible = "apple,t6000-dcpext", "apple,dcpext"; + mboxes = <&DIE_NODE(dcpext0_mbox)>; + mbox-names = "mbox"; + iommus = <&DIE_NODE(dcpext0_dart) 0>; + + reg-names = "coproc", "disp-0", "disp-1", "disp-2", "disp-3"; + reg = <0x2 0x89c00000 0x0 0x4000>, + <0x2 0x88000000 0x0 0x3000000>, + <0x2 0x89320000 0x0 0x4000>, + <0x2 0x89344000 0x0 0x4000>, + <0x2 0x89800000 0x0 0x800000>; + apple,bw-scratch = <&pmgr_dcp 0 4 0x990>; + power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + resets = <&DIE_NODE(ps_dispext0_cpu0)>; + clocks = <&DIE_NODE(clk_dispext0)>; + phandle = <&DIE_NODE(dcpext0)>; + apple,dcp-index = <1>; + status = "disabled"; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + piodma { + iommus = <&DIE_NODE(dispext0_dart) 4>; + }; + }; + + DIE_NODE(dispext1_dart): iommu@28c304000 { + compatible = "apple,t6000-dart", "apple,t8110-dart"; + reg = <0x2 0x8c304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + apple,dma-range = <0x0 0x0 0x0 0xfc000000>; + status = "disabled"; + }; + + DIE_NODE(dcpext1_dart): iommu@28c30c000 { + compatible = "apple,t6000-dart", "apple,t8110-dart"; + reg = <0x2 0x8c30c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + apple,dma-range = <0x1f0 0x0 0x0 0xfc000000>; + status = "disabled"; + }; + + DIE_NODE(dcpext1_mbox): mbox@28cc08000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x8cc08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + resets = <&DIE_NODE(ps_dispext1_cpu0)>; + status = "disabled"; + }; + + DIE_NODE(dcpext1): dcp@28cc00000 { + compatible = "apple,t6000-dcpext", "apple,dcpext"; + mboxes = <&DIE_NODE(dcpext1_mbox)>; + mbox-names = "mbox"; + iommus = <&DIE_NODE(dcpext1_dart) 0>; + + reg-names = "coproc", "disp-0", "disp-1", "disp-2", "disp-3"; + reg = <0x2 0x8cc00000 0x0 0x4000>, + <0x2 0x8b000000 0x0 0x3000000>, + <0x2 0x8c320000 0x0 0x4000>, + <0x2 0x8c344000 0x0 0x4000>, + <0x2 0x8c800000 0x0 0x800000>; + apple,bw-scratch = <&pmgr_dcp 0 4 0x998>; + power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + resets = <&DIE_NODE(ps_dispext1_cpu0)>; + clocks = <&DIE_NODE(clk_dispext1)>; + phandle = <&DIE_NODE(dcpext1)>; + apple,dcp-index = <2>; + status = "disabled"; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + piodma { + iommus = <&DIE_NODE(dispext1_dart) 4>; + }; + }; + DIE_NODE(pmgr): power-management@28e080000 { compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; From 8004dabe188c425ead6b3541ff97af057cd904e5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 17 Aug 2023 19:45:46 +0200 Subject: [PATCH 058/352] arm64: dts: apple: t602x: Add t6020 dispext device nodes While thunderbolt and DP-altmode are not working 2 dispext/dcpext devices are enough. "dispext0" will be used for the HDMI output and dispext1 can be used for DP-altmopde experiments. All nodes are disabled and have be enabled explicitly in device .dts or .dtsi. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6022.dtsi | 8 ++ arch/arm64/boot/dts/apple/t602x-common.dtsi | 28 +++++ arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 132 ++++++++++++++++++++ 3 files changed, 168 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6022.dtsi b/arch/arm64/boot/dts/apple/t6022.dtsi index b7d13dafc7a265..f17c9a4f59e482 100644 --- a/arch/arm64/boot/dts/apple/t6022.dtsi +++ b/arch/arm64/boot/dts/apple/t6022.dtsi @@ -346,6 +346,14 @@ }; }; +&dcpext0_die1 { + apple,bw-scratch = <&pmgr_dcp 0 4 0x1240>; +}; + +&dcpext1_die1 { + apple,bw-scratch = <&pmgr_dcp 0 4 0x1248>; +}; + &ps_gfx { // On t6022, the die0 GPU power domain needs both AFR power domains power-domains = <&ps_afr>, <&ps_afr_die1>; diff --git a/arch/arm64/boot/dts/apple/t602x-common.dtsi b/arch/arm64/boot/dts/apple/t602x-common.dtsi index 3eeb5139fcde05..fe888cbb81e475 100644 --- a/arch/arm64/boot/dts/apple/t602x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-common.dtsi @@ -558,6 +558,34 @@ clock-output-names = "clk_disp0"; }; + clk_dispext0: clock-dispext0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext0"; + }; + + clk_dispext0_die1: clock-dispext0_die1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext0_die1"; + }; + + clk_dispext1: clock-dispext1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext1"; + }; + + clk_dispext1_die1: clock-dispext1_die1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dispext1_die1"; + }; + /* * This is a fabulated representation of the input clock * to NCO since we don't know the true clock tree. diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi index 0e77c1cbf8a5c2..17a239e9206c82 100644 --- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi @@ -23,6 +23,72 @@ #performance-domain-cells = <0>; }; + DIE_NODE(dispext0_dart): iommu@289304000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x2 0x89304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + apple,dma-range = <0x100 0x0 0x10 0x0>; + status = "disabled"; + }; + + DIE_NODE(dcpext0_dart): iommu@28930c000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x2 0x8930c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + apple,dma-range = <0x100 0x0 0x10 0x0>; + status = "disabled"; + }; + + DIE_NODE(dcpext0_mbox): mbox@289c08000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x89c08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + resets = <&DIE_NODE(ps_dispext0_cpu0)>; + status = "disabled"; + }; + + DIE_NODE(dcpext0): dcp@289c00000 { + compatible = "apple,t6020-dcpext", "apple,dcpext"; + mboxes = <&DIE_NODE(dcpext0_mbox)>; + mbox-names = "mbox"; + iommus = <&DIE_NODE(dcpext0_dart) 5>; + + reg-names = "coproc", "disp-0", "disp-1", "disp-2", "disp-3"; + reg = <0x2 0x89c00000 0x0 0x4000>, + <0x2 0x88000000 0x0 0x4000000>, + <0x2 0x89320000 0x0 0x4000>, + <0x2 0x89344000 0x0 0x4000>, + <0x2 0x89800000 0x0 0x800000>; + apple,bw-scratch = <&pmgr_dcp 0 4 0x1210>; + power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + resets = <&DIE_NODE(ps_dispext0_cpu0)>; + clocks = <&DIE_NODE(clk_dispext0)>; + phandle = <&DIE_NODE(dcpext0)>; + apple,dcp-index = <1>; + status = "disabled"; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + piodma { + iommus = <&DIE_NODE(dispext0_dart) 4>; + }; + }; + DIE_NODE(pmgr): power-management@28e080000 { compatible = "apple,t6020-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -94,6 +160,72 @@ ; }; + DIE_NODE(dispext1_dart): iommu@315304000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x15304000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + apple,dma-range = <0x100 0x0 0x10 0x0>; + status = "disabled"; + }; + + DIE_NODE(dcpext1_dart): iommu@31530c000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x1530c000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + apple,dma-range = <0x100 0x0 0x10 0x0>; + status = "disabled"; + }; + + DIE_NODE(dcpext1_mbox): mbox@315c08000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x15c08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + resets = <&DIE_NODE(ps_dispext1_cpu0)>; + status = "disabled"; + }; + + DIE_NODE(dcpext1): dcp@315c00000 { + compatible = "apple,t6020-dcpext", "apple,dcpext"; + mboxes = <&DIE_NODE(dcpext1_mbox)>; + mbox-names = "mbox"; + iommus = <&DIE_NODE(dcpext1_dart) 5>; + + reg-names = "coproc", "disp-0", "disp-1", "disp-2", "disp-3"; + reg = <0x3 0x15c00000 0x0 0x4000>, + <0x3 0x14000000 0x0 0x4000000>, + <0x3 0x15320000 0x0 0x4000>, + <0x3 0x15344000 0x0 0x4000>, + <0x3 0x15800000 0x0 0x800000>; + apple,bw-scratch = <&pmgr_dcp 0 4 0x1218>; + power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + resets = <&DIE_NODE(ps_dispext1_cpu0)>; + clocks = <&DIE_NODE(clk_dispext1)>; + phandle = <&DIE_NODE(dcpext1)>; + apple,dcp-index = <2>; + status = "disabled"; + // required bus properties for 'piodma' subdevice + #address-cells = <2>; + #size-cells = <2>; + + piodma { + iommus = <&DIE_NODE(dispext1_dart) 4>; + }; + }; + DIE_NODE(pinctrl_ap): pinctrl@39b028000 { compatible = "apple,t6020-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x3 0x9b028000 0x0 0x4000>; From bf9a11233ce6cd330ab15e64c8f5940bb9f7be57 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 28 Oct 2023 23:12:33 +0200 Subject: [PATCH 059/352] arm64: dts: apple: t8112: Add dptx-phy node On M2 desktop devices more parts of the HDMI output pipeline are under the OS' control. One of this parts is the primary DPTX phy which drives the the HDMI port through an integrated MCDP29XX DP to HDMI converter. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 332494f0213cdb..d5186dfc2758ea 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1058,6 +1058,17 @@ }; }; + dptxphy: phy@23c500000 { + compatible = "apple,t8112-dptx-phy", "apple,dptx-phy"; + reg = <0x2 0x3c500000 0x0 0x4000>, + <0x2 0x3c540000 0x0 0xc000>; + reg-names = "core", "dptx"; + power-domains = <&ps_dptx_ext_phy>; + #phy-cells = <0>; + #reset-cells = <0>; + status = "disabled"; /* only used on j473 */ + }; + pinctrl_nub: pinctrl@23d1f0000 { compatible = "apple,t8112-pinctrl", "apple,pinctrl"; reg = <0x2 0x3d1f0000 0x0 0x4000>; From 90a73d5d44fd7e95890349f4a3746e3495053f64 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 29 Oct 2023 10:39:17 +0100 Subject: [PATCH 060/352] arm64: dts: apple: t602x: Add lpdptx-phy node On M2 desktop devices more parts of the HDMI output pipeline are under the OS' control. One of this parts is the primary DPTX phy which drives the the HDMI port through an integrated MCDP29XX DP to HDMI converter. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi index 17a239e9206c82..7234eea2847204 100644 --- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi @@ -251,6 +251,17 @@ #interrupt-cells = <2>; }; + DIE_NODE(lpdptxphy): phy@39c000000 { + compatible = "apple,t6020-dptx-phy", "apple,dptx-phy"; + reg = <0x3 0x9c000000 0x0 0x4000>, + <0x3 0x9c040000 0x0 0xc000>; + reg-names = "core", "dptx"; + power-domains = <&DIE_NODE(ps_dptx_phy_ps)>; + #phy-cells = <0>; + #reset-cells = <0>; + status = "disabled"; /* only exposed on desktop devices */ + }; + DIE_NODE(pmgr_gfx): power-management@404e80000 { compatible = "apple,t6020-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; #address-cells = <1>; From bde1175e123d1bc5e2823ec5427682095284ceea Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 00:35:54 +0100 Subject: [PATCH 061/352] arm64: dts: apple: t600x: Add device nodes for atc DP crossbar Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6002-j375d.dts | 2 ++ arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 32 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts index c04597225b6ade..9d61a601c6bf18 100644 --- a/arch/arm64/boot/dts/apple/t6002-j375d.dts +++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts @@ -195,11 +195,13 @@ /delete-node/ &dwc3_2_dart_1_die1; /delete-node/ &dwc3_2_die1; /delete-node/ &atcphy2_die1; +/delete-node/ &atcphy2_xbar_die1; /delete-node/ &dwc3_3_dart_0_die1; /delete-node/ &dwc3_3_dart_1_die1; /delete-node/ &dwc3_3_die1; /delete-node/ &atcphy3_die1; +/delete-node/ &atcphy3_xbar_die1; /* delete unused always-on power-domains on die 1 */ diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi index aa6261aeda8363..1beace2af86aa4 100644 --- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi @@ -305,6 +305,14 @@ power-domains = <&DIE_NODE(ps_atc0_usb)>; }; + DIE_NODE(atcphy0_xbar): mux@70304c000 { + compatible = "apple,t6000-display-crossbar"; + reg = <0x7 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&DIE_NODE(ps_atc0_usb)>; + status = "disabled"; + }; + DIE_NODE(dwc3_1): usb@b02280000 { compatible = "apple,t6000-dwc3", "apple,t8103-dwc3"; reg = <0xb 0x02280000 0x0 0xcd00>, <0xb 0x0228cd00 0x0 0x3200>; @@ -358,6 +366,14 @@ power-domains = <&DIE_NODE(ps_atc1_usb)>; }; + DIE_NODE(atcphy1_xbar): mux@b0304c000 { + compatible = "apple,t6000-display-crossbar"; + reg = <0xb 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&DIE_NODE(ps_atc1_usb)>; + status = "disabled"; + }; + DIE_NODE(dwc3_2): usb@f02280000 { compatible = "apple,t6000-dwc3", "apple,t8103-dwc3"; reg = <0xf 0x02280000 0x0 0xcd00>, <0xf 0x0228cd00 0x0 0x3200>; @@ -411,6 +427,14 @@ power-domains = <&DIE_NODE(ps_atc2_usb)>; }; + DIE_NODE(atcphy2_xbar): mux@f0304c000 { + compatible = "apple,t6000-display-crossbar"; + reg = <0xf 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&DIE_NODE(ps_atc2_usb)>; + status = "disabled"; + }; + DIE_NODE(dwc3_3): usb@1302280000 { compatible = "apple,t6000-dwc3", "apple,t8103-dwc3"; reg = <0x13 0x02280000 0x0 0xcd00>, <0x13 0x0228cd00 0x0 0x3200>; @@ -463,3 +487,11 @@ mode-switch; power-domains = <&DIE_NODE(ps_atc3_usb)>; }; + + DIE_NODE(atcphy3_xbar): mux@130304c000 { + compatible = "apple,t6000-display-crossbar"; + reg = <0x13 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&DIE_NODE(ps_atc3_usb)>; + status = "disabled"; + }; From f1b11a050e91a148467c662e7f5b5512f73fc1e7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 17 Aug 2023 23:17:13 +0200 Subject: [PATCH 062/352] arm64: dts: apple: t602x: Add device nodes for atc DP crossbar Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6022-j475d.dts | 2 ++ arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 32 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6022-j475d.dts b/arch/arm64/boot/dts/apple/t6022-j475d.dts index 141c8497b8890b..227c574be91981 100644 --- a/arch/arm64/boot/dts/apple/t6022-j475d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j475d.dts @@ -52,11 +52,13 @@ /delete-node/ &dwc3_2_dart_1_die1; /delete-node/ &dwc3_2_die1; /delete-node/ &atcphy2_die1; +/delete-node/ &atcphy2_xbar_die1; /delete-node/ &dwc3_3_dart_0_die1; /delete-node/ &dwc3_3_dart_1_die1; /delete-node/ &dwc3_3_die1; /delete-node/ &atcphy3_die1; +/delete-node/ &atcphy3_xbar_die1; /* delete unused always-on power-domains on die 1 */ /delete-node/ &ps_atc2_usb_aon_die1; diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi index 7234eea2847204..3345c6f4829051 100644 --- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi @@ -323,6 +323,14 @@ power-domains = <&DIE_NODE(ps_atc0_usb)>; }; + DIE_NODE(atcphy0_xbar): mux@70304c000 { + compatible = "apple,t6020-display-crossbar"; + reg = <0x7 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&DIE_NODE(ps_atc0_usb)>; + status = "disabled"; + }; + DIE_NODE(dwc3_1): usb@b02280000 { compatible = "apple,t6020-dwc3", "apple,t8103-dwc3"; reg = <0xb 0x02280000 0x0 0xcd00>, <0xb 0x0228cd00 0x0 0x3200>; @@ -376,6 +384,14 @@ power-domains = <&DIE_NODE(ps_atc1_usb)>; }; + DIE_NODE(atcphy1_xbar): mux@b0304c000 { + compatible = "apple,t6020-display-crossbar"; + reg = <0xb 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&DIE_NODE(ps_atc1_usb)>; + status = "disabled"; + }; + DIE_NODE(dwc3_2): usb@f02280000 { compatible = "apple,t6020-dwc3", "apple,t8103-dwc3"; reg = <0xf 0x02280000 0x0 0xcd00>, <0xf 0x0228cd00 0x0 0x3200>; @@ -429,6 +445,14 @@ power-domains = <&DIE_NODE(ps_atc2_usb)>; }; + DIE_NODE(atcphy2_xbar): mux@f0304c000 { + compatible = "apple,t6020-display-crossbar"; + reg = <0xf 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&DIE_NODE(ps_atc2_usb)>; + status = "disabled"; + }; + DIE_NODE(dwc3_3): usb@1302280000 { compatible = "apple,t6020-dwc3", "apple,t8103-dwc3"; reg = <0x13 0x02280000 0x0 0xcd00>, <0x13 0x0228cd00 0x0 0x3200>; @@ -481,3 +505,11 @@ mode-switch; power-domains = <&DIE_NODE(ps_atc3_usb)>; }; + + DIE_NODE(atcphy3_xbar): mux@130304c000 { + compatible = "apple,t6020-display-crossbar"; + reg = <0x13 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&DIE_NODE(ps_atc3_usb)>; + status = "disabled"; + }; From 034e0da10752ef0d125da7ec3b87d38ebaecdac8 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 28 Oct 2023 23:40:47 +0200 Subject: [PATCH 063/352] arm64: dts: apple: t8112-j473: Enable dcpext0/dptx-phy/dp2hdmi After all parts are in place enable DCP on the M2 Mac Mini for HDMI output. Use dcpext for HDMI out dcp on t8112 and t602x does not wake up after sleep + reset but dcpext* does. Use dcpext0 for sharing the code with M1* devices. My interpretation of the tea leaves from Apple's marketing department suggests that dcpext is more capable (6k 60Hz vs 5k 60Hz) so use dcpext as long as only one is used. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j473.dts | 36 ++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts index cf24579ca7b325..62e0fab7dd05d5 100644 --- a/arch/arm64/boot/dts/apple/t8112-j473.dts +++ b/arch/arm64/boot/dts/apple/t8112-j473.dts @@ -19,20 +19,52 @@ aliases { bluetooth0 = &bluetooth0; + /delete-property/ dcp; + dcpext = &dcpext; ethernet0 = ðernet0; wifi0 = &wifi0; }; }; &framebuffer0 { - power-domains = <&ps_disp0_cpu0>, <&ps_dptx_ext_phy>; + power-domains = <&ps_dispext_cpu0>, <&ps_dptx_ext_phy>; +}; + +&dptxphy { + status = "okay"; }; -/* disable dcp until it is supported */ &dcp { status = "disabled"; }; +&display { + iommus = <&dispext0_dart 0>; +}; +&dispext0_dart { + status = "okay"; +}; +&dcpext_dart { + status = "okay"; +}; +&dcpext_mbox { + status = "okay"; +}; +&dcpext { + status = "okay"; + apple,connector-type = "HDMI-A"; + + /* HDMI HPD gpio, used as interrupt*/ + hdmi-hpd-gpios = <&pinctrl_aop 49 GPIO_ACTIVE_HIGH>; + + hdmi-pwren-gpios = <&smc_gpio 21 GPIO_ACTIVE_HIGH>; + dp2hdmi-pwren-gpios = <&smc_gpio 22 GPIO_ACTIVE_HIGH>; + + phys = <&dptxphy>; + phy-names = "dp-phy"; + apple,dptx-phy = <5>; +}; + /* * Keep the power-domains used for the HDMI port on. */ From 146d7d6e990adc423f90643051fcdc4ff2f5210b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 21:47:19 +0100 Subject: [PATCH 064/352] arm64: dts: apple: t6020-j474,t6021-j475: Enable dcpext0/dptx-phy/dp2hdmi After all parts are in place enable the DCP on the M2 Pro Mac Mini and the M2 Max Mac Studio for HDMI output. Use dcpext0 for HDMI out. dcp on t8112 and t602x does not wake up after sleep + reset but dcpext* does. Use dcpext0 for sharing the code with M1* devices. My interpretation of the tea leaves from Apple's marketing department suggests that dcpext is more capable (6k 60Hz vs 5k 60Hz) so use dcpext as long as only one is used. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6020-j474s.dts | 51 ++++++++++++++++++ arch/arm64/boot/dts/apple/t6021-j475c.dts | 52 +++++++++++++++++++ .../arm64/boot/dts/apple/t602x-j474-j475.dtsi | 5 -- 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6020-j474s.dts b/arch/arm64/boot/dts/apple/t6020-j474s.dts index 17c72b0bb87721..89b6c46a036eca 100644 --- a/arch/arm64/boot/dts/apple/t6020-j474s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j474s.dts @@ -63,6 +63,57 @@ model = "Mac mini J474"; }; +&lpdptxphy { + status = "okay"; +}; + +#define USE_DCPEXT0 1 + +#if USE_DCPEXT0 +/ { + aliases { + dcpext0 = &dcpext0; + /delete-property/ dcp; + }; +}; + +&framebuffer0 { + power-domains = <&ps_dispext0_cpu0>, <&ps_dptx_phy_ps>; +}; + +&dcp { + status = "disabled"; +}; +&display { + iommus = <&dispext0_dart 0>; +}; +&dispext0_dart { + status = "okay"; +}; +&dcpext0_dart { + status = "okay"; +}; +&dcpext0_mbox { + status = "okay"; +}; +&dcpext0 { +#else +&dcp { +#endif + status = "okay"; + apple,connector-type = "HDMI-A"; + + /* HDMI HPD gpio, used as interrupt*/ + hdmi-hpd-gpios = <&pinctrl_aop 25 GPIO_ACTIVE_HIGH>; + + hdmi-pwren-gpios = <&smc_gpio 23 GPIO_ACTIVE_HIGH>; + dp2hdmi-pwren-gpios = <&smc_gpio 25 GPIO_ACTIVE_HIGH>; + + phys = <&lpdptxphy>; + phy-names = "dp-phy"; + apple,dptx-phy = <4>; +}; + &gpu { /* Apple does not do this, but they probably should */ apple,perf-base-pstate = <3>; diff --git a/arch/arm64/boot/dts/apple/t6021-j475c.dts b/arch/arm64/boot/dts/apple/t6021-j475c.dts index ebc3ec8c387b30..07d6f5d366830a 100644 --- a/arch/arm64/boot/dts/apple/t6021-j475c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j475c.dts @@ -58,6 +58,58 @@ model = "Mac Studio J475"; }; +&lpdptxphy { + status = "okay"; +}; + + +#define USE_DCPEXT0 1 + +#if USE_DCPEXT0 +/ { + aliases { + dcpext0 = &dcpext0; + /delete-property/ dcp; + }; +}; + +&framebuffer0 { + power-domains = <&ps_dispext0_cpu0>, <&ps_dptx_phy_ps>; +}; + +&dcp { + status = "disabled"; +}; +&display { + iommus = <&dispext0_dart 0>; +}; +&dispext0_dart { + status = "okay"; +}; +&dcpext0_dart { + status = "okay"; +}; +&dcpext0_mbox { + status = "okay"; +}; +&dcpext0 { +#else +&dcp { +#endif + status = "okay"; + apple,connector-type = "HDMI-A"; + + /* HDMI HPD gpio, used as interrupt*/ + hdmi-hpd-gpios = <&pinctrl_aop 25 GPIO_ACTIVE_HIGH>; + + hdmi-pwren-gpios = <&smc_gpio 23 GPIO_ACTIVE_HIGH>; + dp2hdmi-pwren-gpios = <&smc_gpio 25 GPIO_ACTIVE_HIGH>; + + phys = <&lpdptxphy>; + phy-names = "dp-phy"; + apple,dptx-phy = <4>; +}; + &gpu { apple,idleoff-standby-timer = <3000>; apple,perf-base-pstate = <5>; diff --git a/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi b/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi index 25c0e6bf41724b..287348628eb177 100644 --- a/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi @@ -21,11 +21,6 @@ power-domains = <&ps_dispext0_cpu0>, <&ps_dptx_phy_ps>; }; -/* disable dcp until it is supported */ -&dcp { - status = "disabled"; -}; - &hpm0 { interrupts = <44 IRQ_TYPE_LEVEL_LOW>; }; From 39735456844ab535a86f113f7e2c8a1e49d352ac Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 4 Nov 2023 22:33:29 +0100 Subject: [PATCH 065/352] arm64: dts: apple: t6022-{j180,j475}: Enable dcpext0/dptx-phy/dp2hdmi After all parts are in place enable dcpext on M2 Ultra Mac Pro and Studio. On the Mac Pro only the HDMI output connected to die1 is enabled. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6022-j475d.dts | 6 +++ arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi | 43 ++++++++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6022-j475d.dts b/arch/arm64/boot/dts/apple/t6022-j475d.dts index 227c574be91981..74a75d680345d8 100644 --- a/arch/arm64/boot/dts/apple/t6022-j475d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j475d.dts @@ -22,6 +22,7 @@ aliases { atcphy4 = &atcphy0_die1; atcphy5 = &atcphy1_die1; + /delete-property/ dcp; }; }; @@ -29,6 +30,11 @@ power-domains = <&ps_dispext0_cpu0_die1>, <&ps_dptx_phy_ps_die1>; }; +&dcpext0_die1 { + // J180 misses "function-dp2hdmi_pwr_en" + dp2hdmi-pwren-gpios = <&smc_gpio 25 GPIO_ACTIVE_HIGH>; +}; + /* enable PCIe port01 with SDHCI */ &port01 { pwren-gpios = <&smc_gpio 22 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi index 5b7b41ce07c3d8..545f1087aa80dc 100644 --- a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi +++ b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi @@ -9,11 +9,48 @@ * Copyright The Asahi Linux Contributors */ -/* disable unused display node */ +/ { + aliases { + dcpext4 = &dcpext0_die1; + disp0 = &display; + }; +}; + +&lpdptxphy_die1 { + status = "okay"; +}; &display { - status = "disabled"; - iommus = <>; /* <&dispext0_dart_die1 0>; */ + iommus = <&dispext0_dart_die1 0>; +}; + +&dispext0_dart_die1 { + status = "okay"; +}; + +&dcpext0_dart_die1 { + status = "okay"; +}; + +&dcpext0_mbox_die1 { + status = "okay"; +}; + +&dcpext0_die1 { + status = "okay"; + apple,connector-type = "HDMI-A"; + + /* HDMI HPD gpio, used as interrupt*/ + hdmi-hpd-gpios = <&pinctrl_aop 41 GPIO_ACTIVE_HIGH>; + + hdmi-pwren-gpios = <&smc_gpio 23 GPIO_ACTIVE_HIGH>; + // J180 misses "function-dp2hdmi_pwr_en" + // dp2hdmi-pwren-gpios = <&smc_gpio 25 GPIO_ACTIVE_HIGH>; + + phys = <&lpdptxphy_die1>; + phy-names = "dp-phy"; + apple,dptx-phy = <4>; + apple,dptx-die = <1>; }; /* delete missing dcp0/disp0 */ From bd71a37acc8dc3bb3b00036f096288be04b37a43 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 20:39:42 +0100 Subject: [PATCH 066/352] arm64: dts: apple: Fill device node for dp2hdmi on Macbook Pros The HDMI output on the 14 and 16 inch Macbook Pros with M1/M2 Pro/Max is driven by an unused ATC port using the phy and crossbar. The DP output from any dcpext display controller is routed to a Kinetic DP2HDMI converter (MCDP2920 and a unknown HDMI 2.1 capable variant). Signed-off-by: Janne Grunau --- .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 39 +++++++++++++++++++ .../arm64/boot/dts/apple/t602x-j414-j416.dtsi | 5 +++ 2 files changed, 44 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 187e132d77281b..6899c5f4a80df1 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -21,6 +21,7 @@ atcphy3 = &atcphy3; bluetooth0 = &bluetooth0; dcp = &dcp; + dcpext0 = &dcpext0; disp0 = &display; disp0_piodma = &disp0_piodma; serial0 = &serial0; @@ -73,6 +74,44 @@ }; }; +&display { + iommus = <&disp0_dart 0>, <&dispext0_dart 0>; +}; + +&dispext0_dart { + status = "okay"; +}; + +&dcpext0_dart { + status = "okay"; +}; + +&dcpext0_mbox { + status = "okay"; +}; + +&dcpext0 { + /* enabled by the loader */ + apple,connector-type = "HDMI-A"; + + /* HDMI HPD gpio, used as interrupt*/ + hdmi-hpd-gpios = <&pinctrl_nub 15 GPIO_ACTIVE_HIGH>; + + hdmi-pwren-gpios = <&smc_gpio 23 GPIO_ACTIVE_HIGH>; + dp2hdmi-pwren-gpios = <&smc_gpio 6 GPIO_ACTIVE_HIGH>; + + phys = <&atcphy3 PHY_TYPE_DP>; + phy-names = "dp-phy"; + mux-controls = <&atcphy3_xbar 0>; + mux-control-names = "dp-xbar"; + mux-index = <0>; + apple,dptx-phy = <3>; +}; + +&atcphy3_xbar { + status = "okay"; +}; + /* USB Type C */ &i2c0 { hpm0: usb-pd@38 { diff --git a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi index b9aee8ec432b9a..0057e6a9465f9d 100644 --- a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi @@ -34,6 +34,11 @@ apple,always-on; }; +&dcpext0 { + /* HDMI HPD gpio, used as interrupt*/ + hdmi-hpd-gpios = <&pinctrl_aop 25 GPIO_ACTIVE_HIGH>; +}; + &hpm0 { interrupts = <44 IRQ_TYPE_LEVEL_LOW>; }; From 49b0440433d8f8cd980fe0e1b20dcfb2c7aa74cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sun, 12 Feb 2023 15:26:30 +0100 Subject: [PATCH 067/352] arm64: apple: t8103-pmgr: SIO: Add audio, spi and uart power-domains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The power-domains AUDIO_P, SPI_P and UART_P are necessary for SIO's ASC firmware to run. This is not explicitly expressed in the ADT (probably since the power-domains are implicitly turned on when macOS uses SIO). Since we plan to use SIO only for DP/HDMI audio add the power-domains explicitly as dependency of ps_sio_cpu. They might be better placed directly into the SIO node but the SIO driver doesn't support multiple power-domains. Signed-off-by: Janne Grunau Signed-off-by: Martin Povišer --- arch/arm64/boot/dts/apple/t8103-pmgr.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi index 10facd0c01e420..5d3846d44e3578 100644 --- a/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-pmgr.dtsi @@ -234,7 +234,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = "sio_cpu"; - power-domains = <&ps_sio>; + power-domains = <&ps_sio &ps_uart_p &ps_spi_p &ps_dpa0>; }; ps_fpwm0: power-controller@1d8 { From de42d0a09f7b4790c01e7a9bb89e0a0245d2578b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 13 Nov 2023 23:58:10 +0100 Subject: [PATCH 068/352] arm64: apple: t8112-pmgr: SIO: Add audio, spi and uart power-domains The power-domains AUDIO_P, SPI_P and UART_P are necessary for SIO's ASC firmware to run. This is not explicitly expressed in the ADT (probably since the power-domains are implicitly turned on when macOS uses SIO). Since we plan to use SIO only for DP/HDMI audio add the power-domains explicitly as dependency of ps_sio_cpu. They might be better placed directly into the SIO node but the SIO driver doesn't support multiple power-domains. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-pmgr.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi index 102ff3ad0535d0..ab8ec9bd4e4401 100644 --- a/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-pmgr.dtsi @@ -176,7 +176,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = "sio_cpu"; - power-domains = <&ps_sio>; + power-domains = <&ps_sio &ps_uart_p &ps_spi_p &ps_dpa0>; }; ps_fpwm0: power-controller@1c8 { From 42abcd84cd140d6d9da58b521daa501245511bf6 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Apr 2024 18:01:37 +0200 Subject: [PATCH 069/352] arm64: apple: t600x: pmgr: SIO: Add audio, spi and uart power-domains The power-domains AUDIO_P, SPI_P and UART_P are necessary for SIO's ASC firmware to run. This is not explicitly expressed in the ADT (probably since the power-domains are implicitly turned on when macOS uses SIO). Since we plan to use SIO only for DP/HDMI audio add the power-domains explicitly as dependency of ps_sio_cpu. They might be better placed directly into the SIO node butr the SIO driver doesn't support multiple power-domains. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index a8f85e41baa4fe..1429554ed54505 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -826,7 +826,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(sio_cpu); - power-domains = <&DIE_NODE(ps_sio)>; + power-domains = <&DIE_NODE(ps_sio) &DIE_NODE(ps_uart_p) &DIE_NODE(ps_spi_p) &DIE_NODE(ps_audio_p)>; }; DIE_NODE(ps_fpwm0): power-controller@190 { From 300f525b665aa81962e98af9c0a8eb47452742f9 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Apr 2024 18:01:37 +0200 Subject: [PATCH 070/352] arm64: apple: t602x: pmgr: SIO: Add audio, spi and uart power-domains The power-domains AUDIO_P, SPI_P and UART_P are necessary for SIO's ASC firmware to run. This is not explicitly expressed in the ADT (probably since the power-domains are implicitly turned on when macOS uses SIO). Since we plan to use SIO only for DP/HDMI audio add the power-domains explicitly as dependency of ps_sio_cpu. They might be better placed directly into the SIO node butr the SIO driver doesn't support multiple power-domains. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t602x-pmgr.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi index 7d70e8bb08185a..b9233f252e6ca7 100644 --- a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi @@ -1260,7 +1260,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(sio_cpu); - power-domains = <&DIE_NODE(ps_sio)>; + power-domains = <&DIE_NODE(ps_sio) &DIE_NODE(ps_uart_p) &DIE_NODE(ps_spi_p) &DIE_NODE(ps_audio_p)>; }; DIE_NODE(ps_fpwm0): power-controller@1e8 { From f12640e499e8b131b5b3d7a96b7ef59443f73989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 28 Nov 2022 17:10:01 +0100 Subject: [PATCH 071/352] arm64: apple: t8103: Add SIO, DPA nodes; hook up to DCP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- arch/arm64/boot/dts/apple/t8103-j274.dts | 5 ++ arch/arm64/boot/dts/apple/t8103.dtsi | 90 ++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts index 9396c8a010ab3d..ee38c4832d1dc0 100644 --- a/arch/arm64/boot/dts/apple/t8103-j274.dts +++ b/arch/arm64/boot/dts/apple/t8103-j274.dts @@ -19,6 +19,7 @@ aliases { ethernet0 = ðernet0; + sio = &sio; }; }; @@ -26,6 +27,10 @@ apple,connector-type = "HDMI-A"; }; +&dpaudio0 { + status = "okay"; +}; + &bluetooth0 { brcm,board-type = "apple,atlantisb"; }; diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index df241a52dbcefd..e1c18406147d43 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -671,6 +671,17 @@ iommus = <&disp0_dart 4>; phandle = <&disp0_piodma>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dcp_audio: endpoint { + remote-endpoint = <&dpaudio0_dcp>; + }; + }; + }; }; display: display-subsystem { @@ -891,6 +902,32 @@ status = "disabled"; }; + sio_mbox: mbox@236408000 { + compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x36408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_sio>; + }; + + sio: sio@236400000 { + compatible = "apple,t8103-sio", "apple,sio"; + reg = <0x2 0x36400000 0x0 0x8000>; + dma-channels = <128>; + #dma-cells = <1>; + mboxes = <&sio_mbox>; + iommus = <&sio_dart 0>; + power-domains = <&ps_sio_cpu>; + resets = <&ps_sio>; /* TODO: verify reset does something */ + status = "disabled"; + }; + admac: dma-controller@238200000 { compatible = "apple,t8103-admac", "apple,admac"; reg = <0x2 0x38200000 0x0 0x34000>; @@ -905,6 +942,48 @@ resets = <&ps_audio_p>; }; + dpaudio0: audio-controller@238330000 { + compatible = "apple,t8103-dpaudio", "apple,dpaudio"; + reg = <0x2 0x38330000 0x0 0x4000>; + dmas = <&sio 0x64>; + dma-names = "tx"; + power-domains = <&ps_dpa0>; + reset-domains = <&ps_dpa0>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dpaudio0_dcp: endpoint { + remote-endpoint = <&dcp_audio>; + }; + }; + }; + }; + + dpaudio1: audio-controller@238334000 { + compatible = "apple,t8103-dpaudio", "apple,dpaudio"; + reg = <0x2 0x38334000 0x0 0x4000>; + dmas = <&sio 0x66>; + dma-names = "tx"; + power-domains = <&ps_dpa1>; + reset-domains = <&ps_dpa1>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dpaudio1_dcp: endpoint { + remote-endpoint = <&dcpext_audio>; + }; + }; + }; + }; + mca: i2s@238400000 { compatible = "apple,t8103-mca", "apple,mca"; reg = <0x2 0x38400000 0x0 0x18000>, @@ -1297,6 +1376,17 @@ piodma { iommus = <&dispext0_dart 4>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dcpext_audio: endpoint { + remote-endpoint = <&dpaudio1_dcp>; + }; + }; + }; }; ans_mbox: mbox@277408000 { From 57172ae00c137f09302b1ebf646cd1d32f447a63 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 13 Nov 2023 23:35:07 +0100 Subject: [PATCH 072/352] arm64: apple: t8112: Add SIO, DPA nodes; hook up to DCP Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j473.dts | 5 ++ arch/arm64/boot/dts/apple/t8112.dtsi | 90 ++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts index 62e0fab7dd05d5..4df9b82c5d40e4 100644 --- a/arch/arm64/boot/dts/apple/t8112-j473.dts +++ b/arch/arm64/boot/dts/apple/t8112-j473.dts @@ -22,6 +22,7 @@ /delete-property/ dcp; dcpext = &dcpext; ethernet0 = ðernet0; + sio = &sio; wifi0 = &wifi0; }; }; @@ -65,6 +66,10 @@ apple,dptx-phy = <5>; }; +&dpaudio1 { + status = "okay"; +}; + /* * Keep the power-domains used for the HDMI port on. */ diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index d5186dfc2758ea..94c5dbdbafb49c 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -745,6 +745,17 @@ iommus = <&disp0_dart 4>; phandle = <&disp0_piodma>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dcp_audio: endpoint { + remote-endpoint = <&dpaudio0_dcp>; + }; + }; + }; }; display: display-subsystem { @@ -899,6 +910,32 @@ status = "disabled"; }; + sio_mbox: mbox@236408000 { + compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x36408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_sio_cpu>; + }; + + sio: sio@236400000 { + compatible = "apple,t8112-sio", "apple,sio"; + reg = <0x2 0x36400000 0x0 0x8000>; + dma-channels = <128>; + #dma-cells = <1>; + mboxes = <&sio_mbox>; + iommus = <&sio_dart 0>; + power-domains = <&ps_sio_cpu>; + resets = <&ps_sio>; /* TODO: verify reset does something */ + status = "disabled"; + }; + admac: dma-controller@238200000 { compatible = "apple,t8112-admac", "apple,admac"; reg = <0x2 0x38200000 0x0 0x34000>; @@ -913,6 +950,48 @@ resets = <&ps_audio_p>; }; + dpaudio0: audio-controller@238330000 { + compatible = "apple,t8112-dpaudio", "apple,dpaudio"; + reg = <0x2 0x38330000 0x0 0x4000>; + dmas = <&sio 0x64>; + dma-names = "tx"; + power-domains = <&ps_dpa0>; + reset-domains = <&ps_dpa0>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dpaudio0_dcp: endpoint { + remote-endpoint = <&dcp_audio>; + }; + }; + }; + }; + + dpaudio1: audio-controller@238334000 { + compatible = "apple,t8112-dpaudio", "apple,dpaudio"; + reg = <0x2 0x38334000 0x0 0x4000>; + dmas = <&sio 0x66>; + dma-names = "tx"; + power-domains = <&ps_dpa1>; + reset-domains = <&ps_dpa1>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dpaudio1_dcp: endpoint { + remote-endpoint = <&dcpext_audio>; + }; + }; + }; + }; + mca: i2s@238400000 { compatible = "apple,t8112-mca", "apple,mca"; reg = <0x2 0x38400000 0x0 0x18000>, @@ -1386,6 +1465,17 @@ piodma { iommus = <&dispext0_dart 4>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dcpext_audio: endpoint { + remote-endpoint = <&dpaudio1_dcp>; + }; + }; + }; }; ans_mbox: mbox@277408000 { From fce7ce0b0a6ec3c0b661a108fb7ce53ef973f781 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 19 Nov 2023 14:55:00 +0100 Subject: [PATCH 073/352] arm64: apple: t600x: Move dart_sio* to dieX j375d uses SIO on the second die for DP audio for its dcpexts. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 18 ------------------ arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index af47346967d80e..8e6c8a465253d0 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -236,24 +236,6 @@ phandle = <&display>; }; - sio_dart_0: iommu@39b004000 { - compatible = "apple,t6000-dart"; - reg = <0x3 0x9b004000 0x0 0x4000>; - interrupt-parent = <&aic>; - interrupts = ; - #iommu-cells = <1>; - power-domains = <&ps_sio_cpu>; - }; - - sio_dart_1: iommu@39b008000 { - compatible = "apple,t6000-dart"; - reg = <0x3 0x9b008000 0x0 0x8000>; - interrupt-parent = <&aic>; - interrupts = ; - #iommu-cells = <1>; - power-domains = <&ps_sio_cpu>; - }; - fpwm0: pwm@39b030000 { compatible = "apple,t6000-fpwm", "apple,s5l-fpwm"; reg = <0x3 0x9b030000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi index 1beace2af86aa4..4585e67330dd14 100644 --- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi @@ -227,6 +227,24 @@ ; }; + DIE_NODE(sio_dart_0): iommu@39b004000 { + compatible = "apple,t6000-dart"; + reg = <0x3 0x9b004000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = ; + #iommu-cells = <1>; + power-domains = <&DIE_NODE(ps_sio_cpu)>; + }; + + DIE_NODE(sio_dart_1): iommu@39b008000 { + compatible = "apple,t6000-dart"; + reg = <0x3 0x9b008000 0x0 0x8000>; + interrupt-parent = <&aic>; + interrupts = ; + #iommu-cells = <1>; + power-domains = <&DIE_NODE(ps_sio_cpu)>; + }; + DIE_NODE(pinctrl_ap): pinctrl@39b028000 { compatible = "apple,t6000-pinctrl", "apple,pinctrl"; reg = <0x3 0x9b028000 0x0 0x4000>; From 848dd512550566b88e18e8285e289ea024e2601c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 19 Nov 2023 14:57:09 +0100 Subject: [PATCH 074/352] arm64: apple: t600x: Add sio and dpaudio device nodes Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 32 +++++ arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 136 ++++++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 8e6c8a465253d0..ff106e95b66ef6 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -188,6 +188,27 @@ apple,dma-range = <0x1f0 0x0 0x0 0xfc000000>; }; + dpaudio0: audio-controller@39b500000 { + compatible = "apple,t6000-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b500000 0x0 0x4000>; + dmas = <&sio 0x64>; + dma-names = "tx"; + power-domains = <&ps_dpa0>; + reset-domains = <&ps_dpa0>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dpaudio0_dcp: endpoint { + remote-endpoint = <&dcp_audio>; + }; + }; + }; + }; + dcp_mbox: mbox@38bc08000 { compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; reg = <0x3 0x8bc08000 0x0 0x4000>; @@ -227,6 +248,17 @@ iommus = <&disp0_dart 4>; phandle = <&disp0_piodma>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dcp_audio: endpoint { + remote-endpoint = <&dpaudio0_dcp>; + }; + }; + }; }; display: display-subsystem { diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi index 4585e67330dd14..1671299411e0e6 100644 --- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi @@ -88,6 +88,17 @@ piodma { iommus = <&DIE_NODE(dispext0_dart) 4>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dcpext0_audio): endpoint { + remote-endpoint = <&DIE_NODE(dpaudio1_dcp)>; + }; + }; + }; }; DIE_NODE(dispext1_dart): iommu@28c304000 { @@ -154,6 +165,17 @@ piodma { iommus = <&DIE_NODE(dispext1_dart) 4>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dcpext1_audio): endpoint { + remote-endpoint = <&DIE_NODE(dpaudio2_dcp)>; + }; + }; + }; }; DIE_NODE(pmgr): power-management@28e080000 { @@ -270,6 +292,120 @@ #interrupt-cells = <2>; }; + DIE_NODE(sio_mbox): mbox@39bc08000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x9bc08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&DIE_NODE(ps_sio_cpu)>; + }; + + DIE_NODE(sio): sio@39bc00000 { + compatible = "apple,t6000-sio", "apple,sio"; + reg = <0x3 0x9bc00000 0x0 0x8000>; + dma-channels = <128>; + #dma-cells = <1>; + mboxes = <&DIE_NODE(sio_mbox)>; + iommus = <&DIE_NODE(sio_dart_0) 0>, <&DIE_NODE(sio_dart_1) 0>; + power-domains = <&DIE_NODE(ps_sio_cpu)>; + resets = <&DIE_NODE(ps_sio)>; /* TODO: verify reset does something */ + status = "disabled"; + }; + + DIE_NODE(dpaudio1): audio-controller@39b504000 { + compatible = "apple,t6000-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b540000 0x0 0x4000>; + dmas = <&DIE_NODE(sio) 0x66>; + dma-names = "tx"; + power-domains = <&DIE_NODE(ps_dpa1)>; + reset-domains = <&DIE_NODE(ps_dpa1)>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dpaudio1_dcp): endpoint { + remote-endpoint = <&DIE_NODE(dcpext0_audio)>; + }; + }; + }; + }; + + DIE_NODE(dpaudio2): audio-controller@39b508000 { + compatible = "apple,t6000-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b580000 0x0 0x4000>; + dmas = <&DIE_NODE(sio) 0x68>; + dma-names = "tx"; + power-domains = <&DIE_NODE(ps_dpa2)>; + reset-domains = <&DIE_NODE(ps_dpa2)>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dpaudio2_dcp): endpoint { + remote-endpoint = <&DIE_NODE(dcpext1_audio)>; + }; + }; + }; + }; + + /* + * omit dpaudio3 / 4 as long as the linked dcpext nodes don't exist + * + DIE_NODE(dpaudio3): audio-controller@39b50c000 { + compatible = "apple,t6000-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b5c0000 0x0 0x4000>; + dmas = <&DIE_NODE(sio) 0x6a>; + dma-names = "tx"; + power-domains = <&DIE_NODE(ps_dpa3)>; + reset-domains = <&DIE_NODE(ps_dpa3)>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dpaudio3_dcp): endpoint { + remote-endpoint = <&DIE_NODE(dcpext2_audio)>; + }; + }; + }; + }; + + DIE_NODE(dpaudio4): audio-controller@39b510000 { + compatible = "apple,t6000-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b500000 0x0 0x4000>; + dmas = <&DIE_NODE(sio) 0x6c>; + dma-names = "tx"; + power-domains = <&DIE_NODE(ps_dpa4)>; + reset-domains = <&DIE_NODE(ps_dpa4)>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dpaudio4_dcp): endpoint { + remote-endpoint = <&DIE_NODE(dcpext3_audio)>; + }; + }; + }; + }; + */ + DIE_NODE(dwc3_0): usb@702280000 { compatible = "apple,t6000-dwc3", "apple,t8103-dwc3"; reg = <0x7 0x02280000 0x0 0xcd00>, <0x7 0x0228cd00 0x0 0x3200>; From fe7a4bb0cd8bfa9ca20f4350687e14424c6aa676 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Jan 2024 14:45:49 +0100 Subject: [PATCH 075/352] arm64: apple: t602x: Add sio and dpaudio device nodes Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi | 1 + arch/arm64/boot/dts/apple/t602x-die0.dtsi | 41 ++++-- arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 146 +++++++++++++++++++++ 3 files changed, 179 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi index 545f1087aa80dc..17e97eee64bde6 100644 --- a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi +++ b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi @@ -58,6 +58,7 @@ /delete-node/ &dcp_dart; /delete-node/ &dcp_mbox; /delete-node/ &dcp; +/delete-node/ &dpaudio0; /* delete power-domains for missing disp0 / disp0_die1 */ /delete-node/ &ps_disp0_cpu0; diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 84ab8e250df6e7..4af8d727e61b24 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -355,6 +355,17 @@ iommus = <&disp0_dart 4>; phandle = <&disp0_piodma>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dcp_audio: endpoint { + remote-endpoint = <&dpaudio0_dcp>; + }; + }; + }; }; display: display-subsystem { @@ -364,15 +375,6 @@ phandle = <&display>; }; - sio_dart: iommu@39b008000 { - compatible = "apple,t6020-dart", "apple,t8110-dart"; - reg = <0x3 0x9b008000 0x0 0x8000>; - interrupt-parent = <&aic>; - interrupts = ; - #iommu-cells = <1>; - power-domains = <&ps_sio_cpu>; - }; - fpwm0: pwm@39b030000 { compatible = "apple,t6020-fpwm", "apple,s5l-fpwm"; reg = <0x3 0x9b030000 0x0 0x4000>; @@ -579,6 +581,27 @@ resets = <&ps_audio_p>; }; + dpaudio0: audio-controller@39b500000 { + compatible = "apple,t6020-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b500000 0x0 0x4000>; + dmas = <&sio 0x64>; + dma-names = "tx"; + power-domains = <&ps_dpa0>; + reset-domains = <&ps_dpa0>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dpaudio0_dcp: endpoint { + remote-endpoint = <&dcp_audio>; + }; + }; + }; + }; + mca: mca@39b600000 { compatible = "apple,t6020-mca", "apple,t8103-mca", "apple,mca"; reg = <0x3 0x9b600000 0x0 0x10000>, diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi index 3345c6f4829051..30fe15fe0ac393 100644 --- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi @@ -87,6 +87,17 @@ piodma { iommus = <&DIE_NODE(dispext0_dart) 4>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dcpext0_audio): endpoint { + remote-endpoint = <&DIE_NODE(dpaudio1_dcp)>; + }; + }; + }; }; DIE_NODE(pmgr): power-management@28e080000 { @@ -224,6 +235,27 @@ piodma { iommus = <&DIE_NODE(dispext1_dart) 4>; }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dcpext1_audio): endpoint { + remote-endpoint = <&DIE_NODE(dpaudio2_dcp)>; + }; + }; + }; + }; + + DIE_NODE(sio_dart): iommu@39b008000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x9b008000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = ; + #iommu-cells = <1>; + power-domains = <&DIE_NODE(ps_sio)>; + //apple,dma-range = <0x100 0x0001c000 0x2ff 0xfffe4000>; }; DIE_NODE(pinctrl_ap): pinctrl@39b028000 { @@ -251,6 +283,120 @@ #interrupt-cells = <2>; }; + DIE_NODE(sio_mbox): mbox@39bc08000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x9bc08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&DIE_NODE(ps_sio_cpu)>; + }; + + DIE_NODE(sio): sio@39bc00000 { + compatible = "apple,t6020-sio", "apple,sio"; + reg = <0x3 0x9bc00000 0x0 0x8000>; + dma-channels = <128>; + #dma-cells = <1>; + mboxes = <&DIE_NODE(sio_mbox)>; + iommus = <&DIE_NODE(sio_dart) 0>; + power-domains = <&DIE_NODE(ps_sio_cpu)>; + resets = <&DIE_NODE(ps_sio_cpu)>; + status = "disabled"; + }; + + DIE_NODE(dpaudio1): audio-controller@39b504000 { + compatible = "apple,t6020-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b540000 0x0 0x4000>; + dmas = <&DIE_NODE(sio) 0x66>; + dma-names = "tx"; + power-domains = <&DIE_NODE(ps_dpa1)>; + reset-domains = <&DIE_NODE(ps_dpa1)>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dpaudio1_dcp): endpoint { + remote-endpoint = <&DIE_NODE(dcpext0_audio)>; + }; + }; + }; + }; + + DIE_NODE(dpaudio2): audio-controller@39b508000 { + compatible = "apple,t6020-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b580000 0x0 0x4000>; + dmas = <&DIE_NODE(sio) 0x68>; + dma-names = "tx"; + power-domains = <&DIE_NODE(ps_dpa2)>; + reset-domains = <&DIE_NODE(ps_dpa2)>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dpaudio2_dcp): endpoint { + remote-endpoint = <&DIE_NODE(dcpext1_audio)>; + }; + }; + }; + }; + + /* + * omit dpaudio3 / 4 as long as the linked dcpext nodes don't exist + * + DIE_NODE(dpaudio3): audio-controller@39b50c000 { + compatible = "apple,t6020-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b5c0000 0x0 0x4000>; + dmas = <&DIE_NODE(sio) 0x6a>; + dma-names = "tx"; + power-domains = <&DIE_NODE(ps_dpa3)>; + reset-domains = <&DIE_NODE(ps_dpa3)>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dpaudio3_dcp): endpoint { + remote-endpoint = <&DIE_NODE(dcpext2_audio)>; + }; + }; + }; + }; + + DIE_NODE(dpaudio4): audio-controller@39b510000 { + compatible = "apple,t6020-dpaudio", "apple,dpaudio"; + reg = <0x3 0x9b500000 0x0 0x4000>; + dmas = <&DIE_NODE(sio) 0x6c>; + dma-names = "tx"; + power-domains = <&DIE_NODE(ps_dpa4)>; + reset-domains = <&DIE_NODE(ps_dpa4)>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + DIE_NODE(dpaudio4_dcp): endpoint { + remote-endpoint = <&DIE_NODE(dcpext3_audio)>; + }; + }; + }; + }; + */ + DIE_NODE(lpdptxphy): phy@39c000000 { compatible = "apple,t6020-dptx-phy", "apple,dptx-phy"; reg = <0x3 0x9c000000 0x0 0x4000>, From 89ddd200c0ba3dd074bbdb79d4607c8755e55a7a Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 7 Apr 2024 23:10:55 +0200 Subject: [PATCH 076/352] arm64: apple: t60xx: Enable DP/HMI audio nodes on all devices Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6001-j375c.dts | 4 ++++ arch/arm64/boot/dts/apple/t6002-j375d.dts | 4 ++++ arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 5 +++++ arch/arm64/boot/dts/apple/t600x-j375.dtsi | 1 + arch/arm64/boot/dts/apple/t6020-j474s.dts | 6 ++++++ arch/arm64/boot/dts/apple/t6021-j475c.dts | 6 ++++++ arch/arm64/boot/dts/apple/t6022-j475d.dts | 5 +++++ arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi | 5 +++++ 8 files changed, 36 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts index 68e2b120117840..4028571143ac87 100644 --- a/arch/arm64/boot/dts/apple/t6001-j375c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts @@ -25,6 +25,10 @@ brcm,board-type = "apple,okinawa"; }; +&dpaudio0 { + status = "okay"; +}; + &sound { compatible = "apple,j375-macaudio", "apple,macaudio"; model = "Mac Studio J375"; diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts index 9d61a601c6bf18..e17c71ff18913c 100644 --- a/arch/arm64/boot/dts/apple/t6002-j375d.dts +++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts @@ -21,6 +21,10 @@ }; }; +&dpaudio0 { + status = "okay"; +}; + &sound { compatible = "apple,j375-macaudio", "apple,macaudio"; model = "Mac Studio J375"; diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 6899c5f4a80df1..797ac0c75481ae 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -25,6 +25,7 @@ disp0 = &display; disp0_piodma = &disp0_piodma; serial0 = &serial0; + sio = &sio; wifi0 = &wifi0; }; @@ -108,6 +109,10 @@ apple,dptx-phy = <3>; }; +&dpaudio1 { + status = "okay"; +}; + &atcphy3_xbar { status = "okay"; }; diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi index ce962404b2581d..6336cff863b5eb 100644 --- a/arch/arm64/boot/dts/apple/t600x-j375.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi @@ -25,6 +25,7 @@ #endif ethernet0 = ðernet0; serial0 = &serial0; + sio = &sio; wifi0 = &wifi0; }; diff --git a/arch/arm64/boot/dts/apple/t6020-j474s.dts b/arch/arm64/boot/dts/apple/t6020-j474s.dts index 89b6c46a036eca..f904582f98bb91 100644 --- a/arch/arm64/boot/dts/apple/t6020-j474s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j474s.dts @@ -96,8 +96,14 @@ &dcpext0_mbox { status = "okay"; }; +&dpaudio1 { + status = "okay"; +}; &dcpext0 { #else +&dpaudio0 { + status = "okay"; +}; &dcp { #endif status = "okay"; diff --git a/arch/arm64/boot/dts/apple/t6021-j475c.dts b/arch/arm64/boot/dts/apple/t6021-j475c.dts index 07d6f5d366830a..09f477dbdf28b1 100644 --- a/arch/arm64/boot/dts/apple/t6021-j475c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j475c.dts @@ -92,8 +92,14 @@ &dcpext0_mbox { status = "okay"; }; +&dpaudio1 { + status = "okay"; +}; &dcpext0 { #else +&dpaudio0 { + status = "okay"; +}; &dcp { #endif status = "okay"; diff --git a/arch/arm64/boot/dts/apple/t6022-j475d.dts b/arch/arm64/boot/dts/apple/t6022-j475d.dts index 74a75d680345d8..a9020a23a7e976 100644 --- a/arch/arm64/boot/dts/apple/t6022-j475d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j475d.dts @@ -23,9 +23,14 @@ atcphy4 = &atcphy0_die1; atcphy5 = &atcphy1_die1; /delete-property/ dcp; + /delete-property/ sio; }; }; +&sio { + status = "disabled"; +}; + &framebuffer0 { power-domains = <&ps_dispext0_cpu0_die1>, <&ps_dptx_phy_ps_die1>; }; diff --git a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi index 17e97eee64bde6..f11b017dc0496f 100644 --- a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi +++ b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi @@ -13,6 +13,7 @@ aliases { dcpext4 = &dcpext0_die1; disp0 = &display; + sio1 = &sio_die1; }; }; @@ -53,6 +54,10 @@ apple,dptx-die = <1>; }; +&dpaudio1_die1 { + status = "okay"; +}; + /* delete missing dcp0/disp0 */ /delete-node/ &disp0_dart; /delete-node/ &dcp_dart; From 6b781be20e464a1931e0af3b969c1334e7bcd05f Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 27 Apr 2024 12:57:52 +0200 Subject: [PATCH 077/352] arm64: apple: t60x0/t60x1: Enable sio explicitly To be removed after m1n1 does this after proper setup. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 5 +++++ arch/arm64/boot/dts/apple/t600x-j375.dtsi | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 797ac0c75481ae..bc0513787d8e2f 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -109,6 +109,11 @@ apple,dptx-phy = <3>; }; +/* remove once m1n1 enables sio nodes after setup */ +&sio { + status = "okay"; +}; + &dpaudio1 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi index 6336cff863b5eb..ca68974e043468 100644 --- a/arch/arm64/boot/dts/apple/t600x-j375.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi @@ -59,6 +59,11 @@ apple,connector-type = "HDMI-A"; }; +/* remove once m1n1 enables sio nodes after setup */ +&sio { + status = "okay"; +}; + /* USB Type C */ &i2c0 { hpm0: usb-pd@38 { From 35821530f32bbd654018b35959add2f7a778903b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 27 Apr 2024 12:57:52 +0200 Subject: [PATCH 078/352] arm64: apple: t8103-j274: Enable sio explicitly To be removed after m1n1 does this after proper setup. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103-j274.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts index ee38c4832d1dc0..22552bfbdb1950 100644 --- a/arch/arm64/boot/dts/apple/t8103-j274.dts +++ b/arch/arm64/boot/dts/apple/t8103-j274.dts @@ -27,6 +27,11 @@ apple,connector-type = "HDMI-A"; }; +/* remove once m1n1 enables sio nodes after setup */ +&sio { + status = "okay"; +}; + &dpaudio0 { status = "okay"; }; From beff8a9f38e6c339cfdedf182098b9f1478a12c7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 27 Apr 2024 12:57:52 +0200 Subject: [PATCH 079/352] arm64: apple: t8112-j473: Enable sio explicitly To be removed after m1n1 does this after proper setup. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j473.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts index 4df9b82c5d40e4..2cff118565f9e5 100644 --- a/arch/arm64/boot/dts/apple/t8112-j473.dts +++ b/arch/arm64/boot/dts/apple/t8112-j473.dts @@ -66,6 +66,11 @@ apple,dptx-phy = <5>; }; +/* remove once m1n1 enables sio nodes after setup */ +&sio { + status = "okay"; +}; + &dpaudio1 { status = "okay"; }; From e999fb6d5f054bcdf01b48f733a48615b6558455 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 12 Apr 2025 15:25:24 +0200 Subject: [PATCH 080/352] arm64: dts: apple: t6022-j180d: Enable second HDMI port Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6022-j180d.dts | 41 +++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6022-j180d.dts b/arch/arm64/boot/dts/apple/t6022-j180d.dts index e22dd039bbae85..4a528c28031805 100644 --- a/arch/arm64/boot/dts/apple/t6022-j180d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j180d.dts @@ -28,6 +28,7 @@ atcphy6 = &atcphy2_die1; atcphy7 = &atcphy3_die1; bluetooth0 = &bluetooth0; + dcpext0 = &dcpext0; ethernet0 = ðernet0; ethernet1 = ðernet1; serial0 = &serial0; @@ -67,6 +68,46 @@ status = "okay"; }; +&lpdptxphy { + status = "okay"; +}; + +&display { + iommus = <&dispext0_dart_die1 0>, <&dispext0_dart 0>; +}; + +&dispext0_dart { + status = "okay"; +}; + +&dcpext0_dart { + status = "okay"; +}; + +&dcpext0_mbox { + status = "okay"; +}; + +&dcpext0 { + status = "okay"; + apple,connector-type = "HDMI-A"; + + /* HDMI HPD gpio, used as interrupt*/ + hdmi-hpd-gpios = <&pinctrl_aop 25 GPIO_ACTIVE_HIGH>; + + // shared between dp2hdmi-gpio0 / dp2hdmi-gpio1 + // hdmi-pwren-gpios = <&smc_gpio 23 GPIO_ACTIVE_HIGH>; + + phys = <&lpdptxphy>; + phy-names = "dp-phy"; + apple,dptx-phy = <4>; + apple,dptx-die = <0>; +}; + +&dpaudio1 { + status = "okay"; +}; + /* USB Type C Rear */ &i2c0 { hpm2: usb-pd@3b { From 3e9e487669f193917a4d4f6334363bcfad2b5774 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Mon, 1 Jul 2024 10:07:12 +1000 Subject: [PATCH 081/352] arm64: dts: apple: add common hwmon keys and fans Each SoC's SMC exposes a different set of hardware sensor keys, however there are a number that are shared between all currently supported SoCs. Describe these in a .dtsi so that we don't need to duplicate them across every SoC. Likewise, the fans on every machine are exposed as the same set of keys on each. Add .dtsis for these too. Co-developed-by: Janne Grunau Signed-off-by: Janne Grunau Signed-off-by: James Calligeros --- arch/arm64/boot/dts/apple/hwmon-common.dtsi | 43 +++++++++++++++++++ arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi | 26 +++++++++++ arch/arm64/boot/dts/apple/hwmon-fan.dtsi | 21 +++++++++ arch/arm64/boot/dts/apple/hwmon-laptop.dtsi | 41 ++++++++++++++++++ arch/arm64/boot/dts/apple/hwmon-mini.dtsi | 20 +++++++++ 5 files changed, 151 insertions(+) create mode 100644 arch/arm64/boot/dts/apple/hwmon-common.dtsi create mode 100644 arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi create mode 100644 arch/arm64/boot/dts/apple/hwmon-fan.dtsi create mode 100644 arch/arm64/boot/dts/apple/hwmon-laptop.dtsi create mode 100644 arch/arm64/boot/dts/apple/hwmon-mini.dtsi diff --git a/arch/arm64/boot/dts/apple/hwmon-common.dtsi b/arch/arm64/boot/dts/apple/hwmon-common.dtsi new file mode 100644 index 00000000000000..1f9a2435e14cb7 --- /dev/null +++ b/arch/arm64/boot/dts/apple/hwmon-common.dtsi @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * hwmon sensors expected on all systems + * + * Copyright The Asahi Linux Contributors + */ + +&smc { + hwmon { + apple,power-keys { + power-PSTR { + apple,key-id = "PSTR"; + label = "Total System Power"; + }; + power-PDTR { + apple,key-id = "PDTR"; + label = "AC Input Power"; + }; + power-PMVR { + apple,key-id = "PMVR"; + label = "3.8 V Rail Power"; + }; + }; + apple,temp-keys { + temp-TH0x { + apple,key-id = "TH0x"; + label = "NAND Flash Temperature"; + }; + }; + apple,volt-keys { + volt-VD0R { + apple,key-id = "VD0R"; + label = "AC Input Voltage"; + }; + }; + apple,current-keys { + current-ID0R { + apple,key-id = "ID0R"; + label = "AC Input Current"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi b/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi new file mode 100644 index 00000000000000..782b6051a3866e --- /dev/null +++ b/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright The Asahi Linux Contributors + * + * Fan hwmon sensors for machines with 2 fan. + */ + +#include "hwmon-fan.dtsi" + +&smc { + hwmon { + apple,fan-keys { + fan-F0Ac { + label = "Fan 1"; + }; + fan-F1Ac { + apple,key-id = "F1Ac"; + label = "Fan 2"; + apple,fan-minimum = "F1Mn"; + apple,fan-maximum = "F1Mx"; + apple,fan-target = "F1Tg"; + apple,fan-mode = "F1Md"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/hwmon-fan.dtsi b/arch/arm64/boot/dts/apple/hwmon-fan.dtsi new file mode 100644 index 00000000000000..8f329ac4ff9fef --- /dev/null +++ b/arch/arm64/boot/dts/apple/hwmon-fan.dtsi @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright The Asahi Linux Contributors + * + * Fan hwmon sensors for machines with a single fan. + */ + +&smc { + hwmon { + apple,fan-keys { + fan-F0Ac { + apple,key-id = "F0Ac"; + label = "Fan"; + apple,fan-minimum = "F0Mn"; + apple,fan-maximum = "F0Mx"; + apple,fan-target = "F0Tg"; + apple,fan-mode = "F0Md"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi b/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi new file mode 100644 index 00000000000000..2583ef379dfac9 --- /dev/null +++ b/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * hwmon sensors expected on all laptops + * + * Copyright The Asahi Linux Contributors + */ + +&smc { + hwmon { + apple,power-keys { + power-PHPC { + apple,key-id = "PHPC"; + label = "Heatpipe Power"; + }; + }; + apple,temp-keys { + temp-TB0T { + apple,key-id = "TB0T"; + label = "Battery Hotspot"; + }; + temp-TCHP { + apple,key-id = "TCHP"; + label = "Charge Regulator Temp"; + }; + temp-TW0P { + apple,key-id = "TW0P"; + label = "WiFi/BT Module Temp"; + }; + }; + apple,volt-keys { + volt-SBAV { + apple,key-id = "SBAV"; + label = "Battery Voltage"; + }; + volt-VD0R { + apple,key-id = "VD0R"; + label = "Charger Input Voltage"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/hwmon-mini.dtsi b/arch/arm64/boot/dts/apple/hwmon-mini.dtsi new file mode 100644 index 00000000000000..bd0c22786d4226 --- /dev/null +++ b/arch/arm64/boot/dts/apple/hwmon-mini.dtsi @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * hwmon sensors common to the Mac mini desktop + * models, but not the Studio or Pro. + * + * Copyright The Asahi Linux Contributors + */ + +#include "hwmon-fan.dtsi" + +&smc { + hwmon { + apple,temp-keys { + temp-TW0P { + apple,key-id = "TW0P"; + label = "WiFi/BT Module Temp"; + }; + }; + }; +}; From 71044113888ae35912847e116aa3e5064133ddef Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 11 Jul 2024 21:29:10 +0200 Subject: [PATCH 082/352] arm64: dts: apple: t8103: Add SMC hwmon sensors Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103-j274.dts | 2 ++ arch/arm64/boot/dts/apple/t8103-j293.dts | 3 +++ arch/arm64/boot/dts/apple/t8103-j313.dts | 2 ++ arch/arm64/boot/dts/apple/t8103-j456.dts | 2 ++ arch/arm64/boot/dts/apple/t8103-j457.dts | 2 ++ arch/arm64/boot/dts/apple/t8103-jxxx.dtsi | 2 ++ 6 files changed, 13 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts index 22552bfbdb1950..f55683c48784b8 100644 --- a/arch/arm64/boot/dts/apple/t8103-j274.dts +++ b/arch/arm64/boot/dts/apple/t8103-j274.dts @@ -145,3 +145,5 @@ &gpu { apple,perf-base-pstate = <3>; }; + +#include "hwmon-mini.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts index a113b9a57e1a6e..e26329ee7d019d 100644 --- a/arch/arm64/boot/dts/apple/t8103-j293.dts +++ b/arch/arm64/boot/dts/apple/t8103-j293.dts @@ -279,3 +279,6 @@ &isp { apple,platform-id = <1>; }; + +#include "hwmon-fan.dtsi" +#include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts index 52940e43db9155..92e82b8247b021 100644 --- a/arch/arm64/boot/dts/apple/t8103-j313.dts +++ b/arch/arm64/boot/dts/apple/t8103-j313.dts @@ -174,3 +174,5 @@ &isp { apple,platform-id = <1>; }; + +#include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts index a3638871f3660e..2fdbc4061d6048 100644 --- a/arch/arm64/boot/dts/apple/t8103-j456.dts +++ b/arch/arm64/boot/dts/apple/t8103-j456.dts @@ -143,3 +143,5 @@ &isp { apple,platform-id = <2>; }; + +#include "hwmon-fan-dual.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts index 4c1adb310ba91f..80067e95db1d82 100644 --- a/arch/arm64/boot/dts/apple/t8103-j457.dts +++ b/arch/arm64/boot/dts/apple/t8103-j457.dts @@ -124,3 +124,5 @@ &isp { apple,platform-id = <2>; }; + +#include "hwmon-fan.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi index 7ca9da15c8171d..67a57fc507df92 100644 --- a/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi +++ b/arch/arm64/boot/dts/apple/t8103-jxxx.dtsi @@ -237,4 +237,6 @@ clock-frequency = <900000000>; }; +#include "hwmon-common.dtsi" + #include "spi1-nvram.dtsi" From ff7c5fbb095b0892dd614ddd2b23ebfa83880212 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 11 Jul 2024 21:31:30 +0200 Subject: [PATCH 083/352] arm64: dts: apple: t8112: Add SMC hwmon sensors Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j413.dts | 2 ++ arch/arm64/boot/dts/apple/t8112-j415.dts | 2 ++ arch/arm64/boot/dts/apple/t8112-j473.dts | 2 ++ arch/arm64/boot/dts/apple/t8112-j493.dts | 3 +++ arch/arm64/boot/dts/apple/t8112-jxxx.dtsi | 2 ++ 5 files changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts index 5c0cb7fc235ad5..43977e7c9491e7 100644 --- a/arch/arm64/boot/dts/apple/t8112-j413.dts +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts @@ -250,3 +250,5 @@ apple,platform-id = <14>; apple,temporal-filter = <1>; }; + +#include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts index 7e39a477728e3f..da41960b2c455a 100644 --- a/arch/arm64/boot/dts/apple/t8112-j415.dts +++ b/arch/arm64/boot/dts/apple/t8112-j415.dts @@ -276,3 +276,5 @@ apple,platform-id = <15>; apple,temporal-filter = <1>; }; + +#include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts index 2cff118565f9e5..4fc96779806ea3 100644 --- a/arch/arm64/boot/dts/apple/t8112-j473.dts +++ b/arch/arm64/boot/dts/apple/t8112-j473.dts @@ -213,3 +213,5 @@ &gpu { apple,perf-base-pstate = <3>; }; + +#include "hwmon-mini.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts index b6c60ec51b4a1a..7ff910ef8925ab 100644 --- a/arch/arm64/boot/dts/apple/t8112-j493.dts +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts @@ -303,3 +303,6 @@ &isp { apple,platform-id = <6>; }; + +#include "hwmon-fan.dtsi" +#include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi index 35565dbf535381..fb957f785d82c5 100644 --- a/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi +++ b/arch/arm64/boot/dts/apple/t8112-jxxx.dtsi @@ -218,4 +218,6 @@ clock-frequency = <900000000>; }; +#include "hwmon-common.dtsi" + #include "spi1-nvram.dtsi" From 819919cf79c3a55bb022c2df1edc797de7699229 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 11 Jul 2024 21:34:02 +0200 Subject: [PATCH 084/352] arm64: dts: apple: t600x-j3xx: Add SMC hwmon sensors Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6001-j375c.dts | 2 ++ arch/arm64/boot/dts/apple/t6002-j375d.dts | 2 ++ arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 4 ++++ arch/arm64/boot/dts/apple/t600x-j375.dtsi | 2 ++ 4 files changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts index 4028571143ac87..f3f98f03800908 100644 --- a/arch/arm64/boot/dts/apple/t6001-j375c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts @@ -58,3 +58,5 @@ apple,ppm-ki = <5.8>; apple,ppm-kp = <0.355>; }; + +#include "hwmon-fan-dual.dtsi" diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts index e17c71ff18913c..5cf30cd162b679 100644 --- a/arch/arm64/boot/dts/apple/t6002-j375d.dts +++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts @@ -226,3 +226,5 @@ apple,ppm-ki = <5.8>; apple,ppm-kp = <0.355>; }; + +#include "hwmon-fan-dual.dtsi" diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index bc0513787d8e2f..886085d3362c94 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -597,3 +597,7 @@ &isp { apple,platform-id = <3>; }; + +#include "hwmon-common.dtsi" +#include "hwmon-fan-dual.dtsi" +#include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi index ca68974e043468..ce339c0855bc98 100644 --- a/arch/arm64/boot/dts/apple/t600x-j375.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi @@ -486,3 +486,5 @@ }; #include "spi1-nvram.dtsi" + +#include "hwmon-common.dtsi" From 98125a9da2718fc41db88e685405e0f8bfb9a8b7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 11 Jul 2024 21:36:29 +0200 Subject: [PATCH 085/352] arm64: dts: apple: t602x-j4xx: Add SMC hwmon sensors Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t6020-j474s.dts | 2 ++ arch/arm64/boot/dts/apple/t6021-j475c.dts | 2 ++ arch/arm64/boot/dts/apple/t6022-j475d.dts | 2 ++ 3 files changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6020-j474s.dts b/arch/arm64/boot/dts/apple/t6020-j474s.dts index f904582f98bb91..12dfe9693502ad 100644 --- a/arch/arm64/boot/dts/apple/t6020-j474s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j474s.dts @@ -124,3 +124,5 @@ /* Apple does not do this, but they probably should */ apple,perf-base-pstate = <3>; }; + +#include "hwmon-mini.dtsi" diff --git a/arch/arm64/boot/dts/apple/t6021-j475c.dts b/arch/arm64/boot/dts/apple/t6021-j475c.dts index 09f477dbdf28b1..e4321cfc556838 100644 --- a/arch/arm64/boot/dts/apple/t6021-j475c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j475c.dts @@ -123,3 +123,5 @@ apple,perf-boost-min-util = <75>; apple,perf-tgt-utilization = <70>; }; + +#include "hwmon-fan-dual.dtsi" diff --git a/arch/arm64/boot/dts/apple/t6022-j475d.dts b/arch/arm64/boot/dts/apple/t6022-j475d.dts index a9020a23a7e976..cdfc78a1703c7a 100644 --- a/arch/arm64/boot/dts/apple/t6022-j475d.dts +++ b/arch/arm64/boot/dts/apple/t6022-j475d.dts @@ -92,3 +92,5 @@ compatible = "apple,j475-macaudio", "apple,j375-macaudio", "apple,macaudio"; model = "Mac Studio J475"; }; + +#include "hwmon-fan-dual.dtsi" From 8a862321d7805bad65fa3a4f977b815618b54942 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Sat, 9 Nov 2024 18:44:45 +0100 Subject: [PATCH 086/352] arm64: dts: apple: Add AOP and subdevices Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 62 ++++++++++++++++++++++ arch/arm64/boot/dts/apple/t602x-die0.dtsi | 63 +++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8103.dtsi | 62 ++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8112.dtsi | 62 ++++++++++++++++++++++ 4 files changed, 249 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index ff106e95b66ef6..028fc623594630 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -167,6 +167,68 @@ interrupts = ; }; + aop_mbox: mbox@293408000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x93408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@293808000 { + compatible = "apple,t6000-dart"; + reg = <0x2 0x93808000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + aop_admac: dma-controller@293980000 { + compatible = "apple,t6000-admac", "apple,admac"; + reg = <0x2 0x93980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 0 600 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 7>; + status = "disabled"; + }; + + aop: aop@293c00000 { + compatible = "apple,t6000-aop"; + reg = <0x2 0x93c00000 0x0 0x250000>, + <0x2 0x93400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t6000-aop-audio", "apple,aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t6000-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t6000-aop-las", "apple,aop-las"; + }; + }; + disp0_dart: iommu@38b304000 { compatible = "apple,t6000-dart"; reg = <0x3 0x8b304000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 4af8d727e61b24..07fb867a0cfdcb 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -165,6 +165,69 @@ ; }; + aop_mbox: mbox@2a6408000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0xa6408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@2a6808000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x2 0xa6808000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + // apple,dma-range = <0x100 0x0 0x300 0x0>; + }; + + aop_admac: dma-controller@2a6980000 { + compatible = "apple,t6020-admac", "apple,admac"; + reg = <0x2 0xa6980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 0 631 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 10>; + status = "disabled"; + }; + + aop: aop@2a6c00000 { + compatible = "apple,t6020-aop"; + reg = <0x2 0xa6c00000 0x0 0x250000>, + <0x2 0xa6400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t6020-aop-audio", "apple,aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t6020-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t6020-aop-las", "apple,aop-las"; + }; + }; + mtp: mtp@2a9400000 { compatible = "apple,t6020-mtp", "apple,t6020-rtk-helper-asc4", "apple,mtp", "apple,rtk-helper-asc4"; reg = <0x2 0xa9400000 0x0 0x4000>, diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index e1c18406147d43..ff99c0377e663a 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -1310,6 +1310,68 @@ ; }; + aop_mbox: mbox@24a408000 { + compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x4a408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@24a808000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x4a808000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + aop_admac: dma-controller@24a980000 { + compatible = "apple,t8103-admac", "apple,admac"; + reg = <0x2 0x4a980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 321 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 7>; + status = "disabled"; + }; + + aop: aop@24ac00000 { + compatible = "apple,t8103-aop"; + reg = <0x2 0x4ac00000 0x0 0x1e0000>, + <0x2 0x4a400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t8103-aop-audio", "apple,aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t8103-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t8103-aop-las", "apple,aop-las"; + }; + }; + dispext0_dart: iommu@271304000 { compatible = "apple,t8103-dart"; reg = <0x2 0x71304000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 94c5dbdbafb49c..8f117c8c49443b 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1326,6 +1326,68 @@ ; }; + aop_mbox: mbox@24a408000 { + compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x4a408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@24a808000 { + compatible = "apple,t8112-dart", "apple,t8110-dart"; + reg = <0x2 0x4a808000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + aop_admac: dma-controller@24a980000 { + compatible = "apple,t8112-admac", "apple,admac"; + reg = <0x2 0x4a980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 359 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 10>; + status = "disabled"; + }; + + aop: aop@24ac00000 { + compatible = "apple,t8112-aop"; + reg = <0x2 0x4ac00000 0x0 0x1e0000>, + <0x2 0x4a400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t8112-aop-audio", "apple,aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t8112-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t8112-aop-las", "apple,aop-las"; + }; + }; + mtp: mtp@24e400000 { compatible = "apple,t8112-mtp", "apple,t8112-rtk-helper-asc4", "apple,mtp", "apple,rtk-helper-asc4"; reg = <0x2 0x4e400000 0x0 0x4000>, From abaf2264053b702b92316a413e09fccb1675dcdb Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Sun, 10 Nov 2024 23:25:31 +0100 Subject: [PATCH 087/352] arm64: dts: apple: Add SEP device tree nodes Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 31 ++++++++++++++++++++++ arch/arm64/boot/dts/apple/t602x-die0.dtsi | 32 +++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8103.dtsi | 30 +++++++++++++++++++++ arch/arm64/boot/dts/apple/t8112.dtsi | 30 +++++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 028fc623594630..30f5e030154542 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -250,6 +250,37 @@ apple,dma-range = <0x1f0 0x0 0x0 0xfc000000>; }; + sep_dart: iommu@3952c0000 { + compatible = "apple,t6000-dart"; + reg = <0x3 0x952c0000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + sep: sep@396400000 { + compatible = "apple,sep"; + reg = <0x3 0x96400000 0x0 0x6C000>; + mboxes = <&sep_mbox>; + mbox-names = "mbox"; + iommus = <&sep_dart 0>; + power-domains = <&ps_sep>; + status = "disabled"; + }; + + sep_mbox: mbox@396408000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x96408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + }; + dpaudio0: audio-controller@39b500000 { compatible = "apple,t6000-dpaudio", "apple,dpaudio"; reg = <0x3 0x9b500000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 07fb867a0cfdcb..d08bf18311f78d 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -438,6 +438,38 @@ phandle = <&display>; }; + sep_dart: iommu@394ac0000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x3 0x94ac0000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + sep: sep@396400000 { + compatible = "apple,sep"; + reg = <0x3 0x96400000 0x0 0x6C000>; + mboxes = <&sep_mbox>; + mbox-names = "mbox"; + iommus = <&sep_dart 0>; + power-domains = <&ps_sep>; + status = "disabled"; + }; + + sep_mbox: mbox@396408000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x96408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + }; + fpwm0: pwm@39b030000 { compatible = "apple,t6020-fpwm", "apple,s5l-fpwm"; reg = <0x3 0x9b030000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index ff99c0377e663a..28a3b91756bc7a 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -1289,6 +1289,36 @@ ; }; + sep_dart: iommu@2412c0000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x412c0000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + sep: sep@242400000 { + compatible = "apple,sep"; + reg = <0x2 0x42400000 0x0 0x6C000>; + mboxes = <&sep_mbox>; + mbox-names = "mbox"; + iommus = <&sep_dart 0>; + status = "disabled"; + }; + + sep_mbox: mbox@242408000 { + compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x42408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + }; + pinctrl_aop: pinctrl@24a820000 { compatible = "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x2 0x4a820000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 8f117c8c49443b..611fc7c2c6e8e1 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1462,6 +1462,36 @@ }; + sep_dart: iommu@25d2c0000 { + compatible = "apple,t8112-dart", "apple,t8110-dart"; + reg = <0x2 0x5d2c0000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + sep: sep@25e400000 { + compatible = "apple,sep"; + reg = <0x2 0x5e400000 0x0 0x6C000>; + mboxes = <&sep_mbox>; + mbox-names = "mbox"; + iommus = <&sep_dart 0>; + status = "disabled"; + }; + + sep_mbox: mbox@25e408000 { + compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x5e408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + }; + dispext0_dart: iommu@271304000 { compatible = "apple,t8112-dart", "apple,t8110-dart"; reg = <0x2 0x71304000 0x0 0x4000>; From 241b0dd05e0f98b61ee850b8751f43d640a3bbd2 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Sat, 9 Nov 2024 18:44:45 +0100 Subject: [PATCH 088/352] arm64: dts: apple: Add AOP audio identifiers Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t6000-j314s.dts | 5 +++++ arch/arm64/boot/dts/apple/t6000-j316s.dts | 5 +++++ arch/arm64/boot/dts/apple/t6001-j314c.dts | 5 +++++ arch/arm64/boot/dts/apple/t6001-j316c.dts | 5 +++++ arch/arm64/boot/dts/apple/t6020-j414s.dts | 5 +++++ arch/arm64/boot/dts/apple/t6020-j416s.dts | 5 +++++ arch/arm64/boot/dts/apple/t6021-j414c.dts | 5 +++++ arch/arm64/boot/dts/apple/t6021-j416c.dts | 5 +++++ arch/arm64/boot/dts/apple/t8103-j293.dts | 5 +++++ arch/arm64/boot/dts/apple/t8103-j313.dts | 5 +++++ arch/arm64/boot/dts/apple/t8103-j456.dts | 5 +++++ arch/arm64/boot/dts/apple/t8103-j457.dts | 5 +++++ arch/arm64/boot/dts/apple/t8112-j413.dts | 5 +++++ arch/arm64/boot/dts/apple/t8112-j415.dts | 5 +++++ arch/arm64/boot/dts/apple/t8112-j493.dts | 5 +++++ 15 files changed, 75 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6000-j314s.dts b/arch/arm64/boot/dts/apple/t6000-j314s.dts index ae79e3236614be..afa86668440f04 100644 --- a/arch/arm64/boot/dts/apple/t6000-j314s.dts +++ b/arch/arm64/boot/dts/apple/t6000-j314s.dts @@ -32,6 +32,11 @@ adj-height-mm = <189>; }; +&aop_audio { + apple,chassis-name = "J314"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J314"; diff --git a/arch/arm64/boot/dts/apple/t6000-j316s.dts b/arch/arm64/boot/dts/apple/t6000-j316s.dts index 272fa1c1712479..ddfc3c530923c7 100644 --- a/arch/arm64/boot/dts/apple/t6000-j316s.dts +++ b/arch/arm64/boot/dts/apple/t6000-j316s.dts @@ -32,6 +32,11 @@ adj-height-mm = <216>; }; +&aop_audio { + apple,chassis-name = "J316"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J316"; diff --git a/arch/arm64/boot/dts/apple/t6001-j314c.dts b/arch/arm64/boot/dts/apple/t6001-j314c.dts index 81d34507ed81ff..245df6d03ee422 100644 --- a/arch/arm64/boot/dts/apple/t6001-j314c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j314c.dts @@ -32,6 +32,11 @@ adj-height-mm = <189>; }; +&aop_audio { + apple,chassis-name = "J314"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J314"; diff --git a/arch/arm64/boot/dts/apple/t6001-j316c.dts b/arch/arm64/boot/dts/apple/t6001-j316c.dts index 564d927f2fecbd..a000d497b705fa 100644 --- a/arch/arm64/boot/dts/apple/t6001-j316c.dts +++ b/arch/arm64/boot/dts/apple/t6001-j316c.dts @@ -32,6 +32,11 @@ adj-height-mm = <216>; }; +&aop_audio { + apple,chassis-name = "J316"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J316"; diff --git a/arch/arm64/boot/dts/apple/t6020-j414s.dts b/arch/arm64/boot/dts/apple/t6020-j414s.dts index 5dd97df71efc4b..a227069727dd8f 100644 --- a/arch/arm64/boot/dts/apple/t6020-j414s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j414s.dts @@ -32,6 +32,11 @@ adj-height-mm = <189>; }; +&aop_audio { + apple,chassis-name = "J414"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j414-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J414"; diff --git a/arch/arm64/boot/dts/apple/t6020-j416s.dts b/arch/arm64/boot/dts/apple/t6020-j416s.dts index 56ddf7c61de634..3ea2b1d52593e2 100644 --- a/arch/arm64/boot/dts/apple/t6020-j416s.dts +++ b/arch/arm64/boot/dts/apple/t6020-j416s.dts @@ -32,6 +32,11 @@ adj-height-mm = <216>; }; +&aop_audio { + apple,chassis-name = "J416"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J416"; diff --git a/arch/arm64/boot/dts/apple/t6021-j414c.dts b/arch/arm64/boot/dts/apple/t6021-j414c.dts index 6905c7d39db0ce..fab3b03ff3c452 100644 --- a/arch/arm64/boot/dts/apple/t6021-j414c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j414c.dts @@ -32,6 +32,11 @@ adj-height-mm = <189>; }; +&aop_audio { + apple,chassis-name = "J414"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j414-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J414"; diff --git a/arch/arm64/boot/dts/apple/t6021-j416c.dts b/arch/arm64/boot/dts/apple/t6021-j416c.dts index 786ac2393d7535..b476e235639ffc 100644 --- a/arch/arm64/boot/dts/apple/t6021-j416c.dts +++ b/arch/arm64/boot/dts/apple/t6021-j416c.dts @@ -52,6 +52,11 @@ adj-height-mm = <216>; }; +&aop_audio { + apple,chassis-name = "J416"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J416"; diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts index e26329ee7d019d..82773f2468a37f 100644 --- a/arch/arm64/boot/dts/apple/t8103-j293.dts +++ b/arch/arm64/boot/dts/apple/t8103-j293.dts @@ -244,6 +244,11 @@ status = "okay"; }; +&aop_audio { + apple,chassis-name = "J293"; + apple,machine-kind = "MacBook Pro"; +}; + / { sound { compatible = "apple,j293-macaudio", "apple,macaudio"; diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts index 92e82b8247b021..376f111b34ef22 100644 --- a/arch/arm64/boot/dts/apple/t8103-j313.dts +++ b/arch/arm64/boot/dts/apple/t8103-j313.dts @@ -140,6 +140,11 @@ }; }; +&aop_audio { + apple,chassis-name = "J313"; + apple,machine-kind = "MacBook Air"; +}; + / { sound { compatible = "apple,j313-macaudio", "apple,macaudio"; diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts index 2fdbc4061d6048..155b4c94636857 100644 --- a/arch/arm64/boot/dts/apple/t8103-j456.dts +++ b/arch/arm64/boot/dts/apple/t8103-j456.dts @@ -116,6 +116,11 @@ }; }; +&aop_audio { + apple,chassis-name = "J456"; + apple,machine-kind = "iMac"; +}; + / { sound { compatible = "apple,j456-macaudio", "apple,macaudio"; diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts index 80067e95db1d82..7bec55944f6a5d 100644 --- a/arch/arm64/boot/dts/apple/t8103-j457.dts +++ b/arch/arm64/boot/dts/apple/t8103-j457.dts @@ -97,6 +97,11 @@ }; }; +&aop_audio { + apple,chassis-name = "J457"; + apple,machine-kind = "iMac"; +}; + / { sound { compatible = "apple,j457-macaudio", "apple,macaudio"; diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts index 43977e7c9491e7..e298a3d90a2c4f 100644 --- a/arch/arm64/boot/dts/apple/t8112-j413.dts +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts @@ -179,6 +179,11 @@ status = "okay"; }; +&aop_audio { + apple,chassis-name = "J413"; + apple,machine-kind = "MacBook Air"; +}; + / { sound { compatible = "apple,j413-macaudio", "apple,macaudio"; diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts index da41960b2c455a..a789f6bc736173 100644 --- a/arch/arm64/boot/dts/apple/t8112-j415.dts +++ b/arch/arm64/boot/dts/apple/t8112-j415.dts @@ -201,6 +201,11 @@ status = "okay"; }; +&aop_audio { + apple,chassis-name = "J415"; + apple,machine-kind = "MacBook Air"; +}; + / { sound { compatible = "apple,j415-macaudio", "apple,macaudio"; diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts index 7ff910ef8925ab..c7e10df168e832 100644 --- a/arch/arm64/boot/dts/apple/t8112-j493.dts +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts @@ -233,6 +233,11 @@ }; }; +&aop_audio { + apple,chassis-name = "J493"; + apple,machine-kind = "MacBook Pro"; +}; + / { sound { compatible = "apple,j493-macaudio", "apple,macaudio"; From 294ca987d3b3413d6a5e3a6b135d922aaaca3a23 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Dec 2024 14:55:05 +0100 Subject: [PATCH 089/352] arm64: dts: apple: t600x-j314-j316: Enable AOP Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 886085d3362c94..7e1d4b407ebaa3 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -557,6 +557,22 @@ status = "disabled"; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + / { sound: sound { /* compatible is set per machine */ From a82990657bb24dcbebaa699bbbf22586460309ba Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Dec 2024 15:08:45 +0100 Subject: [PATCH 090/352] arm64: dts: apple: t8103-j293: Enable AOP Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103-j293.dts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts index 82773f2468a37f..6fa04626b1d08b 100644 --- a/arch/arm64/boot/dts/apple/t8103-j293.dts +++ b/arch/arm64/boot/dts/apple/t8103-j293.dts @@ -24,6 +24,7 @@ */ aliases { touchbar0 = &touchbar0; + sep = &sep; }; led-controller { @@ -244,6 +245,26 @@ status = "okay"; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&sep { + status = "okay"; +}; + &aop_audio { apple,chassis-name = "J293"; apple,machine-kind = "MacBook Pro"; From 247f8cc95e854e0f50f0d6eee429b1566d8e36ce Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Dec 2024 15:09:31 +0100 Subject: [PATCH 091/352] arm64: dts: apple: t8103-j313: Enable AOP Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103-j313.dts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts index 376f111b34ef22..883ba4a1f0100a 100644 --- a/arch/arm64/boot/dts/apple/t8103-j313.dts +++ b/arch/arm64/boot/dts/apple/t8103-j313.dts @@ -18,6 +18,10 @@ model = "Apple MacBook Air (M1, 2020)"; chassis-type = "laptop"; + aliases { + sep = &sep; + }; + led-controller { compatible = "pwm-leds"; led-0 { @@ -140,6 +144,26 @@ }; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&sep { + status = "okay"; +}; + &aop_audio { apple,chassis-name = "J313"; apple,machine-kind = "MacBook Air"; From 52546b11743a81d32617886fdc4f76696906efde Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Dec 2024 15:19:31 +0100 Subject: [PATCH 092/352] arm64: dts: apple: t8103-j45x: Enable AOP Probing is blocked by the "apple,no-beamforming" property until userspace is ready. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103-j456.dts | 21 +++++++++++++++++++++ arch/arm64/boot/dts/apple/t8103-j457.dts | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts index 155b4c94636857..c7da4815fb94c0 100644 --- a/arch/arm64/boot/dts/apple/t8103-j456.dts +++ b/arch/arm64/boot/dts/apple/t8103-j456.dts @@ -116,9 +116,30 @@ }; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&sep { + status = "okay"; +}; + &aop_audio { apple,chassis-name = "J456"; apple,machine-kind = "iMac"; + apple,no-beamforming; }; / { diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts index 7bec55944f6a5d..fc0f28fb1c4367 100644 --- a/arch/arm64/boot/dts/apple/t8103-j457.dts +++ b/arch/arm64/boot/dts/apple/t8103-j457.dts @@ -97,9 +97,30 @@ }; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&sep { + status = "okay"; +}; + &aop_audio { apple,chassis-name = "J457"; apple,machine-kind = "iMac"; + apple,no-beamforming; }; / { From b639d73a24ce5def689458d9ec9407172697adf0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Dec 2024 15:10:42 +0100 Subject: [PATCH 093/352] arm64: dts: apple: t8112-j413: Enable AOP Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j413.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts index e298a3d90a2c4f..20285be747d965 100644 --- a/arch/arm64/boot/dts/apple/t8112-j413.dts +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts @@ -179,6 +179,22 @@ status = "okay"; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + &aop_audio { apple,chassis-name = "J413"; apple,machine-kind = "MacBook Air"; From e8a329e96660dcd9f56ae9c9b4c69615be8c6141 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Dec 2024 15:11:36 +0100 Subject: [PATCH 094/352] arm64: dts: apple: t8112-j415: Enable AOP Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j415.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts index a789f6bc736173..c2c32ca5577eff 100644 --- a/arch/arm64/boot/dts/apple/t8112-j415.dts +++ b/arch/arm64/boot/dts/apple/t8112-j415.dts @@ -201,6 +201,22 @@ status = "okay"; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + &aop_audio { apple,chassis-name = "J415"; apple,machine-kind = "MacBook Air"; From fc09f3076c5f17de90d65a9c38fa006475600120 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Dec 2024 15:12:15 +0100 Subject: [PATCH 095/352] arm64: dts: apple: t8112-j493: Enable AOP Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112-j493.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts index c7e10df168e832..368c4a9cc01758 100644 --- a/arch/arm64/boot/dts/apple/t8112-j493.dts +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts @@ -233,6 +233,22 @@ }; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + &aop_audio { apple,chassis-name = "J493"; apple,machine-kind = "MacBook Pro"; From b64633359fcddcf51b6e8120c0df687b43a39864 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 6 Sep 2025 11:23:03 +0200 Subject: [PATCH 096/352] arm64: dts: apple: t600x: Add "pm_setting" for smc_reboot For backawrds compatibility with the downstream driver. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 30f5e030154542..92b80e8428f92b 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -56,9 +56,9 @@ smc_reboot: reboot { compatible = "apple,smc-reboot"; nvmem-cells = <&shutdown_flag>, <&boot_stage>, - <&boot_error_count>, <&panic_count>; + <&boot_error_count>, <&panic_count>, <&pm_setting>; nvmem-cell-names = "shutdown_flag", "boot_stage", - "boot_error_count", "panic_count"; + "boot_error_count", "panic_count", "pm_setting"; }; rtc { From b085a8ea1f2998239f4b4017293818a651d14f70 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 6 Sep 2025 11:23:03 +0200 Subject: [PATCH 097/352] arm64: dts: apple: t8103: Add "pm_setting" for smc_reboot For backawrds compatibility with the downstream driver. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 28a3b91756bc7a..088df6c8d0eb23 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -1243,9 +1243,9 @@ smc_reboot: reboot { compatible = "apple,smc-reboot"; nvmem-cells = <&shutdown_flag>, <&boot_stage>, - <&boot_error_count>, <&panic_count>; + <&boot_error_count>, <&panic_count>, <&pm_setting>; nvmem-cell-names = "shutdown_flag", "boot_stage", - "boot_error_count", "panic_count"; + "boot_error_count", "panic_count", "pm_setting"; }; rtc { From 01fe93c8bdc0ffa7eea9f42c9cdaa753b2f7517d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 6 Sep 2025 11:23:04 +0200 Subject: [PATCH 098/352] arm64: dts: apple: t8112: Add "pm_setting" for smc_reboot For backawrds compatibility with the downstream driver. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 611fc7c2c6e8e1..ac65696aa9eb72 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1259,9 +1259,9 @@ smc_reboot: reboot { compatible = "apple,smc-reboot"; nvmem-cells = <&shutdown_flag>, <&boot_stage>, - <&boot_error_count>, <&panic_count>; + <&boot_error_count>, <&panic_count>, <&pm_setting>; nvmem-cell-names = "shutdown_flag", "boot_stage", - "boot_error_count", "panic_count"; + "boot_error_count", "panic_count", "pm_setting"; }; rtc { From 367ee693a42a36eebe5a9ce5ecf77354b171f455 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 26 Sep 2025 10:24:04 +0200 Subject: [PATCH 099/352] arm64: dts: apple: Add SMC hwmon node for t600x,t602x,t8103,t8112 Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 4 ++++ arch/arm64/boot/dts/apple/t602x-die0.dtsi | 4 ++++ arch/arm64/boot/dts/apple/t8103.dtsi | 4 ++++ arch/arm64/boot/dts/apple/t8112.dtsi | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 92b80e8428f92b..f00550a680e131 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -53,6 +53,10 @@ #gpio-cells = <2>; }; + smc_hwmon: hwmon { + compatible = "apple,smc-hwmon"; + }; + smc_reboot: reboot { compatible = "apple,smc-reboot"; nvmem-cells = <&shutdown_flag>, <&boot_stage>, diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index d08bf18311f78d..6803254a38af5e 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -129,6 +129,10 @@ #gpio-cells = <2>; }; + smc_hwmon: hwmon { + compatible = "apple,smc-hwmon"; + }; + smc_reboot: reboot { compatible = "apple,smc-reboot"; nvmem-cells = <&shutdown_flag>, <&boot_stage>, diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 088df6c8d0eb23..3e510b4a692236 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -1240,6 +1240,10 @@ #gpio-cells = <2>; }; + smc_hwmon: hwmon { + compatible = "apple,smc-hwmon"; + }; + smc_reboot: reboot { compatible = "apple,smc-reboot"; nvmem-cells = <&shutdown_flag>, <&boot_stage>, diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index ac65696aa9eb72..9e7777bf477f04 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1256,6 +1256,10 @@ #gpio-cells = <2>; }; + smc_hwmon: hwmon { + compatible = "apple,smc-hwmon"; + }; + smc_reboot: reboot { compatible = "apple,smc-reboot"; nvmem-cells = <&shutdown_flag>, <&boot_stage>, From 52a329f965f827cfe1889eb9be7ac3d8faa2857c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 26 Sep 2025 10:25:37 +0200 Subject: [PATCH 100/352] arm64: dts: apple: Adjust all hwmon sensors for upstream driver Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/hwmon-common.dtsi | 58 ++++++++----------- arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi | 26 ++++----- arch/arm64/boot/dts/apple/hwmon-fan.dtsi | 20 +++---- arch/arm64/boot/dts/apple/hwmon-laptop.dtsi | 56 ++++++++---------- arch/arm64/boot/dts/apple/hwmon-mini.dtsi | 12 ++-- 5 files changed, 71 insertions(+), 101 deletions(-) diff --git a/arch/arm64/boot/dts/apple/hwmon-common.dtsi b/arch/arm64/boot/dts/apple/hwmon-common.dtsi index 1f9a2435e14cb7..2a74d9a114abb6 100644 --- a/arch/arm64/boot/dts/apple/hwmon-common.dtsi +++ b/arch/arm64/boot/dts/apple/hwmon-common.dtsi @@ -5,39 +5,29 @@ * Copyright The Asahi Linux Contributors */ -&smc { - hwmon { - apple,power-keys { - power-PSTR { - apple,key-id = "PSTR"; - label = "Total System Power"; - }; - power-PDTR { - apple,key-id = "PDTR"; - label = "AC Input Power"; - }; - power-PMVR { - apple,key-id = "PMVR"; - label = "3.8 V Rail Power"; - }; - }; - apple,temp-keys { - temp-TH0x { - apple,key-id = "TH0x"; - label = "NAND Flash Temperature"; - }; - }; - apple,volt-keys { - volt-VD0R { - apple,key-id = "VD0R"; - label = "AC Input Voltage"; - }; - }; - apple,current-keys { - current-ID0R { - apple,key-id = "ID0R"; - label = "AC Input Current"; - }; - }; +&smc_hwmon { + power-PSTR { + apple,key-id = "PSTR"; + label = "Total System Power"; + }; + power-PDTR { + apple,key-id = "PDTR"; + label = "AC Input Power"; + }; + power-PMVR { + apple,key-id = "PMVR"; + label = "3.8 V Rail Power"; + }; + temperature-TH0x { + apple,key-id = "TH0x"; + label = "NAND Flash Temperature"; + }; + voltage-VD0R { + apple,key-id = "VD0R"; + label = "AC Input Voltage"; + }; + current-ID0R { + apple,key-id = "ID0R"; + label = "AC Input Current"; }; }; diff --git a/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi b/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi index 782b6051a3866e..61c34692f1cd5a 100644 --- a/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi +++ b/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi @@ -7,20 +7,16 @@ #include "hwmon-fan.dtsi" -&smc { - hwmon { - apple,fan-keys { - fan-F0Ac { - label = "Fan 1"; - }; - fan-F1Ac { - apple,key-id = "F1Ac"; - label = "Fan 2"; - apple,fan-minimum = "F1Mn"; - apple,fan-maximum = "F1Mx"; - apple,fan-target = "F1Tg"; - apple,fan-mode = "F1Md"; - }; - }; +&smc_hwmon { + fan-F0Ac { + label = "Fan 1"; + }; + fan-F1Ac { + apple,key-id = "F1Ac"; + label = "Fan 2"; + apple,fan-minimum = "F1Mn"; + apple,fan-maximum = "F1Mx"; + apple,fan-target = "F1Tg"; + apple,fan-mode = "F1Md"; }; }; diff --git a/arch/arm64/boot/dts/apple/hwmon-fan.dtsi b/arch/arm64/boot/dts/apple/hwmon-fan.dtsi index 8f329ac4ff9fef..180eb8d7441f44 100644 --- a/arch/arm64/boot/dts/apple/hwmon-fan.dtsi +++ b/arch/arm64/boot/dts/apple/hwmon-fan.dtsi @@ -5,17 +5,13 @@ * Fan hwmon sensors for machines with a single fan. */ -&smc { - hwmon { - apple,fan-keys { - fan-F0Ac { - apple,key-id = "F0Ac"; - label = "Fan"; - apple,fan-minimum = "F0Mn"; - apple,fan-maximum = "F0Mx"; - apple,fan-target = "F0Tg"; - apple,fan-mode = "F0Md"; - }; - }; +&smc_hwmon { + fan-F0Ac { + apple,key-id = "F0Ac"; + label = "Fan"; + apple,fan-minimum = "F0Mn"; + apple,fan-maximum = "F0Mx"; + apple,fan-target = "F0Tg"; + apple,fan-mode = "F0Md"; }; }; diff --git a/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi b/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi index 2583ef379dfac9..4afb91ee69fe76 100644 --- a/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi +++ b/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi @@ -5,37 +5,29 @@ * Copyright The Asahi Linux Contributors */ -&smc { - hwmon { - apple,power-keys { - power-PHPC { - apple,key-id = "PHPC"; - label = "Heatpipe Power"; - }; - }; - apple,temp-keys { - temp-TB0T { - apple,key-id = "TB0T"; - label = "Battery Hotspot"; - }; - temp-TCHP { - apple,key-id = "TCHP"; - label = "Charge Regulator Temp"; - }; - temp-TW0P { - apple,key-id = "TW0P"; - label = "WiFi/BT Module Temp"; - }; - }; - apple,volt-keys { - volt-SBAV { - apple,key-id = "SBAV"; - label = "Battery Voltage"; - }; - volt-VD0R { - apple,key-id = "VD0R"; - label = "Charger Input Voltage"; - }; - }; +&smc_hwmon { + power-PHPC { + apple,key-id = "PHPC"; + label = "Heatpipe Power"; + }; + temperature-TB0T { + apple,key-id = "TB0T"; + label = "Battery Hotspot"; + }; + temperature-TCHP { + apple,key-id = "TCHP"; + label = "Charge Regulator Temp"; + }; + temperature-TW0P { + apple,key-id = "TW0P"; + label = "WiFi/BT Module Temp"; + }; + voltage-SBAV { + apple,key-id = "SBAV"; + label = "Battery Voltage"; + }; + voltage-VD0R { + apple,key-id = "VD0R"; + label = "Charger Input Voltage"; }; }; diff --git a/arch/arm64/boot/dts/apple/hwmon-mini.dtsi b/arch/arm64/boot/dts/apple/hwmon-mini.dtsi index bd0c22786d4226..7fd86e911acfe7 100644 --- a/arch/arm64/boot/dts/apple/hwmon-mini.dtsi +++ b/arch/arm64/boot/dts/apple/hwmon-mini.dtsi @@ -8,13 +8,9 @@ #include "hwmon-fan.dtsi" -&smc { - hwmon { - apple,temp-keys { - temp-TW0P { - apple,key-id = "TW0P"; - label = "WiFi/BT Module Temp"; - }; - }; +&smc_hwmon { + temperature-TW0P { + apple,key-id = "TW0P"; + label = "WiFi/BT Module Temp"; }; }; From 80b494a3430f51cdc69011afe2da9013377a6f48 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 16 Dec 2025 21:50:05 +0100 Subject: [PATCH 101/352] arm64: apple: t602x: Remove disabled status from uat reserved-mem regions m1n1 unfortunately doesn't enable these. Drop 3 months after a m1n1 which enables these is released. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t602x-common.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t602x-common.dtsi b/arch/arm64/boot/dts/apple/t602x-common.dtsi index fe888cbb81e475..2905234ad6d40b 100644 --- a/arch/arm64/boot/dts/apple/t602x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-common.dtsi @@ -614,17 +614,14 @@ }; uat_handoff: uat-handoff { - status = "disabled"; reg = <0 0 0 0>; }; uat_pagetables: uat-pagetables { - status = "disabled"; reg = <0 0 0 0>; }; uat_ttbs: uat-ttbs { - status = "disabled"; reg = <0 0 0 0>; }; }; From 6022c66d016013d801d8b314b34448ad7fcf7673 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 22 Dec 2025 22:33:21 +0100 Subject: [PATCH 102/352] rm64: dts: apple: t8103: Add ATC display crossbar devices These are mux devices which control which DCP source is routed to DP complex in ATC. The display signals are either routed to the DP phy for DP-altmode or one of two DP in Thunderbolt/USB4 tunnels. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8103.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 3e510b4a692236..d3fc50b8f901b5 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -1571,6 +1571,13 @@ power-domains = <&ps_atc0_usb>; }; + atcphy0_xbar: mux@38304c000 { + compatible = "apple,t8103-display-crossbar"; + reg = <0x3 0x8304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&ps_atc0_usb>; + }; + dwc3_1: usb@502280000 { compatible = "apple,t8103-dwc3"; reg = <0x5 0x02280000 0x0 0xcd00>, <0x5 0x0228cd00 0x0 0x3200>; @@ -1623,6 +1630,13 @@ power-domains = <&ps_atc1_usb>; }; + atcphy1_xbar: mux@50304c000 { + compatible = "apple,t8103-display-crossbar"; + reg = <0x5 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&ps_atc1_usb>; + }; + pcie0_dart_0: iommu@681008000 { compatible = "apple,t8103-dart"; reg = <0x6 0x81008000 0x0 0x4000>; From 959c1dc559f2d6871d0ce549eb9db54f1ddfa924 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 22 Dec 2025 22:33:21 +0100 Subject: [PATCH 103/352] rm64: dts: apple: t8112: Add ATC display crossbar devices These are mux devices which control which DCP source is routed to DP complex in ATC. The display signals are either routed to the DP phy for DP-altmode or one of two DP in Thunderbolt/USB4 tunnels. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8112.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 9e7777bf477f04..5a9a6da25da533 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1660,6 +1660,13 @@ power-domains = <&ps_atc0_usb>; }; + atcphy0_xbar: mux@38304c000 { + compatible = "apple,t8112-display-crossbar", "apple,t8103-display-crossbar"; + reg = <0x3 0x8304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&ps_atc0_usb>; + }; + dwc3_1: usb@502280000 { compatible = "apple,t8112-dwc3", "apple,t8103-dwc3"; reg = <0x5 0x02280000 0x0 0xcd00>, <0x5 0x0228cd00 0x0 0x3200>; @@ -1712,6 +1719,13 @@ power-domains = <&ps_atc1_usb>; }; + atcphy1_xbar: mux@50304c000 { + compatible = "apple,t8112-display-crossbar", "apple,t8103-display-crossbar"; + reg = <0x5 0x0304c000 0x0 0x4000>; + #mux-control-cells = <1>; + power-domains = <&ps_atc1_usb>; + }; + pcie0_dart: iommu@681008000 { compatible = "apple,t8110-dart"; reg = <0x6 0x81008000 0x0 0x4000>; From 6380733002530b70c2ac1f407c890a0a8a052bf9 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Dec 2025 20:25:56 +0100 Subject: [PATCH 104/352] arm64: dts: apple: Connect dcp and atc-phy for dp2hdmi on Macbook Pros The type-c mux lookup requires a graph connection between dcp and atc-phy. Signed-off-by: Janne Grunau --- .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 7e1d4b407ebaa3..02b3ebd756f1c8 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -107,6 +107,19 @@ mux-control-names = "dp-xbar"; mux-index = <0>; apple,dptx-phy = <3>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + decpext0_dpout: endpoint { + remote-endpoint = <&atcphy3_dp>; + }; + }; + }; }; /* remove once m1n1 enables sio nodes after setup */ @@ -554,7 +567,17 @@ }; &atcphy3 { - status = "disabled"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@2 { + reg = <2>; + atcphy3_dp: endpoint { + remote-endpoint = <&decpext0_dpout>; + }; + }; + }; }; &aop_mbox { From aa61504c87821d9c7f49a211061da07b9b5b1904 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 25 Dec 2025 17:47:37 +0100 Subject: [PATCH 105/352] arm64: dts: apple: j[34]1[46]: Mark ps_atc3_common as always-on This works around missing (or incomplete) suspend/resume handling in atc/dcp for the the HDMI output on 14 and 16-inch Macbook Pros. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 02b3ebd756f1c8..c6e33954c03067 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -135,6 +135,10 @@ status = "okay"; }; +&ps_atc3_common { + apple,always-on; /* Needs to stay on for HDMI resume */ +}; + /* USB Type C */ &i2c0 { hpm0: usb-pd@38 { From 234273c4f547fa7d89b3d554afb980fa5204e248 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 12 Mar 2026 23:33:36 +0100 Subject: [PATCH 106/352] fixup! arm64: dts: apple: t600x: Add t6000 dispext device nodes Discovered by https://github.com/girona1975 in [1] Link: https://github.com/AsahiLinux/linux/issues/303#issuecomment-3939589325 [1] Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index c6e33954c03067..c21de230d6e8ec 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -483,10 +483,11 @@ /* * ps_atc3_usb_aon power-domain is always-on to keep dwc3 working over suspend. * atc3 is used exclusively for the DP-to-HDMI so do not keep this always on. + * On t600x it is required to keep atc DP state over suspend. */ -&ps_atc3_usb_aon { - /delete-property/ apple,always-on; -}; +// &ps_atc3_usb_aon { +// /delete-property/ apple,always-on; +// }; /* ATC3 is used for DisplayPort -> HDMI only */ &dwc3_3_dart_0 { From 4a8a0fe0c5596648adf329d3ce2a2f394ea0087d Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 26 Feb 2026 18:15:38 +0100 Subject: [PATCH 107/352] arm64: dts: apple: Add PMP nodes and hook up power reporting Add the PMP device and set it as the power-domain for devices that need to report their power states to it. Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t6000.dtsi | 17 ++ arch/arm64/boot/dts/apple/t6001.dtsi | 12 + arch/arm64/boot/dts/apple/t6002.dtsi | 57 +++++ arch/arm64/boot/dts/apple/t600x-common.dtsi | 3 + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 204 +++++++++++++++ arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 8 + .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 4 + arch/arm64/boot/dts/apple/t600x-pmgr.dtsi | 2 + arch/arm64/boot/dts/apple/t6020.dtsi | 18 ++ arch/arm64/boot/dts/apple/t6021.dtsi | 13 + arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi | 1 + arch/arm64/boot/dts/apple/t6022.dtsi | 43 ++++ arch/arm64/boot/dts/apple/t602x-common.dtsi | 3 + arch/arm64/boot/dts/apple/t602x-die0.dtsi | 233 ++++++++++++++++++ arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 8 + arch/arm64/boot/dts/apple/t8112-j413.dts | 4 + arch/arm64/boot/dts/apple/t8112-j415.dts | 4 + arch/arm64/boot/dts/apple/t8112-j493.dts | 4 + arch/arm64/boot/dts/apple/t8112.dtsi | 176 +++++++++++++ 19 files changed, 814 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6000.dtsi b/arch/arm64/boot/dts/apple/t6000.dtsi index c9e4e52d9aac92..db7ea6eac5a6f1 100644 --- a/arch/arm64/boot/dts/apple/t6000.dtsi +++ b/arch/arm64/boot/dts/apple/t6000.dtsi @@ -18,6 +18,23 @@ }; /delete-node/ &pmgr_south; +/delete-node/ &pmp_report_dispext2; +/delete-node/ &pmp_report_dispext3; +/delete-node/ &pmp_report_venc1; +/delete-node/ &pmp_report_msr1; +/delete-node/ &pmp_report_prores; +/delete-node/ &pmp_report_afnc4_ioa; +/delete-node/ &pmp_report_afnc5_ioa; + +&pmp { + apple,pio-ranges = <0x2 0x82000000 0x0 0x1000000>, + <0x3 0x4000000 0x0 0x1000000>, + <0x3 0x83000000 0x0 0x1000000>, + <0x4 0x2000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>; +}; &gpu { compatible = "apple,agx-t6000", "apple,agx-g13x"; diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi index 3ac838c9b803b6..73053599d71d81 100644 --- a/arch/arm64/boot/dts/apple/t6001.dtsi +++ b/arch/arm64/boot/dts/apple/t6001.dtsi @@ -70,6 +70,18 @@ }; }; +&pmp { + apple,pio-ranges = <0x2 0x82000000 0x0 0x1000000>, + <0x3 0x4000000 0x0 0x1000000>, + <0x3 0x83000000 0x0 0x1000000>, + <0x4 0x2000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>, + <0x4 0x82000000 0x0 0x1000000>, + <0x5 0x2000000 0x0 0x1000000>; +}; + &gpu { compatible = "apple,agx-t6001", "apple,agx-g13c", "apple,agx-g13s"; }; diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi index 9bf333e0cf2d66..b5f175d71ee69a 100644 --- a/arch/arm64/boot/dts/apple/t6002.dtsi +++ b/arch/arm64/boot/dts/apple/t6002.dtsi @@ -320,6 +320,63 @@ power-domains = <&ps_afr>, <&ps_afr_die1>; }; +&pmp { + apple,pio-ranges = <0x2 0x82000000 0x0 0x1000000>, + <0x3 0x4000000 0x0 0x1000000>, + <0x3 0x83000000 0x0 0x1000000>, + <0x4 0x2000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>, + <0x4 0x82000000 0x0 0x1000000>, + <0x5 0x2000000 0x0 0x1000000>, + <0x22 0x82000000 0x0 0x1000000>, + <0x23 0x4000000 0x0 0x1000000>, + <0x23 0x83000000 0x0 0x1000000>, + <0x24 0x2000000 0x0 0x1000000>, + <0x24 0x82000000 0x0 0x1000000>, + <0x25 0x2000000 0x0 0x1000000>, + <0x22 0x10e70000 0x0 0x90000>, + <0x22 0x11e70000 0x0 0x90000>, + <0x22 0x12e70000 0x0 0x90000>; +}; + +&pmp_report { + pmp_report_dispext0_die1: report@33 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x33>; + label = "pmp-dispext0_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext0_cpu0_die1>; + }; + + pmp_report_dispext1_die1: report@34 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x34>; + label = "pmp-dispext1_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0_die1>; + }; + + pmp_report_dispext2_die1: report@35 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x35>; + label = "pmp-dispext2_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0_die1>; + status = "disabled"; + }; + + pmp_report_dispext3_die1: report@36 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x36>; + label = "pmp-dispext3_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0_die1>; + status = "disabled"; + }; +}; + &gpu { compatible = "apple,agx-t6002", "apple,agx-g13d", "apple,agx-g13s"; }; diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi index f37feaea4c2191..a7f25092533e7d 100644 --- a/arch/arm64/boot/dts/apple/t600x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi @@ -13,6 +13,9 @@ aliases { gpu = &gpu; + #ifdef APPLE_USE_PMP + pmp = &pmp; + #endif }; cpus { diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index f00550a680e131..7bff4ede753ad7 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -34,12 +34,208 @@ apple,dcs-min-ps = <7>; }; + pmp_dart: iommu@28e300000 { + compatible = "apple,t6000-dart"; + reg = <0x2 0x8e300000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_pmp>; + }; + + pmp_report: pmp_report@28e3c0000 { + compatible = "apple,t6000-pmp-v2-report"; + reg = <0x2 0x8e3c0000 0x0 0x20000>; + power-domains = <&ps_pms_sram>; + #address-cells = <1>; + #size-cells = <0>; + + pmp_report_ane_sys: report@a { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xa>; + label = "pmp-ane-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_ane_sys>; + status = "disabled"; + }; + + pmp_report_isp_sys: report@b { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xb>; + label = "pmp-isp-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + pmp_report_disp0: report@c { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xc>; + label = "pmp-disp0"; + #power-domain-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + apple,always-on; + }; + + pmp_report_dispext0: report@d { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xd>; + label = "pmp-dispext0"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext0_cpu0>; + apple,always-on; + }; + + pmp_report_dispext1: report@e { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xe>; + label = "pmp-dispext1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0>; + }; + + pmp_report_venc_sys: report@10 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x10>; + label = "pmp-venc-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_venc_sys>; + status = "disabled"; + }; + + pmp_report_avd_sys: report@11 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x11>; + label = "pmp-avd-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_avd_sys>; + status = "disabled"; + }; + + pmp_report_msr0: report@12 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x12>; + label = "pmp-msr0"; + #power-domain-cells = <0>; + power-domains = <&ps_msr0>; + status = "disabled"; + }; + + pmp_report_jpg: report@13 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x13>; + label = "pmp-jpg"; + #power-domain-cells = <0>; + power-domains = <&ps_jpg>; + status = "disabled"; + }; + + pmp_report_scodec: report@14 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x14>; + label = "pmp-scodec"; + #power-domain-cells = <0>; + power-domains = <&ps_scodec>; + status = "disabled"; + }; + + pmp_report_afnc4_ioa: report@1d { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x1d>; + label = "pmp-afnc4-ioa"; + #power-domain-cells = <0>; + apple,always-on; + }; + + pmp_report_afnc5_ioa: report@1e { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x1e>; + label = "pmp-afnc5-ioa"; + #power-domain-cells = <0>; + apple,always-on; + }; + + pmp_report_dispext2: report@20 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x20>; + label = "pmp-dispext2"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext2_cpu0>; + status = "disabled"; + }; + + pmp_report_dispext3: report@21 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x21>; + label = "pmp-dispext3"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext3_cpu0>; + status = "disabled"; + }; + + pmp_report_venc1: report@22 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x22>; + label = "pmp-venc1"; + #power-domain-cells = <0>; + power-domains = <&ps_venc1_sys>; + status = "disabled"; + }; + + pmp_report_msr1: report@23 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x23>; + label = "pmp-msr1"; + #power-domain-cells = <0>; + power-domains = <&ps_msr1>; + status = "disabled"; + }; + + pmp_report_prores: report@24 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x24>; + label = "pmp-prores"; + #power-domain-cells = <0>; + power-domains = <&ps_prores>; + status = "disabled"; + }; + }; + pmgr_dcp: power-management@28e3d0000 { reg = <0x2 0x8e3d0000 0x0 0x4000>; reg-names = "dcp-fw-pmgr"; #apple,bw-scratch-cells = <3>; }; + pmp: pmp@28e700000 { + compatible = "apple,t6000-pmp-v2"; + reg = <0x2 0x8e700000 0x0 0x100000>, + <0x2 0x8ec00000 0x0 0x4000>; + reg-names = "pmp", "asc"; + mboxes = <&pmp_mbox>; + mbox-names = "mbox"; + iommus = <&pmp_dart 0>; + power-domains = <&ps_pmp>; + status = "disabled"; + + tunables { + }; + }; + + pmp_mbox: mbox@28ec08000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x8ec08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_pmp>, <&ps_pms_sram>; + }; + smc: smc@290400000 { compatible = "apple,t6000-smc", "apple,smc"; reg = <0x2 0x90400000 0x0 0x4000>, @@ -333,7 +529,11 @@ <0x3 0x8b344000 0x0 0x4000>, <0x3 0x8b800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x988>; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_disp0>; + #else power-domains = <&ps_disp0_cpu0>; + #endif resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; phandle = <&dcp>; @@ -644,7 +844,11 @@ <0x3 0x861043f0 0x0 0x100>; interrupt-parent = <&aic>; interrupts = ; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_isp_sys>, <&ps_isp_set0>, + #else power-domains = <&ps_isp_sys>, <&ps_isp_set0>, + #endif <&ps_isp_set1>, <&ps_isp_fe>, <&ps_isp_set3>, <&ps_isp_set4>, <&ps_isp_set5>, <&ps_isp_set6>, <&ps_isp_set7>, <&ps_isp_set8>; diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi index 1671299411e0e6..121d158ff1b3ea 100644 --- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi @@ -75,7 +75,11 @@ <0x2 0x89344000 0x0 0x4000>, <0x2 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x990>; + #ifdef APPLE_USE_PMP + power-domains = <&DIE_NODE(pmp_report_dispext0)>; + #else power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + #endif resets = <&DIE_NODE(ps_dispext0_cpu0)>; clocks = <&DIE_NODE(clk_dispext0)>; phandle = <&DIE_NODE(dcpext0)>; @@ -152,7 +156,11 @@ <0x2 0x8c344000 0x0 0x4000>, <0x2 0x8c800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x998>; + #ifdef APPLE_USE_PMP + power-domains = <&DIE_NODE(pmp_report_dispext1)>; + #else power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + #endif resets = <&DIE_NODE(ps_dispext1_cpu0)>; clocks = <&DIE_NODE(clk_dispext1)>; phandle = <&DIE_NODE(dcpext1)>; diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index c21de230d6e8ec..cea603e5c2d9a0 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -642,6 +642,10 @@ apple,platform-id = <3>; }; +&pmp_report_isp_sys { + status = "okay"; +}; + #include "hwmon-common.dtsi" #include "hwmon-fan-dual.dtsi" #include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi index 1429554ed54505..833a59ecf37922 100644 --- a/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-pmgr.dtsi @@ -426,6 +426,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(pmp); + apple,always-on; }; #endif @@ -435,6 +436,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(pms_sram); + apple,always-on; }; DIE_NODE(ps_apcie_st_sys): power-controller@2e8 { diff --git a/arch/arm64/boot/dts/apple/t6020.dtsi b/arch/arm64/boot/dts/apple/t6020.dtsi index 482a1e5f53d0a6..9cc0b75b42c531 100644 --- a/arch/arm64/boot/dts/apple/t6020.dtsi +++ b/arch/arm64/boot/dts/apple/t6020.dtsi @@ -18,6 +18,24 @@ }; /delete-node/ &pmgr_south; +/delete-node/ &pmp_report_dispext2; +/delete-node/ &pmp_report_dispext3; +/delete-node/ &pmp_report_venc1; +/delete-node/ &pmp_report_msr1; +/delete-node/ &pmp_report_prores; +/delete-node/ &pmp_report_afnc4_ioa; +/delete-node/ &pmp_report_afnc5_ioa; + +&pmp { + apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, + <0x3 0x0 0x0 0x1000000>, + <0x3 0x80000000 0x0 0x1000000>, + <0x4 0x0 0x0 0x1000000>, + <0x3 0x40000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>; +}; &gpu { compatible = "apple,agx-t6020", "apple,agx-g14x", "apple,agx-g14s"; diff --git a/arch/arm64/boot/dts/apple/t6021.dtsi b/arch/arm64/boot/dts/apple/t6021.dtsi index bb0e66851f1b59..44c3b09ad46c51 100644 --- a/arch/arm64/boot/dts/apple/t6021.dtsi +++ b/arch/arm64/boot/dts/apple/t6021.dtsi @@ -73,6 +73,19 @@ }; }; +&pmp { + apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, + <0x3 0x0 0x0 0x1000000>, + <0x3 0x80000000 0x0 0x1000000>, + <0x4 0x0 0x0 0x1000000>, + <0x3 0x40000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>, + <0x4 0x80000000 0x0 0x1000000>, + <0x5 0x0 0x0 0x1000000>; +}; + &gpu { compatible = "apple,agx-t6021", "apple,agx-g14x", "apple,agx-g14c", "apple,agx-g14s"; diff --git a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi index f11b017dc0496f..fa0183441d791b 100644 --- a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi +++ b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi @@ -68,6 +68,7 @@ /* delete power-domains for missing disp0 / disp0_die1 */ /delete-node/ &ps_disp0_cpu0; /delete-node/ &ps_disp0_fe; +/delete-node/ &pmp_report_disp0; /delete-node/ &ps_disp0_cpu0_die1; /delete-node/ &ps_disp0_fe_die1; diff --git a/arch/arm64/boot/dts/apple/t6022.dtsi b/arch/arm64/boot/dts/apple/t6022.dtsi index f17c9a4f59e482..788bbf078f3894 100644 --- a/arch/arm64/boot/dts/apple/t6022.dtsi +++ b/arch/arm64/boot/dts/apple/t6022.dtsi @@ -359,6 +359,49 @@ power-domains = <&ps_afr>, <&ps_afr_die1>; }; +&pmp { + apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, + <0x3 0x0 0x0 0x1000000>, + <0x3 0x80000000 0x0 0x1000000>, + <0x4 0x0 0x0 0x1000000>, + <0x3 0x40000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>, + <0x4 0x80000000 0x0 0x1000000>, + <0x5 0x0 0x0 0x1000000>, + <0x22 0x80000000 0x0 0x1000000>, + <0x23 0x0 0x0 0x1000000>, + <0x23 0x80000000 0x0 0x1000000>, + <0x24 0x0 0x0 0x1000000>, + <0x23 0x40000000 0x0 0x1000000>, + <0x24 0x80000000 0x0 0x1000000>, + <0x25 0x0 0x0 0x1000000>, + <0x22 0x10e70000 0x0 0x90000>, + <0x22 0x11e70000 0x0 0x90000>, + <0x22 0x12e70000 0x0 0x90000>; +}; + +&pmp_report { + pmp_report_dispext0_die1: report@1f { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x1f>; + label = "pmp-dispext0_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext0_cpu0_die1>; + }; + + pmp_report_dispext1_die1: report@20 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x20>; + label = "pmp-dispext1_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0_die1>; + }; +}; + &gpu { compatible = "apple,agx-t6022", "apple,agx-g14x", "apple,agx-g14d", "apple,agx-g14s"; diff --git a/arch/arm64/boot/dts/apple/t602x-common.dtsi b/arch/arm64/boot/dts/apple/t602x-common.dtsi index 2905234ad6d40b..2fa6b93a14165f 100644 --- a/arch/arm64/boot/dts/apple/t602x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-common.dtsi @@ -13,6 +13,9 @@ aliases { gpu = &gpu; + #ifdef APPLE_USE_PMP + pmp = &pmp; + #endif }; cpus { diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 6803254a38af5e..8b55b9d6bc7614 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -32,12 +32,233 @@ reg-names = "fabric-ps", "dcs-ps"; }; + pmp_dart: iommu@28e300000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x2 0x8e300000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_pmp>; + }; + + pmp_report: pmp_report@28e3c0000 { + compatible = "apple,t6020-pmp-v2-report"; + reg = <0x2 0x8e3c0000 0x0 0x20000>; + power-domains = <&ps_pms_sram>; + #address-cells = <1>; + #size-cells = <0>; + + pmp_report_gfx: report@a { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xa>; + label = "pmp-gfx"; + #power-domain-cells = <0>; + power-domains = <&ps_gfx>; + }; + + pmp_report_ane_sys: report@b { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xb>; + label = "pmp-ane-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_ane_sys>; + status = "disabled"; + }; + + pmp_report_isp_sys: report@c { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xc>; + label = "pmp-isp-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + pmp_report_disp0: report@d { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xd>; + label = "pmp-disp0"; + #power-domain-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + apple,always-on; + }; + + pmp_report_dispext0: report@e { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xe>; + label = "pmp-dispext0"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext0_cpu0>; + }; + + pmp_report_dispext1: report@f { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xe>; + label = "pmp-dispext1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0>; + }; + + pmp_report_venc_sys: report@10 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x10>; + label = "pmp-venc-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_venc_sys>; + status = "disabled"; + }; + + pmp_report_avd_sys: report@11 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x11>; + label = "pmp-avd-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_avd_sys>; + status = "disabled"; + }; + + pmp_report_msr0: report@12 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x12>; + label = "pmp-msr0"; + #power-domain-cells = <0>; + power-domains = <&ps_msr0>; + status = "disabled"; + }; + + pmp_report_jpg: report@13 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x13>; + label = "pmp-jpg"; + #power-domain-cells = <0>; + power-domains = <&ps_jpg>; + status = "disabled"; + }; + + pmp_report_scodec: report@14 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x14>; + label = "pmp-scodec"; + #power-domain-cells = <0>; + power-domains = <&ps_scodec>; + status = "disabled"; + }; + + pmp_report_afnc4_ioa: report@1d { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x1d>; + label = "pmp-afnc4-ioa"; + #power-domain-cells = <0>; + apple,always-on; + }; + + pmp_report_afnc5_ioa: report@1e { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x1e>; + label = "pmp-afnc5-ioa"; + #power-domain-cells = <0>; + apple,always-on; + }; + + pmp_report_dispext2: report@1f { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x1f>; + label = "pmp-dispext2"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext2_cpu0>; + status = "disabled"; + }; + + pmp_report_dispext3: report@20 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x20>; + label = "pmp-dispext3"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext3_cpu0>; + status = "disabled"; + }; + + pmp_report_venc1: report@21 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x21>; + label = "pmp-venc1"; + #power-domain-cells = <0>; + power-domains = <&ps_venc1_sys>; + status = "disabled"; + }; + + pmp_report_msr1: report@22 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x22>; + label = "pmp-msr1"; + #power-domain-cells = <0>; + power-domains = <&ps_msr1>; + status = "disabled"; + }; + + pmp_report_prores: report@23 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x23>; + label = "pmp-prores"; + #power-domain-cells = <0>; + power-domains = <&ps_prores>; + status = "disabled"; + }; + }; + pmgr_dcp: power-management@28e3d0000 { reg = <0x2 0x8e3d0000 0x0 0x4000>; reg-names = "dcp-fw-pmgr"; #apple,bw-scratch-cells = <3>; }; + pmp: pmp@28e700000 { + compatible = "apple,t6020-pmp-v2", "apple,t6000-pmp-v2"; + reg = <0x2 0x8e700000 0x0 0x100000>, + <0x2 0x8ec00000 0x0 0x4000>; + reg-names = "pmp", "asc"; + mboxes = <&pmp_mbox>; + mbox-names = "mbox"; + iommus = <&pmp_dart 0>; + power-domains = <&ps_pmp>; + status = "disabled"; + + tunables { + }; + }; + + pmp_mbox: mbox@28ec08000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x8ec08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_pmp>, <&ps_pms_sram>; + }; + nub_spmi0: spmi@29e114000 { compatible = "apple,t6020-spmi", "apple,t8103-spmi", "apple,spmi"; reg = <0x2 0x9e114000 0x0 0x100>; @@ -314,7 +535,11 @@ #iommu-cells = <1>; interrupt-parent = <&aic>; interrupts = ; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_isp_sys>; + #else power-domains = <&ps_isp_sys>; + #endif apple,dma-range = <0x100 0x0 0x1 0x0>; status = "disabled"; @@ -410,7 +635,11 @@ <0x3 0x89344000 0x0 0x4000>, <0x3 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1208>; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_disp0>; + #else power-domains = <&ps_disp0_cpu0>; + #endif resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; phandle = <&dcp>; @@ -739,7 +968,11 @@ , ; mboxes = <&agx_mbox>; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_gfx>; + #else power-domains = <&ps_gfx>; + #endif memory-region = <&uat_ttbs>, <&uat_pagetables>, <&uat_handoff>, <&gpu_hw_cal_a>, <&gpu_hw_cal_b>, <&gpu_globals>; memory-region-names = "ttbs", "pagetables", "handoff", diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi index 30fe15fe0ac393..ae0038a4c28710 100644 --- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi @@ -74,7 +74,11 @@ <0x2 0x89344000 0x0 0x4000>, <0x2 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1210>; + #ifdef APPLE_USE_PMP + power-domains = <&DIE_NODE(pmp_report_dispext0)>; + #else power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + #endif resets = <&DIE_NODE(ps_dispext0_cpu0)>; clocks = <&DIE_NODE(clk_dispext0)>; phandle = <&DIE_NODE(dcpext0)>; @@ -222,7 +226,11 @@ <0x3 0x15344000 0x0 0x4000>, <0x3 0x15800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1218>; + #ifdef APPLE_USE_PMP + power-domains = <&DIE_NODE(pmp_report_dispext1)>; + #else power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + #endif resets = <&DIE_NODE(ps_dispext1_cpu0)>; clocks = <&DIE_NODE(clk_dispext1)>; phandle = <&DIE_NODE(dcpext1)>; diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts index 20285be747d965..f36d40cb7fe611 100644 --- a/arch/arm64/boot/dts/apple/t8112-j413.dts +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts @@ -272,4 +272,8 @@ apple,temporal-filter = <1>; }; +&pmp_report_isp_sys { + status = "okay"; +}; + #include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts index c2c32ca5577eff..7f63969ede2ab9 100644 --- a/arch/arm64/boot/dts/apple/t8112-j415.dts +++ b/arch/arm64/boot/dts/apple/t8112-j415.dts @@ -298,4 +298,8 @@ apple,temporal-filter = <1>; }; +&pmp_report_isp_sys { + status = "okay"; +}; + #include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts index 368c4a9cc01758..61bbb7a3c6f486 100644 --- a/arch/arm64/boot/dts/apple/t8112-j493.dts +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts @@ -325,5 +325,9 @@ apple,platform-id = <6>; }; +&pmp_report_isp_sys { + status = "okay"; +}; + #include "hwmon-fan.dtsi" #include "hwmon-laptop.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 5a9a6da25da533..1e5478a0521bb9 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -22,6 +22,9 @@ aliases { gpu = &gpu; + #ifdef APPLE_USE_PMP + pmp = &pmp; + #endif }; cpus { @@ -508,7 +511,11 @@ <0x2 0x4000000 0 0x1000000>; reg-names = "asc", "sgx"; mboxes = <&agx_mbox>; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_gfx>; + #else power-domains = <&ps_gfx>; + #endif memory-region = <&uat_ttbs>, <&uat_pagetables>, <&uat_handoff>, <&gpu_hw_cal_a>, <&gpu_hw_cal_b>, <&gpu_globals>; memory-region-names = "ttbs", "pagetables", "handoff", @@ -578,7 +585,11 @@ reg = <0x2 0x28200000 0x0 0xc000>, <0x2 0x28400000 0x0 0x4000>; reg-names = "be", "fe"; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_dispdfr>, <&ps_dispdfr_be>; + #else power-domains = <&ps_dispdfr_fe>, <&ps_dispdfr_be>; + #endif interrupt-parent = <&aic>; interrupts = , ; @@ -672,7 +683,11 @@ <0x2 0x2c4c4430 0x0 0x100>; interrupt-parent = <&aic>; interrupts = ; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_isp_sys>, <&ps_isp_set0>, + #else power-domains = <&ps_isp_sys>, <&ps_isp_set0>, + #endif <&ps_isp_set1>, <&ps_isp_set2>, <&ps_isp_fe>, <&ps_isp_set4>, <&ps_isp_set5>, <&ps_isp_set6>, <&ps_isp_set7>, <&ps_isp_set8>, <&ps_isp_set9>, @@ -733,7 +748,11 @@ <0x2 0x31344000 0x0 0x4000>, <0x2 0x31800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x5d8>; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_disp0>; + #else power-domains = <&ps_disp0_cpu0>; + #endif resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; phandle = <&dcp>; @@ -1055,12 +1074,151 @@ }; }; + pmp_dart: iommu@23b300000 { + compatible = "apple,t8110-dart"; + reg = <0x2 0x3b300000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_pmp>; + }; + + pmp_report: pmp_report@23b3c0000 { + compatible = "apple,t8112-pmp-v2-report"; + reg = <0x2 0x3b3c0000 0x0 0x20000>; + power-domains = <&ps_pms_sram>; + #address-cells = <1>; + #size-cells = <0>; + + pmp_report_gfx: report@4 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x4>; + label = "pmp-gfx"; + #power-domain-cells = <0>; + power-domains = <&ps_gfx>; + }; + + pmp_report_ane_sys: report@5 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x5>; + label = "pmp-ane-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_ane_sys>; + status = "disabled"; + }; + + pmp_report_isp_sys: report@6 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x6>; + label = "pmp-isp-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_isp_sys>; + status = "disabled"; + }; + + pmp_report_disp0: report@7 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x7>; + label = "pmp-disp0"; + #power-domain-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + apple,always-on; + }; + + pmp_report_dispext: report@8 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x8>; + label = "pmp-dispext"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext_cpu0>; + }; + + pmp_report_venc_sys: report@9 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x9>; + label = "pmp-venc-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_venc_sys>; + status = "disabled"; + }; + + pmp_report_avd_sys: report@a { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xa>; + label = "pmp-avd-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_avd_sys>; + status = "disabled"; + }; + + pmp_report_msr: report@b { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xb>; + label = "pmp-msr"; + #power-domain-cells = <0>; + power-domains = <&ps_msr>; + status = "disabled"; + }; + + pmp_report_jpg: report@c { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xc>; + label = "pmp-jpg"; + #power-domain-cells = <0>; + power-domains = <&ps_jpg>; + status = "disabled"; + }; + + pmp_report_scodec: report@d { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xd>; + label = "pmp-scodec"; + #power-domain-cells = <0>; + power-domains = <&ps_scodec>; + status = "disabled"; + }; + + pmp_report_dispdfr: report@11 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x11>; + label = "pmp-dispdfr"; + #power-domain-cells = <0>; + power-domains = <&ps_dispdfr_fe>; + }; + }; + pmgr_dcp: power-management@23b3d0000 { reg = <0x2 0x3b3d0000 0x0 0x4000>; reg-names = "dcp-bw-scratch"; #apple,bw-scratch-cells = <3>; }; + pmp: pmp@23b500000 { + compatible = "apple,t8112-pmp-v2", "apple,t6000-pmp-v2"; + reg = <0x2 0x3b500000 0x0 0x80000>, + <0x2 0x3bc00000 0x0 0x4000>; + reg-names = "pmp", "asc"; + mboxes = <&pmp_mbox>; + mbox-names = "mbox"; + iommus = <&pmp_dart 0>; + power-domains = <&ps_pmp>; + status = "disabled"; + + tunables { + }; + }; + pmgr: power-management@23b700000 { compatible = "apple,t8112-pmgr", "apple,pmgr", "syscon", "simple-mfd"; #address-cells = <1>; @@ -1069,6 +1227,20 @@ /* child nodes are added in t8103-pmgr.dtsi */ }; + pmp_mbox: mbox@23bc08000 { + compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x3bc08000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_pmp>, <&ps_pms_sram>; + }; + pinctrl_ap: pinctrl@23c100000 { compatible = "apple,t8112-pinctrl", "apple,pinctrl"; reg = <0x2 0x3c100000 0x0 0x100000>; @@ -1549,7 +1721,11 @@ <0x2 0x71344000 0x0 0x4000>, <0x2 0x71800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x5e0>; + #ifdef APPLE_USE_PMP + power-domains = <&pmp_report_dispext>; + #else power-domains = <&ps_dispext_cpu0>; + #endif resets = <&ps_dispext_cpu0>; clocks = <&clk_dispext0>; apple,dcp-index = <1>; From 5828e8932a2d5496f48a01e81bb63be453688aac Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Mar 2026 11:23:58 +0200 Subject: [PATCH 108/352] fixup! arm64: dts: apple: Add PMP nodes and hook up power reporting Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 3 --- arch/arm64/boot/dts/apple/t602x-die0.dtsi | 3 --- arch/arm64/boot/dts/apple/t8112.dtsi | 3 --- 3 files changed, 9 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index 7bff4ede753ad7..6bf9802ed4dc8b 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -217,9 +217,6 @@ iommus = <&pmp_dart 0>; power-domains = <&ps_pmp>; status = "disabled"; - - tunables { - }; }; pmp_mbox: mbox@28ec08000 { diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 8b55b9d6bc7614..4d91bfa1d34232 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -240,9 +240,6 @@ iommus = <&pmp_dart 0>; power-domains = <&ps_pmp>; status = "disabled"; - - tunables { - }; }; pmp_mbox: mbox@28ec08000 { diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 1e5478a0521bb9..b667944f6dc5c3 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -1214,9 +1214,6 @@ iommus = <&pmp_dart 0>; power-domains = <&ps_pmp>; status = "disabled"; - - tunables { - }; }; pmgr: power-management@23b700000 { From 77fd67cbdd2c257e4b49061f3cbb15fd82d31c29 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Tue, 28 Apr 2026 13:00:54 +0200 Subject: [PATCH 109/352] fixup! arm64: dts: apple: Add PMP nodes and hook up power reporting --- arch/arm64/boot/dts/apple/t6020.dtsi | 11 ----------- arch/arm64/boot/dts/apple/t6021.dtsi | 13 ------------- arch/arm64/boot/dts/apple/t6022.dtsi | 23 ----------------------- arch/arm64/boot/dts/apple/t602x-die0.dtsi | 17 +++-------------- arch/arm64/boot/dts/apple/t602x-pmgr.dtsi | 2 ++ 5 files changed, 5 insertions(+), 61 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6020.dtsi b/arch/arm64/boot/dts/apple/t6020.dtsi index 9cc0b75b42c531..500726e697a894 100644 --- a/arch/arm64/boot/dts/apple/t6020.dtsi +++ b/arch/arm64/boot/dts/apple/t6020.dtsi @@ -26,17 +26,6 @@ /delete-node/ &pmp_report_afnc4_ioa; /delete-node/ &pmp_report_afnc5_ioa; -&pmp { - apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, - <0x3 0x0 0x0 0x1000000>, - <0x3 0x80000000 0x0 0x1000000>, - <0x4 0x0 0x0 0x1000000>, - <0x3 0x40000000 0x0 0x1000000>, - <0x2 0x10e70000 0x0 0x90000>, - <0x2 0x11e70000 0x0 0x90000>, - <0x2 0x12e70000 0x0 0x90000>; -}; - &gpu { compatible = "apple,agx-t6020", "apple,agx-g14x", "apple,agx-g14s"; diff --git a/arch/arm64/boot/dts/apple/t6021.dtsi b/arch/arm64/boot/dts/apple/t6021.dtsi index 44c3b09ad46c51..bb0e66851f1b59 100644 --- a/arch/arm64/boot/dts/apple/t6021.dtsi +++ b/arch/arm64/boot/dts/apple/t6021.dtsi @@ -73,19 +73,6 @@ }; }; -&pmp { - apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, - <0x3 0x0 0x0 0x1000000>, - <0x3 0x80000000 0x0 0x1000000>, - <0x4 0x0 0x0 0x1000000>, - <0x3 0x40000000 0x0 0x1000000>, - <0x2 0x10e70000 0x0 0x90000>, - <0x2 0x11e70000 0x0 0x90000>, - <0x2 0x12e70000 0x0 0x90000>, - <0x4 0x80000000 0x0 0x1000000>, - <0x5 0x0 0x0 0x1000000>; -}; - &gpu { compatible = "apple,agx-t6021", "apple,agx-g14x", "apple,agx-g14c", "apple,agx-g14s"; diff --git a/arch/arm64/boot/dts/apple/t6022.dtsi b/arch/arm64/boot/dts/apple/t6022.dtsi index 788bbf078f3894..fe065d48726a3d 100644 --- a/arch/arm64/boot/dts/apple/t6022.dtsi +++ b/arch/arm64/boot/dts/apple/t6022.dtsi @@ -359,29 +359,6 @@ power-domains = <&ps_afr>, <&ps_afr_die1>; }; -&pmp { - apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, - <0x3 0x0 0x0 0x1000000>, - <0x3 0x80000000 0x0 0x1000000>, - <0x4 0x0 0x0 0x1000000>, - <0x3 0x40000000 0x0 0x1000000>, - <0x2 0x10e70000 0x0 0x90000>, - <0x2 0x11e70000 0x0 0x90000>, - <0x2 0x12e70000 0x0 0x90000>, - <0x4 0x80000000 0x0 0x1000000>, - <0x5 0x0 0x0 0x1000000>, - <0x22 0x80000000 0x0 0x1000000>, - <0x23 0x0 0x0 0x1000000>, - <0x23 0x80000000 0x0 0x1000000>, - <0x24 0x0 0x0 0x1000000>, - <0x23 0x40000000 0x0 0x1000000>, - <0x24 0x80000000 0x0 0x1000000>, - <0x25 0x0 0x0 0x1000000>, - <0x22 0x10e70000 0x0 0x90000>, - <0x22 0x11e70000 0x0 0x90000>, - <0x22 0x12e70000 0x0 0x90000>; -}; - &pmp_report { pmp_report_dispext0_die1: report@1f { compatible = "apple,t6020-pmp-v2-report-entry", diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 4d91bfa1d34232..c0c0626249a5a6 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -48,15 +48,6 @@ #address-cells = <1>; #size-cells = <0>; - pmp_report_gfx: report@a { - compatible = "apple,t6020-pmp-v2-report-entry", - "apple,t6000-pmp-v2-report-entry"; - reg = <0xa>; - label = "pmp-gfx"; - #power-domain-cells = <0>; - power-domains = <&ps_gfx>; - }; - pmp_report_ane_sys: report@b { compatible = "apple,t6020-pmp-v2-report-entry", "apple,t6000-pmp-v2-report-entry"; @@ -94,15 +85,17 @@ label = "pmp-dispext0"; #power-domain-cells = <0>; power-domains = <&ps_dispext0_cpu0>; + apple,always-on; }; pmp_report_dispext1: report@f { compatible = "apple,t6020-pmp-v2-report-entry", "apple,t6000-pmp-v2-report-entry"; - reg = <0xe>; + reg = <0xf>; label = "pmp-dispext1"; #power-domain-cells = <0>; power-domains = <&ps_dispext1_cpu0>; + apple,always-on; }; pmp_report_venc_sys: report@10 { @@ -965,11 +958,7 @@ , ; mboxes = <&agx_mbox>; - #ifdef APPLE_USE_PMP - power-domains = <&pmp_report_gfx>; - #else power-domains = <&ps_gfx>; - #endif memory-region = <&uat_ttbs>, <&uat_pagetables>, <&uat_handoff>, <&gpu_hw_cal_a>, <&gpu_hw_cal_b>, <&gpu_globals>; memory-region-names = "ttbs", "pagetables", "handoff", diff --git a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi index b9233f252e6ca7..4ead781fea6893 100644 --- a/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-pmgr.dtsi @@ -454,6 +454,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(pmp); + apple,always-on; }; DIE_NODE(ps_pms_sram): power-controller@2d0 { @@ -462,6 +463,7 @@ #power-domain-cells = <0>; #reset-cells = <0>; label = DIE_LABEL(pms_sram); + apple,always-on; }; DIE_NODE(ps_dispext0_cpu0): power-controller@2d8 { From 77c6937f87ebc07631cf50aed9eb471f48850aa1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 31 Jan 2026 16:51:18 +0100 Subject: [PATCH 110/352] arm64: dts: apple: Initial t603[124] (M3 Max and Ultra) device trees Contains minimal device trees for all M3 Max and Ultra Apple silicon devices. Those are 14-inch and 16-inch MacBook Pros with M3 Max released in November 2023 and Mac Studio with M3 Ultra released in 2025. This does not include M3 Pro since it looks like separate chip and not a smaller variant of the M3 Max contrary to the M1 and M2 generations. The smaller M3 Max variant (10 performance cores) has its own chip variant (t6034) but is clearly the same design as t6031. Besides fewer CPU performance cores and GPU cores it misses also on fourth of the memory controllers and thus has an aggregated bus width of 384 bit instead of 512 bit. Both M3 Ultra variants (28 or 32 CPU cores) are based on t6031 judging by the advertised memory bandwidth of 819GB/s. The device trees have devices nodes for CPU cores, timer, interrupt controller, power states, watchdog, serial, pin controller, i2c, PWM based keyboard LED illumination and the boot framebuffer. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/Makefile | 5 + arch/arm64/boot/dts/apple/t6031-base.dtsi | 297 ++ arch/arm64/boot/dts/apple/t6031-die0.dtsi | 198 ++ arch/arm64/boot/dts/apple/t6031-dieX.dtsi | 107 + .../arm64/boot/dts/apple/t6031-gpio-pins.dtsi | 53 + arch/arm64/boot/dts/apple/t6031-j514c.dts | 18 + arch/arm64/boot/dts/apple/t6031-j516c.dts | 18 + arch/arm64/boot/dts/apple/t6031-pmgr.dtsi | 2399 +++++++++++++++++ arch/arm64/boot/dts/apple/t6031.dtsi | 48 + arch/arm64/boot/dts/apple/t6032-j575d.dts | 46 + arch/arm64/boot/dts/apple/t6032.dtsi | 419 +++ arch/arm64/boot/dts/apple/t6034-j514m.dts | 18 + arch/arm64/boot/dts/apple/t6034-j516m.dts | 18 + arch/arm64/boot/dts/apple/t6034.dtsi | 12 + .../arm64/boot/dts/apple/t603x-j514-j516.dtsi | 67 + 15 files changed, 3723 insertions(+) create mode 100644 arch/arm64/boot/dts/apple/t6031-base.dtsi create mode 100644 arch/arm64/boot/dts/apple/t6031-die0.dtsi create mode 100644 arch/arm64/boot/dts/apple/t6031-dieX.dtsi create mode 100644 arch/arm64/boot/dts/apple/t6031-gpio-pins.dtsi create mode 100644 arch/arm64/boot/dts/apple/t6031-j514c.dts create mode 100644 arch/arm64/boot/dts/apple/t6031-j516c.dts create mode 100644 arch/arm64/boot/dts/apple/t6031-pmgr.dtsi create mode 100644 arch/arm64/boot/dts/apple/t6031.dtsi create mode 100644 arch/arm64/boot/dts/apple/t6032-j575d.dts create mode 100644 arch/arm64/boot/dts/apple/t6032.dtsi create mode 100644 arch/arm64/boot/dts/apple/t6034-j514m.dts create mode 100644 arch/arm64/boot/dts/apple/t6034-j516m.dts create mode 100644 arch/arm64/boot/dts/apple/t6034.dtsi create mode 100644 arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile index 6fc3349a58428f..a22b4a8068b6aa 100644 --- a/arch/arm64/boot/dts/apple/Makefile +++ b/arch/arm64/boot/dts/apple/Makefile @@ -87,6 +87,11 @@ dtb-$(CONFIG_ARCH_APPLE) += t6021-j416c.dtb dtb-$(CONFIG_ARCH_APPLE) += t6020-j474s.dtb dtb-$(CONFIG_ARCH_APPLE) += t6021-j475c.dtb dtb-$(CONFIG_ARCH_APPLE) += t6022-j475d.dtb +dtb-$(CONFIG_ARCH_APPLE) += t6031-j514c.dtb +dtb-$(CONFIG_ARCH_APPLE) += t6031-j516c.dtb +dtb-$(CONFIG_ARCH_APPLE) += t6032-j575d.dtb +dtb-$(CONFIG_ARCH_APPLE) += t6034-j514m.dtb +dtb-$(CONFIG_ARCH_APPLE) += t6034-j516m.dtb dtb-$(CONFIG_ARCH_APPLE) += t8112-j413.dtb dtb-$(CONFIG_ARCH_APPLE) += t8112-j415.dtb dtb-$(CONFIG_ARCH_APPLE) += t8112-j473.dtb diff --git a/arch/arm64/boot/dts/apple/t6031-base.dtsi b/arch/arm64/boot/dts/apple/t6031-base.dtsi new file mode 100644 index 00000000000000..0bb7373b3f0648 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6031-base.dtsi @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Nodes common for T6031, T6032 and T6034 family SoCs (M3 Max/Ultra) + * + * Other names: H15J, H15S, "Palma" + * + * Copyright The Asahi Linux Contributors + */ + +/ { + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu_e00>; + }; + core1 { + cpu = <&cpu_e01>; + }; + core2 { + cpu = <&cpu_e02>; + }; + core3 { + cpu = <&cpu_e03>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu_p00>; + }; + core1 { + cpu = <&cpu_p01>; + }; + core2 { + cpu = <&cpu_p02>; + }; + core3 { + cpu = <&cpu_p03>; + }; + core4 { + cpu = <&cpu_p04>; + }; + core5 { + cpu = <&cpu_p05>; + }; + }; + + cluster2 { + core0 { + cpu = <&cpu_p10>; + }; + core1 { + cpu = <&cpu_p11>; + }; + core2 { + cpu = <&cpu_p12>; + }; + core3 { + cpu = <&cpu_p13>; + }; + core4 { + cpu = <&cpu_p14>; + }; + core5 { + cpu = <&cpu_p15>; + }; + }; + }; + + cpu_e00: cpu@0 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e01: cpu@1 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e02: cpu@2 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e03: cpu@3 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_p00: cpu@10100 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p01: cpu@10101 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p02: cpu@10102 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10102>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p03: cpu@10103 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10103>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p04: cpu@10104 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10104>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p05: cpu@10105 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10105>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p10: cpu@10200 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10200>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_2>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p11: cpu@10201 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10201>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_2>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p12: cpu@10202 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10202>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_2>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p13: cpu@10203 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10203>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_2>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p14: cpu@10204 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10204>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_2>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p15: cpu@10205 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10205>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_2>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + l2_cache_0: l2-cache-0 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x400000>; + }; + + l2_cache_1: l2-cache-1 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x1000000>; + }; + + l2_cache_2: l2-cache-2 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x1000000>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt", "hyp-phys", "hyp-virt"; + interrupts = , + , + , + ; + }; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t6031-die0.dtsi b/arch/arm64/boot/dts/apple/t6031-die0.dtsi new file mode 100644 index 00000000000000..fbc3b5abfbba3f --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6031-die0.dtsi @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Devices used on die 0 on the Apple T6032 "M3 Ultra" SoC and present on + * Apple T6030 ("M3 Pro") and T6031 / T6034 ("M3 Max"). + * + * Copyright The Asahi Linux Contributors + */ + + wdt: watchdog@2a02d4000 { + compatible = "apple,t6031-wdt", "apple,t8103-wdt"; + reg = <0x2 0xa02d4000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + aic: interrupt-controller@292400000 { + compatible = "apple,t6031-aic3", "apple,t8122-aic3"; + #interrupt-cells = <4>; + interrupt-controller; + + reg = <0x00000002 0x92400000 0x00000000 0x1cc000>, + <0x00000002 0x92440000 0x00000000 0x4000>; + reg-names = "core", "event"; + power-domains = <&ps_aic>; + }; + + + pinctrl_smc: pinctrl@2a4820000 { + compatible = "apple,t6031-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; + reg = <0x2 0xa4820000 0x0 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_smc 0 0 30>; + apple,npins = <30>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + i2c0: i2c@391010000 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x91010000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c0>; + #address-cells = <0x1>; + #size-cells = <0x0>; + }; + + i2c1: i2c@391014000 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x91014000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c1>; + #address-cells = <0x1>; + #size-cells = <0x0>; + status = "disabled"; + }; + + i2c2: i2c@391018000 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x91018000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c2>; + #address-cells = <0x1>; + #size-cells = <0x0>; + status = "disabled"; + }; + + i2c3: i2c@39101c000 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x9101c000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c3>; + #address-cells = <0x1>; + #size-cells = <0x0>; + status = "disabled"; + }; + + i2c4: i2c@391020000 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x91020000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c4_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c4>; + #address-cells = <0x1>; + #size-cells = <0x0>; + status = "disabled"; + }; + + i2c5: i2c@391024000 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x91024000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c5_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c5>; + #address-cells = <0x1>; + #size-cells = <0x0>; + status = "disabled"; + }; + + i2c6: i2c@39102c800 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x91028000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c6_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c6>; + #address-cells = <0x1>; + #size-cells = <0x0>; + status = "disabled"; + }; + + i2c7: i2c@39102c000 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x9102c000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c7_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c7>; + #address-cells = <0x1>; + #size-cells = <0x0>; + status = "disabled"; + }; + + i2c8: i2c@391030000 { + compatible = "apple,t6031-i2c", "apple,t8103-i2c", "apple,i2c"; + reg = <0x3 0x91030000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c8_pins>; + pinctrl-names = "default"; + power-domains = <&ps_i2c8>; + #address-cells = <0x1>; + #size-cells = <0x0>; + status = "disabled"; + }; + + fpwm0: pwm@391040000 { + compatible = "apple,t6031-fpwm", "apple,s5l-fpwm"; + reg = <0x3 0x91040000 0x0 0x4000>; + power-domains = <&ps_fpwm0>; + clocks = <&clkref>; + #pwm-cells = <2>; + status = "disabled"; + }; + + serial0: serial@391200000 { + compatible = "apple,s5l-uart"; + reg = <0x3 0x91200000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* + * TODO: figure out the clocking properly, there may + * be a third selectable clock. + */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + power-domains = <&ps_uart0>; + status = "disabled"; + }; diff --git a/arch/arm64/boot/dts/apple/t6031-dieX.dtsi b/arch/arm64/boot/dts/apple/t6031-dieX.dtsi new file mode 100644 index 00000000000000..66f55f82c37412 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6031-dieX.dtsi @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Nodes present on both dies of T6032 (M3 Ultra) and present on T6031 / T6034 + * (M3 Max). + * + * Copyright The Asahi Linux Contributors + */ + + DIE_NODE(pmgr): power-management@292280000 { + compatible = "apple,t6031-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + reg = <0x2 0x92280000 0 0xc000>; + }; + + DIE_NODE(pmgr1): power-management@292800000 { + compatible = "apple,t6031-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + reg = <0x2 0x92800000 0 0x4000>; + }; + + DIE_NODE(pinctrl_nub): pinctrl@2a01f0000 { + compatible = "apple,t6031-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; + reg = <0x2 0xa01f0000 0x0 0x4000>; + power-domains = <&DIE_NODE(ps_nub_gpio)>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&DIE_NODE(pinctrl_nub) 0 0 59>; + apple,npins = <59>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + DIE_NODE(pmgr_mini): power-management@2a0280000 { + compatible = "apple,t6031-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + reg = <0x2 0xa0280000 0 0x4000>; + }; + + DIE_NODE(pinctrl_aop): pinctrl@2a8824000 { + compatible = "apple,t6031-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; + reg = <0x2 0xa8824000 0x0 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&DIE_NODE(pinctrl_aop) 0 0 102>; + apple,npins = <102>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + DIE_NODE(pinctrl_ap): pinctrl@2b3000000 { + compatible = "apple,t6031-pinctrl", "apple,t8103-pinctrl", "apple,pinctrl"; + reg = <0x2 0xb3000000 0x0 0x4000>; + + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + + clocks = <&clkref>; + power-domains = <&DIE_NODE(ps_gpio)>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&DIE_NODE(pinctrl_ap) 0 0 200>; + apple,npins = <200>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + DIE_NODE(pmgr_gfx): power-management@408e80000 { + compatible = "apple,t6031-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + reg = <0x4 0x8e80000 0 0x4000>; + }; diff --git a/arch/arm64/boot/dts/apple/t6031-gpio-pins.dtsi b/arch/arm64/boot/dts/apple/t6031-gpio-pins.dtsi new file mode 100644 index 00000000000000..5e4727e357d218 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6031-gpio-pins.dtsi @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * GPIO pin mappings for Apple T6031/T6032/T6034 SoCs. + * + * Copyright The Asahi Linux Contributors + */ + +&pinctrl_ap { + i2c0_pins: i2c0-pins { + pinmux = , + ; + }; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; + + i2c4_pins: i2c4-pins { + pinmux = , + ; + }; + + i2c5_pins: i2c5-pins { + pinmux = , + ; + }; + + i2c6_pins: i2c6-pins { + pinmux = , + ; + }; + + i2c7_pins: i2c7-pins { + pinmux = , + ; + }; + + i2c8_pins: i2c8-pins { + pinmux = , + ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t6031-j514c.dts b/arch/arm64/boot/dts/apple/t6031-j514c.dts new file mode 100644 index 00000000000000..c1507158325e82 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6031-j514c.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * MacBook Pro (14-inch, M3 Max, 16 CPU cores, Nov 2023) + * + * target-type: J514c + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t6031.dtsi" +#include "t603x-j514-j516.dtsi" + +/ { + compatible = "apple,j514c", "apple,t6031", "apple,arm-platform"; + model = "Apple MacBook Pro (14-inch, M3 Max, 16 CPU cores, Nov 2023)"; +}; diff --git a/arch/arm64/boot/dts/apple/t6031-j516c.dts b/arch/arm64/boot/dts/apple/t6031-j516c.dts new file mode 100644 index 00000000000000..841b2bb10b069d --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6031-j516c.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * MacBook Pro (16-inch, M3 Max, 16 CPU cores, Nov 2023) + * + * target-type: J516c + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t6031.dtsi" +#include "t603x-j514-j516.dtsi" + +/ { + compatible = "apple,j516c", "apple,t6031", "apple,arm-platform"; + model = "Apple MacBook Pro (16-inch, M3 Max, 16 CPU cores, Nov 2023)"; +}; diff --git a/arch/arm64/boot/dts/apple/t6031-pmgr.dtsi b/arch/arm64/boot/dts/apple/t6031-pmgr.dtsi new file mode 100644 index 00000000000000..95d062459df0c7 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6031-pmgr.dtsi @@ -0,0 +1,2399 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * PMGR Power domains for Apple T6031 "M3 Max/Ultra" SoC + * + * Copyright The Asahi Linux Contributors + */ + +&DIE_NODE(pmgr) { + DIE_NODE(ps_ispsens0): power-controller@100 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x100 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ispsens0); + }; + + DIE_NODE(ps_apcie_gp): power-controller@108 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x108 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(apcie_gp); + }; + + DIE_NODE(ps_apcie_ge): power-controller@110 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x110 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(apcie_ge); + }; + + DIE_NODE(ps_apcie_st): power-controller@118 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x118 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(apcie_st); + }; + + DIE_NODE(ps_afnc3_ioa): power-controller@120 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x120 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc3_ioa); + apple,always-on; + }; + + DIE_NODE(ps_afnc3_ls): power-controller@128 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x128 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc3_ls); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc3_ioa)>; + }; + + DIE_NODE(ps_afnc3_lw0): power-controller@138 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x138 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc3_lw0); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc3_ls)>; + }; + + DIE_NODE(ps_afnc3_lw1): power-controller@148 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x148 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc3_lw1); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc3_ls)>; + }; + + DIE_NODE(ps_apcie_sys_gp): power-controller@158 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x158 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(apcie_sys_gp); + power-domains = <&DIE_NODE(ps_apcie_gp)>, <&DIE_NODE(ps_afnc3_lw0)>; + }; + + DIE_NODE(ps_afnc4_ioa): power-controller@168 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x168 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc4_ioa); + apple,always-on; + }; + + DIE_NODE(ps_afnc4_ls): power-controller@178 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x178 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc4_ls); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc4_ioa)>; + }; + + DIE_NODE(ps_afnc4_lw0): power-controller@188 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x188 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc4_lw0); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc4_ls)>; + }; + + DIE_NODE(ps_afnc5_ioa): power-controller@198 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x198 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc5_ioa); + apple,always-on; + }; + + DIE_NODE(ps_afnc5_ls): power-controller@1a8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc5_ls); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc5_ioa)>; + }; + + DIE_NODE(ps_afnc5_lw0): power-controller@1b8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc5_lw0); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc5_ls)>; + }; + + DIE_NODE(ps_afnc6_ioa): power-controller@1c8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1c8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc6_ioa); + apple,always-on; + }; + + DIE_NODE(ps_afnc6_ls): power-controller@1d8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1d8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc6_ls); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc6_ioa)>; + }; + + DIE_NODE(ps_afnc6_lw0): power-controller@1e8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1e8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc6_lw0); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc6_ls)>; + }; + + DIE_NODE(ps_sio): power-controller@1f8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1f8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(sio); + power-domains = <&DIE_NODE(ps_afnc4_lw0)>; + }; + + DIE_NODE(ps_disp_sys): power-controller@200 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x200 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(disp_sys); + power-domains = <&DIE_NODE(ps_afnc4_lw0)>; + }; + + DIE_NODE(ps_isp_sys): power-controller@208 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x208 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_sys); + power-domains = <&DIE_NODE(ps_afnc4_lw0)>; + }; + + DIE_NODE(ps_sio_cpu): power-controller@210 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x210 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(sio_cpu); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_fpwm0): power-controller@218 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x218 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(fpwm0); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_fpwm1): power-controller@220 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x220 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(fpwm1); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_fpwm2): power-controller@228 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x228 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(fpwm2); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c0): power-controller@230 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x230 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c0); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c1): power-controller@238 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x238 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c1); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c2): power-controller@240 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x240 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c2); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c3): power-controller@248 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x248 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c3); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c4): power-controller@250 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x250 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c4); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c5): power-controller@258 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x258 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c5); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c6): power-controller@260 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x260 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c6); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c7): power-controller@268 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x268 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c7); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_i2c8): power-controller@270 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x270 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(i2c8); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_spi_p): power-controller@278 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x278 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(spi_p); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_uart_p): power-controller@280 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x280 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart_p); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_audio_p): power-controller@288 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x288 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(audio_p); + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_aes): power-controller@290 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x290 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(aes); + apple,always-on; + power-domains = <&DIE_NODE(ps_sio)>; + }; + + DIE_NODE(ps_disp_fe): power-controller@298 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x298 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(disp_fe); + power-domains = <&DIE_NODE(ps_disp_cpu)>; + }; + + DIE_NODE(ps_disp_cpu): power-controller@2a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(disp_cpu); + power-domains = <&DIE_NODE(ps_disp_sys)>; + }; + + DIE_NODE(ps_spi0): power-controller@2a8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(spi0); + power-domains = <&DIE_NODE(ps_spi_p)>; + }; + + DIE_NODE(ps_spi1): power-controller@2b0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(spi1); + power-domains = <&DIE_NODE(ps_spi_p)>; + }; + + DIE_NODE(ps_spi2): power-controller@2b8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(spi2); + power-domains = <&DIE_NODE(ps_spi_p)>; + }; + + DIE_NODE(ps_spi3): power-controller@2c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(spi3); + power-domains = <&DIE_NODE(ps_spi_p)>; + }; + + DIE_NODE(ps_spi4): power-controller@2c8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2c8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(spi4); + power-domains = <&DIE_NODE(ps_spi_p)>; + }; + + DIE_NODE(ps_spi5): power-controller@2d0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(spi5); + power-domains = <&DIE_NODE(ps_spi_p)>; + }; + + DIE_NODE(ps_qspi): power-controller@2d8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2d8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(qspi); + power-domains = <&DIE_NODE(ps_spi_p)>; + }; + + DIE_NODE(ps_uart_n): power-controller@2e0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart_n); + power-domains = <&DIE_NODE(ps_uart_p)>; + }; + + DIE_NODE(ps_uart0): power-controller@2e8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2e8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart0); + power-domains = <&DIE_NODE(ps_uart_p)>; + }; + + DIE_NODE(ps_uart1): power-controller@2f0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart1); + power-domains = <&DIE_NODE(ps_uart_p)>; + }; + + DIE_NODE(ps_uart2): power-controller@2f8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2f8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart2); + power-domains = <&DIE_NODE(ps_uart_p)>; + }; + + DIE_NODE(ps_uart3): power-controller@300 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x300 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart3); + power-domains = <&DIE_NODE(ps_uart_p)>; + }; + + DIE_NODE(ps_uart4): power-controller@308 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x308 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart4); + power-domains = <&DIE_NODE(ps_uart_p)>; + }; + + DIE_NODE(ps_uart5): power-controller@310 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x310 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart5); + power-domains = <&DIE_NODE(ps_uart_p)>; + }; + + DIE_NODE(ps_uart6): power-controller@318 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x318 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(uart6); + power-domains = <&DIE_NODE(ps_uart_p)>; + }; + + DIE_NODE(ps_sio_adma): power-controller@320 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x320 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(sio_adma); + power-domains = <&DIE_NODE(ps_sio)>, <&DIE_NODE(ps_audio_p)>; + }; + + DIE_NODE(ps_dpa0): power-controller@328 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x328 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dpa0); + power-domains = <&DIE_NODE(ps_audio_p)>; + }; + + DIE_NODE(ps_dpa1): power-controller@330 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x330 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dpa1); + power-domains = <&DIE_NODE(ps_audio_p)>; + }; + + DIE_NODE(ps_dpa2): power-controller@338 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x338 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dpa2); + power-domains = <&DIE_NODE(ps_audio_p)>; + }; + + DIE_NODE(ps_dpa3): power-controller@340 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x340 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dpa3); + power-domains = <&DIE_NODE(ps_audio_p)>; + }; + + DIE_NODE(ps_dpa4): power-controller@348 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x348 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dpa4); + power-domains = <&DIE_NODE(ps_audio_p)>; + }; + + DIE_NODE(ps_amcc1): power-controller@350 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x350 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(amcc1); + apple,always-on; + }; + + DIE_NODE(ps_amcc3): power-controller@360 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x360 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(amcc3); + apple,always-on; + }; + + DIE_NODE(ps_amcc5): power-controller@370 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x370 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(amcc5); + apple,always-on; + }; + + DIE_NODE(ps_amcc7): power-controller@380 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x380 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(amcc7); + apple,always-on; + }; + + DIE_NODE(ps_dcs_04): power-controller@390 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x390 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_04); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc1)>; + }; + + DIE_NODE(ps_dcs_05): power-controller@3a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_05); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc1)>; + }; + + DIE_NODE(ps_dcs_06): power-controller@3b0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_06); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc1)>; + }; + + DIE_NODE(ps_dcs_07): power-controller@3c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_07); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc1)>; + }; + + DIE_NODE(ps_dcs_12): power-controller@3d0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_12); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc3)>; + }; + + DIE_NODE(ps_dcs_13): power-controller@3e0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_13); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc3)>; + }; + + DIE_NODE(ps_dcs_14): power-controller@3f0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_14); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc3)>; + }; + + DIE_NODE(ps_dcs_15): power-controller@400 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x400 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_15); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc3)>; + }; + + DIE_NODE(ps_dcs_20): power-controller@410 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x410 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_20); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc5)>; + }; + + DIE_NODE(ps_dcs_21): power-controller@420 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x420 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_21); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc5)>; + }; + + DIE_NODE(ps_dcs_22): power-controller@430 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x430 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_22); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc5)>; + }; + + DIE_NODE(ps_dcs_23): power-controller@440 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x440 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_23); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc5)>; + }; + + DIE_NODE(ps_dcs_28): power-controller@450 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x450 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_28); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc7)>; + }; + + DIE_NODE(ps_dcs_29): power-controller@460 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x460 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_29); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc7)>; + }; + + DIE_NODE(ps_dcs_30): power-controller@470 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x470 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_30); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc7)>; + }; + + DIE_NODE(ps_dcs_31): power-controller@480 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x480 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_31); + apple,always-on; /* LPDDR5 interface */ + power-domains = <&DIE_NODE(ps_amcc7)>; + }; + + DIE_NODE(ps_mca0): power-controller@4e8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4e8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mca0); + power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + }; + + DIE_NODE(ps_mca1): power-controller@4f0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mca1); + power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + }; + + DIE_NODE(ps_mca2): power-controller@4f8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4f8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mca2); + power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + }; + + DIE_NODE(ps_mca3): power-controller@500 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x500 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mca3); + power-domains = <&DIE_NODE(ps_audio_p)>, <&DIE_NODE(ps_sio_adma)>; + }; + + DIE_NODE(ps_msr1): power-controller@508 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x508 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(msr1); + power-domains = <&DIE_NODE(ps_afnc5_lw0)>; + }; + + DIE_NODE(ps_venc1_sys): power-controller@510 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x510 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc1_sys); + power-domains = <&DIE_NODE(ps_afnc5_lw0)>; + }; + + DIE_NODE(ps_msr0): power-controller@518 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x518 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(msr0); + power-domains = <&DIE_NODE(ps_afnc6_lw0)>; + }; + + DIE_NODE(ps_ane_sys): power-controller@520 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x520 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ane_sys); + power-domains = <&DIE_NODE(ps_afnc5_lw0)>, <&DIE_NODE(ps_afnc6_lw0)>; + }; + + DIE_NODE(ps_msr1_ase_core): power-controller@538 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x538 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(msr1_ase_core); + power-domains = <&DIE_NODE(ps_msr1)>; + }; + + DIE_NODE(ps_apcie_sys_ge): power-controller@540 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x540 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(apcie_sys_ge); + power-domains = <&DIE_NODE(ps_apcie_ge)>, <&DIE_NODE(ps_afnc3_lw0)>; + }; + + DIE_NODE(ps_ans): power-controller@550 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x550 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ans); + power-domains = <&DIE_NODE(ps_afnc3_lw1)>; + }; + + DIE_NODE(ps_apcie_sys_st): power-controller@560 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x560 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(apcie_sys_st); + power-domains = <&DIE_NODE(ps_apcie_st)>, <&DIE_NODE(ps_ans)>; + }; + + DIE_NODE(ps_apcie_sys_st1): power-controller@570 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x570 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(apcie_sys_st1); + power-domains = <&DIE_NODE(ps_apcie_st)>, <&DIE_NODE(ps_ans)>; + }; + + DIE_NODE(ps_apcie_phy_sw): power-controller@580 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x580 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(apcie_phy_sw); + power-domains = <&DIE_NODE(ps_apcie_sys_gp)>, <&DIE_NODE(ps_apcie_sys_ge)>, <&DIE_NODE(ps_apcie_sys_st)>, <&DIE_NODE(ps_apcie_sys_st1)>; + }; + + DIE_NODE(ps_msr0_ase_core): power-controller@590 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x590 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(msr0_ase_core); + power-domains = <&DIE_NODE(ps_msr0)>; + }; + + DIE_NODE(ps_ane_mpm): power-controller@5a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ane_mpm); + power-domains = <&DIE_NODE(ps_ane_sys)>; + }; + + DIE_NODE(ps_ane_cpu): power-controller@5a8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ane_cpu); + power-domains = <&DIE_NODE(ps_ane_sys)>; + }; + + DIE_NODE(ps_ane_td): power-controller@5b8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ane_td); + power-domains = <&DIE_NODE(ps_ane_sys)>; + }; + + DIE_NODE(ps_ane_base): power-controller@5c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ane_base); + power-domains = <&DIE_NODE(ps_ane_td)>; + }; + + DIE_NODE(ps_sep): power-controller@c00 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xc00 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(sep); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc4_lw0)>; + }; + + DIE_NODE(ps_isp_cpu): power-controller@4008 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4008 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_cpu); + power-domains = <&DIE_NODE(ps_isp_sys)>; + }; + + DIE_NODE(ps_isp_fe): power-controller@4030 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4030 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_fe); + power-domains = <&DIE_NODE(ps_isp_sys)>; + }; + + DIE_NODE(ps_dprx): power-controller@4038 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4038 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dprx); + power-domains = <&DIE_NODE(ps_isp_fe)>; + }; + + DIE_NODE(ps_isp_secure): power-controller@4040 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4040 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_secure); + power-domains = <&DIE_NODE(ps_isp_fe)>; + }; + + DIE_NODE(ps_isp_be): power-controller@4048 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4048 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_be); + power-domains = <&DIE_NODE(ps_isp_fe)>; + }; + + DIE_NODE(ps_isp_clr): power-controller@4050 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4050 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(isp_clr); + power-domains = <&DIE_NODE(ps_isp_be)>; + }; + + DIE_NODE(ps_venc1_dma): power-controller@8000 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8000 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc1_dma); + power-domains = <&DIE_NODE(ps_venc1_sys)>; + }; + + DIE_NODE(ps_venc1_pipe4): power-controller@8008 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8008 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc1_pipe4); + power-domains = <&DIE_NODE(ps_venc1_dma)>; + }; + + DIE_NODE(ps_venc1_pipe5): power-controller@8010 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8010 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc1_pipe5); + power-domains = <&DIE_NODE(ps_venc1_dma)>; + }; + + DIE_NODE(ps_venc1_me0): power-controller@8018 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8018 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc1_me0); + power-domains = <&DIE_NODE(ps_venc1_dma)>; + }; + + DIE_NODE(ps_venc1_me1): power-controller@8020 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8020 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc1_me1); + power-domains = <&DIE_NODE(ps_venc1_me0)>; + }; +}; + +&DIE_NODE(pmgr1) { + DIE_NODE(ps_aic): power-controller@100 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x100 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(aic); + }; + + DIE_NODE(ps_dwi): power-controller@108 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x108 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dwi); + }; + + DIE_NODE(ps_sbr): power-controller@110 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x110 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(sbr); + apple,always-on; + }; + + DIE_NODE(ps_pms): power-controller@118 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x118 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pms); + apple,always-on; + }; + + DIE_NODE(ps_soc_dpe): power-controller@120 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x120 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(soc_dpe); + apple,always-on; + }; + + DIE_NODE(ps_pms_c1ppt): power-controller@128 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x128 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pms_c1ppt); + apple,always-on; + power-domains = <&DIE_NODE(ps_soc_dpe)>; + }; + + DIE_NODE(ps_pmgr_soc_ocla): power-controller@130 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x130 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pmgr_soc_ocla); + }; + + DIE_NODE(ps_pms_fpwm0): power-controller@138 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x138 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pms_fpwm0); + }; + + DIE_NODE(ps_pms_fpwm1): power-controller@140 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x140 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pms_fpwm1); + }; + + DIE_NODE(ps_pms_fpwm2): power-controller@148 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x148 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pms_fpwm2); + }; + + DIE_NODE(ps_pms_fpwm3): power-controller@150 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x150 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pms_fpwm3); + }; + + DIE_NODE(ps_pms_fpwm4): power-controller@158 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x158 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pms_fpwm4); + }; + + DIE_NODE(ps_gpio): power-controller@160 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x160 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(gpio); + power-domains = <&DIE_NODE(ps_sbr)>; + }; + + DIE_NODE(ps_msg): power-controller@168 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x168 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(msg); + }; + + DIE_NODE(ps_afc): power-controller@170 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x170 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afc); + apple,always-on; + }; + + DIE_NODE(ps_amcc0): power-controller@180 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x180 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(amcc0); + apple,always-on; + power-domains = <&DIE_NODE(ps_afc)>; + }; + + DIE_NODE(ps_amcc2): power-controller@190 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x190 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(amcc2); + apple,always-on; + power-domains = <&DIE_NODE(ps_afc)>; + }; + + DIE_NODE(ps_amcc4): power-controller@1a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(amcc4); + apple,always-on; + power-domains = <&DIE_NODE(ps_afc)>; + }; + + DIE_NODE(ps_amcc6): power-controller@1b0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(amcc6); + apple,always-on; + power-domains = <&DIE_NODE(ps_afc)>; + }; + + DIE_NODE(ps_dcs_00): power-controller@1c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_00); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc0)>; + }; + + DIE_NODE(ps_dcs_01): power-controller@1d0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_01); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc0)>; + }; + + DIE_NODE(ps_dcs_02): power-controller@1e0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_02); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc0)>; + }; + + DIE_NODE(ps_dcs_03): power-controller@1f0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_03); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc0)>; + }; + + DIE_NODE(ps_dcs_08): power-controller@200 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x200 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_08); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc2)>; + }; + + DIE_NODE(ps_dcs_09): power-controller@210 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x210 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_09); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc2)>; + }; + + DIE_NODE(ps_dcs_10): power-controller@220 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x220 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_10); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc2)>; + }; + + DIE_NODE(ps_dcs_11): power-controller@230 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x230 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_11); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc2)>; + }; + + DIE_NODE(ps_dcs_16): power-controller@240 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x240 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_16); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc4)>; + }; + + DIE_NODE(ps_dcs_17): power-controller@250 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x250 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_17); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc4)>; + }; + + DIE_NODE(ps_dcs_18): power-controller@260 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x260 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_18); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc4)>; + }; + + DIE_NODE(ps_dcs_19): power-controller@270 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x270 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_19); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc4)>; + }; + + DIE_NODE(ps_dcs_24): power-controller@280 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x280 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_24); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc6)>; + }; + + DIE_NODE(ps_dcs_25): power-controller@290 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x290 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_25); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc6)>; + }; + + DIE_NODE(ps_dcs_26): power-controller@2a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_26); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc6)>; + }; + + DIE_NODE(ps_afi): power-controller@2b0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afi); + apple,always-on; + }; + + DIE_NODE(ps_dcs_27): power-controller@2c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dcs_27); + apple,always-on; + power-domains = <&DIE_NODE(ps_amcc6)>; + }; + + DIE_NODE(ps_afi_d2d_0): power-controller@2d0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afi_d2d_0); + apple,always-on; + status = "disabled"; + }; + + DIE_NODE(ps_afi_d2d_1): power-controller@2e0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afi_d2d_1); + apple,always-on; + status = "disabled"; + }; + + DIE_NODE(ps_afc_d2d_0): power-controller@2f0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afc_d2d_0); + apple,always-on; + status = "disabled"; + }; + + DIE_NODE(ps_afc_d2d_1): power-controller@300 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x300 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afc_d2d_1); + apple,always-on; + status = "disabled"; + }; + + DIE_NODE(ps_afr_d2d_0): power-controller@310 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x310 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afr_d2d_0); + apple,always-on; + status = "disabled"; + }; + + DIE_NODE(ps_afr_d2d_1): power-controller@320 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x320 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afr_d2d_1); + apple,always-on; + status = "disabled"; + }; + + DIE_NODE(ps_afnc1_ioa): power-controller@330 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x330 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc1_ioa); + apple,always-on; + power-domains = <&DIE_NODE(ps_afi)>; + }; + + DIE_NODE(ps_afnc0_ioa): power-controller@340 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x340 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc0_ioa); + apple,always-on; + power-domains = <&DIE_NODE(ps_afi)>; + }; + + DIE_NODE(ps_afnc2_ioa): power-controller@350 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x350 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc2_ioa); + apple,always-on; + power-domains = <&DIE_NODE(ps_afi)>; + }; + + DIE_NODE(ps_afnc7_ioa): power-controller@360 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x360 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc7_ioa); + apple,always-on; + power-domains = <&DIE_NODE(ps_afi)>; + }; + + DIE_NODE(ps_afnc1_ls): power-controller@370 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x370 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc1_ls); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc1_ioa)>; + }; + + DIE_NODE(ps_afnc0_ls): power-controller@380 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x380 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc0_ls); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc0_ioa)>; + }; + + DIE_NODE(ps_afnc2_ls): power-controller@390 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x390 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc2_ls); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc2_ioa)>; + }; + + DIE_NODE(ps_afnc7_ls): power-controller@3a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc7_ls); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc7_ioa)>; + }; + + DIE_NODE(ps_afnc1_lw0): power-controller@3b0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc1_lw0); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc1_ls)>; + }; + + DIE_NODE(ps_afnc1_lw1): power-controller@3c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc1_lw1); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc1_ls)>; + }; + + DIE_NODE(ps_afnc0_lw0): power-controller@3d0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc0_lw0); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc0_ls)>; + }; + + DIE_NODE(ps_afnc2_lw0): power-controller@3e0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc2_lw0); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc2_ls)>; + }; + + DIE_NODE(ps_afnc2_lw1): power-controller@3f0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc2_lw1); + apple,always-on; + power-domains = <&DIE_NODE(ps_afnc2_ls)>; + }; + + DIE_NODE(ps_afnc7_lw0): power-controller@400 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x400 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afnc7_lw0); + apple,always-on; + }; + + DIE_NODE(ps_avd_sys): power-controller@410 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x410 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(avd_sys); + power-domains = <&DIE_NODE(ps_afnc1_lw0)>; + }; + + DIE_NODE(ps_jpg): power-controller@418 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x418 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(jpg); + power-domains = <&DIE_NODE(ps_afnc1_lw0)>; + }; + + DIE_NODE(ps_dispext3_sys): power-controller@420 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x420 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext3_sys); + power-domains = <&DIE_NODE(ps_afnc1_lw1)>; + }; + + DIE_NODE(ps_scodec): power-controller@428 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x428 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(scodec); + power-domains = <&DIE_NODE(ps_afnc1_lw1)>; + }; + + DIE_NODE(ps_venc0_sys): power-controller@430 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x430 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc0_sys); + power-domains = <&DIE_NODE(ps_afnc0_lw0)>; + }; + + DIE_NODE(ps_prores): power-controller@438 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x438 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(prores); + power-domains = <&DIE_NODE(ps_afnc0_lw0)>; + }; + + DIE_NODE(ps_dispext0_sys): power-controller@440 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x440 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext0_sys); + power-domains = <&DIE_NODE(ps_afnc2_lw0)>; + }; + + DIE_NODE(ps_atc0_common): power-controller@448 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x448 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc0_common); + power-domains = <&DIE_NODE(ps_afnc2_lw0)>; + }; + + DIE_NODE(ps_atc1_common): power-controller@450 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x450 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc1_common); + power-domains = <&DIE_NODE(ps_afnc2_lw1)>; + }; + + DIE_NODE(ps_atc2_common): power-controller@458 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x458 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc2_common); + power-domains = <&DIE_NODE(ps_afnc2_lw1)>; + }; + + DIE_NODE(ps_atc3_common): power-controller@460 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x460 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc3_common); + power-domains = <&DIE_NODE(ps_afnc2_lw1)>; + }; + + DIE_NODE(ps_trace_fab): power-controller@468 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x468 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(trace_fab); + power-domains = <&DIE_NODE(ps_afnc2_lw1)>; + }; + + DIE_NODE(ps_dispext1_sys): power-controller@470 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x470 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext1_sys); + power-domains = <&DIE_NODE(ps_afnc7_lw0)>; + }; + + DIE_NODE(ps_dispext2_sys): power-controller@478 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x478 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext2_sys); + power-domains = <&DIE_NODE(ps_afnc7_lw0)>; + }; + + DIE_NODE(ps_dispext3_fe): power-controller@480 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x480 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext3_fe); + power-domains = <&DIE_NODE(ps_dispext3_cpu)>; + }; + + DIE_NODE(ps_dispext3_cpu): power-controller@488 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x488 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext3_cpu); + power-domains = <&DIE_NODE(ps_dispext3_sys)>; + }; + + DIE_NODE(ps_scodec_streaming): power-controller@490 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x490 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(scodec_streaming); + power-domains = <&DIE_NODE(ps_scodec)>; + }; + + DIE_NODE(ps_venc0_dma): power-controller@498 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x498 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc0_dma); + power-domains = <&DIE_NODE(ps_venc0_sys)>; + }; + + DIE_NODE(ps_dispext0_fe): power-controller@4a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext0_fe); + power-domains = <&DIE_NODE(ps_dispext0_cpu)>; + }; + + DIE_NODE(ps_dispext0_cpu): power-controller@4a8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext0_cpu); + power-domains = <&DIE_NODE(ps_dispext0_sys)>; + }; + + DIE_NODE(ps_atc0_cio): power-controller@4b0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc0_cio); + power-domains = <&DIE_NODE(ps_atc0_common)>; + }; + + DIE_NODE(ps_atc0_pcie): power-controller@4b8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc0_pcie); + power-domains = <&DIE_NODE(ps_atc0_common)>; + }; + + DIE_NODE(ps_atc1_cio): power-controller@4c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc1_cio); + power-domains = <&DIE_NODE(ps_atc1_common)>; + }; + + DIE_NODE(ps_atc1_pcie): power-controller@4c8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4c8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc1_pcie); + power-domains = <&DIE_NODE(ps_atc1_common)>; + }; + + DIE_NODE(ps_atc2_cio): power-controller@4d0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc2_cio); + power-domains = <&DIE_NODE(ps_atc2_common)>; + }; + + DIE_NODE(ps_atc2_pcie): power-controller@4d8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4d8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc2_pcie); + power-domains = <&DIE_NODE(ps_atc2_common)>; + }; + + DIE_NODE(ps_atc3_cio): power-controller@4e0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc3_cio); + power-domains = <&DIE_NODE(ps_atc3_common)>; + }; + + DIE_NODE(ps_atc3_pcie): power-controller@4e8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4e8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc3_pcie); + power-domains = <&DIE_NODE(ps_atc3_common)>; + }; + + DIE_NODE(ps_dispext1_fe): power-controller@4f0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext1_fe); + power-domains = <&DIE_NODE(ps_dispext1_cpu)>; + }; + + DIE_NODE(ps_dispext1_cpu): power-controller@4f8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4f8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext1_cpu); + power-domains = <&DIE_NODE(ps_dispext1_sys)>; + }; + + DIE_NODE(ps_dispext2_fe): power-controller@500 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x500 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext2_fe); + power-domains = <&DIE_NODE(ps_dispext2_cpu)>; + }; + + DIE_NODE(ps_dispext2_cpu): power-controller@508 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x508 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(dispext2_cpu); + power-domains = <&DIE_NODE(ps_dispext2_sys)>; + }; + + DIE_NODE(ps_venc0_pipe4): power-controller@538 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x538 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc0_pipe4); + power-domains = <&DIE_NODE(ps_venc0_dma)>; + }; + + DIE_NODE(ps_venc0_pipe5): power-controller@540 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x540 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc0_pipe5); + power-domains = <&DIE_NODE(ps_venc0_dma)>; + }; + + DIE_NODE(ps_venc0_me0): power-controller@548 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x548 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc0_me0); + power-domains = <&DIE_NODE(ps_venc0_dma)>; + }; + + DIE_NODE(ps_pmp): power-controller@550 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x550 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pmp); + }; + + DIE_NODE(ps_pms_sram): power-controller@560 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x560 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(pms_sram); + }; + + DIE_NODE(ps_atc0_cio_pcie): power-controller@598 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x598 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc0_cio_pcie); + power-domains = <&DIE_NODE(ps_atc0_cio)>; + }; + + DIE_NODE(ps_atc0_cio_usb): power-controller@5a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc0_cio_usb); + power-domains = <&DIE_NODE(ps_atc0_cio)>; + }; + + DIE_NODE(ps_atc1_cio_pcie): power-controller@5a8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc1_cio_pcie); + power-domains = <&DIE_NODE(ps_atc1_cio)>; + }; + + DIE_NODE(ps_atc1_cio_usb): power-controller@5b0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc1_cio_usb); + power-domains = <&DIE_NODE(ps_atc1_cio)>; + }; + + DIE_NODE(ps_atc2_cio_pcie): power-controller@5b8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc2_cio_pcie); + power-domains = <&DIE_NODE(ps_atc2_cio)>; + }; + + DIE_NODE(ps_atc2_cio_usb): power-controller@5c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc2_cio_usb); + power-domains = <&DIE_NODE(ps_atc2_cio)>; + }; + + DIE_NODE(ps_atc3_cio_pcie): power-controller@5c8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5c8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc3_cio_pcie); + power-domains = <&DIE_NODE(ps_atc3_cio)>; + }; + + DIE_NODE(ps_atc3_cio_usb): power-controller@5d0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc3_cio_usb); + power-domains = <&DIE_NODE(ps_atc3_cio)>; + }; + + DIE_NODE(ps_venc0_me1): power-controller@638 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x638 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(venc0_me1); + power-domains = <&DIE_NODE(ps_venc0_me0)>; + }; + + DIE_NODE(ps_ap_tmm): power-controller@670 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x670 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(ap_tmm); + }; +}; + +&DIE_NODE(pmgr_mini) { + DIE_NODE(ps_debug_gated): power-controller@58 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x58 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(debug_gated); + apple,always-on; + }; + + DIE_NODE(ps_nub_spmi_ahb_fab): power-controller@60 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x60 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi_ahb_fab); + apple,always-on; + }; + + DIE_NODE(ps_nub_spmi0): power-controller@68 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x68 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi0); + apple,always-on; + power-domains = <&DIE_NODE(ps_nub_spmi_ahb_fab)>; + }; + + DIE_NODE(ps_nub_spmi_a0): power-controller@70 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x70 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi_a0); + apple,always-on; + }; + + DIE_NODE(ps_nub_spmi_a1): power-controller@78 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x78 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi_a1); + apple,always-on; + }; + + DIE_NODE(ps_nub_spmi_a2): power-controller@80 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x80 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi_a2); + apple,always-on; + }; + + DIE_NODE(ps_nub_aon): power-controller@90 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x90 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_aon); + apple,always-on; + }; + + DIE_NODE(ps_nub_gpio): power-controller@98 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x98 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_gpio); + apple,always-on; + }; + + DIE_NODE(ps_nub_ocla): power-controller@a0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xa0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_ocla); + apple,always-on; + }; + + DIE_NODE(ps_atc0_common_dp): power-controller@a8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xa8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc0_common_dp); + }; + + DIE_NODE(ps_atc1_common_dp): power-controller@b0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xb0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc1_common_dp); + }; + + DIE_NODE(ps_atc2_common_dp): power-controller@b8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xb8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc2_common_dp); + }; + + DIE_NODE(ps_atc3_common_dp): power-controller@c0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xc0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc3_common_dp); + }; + + DIE_NODE(ps_nub_spmi1): power-controller@c8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xc8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi1); + apple,always-on; + power-domains = <&DIE_NODE(ps_nub_spmi_ahb_fab)>; + }; + + DIE_NODE(ps_atc0_usb_aon): power-controller@d0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xd0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc0_usb_aon); + }; + + DIE_NODE(ps_atc1_usb_aon): power-controller@d8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xd8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc1_usb_aon); + }; + + DIE_NODE(ps_atc2_usb_aon): power-controller@e0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xe0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc2_usb_aon); + }; + + DIE_NODE(ps_atc3_usb_aon): power-controller@e8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xe8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc3_usb_aon); + }; + + DIE_NODE(ps_nub_spmi2): power-controller@f0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xf0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi2); + apple,always-on; + power-domains = <&DIE_NODE(ps_nub_spmi_ahb_fab)>; + }; + + DIE_NODE(ps_nub_spmi3): power-controller@f8 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xf8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi3); + apple,always-on; + power-domains = <&DIE_NODE(ps_nub_spmi_ahb_fab)>; + }; + + DIE_NODE(ps_nub_spmi4): power-controller@100 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x100 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi4); + apple,always-on; + power-domains = <&DIE_NODE(ps_nub_spmi_ahb_fab)>; + }; + + DIE_NODE(ps_nub_spmi5): power-controller@108 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x108 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_spmi5); + apple,always-on; + power-domains = <&DIE_NODE(ps_nub_spmi_ahb_fab)>; + }; + + DIE_NODE(ps_nub_fabric): power-controller@110 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x110 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_fabric); + apple,always-on; + }; + + DIE_NODE(ps_nub_sram): power-controller@120 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x120 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(nub_sram); + apple,always-on; + }; + + DIE_NODE(ps_debug_switch): power-controller@130 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x130 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(debug_switch); + apple,always-on; + }; + + DIE_NODE(ps_atc0_usb): power-controller@140 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x140 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc0_usb); + power-domains = <&DIE_NODE(ps_atc0_usb_aon)>, <&DIE_NODE(ps_atc0_common)>; + }; + + DIE_NODE(ps_atc1_usb): power-controller@148 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x148 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc1_usb); + power-domains = <&DIE_NODE(ps_atc1_usb_aon)>, <&DIE_NODE(ps_atc1_common)>; + }; + + DIE_NODE(ps_atc2_usb): power-controller@150 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x150 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc2_usb); + power-domains = <&DIE_NODE(ps_atc2_usb_aon)>, <&DIE_NODE(ps_atc2_common)>; + }; + + DIE_NODE(ps_atc3_usb): power-controller@158 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x158 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(atc3_usb); + power-domains = <&DIE_NODE(ps_atc3_usb_aon)>, <&DIE_NODE(ps_atc3_common)>; + }; + +#if 0 + /* MTP stuff is self-managed */ + DIE_NODE(ps_mtp_fabric): power-controller@2000 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2000 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_fabric); + apple,always-on; + power-domains = <&DIE_NODE(ps_nub_fabric)>; + }; + + DIE_NODE(ps_mtp_gpio): power-controller@2008 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2008 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_gpio); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_fabric)>; + }; + + DIE_NODE(ps_mtp_base): power-controller@2010 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2010 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_base); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_fabric)>; + }; + + DIE_NODE(ps_mtp_periph): power-controller@2018 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2018 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_periph); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_fabric)>; + }; + + DIE_NODE(ps_mtp_uart0): power-controller@2020 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2020 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_uart0); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_fabric)>; + }; + + DIE_NODE(ps_mtp_cpu): power-controller@2028 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2028 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_cpu); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_fabric)>; + }; + + DIE_NODE(ps_mtp_scm_fabric): power-controller@2030 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2030 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_scm_fabric); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_periph)>; + }; + + DIE_NODE(ps_mtp_spi0): power-controller@2038 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2038 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_spi0); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_fabric)>, <&DIE_NODE(ps_mtp_periph)>; + }; + + DIE_NODE(ps_mtp_i2cm0): power-controller@2040 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2040 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_i2cm0); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_fabric)>, <&DIE_NODE(ps_mtp_periph)>; + }; + + DIE_NODE(ps_mtp_sram): power-controller@2048 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2048 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_sram); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_cpu)>, <&DIE_NODE(ps_mtp_scm_fabric)>; + }; + + DIE_NODE(ps_mtp_dma): power-controller@2050 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2050 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(mtp_dma); + apple,always-on; + power-domains = <&DIE_NODE(ps_mtp_fabric)>, <&DIE_NODE(ps_mtp_sram)>; + }; +#endif +}; + +&DIE_NODE(pmgr_gfx) { + DIE_NODE(ps_gpx): power-controller@0 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(gpx); + apple,always-on; + }; + + DIE_NODE(ps_afr): power-controller@100 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x100 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(afr); + apple,always-on; + }; + + DIE_NODE(ps_gfx): power-controller@110 { + compatible = "apple,t6031-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x110 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = DIE_LABEL(gfx); + power-domains = <&DIE_NODE(ps_afr)>; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t6031.dtsi b/arch/arm64/boot/dts/apple/t6031.dtsi new file mode 100644 index 00000000000000..0059afe9a84455 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6031.dtsi @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T6031 "M3 Max" SoC + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include + +#include "multi-die-cpp.h" + +#include "t6031-base.dtsi" + +/ { + compatible = "apple,t6031", "apple,arm-platform"; + + #address-cells = <2>; + #size-cells = <2>; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + + ranges; + nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; + + // filled via templated includes at the end of the file + }; +}; + +#define DIE +#define DIE_NO 0 + +&soc { + #include "t6031-die0.dtsi" + #include "t6031-dieX.dtsi" +}; + +#include "t6031-gpio-pins.dtsi" +#include "t6031-pmgr.dtsi" + +#undef DIE +#undef DIE_NO diff --git a/arch/arm64/boot/dts/apple/t6032-j575d.dts b/arch/arm64/boot/dts/apple/t6032-j575d.dts new file mode 100644 index 00000000000000..56edfb1139fbf7 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6032-j575d.dts @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple Mac Studio (M3 Ultra, 2025) + * + * target-type: J575d + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t6032.dtsi" + +/ { + compatible = "apple,j575d", "apple,t6032", "apple,arm-platform"; + model = "Apple Mac Studio (M3 Ultra, 2025)"; + + aliases { + serial0 = &serial0; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + power-domains = <&ps_dispext0_cpu>; + }; + }; + + memory@10000000000 { + device_type = "memory"; + reg = <0x100 0 0x2 0>; /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t6032.dtsi b/arch/arm64/boot/dts/apple/t6032.dtsi new file mode 100644 index 00000000000000..2419cd2f24d7af --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6032.dtsi @@ -0,0 +1,419 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T6032 "M3 Ultra" SoC + * + * Other names: H15J, "Palma 2C" + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include + +#include "multi-die-cpp.h" + +#include "t6031-base.dtsi" + +/ { + compatible = "apple,t6032", "apple,arm-platform"; + + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster3 { + core0 { + cpu = <&cpu_e10>; + }; + core1 { + cpu = <&cpu_e11>; + }; + core2 { + cpu = <&cpu_e12>; + }; + core3 { + cpu = <&cpu_e13>; + }; + }; + + cluster4 { + core0 { + cpu = <&cpu_p20>; + }; + core1 { + cpu = <&cpu_p21>; + }; + core2 { + cpu = <&cpu_p22>; + }; + core3 { + cpu = <&cpu_p23>; + }; + core4 { + cpu = <&cpu_p24>; + }; + core5 { + cpu = <&cpu_p25>; + }; + }; + + cluster5 { + core0 { + cpu = <&cpu_p30>; + }; + core1 { + cpu = <&cpu_p31>; + }; + core2 { + cpu = <&cpu_p32>; + }; + core3 { + cpu = <&cpu_p33>; + }; + core4 { + cpu = <&cpu_p34>; + }; + core5 { + cpu = <&cpu_p35>; + }; + }; + }; + + cpu_e10: cpu@800 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x800>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_3>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e11: cpu@801 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x801>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_3>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e12: cpu@802 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x802>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_3>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e13: cpu@803 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x803>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_3>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_p20: cpu@10900 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10900>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_4>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p21: cpu@10901 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10901>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_4>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p22: cpu@10902 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10902>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_4>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p23: cpu@10903 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10903>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_4>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p24: cpu@10904 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10904>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_4>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p25: cpu@10905 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10105>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_4>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p30: cpu@10a00 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10a00>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_5>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p31: cpu@10a01 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10a01>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_5>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p32: cpu@10a02 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10a02>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_5>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p33: cpu@10a03 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10a03>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_5>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p34: cpu@10a04 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10a04>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_5>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p35: cpu@10a05 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10a05>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_5>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + l2_cache_3: l2-cache-3 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x400000>; + }; + + l2_cache_4: l2-cache-4 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x1000000>; + }; + + l2_cache_5: l2-cache-5 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x1000000>; + }; + }; + + die0: soc@200000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x02 0x00000000 0x02 0x00000000 0x4 0x00000000>, + <0x05 0x80000000 0x05 0x80000000 0x1 0x80000000>, + <0x07 0x00000000 0x07 0x00000000 0xf 0x80000000>, + <0x16 0x80000000 0x16 0x80000000 0x5 0x80000000>; + nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; + + // filled via templated includes at the end of the file + + aic: interrupt-controller@292400000 { + compatible = "apple,t8122-aic3"; + #interrupt-cells = <4>; + interrupt-controller; + + /* + * reg[0]: Main MMIO range (approx 1.8 MB) + * reg[1]: CPU Event/IACK register page (Base + 0x40000) + */ + reg = <0x00000002 0x92400000 0x00000000 0x1cc000>, + <0x00000002 0x92440000 0x00000000 0x4000>; + }; + }; + + die1: soc@2200000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x02 0x00000000 0x22 0x00000000 0x4 0x00000000>, + <0x07 0x00000000 0x27 0x00000000 0xf 0x80000000>, + <0x16 0x80000000 0x36 0x80000000 0x5 0x80000000>; + nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; + + // filled via templated includes at the end of the file + }; +}; + + +#define DIE +#define DIE_NO 0 + +&die0 { + #include "t6031-die0.dtsi" + #include "t6031-dieX.dtsi" +}; + +#include "t6031-pmgr.dtsi" +#include "t6031-gpio-pins.dtsi" + +#undef DIE +#undef DIE_NO + +#define DIE _die1 +#define DIE_NO 1 + +&die1 { + #include "t6031-dieX.dtsi" +}; + +#include "t6031-pmgr.dtsi" + +/delete-node/ &ps_pmp_die1; + +#undef DIE +#undef DIE_NO + +/* delete non-present DISP power-states */ +/delete-node/ &ps_disp_cpu; +/delete-node/ &ps_disp_cpu_die1; +/delete-node/ &ps_disp_fe; +/delete-node/ &ps_disp_fe_die1; +/delete-node/ &ps_disp_sys; +/delete-node/ &ps_disp_sys_die1; + +/* delete non-present ISP power-states */ +/delete-node/ &ps_dprx; +/delete-node/ &ps_dprx_die1; +/delete-node/ &ps_isp_be; +/delete-node/ &ps_isp_be_die1; +/delete-node/ &ps_isp_clr; +/delete-node/ &ps_isp_clr_die1; +/delete-node/ &ps_isp_cpu; +/delete-node/ &ps_isp_cpu_die1; +/delete-node/ &ps_isp_fe; +/delete-node/ &ps_isp_fe_die1; +/delete-node/ &ps_isp_secure; +/delete-node/ &ps_isp_secure_die1; +/delete-node/ &ps_isp_sys; +/delete-node/ &ps_isp_sys_die1; + +&ps_afi_d2d_0 { + status = "okay"; +}; +&ps_afi_d2d_0_die1 { + status = "okay"; +}; +&ps_afi_d2d_1 { + status = "okay"; +}; +&ps_afi_d2d_1_die1 { + status = "okay"; +}; +&ps_afc_d2d_0 { + status = "okay"; +}; +&ps_afc_d2d_0_die1{ + status = "okay"; +}; +&ps_afc_d2d_1 { + status = "okay"; +}; +&ps_afc_d2d_1_die1 { + status = "okay"; +}; +&ps_afr_d2d_0 { + status = "okay"; +}; +&ps_afr_d2d_0_die1 { + status = "okay"; +}; +&ps_afr_d2d_1 { + status = "okay"; +}; +&ps_afr_d2d_1_die1 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t6034-j514m.dts b/arch/arm64/boot/dts/apple/t6034-j514m.dts new file mode 100644 index 00000000000000..5e6a91aa333d6f --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6034-j514m.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * MacBook Pro (14-inch, M3 Max, 14 CPU cores, Nov 2023) + * + * target-type: J514m + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t6034.dtsi" +#include "t603x-j514-j516.dtsi" + +/ { + compatible = "apple,j514m", "apple,t6031", "apple,arm-platform"; + model = "Apple MacBook Pro (14-inch, M3 Max, 14 CPU cores, Nov 2023)"; +}; diff --git a/arch/arm64/boot/dts/apple/t6034-j516m.dts b/arch/arm64/boot/dts/apple/t6034-j516m.dts new file mode 100644 index 00000000000000..1a74cc182871e1 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6034-j516m.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * MacBook Pro (16-inch, M3 Max, 14 CPU cores, Nov 2023) + * + * target-type: J516m + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t6034.dtsi" +#include "t603x-j514-j516.dtsi" + +/ { + compatible = "apple,j514m", "apple,t6031", "apple,arm-platform"; + model = "Apple MacBook Pro (16-inch, M3 Max, 14 CPU cores, Nov 2023)"; +}; diff --git a/arch/arm64/boot/dts/apple/t6034.dtsi b/arch/arm64/boot/dts/apple/t6034.dtsi new file mode 100644 index 00000000000000..aa73af9c512dbc --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6034.dtsi @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T6034 "M3 Max" SoC + * + * Copyright The Asahi Linux Contributors + */ + +#include "t6031.dtsi" + +/ { + compatible = "apple,t6034", "apple,arm-platform"; +}; diff --git a/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi b/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi new file mode 100644 index 00000000000000..467d95cdaf6be8 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * MacBook Pro (14/16-inch, 2023) + * + * This file contains the parts common to J514 and J516 devices with t6030, + * t6031 and t6034. + * + * target-type: J514s / J514m / J514c / J516s / J516m / J516c + * + * Copyright The Asahi Linux Contributors + */ + +/* + * These models are essentially identical to the previous generations, other + * than the GPIO indices and using SPMI based USB Type-C port controllers. + */ + +#include + +/ { + chassis-type = "laptop"; + + aliases { + serial0 = &serial0; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + power-domains = <&ps_disp_fe>; + }; + }; + + memory@10000000000 { + device_type = "memory"; + reg = <0x100 0 0x2 0>; /* To be filled by loader */ + }; + + led-controller { + compatible = "pwm-leds"; + led-0 { + pwms = <&fpwm0 0 40000>; + label = "kbd_backlight"; + function = LED_FUNCTION_KBD_BACKLIGHT; + color = ; + max-brightness = <255>; + default-state = "keep"; + }; + }; +}; + +&serial0 { + status = "okay"; +}; + +&fpwm0 { + status = "okay"; +}; From 629bca65f0aa29df9e9670969ce5aabd8eaa46c0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 31 Jan 2026 16:51:18 +0100 Subject: [PATCH 111/352] arm64: dts: apple: Initial t6030 (M3 Pro) device trees Minimal device trees for the M3 Pro based 14-inch and 16-inch MacBook Pro released in November 2023. The M3 Pro appears to distinct chip design and not a cut down version of the Max variant like for M1 and M2 Pro. The M3 Pro has only a single cluster with up to 6 performance cores and one cluster with 6 efficiency cores. The device trees have devices nodes for CPU cores, timer, interrupt controller, power states, watchdog, serial, pin controller, i2c, PWM based keyboard LED illumination and the boot framebuffer. Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/Makefile | 2 + arch/arm64/boot/dts/apple/t6030-j514s.dts | 18 + arch/arm64/boot/dts/apple/t6030-j516s.dts | 18 + arch/arm64/boot/dts/apple/t6030-pmgr.dtsi | 1436 +++++++++++++++++++++ arch/arm64/boot/dts/apple/t6030.dtsi | 524 ++++++++ 5 files changed, 1998 insertions(+) create mode 100644 arch/arm64/boot/dts/apple/t6030-j514s.dts create mode 100644 arch/arm64/boot/dts/apple/t6030-j516s.dts create mode 100644 arch/arm64/boot/dts/apple/t6030-pmgr.dtsi create mode 100644 arch/arm64/boot/dts/apple/t6030.dtsi diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile index a22b4a8068b6aa..9fea43f760ec98 100644 --- a/arch/arm64/boot/dts/apple/Makefile +++ b/arch/arm64/boot/dts/apple/Makefile @@ -87,6 +87,8 @@ dtb-$(CONFIG_ARCH_APPLE) += t6021-j416c.dtb dtb-$(CONFIG_ARCH_APPLE) += t6020-j474s.dtb dtb-$(CONFIG_ARCH_APPLE) += t6021-j475c.dtb dtb-$(CONFIG_ARCH_APPLE) += t6022-j475d.dtb +dtb-$(CONFIG_ARCH_APPLE) += t6030-j514s.dtb +dtb-$(CONFIG_ARCH_APPLE) += t6030-j516s.dtb dtb-$(CONFIG_ARCH_APPLE) += t6031-j514c.dtb dtb-$(CONFIG_ARCH_APPLE) += t6031-j516c.dtb dtb-$(CONFIG_ARCH_APPLE) += t6032-j575d.dtb diff --git a/arch/arm64/boot/dts/apple/t6030-j514s.dts b/arch/arm64/boot/dts/apple/t6030-j514s.dts new file mode 100644 index 00000000000000..13572cb4ae9485 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6030-j514s.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * MacBook Pro (14-inch, M3 Pro, Nov 2023) + * + * target-type: J514s + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t6030.dtsi" +#include "t603x-j514-j516.dtsi" + +/ { + compatible = "apple,j514s", "apple,t6030", "apple,arm-platform"; + model = "Apple MacBook Pro (14-inch, M3 Pro, Nov 2023)"; +}; diff --git a/arch/arm64/boot/dts/apple/t6030-j516s.dts b/arch/arm64/boot/dts/apple/t6030-j516s.dts new file mode 100644 index 00000000000000..c16fbd6e2af80c --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6030-j516s.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * MacBook Pro (16-inch, M3 Pro, Nov 2023) + * + * target-type: J516s + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t6030.dtsi" +#include "t603x-j514-j516.dtsi" + +/ { + compatible = "apple,j516s", "apple,t6030", "apple,arm-platform"; + model = "Apple MacBook Pro (16-inch, M3 Pro, Nov 2023)"; +}; diff --git a/arch/arm64/boot/dts/apple/t6030-pmgr.dtsi b/arch/arm64/boot/dts/apple/t6030-pmgr.dtsi new file mode 100644 index 00000000000000..1d1cb599f76059 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6030-pmgr.dtsi @@ -0,0 +1,1436 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * PMGR Power domains for Apple T6030 "M3 Pro" SoC + * + * Copyright The Asahi Linux Contributors + */ + +&pmgr_gfx { + ps_gpx: power-controller@0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "gpx"; + apple,always-on; + }; + + ps_afr: power-controller@100 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x100 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "afr"; + apple,always-on; + }; + + ps_gfx: power-controller@110 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x110 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "gfx"; + power-domains = <&ps_gpx>, <&ps_afr>; + }; +}; + +&pmgr { + ps_msg: power-controller@108 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x108 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "msg"; + apple,always-on; + }; + + ps_aic: power-controller@110 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x110 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "aic"; + }; + + ps_dwi: power-controller@118 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x118 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dwi"; + }; + + ps_gpio: power-controller@120 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x120 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "gpio"; + }; + + ps_pms_fpwm0: power-controller@138 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x138 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pms_fpwm0"; + }; + + ps_pms_fpwm1: power-controller@140 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x140 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pms_fpwm1"; + }; + + ps_pms_fpwm2: power-controller@148 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x148 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pms_fpwm2"; + }; + + ps_pms_fpwm3: power-controller@150 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x150 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pms_fpwm3"; + }; + + ps_pms_fpwm4: power-controller@158 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x158 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pms_fpwm4"; + }; + + ps_pms_c1ppt: power-controller@160 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x160 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pms_c1ppt"; + }; + + ps_soc_rc: power-controller@168 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x168 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "soc_rc"; + }; + + ps_soc_dpe: power-controller@170 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x170 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "soc_dpe"; + apple,always-on; + }; + + ps_pmgr_soc_ocla: power-controller@178 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x178 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pmgr_soc_ocla"; + }; + + ps_ispsens0: power-controller@180 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x180 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ispsens0"; + }; + + ps_aft0: power-controller@190 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x190 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "aft0"; + }; + + ps_ap_tmm: power-controller@1a8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ap_tmm"; + }; + + ps_sio: power-controller@1b8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "sio"; + }; + + ps_disp_sys: power-controller@1c0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "disp_sys"; + }; + + ps_jpg: power-controller@1c8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1c8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "jpg"; + }; + + ps_sio_cpu: power-controller@1d0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "sio_cpu"; + power-domains = <&ps_sio>; + }; + + ps_fpwm0: power-controller@1d8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1d8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "fpwm0"; + power-domains = <&ps_sio>; + }; + + ps_fpwm1: power-controller@1e0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "fpwm1"; + power-domains = <&ps_sio>; + }; + + ps_fpwm2: power-controller@1e8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1e8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "fpwm2"; + power-domains = <&ps_sio>; + }; + + ps_i2c0: power-controller@1f0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c0"; + power-domains = <&ps_sio>; + }; + + ps_i2c1: power-controller@1f8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x1f8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c1"; + power-domains = <&ps_sio>; + }; + + ps_i2c2: power-controller@200 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x200 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c2"; + power-domains = <&ps_sio>; + }; + + ps_i2c3: power-controller@208 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x208 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c3"; + power-domains = <&ps_sio>; + }; + + ps_i2c4: power-controller@210 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x210 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c4"; + power-domains = <&ps_sio>; + }; + + ps_i2c5: power-controller@218 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x218 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c5"; + power-domains = <&ps_sio>; + }; + + ps_i2c6: power-controller@220 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x220 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c6"; + power-domains = <&ps_sio>; + }; + + ps_i2c7: power-controller@228 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x228 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c7"; + power-domains = <&ps_sio>; + }; + + ps_i2c8: power-controller@230 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x230 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "i2c8"; + power-domains = <&ps_sio>; + }; + + ps_spi_p: power-controller@238 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x238 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "spi_p"; + power-domains = <&ps_sio>; + }; + + ps_uart_p: power-controller@240 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x240 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart_p"; + power-domains = <&ps_sio>; + }; + + ps_audio_p: power-controller@248 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x248 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "audio_p"; + power-domains = <&ps_sio>; + }; + + ps_aes: power-controller@250 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x250 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "aes"; + power-domains = <&ps_sio>; + }; + + ps_disp_fe: power-controller@258 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x258 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "disp_fe"; + power-domains = <&ps_disp_sys>; + }; + + ps_spi0: power-controller@260 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x260 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "spi0"; + power-domains = <&ps_spi_p>; + }; + + ps_spi1: power-controller@268 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x268 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "spi1"; + power-domains = <&ps_spi_p>; + }; + + ps_spi2: power-controller@270 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x270 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "spi2"; + power-domains = <&ps_spi_p>; + }; + + ps_spi3: power-controller@278 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x278 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "spi3"; + power-domains = <&ps_spi_p>; + }; + + ps_spi4: power-controller@280 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x280 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "spi4"; + power-domains = <&ps_spi_p>; + }; + + ps_spi5: power-controller@288 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x288 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "spi5"; + power-domains = <&ps_spi_p>; + }; + + ps_qspi: power-controller@290 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x290 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "qspi"; + power-domains = <&ps_spi_p>; + }; + + ps_uart_n: power-controller@298 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x298 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart_n"; + power-domains = <&ps_uart_p>; + }; + + ps_uart0: power-controller@2a0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart0"; + power-domains = <&ps_uart_p>; + }; + + ps_uart1: power-controller@2a8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart1"; + power-domains = <&ps_uart_p>; + }; + + ps_uart2: power-controller@2b0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart2"; + power-domains = <&ps_uart_p>; + }; + + ps_uart3: power-controller@2b8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart3"; + power-domains = <&ps_uart_p>; + }; + + ps_uart4: power-controller@2c0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart4"; + power-domains = <&ps_uart_p>; + }; + + ps_uart5: power-controller@2c8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2c8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart5"; + power-domains = <&ps_uart_p>; + }; + + ps_uart6: power-controller@2d0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "uart6"; + power-domains = <&ps_uart_p>; + }; + + ps_sio_adma: power-controller@2d8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2d8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "sio_adma"; + power-domains = <&ps_audio_p>; + }; + + ps_dpa0: power-controller@2e0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dpa0"; + apple,always-on; + power-domains = <&ps_audio_p>; + }; + + ps_dpa1: power-controller@2e8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2e8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dpa1"; + apple,always-on; + power-domains = <&ps_audio_p>; + }; + + ps_dpa2: power-controller@2f0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dpa2"; + apple,always-on; + power-domains = <&ps_audio_p>; + }; + + ps_dpa3: power-controller@2f8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x2f8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dpa3"; + apple,always-on; + power-domains = <&ps_audio_p>; + }; + + ps_dpa4: power-controller@300 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x300 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dpa4"; + apple,always-on; + power-domains = <&ps_audio_p>; + }; + + ps_mca0: power-controller@308 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x308 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "mca0"; + power-domains = <&ps_sio_adma>, <&ps_audio_p>; + }; + + ps_dcs0: power-controller@320 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x320 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs0"; + apple,always-on; + }; + + ps_dcs2: power-controller@328 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x328 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs2"; + apple,always-on; + }; + + ps_dcs1: power-controller@330 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x330 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs1"; + apple,always-on; + }; + + ps_dcs3: power-controller@338 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x338 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs3"; + apple,always-on; + }; + + ps_dcs4: power-controller@340 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x340 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs4"; + apple,always-on; + }; + + ps_dcs5: power-controller@348 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x348 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs5"; + apple,always-on; + }; + + ps_dcs6: power-controller@358 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x358 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs6"; + apple,always-on; + }; + + ps_dcs7: power-controller@360 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x360 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs7"; + apple,always-on; + }; + + ps_dcs8: power-controller@368 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x368 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs8"; + apple,always-on; + }; + + ps_dcs9: power-controller@370 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x370 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs9"; + apple,always-on; + }; + + ps_dcs10: power-controller@378 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x378 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs10"; + apple,always-on; + }; + + ps_dcs11: power-controller@380 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x380 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dcs11"; + apple,always-on; + }; + + ps_mca1: power-controller@388 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x388 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "mca1"; + power-domains = <&ps_sio_adma>, <&ps_audio_p>; + }; + + ps_mca2: power-controller@390 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x390 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "mca2"; + power-domains = <&ps_sio_adma>, <&ps_audio_p>; + }; + + ps_mca3: power-controller@398 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x398 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "mca3"; + power-domains = <&ps_sio_adma>, <&ps_audio_p>; + }; + + ps_ioa1: power-controller@3a0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ioa1"; + apple,always-on; + }; + + ps_ls1: power-controller@3a8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ls1"; + apple,always-on; + power-domains = <&ps_ioa1>; + }; + + ps_lw10: power-controller@3b0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "lw10"; + apple,always-on; + power-domains = <&ps_ls1>; + }; + + ps_dispext0_sys: power-controller@3b8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dispext0_sys"; + power-domains = <&ps_lw10>; + }; + + ps_dispext1_sys: power-controller@3c0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dispext1_sys"; + power-domains = <&ps_lw10>; + }; + + ps_isp_sys: power-controller@3c8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3c8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_sys"; + power-domains = <&ps_lw10>; + }; + + ps_venc_sys: power-controller@3d0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "venc_sys"; + power-domains = <&ps_lw10>; + }; + + ps_dispext0_fe: power-controller@3d8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3d8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dispext0_fe"; + power-domains = <&ps_dispext0_sys>; + }; + + ps_dispext0_cpu: power-controller@3e0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dispext0_cpu"; + power-domains = <&ps_dispext0_fe>; + }; + + ps_trace_fab: power-controller@3e8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3e8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "trace_fab"; + }; + + ps_dispext1_fe: power-controller@3f0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dispext1_fe"; + power-domains = <&ps_dispext1_sys>; + }; + + ps_dispext1_cpu: power-controller@3f8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x3f8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dispext1_cpu"; + power-domains = <&ps_dispext1_fe>; + }; + + ps_dptx_phy: power-controller@408 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x408 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dptx_phy"; + apple,always-on; + }; + + ps_avd_sys: power-controller@490 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x490 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "avd_sys"; + }; + + ps_ane_sys: power-controller@498 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x498 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ane_sys"; + }; + + ps_scodec: power-controller@4a0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "scodec"; + }; + + ps_scodec_stream: power-controller@4a8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "scodec_stream"; + power-domains = <&ps_scodec>; + }; + + ps_ioa3: power-controller@4b0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ioa3"; + apple,always-on; + }; + + ps_ls3: power-controller@4b8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ls3"; + apple,always-on; + power-domains = <&ps_ioa3>; + }; + + ps_lw30: power-controller@4c0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4c0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "lw30"; + apple,always-on; + power-domains = <&ps_ls3>; + }; + + ps_pmp: power-controller@4c8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4c8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pmp"; + }; + + ps_pms_sram: power-controller@4d0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4d0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "pms_sram"; + }; + + ps_lw31: power-controller@4d8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4d8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "lw31"; + apple,always-on; + power-domains = <&ps_ls3>; + }; + + ps_atc0_common: power-controller@4e0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4e0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc0_common"; + power-domains = <&ps_lw30>; + }; + + ps_atc1_common: power-controller@4e8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4e8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc1_common"; + power-domains = <&ps_lw30>; + }; + + ps_atc2_common: power-controller@4f0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4f0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc2_common"; + power-domains = <&ps_lw30>; + }; + + ps_atc3_common: power-controller@4f8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4f8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc3_common"; + power-domains = <&ps_lw30>; + }; + + ps_apcie_gp: power-controller@500 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x500 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "apcie_gp"; + power-domains = <&ps_lw31>; + }; + + ps_msr: power-controller@508 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x508 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "msr"; + power-domains = <&ps_lw31>; + }; + + ps_ans: power-controller@510 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x510 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "ans"; + power-domains = <&ps_lw31>; + }; + + ps_atc0_pcie: power-controller@518 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x518 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc0_pcie"; + power-domains = <&ps_atc0_common>; + }; + + ps_atc0_cio: power-controller@520 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x520 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc0_cio"; + power-domains = <&ps_atc0_common>; + }; + + ps_atc1_pcie: power-controller@528 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x528 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc1_pcie"; + power-domains = <&ps_atc1_common>; + }; + + ps_atc1_cio: power-controller@530 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x530 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc1_cio"; + power-domains = <&ps_atc1_common>; + }; + + ps_atc2_pcie: power-controller@538 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x538 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc2_pcie"; + power-domains = <&ps_atc2_common>; + }; + + ps_atc2_cio: power-controller@540 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x540 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc2_cio"; + power-domains = <&ps_atc2_common>; + }; + + ps_atc3_pcie: power-controller@548 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x548 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc3_pcie"; + power-domains = <&ps_atc3_common>; + }; + + ps_atc3_cio: power-controller@550 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x550 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc3_cio"; + power-domains = <&ps_atc3_common>; + }; + + ps_apcie_sys_gp: power-controller@558 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x558 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "apcie_sys_gp"; + power-domains = <&ps_apcie_gp>; + }; + + ps_msr_ase_core: power-controller@560 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x560 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "msr_ase_core"; + power-domains = <&ps_msr>; + }; + + ps_apcie_st: power-controller@568 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x568 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "apcie_st"; + power-domains = <&ps_ans>; + }; + + ps_atc0_cio_pcie: power-controller@570 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x570 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc0_cio_pcie"; + power-domains = <&ps_atc0_cio>; + }; + + ps_atc0_cio_usb: power-controller@578 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x578 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc0_cio_usb"; + power-domains = <&ps_atc0_cio>; + }; + + ps_atc1_cio_pcie: power-controller@580 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x580 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc1_cio_pcie"; + power-domains = <&ps_atc1_cio>; + }; + + ps_atc1_cio_usb: power-controller@588 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x588 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc1_cio_usb"; + power-domains = <&ps_atc1_cio>; + }; + + ps_atc2_cio_pcie: power-controller@590 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x590 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc2_cio_pcie"; + power-domains = <&ps_atc2_cio>; + }; + + ps_atc2_cio_usb: power-controller@598 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x598 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc2_cio_usb"; + power-domains = <&ps_atc2_cio>; + }; + + ps_atc3_cio_pcie: power-controller@5a0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5a0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc3_cio_pcie"; + power-domains = <&ps_atc3_cio>; + }; + + ps_atc3_cio_usb: power-controller@5a8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5a8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc3_cio_usb"; + power-domains = <&ps_atc3_cio>; + }; + + ps_apcie_sys_st: power-controller@5b0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5b0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "apcie_sys_st"; + power-domains = <&ps_ans>, <&ps_apcie_st>; + }; + + ps_apcie_phy_sw: power-controller@5b8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x5b8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "apcie_phy_sw"; + power-domains = <&ps_apcie_sys_st>, <&ps_apcie_sys_gp>; + }; + + ps_sep: power-controller@c00 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xc00 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "sep"; + apple,always-on; + }; + + ps_isp_cpu: power-controller@4000 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4000 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_cpu"; + power-domains = <&ps_isp_sys>; + }; + + ps_isp_fe: power-controller@4008 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4008 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_fe"; + power-domains = <&ps_isp_sys>; + }; + + ps_dprx: power-controller@4010 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4010 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "dprx"; + power-domains = <&ps_isp_fe>; + }; + + ps_isp_secure: power-controller@4018 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4018 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_secure"; + power-domains = <&ps_isp_fe>; + }; + + ps_isp_be: power-controller@4020 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4020 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_be"; + power-domains = <&ps_isp_fe>; + }; + + ps_isp_clr: power-controller@4028 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x4028 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "isp_clr"; + power-domains = <&ps_isp_be>; + }; + + ps_venc_dma: power-controller@8000 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8000 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "venc_dma"; + power-domains = <&ps_venc_sys>; + }; + + ps_venc_pipe4: power-controller@8008 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8008 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "venc_pipe4"; + power-domains = <&ps_venc_dma>; + }; + + ps_venc_pipe5: power-controller@8010 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8010 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "venc_pipe5"; + power-domains = <&ps_venc_dma>; + }; + + ps_venc_me0: power-controller@8018 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8018 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "venc_me0"; + power-domains = <&ps_venc_dma>; + }; + + ps_venc_me1: power-controller@8020 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x8020 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "venc_me1"; + power-domains = <&ps_venc_me0>; + }; + + ps_disp_cpu: power-controller@10000 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x10000 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "disp_cpu"; + power-domains = <&ps_disp_fe>; + }; +}; + +&pmgr_mini { + ps_debug_gated: power-controller@0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "debug_gated"; + apple,always-on; + }; + + ps_nub_spmi0: power-controller@58 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x58 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_spmi0"; + apple,always-on; + }; + + ps_nub_spmi1: power-controller@60 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x60 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_spmi1"; + apple,always-on; + }; + + ps_nub_spmi2: power-controller@68 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x68 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_spmi2"; + apple,always-on; + }; + + ps_nub_spmi_a0: power-controller@70 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x70 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_spmi_a0"; + apple,always-on; + }; + + ps_nub_spmi_a1: power-controller@78 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x78 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_spmi_a1"; + apple,always-on; + }; + + ps_nub_spi0: power-controller@88 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x88 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_spi0"; + apple,always-on; + }; + + ps_nub_ocla: power-controller@90 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x90 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_ocla"; + apple,always-on; + }; + + ps_nub_gpio: power-controller@98 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0x98 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_gpio"; + apple,always-on; + }; + + ps_nub_sram: power-controller@a8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xa8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "nub_sram"; + apple,always-on; + }; + + ps_debug_switch: power-controller@b0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xb0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "debug_switch"; + apple,always-on; + }; + + ps_atc0_usb_aon: power-controller@b8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xb8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc0_usb_aon"; + }; + + ps_atc1_usb_aon: power-controller@c0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xc0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc1_usb_aon"; + }; + + ps_atc2_usb_aon: power-controller@c8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xc8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc2_usb_aon"; + }; + + ps_atc3_usb_aon: power-controller@d0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xd0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc3_usb_aon"; + }; + + ps_atc0_usb: power-controller@d8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xd8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc0_usb"; + power-domains = <&ps_atc0_usb_aon>, <&ps_atc0_common>; + }; + + ps_atc1_usb: power-controller@e0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xe0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc1_usb"; + power-domains = <&ps_atc1_usb_aon>, <&ps_atc1_common>; + }; + + ps_atc2_usb: power-controller@e8 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xe8 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc2_usb"; + power-domains = <&ps_atc2_usb_aon>, <&ps_atc2_common>; + }; + + ps_atc3_usb: power-controller@f0 { + compatible = "apple,t6030-pmgr-pwrstate", "apple,t8103-pmgr-pwrstate"; + reg = <0xf0 4>; + #power-domain-cells = <0>; + #reset-cells = <0>; + label = "atc3_usb"; + power-domains = <&ps_atc3_usb_aon>, <&ps_atc3_common>; + }; +}; + diff --git a/arch/arm64/boot/dts/apple/t6030.dtsi b/arch/arm64/boot/dts/apple/t6030.dtsi new file mode 100644 index 00000000000000..40dc9b9019df63 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t6030.dtsi @@ -0,0 +1,524 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T6030 "M3 Pro" SoC + * + * Other names: H15J, "Lobos" + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include + +/ { + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu_e00>; + }; + core1 { + cpu = <&cpu_e01>; + }; + core2 { + cpu = <&cpu_e02>; + }; + core3 { + cpu = <&cpu_e03>; + }; + core4 { + cpu = <&cpu_e04>; + }; + core5 { + cpu = <&cpu_e05>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu_p00>; + }; + core1 { + cpu = <&cpu_p01>; + }; + core2 { + cpu = <&cpu_p02>; + }; + core3 { + cpu = <&cpu_p03>; + }; + core4 { + cpu = <&cpu_p04>; + }; + core5 { + cpu = <&cpu_p05>; + }; + }; + }; + + cpu_e00: cpu@0 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e01: cpu@1 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e02: cpu@2 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e03: cpu@3 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e04: cpu@4 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x4>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_e05: cpu@5 { + compatible = "apple,sawtooth"; + device_type = "cpu"; + reg = <0x0 0x5>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* to be filled by loader */ + next-level-cache = <&l2_cache_0>; + i-cache-size = <0x20000>; + d-cache-size = <0x10000>; + }; + + cpu_p00: cpu@10100 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p01: cpu@10101 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p02: cpu@10102 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10102>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p03: cpu@10103 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10103>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p04: cpu@10104 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10104>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + cpu_p05: cpu@10105 { + compatible = "apple,everest"; + device_type = "cpu"; + reg = <0x0 0x10105>; + enable-method = "spin-table"; + cpu-release-addr = <0 0>; /* To be filled by loader */ + next-level-cache = <&l2_cache_1>; + i-cache-size = <0x30000>; + d-cache-size = <0x20000>; + }; + + l2_cache_0: l2-cache-0 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x400000>; + }; + + l2_cache_1: l2-cache-1 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x1000000>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt", "hyp-phys", "hyp-virt"; + interrupts = , + , + , + ; + }; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + + ranges; + nonposted-mmio; + /* Required to get >32-bit DMA via DARTs */ + dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>; + + i2c1: i2c@289014000 { + compatible = "apple,t6030-i2c", "apple,t8103-i2c"; + reg = <0x2 0x89014000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + #address-cells = <0x1>; + #size-cells = <0x0>; + power-domains = <&ps_i2c1>; + status = "disabled"; + }; + + i2c2: i2c@289018000 { + compatible = "apple,t6030-i2c", "apple,t8103-i2c"; + reg = <0x2 0x89018000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + #address-cells = <0x1>; + #size-cells = <0x0>; + power-domains = <&ps_i2c2>; + status = "disabled"; + }; + + i2c3: i2c@28901c000 { + compatible = "apple,t6030-i2c", "apple,t8103-i2c"; + reg = <0x2 0x8901c000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c3_pins>; + pinctrl-names = "default"; + #address-cells = <0x1>; + #size-cells = <0x0>; + power-domains = <&ps_i2c3>; + status = "disabled"; + }; + + i2c4: i2c@289020000 { + compatible = "apple,t6030-i2c", "apple,t8103-i2c"; + reg = <0x2 0x89020000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c4_pins>; + pinctrl-names = "default"; + #address-cells = <0x1>; + #size-cells = <0x0>; + power-domains = <&ps_i2c4>; + status = "disabled"; + }; + + i2c6: i2c@289028000 { + compatible = "apple,t6030-i2c", "apple,t8103-i2c"; + reg = <0x2 0x89028000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c6_pins>; + pinctrl-names = "default"; + #address-cells = <0x1>; + #size-cells = <0x0>; + power-domains = <&ps_i2c6>; + status = "disabled"; + }; + + i2c8: i2c@289030000 { + compatible = "apple,t6030-i2c", "apple,t8103-i2c"; + reg = <0x2 0x89030000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + pinctrl-0 = <&i2c8_pins>; + pinctrl-names = "default"; + #address-cells = <0x1>; + #size-cells = <0x0>; + power-domains = <&ps_i2c8>; + status = "disabled"; + }; + + fpwm0: pwm@289040000 { + compatible = "apple,t6030-fpwm", "apple,s5l-fpwm"; + reg = <0x2 0x89040000 0x0 0x4000>; + power-domains = <&ps_fpwm0>; + clocks = <&clkref>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmgr_gfx: power-management@290e80000 { + compatible = "apple,t6030-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + reg = <0x2 0x90e80000 0 0x4000>; + /* child nodes are added in t6030-pmgr.dtsi */ + }; + + serial0: serial@2892000000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x89200000 0x0 0x1000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* + * TODO: figure out the clocking properly, there may + * be a third selectable clock. + */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + power-domains = <&ps_uart0>; + status = "disabled"; + }; + + pinctrl_ap: pinctrl@347100000 { + compatible = "apple,t6030-pinctrl", "apple,t8103-pinctrl"; + reg = <0x3 0x47100000 0x0 0x4000>; + + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + + power-domains = <&ps_gpio>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_ap 0 0 224>; + apple,npins = <224>; + + interrupt-controller; + #interrupt-cells = <2>; + + i2c1_pins: i2c1-pins { + pinmux = , + ; + }; + + i2c2_pins: i2c2-pins { + pinmux = , + ; + }; + + i2c3_pins: i2c3-pins { + pinmux = , + ; + }; + + i2c4_pins: i2c4-pins { + pinmux = , + ; + }; + + i2c6_pins: i2c6-pins { + pinmux = , + ; + }; + + i2c8_pins: i2c8-pins { + pinmux = , + ; + }; + }; + + pmgr: power-management@350700000 { + compatible = "apple,t6030-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + reg = <0x3 0x50700000 0 0x10000>; + /* child nodes are added in t6030-pmgr.dtsi */ + }; + + aic: interrupt-controller@351000000 { + compatible = "apple,t6030-aic3", "apple,t8122-aic3"; + #interrupt-cells = <3>; + interrupt-controller; + + reg = <0x3 0x51000000 0x0 0x184000>, + <0x3 0x51040000 0x0 0x4000>; + reg-names = "core", "event"; + power-domains = <&ps_aic>; + }; + + pinctrl_nub: pinctrl@3641f0000 { + compatible = "apple,t6030-pinctrl", "apple,t8103-pinctrl"; + reg = <0x3 0x641f0000 0x0 0x4000>; + + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_ap 0 0 37>; + apple,npins = <37>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + pmgr_mini: power-management@364280000 { + compatible = "apple,t6030-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + reg = <0x3 0x64280000 0 0x4000>; + /* child nodes are added in t6030-pmgr.dtsi */ + }; + + wdt: watchdog@3642b0000 { + compatible = "apple,t6030-wdt", "apple,t8103-wdt"; + reg = <0x3 0x642b0000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + pinctrl_smc: pinctrl@36c820000 { + compatible = "apple,t6030-pinctrl", "apple,t8103-pinctrl"; + reg = <0x3 0x6c820000 0x0 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_smc 0 0 18>; + apple,npins = <18>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + pinctrl_aop: pinctrl@374824000 { + compatible = "apple,t6030-pinctrl", "apple,t8103-pinctrl"; + reg = <0x3 0x74824000 0x0 0x4000>; + + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + + clocks = <&clkref>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_ap 0 0 54>; + apple,npins = <54>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; + +#include "t6030-pmgr.dtsi" From 66bff25252bfad1ee4298c3c998404e8f92f19e8 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 11 Apr 2023 01:32:06 +0900 Subject: [PATCH 112/352] iommu: apple-dart: Support specifying the DMA aperture in the DT Apple DARTs are often connected directly to devices that expect only a portion of their address space to be used for DMA (for example, because other ranges are mapped directly to something else). Add an apple,dma-range property to allow specifying this range. This range *can* be outside of the DART's IAS. In that case, it is assumed that the hardware truncates addresses and the page tables will only map the lower bits of the address. However, the specified range cannot straddle an IAS boundary (you cannot cover more than IAS worth of address space nor wrap). This corresponds to the vm-base and vm-size properties on the Apple device tree side of things. Signed-off-by: Hector Martin --- drivers/iommu/apple-dart.c | 51 ++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index de0da076ab4f1a..ac5d87b76f7ad2 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,9 @@ struct apple_dart { u32 supports_bypass : 1; u32 four_level : 1; + dma_addr_t dma_min; + dma_addr_t dma_max; + struct iommu_group *sid2group[DART_MAX_STREAMS]; struct iommu_device iommu; @@ -268,6 +272,7 @@ struct apple_dart_domain { struct io_pgtable_ops *pgtbl_ops; bool finalized; + u64 mask; struct mutex init_lock; struct apple_dart_atomic_stream_map stream_maps[MAX_DARTS_PER_DEVICE]; @@ -540,7 +545,7 @@ static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain, if (!ops) return 0; - return ops->iova_to_phys(ops, iova); + return ops->iova_to_phys(ops, iova & dart_domain->mask); } static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova, @@ -554,8 +559,8 @@ static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova, if (!ops) return -ENODEV; - return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp, - mapped); + return ops->map_pages(ops, iova & dart_domain->mask, paddr, pgsize, + pgcount, prot, gfp, mapped); } static size_t apple_dart_unmap_pages(struct iommu_domain *domain, @@ -566,7 +571,8 @@ static size_t apple_dart_unmap_pages(struct iommu_domain *domain, struct apple_dart_domain *dart_domain = to_dart_domain(domain); struct io_pgtable_ops *ops = dart_domain->pgtbl_ops; - return ops->unmap_pages(ops, iova, pgsize, pgcount, gather); + return ops->unmap_pages(ops, iova & dart_domain->mask, pgsize, pgcount, + gather); } static void @@ -593,6 +599,8 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain, { struct apple_dart *dart = cfg->stream_maps[0].dart; struct io_pgtable_cfg pgtbl_cfg; + dma_addr_t dma_max = dart->dma_max; + u32 ias = min_t(u32, dart->ias, fls64(dma_max)); int ret = 0; int i, j; @@ -613,7 +621,7 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain, pgtbl_cfg = (struct io_pgtable_cfg){ .pgsize_bitmap = dart->pgsize, - .ias = dart->ias, + .ias = ias, .oas = dart->oas, .coherent_walk = 1, .iommu_dev = dart->dev, @@ -626,10 +634,16 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain, goto done; } + if (pgtbl_cfg.pgsize_bitmap == SZ_4K) + dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 32)); + else if (pgtbl_cfg.apple_dart_cfg.n_levels == 3) + dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 36)); + else if (pgtbl_cfg.apple_dart_cfg.n_levels == 4) + dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 47)); + dart_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; - dart_domain->domain.geometry.aperture_start = 0; - dart_domain->domain.geometry.aperture_end = - (dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias); + dart_domain->domain.geometry.aperture_start = dart->dma_min; + dart_domain->domain.geometry.aperture_end = dma_max; dart_domain->domain.geometry.force_aperture = true; dart_domain->finalized = true; @@ -1142,6 +1156,7 @@ static int apple_dart_probe(struct platform_device *pdev) struct resource *res; struct apple_dart *dart; struct device *dev = &pdev->dev; + u64 dma_range[2]; dart = devm_kzalloc(dev, sizeof(*dart), GFP_KERNEL); if (!dart) @@ -1204,6 +1219,26 @@ static int apple_dart_probe(struct platform_device *pdev) break; } + dart->dma_min = 0; + dart->dma_max = DMA_BIT_MASK(dart->ias); + + ret = of_property_read_u64_array(dev->of_node, "apple,dma-range", dma_range, 2); + if (ret == -EINVAL) { + ret = 0; + } else if (ret) { + goto err_clk_disable; + } else { + dart->dma_min = dma_range[0]; + dart->dma_max = dma_range[0] + dma_range[1] - 1; + if ((dart->dma_min ^ dart->dma_max) & ~DMA_BIT_MASK(dart->ias)) { + dev_err(&pdev->dev, "Invalid DMA range for ias=%d\n", + dart->ias); + goto err_clk_disable; + } + dev_info(&pdev->dev, "Limiting DMA range to %pad..%pad\n", + &dart->dma_min, &dart->dma_max); + } + if (dart->num_streams > DART_MAX_STREAMS) { dev_err(&pdev->dev, "Too many streams (%d > %d)\n", dart->num_streams, DART_MAX_STREAMS); From 9d24b2532b22deb13c746fe64c60c216f1ee0d66 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 23 Nov 2023 18:08:50 +0900 Subject: [PATCH 113/352] iommu: apple-dart: Check for fwspec in the device probe path We need to check for a fwspec in the probe path, to ensure that the driver does not probe as a bus iommu driver. This, along with related fixes to the IOMMU core code, fixes races and issues when multiple IOMMUs assigned to the same device probe at different times. Suggested-by: Jason Gunthorpe Signed-off-by: Hector Martin iommu: apple-dart: --- drivers/iommu/apple-dart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index ac5d87b76f7ad2..1c4ff4355b168d 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -782,7 +782,7 @@ static struct iommu_device *apple_dart_probe_device(struct device *dev) struct apple_dart_stream_map *stream_map; int i; - if (!cfg) + if (!dev_iommu_fwspec_get(dev) || !cfg) return ERR_PTR(-ENODEV); for_each_stream_map(i, cfg, stream_map) From e13a507bc677cfdc89ad47ecbbec0edb363f28d7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 24 Mar 2024 18:06:46 +0100 Subject: [PATCH 114/352] iommu/of: Free fwspec on probe deferrel For devices with multiple iommus of_iommu_configure_device() potentially inits the fwspec for one of the iommus but another iommu device might have not yet been probe resulting in -EPROBE_DEFER. Clear the fwspec in such cases to ensure the next of_iommu_configure() call retries to configure all iommus. Signed-off-by: Janne Grunau --- drivers/iommu/of_iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 6b989a62def20e..1ccd33b9f351bf 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -147,6 +147,8 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np, of_pci_check_device_ats(dev, master_np); } else { err = of_iommu_configure_device(master_np, dev, id); + if (err == -EPROBE_DEFER) + iommu_fwspec_free(dev); } if (err && dev_iommu_present) From f3263e9f48b4d62bc13e7e66bf8d751af98bce3f Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 22 Oct 2022 12:00:21 +0200 Subject: [PATCH 115/352] iommu: Add IOMMU_RESV_TRANSLATED for non 1:1 mapped reserved regions The display controller in Apple silicon SoCs uses bootloader mappings which require IOMMU translation. Signed-off-by: Janne Grunau --- drivers/iommu/iommu.c | 24 ++++++++++++++++++++---- include/linux/iommu.h | 10 ++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index ee83850c70605e..36421a8e37885d 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -95,6 +95,7 @@ static const char * const iommu_group_resv_type_string[] = { [IOMMU_RESV_RESERVED] = "reserved", [IOMMU_RESV_MSI] = "msi", [IOMMU_RESV_SW_MSI] = "msi", + [IOMMU_RESV_TRANSLATED] = "translated", }; #define IOMMU_CMD_LINE_DMA_API BIT(0) @@ -2942,10 +2943,11 @@ void iommu_put_resv_regions(struct device *dev, struct list_head *list) } EXPORT_SYMBOL(iommu_put_resv_regions); -struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start, - size_t length, int prot, - enum iommu_resv_type type, - gfp_t gfp) +struct iommu_resv_region *iommu_alloc_resv_region_tr(phys_addr_t start, + dma_addr_t dva_start, + size_t length, int prot, + enum iommu_resv_type type, + gfp_t gfp) { struct iommu_resv_region *region; @@ -2955,11 +2957,25 @@ struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start, INIT_LIST_HEAD(®ion->list); region->start = start; + if (type == IOMMU_RESV_TRANSLATED) + region->dva = dva_start; region->length = length; region->prot = prot; region->type = type; return region; } +EXPORT_SYMBOL_GPL(iommu_alloc_resv_region_tr); + +struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start, + size_t length, int prot, + enum iommu_resv_type type, + gfp_t gfp) +{ + if (type == IOMMU_RESV_TRANSLATED) + return NULL; + + return iommu_alloc_resv_region_tr(start, 0, length, prot, type, gfp); +} EXPORT_SYMBOL_GPL(iommu_alloc_resv_region); void iommu_set_default_passthrough(bool cmd_line) diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 555597b54083cd..634e4b0eff11f1 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -289,12 +289,18 @@ enum iommu_resv_type { IOMMU_RESV_MSI, /* Software-managed MSI translation window */ IOMMU_RESV_SW_MSI, + /* + * Memory regions which must be mapped with the specified mapping + * at all times. + */ + IOMMU_RESV_TRANSLATED, }; /** * struct iommu_resv_region - descriptor for a reserved memory region * @list: Linked list pointers * @start: System physical start address of the region + * @start: Device virtual start address of the region for IOMMU_RESV_TRANSLATED * @length: Length of the region in bytes * @prot: IOMMU Protection flags (READ/WRITE/...) * @type: Type of the reserved region @@ -303,6 +309,7 @@ enum iommu_resv_type { struct iommu_resv_region { struct list_head list; phys_addr_t start; + dma_addr_t dva; size_t length; int prot; enum iommu_resv_type type; @@ -938,6 +945,9 @@ extern bool iommu_default_passthrough(void); extern struct iommu_resv_region * iommu_alloc_resv_region(phys_addr_t start, size_t length, int prot, enum iommu_resv_type type, gfp_t gfp); +extern struct iommu_resv_region * +iommu_alloc_resv_region_tr(phys_addr_t start, dma_addr_t dva_start, size_t length, + int prot, enum iommu_resv_type type, gfp_t gfp); extern int iommu_get_group_resv_regions(struct iommu_group *group, struct list_head *head); From d0a786046a4c98d863b92cd5e0073b9643a9f74d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 22 Oct 2022 12:24:54 +0200 Subject: [PATCH 116/352] iommu: Parse translated reserved regions These regions are setup by the boot loader and require an iommu to translate arbitray physical to device VA mappings. Signed-off-by: Janne Grunau --- drivers/iommu/dma-iommu.c | 9 +++++++-- drivers/iommu/of_iommu.c | 11 +++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 94d5141696424d..6fc9be107cc86c 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -572,8 +572,13 @@ static int iova_reserve_iommu_regions(struct device *dev, if (region->type == IOMMU_RESV_SW_MSI) continue; - lo = iova_pfn(iovad, region->start); - hi = iova_pfn(iovad, region->start + region->length - 1); + if (region->type == IOMMU_RESV_TRANSLATED) { + lo = iova_pfn(iovad, region->dva); + hi = iova_pfn(iovad, region->dva + region->length - 1); + } else { + lo = iova_pfn(iovad, region->start); + hi = iova_pfn(iovad, region->start + region->length - 1); + } reserve_iova(iovad, lo, hi); if (region->type == IOMMU_RESV_MSI) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 1ccd33b9f351bf..69377addd6cebb 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -189,9 +189,7 @@ iommu_resv_region_get_type(struct device *dev, if (start == phys->start && end == phys->end) return IOMMU_RESV_DIRECT; - dev_warn(dev, "treating non-direct mapping [%pr] -> [%pap-%pap] as reservation\n", phys, - &start, &end); - return IOMMU_RESV_RESERVED; + return IOMMU_RESV_TRANSLATED; } /** @@ -262,8 +260,13 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list) } type = iommu_resv_region_get_type(dev, &phys, iova, length); - region = iommu_alloc_resv_region(iova, length, prot, type, + if (type == IOMMU_RESV_TRANSLATED) + region = iommu_alloc_resv_region_tr(phys.start, iova, length, prot, type, + GFP_KERNEL); + else + region = iommu_alloc_resv_region(iova, length, prot, type, GFP_KERNEL); + if (region) list_add_tail(®ion->list, list); } From cf4763af884cfbdeeba4c25aa745148bf6deecf1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 1 Apr 2025 20:31:56 +0200 Subject: [PATCH 117/352] iommu: Rename iommu_create_device_direct_mappings() It will be used to create firmware mappings which require a paging domain and mappings installed at specific IOVA. Signed-off-by: Janne Grunau --- drivers/iommu/iommu.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 36421a8e37885d..3332fc07804a8d 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -139,8 +139,8 @@ static void __iommu_group_set_domain_nofail(struct iommu_group *group, static int iommu_setup_default_domain(struct iommu_group *group, int target_type); -static int iommu_create_device_direct_mappings(struct iommu_domain *domain, - struct device *dev); +static int iommu_create_device_fw_mappings(struct iommu_domain *domain, + struct device *dev); static ssize_t iommu_group_store_type(struct iommu_group *group, const char *buf, size_t count); static struct group_device *iommu_group_alloc_device(struct iommu_group *group, @@ -648,7 +648,7 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list list_add_tail(&gdev->list, &group->devices); WARN_ON(group->default_domain && !group->domain); if (group->default_domain) - iommu_create_device_direct_mappings(group->default_domain, dev); + iommu_create_device_fw_mappings(group->default_domain, dev); if (group->domain) { ret = __iommu_device_set_domain(group, dev, group->domain, NULL, 0); @@ -1177,8 +1177,8 @@ int iommu_group_set_name(struct iommu_group *group, const char *name) } EXPORT_SYMBOL_GPL(iommu_group_set_name); -static int iommu_create_device_direct_mappings(struct iommu_domain *domain, - struct device *dev) +static int iommu_create_device_fw_mappings(struct iommu_domain *domain, + struct device *dev) { struct iommu_resv_region *entry; LIST_HEAD(mappings); @@ -3100,7 +3100,7 @@ static int iommu_setup_default_domain(struct iommu_group *group, struct iommu_domain *old_dom = group->default_domain; struct group_device *gdev; struct iommu_domain *dom; - bool direct_failed; + bool fw_failed; int req_type; int ret; @@ -3130,10 +3130,10 @@ static int iommu_setup_default_domain(struct iommu_group *group, * mapped before their device is attached, in order to guarantee * continuity with any FW activity */ - direct_failed = false; + fw_failed = false; for_each_group_device(group, gdev) { - if (iommu_create_device_direct_mappings(dom, gdev->dev)) { - direct_failed = true; + if (iommu_create_device_fw_mappings(dom, gdev->dev)) { + fw_failed = true; dev_warn_once( gdev->dev->iommu->iommu_dev->dev, "IOMMU driver was not able to establish FW requested direct mapping."); @@ -3165,9 +3165,9 @@ static int iommu_setup_default_domain(struct iommu_group *group, * trying again after attaching. If this happens it means the device * will not continuously have the IOMMU_RESV_DIRECT map. */ - if (direct_failed) { + if (fw_failed) { for_each_group_device(group, gdev) { - ret = iommu_create_device_direct_mappings(dom, gdev->dev); + ret = iommu_create_device_fw_mappings(dom, gdev->dev); if (ret) goto err_restore_domain; } From c2c894befa4c386c0446ff6286f85b4a5b0b21c3 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 1 Apr 2025 20:20:45 +0200 Subject: [PATCH 118/352] iommu: Handle translated device firmware mappings Signed-off-by: Janne Grunau --- drivers/iommu/iommu.c | 31 ++++++++++++++++++++++++++----- include/linux/iommu.h | 2 ++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 3332fc07804a8d..228911f9b47ab6 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1194,21 +1194,29 @@ static int iommu_create_device_fw_mappings(struct iommu_domain *domain, /* We need to consider overlapping regions for different devices */ list_for_each_entry(entry, &mappings, list) { - dma_addr_t start, end, addr; + dma_addr_t start, end, addr, iova; size_t map_size = 0; if (entry->type == IOMMU_RESV_DIRECT) dev->iommu->require_direct = 1; + if (entry->type == IOMMU_RESV_TRANSLATED) + dev->iommu->require_translated = 1; if ((entry->type != IOMMU_RESV_DIRECT && - entry->type != IOMMU_RESV_DIRECT_RELAXABLE) || + entry->type != IOMMU_RESV_DIRECT_RELAXABLE && + entry->type != IOMMU_RESV_TRANSLATED) || !iommu_is_dma_domain(domain)) continue; start = ALIGN(entry->start, pg_size); end = ALIGN(entry->start + entry->length, pg_size); - for (addr = start; addr <= end; addr += pg_size) { + if (entry->type == IOMMU_RESV_TRANSLATED) + iova = ALIGN(entry->dva, pg_size); + else + iova = start; + + for (addr = start; addr <= end; addr += pg_size, iova += pg_size) { phys_addr_t phys_addr; if (addr == end) @@ -1218,7 +1226,7 @@ static int iommu_create_device_fw_mappings(struct iommu_domain *domain, * Return address by iommu_iova_to_phys for 0 is * ambiguous. Offset to address 1 if addr is 0. */ - phys_addr = iommu_iova_to_phys(domain, addr ? addr : 1); + phys_addr = iommu_iova_to_phys(domain, iova ? iova : 1); if (!phys_addr) { map_size += pg_size; continue; @@ -1226,7 +1234,7 @@ static int iommu_create_device_fw_mappings(struct iommu_domain *domain, map_end: if (map_size) { - ret = iommu_map(domain, addr - map_size, + ret = iommu_map(domain, iova - map_size, addr - map_size, map_size, entry->prot, GFP_KERNEL); if (ret) @@ -2384,6 +2392,19 @@ static int __iommu_device_set_domain(struct iommu_group *group, "Firmware has requested this device have a 1:1 IOMMU mapping, rejecting configuring the device without a 1:1 mapping. Contact your platform vendor.\n"); return -EINVAL; } + /* + * If the device requires IOMMU_RESV_TRANSLATED then we cannot allow + * the identy or blocking domain to be attached as it does not contain + * the required translated mapping. + */ + if (dev->iommu->require_translated && + (new_domain->type == IOMMU_DOMAIN_IDENTITY || + new_domain->type == IOMMU_DOMAIN_BLOCKED || + new_domain == group->blocking_domain)) { + dev_warn(dev, + "Firmware has requested this device have a translated IOMMU mapping, rejecting configuring the device without a translated mapping. Contact your platform vendor.\n"); + return -EINVAL; + } if (dev->iommu->attach_deferred) { if (new_domain == group->default_domain) diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 634e4b0eff11f1..5816d8fb9163ab 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -845,6 +845,7 @@ struct iommu_fault_param { * @pci_32bit_workaround: Limit DMA allocations to 32-bit IOVAs * @require_direct: device requires IOMMU_RESV_DIRECT regions * @shadow_on_flush: IOTLB flushes are used to sync shadow tables + * @require_translated: device requires IOMMU_RESV_TRANSLATED regions * * TODO: migrate other per device data pointers under iommu_dev_data, e.g. * struct iommu_group *iommu_group; @@ -860,6 +861,7 @@ struct dev_iommu { u32 pci_32bit_workaround:1; u32 require_direct:1; u32 shadow_on_flush:1; + u32 require_translated:1; }; int iommu_device_register(struct iommu_device *iommu, From 7e34502107805ef6a35d768947d8bf70e6b39f60 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 16 Mar 2025 22:53:21 +0100 Subject: [PATCH 119/352] iommu/dart: Use separate iommu_ops for DARTs w/o bypass These DARTs do not support identity mappings so use a struct iommu_ops without default identity domain. Since commit 3bc0102835f6 ("iommu: apple-dart: Allow mismatched bypass support") groups with mismatched bypass support are supported so the check for bypass support in apple_dart_attach_dev_identity() has to stay. Signed-off-by: Janne Grunau --- drivers/iommu/apple-dart.c | 53 +++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 1c4ff4355b168d..fd9620e18ba565 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -1011,6 +1011,11 @@ static int apple_dart_def_domain_type(struct device *dev) return 0; } +static int apple_dart_def_domain_type_dma(struct device *dev) +{ + return IOMMU_DOMAIN_DMA; +} + #ifndef CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR /* Keep things compiling when CONFIG_PCI_APPLE isn't selected */ #define CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR 0 @@ -1036,27 +1041,36 @@ static void apple_dart_get_resv_regions(struct device *dev, iommu_dma_get_resv_regions(dev, head); } +#define APPLE_DART_IOMMU_COMMON_OPS() \ + .domain_alloc_paging = apple_dart_domain_alloc_paging, \ + .probe_device = apple_dart_probe_device, \ + .release_device = apple_dart_release_device, \ + .device_group = apple_dart_device_group, \ + .of_xlate = apple_dart_of_xlate, \ + .get_resv_regions = apple_dart_get_resv_regions, \ + .owner = THIS_MODULE, \ + .default_domain_ops = &(const struct iommu_domain_ops) { \ + .attach_dev = apple_dart_attach_dev_paging, \ + .map_pages = apple_dart_map_pages, \ + .unmap_pages = apple_dart_unmap_pages, \ + .flush_iotlb_all = apple_dart_flush_iotlb_all, \ + .iotlb_sync = apple_dart_iotlb_sync, \ + .iotlb_sync_map = apple_dart_iotlb_sync_map, \ + .iova_to_phys = apple_dart_iova_to_phys, \ + .free = apple_dart_domain_free, \ + } + static const struct iommu_ops apple_dart_iommu_ops = { .identity_domain = &apple_dart_identity_domain, .blocked_domain = &apple_dart_blocked_domain, - .domain_alloc_paging = apple_dart_domain_alloc_paging, - .probe_device = apple_dart_probe_device, - .release_device = apple_dart_release_device, - .device_group = apple_dart_device_group, - .of_xlate = apple_dart_of_xlate, .def_domain_type = apple_dart_def_domain_type, - .get_resv_regions = apple_dart_get_resv_regions, - .owner = THIS_MODULE, - .default_domain_ops = &(const struct iommu_domain_ops) { - .attach_dev = apple_dart_attach_dev_paging, - .map_pages = apple_dart_map_pages, - .unmap_pages = apple_dart_unmap_pages, - .flush_iotlb_all = apple_dart_flush_iotlb_all, - .iotlb_sync = apple_dart_iotlb_sync, - .iotlb_sync_map = apple_dart_iotlb_sync_map, - .iova_to_phys = apple_dart_iova_to_phys, - .free = apple_dart_domain_free, - } + APPLE_DART_IOMMU_COMMON_OPS() +}; + +static const struct iommu_ops apple_dart_iommu_no_bypass_ops = { + .blocked_domain = &apple_dart_blocked_domain, + .def_domain_type = apple_dart_def_domain_type_dma, + APPLE_DART_IOMMU_COMMON_OPS() }; static irqreturn_t apple_dart_t8020_irq(int irq, void *dev) @@ -1262,7 +1276,10 @@ static int apple_dart_probe(struct platform_device *pdev) if (ret) goto err_free_irq; - ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_ops, dev); + if (!dart->supports_bypass) + ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_no_bypass_ops, dev); + else + ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_ops, dev); if (ret) goto err_sysfs_remove; From d5035145c526c8dd7edc23b22318383a79d0240c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 30 Mar 2025 23:05:27 +0200 Subject: [PATCH 120/352] iommu/dart: Use virtual memory ttbr entries in apple_dart_cfg Locked DARTs can not modify ttbr entries. To ensure atomic updates of PTEs in the L1 table the DART driver will copy entries to the preallocated L1 table. This requires access to io-pgtable-dart's tables. For all other DARTs this moves virt_to_phys() calls into the DART driver. Signed-off-by: Janne Grunau --- drivers/iommu/apple-dart.c | 7 ++++--- drivers/iommu/io-pgtable-dart.c | 2 +- include/linux/io-pgtable.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index fd9620e18ba565..1ed82b81e5020b 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -583,9 +583,10 @@ apple_dart_setup_translation(struct apple_dart_domain *domain, struct io_pgtable_cfg *pgtbl_cfg = &io_pgtable_ops_to_pgtable(domain->pgtbl_ops)->cfg; - for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i) - apple_dart_hw_set_ttbr(stream_map, i, - pgtbl_cfg->apple_dart_cfg.ttbr[i]); + for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i) { + u64 ttbr = virt_to_phys(pgtbl_cfg->apple_dart_cfg.ttbr[i]); + apple_dart_hw_set_ttbr(stream_map, i, ttbr); + } for (; i < stream_map->dart->hw->ttbr_count; ++i) apple_dart_hw_clear_ttbr(stream_map, i); diff --git a/drivers/iommu/io-pgtable-dart.c b/drivers/iommu/io-pgtable-dart.c index cbc5d6aa2daa23..fdaf0584f535e7 100644 --- a/drivers/iommu/io-pgtable-dart.c +++ b/drivers/iommu/io-pgtable-dart.c @@ -435,7 +435,7 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) iommu_alloc_pages_sz(GFP_KERNEL, DART_GRANULE(data)); if (!data->pgd[i]) goto out_free_data; - cfg->apple_dart_cfg.ttbr[i] = virt_to_phys(data->pgd[i]); + cfg->apple_dart_cfg.ttbr[i] = data->pgd[i]; } return &data->iop; diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h index e19872e37e067f..c3b1b92910d94e 100644 --- a/include/linux/io-pgtable.h +++ b/include/linux/io-pgtable.h @@ -177,7 +177,7 @@ struct io_pgtable_cfg { } arm_mali_lpae_cfg; struct { - u64 ttbr[4]; + void *ttbr[4]; u32 n_ttbrs; u32 n_levels; } apple_dart_cfg; From 3379df698302ecaa4b78029feb0c0463acb22b99 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Mon, 10 Feb 2025 14:39:53 -0500 Subject: [PATCH 121/352] iommu/dart: Track if the DART is locked Some DARTs are locked at boot-time. That means they are already configured and we cannot change their configuration, which requires special handling. Locked DARTs are identified in the configuration register. Check this bit when probing and save the result so we can handle accordingly. Signed-off-by: Alyssa Rosenzweig Signed-off-by: Janne Grunau --- drivers/iommu/apple-dart.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 1ed82b81e5020b..2c43fee287abdf 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -203,6 +203,7 @@ struct apple_dart_hw { * @lock: lock for hardware operations involving this dart * @pgsize: pagesize supported by this DART * @supports_bypass: indicates if this DART supports bypass mode + * @locked: indicates if this DART is locked * @sid2group: maps stream ids to iommu_groups * @iommu: iommu core device */ @@ -224,6 +225,7 @@ struct apple_dart { u32 num_streams; u32 supports_bypass : 1; u32 four_level : 1; + u32 locked : 1; dma_addr_t dma_min; dma_addr_t dma_max; @@ -863,6 +865,8 @@ static int apple_dart_of_xlate(struct device *dev, return -EINVAL; if (cfg_dart->ias != dart->ias) return -EINVAL; + if (cfg_dart->locked != dart->locked) + return -EINVAL; } cfg->supports_bypass &= dart->supports_bypass; @@ -1164,6 +1168,11 @@ static irqreturn_t apple_dart_irq(int irq, void *dev) return ret; } +static bool apple_dart_is_locked(struct apple_dart *dart) +{ + return !!(readl(dart->regs + dart->hw->lock) & dart->hw->lock_bit); +} + static int apple_dart_probe(struct platform_device *pdev) { int ret; @@ -1261,6 +1270,7 @@ static int apple_dart_probe(struct platform_device *pdev) goto err_clk_disable; } + dart->locked = apple_dart_is_locked(dart); ret = apple_dart_hw_reset(dart); if (ret) goto err_clk_disable; @@ -1288,9 +1298,9 @@ static int apple_dart_probe(struct platform_device *pdev) dev_info( &pdev->dev, - "DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, AS %d -> %d] initialized\n", + "DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d, AS %d -> %d] initialized\n", dart->pgsize, dart->num_streams, dart->supports_bypass, - dart->pgsize > PAGE_SIZE, dart->ias, dart->oas); + dart->pgsize > PAGE_SIZE, dart->locked, dart->ias, dart->oas); return 0; err_sysfs_remove: From db3bb109390afb0457a0de59a5af43c6144e5bee Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 30 Mar 2025 23:53:20 +0200 Subject: [PATCH 122/352] iommu/dart: Add iommu_ops for locked DARTs A locked DART has partially read-only MMIO registers. Most importantly the TTBR registers are read-only. Apple's bootloader sets the DART up for its intended use before locking it. The single used streams has a L1 translation table allocated in carved out memory and its TTBRs point to this table. In addition translation and bypass can not be disabled or enabled so a locked DART must not offer default identity or blocked domains. The only observed locked DART is for the display coprocessor. It requires careful handling as translation errors result in unrecoverable crashes of the display coprocessor. Signed-off-by: Janne Grunau --- drivers/iommu/apple-dart.c | 164 ++++++++++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 2c43fee287abdf..301d7dd8988819 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -235,6 +235,8 @@ struct apple_dart { u32 save_tcr[DART_MAX_STREAMS]; u32 save_ttbr[DART_MAX_STREAMS][DART_MAX_TTBR]; + + u64 *locked_ttbr[DART_MAX_STREAMS][DART_MAX_TTBR]; }; /* @@ -386,6 +388,82 @@ apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map *stream_map) apple_dart_hw_clear_ttbr(stream_map, i); } +static int +apple_dart_hw_map_locked_ttbr(struct apple_dart_stream_map *stream_map, u8 idx) +{ + struct apple_dart *dart = stream_map->dart; + int sid; + + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) { + u32 ttbr; + phys_addr_t phys; + u64 *l1_tbl; + + ttbr = readl(dart->regs + DART_TTBR(dart, sid, idx)); + + if (!(ttbr & dart->hw->ttbr_valid)) { + dev_err(dart->dev, "Invalid ttbr[%u] for locked dart\n", + idx); + return -EIO; + } + + ttbr &= ~dart->hw->ttbr_valid; + + if (dart->hw->ttbr_addr_field_shift) + ttbr >>= dart->hw->ttbr_addr_field_shift; + phys = ((phys_addr_t) ttbr) << dart->hw->ttbr_shift; + + l1_tbl = devm_memremap(dart->dev, phys, dart->pgsize, + MEMREMAP_WB); + if (!l1_tbl) + return -ENOMEM; + + dart->locked_ttbr[sid][idx] = l1_tbl; + } + + return 0; +} + +static int +apple_dart_hw_unmap_locked_ttbr(struct apple_dart_stream_map *stream_map, + u8 idx) +{ + struct apple_dart *dart = stream_map->dart; + int sid; + + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) { + /* TODO: locked L1 table might need to be restored to boot state */ + if (dart->locked_ttbr[sid][idx]) { + memset(dart->locked_ttbr[sid][idx], 0, dart->pgsize); + devm_memunmap(dart->dev, dart->locked_ttbr[sid][idx]); + } + dart->locked_ttbr[sid][idx] = NULL; + } + + return 0; +} + +static int +apple_dart_hw_sync_locked(struct io_pgtable_cfg *cfg, + struct apple_dart_stream_map *stream_map) +{ + struct apple_dart *dart = stream_map->dart; + int sid; + + for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) { + for (int idx = 0; idx < dart->hw->ttbr_count; idx++) { + u64 *ttbrep = dart->locked_ttbr[sid][idx]; + u64 *ptep = cfg->apple_dart_cfg.ttbr[idx]; + if (!ttbrep || !ptep) + continue; + for (int entry = 0; entry < dart->pgsize / sizeof(*ptep); entry++) + ttbrep[entry] = ptep[entry]; + } + } + + return 0; +} + static int apple_dart_t8020_hw_stream_command(struct apple_dart_stream_map *stream_map, u32 command) @@ -507,6 +585,8 @@ static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain) int i, j; struct apple_dart_atomic_stream_map *domain_stream_map; struct apple_dart_stream_map stream_map; + struct io_pgtable_cfg *pgtbl_cfg = + &io_pgtable_ops_to_pgtable(domain->pgtbl_ops)->cfg; for_each_stream_map(i, domain, domain_stream_map) { stream_map.dart = domain_stream_map->dart; @@ -515,6 +595,10 @@ static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain) stream_map.sidmap[j] = atomic_long_read(&domain_stream_map->sidmap[j]); WARN_ON(pm_runtime_get_sync(stream_map.dart->dev) < 0); + + if (stream_map.dart->locked) + apple_dart_hw_sync_locked(pgtbl_cfg, &stream_map); + stream_map.dart->hw->invalidate_tlb(&stream_map); pm_runtime_put(stream_map.dart->dev); } @@ -597,6 +681,24 @@ apple_dart_setup_translation(struct apple_dart_domain *domain, stream_map->dart->hw->invalidate_tlb(stream_map); } +static void +apple_dart_setup_translation_locked(struct apple_dart_domain *domain, + struct apple_dart_stream_map *stream_map) +{ + int i; + struct io_pgtable_cfg *pgtbl_cfg = + &io_pgtable_ops_to_pgtable(domain->pgtbl_ops)->cfg; + + /* Locked DARTs are set up by the bootloader. */ + for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i) + apple_dart_hw_map_locked_ttbr(stream_map, i); + for (; i < stream_map->dart->hw->ttbr_count; ++i) + apple_dart_hw_unmap_locked_ttbr(stream_map, i); + + apple_dart_hw_sync_locked(pgtbl_cfg, stream_map); + stream_map->dart->hw->invalidate_tlb(stream_map); +} + static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain, struct apple_dart_master_cfg *cfg) { @@ -630,6 +732,42 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain, .iommu_dev = dart->dev, }; + if (dart->locked) { + unsigned long *sidmap; + int sid; + u32 ttbr; + + /* Locked DARTs can only have a single stream bound */ + sidmap = cfg->stream_maps[0].sidmap; + sid = find_first_bit(sidmap, dart->num_streams); + + WARN_ON((sid < 0) || bitmap_weight(sidmap, dart->num_streams) > 1); + ttbr = readl(dart->regs + DART_TTBR(dart, sid, 0)); + + WARN_ON(!(ttbr & dart->hw->ttbr_valid)); + + /* If the DART is locked, we need to keep the translation level count. */ + if (dart->hw->tcr_4level && dart->ias > 36) { + if (readl(dart->regs + DART_TCR(dart, sid)) & dart->hw->tcr_4level) { + if (ias < 37) { + dev_info(dart->dev, "Expanded to ias=37 due to lock\n"); + pgtbl_cfg.ias = 37; + } + } else if (ias > 36) { + dev_info(dart->dev, "Limited to ias=36 due to lock\n"); + pgtbl_cfg.ias = 36; + if (dart->dma_min == 0 && dma_max == DMA_BIT_MASK(dart->ias)) { + dma_max = DMA_BIT_MASK(pgtbl_cfg.ias); + } else if ((dart->dma_min ^ dma_max) & ~DMA_BIT_MASK(36)) { + dev_err(dart->dev, + "Invalid DMA range for locked 3-level PT\n"); + ret = -ENOMEM; + goto done; + } + } + } + } + dart_domain->pgtbl_ops = alloc_io_pgtable_ops(dart->hw->fmt, &pgtbl_cfg, &dart_domain->domain); if (!dart_domain->pgtbl_ops) { @@ -711,8 +849,13 @@ static int apple_dart_attach_dev_paging(struct iommu_domain *domain, if (ret) goto err; - for_each_stream_map(i, cfg, stream_map) - apple_dart_setup_translation(dart_domain, stream_map); + for_each_stream_map(i, cfg, stream_map) { + if (!stream_map->dart->locked) + apple_dart_setup_translation(dart_domain, stream_map); + else + apple_dart_setup_translation_locked(dart_domain, + stream_map); + } err: for_each_stream_map(i, cfg, stream_map) @@ -798,8 +941,16 @@ static struct iommu_device *apple_dart_probe_device(struct device *dev) static void apple_dart_release_device(struct device *dev) { + int i, j; + struct apple_dart_stream_map *stream_map; struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev); + for_each_stream_map(j, cfg, stream_map) { + if (stream_map->dart->locked) + for (i = 0; i < stream_map->dart->hw->ttbr_count; ++i) + apple_dart_hw_unmap_locked_ttbr(stream_map, i); + } + kfree(cfg); } @@ -1078,6 +1229,11 @@ static const struct iommu_ops apple_dart_iommu_no_bypass_ops = { APPLE_DART_IOMMU_COMMON_OPS() }; +static const struct iommu_ops apple_dart_iommu_locked_ops = { + .def_domain_type = apple_dart_def_domain_type_dma, + APPLE_DART_IOMMU_COMMON_OPS() +}; + static irqreturn_t apple_dart_t8020_irq(int irq, void *dev) { struct apple_dart *dart = dev; @@ -1287,7 +1443,9 @@ static int apple_dart_probe(struct platform_device *pdev) if (ret) goto err_free_irq; - if (!dart->supports_bypass) + if (dart->locked) + ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_locked_ops, dev); + else if (!dart->supports_bypass) ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_no_bypass_ops, dev); else ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_ops, dev); From 10d4c15e538c75006f8a8f744fb0b56d32c4bb77 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Mon, 10 Feb 2025 14:39:54 -0500 Subject: [PATCH 123/352] iommu/dart: Support locked DARTs Locked DARTs cannot be reconfigured, therefore the reset/restore procedure can't work and should not be needed. Skip it and allowing locked DARTs to probe. Co-developed-by: Hector Martin Signed-off-by: Hector Martin Signed-off-by: Alyssa Rosenzweig Signed-off-by: Janne Grunau --- drivers/iommu/apple-dart.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 301d7dd8988819..29a858793e0bd6 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -550,17 +550,9 @@ apple_dart_t8110_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map) static int apple_dart_hw_reset(struct apple_dart *dart) { - u32 config; struct apple_dart_stream_map stream_map; int i; - config = readl(dart->regs + dart->hw->lock); - if (config & dart->hw->lock_bit) { - dev_err(dart->dev, "DART is locked down until reboot: %08x\n", - config); - return -EINVAL; - } - stream_map.dart = dart; bitmap_zero(stream_map.sidmap, DART_MAX_STREAMS); bitmap_set(stream_map.sidmap, 0, dart->num_streams); @@ -1427,9 +1419,11 @@ static int apple_dart_probe(struct platform_device *pdev) } dart->locked = apple_dart_is_locked(dart); - ret = apple_dart_hw_reset(dart); - if (ret) - goto err_clk_disable; + if (!dart->locked) { + ret = apple_dart_hw_reset(dart); + if (ret) + goto err_clk_disable; + } ret = request_irq(dart->irq, apple_dart_irq, IRQF_SHARED, "apple-dart fault handler", dart); @@ -1476,7 +1470,9 @@ static void apple_dart_remove(struct platform_device *pdev) { struct apple_dart *dart = platform_get_drvdata(pdev); - apple_dart_hw_reset(dart); + if (!dart->locked) + apple_dart_hw_reset(dart); + free_irq(dart->irq, dart); iommu_device_unregister(&dart->iommu); @@ -1594,6 +1590,10 @@ static __maybe_unused int apple_dart_suspend(struct device *dev) struct apple_dart *dart = dev_get_drvdata(dev); unsigned int sid, idx; + /* Locked DARTs can't be restored so skip saving their registers/. */ + if (dart->locked) + return 0; + for (sid = 0; sid < dart->num_streams; sid++) { dart->save_tcr[sid] = readl(dart->regs + DART_TCR(dart, sid)); for (idx = 0; idx < dart->hw->ttbr_count; idx++) @@ -1610,6 +1610,10 @@ static __maybe_unused int apple_dart_resume(struct device *dev) unsigned int sid, idx; int ret; + /* Locked DARTs can't be restored, and they should not need it */ + if (dart->locked) + return 0; + ret = apple_dart_hw_reset(dart); if (ret) { dev_err(dev, "Failed to reset DART on resume\n"); From 15b72eb7f10a96f9f9b6d8e5c03421620f0f3cfb Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 9 Apr 2025 11:20:28 +0200 Subject: [PATCH 124/352] fixup! iommu/dart: Track if the DART is locked --- drivers/iommu/apple-dart.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 29a858793e0bd6..7f763dfcbea4ae 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -1008,8 +1008,6 @@ static int apple_dart_of_xlate(struct device *dev, return -EINVAL; if (cfg_dart->ias != dart->ias) return -EINVAL; - if (cfg_dart->locked != dart->locked) - return -EINVAL; } cfg->supports_bypass &= dart->supports_bypass; From 08d2cf9dc9e77f8243b518e8d1cedd9c489ca974 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 9 Apr 2025 18:28:19 +0200 Subject: [PATCH 125/352] fixup! iommu/dart: Support locked DARTs --- drivers/iommu/apple-dart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 7f763dfcbea4ae..c8fa8112d6a196 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -1588,7 +1588,7 @@ static __maybe_unused int apple_dart_suspend(struct device *dev) struct apple_dart *dart = dev_get_drvdata(dev); unsigned int sid, idx; - /* Locked DARTs can't be restored so skip saving their registers/. */ + /* Locked DARTs can't be restored so skip saving their registers. */ if (dart->locked) return 0; From a40e7aa9dfe964e55173dfbb2aac00dcedef8b23 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 9 Apr 2025 18:08:08 +0200 Subject: [PATCH 126/352] iommu: apple-dart: Support combinations of locked and unlocked DARTs This is required for the display sub-system. m1n1 locks the DART of the boot framebuffer to minimize the blackout for the transition from boot framebuffer to the full display driver. The display blacks out when the bootloader setup mapping of the framebuffer vanishes during dart_reset(). Under certain circumstances this results in an unrecoverable crash of display coprocessor. Signed-off-by: Janne Grunau --- drivers/iommu/apple-dart.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index c8fa8112d6a196..9c23e8ba4c9418 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -294,6 +294,7 @@ struct apple_dart_domain { struct apple_dart_master_cfg { /* Intersection of DART capabilitles */ u32 supports_bypass : 1; + u32 locked : 1; struct apple_dart_stream_map stream_maps[MAX_DARTS_PER_DEVICE]; }; @@ -999,6 +1000,8 @@ static int apple_dart_of_xlate(struct device *dev, return -ENOMEM; /* Will be ANDed with DART capabilities */ cfg->supports_bypass = true; + /* Will be ORed with DART capabilities*/ + cfg->locked = false; } dev_iommu_priv_set(dev, cfg); @@ -1011,6 +1014,7 @@ static int apple_dart_of_xlate(struct device *dev, } cfg->supports_bypass &= dart->supports_bypass; + cfg->locked |= dart->locked; for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) { if (cfg->stream_maps[i].dart == dart) { From d0d1dceac4333ec545af35e70f65788e292a1cf1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 9 Apr 2025 18:20:02 +0200 Subject: [PATCH 127/352] iommu: apple-dart: Disallow identity domains for locked DARTs The register controlling bypass support is read-only for locked DARTs. In addition trnaslation can not be disabled so blocking domain has to be implemented with an empty translation table. Signed-off-by: Janne Grunau --- drivers/iommu/apple-dart.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 9c23e8ba4c9418..3a0b9cee8a2a21 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -867,6 +867,9 @@ static int apple_dart_attach_dev_identity(struct iommu_domain *domain, if (!cfg->supports_bypass) return -EINVAL; + if (cfg->locked) + return -EINVAL; + for_each_stream_map(i, cfg, stream_map) WARN_ON(pm_runtime_get_sync(stream_map->dart->dev) < 0); @@ -895,6 +898,9 @@ static int apple_dart_attach_dev_blocked(struct iommu_domain *domain, struct apple_dart_stream_map *stream_map; int i; + if (cfg->locked) + return -EINVAL; + for_each_stream_map(i, cfg, stream_map) WARN_ON(pm_runtime_get_sync(stream_map->dart->dev) < 0); From 1fe2c37040cfeced8a9d0161c2d7093cf8c9c1d0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 9 Apr 2025 18:24:13 +0200 Subject: [PATCH 128/352] iommu: apple-dart: Revert separate iommu_ops for locked/bypass DARTs Since combination of DARTs with diverging locked and supports_bypass state have to be supported those DARTs have to share the same iommu_ops pointer (see iommu_fwspec_init()). Signed-off-by: Janne Grunau --- drivers/iommu/apple-dart.c | 62 ++++++++++++-------------------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 3a0b9cee8a2a21..8feacc6bd29cd7 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -1163,15 +1163,12 @@ static int apple_dart_def_domain_type(struct device *dev) return IOMMU_DOMAIN_IDENTITY; if (!cfg->supports_bypass) return IOMMU_DOMAIN_DMA; + if (cfg->locked) + return IOMMU_DOMAIN_DMA; return 0; } -static int apple_dart_def_domain_type_dma(struct device *dev) -{ - return IOMMU_DOMAIN_DMA; -} - #ifndef CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR /* Keep things compiling when CONFIG_PCI_APPLE isn't selected */ #define CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR 0 @@ -1197,41 +1194,27 @@ static void apple_dart_get_resv_regions(struct device *dev, iommu_dma_get_resv_regions(dev, head); } -#define APPLE_DART_IOMMU_COMMON_OPS() \ - .domain_alloc_paging = apple_dart_domain_alloc_paging, \ - .probe_device = apple_dart_probe_device, \ - .release_device = apple_dart_release_device, \ - .device_group = apple_dart_device_group, \ - .of_xlate = apple_dart_of_xlate, \ - .get_resv_regions = apple_dart_get_resv_regions, \ - .owner = THIS_MODULE, \ - .default_domain_ops = &(const struct iommu_domain_ops) { \ - .attach_dev = apple_dart_attach_dev_paging, \ - .map_pages = apple_dart_map_pages, \ - .unmap_pages = apple_dart_unmap_pages, \ - .flush_iotlb_all = apple_dart_flush_iotlb_all, \ - .iotlb_sync = apple_dart_iotlb_sync, \ - .iotlb_sync_map = apple_dart_iotlb_sync_map, \ - .iova_to_phys = apple_dart_iova_to_phys, \ - .free = apple_dart_domain_free, \ - } - static const struct iommu_ops apple_dart_iommu_ops = { .identity_domain = &apple_dart_identity_domain, .blocked_domain = &apple_dart_blocked_domain, .def_domain_type = apple_dart_def_domain_type, - APPLE_DART_IOMMU_COMMON_OPS() -}; - -static const struct iommu_ops apple_dart_iommu_no_bypass_ops = { - .blocked_domain = &apple_dart_blocked_domain, - .def_domain_type = apple_dart_def_domain_type_dma, - APPLE_DART_IOMMU_COMMON_OPS() -}; - -static const struct iommu_ops apple_dart_iommu_locked_ops = { - .def_domain_type = apple_dart_def_domain_type_dma, - APPLE_DART_IOMMU_COMMON_OPS() + .domain_alloc_paging = apple_dart_domain_alloc_paging, + .probe_device = apple_dart_probe_device, + .release_device = apple_dart_release_device, + .device_group = apple_dart_device_group, + .of_xlate = apple_dart_of_xlate, + .get_resv_regions = apple_dart_get_resv_regions, + .owner = THIS_MODULE, + .default_domain_ops = &(const struct iommu_domain_ops) { + .attach_dev = apple_dart_attach_dev_paging, + .map_pages = apple_dart_map_pages, + .unmap_pages = apple_dart_unmap_pages, + .flush_iotlb_all = apple_dart_flush_iotlb_all, + .iotlb_sync = apple_dart_iotlb_sync, + .iotlb_sync_map = apple_dart_iotlb_sync_map, + .iova_to_phys = apple_dart_iova_to_phys, + .free = apple_dart_domain_free, + } }; static irqreturn_t apple_dart_t8020_irq(int irq, void *dev) @@ -1445,12 +1428,7 @@ static int apple_dart_probe(struct platform_device *pdev) if (ret) goto err_free_irq; - if (dart->locked) - ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_locked_ops, dev); - else if (!dart->supports_bypass) - ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_no_bypass_ops, dev); - else - ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_ops, dev); + ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_ops, dev); if (ret) goto err_sysfs_remove; From 033daad0e3013ea11037cd3d33a22d082a8102f3 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 17 Jul 2024 18:23:44 +0900 Subject: [PATCH 129/352] Increase MAX_LOCKDEP_CHAIN_HLOCKS Got a warning somewhere in the USB subsystem while unplugging a device... --- kernel/locking/lockdep_internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/locking/lockdep_internals.h b/kernel/locking/lockdep_internals.h index 0e5e6ffe91a3fe..91a802fea0aa0f 100644 --- a/kernel/locking/lockdep_internals.h +++ b/kernel/locking/lockdep_internals.h @@ -121,7 +121,7 @@ enum { #define MAX_LOCKDEP_CHAINS (1UL << MAX_LOCKDEP_CHAINS_BITS) -#define AVG_LOCKDEP_CHAIN_DEPTH 5 +#define AVG_LOCKDEP_CHAIN_DEPTH 10 #define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS * AVG_LOCKDEP_CHAIN_DEPTH) extern struct lock_chain lock_chains[]; From 6846ee74d645bb37b3808cd363e3baf588717fc1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 4 Oct 2025 15:30:19 +0200 Subject: [PATCH 130/352] arm64: configs: Add asahi.config fragment This can be used to ensure all drivers for Apple silicon hardware are enabled. For a defconfig build it can simply be appended: ``` make defconfig asahi ``` For other build configs (a modified defconfig or distro config) it can be merged via a kernel script: ``` KCONFIG_CONFIG=.config ./scripts/kconfig/merge_config.sh -m .config arch/arm64/configs/asahi.config ``` Signed-off-by: Janne Grunau --- arch/arm64/configs/asahi.config | 74 +++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm64/configs/asahi.config diff --git a/arch/arm64/configs/asahi.config b/arch/arm64/configs/asahi.config new file mode 100644 index 00000000000000..7ed0a173544025 --- /dev/null +++ b/arch/arm64/configs/asahi.config @@ -0,0 +1,74 @@ +CONFIG_RUST=y +CONFIG_ARM64_ACTLR_STATE=y +CONFIG_ARCH_APPLE=y +# CONFIG_ARM64_4K_PAGES is not set +CONFIG_ARM64_16K_PAGES=y +# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_MEMORY_MODEL_CONTROL=y +CONFIG_ARM_APPLE_CPUIDLE=y +CONFIG_ARM_APPLE_SOC_CPUFREQ=m +CONFIG_BT_HCIBCM4377=m +CONFIG_PCIE_APPLE=m +CONFIG_NVME_APPLE=m +CONFIG_BRCMFMAC=m +CONFIG_BRCMFMAC_PCIE=y +CONFIG_TOUCHSCREEN_APPLE_Z2=m +CONFIG_INPUT_MACSMC_INPUT=m +CONFIG_I2C_APPLE=m +CONFIG_SPI_APPLE=m +CONFIG_SPMI_APPLE=m +CONFIG_PINCTRL_APPLE_GPIO=m +CONFIG_GPIO_MACSMC=m +CONFIG_POWER_RESET_MACSMC=m +CONFIG_CHARGER_MACSMC=m +CONFIG_SENSORS_MACSMC_HWMON=m +CONFIG_APPLE_WATCHDOG=m +CONFIG_VIDEO_APPLE_ISP=m +CONFIG_DRM=y +CONFIG_DRM_ASAHI=m +CONFIG_DRM_ADP=m +CONFIG_DRM_APPLE=m +CONFIG_DRM_APPLE_AUDIO=y +CONFIG_SND_SOC_APPLE_AOP_AUDIO=m +CONFIG_SND_SOC_APPLE_MCA=m +CONFIG_SND_SOC_APPLE_MACAUDIO=m +CONFIG_SND_SOC_CS42L83=m +CONFIG_SND_SOC_CS42L84=m +CONFIG_SND_SOC_TAS2764=m +CONFIG_SND_SOC_TAS2770=m +CONFIG_HID_APPLE=m +CONFIG_HID_MAGICMOUSE=m +CONFIG_SERIAL_SAMSUNG=y +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_HID_DOCKCHANNEL=m +CONFIG_SPI_HID_APPLE_OF=m +CONFIG_SPI_HID_APPLE_CORE=m +CONFIG_USB_DWC3_APPLE=m +CONFIG_USB_XHCI_PCI_ASMEDIA=y +CONFIG_RTC_DRV_MACSMC=m +CONFIG_APPLE_ADMAC=m +CONFIG_APPLE_SIO=m +CONFIG_MFD_MACSMC=m +CONFIG_COMMON_CLK_APPLE_NCO=m +CONFIG_APPLE_DART=m +CONFIG_APPLE_DOCKCHANNEL=m +CONFIG_APPLE_MAILBOX=y +CONFIG_APPLE_PMGR_MISC=y +CONFIG_APPLE_RTKIT=y +CONFIG_APPLE_RTKIT_HELPER=m +CONFIG_APPLE_SART=m +CONFIG_RUST_APPLE_RTKIT=y +CONFIG_APPLE_AOP=m +CONFIG_APPLE_SEP=m +CONFIG_APPLE_PMGR_PWRSTATE=y +CONFIG_IIO_AOP_SENSOR_LAS=m +CONFIG_IIO_AOP_SENSOR_ALS=m +CONFIG_RUST_FW_LOADER_ABSTRACTIONS=y +CONFIG_PWM_APPLE=m +CONFIG_APPLE_AIC=y +CONFIG_PHY_APPLE_ATC=m +CONFIG_PHY_APPLE_DPTX=m +CONFIG_APPLE_M1_CPU_PMU=y +CONFIG_NVMEM_APPLE_EFUSES=m +CONFIG_NVMEM_APPLE_SPMI=m +CONFIG_MUX_APPLE_DPXBAR=m From ea7d301c8370ed6b361da9bb5e71dc7cff825dbe Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sun, 11 Jan 2026 15:19:09 +0100 Subject: [PATCH 131/352] power: hibernate: Disable hibernation on Apple Silicon Signed-off-by: Sven Peter --- kernel/power/hibernate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index af8d07bafe02a7..d04eae18ea688c 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "power.h" @@ -110,7 +111,8 @@ bool hibernation_available(void) { return nohibernate == 0 && !security_locked_down(LOCKDOWN_HIBERNATION) && - !secretmem_active() && !cxl_mem_active(); + !secretmem_active() && !cxl_mem_active() && + !of_machine_is_compatible("apple,arm-platform"); } /** From 00391251260fe4beb75d9695b5061815126fff2d Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 26 Feb 2026 17:59:08 +0100 Subject: [PATCH 132/352] pmdomain: apple: Add PMP reporting interface This driver manages a shared SRAM area that is used to communicate desired power states of devices that PMP manages. Signed-off-by: Sasha Finkelstein --- drivers/pmdomain/apple/Kconfig | 6 + drivers/pmdomain/apple/Makefile | 1 + drivers/pmdomain/apple/pmp-report.c | 239 ++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/pmdomain/apple/pmp-report.c diff --git a/drivers/pmdomain/apple/Kconfig b/drivers/pmdomain/apple/Kconfig index a8973f8057fba7..6e9deb9de0739c 100644 --- a/drivers/pmdomain/apple/Kconfig +++ b/drivers/pmdomain/apple/Kconfig @@ -14,4 +14,10 @@ config APPLE_PMGR_PWRSTATE controls for SoC devices. This driver manages them through the generic power domain framework, and also provides reset support. +config APPLE_PMP_REPORT + bool "Apple PMP report control" + depends on OF + depends on PM + select PM_GENERIC_DOMAINS + endif diff --git a/drivers/pmdomain/apple/Makefile b/drivers/pmdomain/apple/Makefile index 53665af630be22..b098b204d9868a 100644 --- a/drivers/pmdomain/apple/Makefile +++ b/drivers/pmdomain/apple/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_APPLE_PMGR_PWRSTATE) += pmgr-pwrstate.o +obj-$(CONFIG_APPLE_PMP_REPORT) += pmp-report.o diff --git a/drivers/pmdomain/apple/pmp-report.c b/drivers/pmdomain/apple/pmp-report.c new file mode 100644 index 00000000000000..8050ade5ef8d08 --- /dev/null +++ b/drivers/pmdomain/apple/pmp-report.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SoC PMP power state reporting driver + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PMP_REPORT_READY 0x1 + +struct apple_pmp_report_offsets { + u32 tgt_read; + u32 tgt_write; + u32 actual; + u32 status; +}; + +struct apple_pmp_report { + struct device *dev; + const struct apple_pmp_report_offsets *offsets; + void __iomem *base; + spinlock_t lock; +}; + +static int apple_pmp_report_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct apple_pmp_report *rep; + int ret; + + rep = devm_kzalloc(dev, sizeof(*rep), GFP_KERNEL); + if (!rep) + return -ENOMEM; + + rep->dev = dev; + rep->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rep->base)) + return PTR_ERR(rep->base); + rep->offsets = of_device_get_match_data(dev); + dev_set_drvdata(dev, rep); + ret = of_platform_populate(np, NULL, NULL, dev); + if (ret) + return dev_err_probe(dev, ret, "failed to create child devices\n"); + + return 0; +} + +static const struct apple_pmp_report_offsets apple_pmp_offsets_t600x = { + .tgt_read = 0xf80, + .tgt_write = 0x107c0, + .actual = 0x1000, + .status = 0x10, +}; + +static const struct apple_pmp_report_offsets apple_pmp_offsets_t602x = { + .tgt_read = 0x2000, + .tgt_write = 0x11000, + .actual = 0x2080, + .status = 0x10, +}; + +static const struct apple_pmp_report_offsets apple_pmp_offsets_t8112 = { + .tgt_read = 0xa00, + .tgt_write = 0x10500, + .actual = 0xa40, + .status = 0x10, +}; + +static const struct of_device_id apple_pmp_report_of_match[] = { + { .compatible = "apple,t6000-pmp-v2-report", .data = &apple_pmp_offsets_t600x }, + { .compatible = "apple,t6020-pmp-v2-report", .data = &apple_pmp_offsets_t602x }, + { .compatible = "apple,t8112-pmp-v2-report", .data = &apple_pmp_offsets_t8112 }, + {} +}; + +static struct platform_driver apple_pmp_report_driver = { + .probe = apple_pmp_report_probe, + .driver = { + .name = "apple-pmp-report", + .of_match_table = apple_pmp_report_of_match, + }, +}; + +struct apple_pmp_report_entry { + struct device *dev; + struct generic_pm_domain genpd; + u32 id; +}; + +#define genpd_to_apple_pmp_report_entry(_genpd) \ + container_of(_genpd, struct apple_pmp_report_entry, genpd) + +static int apple_pmp_report_set_state(struct generic_pm_domain *genpd, bool enable) +{ + struct apple_pmp_report_entry *ent = genpd_to_apple_pmp_report_entry(genpd); + struct apple_pmp_report *rep = dev_get_drvdata(ent->dev->parent); + u64 bit_val = 1 << ent->id; + u64 val; + unsigned long flags; + + spin_lock_irqsave(&rep->lock, flags); + val = readq(rep->base + rep->offsets->tgt_read); + val &= ~bit_val; + if (enable) + val |= bit_val; + writeq(val, rep->base + rep->offsets->tgt_write); + spin_unlock_irqrestore(&rep->lock, flags); + val = readq(rep->base + rep->offsets->status); + if ((val & PMP_REPORT_READY) == 0) + return 0; + return readq_poll_timeout_atomic( + rep->base + rep->offsets->actual, + val, + !!(val & bit_val) == !!enable, + 100, + 50000); +} + +static int apple_pmp_report_entry_power_on(struct generic_pm_domain *genpd) +{ + return apple_pmp_report_set_state(genpd, true); +} + +static int apple_pmp_report_entry_power_off(struct generic_pm_domain *genpd) +{ + return apple_pmp_report_set_state(genpd, false); +} + +static int apple_pmp_report_entry_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct apple_pmp_report_entry *ent; + int ret; + const char *name; + struct of_phandle_iterator it; + + ent = devm_kzalloc(dev, sizeof(*ent), GFP_KERNEL); + if (!ent) + return -ENOMEM; + + ent->dev = dev; + + ret = of_property_read_u32(node, "reg", &ent->id); + if (ret) + return dev_err_probe(dev, ret, "missing reg property\n"); + + ret = of_property_read_string(node, "label", &name); + if (ret < 0) + return dev_err_probe(dev, ret, "missing label property\n"); + + if (of_property_read_bool(node, "apple,always-on")) { + ent->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; + apple_pmp_report_set_state(&ent->genpd, true); + } + + ent->genpd.name = name; + ent->genpd.power_on = apple_pmp_report_entry_power_on; + ent->genpd.power_off = apple_pmp_report_entry_power_off; + + ret = pm_genpd_init(&ent->genpd, NULL, true); + if (ret) + return dev_err_probe(dev, ret, "pm_genpd_init failed\n"); + + ret = of_genpd_add_provider_simple(node, &ent->genpd); + if (ret) + return dev_err_probe(dev, ret, "of_genpd_add_provider_simple failed\n"); + + of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) { + struct of_phandle_args parent, child; + + parent.np = it.node; + parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS); + child.np = node; + child.args_count = 0; + ret = of_genpd_add_subdomain(&parent, &child); + + if (ret == -EPROBE_DEFER) { + of_node_put(parent.np); + goto err_remove; + } else if (ret < 0) { + dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n", + ret, it.node->name, node->name); + of_node_put(parent.np); + goto err_remove; + } + } + + pm_genpd_remove_device(dev); + + return 0; +err_remove: + of_genpd_del_provider(node); + pm_genpd_remove(&ent->genpd); + return ret; +} + +static const struct of_device_id apple_pmp_report_entry_of_match[] = { + { .compatible = "apple,t6000-pmp-v2-report-entry" }, + {} +}; + +static struct platform_driver apple_pmp_report_entry_driver = { + .probe = apple_pmp_report_entry_probe, + .driver = { + .name = "apple-pmp-report-entry", + .of_match_table = apple_pmp_report_entry_of_match, + }, +}; + +MODULE_DEVICE_TABLE(of, apple_pmp_report_of_match); +MODULE_DEVICE_TABLE(of, apple_pmp_report_entry_of_match); + +static int __init apple_pmp_report_init(void) +{ + platform_driver_register(&apple_pmp_report_entry_driver); + platform_driver_register(&apple_pmp_report_driver); + return 0; +} + +static void __exit apple_pmp_report_exit(void) +{ + platform_driver_unregister(&apple_pmp_report_entry_driver); + platform_driver_unregister(&apple_pmp_report_driver); +} + +module_init(apple_pmp_report_init); +module_exit(apple_pmp_report_exit); + +MODULE_DESCRIPTION("PMP power state reporting driver for Apple SoCs"); +MODULE_LICENSE("Dual MIT/GPL"); From ba55a7ab0f6380bbedb1480e837abed687c987dd Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 21 Mar 2026 17:39:42 +0100 Subject: [PATCH 133/352] arm64: configs: asahi: Add new configs for v6.19 Add following configs for PMP: - CONFIG_APPLE_PMP - CONFIG_APPLE_PMP_REPORT Signed-off-by: Janne Grunau --- arch/arm64/configs/asahi.config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/asahi.config b/arch/arm64/configs/asahi.config index 7ed0a173544025..c76f2c727fb0dd 100644 --- a/arch/arm64/configs/asahi.config +++ b/arch/arm64/configs/asahi.config @@ -7,6 +7,7 @@ CONFIG_ARM64_16K_PAGES=y CONFIG_ARM64_MEMORY_MODEL_CONTROL=y CONFIG_ARM_APPLE_CPUIDLE=y CONFIG_ARM_APPLE_SOC_CPUFREQ=m +CONFIG_BT_BRCMEXT=y CONFIG_BT_HCIBCM4377=m CONFIG_PCIE_APPLE=m CONFIG_NVME_APPLE=m @@ -61,6 +62,8 @@ CONFIG_RUST_APPLE_RTKIT=y CONFIG_APPLE_AOP=m CONFIG_APPLE_SEP=m CONFIG_APPLE_PMGR_PWRSTATE=y +CONFIG_APPLE_PMP=m +CONFIG_APPLE_PMP_REPORT=y CONFIG_IIO_AOP_SENSOR_LAS=m CONFIG_IIO_AOP_SENSOR_ALS=m CONFIG_RUST_FW_LOADER_ABSTRACTIONS=y From 2a467e61d288146e8b5e748c8cef4979c399cedc Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 8 Jul 2022 02:12:57 +0900 Subject: [PATCH 134/352] HID: magicmouse: Add MTP multi-touch device support Apple M2 devices expose the multi-touch device over the HID over DockChannel transport, which we represent as the HOST bus type. The report format is the same, except the legacy mouse header is gone and there is no enable request needed. Signed-off-by: Hector Martin --- drivers/hid/hid-magicmouse.c | 63 +++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index a2123299942094..8d4d75c77f570f 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -61,6 +61,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define MOUSE2_REPORT_ID 0x12 #define DOUBLE_REPORT_ID 0xf7 #define SPI_REPORT_ID 0x02 +#define MTP_REPORT_ID 0x75 #define USB_BATTERY_TIMEOUT_SEC 60 #define MAX_CONTACTS 16 @@ -586,25 +587,32 @@ struct tp_finger { } __attribute__((packed, aligned(2))); /** - * struct trackpad report + * vendor trackpad report * - * @report_id: reportid - * @buttons: HID Usage Buttons 3 1-bit reports * @num_fingers: the number of fingers being reported in @fingers - * @clicked: same as @buttons + * @buttons: same as HID buttons */ struct tp_header { + // HID vendor part, up to 1751 bytes + u8 unknown[22]; + u8 num_fingers; + u8 buttons; + u8 unknown3[14]; +}; + +/** + * standard HID mouse report + * + * @report_id: reportid + * @buttons: HID Usage Buttons 3 1-bit reports + */ +struct tp_mouse_report { // HID mouse report u8 report_id; u8 buttons; u8 rel_x; u8 rel_y; u8 padding[4]; - // HID vendor part, up to 1751 bytes - u8 unknown[22]; - u8 num_fingers; - u8 clicked; - u8 unknown3[14]; }; static inline int le16_to_int(__le16 x) @@ -634,7 +642,7 @@ static void report_finger_data(struct input_dev *input, int slot, input_report_abs(input, ABS_MT_POSITION_Y, pos->y); } -static int magicmouse_raw_event_spi(struct hid_device *hdev, +static int magicmouse_raw_event_mtp(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct magicmouse_sc *msc = hid_get_drvdata(hdev); @@ -651,9 +659,6 @@ static int magicmouse_raw_event_spi(struct hid_device *hdev, // print_hex_dump_debug("appleft ev: ", DUMP_PREFIX_OFFSET, 16, 1, data, // size, false); - if (data[0] != SPI_REPORT_ID) - return 0; - /* Expect 46 bytes of prefix, and N * 30 bytes of touch data. */ if (size < hdr_sz || ((size - hdr_sz) % touch_sz) != 0) return 0; @@ -692,12 +697,26 @@ static int magicmouse_raw_event_spi(struct hid_device *hdev, } input_mt_sync_frame(input); - input_report_key(input, BTN_MOUSE, data[1] & 1); + input_report_key(input, BTN_MOUSE, tp_hdr->buttons & 1); input_sync(input); return 1; } +static int magicmouse_raw_event_spi(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + const size_t hdr_sz = sizeof(struct tp_mouse_report); + + if (size < hdr_sz) + return 0; + + if (data[0] != SPI_REPORT_ID) + return 0; + + return magicmouse_raw_event_mtp(hdev, report, data + hdr_sz, size - hdr_sz); +} + static int magicmouse_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { @@ -1124,7 +1143,7 @@ static int magicmouse_probe(struct hid_device *hdev, struct hid_report *report; int ret; - if (id->bus == BUS_SPI && id->vendor == SPI_VENDOR_ID_APPLE && + if ((id->bus == BUS_SPI || id->bus == BUS_HOST) && id->vendor == SPI_VENDOR_ID_APPLE && hdev->type != HID_TYPE_SPI_MOUSE) return -ENODEV; @@ -1136,7 +1155,10 @@ static int magicmouse_probe(struct hid_device *hdev, // internal trackpad use a data format use input ops to avoid // conflicts with the report ID. - if (id->vendor == SPI_VENDOR_ID_APPLE) { + if (id->bus == BUS_HOST) { + msc->input_ops.raw_event = magicmouse_raw_event_mtp; + msc->input_ops.setup_input = magicmouse_setup_input_spi; + } else if (id->bus == BUS_SPI) { msc->input_ops.raw_event = magicmouse_raw_event_spi; msc->input_ops.setup_input = magicmouse_setup_input_spi; } else { @@ -1204,6 +1226,9 @@ static int magicmouse_probe(struct hid_device *hdev, break; default: switch (id->bus) { + case BUS_HOST: + report = hid_register_report(hdev, HID_INPUT_REPORT, MTP_REPORT_ID, 0); + break; case BUS_SPI: report = hid_register_report(hdev, HID_INPUT_REPORT, SPI_REPORT_ID, 0); break; @@ -1222,6 +1247,10 @@ static int magicmouse_probe(struct hid_device *hdev, } report->size = 6; + /* MTP devices do not need the MT enable, this is handled by the MTP driver */ + if (id->bus == BUS_HOST) + return 0; + /* * Some devices repond with 'invalid report id' when feature * report switching it into multitouch mode is sent to it. @@ -1315,6 +1344,8 @@ static const struct hid_device_id magic_mice[] = { USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 }, { HID_SPI_DEVICE(SPI_VENDOR_ID_APPLE, HID_ANY_ID), .driver_data = 0 }, + { HID_DEVICE(BUS_HOST, HID_GROUP_ANY, HOST_VENDOR_ID_APPLE, + HID_ANY_ID), .driver_data = 0 }, { } }; MODULE_DEVICE_TABLE(hid, magic_mice); From 7f580e8a5f628a145e80b3a3b458b6f516037a53 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 11 Dec 2022 22:56:16 +0100 Subject: [PATCH 135/352] HID: magicmouse: Add .reset_resume for SPI trackpads The trackpad has to request multi touch reports during resume. Signed-off-by: Janne Grunau --- drivers/hid/hid-magicmouse.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 8d4d75c77f570f..d64bcc02d6668f 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -1350,6 +1350,16 @@ static const struct hid_device_id magic_mice[] = { }; MODULE_DEVICE_TABLE(hid, magic_mice); +#ifdef CONFIG_PM +static int magicmouse_reset_resume(struct hid_device *hdev) +{ + if (hdev->bus == BUS_SPI) + return magicmouse_enable_multitouch(hdev); + + return 0; +} +#endif + static struct hid_driver magicmouse_driver = { .name = "magicmouse", .id_table = magic_mice, @@ -1360,6 +1370,10 @@ static struct hid_driver magicmouse_driver = { .event = magicmouse_event, .input_mapping = magicmouse_input_mapping, .input_configured = magicmouse_input_configured, +#ifdef CONFIG_PM + .reset_resume = magicmouse_reset_resume, +#endif + }; module_hid_driver(magicmouse_driver); From 78477b90555f3386e05ce4e7b6cddb3a8737d584 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 30 Apr 2023 23:48:45 +0900 Subject: [PATCH 136/352] HID: magicmouse: Handle touch controller resets on SPI devices On at least some SPI devices (e.g. recent Apple Silicon machines), the Broadcom touch controller is prone to crashing. When this happens, the STM eventually notices and resets it. It then notifies the driver via HID report 0x60, and the driver needs to re-enable MT mode to make things work again. This poses an additional issue: the hidinput core will close the low-level transport while the device is closed, which can cause us to miss a reset notification. To fix this, override the input open/close callbacks and send the MT enable every time the HID device is opened, instead of only once on probe. This should increase general robustness, even if the reset mechanism doesn't work for some reason, so it's worth doing it for USB devices too. MTP devices are exempt since they do not require the MT enable at all. Signed-off-by: Hector Martin --- drivers/hid/hid-magicmouse.c | 108 ++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 21 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index d64bcc02d6668f..dc2d3cb89214cc 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -61,6 +61,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define MOUSE2_REPORT_ID 0x12 #define DOUBLE_REPORT_ID 0xf7 #define SPI_REPORT_ID 0x02 +#define SPI_RESET_REPORT_ID 0x60 #define MTP_REPORT_ID 0x75 #define USB_BATTERY_TIMEOUT_SEC 60 @@ -176,6 +177,50 @@ struct magicmouse_sc { struct magicmouse_input_ops input_ops; }; +static int magicmouse_enable_multitouch(struct hid_device *hdev); + +static int magicmouse_open(struct input_dev *dev) +{ + struct hid_device *hdev = input_get_drvdata(dev); + struct magicmouse_sc *msc = hid_get_drvdata(hdev); + int ret; + + ret = hid_hw_open(hdev); + if (ret) + return ret; + + /* + * Some devices repond with 'invalid report id' when feature + * report switching it into multitouch mode is sent to it. + * + * This results in -EIO from the _raw low-level transport callback, + * but there seems to be no other way of switching the mode. + * Thus the super-ugly hacky success check below. + */ + ret = magicmouse_enable_multitouch(hdev); + if (ret != -EIO && ret < 0) { + hid_err(hdev, "unable to request touch data (%d)\n", ret); + return ret; + } + if (ret == -EIO && (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || + hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC)) { + schedule_delayed_work(&msc->work, msecs_to_jiffies(500)); + } + + /* + * MT enable is usually not required after the first time, so don't + * consider it fatal. + */ + return 0; +} + +static void magicmouse_close(struct input_dev *dev) +{ + struct hid_device *hdev = input_get_drvdata(dev); + + hid_hw_close(hdev); +} + static int magicmouse_firm_touch(struct magicmouse_sc *msc) { int touch = -1; @@ -706,12 +751,19 @@ static int magicmouse_raw_event_mtp(struct hid_device *hdev, static int magicmouse_raw_event_spi(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { + struct magicmouse_sc *msc = hid_get_drvdata(hdev); const size_t hdr_sz = sizeof(struct tp_mouse_report); - if (size < hdr_sz) + if (!size) return 0; - if (data[0] != SPI_REPORT_ID) + if (data[0] == SPI_RESET_REPORT_ID) { + hid_info(hdev, "Touch controller was reset, re-enabling touch mode\n"); + schedule_delayed_work(&msc->work, msecs_to_jiffies(10)); + return 1; + } + + if (data[0] != SPI_REPORT_ID || size < hdr_sz) return 0; return magicmouse_raw_event_mtp(hdev, report, data + hdr_sz, size - hdr_sz); @@ -904,10 +956,17 @@ static int magicmouse_setup_input_usb(struct input_dev *input, */ __clear_bit(EV_REP, input->evbit); + /* + * This isn't strictly speaking needed for USB, but enabling MT on + * device open is probably more robust than only doing it once on probe + * even if USB devices are not known to suffer from the SPI reset issue. + */ + input->open = magicmouse_open; + input->close = magicmouse_close; return 0; } -static int magicmouse_setup_input_spi(struct input_dev *input, +static int magicmouse_setup_input_mtp(struct input_dev *input, struct hid_device *hdev) { int error; @@ -980,6 +1039,25 @@ static int magicmouse_setup_input_spi(struct input_dev *input, return 0; } +static int magicmouse_setup_input_spi(struct input_dev *input, + struct hid_device *hdev) +{ + int ret = magicmouse_setup_input_mtp(input, hdev); + if (ret) + return ret; + + /* + * Override the default input->open function to send the MT + * enable every time the device is opened. This ensures it works + * even if we missed a reset event due to the device being closed. + * input->close is overridden for symmetry. + */ + input->open = magicmouse_open; + input->close = magicmouse_close; + + return 0; +} + static int magicmouse_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -1046,7 +1124,7 @@ static int magicmouse_enable_multitouch(struct hid_device *hdev) feature_size = sizeof(feature_mt_trackpad2_bt); feature = feature_mt_trackpad2_bt; break; - default: /* USB_VENDOR_ID_APPLE || SPI_VENDOR_ID_APPLE */ + default: /* USB_VENDOR_ID_APPLE || SPI_VENDOR_ID_APPLE */ feature_size = sizeof(feature_mt_trackpad2_usb); feature = feature_mt_trackpad2_usb; } @@ -1157,7 +1235,7 @@ static int magicmouse_probe(struct hid_device *hdev, // conflicts with the report ID. if (id->bus == BUS_HOST) { msc->input_ops.raw_event = magicmouse_raw_event_mtp; - msc->input_ops.setup_input = magicmouse_setup_input_spi; + msc->input_ops.setup_input = magicmouse_setup_input_mtp; } else if (id->bus == BUS_SPI) { msc->input_ops.raw_event = magicmouse_raw_event_spi; msc->input_ops.setup_input = magicmouse_setup_input_spi; @@ -1251,22 +1329,10 @@ static int magicmouse_probe(struct hid_device *hdev, if (id->bus == BUS_HOST) return 0; - /* - * Some devices repond with 'invalid report id' when feature - * report switching it into multitouch mode is sent to it. - * - * This results in -EIO from the _raw low-level transport callback, - * but there seems to be no other way of switching the mode. - * Thus the super-ugly hacky success check below. - */ - ret = magicmouse_enable_multitouch(hdev); - if (ret != -EIO && ret < 0) { - hid_err(hdev, "unable to request touch data (%d)\n", ret); - goto err_stop_hw; - } - if (ret == -EIO && (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || - id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC)) { - schedule_delayed_work(&msc->work, msecs_to_jiffies(500)); + /* SPI devices need to watch for reset events to re-send the MT enable */ + if (id->bus == BUS_SPI) { + report = hid_register_report(hdev, HID_INPUT_REPORT, SPI_RESET_REPORT_ID, 0); + report->size = 2; } return 0; From 4bc659066b0ab9a53ef05976abbdea36716ba705 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 3 Dec 2023 21:08:17 +0900 Subject: [PATCH 137/352] HID: magicmouse: Query device dimensions via HID report For SPI/MTP trackpads, query the dimensions via HID report instead of hardcoding values. TODO: Does this work for the USB/BT devices? Maybe we can get rid of the hardcoded sizes everywhere? Signed-off-by: Hector Martin --- drivers/hid/hid-magicmouse.c | 104 +++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index dc2d3cb89214cc..82b2a0954a2040 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -63,6 +63,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define SPI_REPORT_ID 0x02 #define SPI_RESET_REPORT_ID 0x60 #define MTP_REPORT_ID 0x75 +#define SENSOR_DIMENSIONS_REPORT_ID 0xd9 #define USB_BATTERY_TIMEOUT_SEC 60 #define MAX_CONTACTS 16 @@ -117,6 +118,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define TRACKPAD2_RES_Y \ ((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100)) +/* These are fallback values, since the real values will be queried from the device. */ #define J314_TP_DIMENSION_X (float)13000 #define J314_TP_MIN_X -5900 #define J314_TP_MAX_X 6500 @@ -140,6 +142,7 @@ struct magicmouse_input_ops { * struct magicmouse_sc - Tracks Magic Mouse-specific data. * @input: Input device through which we report events. * @quirks: Currently unused. + * @query_dimensions: Whether to query and update dimensions on first open * @ntouches: Number of touches in most recent touch report. * @scroll_accel: Number of consecutive scroll motions. * @scroll_jiffies: Time of last scroll motion. @@ -154,6 +157,7 @@ struct magicmouse_input_ops { struct magicmouse_sc { struct input_dev *input; unsigned long quirks; + bool query_dimensions; int ntouches; int scroll_accel; @@ -179,6 +183,11 @@ struct magicmouse_sc { static int magicmouse_enable_multitouch(struct hid_device *hdev); +static inline int le16_to_int(__le16 x) +{ + return (signed short)le16_to_cpu(x); +} + static int magicmouse_open(struct input_dev *dev) { struct hid_device *hdev = input_get_drvdata(dev); @@ -196,21 +205,69 @@ static int magicmouse_open(struct input_dev *dev) * This results in -EIO from the _raw low-level transport callback, * but there seems to be no other way of switching the mode. * Thus the super-ugly hacky success check below. + * + * MTP devices do not need this. */ - ret = magicmouse_enable_multitouch(hdev); - if (ret != -EIO && ret < 0) { - hid_err(hdev, "unable to request touch data (%d)\n", ret); - return ret; - } - if (ret == -EIO && (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || - hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC)) { - schedule_delayed_work(&msc->work, msecs_to_jiffies(500)); + if (hdev->bus != BUS_HOST) { + ret = magicmouse_enable_multitouch(hdev); + if (ret != -EIO && ret < 0) { + hid_err(hdev, "unable to request touch data (%d)\n", ret); + return ret; + } + if (ret == -EIO && (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || + hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC)) { + schedule_delayed_work(&msc->work, msecs_to_jiffies(500)); + } } /* - * MT enable is usually not required after the first time, so don't - * consider it fatal. + * For Apple Silicon trackpads, we want to query the dimensions on + * device open. This is because doing so requires the firmware, but + * we don't want to force a firmware load until the device is opened + * for the first time. So do that here and update the input properties + * just in time before userspace queries them. */ + if (msc->query_dimensions) { + struct input_dev *input = msc->input; + u8 buf[32]; + struct { + __le32 width; + __le32 height; + __le16 min_x; + __le16 min_y; + __le16 max_x; + __le16 max_y; + } dim; + uint32_t x_span, y_span; + + ret = hid_hw_raw_request(hdev, SENSOR_DIMENSIONS_REPORT_ID, buf, sizeof(buf), HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret < (int)(1 + sizeof(dim))) { + hid_err(hdev, "unable to request dimensions (%d)\n", ret); + return ret; + } + + memcpy(&dim, buf + 1, sizeof(dim)); + + /* finger position */ + input_set_abs_params(input, ABS_MT_POSITION_X, + le16_to_int(dim.min_x), le16_to_int(dim.max_x), 0, 0); + /* Y axis is inverted */ + input_set_abs_params(input, ABS_MT_POSITION_Y, + -le16_to_int(dim.max_y), -le16_to_int(dim.min_y), 0, 0); + x_span = le16_to_int(dim.max_x) - le16_to_int(dim.min_x); + y_span = le16_to_int(dim.max_y) - le16_to_int(dim.min_y); + + /* X/Y resolution */ + input_abs_set_res(input, ABS_MT_POSITION_X, 100 * x_span / le32_to_cpu(dim.width) ); + input_abs_set_res(input, ABS_MT_POSITION_Y, 100 * y_span / le32_to_cpu(dim.height) ); + + /* copy info, as input_mt_init_slots() does */ + dev->absinfo[ABS_X] = dev->absinfo[ABS_MT_POSITION_X]; + dev->absinfo[ABS_Y] = dev->absinfo[ABS_MT_POSITION_Y]; + + msc->query_dimensions = false; + } + return 0; } @@ -660,11 +717,6 @@ struct tp_mouse_report { u8 padding[4]; }; -static inline int le16_to_int(__le16 x) -{ - return (signed short)le16_to_cpu(x); -} - static void report_finger_data(struct input_dev *input, int slot, const struct input_mt_pos *pos, const struct tp_finger *f) @@ -971,6 +1023,7 @@ static int magicmouse_setup_input_mtp(struct input_dev *input, { int error; int mt_flags = 0; + struct magicmouse_sc *msc = hid_get_drvdata(hdev); __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); __clear_bit(BTN_0, input->keybit); @@ -1036,6 +1089,18 @@ static int magicmouse_setup_input_mtp(struct input_dev *input, if (error) return error; + /* + * Override the default input->open function to send the MT + * enable every time the device is opened. This ensures it works + * even if we missed a reset event due to the device being closed. + * input->close is overridden for symmetry. + * + * This also takes care of the dimensions query. + */ + input->open = magicmouse_open; + input->close = magicmouse_close; + msc->query_dimensions = true; + return 0; } @@ -1046,15 +1111,6 @@ static int magicmouse_setup_input_spi(struct input_dev *input, if (ret) return ret; - /* - * Override the default input->open function to send the MT - * enable every time the device is opened. This ensures it works - * even if we missed a reset event due to the device being closed. - * input->close is overridden for symmetry. - */ - input->open = magicmouse_open; - input->close = magicmouse_close; - return 0; } From ed5c2a49b2ad6102dc9a4a26cba8a71e60fb2843 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 10 Dec 2021 19:38:43 +0100 Subject: [PATCH 138/352] WIP: HID: transport: spi: add Apple SPI transport Keyboard and trackpad of Apple Sillicon SoCs (M1, M1 Pro/Max) laptops are are HID devices connected via SPI. This is the same protocol as implemented by applespi.c. It was not noticed that protocol is a transport for HID. Adding support for ACPI based Intel MacBooks will be done in a separate commit. How HID is mapped in this protocol is not yet fully understood. Microsoft has a specification for HID over SPI [1] incompatible with the transport protocol used by Apple. [1] https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/hid-over-spi Contains "HID: transport: spi: apple: Increase receive buffer size" The SPI receive buffer is passed directly to hid_input_report() if it contains a complete report. It is then passed to hid_report_raw_event() which computes the expected report size and memsets the "missing trailing data up to HID_MAX_BUFFER_SIZE (16K) or hid_ll_driver.max_buffer_size (if set) to zero. Co-developed-by: Hector Martin Signed-off-by: Hector Martin Signed-off-by: Janne Grunau --- drivers/hid/Kconfig | 2 + drivers/hid/Makefile | 2 + drivers/hid/spi-hid/Kconfig | 24 + drivers/hid/spi-hid/Makefile | 10 + drivers/hid/spi-hid/spi-hid-apple-core.c | 1194 ++++++++++++++++++++++ drivers/hid/spi-hid/spi-hid-apple-of.c | 153 +++ drivers/hid/spi-hid/spi-hid-apple.h | 35 + 7 files changed, 1420 insertions(+) create mode 100644 drivers/hid/spi-hid/Kconfig create mode 100644 drivers/hid/spi-hid/Makefile create mode 100644 drivers/hid/spi-hid/spi-hid-apple-core.c create mode 100644 drivers/hid/spi-hid/spi-hid-apple-of.c create mode 100644 drivers/hid/spi-hid/spi-hid-apple.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index e01a6da3eade45..e2ca5dd016f08d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1456,4 +1456,6 @@ endif # HID source "drivers/hid/usbhid/Kconfig" +source "drivers/hid/spi-hid/Kconfig" + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index e01838239ae64c..0907f3a109c26c 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -174,6 +174,8 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ +obj-$(CONFIG_SPI_HID_APPLE_CORE) += spi-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ diff --git a/drivers/hid/spi-hid/Kconfig b/drivers/hid/spi-hid/Kconfig new file mode 100644 index 00000000000000..59076c6ebeed9b --- /dev/null +++ b/drivers/hid/spi-hid/Kconfig @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-only +menu "SPI HID support" + depends on SPI + +config SPI_HID_APPLE_OF + tristate "HID over SPI transport layer for Apple Silicon SoCs" + depends on INPUT && OF + select SPI_HID_APPLE_CORE + help + Say Y here if you use Apple Silicon based laptop. The keyboard and + touchpad are HID based devices connected via SPI. + + If unsure, say N. + + This support is also available as a module. If so, the module + will be called spi-hid-apple-of. It will also build/depend on the + module spi-hid-apple. + +endmenu + +config SPI_HID_APPLE_CORE + tristate + select HID + select CRC16 diff --git a/drivers/hid/spi-hid/Makefile b/drivers/hid/spi-hid/Makefile new file mode 100644 index 00000000000000..f276ee12cb94fc --- /dev/null +++ b/drivers/hid/spi-hid/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for SPI HID tarnsport drivers +# + +obj-$(CONFIG_SPI_HID_APPLE_CORE) += spi-hid-apple.o + +spi-hid-apple-objs = spi-hid-apple-core.o + +obj-$(CONFIG_SPI_HID_APPLE_OF) += spi-hid-apple-of.o diff --git a/drivers/hid/spi-hid/spi-hid-apple-core.c b/drivers/hid/spi-hid/spi-hid-apple-core.c new file mode 100644 index 00000000000000..2ed909895391c8 --- /dev/null +++ b/drivers/hid/spi-hid/spi-hid-apple-core.c @@ -0,0 +1,1194 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * + * Apple SPI HID transport driver + * + * Copyright (C) The Asahi Linux Contributors + * + * Based on: drivers/input/applespi.c + * + * MacBook (Pro) SPI keyboard and touchpad driver + * + * Copyright (c) 2015-2018 Federico Lorenzi + * Copyright (c) 2017-2018 Ronald Tschalär + * + */ + +//#define DEBUG 2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spi-hid-apple.h" + +#define SPIHID_DEF_WAIT msecs_to_jiffies(1000) + +#define SPIHID_MAX_INPUT_REPORT_SIZE 0x800 + +/* support only keyboard, trackpad and management dev for now */ +#define SPIHID_MAX_DEVICES 3 + +#define SPIHID_DEVICE_ID_MNGT 0x0 +#define SPIHID_DEVICE_ID_KBD 0x1 +#define SPIHID_DEVICE_ID_TP 0x2 +#define SPIHID_DEVICE_ID_INFO 0xd0 + +#define SPIHID_READ_PACKET 0x20 +#define SPIHID_WRITE_PACKET 0x40 + +#define SPIHID_DESC_MAX 512 + +#define SPIHID_SET_LEDS 0x0151 /* caps lock */ + +#define SPI_RW_CHG_DELAY_US 200 /* 'Inter Stage Us'? */ + +static const u8 spi_hid_apple_booted[4] = { 0xa0, 0x80, 0x00, 0x00 }; +static const u8 spi_hid_apple_status_ok[4] = { 0xac, 0x27, 0x68, 0xd5 }; + +struct spihid_interface { + struct hid_device *hid; + u8 *hid_desc; + u32 hid_desc_len; + u32 id; + unsigned country; + u32 max_control_report_len; + u32 max_input_report_len; + u32 max_output_report_len; + u8 name[32]; + u8 reply_buf[SPIHID_DESC_MAX]; + u32 reply_len; + bool ready; +}; + +struct spihid_input_report { + u8 *buf; + u32 length; + u32 offset; + u8 device; + u8 flags; +}; + +struct spihid_apple { + struct spi_device *spidev; + + struct spihid_apple_ops *ops; + + struct spihid_interface mngt; + struct spihid_interface kbd; + struct spihid_interface tp; + + wait_queue_head_t wait; + struct mutex tx_lock; //< protects against concurrent SPI writes + + struct spi_message rx_msg; + struct spi_message tx_msg; + struct spi_transfer rx_transfer; + struct spi_transfer tx_transfer; + struct spi_transfer status_transfer; + + u8 *rx_buf; + u8 *tx_buf; + u8 *status_buf; + + u8 vendor[32]; + u8 product[64]; + u8 serial[32]; + + u32 num_devices; + + u32 vendor_id; + u32 product_id; + u32 version_number; + + u8 msg_id; + + /* fragmented HID report */ + struct spihid_input_report report; + + /* state tracking flags */ + bool status_booted; + +#ifdef IRQ_WAKE_SUPPORT + bool irq_wake_enabled; +#endif +}; + +/** + * struct spihid_msg_hdr - common header of protocol messages. + * + * Each message begins with fixed header, followed by a message-type specific + * payload, and ends with a 16-bit crc. Because of the varying lengths of the + * payload, the crc is defined at the end of each payload struct, rather than + * in this struct. + * + * @unknown0: request type? output, input (0x10), feature, protocol + * @unknown1: maybe report id? + * @unknown2: mostly zero, in info request maybe device num + * @id: incremented on each message, rolls over after 255; there is a + * separate counter for each message type. + * @rsplen: response length (the exact nature of this field is quite + * speculative). On a request/write this is often the same as + * @length, though in some cases it has been seen to be much larger + * (e.g. 0x400); on a response/read this the same as on the + * request; for reads that are not responses it is 0. + * @length: length of the remainder of the data in the whole message + * structure (after re-assembly in case of being split over + * multiple spi-packets), minus the trailing crc. The total size + * of a message is therefore @length + 10. + */ + +struct spihid_msg_hdr { + u8 unknown0; + u8 unknown1; + u8 unknown2; + u8 id; + __le16 rsplen; + __le16 length; +}; + +/** + * struct spihid_transfer_packet - a complete spi packet; always 256 bytes. This carries + * the (parts of the) message in the data. But note that this does not + * necessarily contain a complete message, as in some cases (e.g. many + * fingers pressed) the message is split over multiple packets (see the + * @offset, @remain, and @length fields). In general the data parts in + * spihid_transfer_packet's are concatenated until @remaining is 0, and the + * result is an message. + * + * @flags: 0x40 = write (to device), 0x20 = read (from device); note that + * the response to a write still has 0x40. + * @device: 1 = keyboard, 2 = touchpad + * @offset: specifies the offset of this packet's data in the complete + * message; i.e. > 0 indicates this is a continuation packet (in + * the second packet for a message split over multiple packets + * this would then be the same as the @length in the first packet) + * @remain: number of message bytes remaining in subsequents packets (in + * the first packet of a message split over two packets this would + * then be the same as the @length in the second packet) + * @length: length of the valid data in the @data in this packet + * @data: all or part of a message + * @crc16: crc over this whole structure minus this @crc16 field. This + * covers just this packet, even on multi-packet messages (in + * contrast to the crc in the message). + */ +struct spihid_transfer_packet { + u8 flags; + u8 device; + __le16 offset; + __le16 remain; + __le16 length; + u8 data[246]; + __le16 crc16; +}; + +/* + * how HID is mapped onto the protocol is not fully clear. This are the known + * reports/request: + * + * pkt.flags pkt.dev? msg.u0 msg.u1 msg.u2 + * info 0x40 0xd0 0x20 0x01 0xd0 + * + * info mngt: 0x40 0xd0 0x20 0x10 0x00 + * info kbd: 0x40 0xd0 0x20 0x10 0x01 + * info tp: 0x40 0xd0 0x20 0x10 0x02 + * + * desc kbd: 0x40 0xd0 0x20 0x10 0x01 + * desc trackpad: 0x40 0xd0 0x20 0x10 0x02 + * + * mt mode: 0x40 0x02 0x52 0x02 0x00 set protocol? + * capslock led 0x40 0x01 0x51 0x01 0x00 output report + * + * report kbd: 0x20 0x01 0x10 0x01 0x00 input report + * report tp: 0x20 0x02 0x10 0x02 0x00 input report + * + */ + + +static int spihid_apple_request(struct spihid_apple *spihid, u8 target, u8 unk0, + u8 unk1, u8 unk2, u16 resp_len, u8 *buf, + size_t len) +{ + struct spihid_transfer_packet *pkt; + struct spihid_msg_hdr *hdr; + u16 crc; + int err; + + /* know reports are small enoug to fit in a single packet */ + if (len > sizeof(pkt->data) - sizeof(*hdr) - sizeof(__le16)) + return -EINVAL; + + err = mutex_lock_interruptible(&spihid->tx_lock); + if (err < 0) + return err; + + pkt = (struct spihid_transfer_packet *)spihid->tx_buf; + + memset(pkt, 0, sizeof(*pkt)); + pkt->flags = SPIHID_WRITE_PACKET; + pkt->device = target; + pkt->length = cpu_to_le16(sizeof(*hdr) + len + sizeof(__le16)); + + hdr = (struct spihid_msg_hdr *)&pkt->data[0]; + hdr->unknown0 = unk0; + hdr->unknown1 = unk1; + hdr->unknown2 = unk2; + hdr->id = spihid->msg_id++; + hdr->rsplen = cpu_to_le16(resp_len); + hdr->length = cpu_to_le16(len); + + if (len) + memcpy(pkt->data + sizeof(*hdr), buf, len); + crc = crc16(0, &pkt->data[0], sizeof(*hdr) + len); + put_unaligned_le16(crc, pkt->data + sizeof(*hdr) + len); + + pkt->crc16 = cpu_to_le16(crc16(0, spihid->tx_buf, + offsetof(struct spihid_transfer_packet, crc16))); + + memset(spihid->status_buf, 0, sizeof(spi_hid_apple_status_ok)); + + err = spi_sync(spihid->spidev, &spihid->tx_msg); + + if (memcmp(spihid->status_buf, spi_hid_apple_status_ok, + sizeof(spi_hid_apple_status_ok))) { + u8 *b = spihid->status_buf; + dev_warn_ratelimited(&spihid->spidev->dev, "status message " + "mismatch: %02x %02x %02x %02x\n", + b[0], b[1], b[2], b[3]); + } + mutex_unlock(&spihid->tx_lock); + if (err < 0) + return err; + + return (int)len; +} + +static struct spihid_apple *spihid_get_data(struct spihid_interface *idev) +{ + switch (idev->id) { + case SPIHID_DEVICE_ID_KBD: + return container_of(idev, struct spihid_apple, kbd); + case SPIHID_DEVICE_ID_TP: + return container_of(idev, struct spihid_apple, tp); + default: + return NULL; + } +} + +static int apple_ll_start(struct hid_device *hdev) +{ + /* no-op SPI transport is already setup */ + return 0; +}; + +static void apple_ll_stop(struct hid_device *hdev) +{ + /* no-op, devices will be desstroyed on driver destruction */ +} + +static int apple_ll_open(struct hid_device *hdev) +{ + struct spihid_apple *spihid; + struct spihid_interface *idev = hdev->driver_data; + + if (idev->hid_desc_len == 0) { + spihid = spihid_get_data(idev); + dev_warn(&spihid->spidev->dev, + "HID descriptor missing for dev %u", idev->id); + } else + idev->ready = true; + + return 0; +} + +static void apple_ll_close(struct hid_device *hdev) +{ + struct spihid_interface *idev = hdev->driver_data; + idev->ready = false; +} + +static int apple_ll_parse(struct hid_device *hdev) +{ + struct spihid_interface *idev = hdev->driver_data; + + return hid_parse_report(hdev, idev->hid_desc, idev->hid_desc_len); +} + +static int apple_ll_raw_request(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, size_t len, + unsigned char rtype, int reqtype) +{ + struct spihid_interface *idev = hdev->driver_data; + struct spihid_apple *spihid = spihid_get_data(idev); + int ret; + + dev_dbg(&spihid->spidev->dev, + "apple_ll_raw_request: device:%u reportnum:%hhu rtype:%hhu", + idev->id, reportnum, rtype); + + switch (reqtype) { + case HID_REQ_GET_REPORT: + if (rtype != HID_FEATURE_REPORT) + return -EINVAL; + + idev->reply_len = 0; + ret = spihid_apple_request(spihid, idev->id, 0x32, reportnum, 0x00, len, NULL, 0); + if (ret < 0) + return ret; + + ret = wait_event_interruptible_timeout(spihid->wait, idev->reply_len, + SPIHID_DEF_WAIT); + if (ret == 0) + ret = -ETIMEDOUT; + if (ret < 0) { + dev_err(&spihid->spidev->dev, "waiting for get report failed: %d", ret); + return ret; + } + memcpy(buf, idev->reply_buf, max_t(size_t, len, idev->reply_len)); + return idev->reply_len; + + case HID_REQ_SET_REPORT: + if (buf[0] != reportnum) + return -EINVAL; + if (reportnum != idev->id) { + dev_warn(&spihid->spidev->dev, + "device:%u reportnum:" + "%hhu mismatch", + idev->id, reportnum); + return -EINVAL; + } + return spihid_apple_request(spihid, idev->id, 0x52, reportnum, 0x00, 2, buf, len); + default: + return -EIO; + } +} + +static int apple_ll_output_report(struct hid_device *hdev, __u8 *buf, + size_t len) +{ + struct spihid_interface *idev = hdev->driver_data; + struct spihid_apple *spihid = spihid_get_data(idev); + if (!spihid) + return -1; + + dev_dbg(&spihid->spidev->dev, + "apple_ll_output_report: device:%u len:%zu:", + idev->id, len); + // second idev->id should maybe be buf[0]? + return spihid_apple_request(spihid, idev->id, 0x51, idev->id, 0x00, 0, buf, len); +} + +static struct hid_ll_driver apple_hid_ll = { + .start = &apple_ll_start, + .stop = &apple_ll_stop, + .open = &apple_ll_open, + .close = &apple_ll_close, + .parse = &apple_ll_parse, + .raw_request = &apple_ll_raw_request, + .output_report = &apple_ll_output_report, + .max_buffer_size = SPIHID_MAX_INPUT_REPORT_SIZE, +}; + +static struct spihid_interface *spihid_get_iface(struct spihid_apple *spihid, + u32 iface) +{ + switch (iface) { + case SPIHID_DEVICE_ID_MNGT: + return &spihid->mngt; + case SPIHID_DEVICE_ID_KBD: + return &spihid->kbd; + case SPIHID_DEVICE_ID_TP: + return &spihid->tp; + default: + return NULL; + } +} + +static int spihid_verify_msg(struct spihid_apple *spihid, u8 *buf, size_t len) +{ + u16 msg_crc, crc; + struct device *dev = &spihid->spidev->dev; + + crc = crc16(0, buf, len - sizeof(__le16)); + msg_crc = get_unaligned_le16(buf + len - sizeof(__le16)); + if (crc != msg_crc) { + dev_warn_ratelimited(dev, "Read message crc mismatch\n"); + return 0; + } + return 1; +} + +static bool spihid_status_report(struct spihid_apple *spihid, u8 *pl, + size_t len) +{ + struct device *dev = &spihid->spidev->dev; + dev_dbg(dev, "%s: len: %zu", __func__, len); + if (len == 5 && pl[0] == 0xe0) + return true; + + return false; +} + +static bool spihid_process_input_report(struct spihid_apple *spihid, u32 device, + struct spihid_msg_hdr *hdr, u8 *payload, + size_t len) +{ + //dev_dbg(&spihid>spidev->dev, "input report: req:%hx iface:%u ", hdr->unknown0, device); + if (hdr->unknown0 != 0x10) + return false; + + /* HID device as well but Vendor usage only, handle it internally for now */ + if (device == 0) { + if (hdr->unknown1 == 0xe0) { + return spihid_status_report(spihid, payload, len); + } + } else if (device < SPIHID_MAX_DEVICES) { + struct spihid_interface *iface = + spihid_get_iface(spihid, device); + if (iface && iface->hid && iface->ready) { + hid_input_report(iface->hid, HID_INPUT_REPORT, payload, + len, 1); + return true; + } + } else + dev_dbg(&spihid->spidev->dev, + "unexpected iface:%u for input report", device); + + return false; +} + +struct spihid_device_info { + __le16 u0[2]; + __le16 num_devices; + __le16 vendor_id; + __le16 product_id; + __le16 version_number; + __le16 vendor_str[2]; //< offset and string length + __le16 product_str[2]; //< offset and string length + __le16 serial_str[2]; //< offset and string length +}; + +static bool spihid_process_device_info(struct spihid_apple *spihid, u32 iface, + u8 *payload, size_t len) +{ + struct device *dev = &spihid->spidev->dev; + + if (iface != SPIHID_DEVICE_ID_INFO) + return false; + + if (spihid->vendor_id == 0 && + len >= sizeof(struct spihid_device_info)) { + struct spihid_device_info *info = + (struct spihid_device_info *)payload; + u16 voff, vlen, poff, plen, soff, slen; + u32 num_devices; + + num_devices = __le16_to_cpu(info->num_devices); + + if (num_devices < SPIHID_MAX_DEVICES) { + dev_err(dev, + "Device info reports %u devices, expecting at least 3", + num_devices); + return false; + } + spihid->num_devices = num_devices; + + if (spihid->num_devices > SPIHID_MAX_DEVICES) { + dev_info( + dev, + "limiting the number of devices to mngt, kbd and mouse"); + spihid->num_devices = SPIHID_MAX_DEVICES; + } + + spihid->vendor_id = __le16_to_cpu(info->vendor_id); + spihid->product_id = __le16_to_cpu(info->product_id); + spihid->version_number = __le16_to_cpu(info->version_number); + + voff = __le16_to_cpu(info->vendor_str[0]); + vlen = __le16_to_cpu(info->vendor_str[1]); + + if (voff < len && vlen <= len - voff && + vlen < sizeof(spihid->vendor)) { + memcpy(spihid->vendor, payload + voff, vlen); + spihid->vendor[vlen] = '\0'; + } + + poff = __le16_to_cpu(info->product_str[0]); + plen = __le16_to_cpu(info->product_str[1]); + + if (poff < len && plen <= len - poff && + plen < sizeof(spihid->product)) { + memcpy(spihid->product, payload + poff, plen); + spihid->product[plen] = '\0'; + } + + soff = __le16_to_cpu(info->serial_str[0]); + slen = __le16_to_cpu(info->serial_str[1]); + + if (soff < len && slen <= len - soff && + slen < sizeof(spihid->serial)) { + memcpy(spihid->vendor, payload + soff, slen); + spihid->serial[slen] = '\0'; + } + + wake_up_interruptible(&spihid->wait); + } + return true; +} + +struct spihid_iface_info { + u8 u_0; + u8 interface_num; + u8 u_2; + u8 u_3; + u8 u_4; + u8 country_code; + __le16 max_input_report_len; + __le16 max_output_report_len; + __le16 max_control_report_len; + __le16 name_offset; + __le16 name_length; +}; + +static bool spihid_process_iface_info(struct spihid_apple *spihid, u32 num, + u8 *payload, size_t len) +{ + struct spihid_iface_info *info; + struct spihid_interface *iface = spihid_get_iface(spihid, num); + u32 name_off, name_len; + + if (!iface) + return false; + + if (!iface->max_input_report_len) { + if (len < sizeof(*info)) + return false; + + info = (struct spihid_iface_info *)payload; + + iface->max_input_report_len = + le16_to_cpu(info->max_input_report_len); + iface->max_output_report_len = + le16_to_cpu(info->max_output_report_len); + iface->max_control_report_len = + le16_to_cpu(info->max_control_report_len); + iface->country = info->country_code; + + name_off = le16_to_cpu(info->name_offset); + name_len = le16_to_cpu(info->name_length); + + if (name_off < len && name_len <= len - name_off && + name_len < sizeof(iface->name)) { + memcpy(iface->name, payload + name_off, name_len); + iface->name[name_len] = '\0'; + } + + dev_dbg(&spihid->spidev->dev, "Info for %s, country code: 0x%x", + iface->name, iface->country); + + wake_up_interruptible(&spihid->wait); + } + + return true; +} + +static int spihid_register_hid_device(struct spihid_apple *spihid, + struct spihid_interface *idev, u8 device); + +static bool spihid_process_iface_hid_report_desc(struct spihid_apple *spihid, + u32 num, u8 *payload, + size_t len) +{ + struct spihid_interface *iface = spihid_get_iface(spihid, num); + + if (!iface) + return false; + + if (iface->hid_desc_len == 0) { + if (len > SPIHID_DESC_MAX) + return false; + memcpy(iface->hid_desc, payload, len); + iface->hid_desc_len = len; + + /* do not register the mngt iface as HID device */ + if (num > 0) + spihid_register_hid_device(spihid, iface, num); + + wake_up_interruptible(&spihid->wait); + } + return true; +} + +static bool spihid_process_iface_get_report(struct spihid_apple *spihid, + u32 device, u8 report, + u8 *payload, size_t len) +{ + struct spihid_interface *iface = spihid_get_iface(spihid, device); + + if (!iface) + return false; + + if (len > sizeof(iface->reply_buf) || len < 1) + return false; + + memcpy(iface->reply_buf, payload, len); + iface->reply_len = len; + + wake_up_interruptible(&spihid->wait); + + return true; +} + +static bool spihid_process_response(struct spihid_apple *spihid, u32 device, + struct spihid_msg_hdr *hdr, u8 *payload, + size_t len) +{ + if (hdr->unknown0 == 0x20) { + switch (hdr->unknown1) { + case 0x01: + return spihid_process_device_info(spihid, hdr->unknown2, + payload, len); + case 0x02: + return spihid_process_iface_info(spihid, hdr->unknown2, + payload, len); + case 0x10: + return spihid_process_iface_hid_report_desc( + spihid, hdr->unknown2, payload, len); + default: + break; + } + } + + if (hdr->unknown0 == 0x32) { + return spihid_process_iface_get_report(spihid, device, hdr->unknown1, payload, len); + } + + return false; +} + +static void spihid_process_message(struct spihid_apple *spihid, u8 *data, + size_t length, u8 device, u8 flags) +{ + struct device *dev = &spihid->spidev->dev; + struct spihid_msg_hdr *hdr; + bool handled = false; + size_t payload_len; + u8 *payload; + + if (!spihid_verify_msg(spihid, data, length)) + return; + + hdr = (struct spihid_msg_hdr *)data; + payload_len = le16_to_cpu(hdr->length); + + if (payload_len == 0 || + (payload_len + sizeof(struct spihid_msg_hdr) + 2) > length) + return; + + payload = data + sizeof(struct spihid_msg_hdr); + + switch (flags) { + case SPIHID_READ_PACKET: + handled = spihid_process_input_report(spihid, device, hdr, + payload, payload_len); + break; + case SPIHID_WRITE_PACKET: + handled = spihid_process_response(spihid, device, hdr, payload, + payload_len); + break; + default: + break; + } + +#if defined(DEBUG) && DEBUG > 1 + { + dev_dbg(dev, + "R msg: req:%02hhx rep:%02hhx dev:%02hhx id:%hu len:%hu\n", + hdr->unknown0, hdr->unknown1, hdr->unknown2, hdr->id, + hdr->length); + print_hex_dump_debug("spihid msg: ", DUMP_PREFIX_OFFSET, 16, 1, + payload, le16_to_cpu(hdr->length), true); + } +#else + if (!handled) { + dev_dbg(dev, + "R unhandled msg: req:%02hhx rep:%02hhx dev:%02hhx id:%hu len:%hu\n", + hdr->unknown0, hdr->unknown1, hdr->unknown2, hdr->id, + hdr->length); + print_hex_dump_debug("spihid msg: ", DUMP_PREFIX_OFFSET, 16, 1, + payload, le16_to_cpu(hdr->length), true); + } +#endif +} + +static void spihid_assemble_message(struct spihid_apple *spihid, + struct spihid_transfer_packet *pkt) +{ + size_t length, offset, remain; + struct device *dev = &spihid->spidev->dev; + struct spihid_input_report *rep = &spihid->report; + + length = le16_to_cpu(pkt->length); + remain = le16_to_cpu(pkt->remain); + offset = le16_to_cpu(pkt->offset); + + if (offset + length + remain > U16_MAX) { + return; + } + + if (pkt->device != rep->device || pkt->flags != rep->flags || + offset != rep->offset) { + rep->device = 0; + rep->flags = 0; + rep->offset = 0; + rep->length = 0; + } + + if (offset == 0) { + if (rep->offset != 0) { + dev_warn(dev, "incomplete report off:%u len:%u", + rep->offset, rep->length); + } + memcpy(rep->buf, pkt->data, length); + rep->offset = length; + rep->length = length + remain; + rep->device = pkt->device; + rep->flags = pkt->flags; + } else if (offset == rep->offset) { + if (offset + length + remain != rep->length) { + dev_warn(dev, "incomplete report off:%u len:%u", + rep->offset, rep->length); + return; + } + memcpy(rep->buf + offset, pkt->data, length); + rep->offset += length; + + if (rep->offset == rep->length) { + spihid_process_message(spihid, rep->buf, rep->length, + rep->device, rep->flags); + rep->device = 0; + rep->flags = 0; + rep->offset = 0; + rep->length = 0; + } + } +} + +static void spihid_process_read(struct spihid_apple *spihid) +{ + u16 crc; + size_t length; + struct device *dev = &spihid->spidev->dev; + struct spihid_transfer_packet *pkt; + + pkt = (struct spihid_transfer_packet *)spihid->rx_buf; + + /* check transfer packet crc */ + crc = crc16(0, spihid->rx_buf, + offsetof(struct spihid_transfer_packet, crc16)); + if (crc != le16_to_cpu(pkt->crc16)) { + dev_warn_ratelimited(dev, "Read package crc mismatch\n"); + return; + } + + length = le16_to_cpu(pkt->length); + + if (length < sizeof(struct spihid_msg_hdr) + 2) { + if (length == sizeof(spi_hid_apple_booted) && + !memcmp(pkt->data, spi_hid_apple_booted, length)) { + if (!spihid->status_booted) { + spihid->status_booted = true; + wake_up_interruptible(&spihid->wait); + } + } else { + dev_info(dev, "R short packet: len:%zu\n", length); + print_hex_dump(KERN_INFO, "spihid pkt:", + DUMP_PREFIX_OFFSET, 16, 1, pkt->data, + length, false); + } + return; + } + +#if defined(DEBUG) && DEBUG > 1 + dev_dbg(dev, + "R pkt: flags:%02hhx dev:%02hhx off:%hu remain:%hu, len:%zu\n", + pkt->flags, pkt->device, pkt->offset, pkt->remain, length); +#if defined(DEBUG) && DEBUG > 2 + print_hex_dump_debug("spihid pkt: ", DUMP_PREFIX_OFFSET, 16, 1, + spihid->rx_buf, + sizeof(struct spihid_transfer_packet), true); +#endif +#endif + + if (length > sizeof(pkt->data)) { + dev_warn_ratelimited(dev, "Invalid pkt len:%zu", length); + return; + } + + /* short message */ + if (pkt->offset == 0 && pkt->remain == 0) { + spihid_process_message(spihid, pkt->data, length, pkt->device, + pkt->flags); + } else { + spihid_assemble_message(spihid, pkt); + } +} + +static void spihid_read_packet_sync(struct spihid_apple *spihid) +{ + int err; + + err = spi_sync(spihid->spidev, &spihid->rx_msg); + if (!err) { + spihid_process_read(spihid); + } else { + dev_warn(&spihid->spidev->dev, "RX failed: %d\n", err); + } +} + +irqreturn_t spihid_apple_core_irq(int irq, void *data) +{ + struct spi_device *spi = data; + struct spihid_apple *spihid = spi_get_drvdata(spi); + + spihid_read_packet_sync(spihid); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(spihid_apple_core_irq); + +static void spihid_apple_setup_spi_msgs(struct spihid_apple *spihid) +{ + memset(&spihid->rx_transfer, 0, sizeof(spihid->rx_transfer)); + + spihid->rx_transfer.rx_buf = spihid->rx_buf; + spihid->rx_transfer.len = sizeof(struct spihid_transfer_packet); + + spi_message_init(&spihid->rx_msg); + spi_message_add_tail(&spihid->rx_transfer, &spihid->rx_msg); + + memset(&spihid->tx_transfer, 0, sizeof(spihid->rx_transfer)); + memset(&spihid->status_transfer, 0, sizeof(spihid->status_transfer)); + + spihid->tx_transfer.tx_buf = spihid->tx_buf; + spihid->tx_transfer.len = sizeof(struct spihid_transfer_packet); + spihid->tx_transfer.delay.unit = SPI_DELAY_UNIT_USECS; + spihid->tx_transfer.delay.value = SPI_RW_CHG_DELAY_US; + + spihid->status_transfer.rx_buf = spihid->status_buf; + spihid->status_transfer.len = sizeof(spi_hid_apple_status_ok); + + spi_message_init(&spihid->tx_msg); + spi_message_add_tail(&spihid->tx_transfer, &spihid->tx_msg); + spi_message_add_tail(&spihid->status_transfer, &spihid->tx_msg); +} + +static int spihid_apple_setup_spi(struct spihid_apple *spihid) +{ + spihid_apple_setup_spi_msgs(spihid); + + return spihid->ops->power_on(spihid->ops); +} + +static int spihid_register_hid_device(struct spihid_apple *spihid, + struct spihid_interface *iface, u8 device) +{ + int ret; + char *suffix; + struct hid_device *hid; + + iface->id = device; + + hid = hid_allocate_device(); + if (IS_ERR(hid)) + return PTR_ERR(hid); + + /* + * Use 'Apple SPI Keyboard' and 'Apple SPI Trackpad' as input device + * names. The device names need to be distinct since at least Kwin uses + * the tripple Vendor ID, Product ID, Name to identify devices. + */ + snprintf(hid->name, sizeof(hid->name), "Apple SPI %s", iface->name); + // strip ' / Boot' suffix from the name + suffix = strstr(hid->name, " / Boot"); + if (suffix) + suffix[0] = '\0'; + snprintf(hid->phys, sizeof(hid->phys), "%s (%hhx)", + dev_name(&spihid->spidev->dev), device); + strscpy(hid->uniq, spihid->serial, sizeof(hid->uniq)); + + hid->ll_driver = &apple_hid_ll; + hid->bus = BUS_SPI; + hid->vendor = spihid->vendor_id; + hid->product = spihid->product_id; + hid->version = spihid->version_number; + + if (device == SPIHID_DEVICE_ID_KBD) + hid->type = HID_TYPE_SPI_KEYBOARD; + else if (device == SPIHID_DEVICE_ID_TP) + hid->type = HID_TYPE_SPI_MOUSE; + + hid->country = iface->country; + hid->dev.parent = &spihid->spidev->dev; + hid->driver_data = iface; + + ret = hid_add_device(hid); + if (ret < 0) { + hid_destroy_device(hid); + dev_warn(&spihid->spidev->dev, + "Failed to register hid device %hhu", device); + return ret; + } + + iface->hid = hid; + + return 0; +} + +static void spihid_destroy_hid_device(struct spihid_interface *iface) +{ + if (iface->hid) { + hid_destroy_device(iface->hid); + iface->hid = NULL; + } + iface->ready = false; +} + +int spihid_apple_core_probe(struct spi_device *spi, struct spihid_apple_ops *ops) +{ + struct device *dev = &spi->dev; + struct spihid_apple *spihid; + int err, i; + + if (!ops || !ops->power_on || !ops->power_off || !ops->enable_irq || !ops->disable_irq) + return -EINVAL; + + spihid = devm_kzalloc(dev, sizeof(*spihid), GFP_KERNEL); + if (!spihid) + return -ENOMEM; + + spihid->ops = ops; + spihid->spidev = spi; + + // init spi + spi_set_drvdata(spi, spihid); + + /* + * allocate SPI buffers + * Overallocate the receice buffer since it passed directly into + * hid_input_report / hid_report_raw_event. The later expects the buffer + * to be HID_MAX_BUFFER_SIZE (16k) or hid_ll_driver.max_buffer_size if + * set. + */ + spihid->rx_buf = devm_kmalloc( + &spi->dev, SPIHID_MAX_INPUT_REPORT_SIZE, GFP_KERNEL); + spihid->tx_buf = devm_kmalloc( + &spi->dev, sizeof(struct spihid_transfer_packet), GFP_KERNEL); + spihid->status_buf = devm_kmalloc( + &spi->dev, sizeof(spi_hid_apple_status_ok), GFP_KERNEL); + + if (!spihid->rx_buf || !spihid->tx_buf || !spihid->status_buf) + return -ENOMEM; + + spihid->report.buf = + devm_kmalloc(dev, SPIHID_MAX_INPUT_REPORT_SIZE, GFP_KERNEL); + + spihid->kbd.hid_desc = devm_kmalloc(dev, SPIHID_DESC_MAX, GFP_KERNEL); + spihid->tp.hid_desc = devm_kmalloc(dev, SPIHID_DESC_MAX, GFP_KERNEL); + + if (!spihid->report.buf || !spihid->kbd.hid_desc || + !spihid->tp.hid_desc) + return -ENOMEM; + + init_waitqueue_head(&spihid->wait); + + mutex_init(&spihid->tx_lock); + + /* Init spi transfer buffers and power device on */ + err = spihid_apple_setup_spi(spihid); + if (err < 0) + goto error; + + /* enable HID irq */ + spihid->ops->enable_irq(spihid->ops); + + // wait for boot message + err = wait_event_interruptible_timeout(spihid->wait, + spihid->status_booted, + msecs_to_jiffies(1000)); + if (err == 0) + err = -ENODEV; + if (err < 0) { + dev_err(dev, "waiting for device boot failed: %d", err); + goto error; + } + + /* request device information */ + dev_dbg(dev, "request device info"); + spihid_apple_request(spihid, 0xd0, 0x20, 0x01, 0xd0, 0, NULL, 0); + err = wait_event_interruptible_timeout(spihid->wait, spihid->vendor_id, + SPIHID_DEF_WAIT); + if (err == 0) + err = -ENODEV; + if (err < 0) { + dev_err(dev, "waiting for device info failed: %d", err); + goto error; + } + + /* request interface information */ + for (i = 0; i < spihid->num_devices; i++) { + struct spihid_interface *iface = spihid_get_iface(spihid, i); + if (!iface) + continue; + dev_dbg(dev, "request interface info 0x%02x", i); + spihid_apple_request(spihid, 0xd0, 0x20, 0x02, i, + SPIHID_DESC_MAX, NULL, 0); + err = wait_event_interruptible_timeout( + spihid->wait, iface->max_input_report_len, + SPIHID_DEF_WAIT); + } + + /* request HID report descriptors */ + for (i = 1; i < spihid->num_devices; i++) { + struct spihid_interface *iface = spihid_get_iface(spihid, i); + if (!iface) + continue; + dev_dbg(dev, "request hid report desc 0x%02x", i); + spihid_apple_request(spihid, 0xd0, 0x20, 0x10, i, + SPIHID_DESC_MAX, NULL, 0); + wait_event_interruptible_timeout( + spihid->wait, iface->hid_desc_len, SPIHID_DEF_WAIT); + } + + return 0; +error: + return err; +} +EXPORT_SYMBOL_GPL(spihid_apple_core_probe); + +void spihid_apple_core_remove(struct spi_device *spi) +{ + struct spihid_apple *spihid = spi_get_drvdata(spi); + + /* destroy input devices */ + + spihid_destroy_hid_device(&spihid->tp); + spihid_destroy_hid_device(&spihid->kbd); + + /* disable irq */ + spihid->ops->disable_irq(spihid->ops); + + /* power SPI device down */ + spihid->ops->power_off(spihid->ops); +} +EXPORT_SYMBOL_GPL(spihid_apple_core_remove); + +void spihid_apple_core_shutdown(struct spi_device *spi) +{ + struct spihid_apple *spihid = spi_get_drvdata(spi); + + /* disable irq */ + spihid->ops->disable_irq(spihid->ops); + + /* power SPI device down */ + spihid->ops->power_off(spihid->ops); +} +EXPORT_SYMBOL_GPL(spihid_apple_core_shutdown); + +#ifdef CONFIG_PM_SLEEP +static int spihid_apple_core_suspend(struct device *dev) +{ + int ret; +#ifdef IRQ_WAKE_SUPPORT + int wake_status; +#endif + struct spihid_apple *spihid = spi_get_drvdata(to_spi_device(dev)); + + if (spihid->tp.hid) { + ret = hid_driver_suspend(spihid->tp.hid, PMSG_SUSPEND); + if (ret < 0) + return ret; + } + + if (spihid->kbd.hid) { + ret = hid_driver_suspend(spihid->kbd.hid, PMSG_SUSPEND); + if (ret < 0) { + if (spihid->tp.hid) + hid_driver_resume(spihid->tp.hid); + return ret; + } + } + + /* Save some power */ + spihid->ops->disable_irq(spihid->ops); + +#ifdef IRQ_WAKE_SUPPORT + if (device_may_wakeup(dev)) { + wake_status = spihid->ops->enable_irq_wake(spihid->ops); + if (!wake_status) + spihid->irq_wake_enabled = true; + else + dev_warn(dev, "Failed to enable irq wake: %d\n", + wake_status); + } else { + spihid->ops->power_off(spihid->ops); + } +#else + spihid->ops->power_off(spihid->ops); +#endif + + return 0; +} + +static int spihid_apple_core_resume(struct device *dev) +{ + int ret_tp = 0, ret_kbd = 0; + struct spihid_apple *spihid = spi_get_drvdata(to_spi_device(dev)); +#ifdef IRQ_WAKE_SUPPORT + int wake_status; + + if (!device_may_wakeup(dev)) { + spihid->ops->power_on(spihid->ops); + } else if (spihid->irq_wake_enabled) { + wake_status = spihid->ops->disable_irq_wake(spihid->ops); + if (!wake_status) + spihid->irq_wake_enabled = false; + else + dev_warn(dev, "Failed to disable irq wake: %d\n", + wake_status); + } +#endif + + spihid->ops->enable_irq(spihid->ops); + spihid->ops->power_on(spihid->ops); + + if (spihid->tp.hid) + ret_tp = hid_driver_reset_resume(spihid->tp.hid); + if (spihid->kbd.hid) + ret_kbd = hid_driver_reset_resume(spihid->kbd.hid); + + if (ret_tp < 0) + return ret_tp; + + return ret_kbd; +} +#endif + +const struct dev_pm_ops spihid_apple_core_pm = { + SET_SYSTEM_SLEEP_PM_OPS(spihid_apple_core_suspend, + spihid_apple_core_resume) +}; +EXPORT_SYMBOL_GPL(spihid_apple_core_pm); + +MODULE_DESCRIPTION("Apple SPI HID transport driver"); +MODULE_AUTHOR("Janne Grunau "); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/spi-hid/spi-hid-apple-of.c b/drivers/hid/spi-hid/spi-hid-apple-of.c new file mode 100644 index 00000000000000..b631212b836d30 --- /dev/null +++ b/drivers/hid/spi-hid/spi-hid-apple-of.c @@ -0,0 +1,153 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * + * Apple SPI HID transport driver - Open Firmware + * + * Copyright (C) The Asahi Linux Contributors + */ + +#include +#include +#include +#include + +#include "spi-hid-apple.h" + + +struct spihid_apple_of { + struct spihid_apple_ops ops; + + struct gpio_desc *enable_gpio; + int irq; +}; + +static int spihid_apple_of_power_on(struct spihid_apple_ops *ops) +{ + struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); + + /* reset the controller on boot */ + gpiod_direction_output(sh_of->enable_gpio, 1); + msleep(5); + gpiod_direction_output(sh_of->enable_gpio, 0); + msleep(5); + /* turn SPI device on */ + gpiod_direction_output(sh_of->enable_gpio, 1); + msleep(50); + + return 0; +} + +static int spihid_apple_of_power_off(struct spihid_apple_ops *ops) +{ + struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); + + /* turn SPI device off */ + gpiod_direction_output(sh_of->enable_gpio, 0); + + return 0; +} + +static int spihid_apple_of_enable_irq(struct spihid_apple_ops *ops) +{ + struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); + + enable_irq(sh_of->irq); + + return 0; +} + +static int spihid_apple_of_disable_irq(struct spihid_apple_ops *ops) +{ + struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); + + disable_irq(sh_of->irq); + + return 0; +} + +static int spihid_apple_of_enable_irq_wake(struct spihid_apple_ops *ops) +{ + struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); + + return enable_irq_wake(sh_of->irq); +} + +static int spihid_apple_of_disable_irq_wake(struct spihid_apple_ops *ops) +{ + struct spihid_apple_of *sh_of = container_of(ops, struct spihid_apple_of, ops); + + return disable_irq_wake(sh_of->irq); +} + +static int spihid_apple_of_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct spihid_apple_of *spihid_of; + int err; + + spihid_of = devm_kzalloc(dev, sizeof(*spihid_of), GFP_KERNEL); + if (!spihid_of) + return -ENOMEM; + + spihid_of->ops.power_on = spihid_apple_of_power_on; + spihid_of->ops.power_off = spihid_apple_of_power_off; + spihid_of->ops.enable_irq = spihid_apple_of_enable_irq; + spihid_of->ops.disable_irq = spihid_apple_of_disable_irq; + spihid_of->ops.enable_irq_wake = spihid_apple_of_enable_irq_wake; + spihid_of->ops.disable_irq_wake = spihid_apple_of_disable_irq_wake; + + spihid_of->enable_gpio = devm_gpiod_get_index(dev, "spien", 0, 0); + if (IS_ERR(spihid_of->enable_gpio)) { + err = PTR_ERR(spihid_of->enable_gpio); + dev_err(dev, "failed to get 'spien' gpio pin: %d", err); + return err; + } + + spihid_of->irq = of_irq_get(dev->of_node, 0); + if (spihid_of->irq < 0) { + err = spihid_of->irq; + dev_err(dev, "failed to get 'extended-irq': %d", err); + return err; + } + err = devm_request_threaded_irq(dev, spihid_of->irq, NULL, + spihid_apple_core_irq, IRQF_ONESHOT | IRQF_NO_AUTOEN, + "spi-hid-apple-irq", spi); + if (err < 0) { + dev_err(dev, "failed to request extended-irq %d: %d", + spihid_of->irq, err); + return err; + } + + return spihid_apple_core_probe(spi, &spihid_of->ops); +} + +static const struct of_device_id spihid_apple_of_match[] = { + { .compatible = "apple,spi-hid-transport" }, + {}, +}; +MODULE_DEVICE_TABLE(of, spihid_apple_of_match); + +static struct spi_device_id spihid_apple_of_id[] = { + { "spi-hid-transport", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, spihid_apple_of_id); + +static struct spi_driver spihid_apple_of_driver = { + .driver = { + .name = "spi-hid-apple-of", + .pm = &spihid_apple_core_pm, + .of_match_table = of_match_ptr(spihid_apple_of_match), + }, + + .id_table = spihid_apple_of_id, + .probe = spihid_apple_of_probe, + .remove = spihid_apple_core_remove, + .shutdown = spihid_apple_core_shutdown, +}; + +module_spi_driver(spihid_apple_of_driver); + +MODULE_DESCRIPTION("Apple SPI HID transport driver for OpenFirmware systems"); +MODULE_AUTHOR("Janne Grunau "); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/spi-hid/spi-hid-apple.h b/drivers/hid/spi-hid/spi-hid-apple.h new file mode 100644 index 00000000000000..9abecd1ba78028 --- /dev/null +++ b/drivers/hid/spi-hid/spi-hid-apple.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ + +#ifndef SPI_HID_APPLE_H +#define SPI_HID_APPLE_H + +#include +#include + +/** + * struct spihid_apple_ops - Ops to control the device from the core driver. + * + * @power_on: reset and power the device on. + * @power_off: power the device off. + * @enable_irq: enable irq or ACPI gpe. + * @disable_irq: disable irq or ACPI gpe. + */ + +struct spihid_apple_ops { + int (*power_on)(struct spihid_apple_ops *ops); + int (*power_off)(struct spihid_apple_ops *ops); + int (*enable_irq)(struct spihid_apple_ops *ops); + int (*disable_irq)(struct spihid_apple_ops *ops); + int (*enable_irq_wake)(struct spihid_apple_ops *ops); + int (*disable_irq_wake)(struct spihid_apple_ops *ops); +}; + +irqreturn_t spihid_apple_core_irq(int irq, void *data); + +int spihid_apple_core_probe(struct spi_device *spi, struct spihid_apple_ops *ops); +void spihid_apple_core_remove(struct spi_device *spi); +void spihid_apple_core_shutdown(struct spi_device *spi); + +extern const struct dev_pm_ops spihid_apple_core_pm; + +#endif /* SPI_HID_APPLE_H */ From efc2ec7cad4b235a76d79a7cf3340b733d3c076a Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 12 Nov 2023 12:35:51 +0100 Subject: [PATCH 139/352] drm: apple: afk: Use linear array of services "Channel numbers" as received by AFK/EPIC are constantly increasing over restarts of the endpoint. Use a linear array of services and match based on the channel number. The number of services per endpoint is too small to make a difference. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/afk.c | 74 +++++++++++++++++++++++++++---------- drivers/gpu/drm/apple/afk.h | 1 + 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index 9f2f0b646ac6e0..d577f4ec055b03 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -201,11 +201,22 @@ afk_match_service(struct apple_dcp_afkep *ep, const char *name) return NULL; } +static struct apple_epic_service *afk_epic_find_service(struct apple_dcp_afkep *ep, + u32 channel) +{ + for (u32 i = 0; i < ep->num_channels; i++) + if (ep->services[i].enabled && ep->services[i].channel == channel) + return &ep->services[i]; + + return NULL; +} + static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel, u8 *payload, size_t payload_size) { char name[32]; s64 epic_unit = -1; + u32 ch_idx; const char *service_name = name; const char *epic_name = NULL, *epic_class = NULL; const struct apple_epic_service_ops *ops; @@ -213,7 +224,7 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel, u8 *props = payload + sizeof(name); size_t props_size = payload_size - sizeof(name); - WARN_ON(ep->services[channel].enabled); + WARN_ON(afk_epic_find_service(ep, channel)); if (payload_size < sizeof(name)) { dev_err(ep->dcp->dev, "AFK[ep:%02x]: payload too small: %lx\n", @@ -221,7 +232,13 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel, return; } - strlcpy(name, payload, sizeof(name)); + if (ep->num_channels >= AFK_MAX_CHANNEL) { + dev_err(ep->dcp->dev, "AFK[ep:%02x]: too many enabled services!\n", + ep->endpoint); + return; + } + + strscpy(name, payload, sizeof(name)); /* * in DCP firmware 13.2 DCP reports interface-name as name which starts @@ -257,13 +274,14 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel, goto free; } - spin_lock_init(&ep->services[channel].lock); - ep->services[channel].enabled = true; - ep->services[channel].ops = ops; - ep->services[channel].ep = ep; - ep->services[channel].channel = channel; - ep->services[channel].cmd_tag = 0; - ops->init(&ep->services[channel], epic_name, epic_class, epic_unit); + ch_idx = ep->num_channels++; + spin_lock_init(&ep->services[ch_idx].lock); + ep->services[ch_idx].enabled = true; + ep->services[ch_idx].ops = ops; + ep->services[ch_idx].ep = ep; + ep->services[ch_idx].channel = channel; + ep->services[ch_idx].cmd_tag = 0; + ops->init(&ep->services[ch_idx], epic_name, epic_class, epic_unit); dev_info(ep->dcp->dev, "AFK[ep:%02x]: new service %s on channel %d\n", ep->endpoint, service_name, channel); free: @@ -273,11 +291,16 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel, static void afk_recv_handle_teardown(struct apple_dcp_afkep *ep, u32 channel) { - struct apple_epic_service *service = &ep->services[channel]; + struct apple_epic_service *service; const struct apple_epic_service_ops *ops; unsigned long flags; - WARN_ON(!service->enabled); + service = afk_epic_find_service(ep, channel); + if (!service) { + dev_warn(ep->dcp->dev, "AFK[ep:%02x]: teardown for disabled channel %u\n", + ep->endpoint, channel); + return; + } // TODO: think through what locking is necessary spin_lock_irqsave(&service->lock, flags); @@ -293,13 +316,20 @@ static void afk_recv_handle_reply(struct apple_dcp_afkep *ep, u32 channel, u16 tag, void *payload, size_t payload_size) { struct epic_cmd *cmd = payload; - struct apple_epic_service *service = &ep->services[channel]; + struct apple_epic_service *service; unsigned long flags; u8 idx = tag & 0xff; void *rxbuf, *txbuf; dma_addr_t rxbuf_dma, txbuf_dma; size_t rxlen, txlen; + service = afk_epic_find_service(ep, channel); + if (!service) { + dev_warn(ep->dcp->dev, "AFK[ep:%02x]: command reply on disabled channel %u\n", + ep->endpoint, channel); + return; + } + if (payload_size < sizeof(*cmd)) { dev_err(ep->dcp->dev, "AFK[ep:%02x]: command reply on channel %d too small: %ld\n", @@ -371,7 +401,14 @@ static void afk_recv_handle_std_service(struct apple_dcp_afkep *ep, u32 channel, struct epic_sub_hdr *eshdr, void *payload, size_t payload_size) { - struct apple_epic_service *service = &ep->services[channel]; + struct apple_epic_service *service = afk_epic_find_service(ep, channel); + + if (!service) { + dev_warn(ep->dcp->dev, + "AFK[ep:%02x]: std service notify on disabled channel %u\n", + ep->endpoint, channel); + return; + } if (type == EPIC_TYPE_NOTIFY && eshdr->category == EPIC_CAT_NOTIFY) { struct epic_std_service_ap_call *call = payload; @@ -438,6 +475,7 @@ static void afk_recv_handle_std_service(struct apple_dcp_afkep *ep, u32 channel, static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type, u8 *data, size_t data_size) { + struct apple_epic_service *service; struct epic_hdr *ehdr = (struct epic_hdr *)data; struct epic_sub_hdr *eshdr = (struct epic_sub_hdr *)(data + sizeof(*ehdr)); @@ -454,13 +492,9 @@ static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type, trace_afk_recv_handle(ep, channel, type, data_size, ehdr, eshdr); - if (channel >= AFK_MAX_CHANNEL) { - dev_err(ep->dcp->dev, "AFK[ep:%02x]: channel %d out of bounds\n", - ep->endpoint, channel); - return; - } + service = afk_epic_find_service(ep, channel); - if (!ep->services[channel].enabled) { + if (!service) { if (type != EPIC_TYPE_NOTIFY) { dev_err(ep->dcp->dev, "AFK[ep:%02x]: expected notify but got 0x%x on channel %d\n", @@ -483,7 +517,7 @@ static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type, return afk_recv_handle_init(ep, channel, payload, payload_size); } - if (!ep->services[channel].enabled) { + if (!service) { dev_err(ep->dcp->dev, "AFK[ep:%02x]: channel %d has no service\n", ep->endpoint, channel); return; diff --git a/drivers/gpu/drm/apple/afk.h b/drivers/gpu/drm/apple/afk.h index b800840b4f4a3a..fe4ed35159ace0 100644 --- a/drivers/gpu/drm/apple/afk.h +++ b/drivers/gpu/drm/apple/afk.h @@ -169,6 +169,7 @@ struct apple_dcp_afkep { const struct apple_epic_service_ops *ops; struct apple_epic_service services[AFK_MAX_CHANNEL]; + u32 num_channels; }; struct apple_dcp_afkep *afk_init(struct apple_dcp *dcp, u32 endpoint, From ee8d88c42d3bf16716a7fa1da7479e89fc153d1d Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sat, 5 Nov 2022 13:15:34 +0100 Subject: [PATCH 140/352] drm: apple: Add DPTX support This is required for DP Altmode, DP Thunderbolt tunneling and HDMI output on 14/16-inch Macbook Pros and M2* desktop devices. M2* desktops and 14 and 16 inch Macbook Pros expose a DisplayPort to HDMI converter which is driven by the DP output of one of the DCP/DCPext display coprocessor/controller blocks. Two gpio pins are used for power control. Another gpio pin acts as HDMI hpd. Do not use the hpd as direct drm_connector interrupt since that is already wired to DCPs hotplug notification. Instead use it to trigger link setup via the dptx endpoint. Signed-off-by: Sven Peter Co-developed-by: Janne Grunau Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Kconfig | 1 + drivers/gpu/drm/apple/Makefile | 3 +- drivers/gpu/drm/apple/apple_drv.c | 11 +- drivers/gpu/drm/apple/dcp-internal.h | 34 +++ drivers/gpu/drm/apple/dcp.c | 225 ++++++++++++++- drivers/gpu/drm/apple/dcp.h | 3 + drivers/gpu/drm/apple/dcp_trace.c | 3 + drivers/gpu/drm/apple/dptxep.c | 408 +++++++++++++++++++++++++++ drivers/gpu/drm/apple/dptxep.h | 66 +++++ drivers/gpu/drm/apple/ibootep.c | 29 ++ drivers/gpu/drm/apple/parser.c | 11 +- drivers/gpu/drm/apple/parser.h | 5 + drivers/gpu/drm/apple/systemep.c | 100 +++++++ drivers/gpu/drm/apple/trace.h | 140 +++++++++ 14 files changed, 1026 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/apple/dcp_trace.c create mode 100644 drivers/gpu/drm/apple/dptxep.c create mode 100644 drivers/gpu/drm/apple/dptxep.h create mode 100644 drivers/gpu/drm/apple/ibootep.c create mode 100644 drivers/gpu/drm/apple/systemep.c diff --git a/drivers/gpu/drm/apple/Kconfig b/drivers/gpu/drm/apple/Kconfig index 805639cf94d571..b28b84cef961b1 100644 --- a/drivers/gpu/drm/apple/Kconfig +++ b/drivers/gpu/drm/apple/Kconfig @@ -9,5 +9,6 @@ config DRM_APPLE select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select VIDEOMODE_HELPERS + select MULTIPLEXER help Say Y if you have an Apple Silicon chipset. diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index 12f72293bc4976..dde8fa879b3a61 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -4,7 +4,8 @@ CFLAGS_trace.o = -I$(src) appledrm-y := apple_drv.o -apple_dcp-y := afk.o dcp.o dcp_backlight.o iomfb.o parser.o +apple_dcp-y := afk.o dcp.o dcp_backlight.o dptxep.o iomfb.o parser.o systemep.o +apple_dcp-y += ibootep.o apple_dcp-y += iomfb_v12_3.o apple_dcp-y += iomfb_v13_3.o apple_dcp-$(CONFIG_TRACING) += trace.o diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 992facd17258c7..d54a0d4712c64f 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -315,7 +315,7 @@ static const struct drm_crtc_helper_funcs apple_crtc_helper_funcs = { static int apple_probe_per_dcp(struct device *dev, struct drm_device *drm, struct platform_device *dcp, - int num) + int num, bool dcp_ext) { struct apple_crtc *crtc; struct apple_connector *connector; @@ -347,6 +347,10 @@ static int apple_probe_per_dcp(struct device *dev, drm_connector_helper_add(&connector->base, &apple_connector_helper_funcs); + // HACK: + if (dcp_ext) + connector->base.fwnode = fwnode_handle_get(dcp->dev.fwnode); + ret = drm_connector_init(drm, &connector->base, &apple_connector_funcs, dcp_get_connector_type(dcp)); if (ret) @@ -398,6 +402,7 @@ static int apple_get_fb_resource(struct device *dev, const char *name, static const struct of_device_id apple_dcp_id_tbl[] = { { .compatible = "apple,dcp" }, + { .compatible = "apple,dcpext" }, {}, }; @@ -410,10 +415,12 @@ static int apple_drm_init_dcp(struct device *dev) int i, ret, num_dcp = 0; for_each_matching_node(np, apple_dcp_id_tbl) { + bool dcp_ext; if (!of_device_is_available(np)) { of_node_put(np); continue; } + dcp_ext = of_device_is_compatible(np, "apple,dcpext"); dcp[num_dcp] = of_find_device_by_node(np); of_node_put(np); @@ -421,7 +428,7 @@ static int apple_drm_init_dcp(struct device *dev) continue; ret = apple_probe_per_dcp(dev, &apple->drm, dcp[num_dcp], - num_dcp); + num_dcp, dcp_ext); if (ret) continue; diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 05a0459c1cecb3..b7b5c9dcc046db 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -7,9 +7,12 @@ #include #include #include +#include +#include #include #include +#include "dptxep.h" #include "iomfb.h" #include "iomfb_v12_3.h" #include "iomfb_v13_3.h" @@ -94,6 +97,10 @@ struct dcp_panel { bool has_mini_led; }; +struct apple_dcp_hw_data { + u32 num_dptx_ports; +}; + /* TODO: move IOMFB members to its own struct */ struct apple_dcp { struct device *dev; @@ -103,6 +110,8 @@ struct apple_dcp { struct apple_crtc *crtc; struct apple_connector *connector; + struct apple_dcp_hw_data hw; + /* firmware version and compatible firmware version */ enum dcp_firmware_version fw_compat; @@ -127,6 +136,8 @@ struct apple_dcp { struct resource *disp_registers[MAX_DISP_REGISTERS]; unsigned int nr_disp_registers; + u32 index; + /* Bitmap of memory descriptors used for mappings made by the DCP */ DECLARE_BITMAP(memdesc_map, DCP_MAX_MAPPINGS); @@ -191,6 +202,29 @@ struct apple_dcp { /* integrated panel if present */ struct dcp_panel panel; + + struct apple_dcp_afkep *systemep; + struct completion systemep_done; + + struct apple_dcp_afkep *ibootep; + + struct apple_dcp_afkep *dptxep; + + struct dptx_port dptxport[2]; + + /* these fields are output port specific */ + struct phy *phy; + struct mux_control *xbar; + + struct gpio_desc *hdmi_hpd; + struct gpio_desc *hdmi_pwren; + struct gpio_desc *dp2hdmi_pwren; + + struct mutex hpd_mutex; + + u32 dptx_phy; + u32 dptx_die; + int hdmi_hpd_irq; }; int dcp_backlight_register(struct apple_dcp *dcp); diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 761c52e3a30e9a..6f96f9159c9fd6 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -115,6 +116,15 @@ static void dcp_recv_msg(void *cookie, u8 endpoint, u64 message) switch (endpoint) { case IOMFB_ENDPOINT: return iomfb_recv_msg(dcp, message); + case SYSTEM_ENDPOINT: + afk_receive_message(dcp->systemep, message); + return; + case DISP0_ENDPOINT: + afk_receive_message(dcp->ibootep, message); + return; + case DPTX_ENDPOINT: + afk_receive_message(dcp->dptxep, message); + return; default: WARN(endpoint, "unknown DCP endpoint %hhu", endpoint); } @@ -194,7 +204,7 @@ void dcp_send_message(struct apple_dcp *dcp, u8 endpoint, u64 message) { trace_dcp_send_msg(dcp, endpoint, message); apple_rtkit_send_message(dcp->rtk, endpoint, message, NULL, - false); + true); } int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) @@ -243,6 +253,66 @@ int dcp_get_connector_type(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(dcp_get_connector_type); +static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) +{ + if (!dcp->phy) { + dev_warn(dcp->dev, "dcp_dptx_connect: missing phy\n"); + return -ENODEV; + } + + mutex_lock(&dcp->hpd_mutex); + if (!dcp->dptxport[port].enabled) { + dev_warn(dcp->dev, "dcp_dptx_connect: dptx service for port %d not enabled\n", port); + mutex_unlock(&dcp->hpd_mutex); + return -ENODEV; + } + + if (dcp->dptxport[port].connected) + return 0; + + dcp->dptxport[port].atcphy = dcp->phy; + dptxport_connect(dcp->dptxport[port].service, 0, dcp->dptx_phy, dcp->dptx_die); + dptxport_request_display(dcp->dptxport[port].service); + dcp->dptxport[port].connected = true; + mutex_unlock(&dcp->hpd_mutex); + + return 0; +} + +static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) +{ + struct apple_connector *connector = dcp->connector; + + mutex_lock(&dcp->hpd_mutex); + if (connector && connector->connected) { + dcp->valid_mode = false; + schedule_work(&connector->hotplug_wq); + } + + if (dcp->dptxport[port].enabled && dcp->dptxport[port].connected) { + dptxport_release_display(dcp->dptxport[port].service); + dcp->dptxport[port].connected = false; + } + mutex_unlock(&dcp->hpd_mutex); + + return 0; +} + +static irqreturn_t dcp_dp2hdmi_hpd(int irq, void *data) +{ + struct apple_dcp *dcp = data; + bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); + + dev_info(dcp->dev, "DP2HDMI HPD connected:%d\n", connected); + + if (connected) + dcp_dptx_connect(dcp, 0); + else + dcp_dptx_disconnect(dcp, 0); + + return IRQ_HANDLED; +} + void dcp_link(struct platform_device *pdev, struct apple_crtc *crtc, struct apple_connector *connector) { @@ -261,6 +331,28 @@ int dcp_start(struct platform_device *pdev) init_completion(&dcp->start_done); /* start RTKit endpoints */ + ret = systemep_init(dcp); + if (ret) + dev_warn(dcp->dev, "Failed to start system endpoint: %d", ret); + + if (dcp->phy) { + if (dcp->fw_compat >= DCP_FIRMWARE_V_13_5) { + ret = ibootep_init(dcp); + if (ret) + dev_warn(dcp->dev, + "Failed to start IBOOT endpoint: %d", + ret); + + ret = dptxep_init(dcp); + if (ret) + dev_warn(dcp->dev, + "Failed to start DPTX endpoint: %d", + ret); + } else + dev_warn(dcp->dev, + "OS firmware incompatible with dptxport EP\n"); + } + ret = iomfb_start_rtkit(dcp); if (ret) dev_err(dcp->dev, "Failed to start IOMFB endpoint: %d", ret); @@ -269,6 +361,23 @@ int dcp_start(struct platform_device *pdev) } EXPORT_SYMBOL(dcp_start); +static int dcp_enable_dp2hdmi_hpd(struct apple_dcp *dcp) +{ + if (dcp->hdmi_hpd) { + bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); + dev_info(dcp->dev, "%s: DP2HDMI HPD connected:%d\n", __func__, connected); + + // necessary on j473/j474 but not on j314c + if (connected) + dcp_dptx_connect(dcp, 0); + + if (dcp->hdmi_hpd_irq) + enable_irq(dcp->hdmi_hpd_irq); + } + + return 0; +} + int dcp_wait_ready(struct platform_device *pdev, u64 timeout) { struct apple_dcp *dcp = platform_get_drvdata(pdev); @@ -277,7 +386,7 @@ int dcp_wait_ready(struct platform_device *pdev, u64 timeout) if (dcp->crashed) return -ENODEV; if (dcp->active) - return 0; + return dcp_enable_dp2hdmi_hpd(dcp); if (timeout <= 0) return -ETIMEDOUT; @@ -288,6 +397,9 @@ int dcp_wait_ready(struct platform_device *pdev, u64 timeout) if (dcp->crashed) return -ENODEV; + if (dcp->active) + dcp_enable_dp2hdmi_hpd(dcp); + return dcp->active ? 0 : -ETIMEDOUT; } EXPORT_SYMBOL(dcp_wait_ready); @@ -476,6 +588,17 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) if (IS_ERR(dcp->coproc_reg)) return PTR_ERR(dcp->coproc_reg); + of_property_read_u32(dev->of_node, "apple,dcp-index", + &dcp->index); + of_property_read_u32(dev->of_node, "apple,dptx-phy", + &dcp->dptx_phy); + of_property_read_u32(dev->of_node, "apple,dptx-die", + &dcp->dptx_die); + if (dcp->index || dcp->dptx_phy || dcp->dptx_die) + dev_info(dev, "DCP index:%u dptx target phy: %u dptx die: %u\n", + dcp->index, dcp->dptx_phy, dcp->dptx_die); + mutex_init(&dcp->hpd_mutex); + if (!show_notch) ret = of_property_read_u32(dev->of_node, "apple,notch-height", &dcp->notch_height); @@ -560,7 +683,6 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) if (ret) return dev_err_probe(dev, ret, "Failed to boot RTKit: %d", ret); - return ret; } @@ -572,6 +694,9 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) { struct apple_dcp *dcp = dev_get_drvdata(dev); + if (dcp->hdmi_hpd_irq) + disable_irq(dcp->hdmi_hpd_irq); + if (dcp && dcp->shmem) iomfb_shutdown(dcp); @@ -596,6 +721,7 @@ static int dcp_platform_probe(struct platform_device *pdev) enum dcp_firmware_version fw_compat; struct device *dev = &pdev->dev; struct apple_dcp *dcp; + u32 mux_index; fw_compat = dcp_check_firmware_version(dev); if (fw_compat == DCP_FIRMWARE_UNKNOWN) @@ -607,9 +733,71 @@ static int dcp_platform_probe(struct platform_device *pdev) dcp->fw_compat = fw_compat; dcp->dev = dev; + dcp->hw = *(struct apple_dcp_hw_data *)of_device_get_match_data(dev); platform_set_drvdata(pdev, dcp); + dcp->phy = devm_phy_optional_get(dev, "dp-phy"); + if (IS_ERR(dcp->phy)) { + dev_err(dev, "Failed to get dp-phy: %ld", PTR_ERR(dcp->phy)); + return PTR_ERR(dcp->phy); + } + if (dcp->phy) { + int ret; + /* + * Request DP2HDMI related GPIOs as optional for DP-altmode + * compatibility. J180D misses a dp2hdmi-pwren GPIO in the + * template ADT. TODO: check device ADT + */ + dcp->hdmi_hpd = devm_gpiod_get_optional(dev, "hdmi-hpd", GPIOD_IN); + if (IS_ERR(dcp->hdmi_hpd)) + return PTR_ERR(dcp->hdmi_hpd); + if (dcp->hdmi_hpd) { + int irq = gpiod_to_irq(dcp->hdmi_hpd); + if (irq < 0) { + dev_err(dev, "failed to translate HDMI hpd GPIO to IRQ\n"); + return irq; + } + dcp->hdmi_hpd_irq = irq; + + ret = devm_request_threaded_irq(dev, dcp->hdmi_hpd_irq, + NULL, dcp_dp2hdmi_hpd, + IRQF_ONESHOT | IRQF_NO_AUTOEN | + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "dp2hdmi-hpd-irq", dcp); + if (ret < 0) { + dev_err(dev, "failed to request HDMI hpd irq %d: %d", + irq, ret); + return ret; + } + } + + /* + * Power DP2HDMI on as it is required for the HPD irq. + * TODO: check if one is sufficient for the hpd to save power + * on battery powered Macbooks. + */ + dcp->hdmi_pwren = devm_gpiod_get_optional(dev, "hdmi-pwren", GPIOD_OUT_HIGH); + if (IS_ERR(dcp->hdmi_pwren)) + return PTR_ERR(dcp->hdmi_pwren); + + dcp->dp2hdmi_pwren = devm_gpiod_get_optional(dev, "dp2hdmi-pwren", GPIOD_OUT_HIGH); + if (IS_ERR(dcp->dp2hdmi_pwren)) + return PTR_ERR(dcp->dp2hdmi_pwren); + + ret = of_property_read_u32(dev->of_node, "mux-index", &mux_index); + if (!ret) { + dcp->xbar = devm_mux_control_get(dev, "dp-xbar"); + if (IS_ERR(dcp->xbar)) { + dev_err(dev, "Failed to get dp-xbar: %ld", PTR_ERR(dcp->xbar)); + return PTR_ERR(dcp->xbar); + } + ret = mux_control_select(dcp->xbar, mux_index); + if (ret) + dev_warn(dev, "mux_control_select failed: %d\n", ret); + } + } + return component_add(&pdev->dev, &dcp_comp_ops); } @@ -625,6 +813,10 @@ static void dcp_platform_shutdown(struct platform_device *pdev) static int dcp_platform_suspend(struct device *dev) { + struct apple_dcp *dcp = dev_get_drvdata(dev); + + if (dcp->hdmi_hpd_irq) + disable_irq(dcp->hdmi_hpd_irq); /* * Set the device as a wakeup device, which forces its power * domains to stay on. We need this as we do not support full @@ -637,14 +829,39 @@ static int dcp_platform_suspend(struct device *dev) static int dcp_platform_resume(struct device *dev) { + struct apple_dcp *dcp = dev_get_drvdata(dev); + + if (dcp->hdmi_hpd_irq) + enable_irq(dcp->hdmi_hpd_irq); + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(dcp_platform_pm_ops, dcp_platform_suspend, dcp_platform_resume); + +static const struct apple_dcp_hw_data apple_dcp_hw_t6020 = { + .num_dptx_ports = 1, +}; + +static const struct apple_dcp_hw_data apple_dcp_hw_t8112 = { + .num_dptx_ports = 2, +}; + +static const struct apple_dcp_hw_data apple_dcp_hw_dcp = { + .num_dptx_ports = 0, +}; + +static const struct apple_dcp_hw_data apple_dcp_hw_dcpext = { + .num_dptx_ports = 2, +}; + static const struct of_device_id of_match[] = { - { .compatible = "apple,dcp" }, + { .compatible = "apple,t6020-dcp", .data = &apple_dcp_hw_t6020, }, + { .compatible = "apple,t8112-dcp", .data = &apple_dcp_hw_t8112, }, + { .compatible = "apple,dcp", .data = &apple_dcp_hw_dcp, }, + { .compatible = "apple,dcpext", .data = &apple_dcp_hw_dcpext, }, {} }; MODULE_DEVICE_TABLE(of, of_match); diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index e472fad58c555c..b502718a3df54c 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -68,4 +68,7 @@ void iomfb_shutdown(struct apple_dcp *dcp); /* rtkit message handler for IOMFB messages */ void iomfb_recv_msg(struct apple_dcp *dcp, u64 message); +int systemep_init(struct apple_dcp *dcp); +int dptxep_init(struct apple_dcp *dcp); +int ibootep_init(struct apple_dcp *dcp); #endif diff --git a/drivers/gpu/drm/apple/dcp_trace.c b/drivers/gpu/drm/apple/dcp_trace.c new file mode 100644 index 00000000000000..d18e71af73a74d --- /dev/null +++ b/drivers/gpu/drm/apple/dcp_trace.c @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-2.0 +#define CREATE_TRACE_POINTS +#include "dcp_trace.h" \ No newline at end of file diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c new file mode 100644 index 00000000000000..2002f540d0e729 --- /dev/null +++ b/drivers/gpu/drm/apple/dptxep.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2022 Sven Peter */ + +#include +#include +#include +#include + +#include "afk.h" +#include "dcp.h" +#include "dptxep.h" +#include "parser.h" +#include "trace.h" + +struct dcpdptx_connection_cmd { + __le32 unk; + __le32 target; +} __attribute__((packed)); + +struct dcpdptx_hotplug_cmd { + u8 _pad0[16]; + __le32 unk; +} __attribute__((packed)); + +struct dptxport_apcall_link_rate { + __le32 retcode; + u8 _unk0[12]; + __le32 link_rate; + u8 _unk1[12]; +} __attribute__((packed)); + +struct dptxport_apcall_get_support { + __le32 retcode; + u8 _unk0[12]; + __le32 supported; + u8 _unk1[12]; +} __attribute__((packed)); + +struct dptxport_apcall_max_drive_settings { + __le32 retcode; + u8 _unk0[12]; + __le32 max_drive_settings[2]; + u8 _unk1[8]; +}; + +int dptxport_validate_connection(struct apple_epic_service *service, u8 core, + u8 atc, u8 die) +{ + struct dptx_port *dptx = service->cookie; + struct dcpdptx_connection_cmd cmd, resp; + int ret; + u32 target = FIELD_PREP(DCPDPTX_REMOTE_PORT_CORE, core) | + FIELD_PREP(DCPDPTX_REMOTE_PORT_ATC, atc) | + FIELD_PREP(DCPDPTX_REMOTE_PORT_DIE, die) | + DCPDPTX_REMOTE_PORT_CONNECTED; + + trace_dptxport_validate_connection(dptx, core, atc, die); + + cmd.target = cpu_to_le32(target); + cmd.unk = cpu_to_le32(0x100); + ret = afk_service_call(service, 0, 14, &cmd, sizeof(cmd), 40, &resp, + sizeof(resp), 40); + if (ret) + return ret; + + if (le32_to_cpu(resp.target) != target) + return -EINVAL; + if (le32_to_cpu(resp.unk) != 0x100) + return -EINVAL; + + return 0; +} + +int dptxport_connect(struct apple_epic_service *service, u8 core, u8 atc, + u8 die) +{ + struct dptx_port *dptx = service->cookie; + struct dcpdptx_connection_cmd cmd, resp; + int ret; + u32 target = FIELD_PREP(DCPDPTX_REMOTE_PORT_CORE, core) | + FIELD_PREP(DCPDPTX_REMOTE_PORT_ATC, atc) | + FIELD_PREP(DCPDPTX_REMOTE_PORT_DIE, die) | + DCPDPTX_REMOTE_PORT_CONNECTED; + + trace_dptxport_connect(dptx, core, atc, die); + + cmd.target = cpu_to_le32(target); + cmd.unk = cpu_to_le32(0x100); + ret = afk_service_call(service, 0, 13, &cmd, sizeof(cmd), 24, &resp, + sizeof(resp), 24); + if (ret) + return ret; + + if (le32_to_cpu(resp.target) != target) + return -EINVAL; + if (le32_to_cpu(resp.unk) != 0x100) + return -EINVAL; + + return 0; +} + +int dptxport_request_display(struct apple_epic_service *service) +{ + return afk_service_call(service, 0, 8, NULL, 0, 16, NULL, 0, 16); +} + +int dptxport_release_display(struct apple_epic_service *service) +{ + return afk_service_call(service, 0, 9, NULL, 0, 16, NULL, 0, 16); +} + +int dptxport_set_hpd(struct apple_epic_service *service, bool hpd) +{ + struct dcpdptx_hotplug_cmd cmd, resp; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + + if (hpd) + cmd.unk = cpu_to_le32(1); + + ret = afk_service_call(service, 8, 10, &cmd, sizeof(cmd), 12, &resp, + sizeof(resp), 12); + if (ret) + return ret; + if (le32_to_cpu(resp.unk) != 1) + return -EINVAL; + return 0; +} + +static int +dptxport_call_get_max_drive_settings(struct apple_epic_service *service, + void *reply_, size_t reply_size) +{ + struct dptxport_apcall_max_drive_settings *reply = reply_; + + if (reply_size < sizeof(*reply)) + return -EINVAL; + + reply->retcode = cpu_to_le32(0); + reply->max_drive_settings[0] = cpu_to_le32(0x3); + reply->max_drive_settings[1] = cpu_to_le32(0x3); + + return 0; +} + +static int dptxport_call_get_max_link_rate(struct apple_epic_service *service, + void *reply_, size_t reply_size) +{ + struct dptxport_apcall_link_rate *reply = reply_; + + if (reply_size < sizeof(*reply)) + return -EINVAL; + + reply->retcode = cpu_to_le32(0); + reply->link_rate = cpu_to_le32(LINK_RATE_HBR3); + + return 0; +} + +static int dptxport_call_get_link_rate(struct apple_epic_service *service, + void *reply_, size_t reply_size) +{ + struct dptx_port *dptx = service->cookie; + struct dptxport_apcall_link_rate *reply = reply_; + + if (reply_size < sizeof(*reply)) + return -EINVAL; + + reply->retcode = cpu_to_le32(0); + reply->link_rate = cpu_to_le32(dptx->link_rate); + + return 0; +} + +static int +dptxport_call_will_change_link_config(struct apple_epic_service *service) +{ + struct dptx_port *dptx = service->cookie; + + dptx->phy_ops.dp.set_lanes = 0; + dptx->phy_ops.dp.set_rate = 0; + dptx->phy_ops.dp.set_voltages = 0; + + return 0; +} + +static int +dptxport_call_did_change_link_config(struct apple_epic_service *service) +{ + /* assume the link config did change and wait a little bit */ + mdelay(10); + return 0; +} + +static int dptxport_call_set_link_rate(struct apple_epic_service *service, + const void *data, size_t data_size, + void *reply_, size_t reply_size) +{ + struct dptx_port *dptx = service->cookie; + const struct dptxport_apcall_link_rate *request = data; + struct dptxport_apcall_link_rate *reply = reply_; + u32 link_rate, phy_link_rate; + bool phy_set_rate = false; + int ret; + + if (reply_size < sizeof(*reply)) + return -EINVAL; + if (data_size < sizeof(*request)) + return -EINVAL; + + link_rate = le32_to_cpu(request->link_rate); + trace_dptxport_call_set_link_rate(dptx, link_rate); + + switch (link_rate) { + case LINK_RATE_RBR: + phy_link_rate = 1620; + phy_set_rate = true; + break; + case LINK_RATE_HBR: + phy_link_rate = 2700; + phy_set_rate = true; + break; + case LINK_RATE_HBR2: + phy_link_rate = 5400; + phy_set_rate = true; + break; + case LINK_RATE_HBR3: + phy_link_rate = 8100; + phy_set_rate = true; + break; + case 0: + phy_link_rate = 0; + phy_set_rate = true; + break; + default: + dev_err(service->ep->dcp->dev, + "DPTXPort: Unsupported link rate 0x%x requested\n", + link_rate); + link_rate = 0; + phy_set_rate = false; + break; + } + + if (phy_set_rate) { + dptx->phy_ops.dp.link_rate = phy_link_rate; + dptx->phy_ops.dp.set_rate = 1; + + if (dptx->atcphy) { + ret = phy_configure(dptx->atcphy, &dptx->phy_ops); + if (ret) + return ret; + } + + //if (dptx->phy_ops.dp.set_rate) + dptx->link_rate = dptx->pending_link_rate = link_rate; + + } + + //dptx->pending_link_rate = link_rate; + reply->retcode = cpu_to_le32(0); + reply->link_rate = cpu_to_le32(link_rate); + + return 0; +} + +static int dptxport_call_get_supports_hpd(struct apple_epic_service *service, + void *reply_, size_t reply_size) +{ + struct dptxport_apcall_get_support *reply = reply_; + + if (reply_size < sizeof(*reply)) + return -EINVAL; + + reply->retcode = cpu_to_le32(0); + reply->supported = cpu_to_le32(0); + return 0; +} + +static int +dptxport_call_get_supports_downspread(struct apple_epic_service *service, + void *reply_, size_t reply_size) +{ + struct dptxport_apcall_get_support *reply = reply_; + + if (reply_size < sizeof(*reply)) + return -EINVAL; + + reply->retcode = cpu_to_le32(0); + reply->supported = cpu_to_le32(0); + return 0; +} + +static int dptxport_call(struct apple_epic_service *service, u32 idx, + const void *data, size_t data_size, void *reply, + size_t reply_size) +{ + struct dptx_port *dptx = service->cookie; + trace_dptxport_apcall(dptx, idx, data_size); + + switch (idx) { + case DPTX_APCALL_WILL_CHANGE_LINKG_CONFIG: + return dptxport_call_will_change_link_config(service); + case DPTX_APCALL_DID_CHANGE_LINK_CONFIG: + return dptxport_call_did_change_link_config(service); + case DPTX_APCALL_GET_MAX_LINK_RATE: + return dptxport_call_get_max_link_rate(service, reply, + reply_size); + case DPTX_APCALL_GET_LINK_RATE: + return dptxport_call_get_link_rate(service, reply, reply_size); + case DPTX_APCALL_SET_LINK_RATE: + return dptxport_call_set_link_rate(service, data, data_size, + reply, reply_size); + case DPTX_APCALL_GET_SUPPORTS_HPD: + return dptxport_call_get_supports_hpd(service, reply, + reply_size); + case DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD: + return dptxport_call_get_supports_downspread(service, reply, + reply_size); + case DPTX_APCALL_GET_MAX_DRIVE_SETTINGS: + return dptxport_call_get_max_drive_settings(service, reply, + reply_size); + default: + /* just try to ACK and hope for the best... */ + dev_info(service->ep->dcp->dev, "DPTXPort: acking unhandled call %u\n", + idx); + fallthrough; + /* we can silently ignore and just ACK these calls */ + case DPTX_APCALL_ACTIVATE: + case DPTX_APCALL_DEACTIVATE: + case DPTX_APCALL_SET_DRIVE_SETTINGS: + case DPTX_APCALL_GET_DRIVE_SETTINGS: + memcpy(reply, data, min(reply_size, data_size)); + if (reply_size > 4) + memset(reply, 0, 4); + return 0; + } +} + +static void dptxport_init(struct apple_epic_service *service, const char *name, + const char *class, s64 unit) +{ + + if (strcmp(name, "dcpdptx-port-epic")) + return; + if (strcmp(class, "AppleDCPDPTXRemotePort")) + return; + + trace_dptxport_init(service->ep->dcp, unit); + + switch (unit) { + case 0: + case 1: + if (service->ep->dcp->dptxport[unit].enabled) { + dev_err(service->ep->dcp->dev, + "DPTXPort: unit %lld already exists\n", unit); + return; + } + service->ep->dcp->dptxport[unit].unit = unit; + service->ep->dcp->dptxport[unit].service = service; + service->ep->dcp->dptxport[unit].enabled = true; + service->cookie = (void *)&service->ep->dcp->dptxport[unit]; + complete(&service->ep->dcp->dptxport[unit].enable_completion); + break; + default: + dev_err(service->ep->dcp->dev, "DPTXPort: invalid unit %lld\n", + unit); + } +} + +static const struct apple_epic_service_ops dptxep_ops[] = { + { + .name = "AppleDCPDPTXRemotePort", + .init = dptxport_init, + .call = dptxport_call, + }, + {} +}; + +int dptxep_init(struct apple_dcp *dcp) +{ + int ret; + u32 port; + unsigned long timeout = msecs_to_jiffies(1000); + + init_completion(&dcp->dptxport[0].enable_completion); + init_completion(&dcp->dptxport[1].enable_completion); + + dcp->dptxep = afk_init(dcp, DPTX_ENDPOINT, dptxep_ops); + if (IS_ERR(dcp->dptxep)) + return PTR_ERR(dcp->dptxep); + + ret = afk_start(dcp->dptxep); + if (ret) + return ret; + + for (port = 0; port < dcp->hw.num_dptx_ports; port++) { + ret = wait_for_completion_timeout(&dcp->dptxport[port].enable_completion, + timeout); + if (!ret) + return -ETIMEDOUT; + else if (ret < 0) + return ret; + timeout = ret; + } + + return 0; +} diff --git a/drivers/gpu/drm/apple/dptxep.h b/drivers/gpu/drm/apple/dptxep.h new file mode 100644 index 00000000000000..efd1d5005f56da --- /dev/null +++ b/drivers/gpu/drm/apple/dptxep.h @@ -0,0 +1,66 @@ +#ifndef __APPLE_DCP_DPTXEP_H__ +#define __APPLE_DCP_DPTXEP_H__ + +#include +#include + +enum dptx_apcall { + DPTX_APCALL_ACTIVATE = 0, + DPTX_APCALL_DEACTIVATE = 1, + DPTX_APCALL_GET_MAX_DRIVE_SETTINGS = 2, + DPTX_APCALL_SET_DRIVE_SETTINGS = 3, + DPTX_APCALL_GET_DRIVE_SETTINGS = 4, + DPTX_APCALL_WILL_CHANGE_LINKG_CONFIG = 5, + DPTX_APCALL_DID_CHANGE_LINK_CONFIG = 6, + DPTX_APCALL_GET_MAX_LINK_RATE = 7, + DPTX_APCALL_GET_LINK_RATE = 8, + DPTX_APCALL_SET_LINK_RATE = 9, + DPTX_APCALL_GET_ACTIVE_LANE_COUNT = 10, + DPTX_APCALL_SET_ACTIVE_LANE_COUNT = 11, + DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD = 12, + DPTX_APCALL_GET_DOWN_SPREAD = 13, + DPTX_APCALL_SET_DOWN_SPREAD = 14, + DPTX_APCALL_GET_SUPPORTS_LANE_MAPPING = 15, + DPTX_APCALL_SET_LANE_MAP = 16, + DPTX_APCALL_GET_SUPPORTS_HPD = 17, + DPTX_APCALL_FORCE_HOTPLUG_DETECT = 18, + DPTX_APCALL_INACTIVE_SINK_DETECTED = 19, + DPTX_APCALL_SET_TILED_DISPLAY_HINTS = 20, + DPTX_APCALL_DEVICE_NOT_RESPONDING = 21, + DPTX_APCALL_DEVICE_BUSY_TIMEOUT = 22, + DPTX_APCALL_DEVICE_NOT_STARTED = 23, +}; + +#define DCPDPTX_REMOTE_PORT_CORE GENMASK(3, 0) +#define DCPDPTX_REMOTE_PORT_ATC GENMASK(7, 4) +#define DCPDPTX_REMOTE_PORT_DIE GENMASK(11, 8) +#define DCPDPTX_REMOTE_PORT_CONNECTED BIT(15) + +enum dptx_link_rate { + LINK_RATE_RBR = 0x06, + LINK_RATE_HBR = 0x0a, + LINK_RATE_HBR2 = 0x14, + LINK_RATE_HBR3 = 0x1e, +}; + +struct apple_epic_service; + +struct dptx_port { + bool enabled, connected; + struct completion enable_completion; + u32 unit; + struct apple_epic_service *service; + union phy_configure_opts phy_ops; + struct phy *atcphy; + struct mux_control *mux; + u32 link_rate, pending_link_rate; +}; + +int dptxport_validate_connection(struct apple_epic_service *service, u8 core, + u8 atc, u8 die); +int dptxport_connect(struct apple_epic_service *service, u8 core, u8 atc, + u8 die); +int dptxport_request_display(struct apple_epic_service *service); +int dptxport_release_display(struct apple_epic_service *service); +int dptxport_set_hpd(struct apple_epic_service *service, bool hpd); +#endif diff --git a/drivers/gpu/drm/apple/ibootep.c b/drivers/gpu/drm/apple/ibootep.c new file mode 100644 index 00000000000000..ae4bc8a69f2a8d --- /dev/null +++ b/drivers/gpu/drm/apple/ibootep.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2023 */ + +#include + +#include "afk.h" +#include "dcp.h" + +static void disp_service_init(struct apple_epic_service *service, const char *name, + const char *class, s64 unit) +{ +} + + +static const struct apple_epic_service_ops ibootep_ops[] = { + { + .name = "disp0-service", + .init = disp_service_init, + }, + {} +}; + +int ibootep_init(struct apple_dcp *dcp) +{ + dcp->ibootep = afk_init(dcp, DISP0_ENDPOINT, ibootep_ops); + afk_start(dcp->ibootep); + + return 0; +} diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 7e1337e1282ee0..a6de7ded260970 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -270,11 +270,6 @@ int parse(void *blob, size_t size, struct dcp_parse_ctx *ctx) return 0; } -struct dimension { - s64 total, front_porch, sync_width, active; - s64 precise_sync_rate; -}; - static int parse_dimension(struct dcp_parse_ctx *handle, struct dimension *dim) { struct iterator it; @@ -445,10 +440,14 @@ static int parse_mode(struct dcp_parse_ctx *handle, if (!IS_ERR_OR_NULL(key)) kfree(key); - if (ret) + if (ret) { + trace_iomfb_parse_mode_fail(id, &horiz, &vert, best_color_mode, is_virtual, *score); return ret; + } } + trace_iomfb_parse_mode_success(id, &horiz, &vert, best_color_mode, is_virtual, *score); + /* * Reject modes without valid color mode. */ diff --git a/drivers/gpu/drm/apple/parser.h b/drivers/gpu/drm/apple/parser.h index fa2f996b53df48..1072aa0f09009c 100644 --- a/drivers/gpu/drm/apple/parser.h +++ b/drivers/gpu/drm/apple/parser.h @@ -25,6 +25,11 @@ struct dcp_display_mode { u32 timing_mode_id; }; +struct dimension { + s64 total, front_porch, sync_width, active; + s64 precise_sync_rate; +}; + int parse(void *blob, size_t size, struct dcp_parse_ctx *ctx); struct dcp_display_mode *enumerate_modes(struct dcp_parse_ctx *handle, unsigned int *count, int width_mm, diff --git a/drivers/gpu/drm/apple/systemep.c b/drivers/gpu/drm/apple/systemep.c new file mode 100644 index 00000000000000..5383a83f1e6c28 --- /dev/null +++ b/drivers/gpu/drm/apple/systemep.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2022 Sven Peter */ + +#include + +#include "afk.h" +#include "dcp.h" + +static bool enable_verbose_logging; +module_param(enable_verbose_logging, bool, 0644); +MODULE_PARM_DESC(enable_verbose_logging, "Enable DCP firmware verbose logging"); + +/* + * Serialized setProperty("gAFKConfigLogMask", 0xffff) IPC call which + * will set the DCP firmware log level to the most verbose setting + */ +#define SYSTEM_SET_PROPERTY 0x43 +static const u8 setprop_gAFKConfigLogMask_ffff[] = { + 0x14, 0x00, 0x00, 0x00, 0x67, 0x41, 0x46, 0x4b, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x4c, 0x6f, 0x67, 0x4d, 0x61, 0x73, + 0x6b, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x84, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +struct systemep_work { + struct apple_epic_service *service; + struct work_struct work; +}; + +static void system_log_work(struct work_struct *work_) +{ + struct systemep_work *work = + container_of(work_, struct systemep_work, work); + + afk_send_command(work->service, SYSTEM_SET_PROPERTY, + setprop_gAFKConfigLogMask_ffff, + sizeof(setprop_gAFKConfigLogMask_ffff), NULL, + sizeof(setprop_gAFKConfigLogMask_ffff), NULL); + complete(&work->service->ep->dcp->systemep_done); + kfree(work); +} + +static void system_init(struct apple_epic_service *service, const char *name, + const char *class, s64 unit) +{ + struct systemep_work *work; + + if (!enable_verbose_logging) + return; + + /* + * We're called from the service message handler thread and can't + * dispatch blocking message from there. + */ + work = kzalloc(sizeof(*work), GFP_KERNEL); + if (!work) + return; + + work->service = service; + INIT_WORK(&work->work, system_log_work); + schedule_work(&work->work); +} + +static void powerlog_init(struct apple_epic_service *service, const char *name, + const char *class, s64 unit) +{ +} + +static const struct apple_epic_service_ops systemep_ops[] = { + { + .name = "system", + .init = system_init, + }, + { + .name = "powerlog-service", + .init = powerlog_init, + }, + {} +}; + +int systemep_init(struct apple_dcp *dcp) +{ + init_completion(&dcp->systemep_done); + + dcp->systemep = afk_init(dcp, SYSTEM_ENDPOINT, systemep_ops); + afk_start(dcp->systemep); + + if (!enable_verbose_logging) + return 0; + + /* + * Timeouts aren't really fatal here: in the worst case we just weren't + * able to enable additional debug prints inside DCP + */ + if (!wait_for_completion_timeout(&dcp->systemep_done, + msecs_to_jiffies(MSEC_PER_SEC))) + dev_err(dcp->dev, "systemep: couldn't enable verbose logs\n"); + + return 0; +} diff --git a/drivers/gpu/drm/apple/trace.h b/drivers/gpu/drm/apple/trace.h index 6b3d9886a4164e..6edc9f1d5db919 100644 --- a/drivers/gpu/drm/apple/trace.h +++ b/drivers/gpu/drm/apple/trace.h @@ -8,6 +8,7 @@ #define _TRACE_DCP_H #include "afk.h" +#include "dptxep.h" #include "dcp-internal.h" #include "parser.h" @@ -36,6 +37,43 @@ { EPIC_CAT_REPLY, "reply" }, \ { EPIC_CAT_COMMAND, "command" }) +#define show_dptxport_apcall(idx) \ + __print_symbolic( \ + idx, { DPTX_APCALL_ACTIVATE, "activate" }, \ + { DPTX_APCALL_DEACTIVATE, "deactivate" }, \ + { DPTX_APCALL_GET_MAX_DRIVE_SETTINGS, \ + "get_max_drive_settings" }, \ + { DPTX_APCALL_SET_DRIVE_SETTINGS, "set_drive_settings" }, \ + { DPTX_APCALL_GET_DRIVE_SETTINGS, "get_drive_settings" }, \ + { DPTX_APCALL_WILL_CHANGE_LINKG_CONFIG, \ + "will_change_link_config" }, \ + { DPTX_APCALL_DID_CHANGE_LINK_CONFIG, \ + "did_change_link_config" }, \ + { DPTX_APCALL_GET_MAX_LINK_RATE, "get_max_link_rate" }, \ + { DPTX_APCALL_GET_LINK_RATE, "get_link_rate" }, \ + { DPTX_APCALL_SET_LINK_RATE, "set_link_rate" }, \ + { DPTX_APCALL_GET_ACTIVE_LANE_COUNT, \ + "get_active_lane_count" }, \ + { DPTX_APCALL_SET_ACTIVE_LANE_COUNT, \ + "set_active_lane_count" }, \ + { DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD, \ + "get_supports_downspread" }, \ + { DPTX_APCALL_GET_DOWN_SPREAD, "get_downspread" }, \ + { DPTX_APCALL_SET_DOWN_SPREAD, "set_downspread" }, \ + { DPTX_APCALL_GET_SUPPORTS_LANE_MAPPING, \ + "get_supports_lane_mapping" }, \ + { DPTX_APCALL_SET_LANE_MAP, "set_lane_map" }, \ + { DPTX_APCALL_GET_SUPPORTS_HPD, "get_supports_hpd" }, \ + { DPTX_APCALL_FORCE_HOTPLUG_DETECT, "force_hotplug_detect" }, \ + { DPTX_APCALL_INACTIVE_SINK_DETECTED, \ + "inactive_sink_detected" }, \ + { DPTX_APCALL_SET_TILED_DISPLAY_HINTS, \ + "set_tiled_display_hints" }, \ + { DPTX_APCALL_DEVICE_NOT_RESPONDING, \ + "device_not_responding" }, \ + { DPTX_APCALL_DEVICE_BUSY_TIMEOUT, "device_busy_timeout" }, \ + { DPTX_APCALL_DEVICE_NOT_STARTED, "device_not_started" }) + TRACE_EVENT(dcp_recv_msg, TP_PROTO(struct apple_dcp *dcp, u8 endpoint, u64 message), TP_ARGS(dcp, endpoint, message), @@ -263,6 +301,108 @@ TRACE_EVENT(iomfb_swap_complete_intent_gated, ) ); +DECLARE_EVENT_CLASS(iomfb_parse_mode_template, + TP_PROTO(s64 id, struct dimension *horiz, struct dimension *vert, s64 best_color_mode, bool is_virtual, s64 score), + TP_ARGS(id, horiz, vert, best_color_mode, is_virtual, score), + + TP_STRUCT__entry(__field(s64, id) + __field_struct(struct dimension, horiz) + __field_struct(struct dimension, vert) + __field(s64, best_color_mode) + __field(bool, is_virtual) + __field(s64, score)), + + TP_fast_assign(__entry->id = id; + __entry->horiz = *horiz; + __entry->vert = *vert; + __entry->best_color_mode = best_color_mode; + __entry->is_virtual = is_virtual; + __entry->score = score;), + + TP_printk("id: %lld, best_color_mode: %lld, resolution:%lldx%lld virtual: %d, score: %lld", + __entry->id, __entry->best_color_mode, + __entry->horiz.active, __entry->vert.active, + __entry->is_virtual, __entry->score)); + +DEFINE_EVENT(iomfb_parse_mode_template, iomfb_parse_mode_success, + TP_PROTO(s64 id, struct dimension *horiz, struct dimension *vert, s64 best_color_mode, bool is_virtual, s64 score), + TP_ARGS(id, horiz, vert, best_color_mode, is_virtual, score)); + +DEFINE_EVENT(iomfb_parse_mode_template, iomfb_parse_mode_fail, + TP_PROTO(s64 id, struct dimension *horiz, struct dimension *vert, s64 best_color_mode, bool is_virtual, s64 score), + TP_ARGS(id, horiz, vert, best_color_mode, is_virtual, score)); + +TRACE_EVENT(dptxport_init, TP_PROTO(struct apple_dcp *dcp, u64 unit), + TP_ARGS(dcp, unit), + + TP_STRUCT__entry(__string(devname, dev_name(dcp->dev)) + __field(u64, unit)), + + TP_fast_assign(__assign_str(devname); + __entry->unit = unit;), + + TP_printk("%s: dptxport unit %lld initialized", __get_str(devname), + __entry->unit)); + +TRACE_EVENT( + dptxport_apcall, + TP_PROTO(struct dptx_port *dptx, int idx, size_t len), + TP_ARGS(dptx, idx, len), + + TP_STRUCT__entry(__string(devname, dev_name(dptx->service->ep->dcp->dev)) + __field(u32, unit) __field(int, idx) __field(size_t, len)), + + TP_fast_assign(__assign_str(devname); + __entry->unit = dptx->unit; __entry->idx = idx; __entry->len = len;), + + TP_printk("%s: dptx%d: AP Call %d (%s) with len %lu", __get_str(devname), + __entry->unit, + __entry->idx, show_dptxport_apcall(__entry->idx), __entry->len)); + +TRACE_EVENT( + dptxport_validate_connection, + TP_PROTO(struct dptx_port *dptx, u8 core, u8 atc, u8 die), + TP_ARGS(dptx, core, atc, die), + + TP_STRUCT__entry(__string(devname, dev_name(dptx->service->ep->dcp->dev)) + __field(u32, unit) __field(u8, core) __field(u8, atc) __field(u8, die)), + + TP_fast_assign(__assign_str(devname); + __entry->unit = dptx->unit; __entry->core = core; __entry->atc = atc; __entry->die = die;), + + TP_printk("%s: dptx%d: core %d, atc %d, die %d", __get_str(devname), + __entry->unit, __entry->core, __entry->atc, __entry->die)); + +TRACE_EVENT( + dptxport_connect, + TP_PROTO(struct dptx_port *dptx, u8 core, u8 atc, u8 die), + TP_ARGS(dptx, core, atc, die), + + TP_STRUCT__entry(__string(devname, dev_name(dptx->service->ep->dcp->dev)) + __field(u32, unit) __field(u8, core) __field(u8, atc) __field(u8, die)), + + TP_fast_assign(__assign_str(devname); + __entry->unit = dptx->unit; __entry->core = core; __entry->atc = atc; __entry->die = die;), + + TP_printk("%s: dptx%d: core %d, atc %d, die %d", __get_str(devname), + __entry->unit, __entry->core, __entry->atc, __entry->die)); + +TRACE_EVENT( + dptxport_call_set_link_rate, + TP_PROTO(struct dptx_port *dptx, u32 link_rate), + TP_ARGS(dptx, link_rate), + + TP_STRUCT__entry(__string(devname, dev_name(dptx->service->ep->dcp->dev)) + __field(u32, unit) + __field(u32, link_rate)), + + TP_fast_assign(__assign_str(devname); + __entry->unit = dptx->unit; + __entry->link_rate = link_rate;), + + TP_printk("%s: dptx%d: link rate 0x%x", __get_str(devname), __entry->unit, + __entry->link_rate)); + TRACE_EVENT(iomfb_brightness, TP_PROTO(struct apple_dcp *dcp, u32 nits), TP_ARGS(dcp, nits), From 9fbb3d370302f229f10fd3e260f658ac354d3c2d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 12 Nov 2023 10:06:45 +0100 Subject: [PATCH 141/352] drm: apple: Move offsets for rt_bandwidth callback to DT The offsets differ for every DCP instance. Instead of hardcoding offsets for each SoC family offsets and calculate the instance offset move everything to the device tree. This helps multi die SoCs since there is and unexpected offset between both dies. On multi die SoCs device tree changes were necessary to avoid translating the PMGR reg via the seconds die "ranges" property. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp-internal.h | 8 ++ drivers/gpu/drm/apple/dcp.c | 122 ++++++++++++++++++++++++- drivers/gpu/drm/apple/iomfb_template.c | 51 +++++------ 3 files changed, 151 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index b7b5c9dcc046db..d7ffb8146e4225 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -136,6 +137,13 @@ struct apple_dcp { struct resource *disp_registers[MAX_DISP_REGISTERS]; unsigned int nr_disp_registers; + struct resource disp_bw_scratch_res; + struct resource disp_bw_doorbell_res; + u32 disp_bw_scratch_index; + u32 disp_bw_scratch_offset; + u32 disp_bw_doorbell_index; + u32 disp_bw_doorbell_offset; + u32 index; /* Bitmap of memory descriptors used for mappings made by the DCP */ diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 6f96f9159c9fd6..16ed18a0fcbec5 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -475,11 +476,108 @@ static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp) return ret; } +static int dcp_get_bw_scratch_reg(struct apple_dcp *dcp, u32 expected) +{ + struct of_phandle_args ph_args; + u32 addr_idx, disp_idx, offset; + int ret; + + ret = of_parse_phandle_with_args(dcp->dev->of_node, "apple,bw-scratch", + "#apple,bw-scratch-cells", 0, &ph_args); + if (ret < 0) { + dev_err(dcp->dev, "Failed to read 'apple,bw-scratch': %d\n", ret); + return ret; + } + + if (ph_args.args_count != 3) { + dev_err(dcp->dev, "Unexpected 'apple,bw-scratch' arg count %d\n", + ph_args.args_count); + ret = -EINVAL; + goto err_of_node_put; + } + + addr_idx = ph_args.args[0]; + disp_idx = ph_args.args[1]; + offset = ph_args.args[2]; + + if (disp_idx != expected || disp_idx >= MAX_DISP_REGISTERS) { + dev_err(dcp->dev, "Unexpected disp_reg value in 'apple,bw-scratch': %d\n", + disp_idx); + ret = -EINVAL; + goto err_of_node_put; + } + + ret = of_address_to_resource(ph_args.np, addr_idx, &dcp->disp_bw_scratch_res); + if (ret < 0) { + dev_err(dcp->dev, "Failed to get 'apple,bw-scratch' resource %d from %pOF\n", + addr_idx, ph_args.np); + goto err_of_node_put; + } + if (offset > resource_size(&dcp->disp_bw_scratch_res) - 4) { + ret = -EINVAL; + goto err_of_node_put; + } + + dcp->disp_registers[disp_idx] = &dcp->disp_bw_scratch_res; + dcp->disp_bw_scratch_index = disp_idx; + dcp->disp_bw_scratch_offset = offset; + ret = 0; + +err_of_node_put: + of_node_put(ph_args.np); + return ret; +} + +static int dcp_get_bw_doorbell_reg(struct apple_dcp *dcp, u32 expected) +{ + struct of_phandle_args ph_args; + u32 addr_idx, disp_idx; + int ret; + + ret = of_parse_phandle_with_args(dcp->dev->of_node, "apple,bw-doorbell", + "#apple,bw-doorbell-cells", 0, &ph_args); + if (ret < 0) { + dev_err(dcp->dev, "Failed to read 'apple,bw-doorbell': %d\n", ret); + return ret; + } + + if (ph_args.args_count != 2) { + dev_err(dcp->dev, "Unexpected 'apple,bw-doorbell' arg count %d\n", + ph_args.args_count); + ret = -EINVAL; + goto err_of_node_put; + } + + addr_idx = ph_args.args[0]; + disp_idx = ph_args.args[1]; + + if (disp_idx != expected || disp_idx >= MAX_DISP_REGISTERS) { + dev_err(dcp->dev, "Unexpected disp_reg value in 'apple,bw-doorbell': %d\n", + disp_idx); + ret = -EINVAL; + goto err_of_node_put; + } + + ret = of_address_to_resource(ph_args.np, addr_idx, &dcp->disp_bw_doorbell_res); + if (ret < 0) { + dev_err(dcp->dev, "Failed to get 'apple,bw-doorbell' resource %d from %pOF\n", + addr_idx, ph_args.np); + goto err_of_node_put; + } + dcp->disp_bw_doorbell_index = disp_idx; + dcp->disp_registers[disp_idx] = &dcp->disp_bw_doorbell_res; + ret = 0; + +err_of_node_put: + of_node_put(ph_args.np); + return ret; +} + static int dcp_get_disp_regs(struct apple_dcp *dcp) { struct platform_device *pdev = to_platform_device(dcp->dev); int count = pdev->num_resources - 1; - int i; + int i, ret; if (count <= 0 || count > MAX_DISP_REGISTERS) return -EINVAL; @@ -489,6 +587,20 @@ static int dcp_get_disp_regs(struct apple_dcp *dcp) platform_get_resource(pdev, IORESOURCE_MEM, 1 + i); } + /* load pmgr bandwidth scratch resource and offset */ + ret = dcp_get_bw_scratch_reg(dcp, count); + if (ret < 0) + return ret; + count += 1; + + /* load pmgr bandwidth doorbell resource if present (only on t8103) */ + if (of_property_present(dcp->dev->of_node, "apple,bw-doorbell")) { + ret = dcp_get_bw_doorbell_reg(dcp, count); + if (ret < 0) + return ret; + count += 1; + } + dcp->nr_disp_registers = count; return 0; } @@ -727,6 +839,14 @@ static int dcp_platform_probe(struct platform_device *pdev) if (fw_compat == DCP_FIRMWARE_UNKNOWN) return -ENODEV; + /* Check for "apple,bw-scratch" to avoid probing appledrm with outdated + * device trees. This prevents replacing simpledrm and ending up without + * display. + */ + if (!of_property_present(dev->of_node, "apple,bw-scratch")) + return dev_err_probe(dev, -ENODEV, "Incompatible devicetree! " + "Use devicetree matching this kernel.\n"); + dcp = devm_kzalloc(dev, sizeof(*dcp), GFP_KERNEL); if (!dcp) return -ENOMEM; diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 4190999359a32c..32a9d90a929d2c 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -33,11 +33,7 @@ #include "version_utils.h" /* Register defines used in bandwidth setup structure */ -#define REG_SCRATCH (0x14) -#define REG_SCRATCH_T600X (0x988) -#define REG_SCRATCH_T602X (0x1208) -#define REG_DOORBELL (0x0) -#define REG_DOORBELL_BIT (2) +#define REG_DOORBELL_BIT(idx) (2 + (idx)) struct dcp_wait_cookie { struct kref refcount; @@ -665,34 +661,31 @@ static struct dcp_allocate_bandwidth_resp dcpep_cb_allocate_bandwidth(struct app static struct dcp_rt_bandwidth dcpep_cb_rt_bandwidth(struct apple_dcp *dcp) { - if (dcp->disp_registers[5] && dcp->disp_registers[6]) { - return (struct dcp_rt_bandwidth){ - .reg_scratch = - dcp->disp_registers[5]->start + REG_SCRATCH, - .reg_doorbell = - dcp->disp_registers[6]->start + REG_DOORBELL, - .doorbell_bit = REG_DOORBELL_BIT, - - .padding[3] = 0x4, // XXX: required by 11.x firmware - }; - } else if (dcp->disp_registers[4]) { - u32 offset = REG_SCRATCH_T600X; - if (of_device_is_compatible(dcp->dev->of_node, "apple,t6020-dcp")) - offset = REG_SCRATCH_T602X; - - return (struct dcp_rt_bandwidth){ - .reg_scratch = dcp->disp_registers[4]->start + - offset, - .reg_doorbell = 0, - .doorbell_bit = 0, - }; - } else { - return (struct dcp_rt_bandwidth){ + struct dcp_rt_bandwidth rt_bw = (struct dcp_rt_bandwidth){ .reg_scratch = 0, .reg_doorbell = 0, .doorbell_bit = 0, - }; + }; + + if (dcp->disp_bw_scratch_index) { + u32 offset = dcp->disp_bw_scratch_offset; + u32 index = dcp->disp_bw_scratch_index; + rt_bw.reg_scratch = dcp->disp_registers[index]->start + offset; } + + if (dcp->disp_bw_doorbell_index) { + u32 index = dcp->disp_bw_doorbell_index; + rt_bw.reg_doorbell = dcp->disp_registers[index]->start; + rt_bw.doorbell_bit = REG_DOORBELL_BIT(dcp->index); + /* + * This is most certainly not padding. t8103-dcp crashes without + * setting this immediately during modeset on 12.3 and 13.5 + * firmware. + */ + rt_bw.padding[3] = 0x4; + } + + return rt_bw; } static struct dcp_set_frame_sync_props_resp From f011e1e0d26449247742689bd1c7963d04c9095a Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 17 Aug 2023 23:52:39 +0200 Subject: [PATCH 142/352] drm: apple: iomfb: Do not match/create PMU service for dcpext Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp-internal.h | 3 +++ drivers/gpu/drm/apple/dcp.c | 2 ++ drivers/gpu/drm/apple/iomfb_template.c | 16 ++++++++++++++++ drivers/gpu/drm/apple/iomfb_v12_3.c | 2 +- drivers/gpu/drm/apple/iomfb_v13_3.c | 2 +- 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index d7ffb8146e4225..a9d54698c7fdab 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -183,6 +183,9 @@ struct apple_dcp { /* clear all surfaces on init */ bool surfaces_cleared; + /* is dcpext / requires dptx */ + bool is_dptx; + /* Modes valid for the connected display */ struct dcp_display_mode *modes; unsigned int nr_modes; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 16ed18a0fcbec5..2c39a594200482 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -700,6 +700,8 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) if (IS_ERR(dcp->coproc_reg)) return PTR_ERR(dcp->coproc_reg); + dcp->is_dptx = dcp->phy != NULL; + of_property_read_u32(dev->of_node, "apple,dcp-index", &dcp->index); of_property_read_u32(dev->of_node, "apple,dptx-phy", diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 32a9d90a929d2c..9e3eafec75a41e 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -135,6 +135,10 @@ static void complete_vi_set_temperature_hint(struct apple_dcp *dcp, void *out, v static bool iomfbep_cb_match_pmu_service(struct apple_dcp *dcp, int tag, void *out, void *in) { trace_iomfb_callback(dcp, tag, __func__); + + if (dcp->is_dptx) + return true; + iomfb_a358_vi_set_temperature_hint(dcp, false, complete_vi_set_temperature_hint, NULL); @@ -158,6 +162,12 @@ static bool iomfbep_cb_match_pmu_service_2(struct apple_dcp *dcp, int tag, void { trace_iomfb_callback(dcp, tag, __func__); + if (dcp->is_dptx) { + u8 *ret = out; + ret[0] = 1; + return true; + } + iomfb_a131_pmu_service_matched(dcp, false, complete_pmu_service_matched, out); @@ -1044,6 +1054,11 @@ dcpep_cb_get_tiling_state(struct apple_dcp *dcp, }; } +static u8 dcpep_cb_create_pmu_service(struct apple_dcp *dcp) +{ + return !dcp->is_dptx; +} + static u8 dcpep_cb_create_backlight_service(struct apple_dcp *dcp) { return dcp_has_panel(dcp); @@ -1101,6 +1116,7 @@ TRAMPOLINE_IN(trampoline_pr_publish, iomfb_cb_pr_publish, struct iomfb_property); TRAMPOLINE_INOUT(trampoline_get_tiling_state, dcpep_cb_get_tiling_state, struct dcpep_get_tiling_state_req, struct dcpep_get_tiling_state_resp); +TRAMPOLINE_OUT(trampoline_create_pmu_service, dcpep_cb_create_pmu_service, u8); TRAMPOLINE_OUT(trampoline_create_backlight_service, dcpep_cb_create_backlight_service, u8); /* diff --git a/drivers/gpu/drm/apple/iomfb_v12_3.c b/drivers/gpu/drm/apple/iomfb_v12_3.c index abcd1e4aab3ff8..8b4d87ad9012bd 100644 --- a/drivers/gpu/drm/apple/iomfb_v12_3.c +++ b/drivers/gpu/drm/apple/iomfb_v12_3.c @@ -48,7 +48,7 @@ static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { [106] = trampoline_nop, /* remove_property */ [107] = trampoline_true, /* create_provider_service */ [108] = trampoline_true, /* create_product_service */ - [109] = trampoline_true, /* create_pmu_service */ + [109] = trampoline_create_pmu_service, [110] = trampoline_true, /* create_iomfb_service */ [111] = trampoline_create_backlight_service, [116] = dcpep_cb_boot_1, diff --git a/drivers/gpu/drm/apple/iomfb_v13_3.c b/drivers/gpu/drm/apple/iomfb_v13_3.c index 9c692ba3c81b92..0689c0a593f784 100644 --- a/drivers/gpu/drm/apple/iomfb_v13_3.c +++ b/drivers/gpu/drm/apple/iomfb_v13_3.c @@ -50,7 +50,7 @@ static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { [107] = trampoline_nop, /* remove_property */ [108] = trampoline_true, /* create_provider_service */ [109] = trampoline_true, /* create_product_service */ - [110] = trampoline_true, /* create_pmu_service */ + [110] = trampoline_create_pmu_service, [111] = trampoline_true, /* create_iomfb_service */ [112] = trampoline_create_backlight_service, [113] = trampoline_true, /* create_nvram_servce? */ From 6a11a6a28e7d7a5ad4d1623a55c4c4df3d1ebc9a Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 9 Apr 2023 22:44:35 +0200 Subject: [PATCH 143/352] drm: apple: afk: Adapt to macOS 13.3 firmware Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/afk.c | 9 ++++++--- drivers/gpu/drm/apple/afk.h | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index d577f4ec055b03..f1e8bdfcc319a2 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -495,7 +495,7 @@ static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type, service = afk_epic_find_service(ep, channel); if (!service) { - if (type != EPIC_TYPE_NOTIFY) { + if (type != EPIC_TYPE_NOTIFY && type != EPIC_TYPE_REPLY) { dev_err(ep->dcp->dev, "AFK[ep:%02x]: expected notify but got 0x%x on channel %d\n", ep->endpoint, type, channel); @@ -807,12 +807,15 @@ int afk_send_epic(struct apple_dcp_afkep *ep, u32 channel, u16 tag, eshdr = ep->txbfr.buf + wptr; memset(eshdr, 0, sizeof(*eshdr)); eshdr->length = cpu_to_le32(payload_len); - eshdr->version = 3; + eshdr->version = 4; eshdr->category = ecat; eshdr->type = cpu_to_le16(stype); eshdr->timestamp = cpu_to_le64(0); eshdr->tag = cpu_to_le16(tag); - eshdr->inline_len = cpu_to_le16(0); + if (ecat == EPIC_CAT_REPLY) + eshdr->inline_len = cpu_to_le16(payload_len - 4); + else + eshdr->inline_len = cpu_to_le16(0); wptr += sizeof(*eshdr); memcpy(ep->txbfr.buf + wptr, payload, payload_len); diff --git a/drivers/gpu/drm/apple/afk.h b/drivers/gpu/drm/apple/afk.h index fe4ed35159ace0..1fdb4100352b25 100644 --- a/drivers/gpu/drm/apple/afk.h +++ b/drivers/gpu/drm/apple/afk.h @@ -106,6 +106,8 @@ struct epic_cmd { __le64 txbuf; __le32 rxlen; __le32 txlen; + u8 rxcookie; + u8 txcookie; } __attribute__((packed)); struct epic_service_call { From b196a284bc69dea1fdff90c9280274fad5ec7269 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 28 Apr 2023 22:24:59 +0200 Subject: [PATCH 144/352] drm: apple: dptx: Port APCALL to macOS 13.3 firmware The 13.3 firmware has an additional get_max_lane_count call inserted with ID 10. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 23 +++++++++++++++++++++++ drivers/gpu/drm/apple/dptxep.h | 29 +++++++++++++++-------------- drivers/gpu/drm/apple/trace.h | 2 ++ 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 2002f540d0e729..7179cc35991d3d 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -29,6 +29,13 @@ struct dptxport_apcall_link_rate { u8 _unk1[12]; } __attribute__((packed)); +struct dptxport_apcall_lane_count { + __le32 retcode; + u8 _unk0[12]; + __le64 lane_count; + u8 _unk1[8]; +} __attribute__((packed)); + struct dptxport_apcall_get_support { __le32 retcode; u8 _unk0[12]; @@ -158,6 +165,20 @@ static int dptxport_call_get_max_link_rate(struct apple_epic_service *service, return 0; } +static int dptxport_call_get_max_lane_count(struct apple_epic_service *service, + void *reply_, size_t reply_size) +{ + struct dptxport_apcall_lane_count *reply = reply_; + + if (reply_size < sizeof(*reply)) + return -EINVAL; + + reply->retcode = cpu_to_le32(0); + reply->lane_count = cpu_to_le64(4); + + return 0; +} + static int dptxport_call_get_link_rate(struct apple_epic_service *service, void *reply_, size_t reply_size) { @@ -311,6 +332,8 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx, case DPTX_APCALL_SET_LINK_RATE: return dptxport_call_set_link_rate(service, data, data_size, reply, reply_size); + case DPTX_APCALL_GET_MAX_LANE_COUNT: + return dptxport_call_get_max_lane_count(service, reply, reply_size); case DPTX_APCALL_GET_SUPPORTS_HPD: return dptxport_call_get_supports_hpd(service, reply, reply_size); diff --git a/drivers/gpu/drm/apple/dptxep.h b/drivers/gpu/drm/apple/dptxep.h index efd1d5005f56da..8f0483e7030b7a 100644 --- a/drivers/gpu/drm/apple/dptxep.h +++ b/drivers/gpu/drm/apple/dptxep.h @@ -15,20 +15,21 @@ enum dptx_apcall { DPTX_APCALL_GET_MAX_LINK_RATE = 7, DPTX_APCALL_GET_LINK_RATE = 8, DPTX_APCALL_SET_LINK_RATE = 9, - DPTX_APCALL_GET_ACTIVE_LANE_COUNT = 10, - DPTX_APCALL_SET_ACTIVE_LANE_COUNT = 11, - DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD = 12, - DPTX_APCALL_GET_DOWN_SPREAD = 13, - DPTX_APCALL_SET_DOWN_SPREAD = 14, - DPTX_APCALL_GET_SUPPORTS_LANE_MAPPING = 15, - DPTX_APCALL_SET_LANE_MAP = 16, - DPTX_APCALL_GET_SUPPORTS_HPD = 17, - DPTX_APCALL_FORCE_HOTPLUG_DETECT = 18, - DPTX_APCALL_INACTIVE_SINK_DETECTED = 19, - DPTX_APCALL_SET_TILED_DISPLAY_HINTS = 20, - DPTX_APCALL_DEVICE_NOT_RESPONDING = 21, - DPTX_APCALL_DEVICE_BUSY_TIMEOUT = 22, - DPTX_APCALL_DEVICE_NOT_STARTED = 23, + DPTX_APCALL_GET_MAX_LANE_COUNT = 10, + DPTX_APCALL_GET_ACTIVE_LANE_COUNT = 11, + DPTX_APCALL_SET_ACTIVE_LANE_COUNT = 12, + DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD = 13, + DPTX_APCALL_GET_DOWN_SPREAD = 14, + DPTX_APCALL_SET_DOWN_SPREAD = 15, + DPTX_APCALL_GET_SUPPORTS_LANE_MAPPING = 16, + DPTX_APCALL_SET_LANE_MAP = 17, + DPTX_APCALL_GET_SUPPORTS_HPD = 18, + DPTX_APCALL_FORCE_HOTPLUG_DETECT = 19, + DPTX_APCALL_INACTIVE_SINK_DETECTED = 20, + DPTX_APCALL_SET_TILED_DISPLAY_HINTS = 21, + DPTX_APCALL_DEVICE_NOT_RESPONDING = 22, + DPTX_APCALL_DEVICE_BUSY_TIMEOUT = 23, + DPTX_APCALL_DEVICE_NOT_STARTED = 24, }; #define DCPDPTX_REMOTE_PORT_CORE GENMASK(3, 0) diff --git a/drivers/gpu/drm/apple/trace.h b/drivers/gpu/drm/apple/trace.h index 6edc9f1d5db919..814bc7f0864475 100644 --- a/drivers/gpu/drm/apple/trace.h +++ b/drivers/gpu/drm/apple/trace.h @@ -52,6 +52,8 @@ { DPTX_APCALL_GET_MAX_LINK_RATE, "get_max_link_rate" }, \ { DPTX_APCALL_GET_LINK_RATE, "get_link_rate" }, \ { DPTX_APCALL_SET_LINK_RATE, "set_link_rate" }, \ + { DPTX_APCALL_GET_MAX_LANE_COUNT, \ + "get_max_lane_count" }, \ { DPTX_APCALL_GET_ACTIVE_LANE_COUNT, \ "get_active_lane_count" }, \ { DPTX_APCALL_SET_ACTIVE_LANE_COUNT, \ From 702c093a51c7bb2d308ca2d87f1207ff973da80f Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 18 Aug 2023 00:05:15 +0200 Subject: [PATCH 145/352] drm: apple: dptx: port interface to macOS 13.5 firmware Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 7179cc35991d3d..0ffcde99d0c070 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -65,7 +65,7 @@ int dptxport_validate_connection(struct apple_epic_service *service, u8 core, cmd.target = cpu_to_le32(target); cmd.unk = cpu_to_le32(0x100); - ret = afk_service_call(service, 0, 14, &cmd, sizeof(cmd), 40, &resp, + ret = afk_service_call(service, 0, 12, &cmd, sizeof(cmd), 40, &resp, sizeof(resp), 40); if (ret) return ret; @@ -93,7 +93,7 @@ int dptxport_connect(struct apple_epic_service *service, u8 core, u8 atc, cmd.target = cpu_to_le32(target); cmd.unk = cpu_to_le32(0x100); - ret = afk_service_call(service, 0, 13, &cmd, sizeof(cmd), 24, &resp, + ret = afk_service_call(service, 0, 11, &cmd, sizeof(cmd), 24, &resp, sizeof(resp), 24); if (ret) return ret; @@ -108,12 +108,12 @@ int dptxport_connect(struct apple_epic_service *service, u8 core, u8 atc, int dptxport_request_display(struct apple_epic_service *service) { - return afk_service_call(service, 0, 8, NULL, 0, 16, NULL, 0, 16); + return afk_service_call(service, 0, 6, NULL, 0, 16, NULL, 0, 16); } int dptxport_release_display(struct apple_epic_service *service) { - return afk_service_call(service, 0, 9, NULL, 0, 16, NULL, 0, 16); + return afk_service_call(service, 0, 7, NULL, 0, 16, NULL, 0, 16); } int dptxport_set_hpd(struct apple_epic_service *service, bool hpd) @@ -126,7 +126,7 @@ int dptxport_set_hpd(struct apple_epic_service *service, bool hpd) if (hpd) cmd.unk = cpu_to_le32(1); - ret = afk_service_call(service, 8, 10, &cmd, sizeof(cmd), 12, &resp, + ret = afk_service_call(service, 8, 8, &cmd, sizeof(cmd), 12, &resp, sizeof(resp), 12); if (ret) return ret; From e195c24325c721ace3005a5ffe668e0870ec7138 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 23:36:20 +0100 Subject: [PATCH 146/352] drm: apple: dptx: Add set_active_lanes APCALL Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 0ffcde99d0c070..23599f8c4c9c77 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -36,6 +36,13 @@ struct dptxport_apcall_lane_count { u8 _unk1[8]; } __attribute__((packed)); +struct dptxport_apcall_set_active_lane_count { + __le32 retcode; + u8 _unk0[12]; + __le64 lane_count; + u8 _unk1[8]; +} __packed; + struct dptxport_apcall_get_support { __le32 retcode; u8 _unk0[12]; @@ -179,6 +186,51 @@ static int dptxport_call_get_max_lane_count(struct apple_epic_service *service, return 0; } +static int dptxport_call_set_active_lane_count(struct apple_epic_service *service, + const void *data, size_t data_size, + void *reply_, size_t reply_size) +{ + struct dptx_port *dptx = service->cookie; + const struct dptxport_apcall_set_active_lane_count *request = data; + struct dptxport_apcall_set_active_lane_count *reply = reply_; + int ret = 0; + int retcode = 0; + + if (reply_size < sizeof(*reply)) + return -1; + if (data_size < sizeof(*request)) + return -1; + + u64 lane_count = cpu_to_le64(request->lane_count); + + switch (lane_count) { + case 0 ... 2: + case 4: + dptx->phy_ops.dp.lanes = lane_count; + dptx->phy_ops.dp.set_lanes = 1; + break; + default: + dev_err(service->ep->dcp->dev, "set_active_lane_count: invalid lane count:%llu\n", lane_count); + retcode = 1; + lane_count = 0; + break; + } + + if (dptx->phy_ops.dp.set_lanes) { + if (dptx->atcphy) { + ret = phy_configure(dptx->atcphy, &dptx->phy_ops); + if (ret) + return ret; + } + dptx->phy_ops.dp.set_lanes = 0; + } + + reply->retcode = cpu_to_le32(retcode); + reply->lane_count = cpu_to_le64(lane_count); + + return ret; +} + static int dptxport_call_get_link_rate(struct apple_epic_service *service, void *reply_, size_t reply_size) { @@ -334,6 +386,9 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx, reply, reply_size); case DPTX_APCALL_GET_MAX_LANE_COUNT: return dptxport_call_get_max_lane_count(service, reply, reply_size); + case DPTX_APCALL_SET_ACTIVE_LANE_COUNT: + return dptxport_call_set_active_lane_count(service, data, data_size, + reply, reply_size); case DPTX_APCALL_GET_SUPPORTS_HPD: return dptxport_call_get_supports_hpd(service, reply, reply_size); From 0fe67ab9cf7dc4c368b96e916fe6578324f9e164 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 23:37:27 +0100 Subject: [PATCH 147/352] drm: apple: dptx: Add DPTX_APCALL_ACTIVATE Configures the phy to the correct dcp(ext) source by abusing submode in the phy_set_mode_ext() call. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 23599f8c4c9c77..a0f90f7153fccd 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -364,6 +364,24 @@ dptxport_call_get_supports_downspread(struct apple_epic_service *service, return 0; } +static int +dptxport_call_activate(struct apple_epic_service *service, + const void *data, size_t data_size, + void *reply, size_t reply_size) +{ + struct dptx_port *dptx = service->cookie; + const struct apple_dcp *dcp = service->ep->dcp; + + // TODO: hack, use phy_set_mode to select the correct DCP(EXT) input + phy_set_mode_ext(dptx->atcphy, PHY_MODE_DP, dcp->index); + + memcpy(reply, data, min(reply_size, data_size)); + if (reply_size > 4) + memset(reply, 0, 4); + + return 0; +} + static int dptxport_call(struct apple_epic_service *service, u32 idx, const void *data, size_t data_size, void *reply, size_t reply_size) @@ -398,13 +416,15 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx, case DPTX_APCALL_GET_MAX_DRIVE_SETTINGS: return dptxport_call_get_max_drive_settings(service, reply, reply_size); + case DPTX_APCALL_ACTIVATE: + return dptxport_call_activate(service, data, data_size, + reply, reply_size); default: /* just try to ACK and hope for the best... */ dev_info(service->ep->dcp->dev, "DPTXPort: acking unhandled call %u\n", idx); fallthrough; /* we can silently ignore and just ACK these calls */ - case DPTX_APCALL_ACTIVATE: case DPTX_APCALL_DEACTIVATE: case DPTX_APCALL_SET_DRIVE_SETTINGS: case DPTX_APCALL_GET_DRIVE_SETTINGS: From aa171821797f3e5d90d887ad708dd92c7ee8555c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 23:44:08 +0100 Subject: [PATCH 148/352] drm: apple: dptx: Adapt dptxport_connect() to observed behavior Adapt to behavior seen on j474s with dcp0 driving lpdptx-phy and dp2hdmi using the macOS 13.5 firmware. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index a0f90f7153fccd..2c751c630a122d 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -90,6 +90,7 @@ int dptxport_connect(struct apple_epic_service *service, u8 core, u8 atc, { struct dptx_port *dptx = service->cookie; struct dcpdptx_connection_cmd cmd, resp; + u32 unk_field = 0x0; // seen as 0x100 under some conditions int ret; u32 target = FIELD_PREP(DCPDPTX_REMOTE_PORT_CORE, core) | FIELD_PREP(DCPDPTX_REMOTE_PORT_ATC, atc) | @@ -99,7 +100,7 @@ int dptxport_connect(struct apple_epic_service *service, u8 core, u8 atc, trace_dptxport_connect(dptx, core, atc, die); cmd.target = cpu_to_le32(target); - cmd.unk = cpu_to_le32(0x100); + cmd.unk = cpu_to_le32(unk_field); ret = afk_service_call(service, 0, 11, &cmd, sizeof(cmd), 24, &resp, sizeof(resp), 24); if (ret) @@ -107,8 +108,9 @@ int dptxport_connect(struct apple_epic_service *service, u8 core, u8 atc, if (le32_to_cpu(resp.target) != target) return -EINVAL; - if (le32_to_cpu(resp.unk) != 0x100) - return -EINVAL; + if (le32_to_cpu(resp.unk) != unk_field) + dev_notice(service->ep->dcp->dev, "unexpected unk field in reply: 0x%x (0x%x)\n", + le32_to_cpu(resp.unk), unk_field); return 0; } From 1a71cec36291ddd4d8f3dbd90feb4b559cfe34ca Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 16 Nov 2023 19:38:49 +0900 Subject: [PATCH 149/352] drm: apple: afk: Clear commands before sending them Signed-off-by: Hector Martin --- drivers/gpu/drm/apple/afk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index f1e8bdfcc319a2..10255f2e15ee4d 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -861,6 +861,7 @@ int afk_send_command(struct apple_epic_service *service, u8 type, memcpy(txbuf, payload, payload_len); + memset(&cmd, 0, sizeof(cmd)); cmd.retcode = cpu_to_le32(0); cmd.rxbuf = cpu_to_le64(rxbuf_dma); cmd.rxlen = cpu_to_le32(output_len); @@ -951,6 +952,8 @@ int afk_service_call(struct apple_epic_service *service, u16 group, u32 command, return -ENOMEM; call = bfr; + + memset(call, 0, sizeof(*call)); call->group = cpu_to_le16(group); call->command = cpu_to_le32(command); call->data_len = cpu_to_le32(data_len + data_pad); From 51d866ba3b71dda5e6fc0134602044b307062b09 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 17 Nov 2023 00:02:27 +0900 Subject: [PATCH 150/352] drm: apple: Fix missing unlock path in dcp_dptx_connect Signed-off-by: Hector Martin --- drivers/gpu/drm/apple/dcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 2c39a594200482..7d2a21967f12ec 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -269,12 +269,14 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) } if (dcp->dptxport[port].connected) - return 0; + goto ret; dcp->dptxport[port].atcphy = dcp->phy; dptxport_connect(dcp->dptxport[port].service, 0, dcp->dptx_phy, dcp->dptx_die); dptxport_request_display(dcp->dptxport[port].service); dcp->dptxport[port].connected = true; + +ret: mutex_unlock(&dcp->hpd_mutex); return 0; From e17f9e1e1c12d3f553b9b3a2bfbb969f2942c0a3 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 17 Nov 2023 00:03:36 +0900 Subject: [PATCH 151/352] drm: apple: dptxep: Fix reply size check Signed-off-by: Hector Martin --- drivers/gpu/drm/apple/dptxep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 2c751c630a122d..50d14741e66da7 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -378,7 +378,7 @@ dptxport_call_activate(struct apple_epic_service *service, phy_set_mode_ext(dptx->atcphy, PHY_MODE_DP, dcp->index); memcpy(reply, data, min(reply_size, data_size)); - if (reply_size > 4) + if (reply_size >= 4) memset(reply, 0, 4); return 0; @@ -431,7 +431,7 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx, case DPTX_APCALL_SET_DRIVE_SETTINGS: case DPTX_APCALL_GET_DRIVE_SETTINGS: memcpy(reply, data, min(reply_size, data_size)); - if (reply_size > 4) + if (reply_size >= 4) memset(reply, 0, 4); return 0; } From 68e61f6b6bebdb158ab69e9050393402bc96d9c1 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 17 Nov 2023 00:03:51 +0900 Subject: [PATCH 152/352] drm: apple: dptxep: Implement drive settings stuff Just in case, for consistency with macOS. Signed-off-by: Hector Martin --- drivers/gpu/drm/apple/dptxep.c | 75 +++++++++++++++++++++++++++++++++- drivers/gpu/drm/apple/dptxep.h | 1 + 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 50d14741e66da7..83d4a3925af0ac 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -57,6 +57,18 @@ struct dptxport_apcall_max_drive_settings { u8 _unk1[8]; }; +struct dptxport_apcall_drive_settings { + __le32 retcode; + u8 _unk0[12]; + __le32 unk1; + __le32 unk2; + __le32 unk3; + __le32 unk4; + __le32 unk5; + __le32 unk6; + __le32 unk7; +}; + int dptxport_validate_connection(struct apple_epic_service *service, u8 core, u8 atc, u8 die) { @@ -160,6 +172,61 @@ dptxport_call_get_max_drive_settings(struct apple_epic_service *service, return 0; } +static int +dptxport_call_get_drive_settings(struct apple_epic_service *service, + const void *request_, size_t request_size, + void *reply_, size_t reply_size) +{ + struct dptx_port *dptx = service->cookie; + const struct dptxport_apcall_drive_settings *request = request_; + struct dptxport_apcall_drive_settings *reply = reply_; + + if (reply_size < sizeof(*reply) || request_size < sizeof(*request)) + return -EINVAL; + + *reply = *request; + + /* Clear the rest of the buffer */ + memset(reply_ + sizeof(*reply), 0, reply_size - sizeof(*reply)); + + if (reply->retcode != 4) + dev_err(service->ep->dcp->dev, + "get_drive_settings: unexpected retcode %d\n", + reply->retcode); + + reply->retcode = 4; /* Should already be 4? */ + reply->unk5 = dptx->drive_settings[0]; + reply->unk6 = 0; + reply->unk7 = dptx->drive_settings[1]; + + return 0; +} + +static int +dptxport_call_set_drive_settings(struct apple_epic_service *service, + const void *request_, size_t request_size, + void *reply_, size_t reply_size) +{ + struct dptx_port *dptx = service->cookie; + const struct dptxport_apcall_drive_settings *request = request_; + struct dptxport_apcall_drive_settings *reply = reply_; + + if (reply_size < sizeof(*reply) || request_size < sizeof(*request)) + return -EINVAL; + + *reply = *request; + reply->retcode = cpu_to_le32(0); + + dev_info(service->ep->dcp->dev, "set_drive_settings: %d:%d:%d:%d:%d:%d:%d\n", + request->unk1, request->unk2, request->unk3, request->unk4, + request->unk5, request->unk6, request->unk7); + + dptx->drive_settings[0] = reply->unk5; + dptx->drive_settings[1] = reply->unk7; + + return 0; +} + static int dptxport_call_get_max_link_rate(struct apple_epic_service *service, void *reply_, size_t reply_size) { @@ -418,6 +485,12 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx, case DPTX_APCALL_GET_MAX_DRIVE_SETTINGS: return dptxport_call_get_max_drive_settings(service, reply, reply_size); + case DPTX_APCALL_GET_DRIVE_SETTINGS: + return dptxport_call_get_drive_settings(service, data, data_size, + reply, reply_size); + case DPTX_APCALL_SET_DRIVE_SETTINGS: + return dptxport_call_set_drive_settings(service, data, data_size, + reply, reply_size); case DPTX_APCALL_ACTIVATE: return dptxport_call_activate(service, data, data_size, reply, reply_size); @@ -428,8 +501,6 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx, fallthrough; /* we can silently ignore and just ACK these calls */ case DPTX_APCALL_DEACTIVATE: - case DPTX_APCALL_SET_DRIVE_SETTINGS: - case DPTX_APCALL_GET_DRIVE_SETTINGS: memcpy(reply, data, min(reply_size, data_size)); if (reply_size >= 4) memset(reply, 0, 4); diff --git a/drivers/gpu/drm/apple/dptxep.h b/drivers/gpu/drm/apple/dptxep.h index 8f0483e7030b7a..481ebbc97bf38d 100644 --- a/drivers/gpu/drm/apple/dptxep.h +++ b/drivers/gpu/drm/apple/dptxep.h @@ -55,6 +55,7 @@ struct dptx_port { struct phy *atcphy; struct mux_control *mux; u32 link_rate, pending_link_rate; + u32 drive_settings[2]; }; int dptxport_validate_connection(struct apple_epic_service *service, u8 core, From 20adcc168b11f9ff41736b08ea5669739f9c8564 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 20 Nov 2023 22:43:48 +0100 Subject: [PATCH 153/352] drm: apple: HACK: Do not delete piodma platform device of_platform_device_destroy() can trigger several NULL pointer dereference which have been elusive so far. Comment this for now since the oopses causes the shutdown to hang. Since dcp can not be reloaded this leaks the platform device on shutdown and reboot. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 7d2a21967f12ec..a2bb0debfb138d 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -819,7 +819,10 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) if (dcp->piodma) { iommu_detach_device(dcp->iommu_dom, &dcp->piodma->dev); iommu_domain_free(dcp->iommu_dom); - of_platform_device_destroy(&dcp->piodma->dev, NULL); + /* TODO: the piodma platform device has to be destroyed but + * doing so leads to all kind of breakage. + */ + // of_platform_device_destroy(&dcp->piodma->dev, NULL); dcp->piodma = NULL; } From f1b8bdaffa51765e134196136abde68d32f04995 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 6 Nov 2023 22:27:54 +0100 Subject: [PATCH 154/352] drm: apple: afk: Update read pointer before processing message Avoids out of order messages and already unmapped buffers while tracing with hv/trace_dcp.py. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/afk.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index 10255f2e15ee4d..fc90150bb7b5ab 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -613,8 +613,6 @@ static bool afk_recv(struct apple_dcp_afkep *ep) channel = le32_to_cpu(hdr->channel); type = le32_to_cpu(hdr->type); - afk_recv_handle(ep, channel, type, hdr->data, size); - rptr = ALIGN(rptr + sizeof(*hdr) + size, 1 << BLOCK_SHIFT); if (WARN_ON(rptr > ep->rxbfr.bufsz)) rptr = 0; @@ -626,6 +624,15 @@ static bool afk_recv(struct apple_dcp_afkep *ep) ep->rxbfr.hdr->rptr = cpu_to_le32(rptr); trace_afk_recv_rwptr_post(ep, rptr, wptr); + /* + * TODO: this is theoretically unsafe since DCP could overwrite data + * after the read pointer was updated above. Do it anyway since + * it avoids 2 problems in the DCP tracer: + * 1. the tracer sees replies before the the notifies from dcp + * 2. the tracer tries to read buffers after they are unmapped. + */ + afk_recv_handle(ep, channel, type, hdr->data, size); + return true; } From a583a3466278cbe49cc5b5267131b5508350e400 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 19 Nov 2023 18:07:41 +0100 Subject: [PATCH 155/352] drm: apple: Implement D592 callback This callback is occasionally seen around (failed) modesets. There seems to be no need to handle it so just trace it. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 7 +++++++ drivers/gpu/drm/apple/iomfb_v12_3.c | 1 + drivers/gpu/drm/apple/iomfb_v13_3.c | 1 + drivers/gpu/drm/apple/trace.h | 17 +++++++++++++++++ 4 files changed, 26 insertions(+) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 9e3eafec75a41e..088ba18e9a8d32 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1044,6 +1044,12 @@ dcpep_cb_swap_complete_intent_gated(struct apple_dcp *dcp, info->width, info->height); } +static void +dcpep_cb_abort_swap_ap_gated(struct apple_dcp *dcp, u32 *swap_id) +{ + trace_iomfb_abort_swap_ap_gated(dcp, *swap_id); +} + static struct dcpep_get_tiling_state_resp dcpep_cb_get_tiling_state(struct apple_dcp *dcp, struct dcpep_get_tiling_state_req *req) @@ -1110,6 +1116,7 @@ TRAMPOLINE_IN(trampoline_hotplug, dcpep_cb_hotplug, u64); TRAMPOLINE_IN(trampoline_swap_complete_intent_gated, dcpep_cb_swap_complete_intent_gated, struct dcp_swap_complete_intent_gated); +TRAMPOLINE_IN(trampoline_abort_swap_ap_gated, dcpep_cb_abort_swap_ap_gated, u32); TRAMPOLINE_IN(trampoline_enable_backlight_message_ap_gated, iomfbep_cb_enable_backlight_message_ap_gated, u8); TRAMPOLINE_IN(trampoline_pr_publish, iomfb_cb_pr_publish, diff --git a/drivers/gpu/drm/apple/iomfb_v12_3.c b/drivers/gpu/drm/apple/iomfb_v12_3.c index 8b4d87ad9012bd..ad3cbf576cfdcf 100644 --- a/drivers/gpu/drm/apple/iomfb_v12_3.c +++ b/drivers/gpu/drm/apple/iomfb_v12_3.c @@ -89,6 +89,7 @@ static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { [588] = trampoline_nop, /* resize_default_fb_surface_gated */ [589] = trampoline_swap_complete, [591] = trampoline_swap_complete_intent_gated, + [592] = trampoline_abort_swap_ap_gated, [593] = trampoline_enable_backlight_message_ap_gated, [594] = trampoline_nop, /* IOMobileFramebufferAP::setSystemConsoleMode */ [596] = trampoline_false, /* IOMobileFramebufferAP::isDFBAllocated */ diff --git a/drivers/gpu/drm/apple/iomfb_v13_3.c b/drivers/gpu/drm/apple/iomfb_v13_3.c index 0689c0a593f784..0311e1c8c39874 100644 --- a/drivers/gpu/drm/apple/iomfb_v13_3.c +++ b/drivers/gpu/drm/apple/iomfb_v13_3.c @@ -95,6 +95,7 @@ static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { [588] = trampoline_nop, /* resize_default_fb_surface_gated */ [589] = trampoline_swap_complete, [591] = trampoline_swap_complete_intent_gated, + [592] = trampoline_abort_swap_ap_gated, [593] = trampoline_enable_backlight_message_ap_gated, [594] = trampoline_nop, /* IOMobileFramebufferAP::setSystemConsoleMode */ [596] = trampoline_false, /* IOMobileFramebufferAP::isDFBAllocated */ diff --git a/drivers/gpu/drm/apple/trace.h b/drivers/gpu/drm/apple/trace.h index 814bc7f0864475..e03bf8b199c88f 100644 --- a/drivers/gpu/drm/apple/trace.h +++ b/drivers/gpu/drm/apple/trace.h @@ -303,6 +303,23 @@ TRACE_EVENT(iomfb_swap_complete_intent_gated, ) ); +TRACE_EVENT(iomfb_abort_swap_ap_gated, + TP_PROTO(struct apple_dcp *dcp, u32 swap_id), + TP_ARGS(dcp, swap_id), + TP_STRUCT__entry( + __field(u64, dcp) + __field(u32, swap_id) + ), + TP_fast_assign( + __entry->dcp = (u64)dcp; + __entry->swap_id = swap_id; + ), + TP_printk("dcp=%llx, swap_id=%u", + __entry->dcp, + __entry->swap_id + ) +); + DECLARE_EVENT_CLASS(iomfb_parse_mode_template, TP_PROTO(s64 id, struct dimension *horiz, struct dimension *vert, s64 best_color_mode, bool is_virtual, s64 score), TP_ARGS(id, horiz, vert, best_color_mode, is_virtual, score), From 6d7b6bdca39e8b3af043400ec9cbdf113c3a58f9 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 19 Nov 2023 18:25:22 +0100 Subject: [PATCH 156/352] drm: apple: Keep information at which swap_id fb are still referenced Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp-internal.h | 4 ++++ drivers/gpu/drm/apple/iomfb_template.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index a9d54698c7fdab..d82581bc63a6eb 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -75,6 +75,7 @@ struct dcp_channel { struct dcp_fb_reference { struct list_head head; struct drm_framebuffer *fb; + u32 swap_id; }; #define MAX_NOTCH_HEIGHT 160 @@ -167,6 +168,9 @@ struct apple_dcp { struct dcp_swap_submit_req_v13_3 v13_3; } swap; + /* swap id of the last completed swap */ + u32 last_swap_id; + /* Current display mode */ bool valid_mode; struct dcp_set_digital_out_mode_req mode; diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 088ba18e9a8d32..c810a4ad956c1c 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -121,6 +121,7 @@ static void dcpep_cb_swap_complete(struct apple_dcp *dcp, struct DCP_FW_NAME(dc_swap_complete_resp) *resp) { trace_iomfb_swap_complete(dcp, resp->swap_id); + dcp->last_swap_id = resp->swap_id; dcp_drm_crtc_vblank(dcp->crtc); } @@ -746,6 +747,8 @@ static void dcp_swap_cleared(struct apple_dcp *dcp, void *data, void *cookie) struct dcp_fb_reference *entry; entry = list_first_entry(&dcp->swapped_out_fbs, struct dcp_fb_reference, head); + if (entry->swap_id == dcp->last_swap_id) + break; if (entry->fb) drm_framebuffer_put(entry->fb); list_del(&entry->head); @@ -1145,6 +1148,8 @@ static void dcp_swapped(struct apple_dcp *dcp, void *data, void *cookie) struct dcp_fb_reference *entry; entry = list_first_entry(&dcp->swapped_out_fbs, struct dcp_fb_reference, head); + if (entry->swap_id == dcp->last_swap_id) + break; if (entry->fb) drm_framebuffer_put(entry->fb); list_del(&entry->head); @@ -1252,6 +1257,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru kzalloc(sizeof(*entry), GFP_KERNEL); if (entry) { entry->fb = old_state->fb; + entry->swap_id = dcp->last_swap_id; list_add_tail(&entry->head, &dcp->swapped_out_fbs); } From ae8e9a0817287739d116cc948ad204e5e63d7925 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 20 Nov 2023 20:09:25 +0100 Subject: [PATCH 157/352] Revert "drm: apple: iomfb: Do not match/create PMU service for dcpext" This reverts commit ab69434d230f9951644e10c9142dbc43ea0516c4. --- drivers/gpu/drm/apple/dcp-internal.h | 3 --- drivers/gpu/drm/apple/dcp.c | 2 -- drivers/gpu/drm/apple/iomfb_template.c | 16 ---------------- drivers/gpu/drm/apple/iomfb_v12_3.c | 2 +- drivers/gpu/drm/apple/iomfb_v13_3.c | 2 +- 5 files changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index d82581bc63a6eb..4817412edf6407 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -187,9 +187,6 @@ struct apple_dcp { /* clear all surfaces on init */ bool surfaces_cleared; - /* is dcpext / requires dptx */ - bool is_dptx; - /* Modes valid for the connected display */ struct dcp_display_mode *modes; unsigned int nr_modes; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index a2bb0debfb138d..98d273c719fc21 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -702,8 +702,6 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) if (IS_ERR(dcp->coproc_reg)) return PTR_ERR(dcp->coproc_reg); - dcp->is_dptx = dcp->phy != NULL; - of_property_read_u32(dev->of_node, "apple,dcp-index", &dcp->index); of_property_read_u32(dev->of_node, "apple,dptx-phy", diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index c810a4ad956c1c..a2b6556b62dac5 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -136,10 +136,6 @@ static void complete_vi_set_temperature_hint(struct apple_dcp *dcp, void *out, v static bool iomfbep_cb_match_pmu_service(struct apple_dcp *dcp, int tag, void *out, void *in) { trace_iomfb_callback(dcp, tag, __func__); - - if (dcp->is_dptx) - return true; - iomfb_a358_vi_set_temperature_hint(dcp, false, complete_vi_set_temperature_hint, NULL); @@ -163,12 +159,6 @@ static bool iomfbep_cb_match_pmu_service_2(struct apple_dcp *dcp, int tag, void { trace_iomfb_callback(dcp, tag, __func__); - if (dcp->is_dptx) { - u8 *ret = out; - ret[0] = 1; - return true; - } - iomfb_a131_pmu_service_matched(dcp, false, complete_pmu_service_matched, out); @@ -1063,11 +1053,6 @@ dcpep_cb_get_tiling_state(struct apple_dcp *dcp, }; } -static u8 dcpep_cb_create_pmu_service(struct apple_dcp *dcp) -{ - return !dcp->is_dptx; -} - static u8 dcpep_cb_create_backlight_service(struct apple_dcp *dcp) { return dcp_has_panel(dcp); @@ -1126,7 +1111,6 @@ TRAMPOLINE_IN(trampoline_pr_publish, iomfb_cb_pr_publish, struct iomfb_property); TRAMPOLINE_INOUT(trampoline_get_tiling_state, dcpep_cb_get_tiling_state, struct dcpep_get_tiling_state_req, struct dcpep_get_tiling_state_resp); -TRAMPOLINE_OUT(trampoline_create_pmu_service, dcpep_cb_create_pmu_service, u8); TRAMPOLINE_OUT(trampoline_create_backlight_service, dcpep_cb_create_backlight_service, u8); /* diff --git a/drivers/gpu/drm/apple/iomfb_v12_3.c b/drivers/gpu/drm/apple/iomfb_v12_3.c index ad3cbf576cfdcf..0fe08c42d64659 100644 --- a/drivers/gpu/drm/apple/iomfb_v12_3.c +++ b/drivers/gpu/drm/apple/iomfb_v12_3.c @@ -48,7 +48,7 @@ static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { [106] = trampoline_nop, /* remove_property */ [107] = trampoline_true, /* create_provider_service */ [108] = trampoline_true, /* create_product_service */ - [109] = trampoline_create_pmu_service, + [109] = trampoline_true, /* create_pmu_service */ [110] = trampoline_true, /* create_iomfb_service */ [111] = trampoline_create_backlight_service, [116] = dcpep_cb_boot_1, diff --git a/drivers/gpu/drm/apple/iomfb_v13_3.c b/drivers/gpu/drm/apple/iomfb_v13_3.c index 0311e1c8c39874..1ee29112be4543 100644 --- a/drivers/gpu/drm/apple/iomfb_v13_3.c +++ b/drivers/gpu/drm/apple/iomfb_v13_3.c @@ -50,7 +50,7 @@ static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { [107] = trampoline_nop, /* remove_property */ [108] = trampoline_true, /* create_provider_service */ [109] = trampoline_true, /* create_product_service */ - [110] = trampoline_create_pmu_service, + [110] = trampoline_true, /* create_pmu_service */ [111] = trampoline_true, /* create_iomfb_service */ [112] = trampoline_create_backlight_service, [113] = trampoline_true, /* create_nvram_servce? */ From 16ca667f7afb969da578ae79eec8e550a12aecb0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 20 Nov 2023 22:48:02 +0100 Subject: [PATCH 158/352] drm: apple: dptx: Implement APCALL_DEACTIVATE and reset the phy This mirrors what macOS does and should make reconnections more reliable. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 83d4a3925af0ac..328ff41aee7dd0 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -451,6 +451,23 @@ dptxport_call_activate(struct apple_epic_service *service, return 0; } +static int +dptxport_call_deactivate(struct apple_epic_service *service, + const void *data, size_t data_size, + void *reply, size_t reply_size) +{ + struct dptx_port *dptx = service->cookie; + + /* deactivate phy */ + phy_set_mode_ext(dptx->atcphy, PHY_MODE_INVALID, 0); + + memcpy(reply, data, min(reply_size, data_size)); + if (reply_size >= 4) + memset(reply, 0, 4); + + return 0; +} + static int dptxport_call(struct apple_epic_service *service, u32 idx, const void *data, size_t data_size, void *reply, size_t reply_size) @@ -494,13 +511,13 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx, case DPTX_APCALL_ACTIVATE: return dptxport_call_activate(service, data, data_size, reply, reply_size); + case DPTX_APCALL_DEACTIVATE: + return dptxport_call_deactivate(service, data, data_size, + reply, reply_size); default: /* just try to ACK and hope for the best... */ dev_info(service->ep->dcp->dev, "DPTXPort: acking unhandled call %u\n", idx); - fallthrough; - /* we can silently ignore and just ACK these calls */ - case DPTX_APCALL_DEACTIVATE: memcpy(reply, data, min(reply_size, data_size)); if (reply_size >= 4) memset(reply, 0, 4); From 044cb318508e3c0c0be1e9c28fcd1c16d45ae911 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 20 Nov 2023 22:56:43 +0100 Subject: [PATCH 159/352] drm: apple: Disconnect dptx When the CRTC is powered down Seems to make disconnect / reconnect more reliable and almost fixes suspend/resume. The drm device tries to modeset too early on resume which leaves the screen blank. This should reduce power consumption after disconnecting the HDMI port. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 64 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/apple/iomfb.c | 51 ---------------------------- 2 files changed, 64 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 98d273c719fc21..9fb2d3181ff400 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -287,6 +287,7 @@ static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) struct apple_connector *connector = dcp->connector; mutex_lock(&dcp->hpd_mutex); + if (connector && connector->connected) { dcp->valid_mode = false; schedule_work(&connector->hotplug_wq); @@ -407,6 +408,69 @@ int dcp_wait_ready(struct platform_device *pdev, u64 timeout) } EXPORT_SYMBOL(dcp_wait_ready); +static void __maybe_unused dcp_sleep(struct apple_dcp *dcp) +{ + switch (dcp->fw_compat) { + case DCP_FIRMWARE_V_12_3: + iomfb_sleep_v12_3(dcp); + break; + case DCP_FIRMWARE_V_13_5: + iomfb_sleep_v13_3(dcp); + break; + default: + WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); + break; + } +} + +void dcp_poweron(struct platform_device *pdev) +{ + struct apple_dcp *dcp = platform_get_drvdata(pdev); + + if (dcp->hdmi_hpd) { + bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); + dev_info(dcp->dev, "%s: DP2HDMI HPD connected:%d\n", __func__, connected); + + if (connected) + dcp_dptx_connect(dcp, 0); + } + + switch (dcp->fw_compat) { + case DCP_FIRMWARE_V_12_3: + iomfb_poweron_v12_3(dcp); + break; + case DCP_FIRMWARE_V_13_5: + iomfb_poweron_v13_3(dcp); + break; + default: + WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); + break; + } +} +EXPORT_SYMBOL(dcp_poweron); + +void dcp_poweroff(struct platform_device *pdev) +{ + struct apple_dcp *dcp = platform_get_drvdata(pdev); + + switch (dcp->fw_compat) { + case DCP_FIRMWARE_V_12_3: + iomfb_poweroff_v12_3(dcp); + break; + case DCP_FIRMWARE_V_13_5: + iomfb_poweroff_v13_3(dcp); + break; + default: + WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); + break; + } + + if (dcp->phy) + dcp_dptx_disconnect(dcp, 0); + +} +EXPORT_SYMBOL(dcp_poweroff); + static void dcp_work_register_backlight(struct work_struct *work) { int ret; diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index af61d74ca443da..d6af92637355df 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -219,57 +219,6 @@ void dcp_ack(struct apple_dcp *dcp, enum dcp_context_id context) dcpep_ack(context)); } -void dcp_sleep(struct apple_dcp *dcp) -{ - switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_sleep_v12_3(dcp); - break; - case DCP_FIRMWARE_V_13_5: - iomfb_sleep_v13_3(dcp); - break; - default: - WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); - break; - } -} - -void dcp_poweron(struct platform_device *pdev) -{ - struct apple_dcp *dcp = platform_get_drvdata(pdev); - - switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_poweron_v12_3(dcp); - break; - case DCP_FIRMWARE_V_13_5: - iomfb_poweron_v13_3(dcp); - break; - default: - WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); - break; - } -} -EXPORT_SYMBOL(dcp_poweron); - -void dcp_poweroff(struct platform_device *pdev) -{ - struct apple_dcp *dcp = platform_get_drvdata(pdev); - - switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_poweroff_v12_3(dcp); - break; - case DCP_FIRMWARE_V_13_5: - iomfb_poweroff_v13_3(dcp); - break; - default: - WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); - break; - } -} -EXPORT_SYMBOL(dcp_poweroff); - /* * Helper to send a DRM hotplug event. The DCP is accessed from a single * (RTKit) thread. To handle hotplug callbacks, we need to call From 4106f1e87f38147484794d641a25ec65e7d5f8ea Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 21 Nov 2023 23:32:07 +0100 Subject: [PATCH 160/352] drm: apple: dptx: Wait for completion of dptx_connect. Makes connects more reliable. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 17 ++++++++++++----- drivers/gpu/drm/apple/dptxep.c | 4 ++++ drivers/gpu/drm/apple/dptxep.h | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 9fb2d3181ff400..dd60d31e9733e6 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -256,6 +256,8 @@ EXPORT_SYMBOL_GPL(dcp_get_connector_type); static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) { + int ret = 0; + if (!dcp->phy) { dev_warn(dcp->dev, "dcp_dptx_connect: missing phy\n"); return -ENODEV; @@ -264,22 +266,27 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) mutex_lock(&dcp->hpd_mutex); if (!dcp->dptxport[port].enabled) { dev_warn(dcp->dev, "dcp_dptx_connect: dptx service for port %d not enabled\n", port); - mutex_unlock(&dcp->hpd_mutex); - return -ENODEV; + ret = -ENODEV; + goto out_unlock; } if (dcp->dptxport[port].connected) - goto ret; + goto out_unlock; + reinit_completion(&dcp->dptxport[port].linkcfg_completion); dcp->dptxport[port].atcphy = dcp->phy; dptxport_connect(dcp->dptxport[port].service, 0, dcp->dptx_phy, dcp->dptx_die); dptxport_request_display(dcp->dptxport[port].service); dcp->dptxport[port].connected = true; -ret: mutex_unlock(&dcp->hpd_mutex); - + wait_for_completion_timeout(&dcp->dptxport[port].linkcfg_completion, + msecs_to_jiffies(1000)); return 0; + +out_unlock: + mutex_unlock(&dcp->hpd_mutex); + return ret; } static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 328ff41aee7dd0..0a3ab4abd074c6 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -330,8 +330,10 @@ dptxport_call_will_change_link_config(struct apple_epic_service *service) static int dptxport_call_did_change_link_config(struct apple_epic_service *service) { + struct dptx_port *dptx = service->cookie; /* assume the link config did change and wait a little bit */ mdelay(10); + complete(&dptx->linkcfg_completion); return 0; } @@ -573,6 +575,8 @@ int dptxep_init(struct apple_dcp *dcp) init_completion(&dcp->dptxport[0].enable_completion); init_completion(&dcp->dptxport[1].enable_completion); + init_completion(&dcp->dptxport[0].linkcfg_completion); + init_completion(&dcp->dptxport[1].linkcfg_completion); dcp->dptxep = afk_init(dcp, DPTX_ENDPOINT, dptxep_ops); if (IS_ERR(dcp->dptxep)) diff --git a/drivers/gpu/drm/apple/dptxep.h b/drivers/gpu/drm/apple/dptxep.h index 481ebbc97bf38d..4a0770d43c954c 100644 --- a/drivers/gpu/drm/apple/dptxep.h +++ b/drivers/gpu/drm/apple/dptxep.h @@ -49,6 +49,7 @@ struct apple_epic_service; struct dptx_port { bool enabled, connected; struct completion enable_completion; + struct completion linkcfg_completion; u32 unit; struct apple_epic_service *service; union phy_configure_opts phy_ops; From a8e8f8c45d610b0d9b474d6737a993354bf1a088 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 21 Nov 2023 23:50:49 +0100 Subject: [PATCH 161/352] drm: apple: HPD: Only act on connect IRQs DCP notices the disconnects on its own and the parallel handling just results in confusion (both on DRM and developer side). Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index dd60d31e9733e6..7e4db565f4eda3 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -314,12 +314,16 @@ static irqreturn_t dcp_dp2hdmi_hpd(int irq, void *data) struct apple_dcp *dcp = data; bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); - dev_info(dcp->dev, "DP2HDMI HPD connected:%d\n", connected); + /* do nothing on disconnect and trust that dcp detects it itself. + * Parallel disconnect HPDs result drm disabling the CRTC even when it + * should not. + * The interrupt should be changed to rising but for now the disconnect + * IRQs might be helpful for debugging. + */ + dev_info(dcp->dev, "DP2HDMI HPD irq, connected:%d\n", connected); if (connected) dcp_dptx_connect(dcp, 0); - else - dcp_dptx_disconnect(dcp, 0); return IRQ_HANDLED; } From 6bf0134860e35a7ce729d50827787c0477f0e599 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 21 Nov 2023 23:57:07 +0100 Subject: [PATCH 162/352] drm: apple: iomfb: Improve hotplug related logging Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb.c | 3 ++- drivers/gpu/drm/apple/iomfb_template.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index d6af92637355df..0d0a82f544171d 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -236,7 +236,8 @@ void dcp_hotplug(struct work_struct *work) dev = connector->base.dev; dcp = platform_get_drvdata(connector->dcp); - dev_info(dcp->dev, "%s: connected: %d", __func__, connector->connected); + dev_info(dcp->dev, "%s() connected:%d valid_mode:%d\n", __func__, + connector->connected, dcp->valid_mode); /* * DCP defers link training until we set a display mode. But we set diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index a2b6556b62dac5..cae16951ba0961 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1014,6 +1014,9 @@ static void dcpep_cb_hotplug(struct apple_dcp *dcp, u64 *connected) if (dcp->main_display) return; + dev_info(dcp->dev, "cb_hotplug() connected:%llu, valid_mode:%d\n", + *connected, dcp->valid_mode); + /* Hotplug invalidates mode. DRM doesn't always handle this. */ if (!(*connected)) { dcp->valid_mode = false; From 245e745dff6b65cf9b1a6e6ba8026d57e51e81d1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 22 Nov 2023 09:41:29 +0100 Subject: [PATCH 163/352] drm: apple: Extract modeset crtc's atomic_flush() Triggering modesets from drm_connector_helper_funcs.atomic_check is more in line with DRM/KMS' design and allows returning errors from failed modesets. Ignore hotplug callbacks from DCP during modeset. DCP always does disconnected -> connected on (at least the initial) modeset. Shield drm helpers from this. This improves reliability with externel (dptx based) displays. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 2 + drivers/gpu/drm/apple/dcp-internal.h | 1 + drivers/gpu/drm/apple/dcp.h | 2 + drivers/gpu/drm/apple/iomfb.c | 41 ++++++++ drivers/gpu/drm/apple/iomfb_template.c | 137 ++++++++++++++----------- drivers/gpu/drm/apple/iomfb_template.h | 2 + 6 files changed, 124 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index d54a0d4712c64f..93c1c1038ae1e6 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -301,6 +301,8 @@ static const struct drm_connector_funcs apple_connector_funcs = { static const struct drm_connector_helper_funcs apple_connector_helper_funcs = { .get_modes = dcp_get_modes, .mode_valid = dcp_mode_valid, + .atomic_check = dcp_connector_atomic_check, + }; static const struct drm_crtc_helper_funcs apple_crtc_helper_funcs = { diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 4817412edf6407..ef6cddef40a44d 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -172,6 +172,7 @@ struct apple_dcp { u32 last_swap_id; /* Current display mode */ + bool during_modeset; bool valid_mode; struct dcp_set_digital_out_mode_req mode; diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index b502718a3df54c..4fa76418802b4b 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -57,6 +57,8 @@ void dcp_drm_crtc_vblank(struct apple_crtc *crtc); int dcp_get_modes(struct drm_connector *connector); int dcp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode); +int dcp_connector_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state); bool dcp_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 0d0a82f544171d..3ca3563ee250d6 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -422,6 +422,47 @@ int dcp_mode_valid(struct drm_connector *connector, } EXPORT_SYMBOL_GPL(dcp_mode_valid); +int dcp_connector_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + struct apple_connector *apple_connector = to_apple_connector(connector); + struct platform_device *pdev = apple_connector->dcp; + struct apple_dcp *dcp = platform_get_drvdata(pdev); + struct drm_crtc *crtc = &dcp->crtc->base; + struct drm_crtc_state *crtc_state; + int ret = -EIO; + bool modeset; + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + if (!crtc_state) + return 0; + + modeset = drm_atomic_crtc_needs_modeset(crtc_state) || !dcp->valid_mode; + + if (!modeset) + return 0; + + /* ignore no mode, poweroff is handled elsewhere */ + if (crtc_state->mode.hdisplay == 0 && crtc_state->mode.vdisplay == 0) + return 0; + + switch (dcp->fw_compat) { + case DCP_FIRMWARE_V_12_3: + ret = iomfb_modeset_v12_3(dcp, crtc_state); + break; + case DCP_FIRMWARE_V_13_5: + ret = iomfb_modeset_v13_3(dcp, crtc_state); + break; + default: + WARN_ONCE(true, "Unexpected firmware version: %u\n", + dcp->fw_compat); + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(dcp_connector_atomic_check); + bool dcp_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index cae16951ba0961..54a36f02be079b 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1014,6 +1014,13 @@ static void dcpep_cb_hotplug(struct apple_dcp *dcp, u64 *connected) if (dcp->main_display) return; + if (dcp->during_modeset) { + dev_info(dcp->dev, + "cb_hotplug() ignored during modeset connected:%llu\n", + *connected); + return; + } + dev_info(dcp->dev, "cb_hotplug() connected:%llu, valid_mode:%d\n", *connected, dcp->valid_mode); @@ -1178,6 +1185,75 @@ static void complete_set_digital_out_mode(struct apple_dcp *dcp, void *data, } } +int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, + struct drm_crtc_state *crtc_state) +{ + struct dcp_display_mode *mode; + struct dcp_wait_cookie *cookie; + int ret; + + mode = lookup_mode(dcp, &crtc_state->mode); + if (!mode) { + dev_err(dcp->dev, "no match for " DRM_MODE_FMT "\n", + DRM_MODE_ARG(&crtc_state->mode)); + return -EIO; + } + + dev_info(dcp->dev, + "set_digital_out_mode(color:%d timing:%d) " DRM_MODE_FMT "\n", + mode->color_mode_id, mode->timing_mode_id, + DRM_MODE_ARG(&crtc_state->mode)); + dcp->mode = (struct dcp_set_digital_out_mode_req){ + .color_mode_id = mode->color_mode_id, + .timing_mode_id = mode->timing_mode_id + }; + + cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); + if (!cookie) { + return -ENOMEM; + } + + init_completion(&cookie->done); + kref_init(&cookie->refcount); + /* increase refcount to ensure the receiver has a reference */ + kref_get(&cookie->refcount); + + dcp->during_modeset = true; + + dcp_set_digital_out_mode(dcp, false, &dcp->mode, + complete_set_digital_out_mode, cookie); + + /* + * The DCP firmware has an internal timeout of ~8 seconds for + * modesets. Add an extra 500ms to safe side that the modeset + * call has returned. + */ + dev_dbg(dcp->dev, "%s - wait for modeset", __func__); + ret = wait_for_completion_timeout(&cookie->done, + msecs_to_jiffies(8500)); + + kref_put(&cookie->refcount, release_wait_cookie); + dcp->during_modeset = false; + dev_info(dcp->dev, "set_digital_out_mode finished:%d\n", ret); + + if (ret == 0) { + dev_info(dcp->dev, "set_digital_out_mode timed out\n"); + return -EIO; + } else if (ret < 0) { + dev_info(dcp->dev, + "waiting on set_digital_out_mode failed:%d\n", ret); + return -EIO; + + } else if (ret > 0) { + dev_dbg(dcp->dev, + "set_digital_out_mode finished with %d to spare\n", + jiffies_to_msecs(ret)); + } + dcp->valid_mode = true; + + return 0; +} + void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_plane *plane; @@ -1186,13 +1262,10 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru struct DCP_FW_NAME(dcp_swap_submit_req) *req = &DCP_FW_UNION(dcp->swap); int plane_idx, l; int has_surface = 0; - bool modeset; dev_dbg(dcp->dev, "%s", __func__); crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - modeset = drm_atomic_crtc_needs_modeset(crtc_state) || !dcp->valid_mode; - /* Reset to defaults */ memset(req, 0, sizeof(*req)); for (l = 0; l < SWAP_SURFACES; l++) @@ -1305,64 +1378,6 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru l += 1; } - if (modeset) { - struct dcp_display_mode *mode; - struct dcp_wait_cookie *cookie; - int ret; - - mode = lookup_mode(dcp, &crtc_state->mode); - if (!mode) { - dev_warn(dcp->dev, "no match for " DRM_MODE_FMT, - DRM_MODE_ARG(&crtc_state->mode)); - schedule_work(&dcp->vblank_wq); - return; - } - - dev_info(dcp->dev, "set_digital_out_mode(color:%d timing:%d)", - mode->color_mode_id, mode->timing_mode_id); - dcp->mode = (struct dcp_set_digital_out_mode_req){ - .color_mode_id = mode->color_mode_id, - .timing_mode_id = mode->timing_mode_id - }; - - cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); - if (!cookie) { - schedule_work(&dcp->vblank_wq); - return; - } - - init_completion(&cookie->done); - kref_init(&cookie->refcount); - /* increase refcount to ensure the receiver has a reference */ - kref_get(&cookie->refcount); - - dcp_set_digital_out_mode(dcp, false, &dcp->mode, - complete_set_digital_out_mode, cookie); - - /* - * The DCP firmware has an internal timeout of ~8 seconds for - * modesets. Add an extra 500ms to safe side that the modeset - * call has returned. - */ - dev_dbg(dcp->dev, "%s - wait for modeset", __func__); - ret = wait_for_completion_timeout(&cookie->done, - msecs_to_jiffies(8500)); - - kref_put(&cookie->refcount, release_wait_cookie); - - if (ret == 0) { - dev_info(dcp->dev, "set_digital_out_mode timed out"); - schedule_work(&dcp->vblank_wq); - return; - } else if (ret > 0) { - dev_dbg(dcp->dev, - "set_digital_out_mode finished with %d to spare", - jiffies_to_msecs(ret)); - } - - dcp->valid_mode = true; - } - if (!has_surface && !crtc_state->color_mgmt_changed) { if (crtc_state->enable && crtc_state->active && !crtc_state->planes_changed) { diff --git a/drivers/gpu/drm/apple/iomfb_template.h b/drivers/gpu/drm/apple/iomfb_template.h index 4a4708229f081e..3ff0fadff65243 100644 --- a/drivers/gpu/drm/apple/iomfb_template.h +++ b/drivers/gpu/drm/apple/iomfb_template.h @@ -172,6 +172,8 @@ struct DCP_FW_NAME(dcp_map_reg_resp) { struct apple_dcp; +int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, + struct drm_crtc_state *crtc_state); void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, struct drm_atomic_state *state); void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp); void DCP_FW_NAME(iomfb_poweroff)(struct apple_dcp *dcp); From 88d9cd6dfd76028cdcb560bc070a20f0ee3f6704 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 22 Nov 2023 09:53:09 +0100 Subject: [PATCH 164/352] drm: apple: dptx: Log connect/disconnect calls Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 7e4db565f4eda3..68e94694e32a07 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -262,6 +262,7 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) dev_warn(dcp->dev, "dcp_dptx_connect: missing phy\n"); return -ENODEV; } + dev_info(dcp->dev, "%s(port=%d)\n", __func__, port); mutex_lock(&dcp->hpd_mutex); if (!dcp->dptxport[port].enabled) { @@ -292,6 +293,7 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) { struct apple_connector *connector = dcp->connector; + dev_info(dcp->dev, "%s(port=%d)\n", __func__, port); mutex_lock(&dcp->hpd_mutex); From 5cca0c5202c963104e9885bbcb67e057b67dce17 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 23 Nov 2023 22:58:16 +0100 Subject: [PATCH 165/352] drm: apple: Move modeset into drm_crtc's atomic_enable squash! drm: apple: Extract modeset crtc's atomic_flush() Fixes: 99d7bb861908 ("drm: apple: Extract modeset crtc's atomic_flush()") Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 5 +++-- drivers/gpu/drm/apple/dcp.h | 4 ++-- drivers/gpu/drm/apple/iomfb.c | 12 +++++------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 93c1c1038ae1e6..51f3e873a1e272 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -200,6 +200,9 @@ static void apple_crtc_atomic_enable(struct drm_crtc *crtc, dcp_poweron(apple_crtc->dcp); dev_dbg(&apple_crtc->dcp->dev, "%s finished", __func__); } + + if (crtc_state->active) + dcp_crtc_atomic_modeset(crtc, state); } static void apple_crtc_atomic_disable(struct drm_crtc *crtc, @@ -301,8 +304,6 @@ static const struct drm_connector_funcs apple_connector_funcs = { static const struct drm_connector_helper_funcs apple_connector_helper_funcs = { .get_modes = dcp_get_modes, .mode_valid = dcp_mode_valid, - .atomic_check = dcp_connector_atomic_check, - }; static const struct drm_crtc_helper_funcs apple_crtc_helper_funcs = { diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index 4fa76418802b4b..268bda8fa3bfc0 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -57,8 +57,8 @@ void dcp_drm_crtc_vblank(struct apple_crtc *crtc); int dcp_get_modes(struct drm_connector *connector); int dcp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode); -int dcp_connector_atomic_check(struct drm_connector *connector, - struct drm_atomic_state *state); +int dcp_crtc_atomic_modeset(struct drm_crtc *crtc, + struct drm_atomic_state *state); bool dcp_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 3ca3563ee250d6..f2a17c1b92c2c0 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -422,13 +422,11 @@ int dcp_mode_valid(struct drm_connector *connector, } EXPORT_SYMBOL_GPL(dcp_mode_valid); -int dcp_connector_atomic_check(struct drm_connector *connector, - struct drm_atomic_state *state) +int dcp_crtc_atomic_modeset(struct drm_crtc *crtc, + struct drm_atomic_state *state) { - struct apple_connector *apple_connector = to_apple_connector(connector); - struct platform_device *pdev = apple_connector->dcp; - struct apple_dcp *dcp = platform_get_drvdata(pdev); - struct drm_crtc *crtc = &dcp->crtc->base; + struct apple_crtc *apple_crtc = to_apple_crtc(crtc); + struct apple_dcp *dcp = platform_get_drvdata(apple_crtc->dcp); struct drm_crtc_state *crtc_state; int ret = -EIO; bool modeset; @@ -461,7 +459,7 @@ int dcp_connector_atomic_check(struct drm_connector *connector, return ret; } -EXPORT_SYMBOL_GPL(dcp_connector_atomic_check); +EXPORT_SYMBOL_GPL(dcp_crtc_atomic_modeset); bool dcp_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, From db021711d5107f25768604a656efc301e719b64e Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 23 Nov 2023 22:58:51 +0100 Subject: [PATCH 166/352] drm: apple: Fix DPTX hotplug handling - Do not trigger an hotplug event from disconnect. DCP/iomfb notices that itself. - Check HPD status before disconnecting DPTX in the crtc disable path. - disconnect on suspend to allow an orderly re-connect on resume Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 68e94694e32a07..ea131ce73d7011 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -292,16 +292,9 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) { - struct apple_connector *connector = dcp->connector; dev_info(dcp->dev, "%s(port=%d)\n", __func__, port); mutex_lock(&dcp->hpd_mutex); - - if (connector && connector->connected) { - dcp->valid_mode = false; - schedule_work(&connector->hotplug_wq); - } - if (dcp->dptxport[port].enabled && dcp->dptxport[port].connected) { dptxport_release_display(dcp->dptxport[port].service); dcp->dptxport[port].connected = false; @@ -478,9 +471,11 @@ void dcp_poweroff(struct platform_device *pdev) break; } - if (dcp->phy) - dcp_dptx_disconnect(dcp, 0); - + if (dcp->hdmi_hpd) { + bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); + if (!connected) + dcp_dptx_disconnect(dcp, 0); + } } EXPORT_SYMBOL(dcp_poweroff); @@ -1017,8 +1012,10 @@ static int dcp_platform_suspend(struct device *dev) { struct apple_dcp *dcp = dev_get_drvdata(dev); - if (dcp->hdmi_hpd_irq) + if (dcp->hdmi_hpd_irq) { disable_irq(dcp->hdmi_hpd_irq); + dcp_dptx_disconnect(dcp, 0); + } /* * Set the device as a wakeup device, which forces its power * domains to stay on. We need this as we do not support full From c6ca840d68e0c26d495e6417905ab5b888e9779d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 23 Nov 2023 23:04:47 +0100 Subject: [PATCH 167/352] drm: apple: iomfb: Use drm_kms_helper_connector_hotplug_event Avoid device wide hotplugs as DCP knowns the affected connector. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index f2a17c1b92c2c0..f5ae64ea5862c2 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -229,11 +229,9 @@ void dcp_ack(struct apple_dcp *dcp, enum dcp_context_id context) void dcp_hotplug(struct work_struct *work) { struct apple_connector *connector; - struct drm_device *dev; struct apple_dcp *dcp; connector = container_of(work, struct apple_connector, hotplug_wq); - dev = connector->base.dev; dcp = platform_get_drvdata(connector->dcp); dev_info(dcp->dev, "%s() connected:%d valid_mode:%d\n", __func__, @@ -244,13 +242,11 @@ void dcp_hotplug(struct work_struct *work) * display modes from atomic_flush, so userspace needs to trigger a * flush, or the CRTC gets no signal. */ - if (connector->base.state && !dcp->valid_mode && connector->connected) { - drm_connector_set_link_status_property( - &connector->base, DRM_MODE_LINK_STATUS_BAD); - } + if (connector->base.state && !dcp->valid_mode && connector->connected) + drm_connector_set_link_status_property(&connector->base, + DRM_MODE_LINK_STATUS_BAD); - if (dev && dev->registered) - drm_kms_helper_hotplug_event(dev); + drm_kms_helper_connector_hotplug_event(&connector->base); } EXPORT_SYMBOL_GPL(dcp_hotplug); From e88f33aa721944d2cf37d5e8201b03ef8e74eb14 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 26 Nov 2023 18:30:59 +0100 Subject: [PATCH 168/352] drm: apple: iomfb: Handle OOB ASYNC/CB context Only observed with dcp/dptx in linux after initialisation and reset in m1n1. On the initial startup dcp sends two D576 (hotPlug_notify_gated) presumendly due to state confusion due to the multiple dptx connections. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp-internal.h | 2 +- drivers/gpu/drm/apple/iomfb.c | 4 ++++ drivers/gpu/drm/apple/iomfb.h | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index ef6cddef40a44d..72b4ca86ed31bc 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -154,7 +154,7 @@ struct apple_dcp { struct dcp_mem_descriptor memdesc[DCP_MAX_MAPPINGS]; struct dcp_channel ch_cmd, ch_oobcmd; - struct dcp_channel ch_cb, ch_oobcb, ch_async; + struct dcp_channel ch_cb, ch_oobcb, ch_async, ch_oobasync; /* iomfb EP callback handlers */ const iomfb_cb_handler *cb_handlers; diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index f5ae64ea5862c2..bb4737fa0f2593 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -49,6 +49,8 @@ static int dcp_channel_offset(enum dcp_context_id id) switch (id) { case DCP_CONTEXT_ASYNC: return 0x40000; + case DCP_CONTEXT_OOBASYNC: + return 0x48000; case DCP_CONTEXT_CB: return 0x60000; case DCP_CONTEXT_OOBCB: @@ -118,6 +120,8 @@ static struct dcp_channel *dcp_get_channel(struct apple_dcp *dcp, return &dcp->ch_oobcmd; case DCP_CONTEXT_ASYNC: return &dcp->ch_async; + case DCP_CONTEXT_OOBASYNC: + return &dcp->ch_oobasync; default: return NULL; } diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index db48c3b0ca8cc2..ffd049e0cf32d1 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -28,6 +28,9 @@ enum dcp_context_id { /* Out-of-band command */ DCP_CONTEXT_OOBCMD = 6, + /* Out-of-band Asynchronous */ + DCP_CONTEXT_OOBASYNC = 7, + DCP_NUM_CONTEXTS }; From bcbc1756a0292748053d030a371fdefb2784b1ee Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 26 Nov 2023 18:57:07 +0100 Subject: [PATCH 169/352] drm: apple: iomfb: Extend hotplug/mode parsing logging Under unknown but slightly broken conditions dcp sends timing modes without linked color modes. Log a warning when this happens and log the number of valid modes before emitting HPD events. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb.c | 4 ++-- drivers/gpu/drm/apple/iomfb_template.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index bb4737fa0f2593..e3b9abebe5ed56 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -238,8 +238,8 @@ void dcp_hotplug(struct work_struct *work) connector = container_of(work, struct apple_connector, hotplug_wq); dcp = platform_get_drvdata(connector->dcp); - dev_info(dcp->dev, "%s() connected:%d valid_mode:%d\n", __func__, - connector->connected, dcp->valid_mode); + dev_info(dcp->dev, "%s() connected:%d valid_mode:%d nr_modes:%u\n", __func__, + connector->connected, dcp->valid_mode, dcp->nr_modes); /* * DCP defers link training until we set a display mode. But we set diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 54a36f02be079b..caf044cb785840 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -567,6 +567,8 @@ static bool dcpep_process_chunks(struct apple_dcp *dcp, dcp->nr_modes = 0; return false; } + if (dcp->nr_modes == 0) + dev_warn(dcp->dev, "TimingElements without valid modes!\n"); } else if (!strcmp(req->key, "DisplayAttributes")) { /* DisplayAttributes are empty for integrated displays, use * display dimensions read from the devicetree From fc3ec5c0df25175fe0ffcd0bc83af9468fb3371c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 27 Nov 2023 00:11:12 +0100 Subject: [PATCH 170/352] drm: apple: Adjust startup sequence and timing for dptx DPTX setup from an initialized connection and display with sleeping and reset dcp is unfortunately quite fragile. The display connection has to be stopped and reestablished. Goodbye flicker free boot. If the IOMFB endpoint is started too early dcp might provide incomplete timing modes which prevent modesets. On display standby a HPD is triggered should result in a fully initialized dcp. If not a display cable unplug and plug should help. MacOS doesn't handle this at all and just gives up. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 8 +++- drivers/gpu/drm/apple/dcp.c | 64 +++++++++++++++++-------------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 51f3e873a1e272..6dcebb5c62203f 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -445,7 +446,10 @@ static int apple_drm_init_dcp(struct device *dev) if (num_dcp < 1) return -ENODEV; - timeout = get_jiffies_64() + msecs_to_jiffies(500); + /* + * Starting DPTX might take some time. + */ + timeout = get_jiffies_64() + msecs_to_jiffies(3000); for (i = 0; i < num_dcp; ++i) { u64 jiffies = get_jiffies_64(); @@ -460,6 +464,8 @@ static int apple_drm_init_dcp(struct device *dev) if (ret) dev_warn(dev, "DCP[%d] not ready: %d\n", i, ret); } + /* HACK: Wait for dcp* to settle before a modeset */ + msleep(100); return 0; } diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index ea131ce73d7011..72d9571a86dc56 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -345,23 +345,40 @@ int dcp_start(struct platform_device *pdev) if (ret) dev_warn(dcp->dev, "Failed to start system endpoint: %d", ret); - if (dcp->phy) { - if (dcp->fw_compat >= DCP_FIRMWARE_V_13_5) { - ret = ibootep_init(dcp); - if (ret) - dev_warn(dcp->dev, - "Failed to start IBOOT endpoint: %d", - ret); - - ret = dptxep_init(dcp); - if (ret) - dev_warn(dcp->dev, - "Failed to start DPTX endpoint: %d", - ret); - } else - dev_warn(dcp->dev, - "OS firmware incompatible with dptxport EP\n"); - } + if (dcp->phy && dcp->fw_compat >= DCP_FIRMWARE_V_13_5) { + ret = ibootep_init(dcp); + if (ret) + dev_warn(dcp->dev, "Failed to start IBOOT endpoint: %d", + ret); + + ret = dptxep_init(dcp); + if (ret) + dev_warn(dcp->dev, "Failed to start DPTX endpoint: %d", + ret); + else if (dcp->dptxport[0].enabled) { + bool connected; + /* force disconnect on start - necessary if the display + * is already up from m1n1 + */ + dptxport_set_hpd(dcp->dptxport[0].service, false); + dptxport_release_display(dcp->dptxport[0].service); + usleep_range(10 * USEC_PER_MSEC, 25 * USEC_PER_MSEC); + + connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); + dev_info(dcp->dev, "%s: DP2HDMI HPD connected:%d\n", __func__, connected); + + // necessary on j473/j474 but not on j314c + if (connected) + dcp_dptx_connect(dcp, 0); + /* + * Long sleep necessary to ensure dcp delivers timing + * modes with matched color modes. + * 400ms was sufficient on j473 + */ + msleep(500); + } + } else if (dcp->phy) + dev_warn(dcp->dev, "OS firmware incompatible with dptxport EP\n"); ret = iomfb_start_rtkit(dcp); if (ret) @@ -373,17 +390,8 @@ EXPORT_SYMBOL(dcp_start); static int dcp_enable_dp2hdmi_hpd(struct apple_dcp *dcp) { - if (dcp->hdmi_hpd) { - bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); - dev_info(dcp->dev, "%s: DP2HDMI HPD connected:%d\n", __func__, connected); - - // necessary on j473/j474 but not on j314c - if (connected) - dcp_dptx_connect(dcp, 0); - - if (dcp->hdmi_hpd_irq) - enable_irq(dcp->hdmi_hpd_irq); - } + if (dcp->hdmi_hpd_irq) + enable_irq(dcp->hdmi_hpd_irq); return 0; } From 800e024c0e805598d3619e78058a5471449d246d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 28 Nov 2023 14:27:18 +0100 Subject: [PATCH 171/352] drm: apple: dcp: Fix resume with DPTX based display outputs Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 72d9571a86dc56..eb00f2724e3412 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -1041,6 +1041,13 @@ static int dcp_platform_resume(struct device *dev) if (dcp->hdmi_hpd_irq) enable_irq(dcp->hdmi_hpd_irq); + if (dcp->hdmi_hpd) { + bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); + dev_info(dcp->dev, "resume: HPD connected:%d\n", connected); + if (connected) + dcp_dptx_connect(dcp, 0); + } + return 0; } From 7107869a2619838c28c404f8442cf51a6da28be7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 2 Dec 2023 10:26:13 +0100 Subject: [PATCH 172/352] drm: apple: Be less noisy about teardown notifies without service Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/afk.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index fc90150bb7b5ab..a11e9f1f5be4d3 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -507,6 +507,12 @@ static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type, ep->endpoint, eshdr->category, channel); return; } + if (subtype == EPIC_SUBTYPE_TEARDOWN) { + dev_dbg(ep->dcp->dev, + "AFK[ep:%02x]: teardown without service on channel %d\n", + ep->endpoint, channel); + return; + } if (subtype != EPIC_SUBTYPE_ANNOUNCE) { dev_err(ep->dcp->dev, "AFK[ep:%02x]: expected announce but got 0x%x on channel %d\n", From 5d2013c75056f0b0e9c61e2fba45c4d81b0757d5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 3 Dec 2023 23:57:25 +0100 Subject: [PATCH 173/352] drm: apple: dptx: Wait for link config on connect Should make connect more reliable by avoiding hardcoded waits which are either to long or too short. In the second case the display can't be brought up since dcp fails to report any modes during start. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 22 ++++++++++++++-------- drivers/gpu/drm/apple/dptxep.c | 8 ++++++-- drivers/gpu/drm/apple/dptxep.h | 1 + 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index eb00f2724e3412..4ec85e41ca6ffd 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -254,6 +255,8 @@ int dcp_get_connector_type(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(dcp_get_connector_type); +#define DPTX_CONNECT_TIMEOUT msecs_to_jiffies(1000) + static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) { int ret = 0; @@ -281,8 +284,17 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) dcp->dptxport[port].connected = true; mutex_unlock(&dcp->hpd_mutex); - wait_for_completion_timeout(&dcp->dptxport[port].linkcfg_completion, - msecs_to_jiffies(1000)); + ret = wait_for_completion_timeout(&dcp->dptxport[port].linkcfg_completion, + DPTX_CONNECT_TIMEOUT); + if (ret < 0) + dev_warn(dcp->dev, "dcp_dptx_connect: port %d link complete failed:%d\n", + port, ret); + else + dev_dbg(dcp->dev, "dcp_dptx_connect: waited %d ms for link\n", + jiffies_to_msecs(DPTX_CONNECT_TIMEOUT - ret)); + + usleep_range(5, 10); + return 0; out_unlock: @@ -370,12 +382,6 @@ int dcp_start(struct platform_device *pdev) // necessary on j473/j474 but not on j314c if (connected) dcp_dptx_connect(dcp, 0); - /* - * Long sleep necessary to ensure dcp delivers timing - * modes with matched color modes. - * 400ms was sufficient on j473 - */ - msleep(500); } } else if (dcp->phy) dev_warn(dcp->dev, "OS firmware incompatible with dptxport EP\n"); diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 0a3ab4abd074c6..56b86966e807a7 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -294,9 +294,14 @@ static int dptxport_call_set_active_lane_count(struct apple_epic_service *servic dptx->phy_ops.dp.set_lanes = 0; } + dptx->lane_count = lane_count; + reply->retcode = cpu_to_le32(retcode); reply->lane_count = cpu_to_le64(lane_count); + if (dptx->lane_count > 0) + complete(&dptx->linkcfg_completion); + return ret; } @@ -330,10 +335,9 @@ dptxport_call_will_change_link_config(struct apple_epic_service *service) static int dptxport_call_did_change_link_config(struct apple_epic_service *service) { - struct dptx_port *dptx = service->cookie; /* assume the link config did change and wait a little bit */ mdelay(10); - complete(&dptx->linkcfg_completion); + return 0; } diff --git a/drivers/gpu/drm/apple/dptxep.h b/drivers/gpu/drm/apple/dptxep.h index 4a0770d43c954c..0bf2534054fd7b 100644 --- a/drivers/gpu/drm/apple/dptxep.h +++ b/drivers/gpu/drm/apple/dptxep.h @@ -55,6 +55,7 @@ struct dptx_port { union phy_configure_opts phy_ops; struct phy *atcphy; struct mux_control *mux; + u32 lane_count; u32 link_rate, pending_link_rate; u32 drive_settings[2]; }; From 17916eac75df131a5e86f5be1496c2c54e6a1ab1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 1 Dec 2023 23:41:53 +0100 Subject: [PATCH 174/352] drm: apple: Prefer RGB SDR modes DCP color mode scoring seems to prefer high bit depth color modes even when it it would require DSC. For example 12-bit 4k 60 Hz YCbCr 4:4:4 over a 600 MHz HDMI 2.0 link. Prefer 8-/10-bit RGB or YCbCr 4:4:4 modes if available. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 16 ++++++ drivers/gpu/drm/apple/parser.c | 79 ++++++++++++++++++-------- drivers/gpu/drm/apple/parser.h | 68 ++++++++++++++++++++++ 3 files changed, 139 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index caf044cb785840..6272a61dd32a5c 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1192,6 +1192,7 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, { struct dcp_display_mode *mode; struct dcp_wait_cookie *cookie; + struct dcp_color_mode *cmode = NULL; int ret; mode = lookup_mode(dcp, &crtc_state->mode); @@ -1205,6 +1206,21 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, "set_digital_out_mode(color:%d timing:%d) " DRM_MODE_FMT "\n", mode->color_mode_id, mode->timing_mode_id, DRM_MODE_ARG(&crtc_state->mode)); + if (mode->color_mode_id == mode->sdr_rgb.id) + cmode = &mode->sdr_rgb; + else if (mode->color_mode_id == mode->sdr_444.id) + cmode = &mode->sdr_444; + else if (mode->color_mode_id == mode->sdr.id) + cmode = &mode->sdr; + else if (mode->color_mode_id == mode->best.id) + cmode = &mode->best; + if (cmode) + dev_info(dcp->dev, + "set_digital_out_mode() color mode depth:%hhu format:%u " + "colorimetry:%u eotf:%u range:%u\n", cmode->depth, + cmode->format, cmode->colorimetry, cmode->eotf, + cmode->range); + dcp->mode = (struct dcp_set_digital_out_mode_req){ .color_mode_id = mode->color_mode_id, .timing_mode_id = mode->timing_mode_id diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index a6de7ded260970..33b6787e5aee3d 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -313,14 +313,43 @@ struct color_mode { s64 score; }; -static int parse_color_modes(struct dcp_parse_ctx *handle, s64 *preferred_id) +static int fill_color_mode(struct dcp_color_mode *color, + struct color_mode *cmode) +{ + if (color->score >= cmode->score) + return 0; + + if (cmode->colorimetry < 0 || cmode->colorimetry >= DCP_COLORIMETRY_COUNT) + return -EINVAL; + if (cmode->depth < 8 || cmode->depth > 12) + return -EINVAL; + if (cmode->dynamic_range < 0 || cmode->dynamic_range >= DCP_COLOR_YCBCR_RANGE_COUNT) + return -EINVAL; + if (cmode->eotf < 0 || cmode->eotf >= DCP_EOTF_COUNT) + return -EINVAL; + if (cmode->pixel_encoding < 0 || cmode->pixel_encoding >= DCP_COLOR_FORMAT_COUNT) + return -EINVAL; + + color->score = cmode->score; + color->id = cmode->id; + color->eotf = cmode->eotf; + color->format = cmode->pixel_encoding; + color->colorimetry = cmode->colorimetry; + color->range = cmode->dynamic_range; + color->depth = cmode->depth; + + return 0; +} + +static int parse_color_modes(struct dcp_parse_ctx *handle, + struct dcp_display_mode *out) { struct iterator outer_it; int ret = 0; - s64 best_score = -1, best_score_sdr = -1; - s64 best_id = -1, best_id_sdr = -1; - - *preferred_id = -1; + out->sdr_444.score = -1; + out->sdr_rgb.score = -1; + out->sdr.score = -1; + out->best.score = -1; dcp_parse_foreach_in_array(handle, outer_it) { struct iterator it; @@ -367,25 +396,18 @@ static int parse_color_modes(struct dcp_parse_ctx *handle, s64 *preferred_id) cmode.eotf, cmode.dynamic_range, cmode.pixel_encoding); - if (cmode.eotf == 0) { - if (cmode.score > best_score_sdr) { - best_score_sdr = cmode.score; - best_id_sdr = cmode.id; - } - } else { - if (cmode.score > best_score) { - best_score = cmode.score; - best_id = cmode.id; - } + if (cmode.eotf == DCP_EOTF_SDR_GAMMA) { + if (cmode.pixel_encoding == DCP_COLOR_FORMAT_RGB && + cmode.depth <= 10) + fill_color_mode(&out->sdr_rgb, &cmode); + else if (cmode.pixel_encoding == DCP_COLOR_FORMAT_YCBCR444 && + cmode.depth <= 10) + fill_color_mode(&out->sdr_444, &cmode); + fill_color_mode(&out->sdr, &cmode); } + fill_color_mode(&out->best, &cmode); } - /* prefer SDR color modes as long as HDR is not supported */ - if (best_score_sdr >= 0) - *preferred_id = best_id_sdr; - else if (best_score >= 0) - *preferred_id = best_id; - return 0; } @@ -427,7 +449,7 @@ static int parse_mode(struct dcp_parse_ctx *handle, else if (!strcmp(key, "VerticalAttributes")) ret = parse_dimension(it.handle, &vert); else if (!strcmp(key, "ColorModes")) - ret = parse_color_modes(it.handle, &best_color_mode); + ret = parse_color_modes(it.handle, out); else if (!strcmp(key, "ID")) ret = parse_int(it.handle, &id); else if (!strcmp(key, "IsVirtual")) @@ -445,8 +467,17 @@ static int parse_mode(struct dcp_parse_ctx *handle, return ret; } } - - trace_iomfb_parse_mode_success(id, &horiz, &vert, best_color_mode, is_virtual, *score); + if (out->sdr_rgb.score >= 0) + best_color_mode = out->sdr_rgb.id; + else if (out->sdr_444.score >= 0) + best_color_mode = out->sdr_444.id; + else if (out->sdr.score >= 0) + best_color_mode = out->sdr.id; + else if (out->best.score >= 0) + best_color_mode = out->best.id; + + trace_iomfb_parse_mode_success(id, &horiz, &vert, best_color_mode, + is_virtual, *score); /* * Reject modes without valid color mode. diff --git a/drivers/gpu/drm/apple/parser.h b/drivers/gpu/drm/apple/parser.h index 1072aa0f09009c..2ea77bcfee7d83 100644 --- a/drivers/gpu/drm/apple/parser.h +++ b/drivers/gpu/drm/apple/parser.h @@ -15,6 +15,70 @@ struct dcp_parse_ctx { u32 pos, len; }; +enum dcp_color_eotf { + DCP_EOTF_SDR_GAMMA = 0, // "SDR gamma" + DCP_EOTF_HDR_GAMMA = 1, // "HDR gamma" + DCP_EOTF_ST_2084 = 2, // "ST 2084 (PQ)" + DCP_EOTF_BT_2100 = 3, // "BT.2100 (HLG)" + DCP_EOTF_COUNT +}; + +enum dcp_color_format { + DCP_COLOR_FORMAT_RGB = 0, // "RGB" + DCP_COLOR_FORMAT_YCBCR420 = 1, // "YUV 4:2:0" + DCP_COLOR_FORMAT_YCBCR422 = 3, // "YUV 4:2:2" + DCP_COLOR_FORMAT_YCBCR444 = 2, // "YUV 4:4:4" + DCP_COLOR_FORMAT_DV_NATIVE = 4, // "DolbyVision (native)" + DCP_COLOR_FORMAT_DV_HDMI = 5, // "DolbyVision (HDMI)" + DCP_COLOR_FORMAT_YCBCR422_DP = 6, // "YCbCr 4:2:2 (DP tunnel)" + DCP_COLOR_FORMAT_YCBCR422_HDMI = 7, // "YCbCr 4:2:2 (HDMI tunnel)" + DCP_COLOR_FORMAT_DV_LL_YCBCR422 = 8, // "DolbyVision LL YCbCr 4:2:2" + DCP_COLOR_FORMAT_DV_LL_YCBCR422_DP = 9, // "DolbyVision LL YCbCr 4:2:2 (DP)" + DCP_COLOR_FORMAT_DV_LL_YCBCR422_HDMI = 10, // "DolbyVision LL YCbCr 4:2:2 (HDMI)" + DCP_COLOR_FORMAT_DV_LL_YCBCR444 = 11, // "DolbyVision LL YCbCr 4:4:4" + DCP_COLOR_FORMAT_DV_LL_RGB422 = 12, // "DolbyVision LL RGB 4:2:2" + DCP_COLOR_FORMAT_GRGB_BLUE_422 = 13, // "GRGB as YCbCr422 (Even line blue)" + DCP_COLOR_FORMAT_GRGB_RED_422 = 14, // "GRGB as YCbCr422 (Even line red)" + DCP_COLOR_FORMAT_COUNT +}; + +enum dcp_colorimetry { + DCP_COLORIMETRY_BT601 = 0, // "SMPTE 170M/BT.601" + DCP_COLORIMETRY_BT709 = 1, // "BT.701" + DCP_COLORIMETRY_XVYCC_601 = 2, // "xvYCC601" + DCP_COLORIMETRY_XVYCC_709 = 3, // "xvYCC709" + DCP_COLORIMETRY_SYCC_601 = 4, // "sYCC601" + DCP_COLORIMETRY_ADOBE_YCC_601 = 5, // "AdobeYCC601" + DCP_COLORIMETRY_BT2020_CYCC = 6, // "BT.2020 (c)" + DCP_COLORIMETRY_BT2020_YCC = 7, // "BT.2020 (nc)" + DCP_COLORIMETRY_VSVDB = 8, // "DolbyVision VSVDB" + DCP_COLORIMETRY_BT2020_RGB = 9, // "BT.2020 (RGB)" + DCP_COLORIMETRY_SRGB = 10, // "sRGB" + DCP_COLORIMETRY_SCRGB = 11, // "scRGB" + DCP_COLORIMETRY_SCRGB_FIXED = 12, // "scRGBfixed" + DCP_COLORIMETRY_ADOBE_RGB = 13, // "AdobeRGB" + DCP_COLORIMETRY_DCI_P3_RGB_D65 = 14, // "DCI-P3 (D65)" + DCP_COLORIMETRY_DCI_P3_RGB_THEATER = 15, // "DCI-P3 (Theater)" + DCP_COLORIMETRY_RGB = 16, // "Default RGB" + DCP_COLORIMETRY_COUNT +}; + +enum dcp_color_range { + DCP_COLOR_YCBCR_RANGE_FULL = 0, + DCP_COLOR_YCBCR_RANGE_LIMITED = 1, + DCP_COLOR_YCBCR_RANGE_COUNT +}; + +struct dcp_color_mode { + s64 score; + u32 id; + enum dcp_color_eotf eotf; + enum dcp_color_format format; + enum dcp_colorimetry colorimetry; + enum dcp_color_range range; + u8 depth; +}; + /* * Represents a single display mode. These mode objects are populated at * runtime based on the TimingElements dictionary sent by the DCP. @@ -23,6 +87,10 @@ struct dcp_display_mode { struct drm_display_mode mode; u32 color_mode_id; u32 timing_mode_id; + struct dcp_color_mode sdr_rgb; + struct dcp_color_mode sdr_444; + struct dcp_color_mode sdr; + struct dcp_color_mode best; }; struct dimension { From 71a4ebb6b735e87d9f8df2690a463a33c89e9ffc Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 4 Dec 2023 23:27:29 +0100 Subject: [PATCH 175/352] drm: apple: iomfb: Always parse DisplayAttributes Fixes missing physical display dimensions for HDMI display on Macbook Pros. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 6272a61dd32a5c..641abfb2bab30b 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -570,17 +570,12 @@ static bool dcpep_process_chunks(struct apple_dcp *dcp, if (dcp->nr_modes == 0) dev_warn(dcp->dev, "TimingElements without valid modes!\n"); } else if (!strcmp(req->key, "DisplayAttributes")) { - /* DisplayAttributes are empty for integrated displays, use - * display dimensions read from the devicetree - */ - if (dcp->main_display) { - ret = parse_display_attributes(&ctx, &dcp->width_mm, - &dcp->height_mm); + ret = parse_display_attributes(&ctx, &dcp->width_mm, + &dcp->height_mm); - if (ret) { - dev_warn(dcp->dev, "failed to parse display attribs\n"); - return false; - } + if (ret) { + dev_warn(dcp->dev, "failed to parse display attribs\n"); + return false; } dcp_set_dimensions(dcp); From 34a8d8ef1b008f5ef481a7637b53a964abac383a Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 10 Dec 2023 13:01:22 +0100 Subject: [PATCH 176/352] drm: apple: parser: constify parser data Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/parser.c | 40 +++++++++++++++++----------------- drivers/gpu/drm/apple/parser.h | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 33b6787e5aee3d..6e9cea6a8a2686 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -30,9 +30,9 @@ struct dcp_parse_tag { bool last : 1; } __packed; -static void *parse_bytes(struct dcp_parse_ctx *ctx, size_t count) +static const void *parse_bytes(struct dcp_parse_ctx *ctx, size_t count) { - void *ptr = ctx->blob + ctx->pos; + const void *ptr = ctx->blob + ctx->pos; if (ctx->pos + count > ctx->len) return ERR_PTR(-EINVAL); @@ -41,14 +41,14 @@ static void *parse_bytes(struct dcp_parse_ctx *ctx, size_t count) return ptr; } -static u32 *parse_u32(struct dcp_parse_ctx *ctx) +static const u32 *parse_u32(struct dcp_parse_ctx *ctx) { return parse_bytes(ctx, sizeof(u32)); } -static struct dcp_parse_tag *parse_tag(struct dcp_parse_ctx *ctx) +static const struct dcp_parse_tag *parse_tag(struct dcp_parse_ctx *ctx) { - struct dcp_parse_tag *tag; + const struct dcp_parse_tag *tag; /* Align to 32-bits */ ctx->pos = round_up(ctx->pos, 4); @@ -64,10 +64,10 @@ static struct dcp_parse_tag *parse_tag(struct dcp_parse_ctx *ctx) return tag; } -static struct dcp_parse_tag *parse_tag_of_type(struct dcp_parse_ctx *ctx, +static const struct dcp_parse_tag *parse_tag_of_type(struct dcp_parse_ctx *ctx, enum dcp_parse_type type) { - struct dcp_parse_tag *tag = parse_tag(ctx); + const struct dcp_parse_tag *tag = parse_tag(ctx); if (IS_ERR(tag)) return tag; @@ -80,7 +80,7 @@ static struct dcp_parse_tag *parse_tag_of_type(struct dcp_parse_ctx *ctx, static int skip(struct dcp_parse_ctx *handle) { - struct dcp_parse_tag *tag = parse_tag(handle); + const struct dcp_parse_tag *tag = parse_tag(handle); int ret = 0; int i; @@ -132,7 +132,7 @@ static int skip_pair(struct dcp_parse_ctx *handle) static bool consume_string(struct dcp_parse_ctx *ctx, const char *specimen) { - struct dcp_parse_tag *tag; + const struct dcp_parse_tag *tag; const char *key; ctx->pos = round_up(ctx->pos, 4); @@ -155,7 +155,7 @@ static bool consume_string(struct dcp_parse_ctx *ctx, const char *specimen) /* Caller must free the result */ static char *parse_string(struct dcp_parse_ctx *handle) { - struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_STRING); + const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_STRING); const char *in; char *out; @@ -175,8 +175,8 @@ static char *parse_string(struct dcp_parse_ctx *handle) static int parse_int(struct dcp_parse_ctx *handle, s64 *value) { - void *tag = parse_tag_of_type(handle, DCP_TYPE_INT64); - s64 *in; + const void *tag = parse_tag_of_type(handle, DCP_TYPE_INT64); + const s64 *in; if (IS_ERR(tag)) return PTR_ERR(tag); @@ -192,7 +192,7 @@ static int parse_int(struct dcp_parse_ctx *handle, s64 *value) static int parse_bool(struct dcp_parse_ctx *handle, bool *b) { - struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BOOL); + const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BOOL); if (IS_ERR(tag)) return PTR_ERR(tag); @@ -201,10 +201,10 @@ static int parse_bool(struct dcp_parse_ctx *handle, bool *b) return 0; } -static int parse_blob(struct dcp_parse_ctx *handle, size_t size, u8 **blob) +static int parse_blob(struct dcp_parse_ctx *handle, size_t size, u8 const **blob) { - struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BLOB); - u8 *out; + const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BLOB); + const u8 *out; if (IS_ERR(tag)) return PTR_ERR(tag); @@ -229,7 +229,7 @@ struct iterator { static int iterator_begin(struct dcp_parse_ctx *handle, struct iterator *it, bool dict) { - struct dcp_parse_tag *tag; + const struct dcp_parse_tag *tag; enum dcp_parse_type type = dict ? DCP_TYPE_DICTIONARY : DCP_TYPE_ARRAY; *it = (struct iterator) { @@ -250,9 +250,9 @@ static int iterator_begin(struct dcp_parse_ctx *handle, struct iterator *it, #define dcp_parse_foreach_in_dict(handle, it) \ for (iterator_begin(handle, &it, true); it.idx < it.len; ++it.idx) -int parse(void *blob, size_t size, struct dcp_parse_ctx *ctx) +int parse(const void *blob, size_t size, struct dcp_parse_ctx *ctx) { - u32 *header; + const u32 *header; *ctx = (struct dcp_parse_ctx) { .blob = blob, @@ -913,7 +913,7 @@ static int parse_mode_in_avep_element(struct dcp_parse_ctx *handle, return ret; } } else if (consume_string(it.handle, "ElementData")) { - u8 *blob; + const u8 *blob; ret = parse_blob(it.handle, sizeof(*cookie), &blob); if (ret) diff --git a/drivers/gpu/drm/apple/parser.h b/drivers/gpu/drm/apple/parser.h index 2ea77bcfee7d83..6e101f77cbb650 100644 --- a/drivers/gpu/drm/apple/parser.h +++ b/drivers/gpu/drm/apple/parser.h @@ -11,7 +11,7 @@ struct apple_dcp; struct dcp_parse_ctx { struct apple_dcp *dcp; - void *blob; + const void *blob; u32 pos, len; }; @@ -98,7 +98,7 @@ struct dimension { s64 precise_sync_rate; }; -int parse(void *blob, size_t size, struct dcp_parse_ctx *ctx); +int parse(const void *blob, size_t size, struct dcp_parse_ctx *ctx); struct dcp_display_mode *enumerate_modes(struct dcp_parse_ctx *handle, unsigned int *count, int width_mm, int height_mm, unsigned notch_height); From d05dc845aeb2e0d45f4528f7ff3b7a16b3611eba Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 10 Dec 2023 13:27:12 +0100 Subject: [PATCH 177/352] drm: apple: epic: Pass full notfiy/report payload to handler The payload is not necessarily epic_std_service_ap_call. The powerlog service on the system endpoint passes serialized dictionaries as payload. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/afk.c | 18 +++--------------- drivers/gpu/drm/apple/afk.h | 4 +++- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index a11e9f1f5be4d3..52a5bf5f8a6479 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -447,21 +447,9 @@ static void afk_recv_handle_std_service(struct apple_dcp_afkep *ep, u32 channel, } if (type == EPIC_TYPE_NOTIFY && eshdr->category == EPIC_CAT_REPORT) { - struct epic_std_service_ap_call *call = payload; - size_t call_size; - - if (payload_size < sizeof(*call)) - return; - - call_size = le32_to_cpu(call->len); - if (payload_size < sizeof(*call) + call_size) - return; - - if (!service->ops->report) - return; - - service->ops->report(service, le32_to_cpu(call->type), - payload + sizeof(*call), call_size); + if (service->ops->report) + service->ops->report(service, le16_to_cpu(eshdr->type), + payload, payload_size); return; } diff --git a/drivers/gpu/drm/apple/afk.h b/drivers/gpu/drm/apple/afk.h index 1fdb4100352b25..737288b1346b28 100644 --- a/drivers/gpu/drm/apple/afk.h +++ b/drivers/gpu/drm/apple/afk.h @@ -49,6 +49,8 @@ struct apple_epic_service { void *cookie; }; +enum epic_subtype; + struct apple_epic_service_ops { const char name[32]; @@ -57,7 +59,7 @@ struct apple_epic_service_ops { int (*call)(struct apple_epic_service *service, u32 idx, const void *data, size_t data_size, void *reply, size_t reply_size); - int (*report)(struct apple_epic_service *service, u32 idx, + int (*report)(struct apple_epic_service *service, enum epic_subtype type, const void *data, size_t data_size); void (*teardown)(struct apple_epic_service *service); }; From 373da0bbc3689f8626225bb56ddd0670d09109fb Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 10 Dec 2023 13:40:14 +0100 Subject: [PATCH 178/352] drm: apple: epic: systemep: Parse "mNits" log events The 13.5 firmware has stopped updating the NITS property on backlight brightness changes. Parse system log events instead which report backlight's brightness in millinits. Fixes the backlight device's "actual_brightness" property used by the systemd backlight service to save and restore brightness. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/parser.c | 48 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/apple/parser.h | 9 ++++++ drivers/gpu/drm/apple/systemep.c | 37 ++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 6e9cea6a8a2686..65bf0ad60daa5a 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -984,3 +984,51 @@ int parse_sound_mode(struct dcp_parse_ctx *handle, return 0; } EXPORT_SYMBOL_GPL(parse_sound_mode); + +int parse_system_log_mnits(struct dcp_parse_ctx *handle, struct dcp_system_ev_mnits *entry) +{ + struct iterator it; + int ret; + s64 mnits = -1; + s64 idac = -1; + s64 timestamp = -1; + bool type_match = false; + + dcp_parse_foreach_in_dict(handle, it) { + char *key = parse_string(it.handle); + if (IS_ERR(key)) { + ret = PTR_ERR(key); + } else if (!strcmp(key, "mNits")) { + ret = parse_int(it.handle, &mnits); + } else if (!strcmp(key, "iDAC")) { + ret = parse_int(it.handle, &idac); + } else if (!strcmp(key, "logEvent")) { + const char * value = parse_string(it.handle); + if (!IS_ERR_OR_NULL(value)) { + type_match = strcmp(value, "Display (Event Forward)") == 0; + kfree(value); + } + } else if (!strcmp(key, "timestamp")) { + ret = parse_int(it.handle, ×tamp); + } else { + skip(it.handle); + } + + if (!IS_ERR_OR_NULL(key)) + kfree(key); + + if (ret) { + pr_err("dcp parser: failed to parse mNits sys event\n"); + return ret; + } + } + + if (!type_match || mnits < 0 || idac < 0 || timestamp < 0) + return -EINVAL; + + entry->millinits = mnits; + entry->idac = idac; + entry->timestamp = timestamp; + + return 0; +} diff --git a/drivers/gpu/drm/apple/parser.h b/drivers/gpu/drm/apple/parser.h index 6e101f77cbb650..11857f0aa6afa9 100644 --- a/drivers/gpu/drm/apple/parser.h +++ b/drivers/gpu/drm/apple/parser.h @@ -126,4 +126,13 @@ int parse_sound_mode(struct dcp_parse_ctx *handle, struct snd_pcm_chmap_elem *chmap, struct dcp_sound_cookie *cookie); +struct dcp_system_ev_mnits { + u32 timestamp; + u32 millinits; + u32 idac; +}; + +int parse_system_log_mnits(struct dcp_parse_ctx *handle, + struct dcp_system_ev_mnits *entry); + #endif diff --git a/drivers/gpu/drm/apple/systemep.c b/drivers/gpu/drm/apple/systemep.c index 5383a83f1e6c28..9fe7a0ce495aab 100644 --- a/drivers/gpu/drm/apple/systemep.c +++ b/drivers/gpu/drm/apple/systemep.c @@ -5,6 +5,7 @@ #include "afk.h" #include "dcp.h" +#include "parser.h" static bool enable_verbose_logging; module_param(enable_verbose_logging, bool, 0644); @@ -66,6 +67,41 @@ static void powerlog_init(struct apple_epic_service *service, const char *name, { } +static int powerlog_report(struct apple_epic_service *service, enum epic_subtype type, + const void *data, size_t data_size) +{ + struct dcp_system_ev_mnits mnits; + struct dcp_parse_ctx parse_ctx; + struct apple_dcp *dcp = service->ep->dcp; + int ret; + + dev_dbg(dcp->dev, "systemep[ch:%u]: report type:%02x len:%zu\n", + service->channel, type, data_size); + + if (type != EPIC_SUBTYPE_STD_SERVICE) + return 0; + + ret = parse(data, data_size, &parse_ctx); + if (ret) { + dev_warn(service->ep->dcp->dev, "systemep: failed to parse report: %d\n", ret); + return ret; + } + + ret = parse_system_log_mnits(&parse_ctx, &mnits); + if (ret) { + /* ignore parse errors in the case dcp sends unknown log events */ + dev_dbg(dcp->dev, "systemep: failed to parse mNits event: %d\n", ret); + return 0; + } + + dev_dbg(dcp->dev, "systemep: mNits event: Nits: %u.%03u, iDAC: %u\n", + mnits.millinits / 1000, mnits.millinits % 1000, mnits.idac); + + dcp->brightness.nits = mnits.millinits / 1000; + + return 0; +} + static const struct apple_epic_service_ops systemep_ops[] = { { .name = "system", @@ -74,6 +110,7 @@ static const struct apple_epic_service_ops systemep_ops[] = { { .name = "powerlog-service", .init = powerlog_init, + .report = powerlog_report, }, {} }; From 3fbe0ab5fc37f7835fa618310b822d0f1291b6a9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 Jan 2024 11:44:10 +0100 Subject: [PATCH 179/352] drm: apple: mark local functions static With linux-6.8, the kernel warns about functions that have no extern declaration, so mark both of these static. Fixes: 2d782b0d007d ("gpu: drm: apple: Add sound mode parsing") Signed-off-by: Arnd Bergmann --- drivers/gpu/drm/apple/parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 65bf0ad60daa5a..0aab3ecde8e12e 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -681,7 +681,7 @@ int parse_epic_service_init(struct dcp_parse_ctx *handle, const char **name, return ret; } -int parse_sample_rate_bit(struct dcp_parse_ctx *handle, unsigned int *ratebit) +static int parse_sample_rate_bit(struct dcp_parse_ctx *handle, unsigned int *ratebit) { s64 rate; int ret = parse_int(handle, &rate); @@ -702,7 +702,7 @@ int parse_sample_rate_bit(struct dcp_parse_ctx *handle, unsigned int *ratebit) return 0; } -int parse_sample_fmtbit(struct dcp_parse_ctx *handle, u64 *fmtbit) +static int parse_sample_fmtbit(struct dcp_parse_ctx *handle, u64 *fmtbit) { s64 sample_size; int ret = parse_int(handle, &sample_size); From ca6a175a935a80d96ae2367a9048986dd71a418d Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Thu, 11 Jan 2024 11:39:10 +0100 Subject: [PATCH 180/352] drm/apple: Add missing RTKit Kconfig dependency Signed-off-by: Alyssa Ross --- drivers/gpu/drm/apple/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/apple/Kconfig b/drivers/gpu/drm/apple/Kconfig index b28b84cef961b1..e2d424b983314a 100644 --- a/drivers/gpu/drm/apple/Kconfig +++ b/drivers/gpu/drm/apple/Kconfig @@ -3,6 +3,7 @@ config DRM_APPLE tristate "DRM Support for Apple display controllers" depends on DRM && OF && ARM64 depends on ARCH_APPLE || COMPILE_TEST + depends on APPLE_RTKIT depends on OF_ADDRESS select DRM_CLIENT_SELECTION select DRM_KMS_HELPER From 963cec0267fe9ea4ce822ea25800cc0dbf969c59 Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Mon, 22 Jan 2024 18:54:31 +1100 Subject: [PATCH 181/352] drm/apple: spelling fixes Signed-off-by: Jonathan Gray --- drivers/gpu/drm/apple/apple_drv.c | 2 +- drivers/gpu/drm/apple/dcp-internal.h | 2 +- drivers/gpu/drm/apple/dcp.c | 4 ++-- drivers/gpu/drm/apple/iomfb.c | 2 +- drivers/gpu/drm/apple/iomfb_template.c | 2 +- drivers/gpu/drm/apple/iomfb_v13_3.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 6dcebb5c62203f..3483a30f6f28fc 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -459,7 +459,7 @@ static int apple_drm_init_dcp(struct device *dev) ret = dcp_wait_ready(dcp[i], wait); /* There is nothing we can do if a dcp/dcpext does not boot * (successfully). Ignoring it should not do any harm now. - * Needs to reevaluated whenn adding dcpext support. + * Needs to reevaluated when adding dcpext support. */ if (ret) dev_warn(dev, "DCP[%d] not ready: %d\n", i, ret); diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 72b4ca86ed31bc..b6fc500e745324 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -95,7 +95,7 @@ struct dcp_panel { int width_mm; /// panel height in millimeter int height_mm; - /// panel has a mini-LED backllight + /// panel has a mini-LED backlight bool has_mini_led; }; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 4ec85e41ca6ffd..81235f23198041 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -808,7 +808,7 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) if (dcp->notch_height > 0) dev_info(dev, "Detected display with notch of %u pixel\n", dcp->notch_height); - /* intialize brightness scale to a sensible default to avoid divide by 0*/ + /* initialize brightness scale to a sensible default to avoid divide by 0*/ dcp->brightness.scale = 65536; panel_np = of_get_compatible_child(dev->of_node, "apple,panel-mini-led"); if (panel_np) @@ -877,7 +877,7 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) dcp->rtk = devm_apple_rtkit_init(dev, dcp, "mbox", 0, &rtkit_ops); if (IS_ERR(dcp->rtk)) return dev_err_probe(dev, PTR_ERR(dcp->rtk), - "Failed to intialize RTKit"); + "Failed to initialize RTKit"); ret = apple_rtkit_wake(dcp->rtk); if (ret) diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index e3b9abebe5ed56..1d5e0bf4b197f9 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -274,7 +274,7 @@ static void dcpep_handle_cb(struct apple_dcp *dcp, enum dcp_context_id context, out = in + hdr->in_len; // TODO: verify that in_len and out_len match our prototypes - // for now just clear the out data to have at least consistant results + // for now just clear the out data to have at least consistent results if (hdr->out_len) memset(out, 0, hdr->out_len); diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 641abfb2bab30b..86ff2f1d76e49b 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -326,7 +326,7 @@ static void dcpep_cb_unmap_piodma(struct apple_dcp *dcp, /* * Allocate an IOVA contiguous buffer mapped to the DCP. The buffer need not be - * physically contigiuous, however we should save the sgtable in case the + * physically contiguous, however we should save the sgtable in case the * buffer needs to be later mapped for PIODMA. */ static struct dcp_allocate_buffer_resp diff --git a/drivers/gpu/drm/apple/iomfb_v13_3.c b/drivers/gpu/drm/apple/iomfb_v13_3.c index 1ee29112be4543..115490fd9cc6e3 100644 --- a/drivers/gpu/drm/apple/iomfb_v13_3.c +++ b/drivers/gpu/drm/apple/iomfb_v13_3.c @@ -53,7 +53,7 @@ static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { [110] = trampoline_true, /* create_pmu_service */ [111] = trampoline_true, /* create_iomfb_service */ [112] = trampoline_create_backlight_service, - [113] = trampoline_true, /* create_nvram_servce? */ + [113] = trampoline_true, /* create_nvram_service? */ [114] = trampoline_get_tiling_state, [115] = trampoline_false, /* set_tiling_state */ [120] = dcpep_cb_boot_1, From 68912a70b6f77183cb1a0ce56eed4eee8da8cae0 Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Thu, 28 Dec 2023 11:41:55 +0100 Subject: [PATCH 182/352] drm: apple: backlight: force backlight update after resume If the DCP firmware indicates that it didn't restore the brightness, schedule an update. Wait for 1 frame duration and check if the brightness update has been taken care of by a swap that happened in the meantime. Fixes restoring the brightness after resume when running on a dumb framebuffer where swaps may not happen for a very long time. Signed-off-by: Mark Kettenis --- drivers/gpu/drm/apple/dcp-internal.h | 3 +++ drivers/gpu/drm/apple/dcp.c | 10 +++++++++ drivers/gpu/drm/apple/dcp_backlight.c | 31 +++++++++++++++----------- drivers/gpu/drm/apple/iomfb_template.c | 1 + 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index b6fc500e745324..3e78435edbf529 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -212,6 +212,8 @@ struct apple_dcp { /* Workqueue for updating the initial initial brightness */ struct work_struct bl_register_wq; struct mutex bl_register_mutex; + /* Workqueue for updating the brightness */ + struct work_struct bl_update_wq; /* integrated panel if present */ struct dcp_panel panel; @@ -241,6 +243,7 @@ struct apple_dcp { }; int dcp_backlight_register(struct apple_dcp *dcp); +int dcp_backlight_update(struct apple_dcp *dcp); bool dcp_has_panel(struct apple_dcp *dcp); #define DCP_AUDIO_MAX_CHANS 15 diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 81235f23198041..958b9620f92e5d 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -515,6 +515,15 @@ static void dcp_work_register_backlight(struct work_struct *work) mutex_unlock(&dcp->bl_register_mutex); } +static void dcp_work_update_backlight(struct work_struct *work) +{ + struct apple_dcp *dcp; + + dcp = container_of(work, struct apple_dcp, bl_update_wq); + + dcp_backlight_update(dcp); +} + static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp) { int ret; @@ -835,6 +844,7 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) dcp->connector_type = DRM_MODE_CONNECTOR_eDP; INIT_WORK(&dcp->bl_register_wq, dcp_work_register_backlight); mutex_init(&dcp->bl_register_mutex); + INIT_WORK(&dcp->bl_update_wq, dcp_work_update_backlight); } else if (of_property_match_string(dev->of_node, "apple,connector-type", "HDMI-A") >= 0) dcp->connector_type = DRM_MODE_CONNECTOR_HDMIA; else if (of_property_match_string(dev->of_node, "apple,connector-type", "DP") >= 0) diff --git a/drivers/gpu/drm/apple/dcp_backlight.c b/drivers/gpu/drm/apple/dcp_backlight.c index 0eeb3d6d92c5a2..dfc78f3ce37b0d 100644 --- a/drivers/gpu/drm/apple/dcp_backlight.c +++ b/drivers/gpu/drm/apple/dcp_backlight.c @@ -172,20 +172,8 @@ static int drm_crtc_set_brightness(struct apple_dcp *dcp) return ret; } -static int dcp_set_brightness(struct backlight_device *bd) +int dcp_backlight_update(struct apple_dcp *dcp) { - int ret = 0; - struct apple_dcp *dcp = bl_get_data(bd); - struct drm_modeset_acquire_ctx ctx; - int brightness = backlight_get_brightness(bd); - - DRM_MODESET_LOCK_ALL_BEGIN(dcp->crtc->base.dev, ctx, 0, ret); - - dcp->brightness.dac = calculate_dac(dcp, brightness); - dcp->brightness.update = true; - - DRM_MODESET_LOCK_ALL_END(dcp->crtc->base.dev, ctx, ret); - /* * Do not actively try to change brightness if no mode is set. * TODO: should this be reflected the in backlight's power property? @@ -202,6 +190,23 @@ static int dcp_set_brightness(struct backlight_device *bd) return drm_crtc_set_brightness(dcp); } +static int dcp_set_brightness(struct backlight_device *bd) +{ + int ret = 0; + struct apple_dcp *dcp = bl_get_data(bd); + struct drm_modeset_acquire_ctx ctx; + int brightness = backlight_get_brightness(bd); + + DRM_MODESET_LOCK_ALL_BEGIN(dcp->crtc->base.dev, ctx, 0, ret); + + dcp->brightness.dac = calculate_dac(dcp, brightness); + dcp->brightness.update = true; + + DRM_MODESET_LOCK_ALL_END(dcp->crtc->base.dev, ctx, ret); + + return dcp_backlight_update(dcp); +} + static const struct backlight_ops dcp_backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = dcp_get_brightness, diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 86ff2f1d76e49b..d61956a6cc85b9 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -497,6 +497,7 @@ static void iomfbep_cb_enable_backlight_message_ap_gated(struct apple_dcp *dcp, * syslog: "[BrightnessLCD.cpp:743][AFK]nitsToDBV: iDAC out of range" */ dcp->brightness.update = true; + schedule_work(&dcp->bl_update_wq); } /* Chunked data transfer for property dictionaries */ From d630b078df42469031dad85ed8f1fa6dd575577c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 22 Jan 2024 22:24:11 +0100 Subject: [PATCH 183/352] drm: apple: Fix/remove log messages Add missing training '\n' and remove leftover dev_dbg() statements. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/afk.c | 8 +++--- drivers/gpu/drm/apple/apple_drv.c | 4 --- drivers/gpu/drm/apple/dcp.c | 30 +++++++++---------- drivers/gpu/drm/apple/dcp_backlight.c | 2 +- drivers/gpu/drm/apple/iomfb.c | 4 +-- drivers/gpu/drm/apple/iomfb_template.c | 40 ++++++++------------------ 6 files changed, 34 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index 52a5bf5f8a6479..b3a5cf74e817e9 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -138,7 +138,7 @@ static void afk_init_rxtx(struct apple_dcp_afkep *ep, u64 message, u32 bufsz, end; if (tag != ep->bfr_tag) { - dev_err(ep->dcp->dev, "AFK[ep:%02x]: expected tag 0x%x but got 0x%x", + dev_err(ep->dcp->dev, "AFK[ep:%02x]: expected tag 0x%x but got 0x%x\n", ep->endpoint, ep->bfr_tag, tag); return; } @@ -151,7 +151,7 @@ static void afk_init_rxtx(struct apple_dcp_afkep *ep, u64 message, if (base >= ep->bfr_size) { dev_err(ep->dcp->dev, - "AFK[ep:%02x]: requested base 0x%x >= max size 0x%lx", + "AFK[ep:%02x]: requested base 0x%x >= max size 0x%lx\n", ep->endpoint, base, ep->bfr_size); return; } @@ -159,7 +159,7 @@ static void afk_init_rxtx(struct apple_dcp_afkep *ep, u64 message, end = base + size; if (end > ep->bfr_size) { dev_err(ep->dcp->dev, - "AFK[ep:%02x]: requested end 0x%x > max size 0x%lx", + "AFK[ep:%02x]: requested end 0x%x > max size 0x%lx\n", ep->endpoint, end, ep->bfr_size); return; } @@ -168,7 +168,7 @@ static void afk_init_rxtx(struct apple_dcp_afkep *ep, u64 message, bufsz = le32_to_cpu(bfr->hdr->bufsz); if (bufsz + sizeof(*bfr->hdr) != size) { dev_err(ep->dcp->dev, - "AFK[ep:%02x]: ring buffer size 0x%x != expected 0x%lx", + "AFK[ep:%02x]: ring buffer size 0x%x != expected 0x%lx\n", ep->endpoint, bufsz, sizeof(*bfr->hdr)); return; } diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 3483a30f6f28fc..900e509faa2f63 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -197,9 +197,7 @@ static void apple_crtc_atomic_enable(struct drm_crtc *crtc, if (crtc_state->active_changed && crtc_state->active) { struct apple_crtc *apple_crtc = to_apple_crtc(crtc); - dev_dbg(&apple_crtc->dcp->dev, "%s", __func__); dcp_poweron(apple_crtc->dcp); - dev_dbg(&apple_crtc->dcp->dev, "%s finished", __func__); } if (crtc_state->active) @@ -214,9 +212,7 @@ static void apple_crtc_atomic_disable(struct drm_crtc *crtc, if (crtc_state->active_changed && !crtc_state->active) { struct apple_crtc *apple_crtc = to_apple_crtc(crtc); - dev_dbg(&apple_crtc->dcp->dev, "%s", __func__); dcp_poweroff(apple_crtc->dcp); - dev_dbg(&apple_crtc->dcp->dev, "%s finished", __func__); } if (crtc->state->event && !crtc->state->active) { diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 958b9620f92e5d..0aa747990ea65f 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -128,7 +128,7 @@ static void dcp_recv_msg(void *cookie, u8 endpoint, u64 message) afk_receive_message(dcp->dptxep, message); return; default: - WARN(endpoint, "unknown DCP endpoint %hhu", endpoint); + WARN(endpoint, "unknown DCP endpoint %hhu\n", endpoint); } } @@ -137,7 +137,7 @@ static void dcp_rtk_crashed(void *cookie, const void *crashlog, size_t crashlog_ struct apple_dcp *dcp = cookie; dcp->crashed = true; - dev_err(dcp->dev, "DCP has crashed"); + dev_err(dcp->dev, "DCP has crashed\n"); if (dcp->connector) { dcp->connector->connected = 0; schedule_work(&dcp->connector->hotplug_wq); @@ -169,7 +169,7 @@ static int dcp_rtk_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr) bfr->is_mapped = true; dev_info(dcp->dev, - "shmem_setup: iova: %lx -> pa: %lx -> iomem: %lx", + "shmem_setup: iova: %lx -> pa: %lx -> iomem: %lx\n", (uintptr_t)bfr->iova, (uintptr_t)phy_addr, (uintptr_t)bfr->buffer); } else { @@ -178,7 +178,7 @@ static int dcp_rtk_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr) if (!bfr->buffer) return -ENOMEM; - dev_info(dcp->dev, "shmem_setup: iova: %lx, buffer: %lx", + dev_info(dcp->dev, "shmem_setup: iova: %lx, buffer: %lx\n", (uintptr_t)bfr->iova, (uintptr_t)bfr->buffer); } @@ -226,7 +226,7 @@ int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) needs_modeset = drm_atomic_crtc_needs_modeset(crtc_state) || !dcp->valid_mode; if (!needs_modeset && !dcp->connector->connected) { - dev_err(dcp->dev, "crtc_atomic_check: disconnected but no modeset"); + dev_err(dcp->dev, "crtc_atomic_check: disconnected but no modeset\n"); return -EINVAL; } @@ -239,7 +239,7 @@ int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) } if (plane_count > DCP_MAX_PLANES) { - dev_err(dcp->dev, "crtc_atomic_check: Blend supports only 2 layers!"); + dev_err(dcp->dev, "crtc_atomic_check: Blend supports only 2 layers!\n"); return -EINVAL; } @@ -355,17 +355,17 @@ int dcp_start(struct platform_device *pdev) /* start RTKit endpoints */ ret = systemep_init(dcp); if (ret) - dev_warn(dcp->dev, "Failed to start system endpoint: %d", ret); + dev_warn(dcp->dev, "Failed to start system endpoint: %d\n", ret); if (dcp->phy && dcp->fw_compat >= DCP_FIRMWARE_V_13_5) { ret = ibootep_init(dcp); if (ret) - dev_warn(dcp->dev, "Failed to start IBOOT endpoint: %d", + dev_warn(dcp->dev, "Failed to start IBOOT endpoint: %d\n", ret); ret = dptxep_init(dcp); if (ret) - dev_warn(dcp->dev, "Failed to start DPTX endpoint: %d", + dev_warn(dcp->dev, "Failed to start DPTX endpoint: %d\n", ret); else if (dcp->dptxport[0].enabled) { bool connected; @@ -388,7 +388,7 @@ int dcp_start(struct platform_device *pdev) ret = iomfb_start_rtkit(dcp); if (ret) - dev_err(dcp->dev, "Failed to start IOMFB endpoint: %d", ret); + dev_err(dcp->dev, "Failed to start IOMFB endpoint: %d\n", ret); return ret; } @@ -887,12 +887,12 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) dcp->rtk = devm_apple_rtkit_init(dev, dcp, "mbox", 0, &rtkit_ops); if (IS_ERR(dcp->rtk)) return dev_err_probe(dev, PTR_ERR(dcp->rtk), - "Failed to initialize RTKit"); + "Failed to initialize RTKit\n"); ret = apple_rtkit_wake(dcp->rtk); if (ret) return dev_err_probe(dev, ret, - "Failed to boot RTKit: %d", ret); + "Failed to boot RTKit: %d\n", ret); return ret; } @@ -960,7 +960,7 @@ static int dcp_platform_probe(struct platform_device *pdev) dcp->phy = devm_phy_optional_get(dev, "dp-phy"); if (IS_ERR(dcp->phy)) { - dev_err(dev, "Failed to get dp-phy: %ld", PTR_ERR(dcp->phy)); + dev_err(dev, "Failed to get dp-phy: %ld\n", PTR_ERR(dcp->phy)); return PTR_ERR(dcp->phy); } if (dcp->phy) { @@ -987,7 +987,7 @@ static int dcp_platform_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "dp2hdmi-hpd-irq", dcp); if (ret < 0) { - dev_err(dev, "failed to request HDMI hpd irq %d: %d", + dev_err(dev, "failed to request HDMI hpd irq %d: %d\n", irq, ret); return ret; } @@ -1010,7 +1010,7 @@ static int dcp_platform_probe(struct platform_device *pdev) if (!ret) { dcp->xbar = devm_mux_control_get(dev, "dp-xbar"); if (IS_ERR(dcp->xbar)) { - dev_err(dev, "Failed to get dp-xbar: %ld", PTR_ERR(dcp->xbar)); + dev_err(dev, "Failed to get dp-xbar: %ld\n", PTR_ERR(dcp->xbar)); return PTR_ERR(dcp->xbar); } ret = mux_control_select(dcp->xbar, mux_index); diff --git a/drivers/gpu/drm/apple/dcp_backlight.c b/drivers/gpu/drm/apple/dcp_backlight.c index dfc78f3ce37b0d..ed3b240ead8557 100644 --- a/drivers/gpu/drm/apple/dcp_backlight.c +++ b/drivers/gpu/drm/apple/dcp_backlight.c @@ -99,7 +99,7 @@ static u32 interpolate(int val, int min, int max, u32 *tbl, size_t tbl_size) size_t index = interpolated / SCALE_FACTOR; - if (WARN(index + 1 >= tbl_size, "invalid index %zu for brightness %u", index, val)) + if (WARN(index + 1 >= tbl_size, "invalid index %zu for brightness %u\n", index, val)) return tbl[tbl_size / 2]; frac = interpolated & (SCALE_FACTOR - 1); diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 1d5e0bf4b197f9..788d63d90e3747 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -326,7 +326,7 @@ static void dcpep_got_msg(struct apple_dcp *dcp, u64 message) channel_offset = dcp_channel_offset(ctx_id); if (channel_offset < 0) { - dev_warn(dcp->dev, "invalid context received %u", ctx_id); + dev_warn(dcp->dev, "invalid context received %u\n", ctx_id); return; } @@ -482,7 +482,7 @@ void dcp_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) if (dcp_channel_busy(&dcp->ch_cmd)) { - dev_err(dcp->dev, "unexpected busy command channel"); + dev_err(dcp->dev, "unexpected busy command channel\n"); /* HACK: issue a delayed vblank event to avoid timeouts in * drm_atomic_helper_wait_for_vblanks(). */ diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index d61956a6cc85b9..56b2afa5756614 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -299,7 +299,7 @@ static void dcpep_cb_unmap_piodma(struct apple_dcp *dcp, struct dcp_mem_descriptor *memdesc; if (resp->buffer >= ARRAY_SIZE(dcp->memdesc)) { - dev_warn(dcp->dev, "unmap request for out of range buffer %llu", + dev_warn(dcp->dev, "unmap request for out of range buffer %llu\n", resp->buffer); return; } @@ -308,14 +308,14 @@ static void dcpep_cb_unmap_piodma(struct apple_dcp *dcp, if (!memdesc->buf) { dev_warn(dcp->dev, - "unmap for non-mapped buffer %llu iova:0x%08llx", + "unmap for non-mapped buffer %llu iova:0x%08llx\n", resp->buffer, resp->dva); return; } if (memdesc->dva != resp->dva) { dev_warn(dcp->dev, "unmap buffer %llu address mismatch " - "memdesc.dva:%llx dva:%llx", resp->buffer, + "memdesc.dva:%llx dva:%llx\n", resp->buffer, memdesc->dva, resp->dva); return; } @@ -343,7 +343,7 @@ dcpep_cb_allocate_buffer(struct apple_dcp *dcp, find_first_zero_bit(dcp->memdesc_map, DCP_MAX_MAPPINGS); if (resp.mem_desc_id >= DCP_MAX_MAPPINGS) { - dev_warn(dcp->dev, "DCP overflowed mapping table, ignoring"); + dev_warn(dcp->dev, "DCP overflowed mapping table, ignoring\n"); resp.dva_size = 0; resp.mem_desc_id = 0; return resp; @@ -378,7 +378,7 @@ static u8 dcpep_cb_release_mem_desc(struct apple_dcp *dcp, u32 *mem_desc_id) } if (!test_and_clear_bit(id, dcp->memdesc_map)) { - dev_warn(dcp->dev, "unmap request for unused mem_desc_id %u", + dev_warn(dcp->dev, "unmap request for unused mem_desc_id %u\n", id); return 0; } @@ -428,7 +428,7 @@ dcpep_cb_map_physical(struct apple_dcp *dcp, struct dcp_map_physical_req *req) u32 id; if (!is_disp_register(dcp, req->paddr, req->paddr + size - 1)) { - dev_err(dcp->dev, "refusing to map phys address %llx size %llx", + dev_err(dcp->dev, "refusing to map phys address %llx size %llx\n", req->paddr, req->size); return (struct dcp_map_physical_resp){}; } @@ -457,7 +457,7 @@ static struct DCP_FW_NAME(dcp_map_reg_resp) dcpep_cb_map_reg(struct apple_dcp *d struct DCP_FW_NAME(dcp_map_reg_req) *req) { if (req->index >= dcp->nr_disp_registers) { - dev_warn(dcp->dev, "attempted to read invalid reg index %u", + dev_warn(dcp->dev, "attempted to read invalid reg index %u\n", req->index); return (struct DCP_FW_NAME(dcp_map_reg_resp)){ .ret = 1 }; @@ -602,7 +602,7 @@ static void boot_done(struct apple_dcp *dcp, void *out, void *cookie) { struct dcp_channel *ch = &dcp->ch_cb; u8 *succ = ch->output[ch->depth - 1]; - dev_dbg(dcp->dev, "boot done"); + dev_dbg(dcp->dev, "boot done\n"); *succ = true; dcp_ack(dcp, DCP_CONTEXT_CB); @@ -717,7 +717,6 @@ static void release_swap_cookie(struct kref *ref) static void dcp_swap_cleared(struct apple_dcp *dcp, void *data, void *cookie) { struct DCP_FW_NAME(dcp_swap_submit_resp) *resp = data; - dev_dbg(dcp->dev, "%s", __func__); if (cookie) { struct dcp_swap_cookie *info = cookie; @@ -748,7 +747,6 @@ static void dcp_swap_clear_started(struct apple_dcp *dcp, void *data, void *cookie) { struct dcp_swap_start_resp *resp = data; - dev_dbg(dcp->dev, "%s swap_id: %u", __func__, resp->swap_id); DCP_FW_UNION(dcp->swap).swap.swap_id = resp->swap_id; if (cookie) { @@ -762,7 +760,6 @@ static void dcp_swap_clear_started(struct apple_dcp *dcp, void *data, static void dcp_on_final(struct apple_dcp *dcp, void *out, void *cookie) { struct dcp_wait_cookie *wait = cookie; - dev_dbg(dcp->dev, "%s", __func__); if (wait) { complete(&wait->done); @@ -775,7 +772,6 @@ static void dcp_on_set_power_state(struct apple_dcp *dcp, void *out, void *cooki struct dcp_set_power_state_req req = { .unklong = 1, }; - dev_dbg(dcp->dev, "%s", __func__); dcp_set_power_state(dcp, false, &req, dcp_on_final, cookie); } @@ -791,7 +787,6 @@ static void dcp_on_set_parameter(struct apple_dcp *dcp, void *out, void *cookie) .count = 1, #endif }; - dev_dbg(dcp->dev, "%s", __func__); dcp_set_parameter_dcp(dcp, false, ¶m, dcp_on_set_power_state, cookie); } @@ -803,8 +798,6 @@ void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp) u32 handle; dev_info(dcp->dev, "dcp_poweron() starting\n"); - dev_dbg(dcp->dev, "%s", __func__); - cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); if (!cookie) return; @@ -826,7 +819,7 @@ void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp) ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(500)); if (ret == 0) - dev_warn(dcp->dev, "wait for power timed out"); + dev_warn(dcp->dev, "wait for power timed out\n"); kref_put(&cookie->refcount, release_wait_cookie);; @@ -874,8 +867,6 @@ void DCP_FW_NAME(iomfb_poweroff)(struct apple_dcp *dcp) struct dcp_swap_start_req swap_req = { 0 }; struct DCP_FW_NAME(dcp_swap_submit_req) *swap = &DCP_FW_UNION(dcp->swap); - dev_dbg(dcp->dev, "%s", __func__); - cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); if (!cookie) return; @@ -923,7 +914,7 @@ void DCP_FW_NAME(iomfb_poweroff)(struct apple_dcp *dcp) return; } - dev_dbg(dcp->dev, "%s: clear swap submitted: %u", __func__, swap_id); + dev_dbg(dcp->dev, "%s: clear swap submitted: %u\n", __func__, swap_id); poff_cookie = kzalloc(sizeof(*poff_cookie), GFP_KERNEL); if (!poff_cookie) @@ -939,14 +930,13 @@ void DCP_FW_NAME(iomfb_poweroff)(struct apple_dcp *dcp) msecs_to_jiffies(1000)); if (ret == 0) - dev_warn(dcp->dev, "setPowerState(0) timeout %u ms", 1000); + dev_warn(dcp->dev, "setPowerState(0) timeout %u ms\n", 1000); else if (ret > 0) dev_dbg(dcp->dev, "setPowerState(0) finished with %d ms to spare", jiffies_to_msecs(ret)); kref_put(&poff_cookie->refcount, release_wait_cookie); - dev_dbg(dcp->dev, "%s: setPowerState(0) done", __func__); dev_info(dcp->dev, "dcp_poweroff() done\n"); } @@ -990,11 +980,9 @@ void DCP_FW_NAME(iomfb_sleep)(struct apple_dcp *dcp) msecs_to_jiffies(1000)); if (ret == 0) - dev_warn(dcp->dev, "setDCPPower(0) timeout %u ms", 1000); + dev_warn(dcp->dev, "setDCPPower(0) timeout %u ms\n", 1000); kref_put(&cookie->refcount, release_wait_cookie); - dev_dbg(dcp->dev, "%s: setDCPPower(0) done", __func__); - dev_info(dcp->dev, "dcp_sleep() done\n"); } @@ -1163,7 +1151,6 @@ static void dcp_swap_started(struct apple_dcp *dcp, void *data, void *cookie) static void do_swap(struct apple_dcp *dcp, void *data, void *cookie) { struct dcp_swap_start_req start_req = { 0 }; - dev_dbg(dcp->dev, "%s", __func__); if (dcp->connector && dcp->connector->connected) dcp_swap_start(dcp, false, &start_req, dcp_swap_started, NULL); @@ -1175,7 +1162,6 @@ static void complete_set_digital_out_mode(struct apple_dcp *dcp, void *data, void *cookie) { struct dcp_wait_cookie *wait = cookie; - dev_dbg(dcp->dev, "%s", __func__); if (wait) { complete(&wait->done); @@ -1242,7 +1228,6 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, * modesets. Add an extra 500ms to safe side that the modeset * call has returned. */ - dev_dbg(dcp->dev, "%s - wait for modeset", __func__); ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(8500)); @@ -1276,7 +1261,6 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru struct DCP_FW_NAME(dcp_swap_submit_req) *req = &DCP_FW_UNION(dcp->swap); int plane_idx, l; int has_surface = 0; - dev_dbg(dcp->dev, "%s", __func__); crtc_state = drm_atomic_get_new_crtc_state(state, crtc); From f58b9ee34c252fec3cc620112fd679c0306ec18d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 26 Mar 2024 22:05:50 +0100 Subject: [PATCH 184/352] drm: apple: dptx: Debounce HPD by simple msleep() Not necessarily only a debounce but 500ms sleep in the HPD interrupt handler seems to make the modeset more reliable on M2* desktop devices. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 0aa747990ea65f..82590dce9493b7 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -329,6 +329,12 @@ static irqreturn_t dcp_dp2hdmi_hpd(int irq, void *data) */ dev_info(dcp->dev, "DP2HDMI HPD irq, connected:%d\n", connected); + if (connected) { + msleep(500); + connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); + dev_info(dcp->dev, "DP2HDMI HPD irq, 500ms debounce: connected:%d\n", connected); + } + if (connected) dcp_dptx_connect(dcp, 0); From be4da12f6230a6f2796171c8a055f46ba4578b5c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Jan 2024 14:47:56 +0100 Subject: [PATCH 185/352] drm: apple: Add Kconfig option for audio Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Kconfig | 7 +++++++ drivers/gpu/drm/apple/parser.c | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/apple/Kconfig b/drivers/gpu/drm/apple/Kconfig index e2d424b983314a..bc7c875ac10b1b 100644 --- a/drivers/gpu/drm/apple/Kconfig +++ b/drivers/gpu/drm/apple/Kconfig @@ -13,3 +13,10 @@ config DRM_APPLE select MULTIPLEXER help Say Y if you have an Apple Silicon chipset. + +config DRM_APPLE_AUDIO + bool "DisplayPort/HDMI Audio support" + default y + depends on DRM_APPLE + depends on SND + select SND_PCM diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 0aab3ecde8e12e..2e3c22d576cb91 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -7,7 +7,9 @@ #include #include +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) #include // for sound format masks +#endif #include "parser.h" #include "trace.h" @@ -119,6 +121,7 @@ static int skip(struct dcp_parse_ctx *handle) } } +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) static int skip_pair(struct dcp_parse_ctx *handle) { int ret; @@ -151,6 +154,7 @@ static bool consume_string(struct dcp_parse_ctx *ctx, const char *specimen) skip(ctx); return true; } +#endif /* Caller must free the result */ static char *parse_string(struct dcp_parse_ctx *handle) @@ -201,6 +205,7 @@ static int parse_bool(struct dcp_parse_ctx *handle, bool *b) return 0; } +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) static int parse_blob(struct dcp_parse_ctx *handle, size_t size, u8 const **blob) { const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BLOB); @@ -220,6 +225,7 @@ static int parse_blob(struct dcp_parse_ctx *handle, size_t size, u8 const **blob *blob = out; return 0; } +#endif struct iterator { struct dcp_parse_ctx *handle; @@ -681,6 +687,7 @@ int parse_epic_service_init(struct dcp_parse_ctx *handle, const char **name, return ret; } +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) static int parse_sample_rate_bit(struct dcp_parse_ctx *handle, unsigned int *ratebit) { s64 rate; @@ -984,6 +991,7 @@ int parse_sound_mode(struct dcp_parse_ctx *handle, return 0; } EXPORT_SYMBOL_GPL(parse_sound_mode); +#endif int parse_system_log_mnits(struct dcp_parse_ctx *handle, struct dcp_system_ev_mnits *entry) { From 22a6eb936627461ab429f9420d33874c42689348 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 25 Dec 2023 18:03:37 +0100 Subject: [PATCH 186/352] drm: apple: iomfb: export property dicts in connector debugfs Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Makefile | 1 + drivers/gpu/drm/apple/apple_drv.c | 2 + drivers/gpu/drm/apple/connector.c | 122 +++++++++++++++++++++++++ drivers/gpu/drm/apple/connector.h | 39 ++++++++ drivers/gpu/drm/apple/dcp.h | 15 +-- drivers/gpu/drm/apple/iomfb_template.c | 5 +- 6 files changed, 168 insertions(+), 16 deletions(-) create mode 100644 drivers/gpu/drm/apple/connector.c create mode 100644 drivers/gpu/drm/apple/connector.h diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index dde8fa879b3a61..20796e2e5899e7 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -5,6 +5,7 @@ CFLAGS_trace.o = -I$(src) appledrm-y := apple_drv.o apple_dcp-y := afk.o dcp.o dcp_backlight.o dptxep.o iomfb.o parser.o systemep.o +apple_dcp-y += connector.o apple_dcp-y += ibootep.o apple_dcp-y += iomfb_v12_3.o apple_dcp-y += iomfb_v13_3.o diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 900e509faa2f63..8a995bea255e4b 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -296,6 +296,7 @@ static const struct drm_connector_funcs apple_connector_funcs = { .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .detect = apple_connector_detect, + .debugfs_init = apple_connector_debugfs_init, }; static const struct drm_connector_helper_funcs apple_connector_helper_funcs = { @@ -344,6 +345,7 @@ static int apple_probe_per_dcp(struct device *dev, enc->base.possible_crtcs = drm_crtc_mask(&crtc->base); connector = kzalloc(sizeof(*connector), GFP_KERNEL); + mutex_init(&connector->chunk_lock); drm_connector_helper_add(&connector->base, &apple_connector_helper_funcs); diff --git a/drivers/gpu/drm/apple/connector.c b/drivers/gpu/drm/apple/connector.c new file mode 100644 index 00000000000000..a39bd249697d90 --- /dev/null +++ b/drivers/gpu/drm/apple/connector.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright (C) The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include + +#include + +#include "connector.h" +#include "dcp-internal.h" + +enum dcp_chunk_type { + DCP_CHUNK_COLOR_ELEMENTS, + DCP_CHUNK_TIMING_ELELMENTS, + DCP_CHUNK_DISPLAY_ATTRIBUTES, + DCP_CHUNK_TRANSPORT, + DCP_CHUNK_NUM_TYPES, +}; + +static int chunk_show(struct seq_file *m, + enum dcp_chunk_type chunk_type) +{ + struct apple_connector *apple_con = m->private; + struct dcp_chunks *chunk = NULL; + + mutex_lock(&apple_con->chunk_lock); + + switch (chunk_type) { + case DCP_CHUNK_COLOR_ELEMENTS: + chunk = &apple_con->color_elements; + break; + case DCP_CHUNK_TIMING_ELELMENTS: + chunk = &apple_con->timing_elements; + break; + case DCP_CHUNK_DISPLAY_ATTRIBUTES: + chunk = &apple_con->display_attributes; + break; + case DCP_CHUNK_TRANSPORT: + chunk = &apple_con->transport; + break; + default: + break; + } + + if (chunk) + seq_write(m, chunk->data, chunk->length); + + mutex_unlock(&apple_con->chunk_lock); + + return 0; +} + +#define CONNECTOR_DEBUGFS_ENTRY(name, type) \ +static int chunk_ ## name ## _show(struct seq_file *m, void *data) \ +{ \ + return chunk_show(m, type); \ +} \ +static int chunk_ ## name ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, chunk_ ## name ## _show, inode->i_private); \ +} \ +static const struct file_operations chunk_ ## name ## _fops = { \ + .owner = THIS_MODULE, \ + .open = chunk_ ## name ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + +CONNECTOR_DEBUGFS_ENTRY(color, DCP_CHUNK_COLOR_ELEMENTS); +CONNECTOR_DEBUGFS_ENTRY(timing, DCP_CHUNK_TIMING_ELELMENTS); +CONNECTOR_DEBUGFS_ENTRY(display_attribs, DCP_CHUNK_DISPLAY_ATTRIBUTES); +CONNECTOR_DEBUGFS_ENTRY(transport, DCP_CHUNK_TRANSPORT); + +void apple_connector_debugfs_init(struct drm_connector *connector, struct dentry *root) +{ + struct apple_connector *apple_con = to_apple_connector(connector); + + debugfs_create_file("ColorElements", 0444, root, apple_con, + &chunk_color_fops); + debugfs_create_file("TimingElements", 0444, root, apple_con, + &chunk_timing_fops); + debugfs_create_file("DisplayAttributes", 0444, root, apple_con, + &chunk_display_attribs_fops); + debugfs_create_file("Transport", 0444, root, apple_con, + &chunk_transport_fops); +} +EXPORT_SYMBOL(apple_connector_debugfs_init); + +static void dcp_connector_set_dict(struct apple_connector *connector, + struct dcp_chunks *dict, + struct dcp_chunks *chunks) +{ + if (dict->data) + devm_kfree(&connector->dcp->dev, dict->data); + + *dict = *chunks; +} + +void dcp_connector_update_dict(struct apple_connector *connector, const char *key, + struct dcp_chunks *chunks) +{ + mutex_lock(&connector->chunk_lock); + if (!strcmp(key, "ColorElements")) + dcp_connector_set_dict(connector, &connector->color_elements, chunks); + else if (!strcmp(key, "TimingElements")) + dcp_connector_set_dict(connector, &connector->timing_elements, chunks); + else if (!strcmp(key, "DisplayAttributes")) + dcp_connector_set_dict(connector, &connector->display_attributes, chunks); + else if (!strcmp(key, "Transport")) + dcp_connector_set_dict(connector, &connector->transport, chunks); + + chunks->data = NULL; + chunks->length = 0; + + mutex_unlock(&connector->chunk_lock); +} diff --git a/drivers/gpu/drm/apple/connector.h b/drivers/gpu/drm/apple/connector.h new file mode 100644 index 00000000000000..5324b1b81f493c --- /dev/null +++ b/drivers/gpu/drm/apple/connector.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* "Copyright" 2021 Alyssa Rosenzweig */ + +#ifndef __APPLE_CONNECTOR_H__ +#define __APPLE_CONNECTOR_H__ + +#include + +#include +#include "drm/drm_connector.h" + +#include "dcp-internal.h" + +void dcp_hotplug(struct work_struct *work); + +struct apple_connector { + struct drm_connector base; + bool connected; + + struct platform_device *dcp; + + /* Workqueue for sending hotplug events to the associated device */ + struct work_struct hotplug_wq; + + struct mutex chunk_lock; + + struct dcp_chunks color_elements; + struct dcp_chunks timing_elements; + struct dcp_chunks display_attributes; + struct dcp_chunks transport; +}; + +#define to_apple_connector(x) container_of(x, struct apple_connector, base) + +void apple_connector_debugfs_init(struct drm_connector *connector, struct dentry *root); + +void dcp_connector_update_dict(struct apple_connector *connector, const char *key, + struct dcp_chunks *chunks); +#endif diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index 268bda8fa3bfc0..557d42c1d87523 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -8,6 +8,7 @@ #include #include +#include "connector.h" #include "dcp-internal.h" #include "parser.h" @@ -22,20 +23,6 @@ struct apple_crtc { #define to_apple_crtc(x) container_of(x, struct apple_crtc, base) -void dcp_hotplug(struct work_struct *work); - -struct apple_connector { - struct drm_connector base; - bool connected; - - struct platform_device *dcp; - - /* Workqueue for sending hotplug events to the associated device */ - struct work_struct hotplug_wq; -}; - -#define to_apple_connector(x) container_of(x, struct apple_connector, base) - struct apple_encoder { struct drm_encoder base; }; diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 56b2afa5756614..e74c3f7863160c 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -590,9 +590,10 @@ static u8 dcpep_cb_prop_end(struct apple_dcp *dcp, { u8 resp = dcpep_process_chunks(dcp, req); - /* Reset for the next transfer */ - devm_kfree(dcp->dev, dcp->chunks.data); + /* move chunked data to connector to provide it via debugfs */ + dcp_connector_update_dict(dcp->connector, req->key, &dcp->chunks); dcp->chunks.data = NULL; + dcp->chunks.length = 0; return resp; } From f679d28e076d0ef64cb70e4dfe44dea8ce60939d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 13 Feb 2023 14:55:13 +0100 Subject: [PATCH 187/352] gpu: drm: apple: Expose injecting of EPIC calls via debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer Co-developed-by: Janne Grunau Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Kconfig | 5 + drivers/gpu/drm/apple/afk.c | 161 +++++++++++++++++++++++++++ drivers/gpu/drm/apple/afk.h | 8 ++ drivers/gpu/drm/apple/connector.c | 29 +++++ drivers/gpu/drm/apple/dcp-internal.h | 3 + 5 files changed, 206 insertions(+) diff --git a/drivers/gpu/drm/apple/Kconfig b/drivers/gpu/drm/apple/Kconfig index bc7c875ac10b1b..d8ae51282e5300 100644 --- a/drivers/gpu/drm/apple/Kconfig +++ b/drivers/gpu/drm/apple/Kconfig @@ -20,3 +20,8 @@ config DRM_APPLE_AUDIO depends on DRM_APPLE depends on SND select SND_PCM + +config DRM_APPLE_DEBUG + bool "Enable additional driver debugging" + depends on DRM_APPLE + depends on EXPERT # only for developers diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index b3a5cf74e817e9..218c28dfe84249 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -2,7 +2,9 @@ /* Copyright 2022 Sven Peter */ #include +#include #include +#include #include #include #include @@ -181,6 +183,18 @@ static void afk_init_rxtx(struct apple_dcp_afkep *ep, u64 message, afk_send(ep, FIELD_PREP(RBEP_TYPE, RBEP_START)); } +#if IS_ENABLED(CONFIG_DRM_APPLE_DEBUG) +static void afk_populate_service_debugfs(struct apple_epic_service *srv); +static void afk_remove_service_debugfs(struct apple_epic_service *srv); +#else +static void afk_populate_service_debugfs(struct apple_epic_service *srv) +{ +} +static void afk_remove_service_debugfs(struct apple_epic_service *srv) +{ +} +#endif + static const struct apple_epic_service_ops * afk_match_service(struct apple_dcp_afkep *ep, const char *name) { @@ -284,6 +298,9 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel, ops->init(&ep->services[ch_idx], epic_name, epic_class, epic_unit); dev_info(ep->dcp->dev, "AFK[ep:%02x]: new service %s on channel %d\n", ep->endpoint, service_name, channel); + + afk_populate_service_debugfs(&ep->services[ch_idx]); + free: kfree(epic_name); kfree(epic_class); @@ -302,6 +319,8 @@ static void afk_recv_handle_teardown(struct apple_dcp_afkep *ep, u32 channel) return; } + afk_remove_service_debugfs(service); + // TODO: think through what locking is necessary spin_lock_irqsave(&service->lock, flags); service->enabled = false; @@ -989,3 +1008,145 @@ int afk_service_call(struct apple_epic_service *service, u16 group, u32 command, kfree(bfr); return ret; } + +#if IS_ENABLED(CONFIG_DRM_APPLE_DEBUG) + +#define AFK_DEBUGFS_MAX_REPLY 8192 + +static ssize_t service_call_write_file(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct apple_epic_service *srv = file->private_data; + void *buf; + int ret; + struct { + u32 group; + u32 command; + } call_info; + + if (count < sizeof(call_info)) + return -EINVAL; + if (!srv->debugfs.scratch) { + srv->debugfs.scratch = \ + devm_kzalloc(srv->ep->dcp->dev, AFK_DEBUGFS_MAX_REPLY, GFP_KERNEL); + if (!srv->debugfs.scratch) + return -ENOMEM; + } + + ret = copy_from_user(&call_info, user_buf, sizeof(call_info)); + if (ret == sizeof(call_info)) + return -EFAULT; + user_buf += sizeof(call_info); + count -= sizeof(call_info); + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = copy_from_user(buf, user_buf, count); + if (ret == count) { + kfree(buf); + return -EFAULT; + } + + memset(srv->debugfs.scratch, 0, AFK_DEBUGFS_MAX_REPLY); + dma_mb(); + + ret = afk_service_call(srv, call_info.group, call_info.command, buf, count, 0, + srv->debugfs.scratch, AFK_DEBUGFS_MAX_REPLY, 0); + kfree(buf); + + if (ret < 0) + return ret; + + return count + sizeof(call_info); +} + +static ssize_t service_call_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct apple_epic_service *srv = file->private_data; + + if (!srv->debugfs.scratch) + return -EINVAL; + + return simple_read_from_buffer(user_buf, count, ppos, + srv->debugfs.scratch, AFK_DEBUGFS_MAX_REPLY); +} + +static const struct file_operations service_call_fops = { + .open = simple_open, + .write = service_call_write_file, + .read = service_call_read_file, +}; + +static ssize_t service_raw_call_write_file(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct apple_epic_service *srv = file->private_data; + u32 retcode; + int ret; + + if (!srv->debugfs.scratch) { + srv->debugfs.scratch = \ + devm_kzalloc(srv->ep->dcp->dev, AFK_DEBUGFS_MAX_REPLY, GFP_KERNEL); + if (!srv->debugfs.scratch) + return -ENOMEM; + } + + memset(srv->debugfs.scratch, 0, AFK_DEBUGFS_MAX_REPLY); + ret = copy_from_user(srv->debugfs.scratch, user_buf, count); + if (ret == count) + return -EFAULT; + + ret = afk_send_command(srv, EPIC_SUBTYPE_STD_SERVICE, srv->debugfs.scratch, count, + srv->debugfs.scratch, AFK_DEBUGFS_MAX_REPLY, &retcode); + if (ret < 0) + return ret; + if (retcode) + return -EINVAL; + + return count; +} + +static ssize_t service_raw_call_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct apple_epic_service *srv = file->private_data; + + if (!srv->debugfs.scratch) + return -EINVAL; + + return simple_read_from_buffer(user_buf, count, ppos, + srv->debugfs.scratch, AFK_DEBUGFS_MAX_REPLY); +} + +static const struct file_operations service_raw_call_fops = { + .open = simple_open, + .write = service_raw_call_write_file, + .read = service_raw_call_read_file, +}; + +static void afk_populate_service_debugfs(struct apple_epic_service *srv) +{ + if (!srv->ep->debugfs_entry || !srv->ops) + return; + + if (strcmp(srv->ops->name, "DCPAVAudioInterface") == 0) { + srv->debugfs.entry = debugfs_create_dir(srv->ops->name, + srv->ep->debugfs_entry); + debugfs_create_file("call", 0600, srv->debugfs.entry, srv, + &service_call_fops); + debugfs_create_file("raw_call", 0600, srv->debugfs.entry, srv, + &service_raw_call_fops); + } +} + +static void afk_remove_service_debugfs(struct apple_epic_service *srv) +{ + if (srv->debugfs.entry) { + debugfs_remove_recursive(srv->debugfs.entry); + srv->debugfs.entry = NULL; + } +} + +#endif diff --git a/drivers/gpu/drm/apple/afk.h b/drivers/gpu/drm/apple/afk.h index 737288b1346b28..0f91f32e08e301 100644 --- a/drivers/gpu/drm/apple/afk.h +++ b/drivers/gpu/drm/apple/afk.h @@ -8,6 +8,7 @@ #define _DRM_APPLE_DCP_AFK_H #include +#include #include #include "dcp.h" @@ -47,6 +48,11 @@ struct apple_epic_service { bool enabled; void *cookie; + + struct { + struct dentry *entry; + u8 *scratch; + } debugfs; }; enum epic_subtype; @@ -174,6 +180,8 @@ struct apple_dcp_afkep { const struct apple_epic_service_ops *ops; struct apple_epic_service services[AFK_MAX_CHANNEL]; u32 num_channels; + + struct dentry *debugfs_entry; }; struct apple_dcp_afkep *afk_init(struct apple_dcp *dcp, u32 endpoint, diff --git a/drivers/gpu/drm/apple/connector.c b/drivers/gpu/drm/apple/connector.c index a39bd249697d90..46de8e8756f1ed 100644 --- a/drivers/gpu/drm/apple/connector.c +++ b/drivers/gpu/drm/apple/connector.c @@ -3,6 +3,7 @@ * Copyright (C) The Asahi Linux Contributors */ +#include "linux/err.h" #include #include #include @@ -77,6 +78,25 @@ CONNECTOR_DEBUGFS_ENTRY(timing, DCP_CHUNK_TIMING_ELELMENTS); CONNECTOR_DEBUGFS_ENTRY(display_attribs, DCP_CHUNK_DISPLAY_ATTRIBUTES); CONNECTOR_DEBUGFS_ENTRY(transport, DCP_CHUNK_TRANSPORT); +static void dcp_afk_debugfs_root(struct platform_device *pdev, int ep, struct dentry *root) +{ +#if IS_ENABLED(CONFIG_DRM_APPLE_DEBUG) + struct dentry *entry = NULL; + struct apple_dcp *dcp = platform_get_drvdata(pdev); + + switch (ep) { + case AV_ENDPOINT: + entry = debugfs_create_dir("avep", root); + break; + default: + break; + } + + if (!IS_ERR_OR_NULL(entry)) + dcp->ep_debugfs[ep - 0x20] = entry; +#endif +} + void apple_connector_debugfs_init(struct drm_connector *connector, struct dentry *root) { struct apple_connector *apple_con = to_apple_connector(connector); @@ -89,6 +109,15 @@ void apple_connector_debugfs_init(struct drm_connector *connector, struct dentry &chunk_display_attribs_fops); debugfs_create_file("Transport", 0444, root, apple_con, &chunk_transport_fops); + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_HDMIA: + dcp_afk_debugfs_root(apple_con->dcp, AV_ENDPOINT, root); + break; + default: + break; + } } EXPORT_SYMBOL(apple_connector_debugfs_init); diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 3e78435edbf529..a3991aab78df5d 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -227,6 +227,9 @@ struct apple_dcp { struct dptx_port dptxport[2]; + /* debugfs entries */ + struct dentry *ep_debugfs[0x20]; + /* these fields are output port specific */ struct phy *phy; struct mux_control *xbar; From be8aae6b725bc0b6a57cfd82b71af2e658443f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 13 Feb 2023 14:56:24 +0100 Subject: [PATCH 188/352] gpu: drm: apple: Set up client of AV endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- drivers/gpu/drm/apple/Makefile | 1 + drivers/gpu/drm/apple/audio.h | 26 +++ drivers/gpu/drm/apple/av.c | 284 +++++++++++++++++++++++++++ drivers/gpu/drm/apple/av.h | 9 + drivers/gpu/drm/apple/dcp-internal.h | 6 + drivers/gpu/drm/apple/dcp.c | 16 ++ drivers/gpu/drm/apple/dcp.h | 2 + 7 files changed, 344 insertions(+) create mode 100644 drivers/gpu/drm/apple/audio.h create mode 100644 drivers/gpu/drm/apple/av.c create mode 100644 drivers/gpu/drm/apple/av.h diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index 20796e2e5899e7..4c6d3947b024b1 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -5,6 +5,7 @@ CFLAGS_trace.o = -I$(src) appledrm-y := apple_drv.o apple_dcp-y := afk.o dcp.o dcp_backlight.o dptxep.o iomfb.o parser.o systemep.o +apple_dcp-$(CONFIG_DRM_APPLE_AUDIO) += av.o apple_dcp-y += connector.o apple_dcp-y += ibootep.o apple_dcp-y += iomfb_v12_3.o diff --git a/drivers/gpu/drm/apple/audio.h b/drivers/gpu/drm/apple/audio.h new file mode 100644 index 00000000000000..3cf4d31417694e --- /dev/null +++ b/drivers/gpu/drm/apple/audio.h @@ -0,0 +1,26 @@ +#ifndef __AUDIO_H__ +#define __AUDIO_H__ + +#include + +struct device; +struct device_node; +struct dcp_sound_cookie; + +typedef void (*dcp_audio_hotplug_callback)(struct device *dev, bool connected); + +struct dcp_audio_pdata { + struct device *dcp_dev; + struct device_node *dpaudio_node; +}; + +void dcp_audiosrv_set_hotplug_cb(struct device *dev, struct device *audio_dev, + dcp_audio_hotplug_callback cb); +int dcp_audiosrv_prepare(struct device *dev, struct dcp_sound_cookie *cookie); +int dcp_audiosrv_startlink(struct device *dev, struct dcp_sound_cookie *cookie); +int dcp_audiosrv_stoplink(struct device *dev); +int dcp_audiosrv_unprepare(struct device *dev); +int dcp_audiosrv_get_elements(struct device *dev, void *elements, size_t maxsize); +int dcp_audiosrv_get_product_attrs(struct device *dev, void *attrs, size_t maxsize); + +#endif /* __AUDIO_H__ */ diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c new file mode 100644 index 00000000000000..bd4c7ec51bdb7d --- /dev/null +++ b/drivers/gpu/drm/apple/av.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2023 Martin Povišer */ + +// #define DEBUG + +#include +#include +#include +#include + +#include "audio.h" +#include "afk.h" +#include "dcp.h" + +struct audiosrv_data { + struct device *audio_dev; + dcp_audio_hotplug_callback hotplug_cb; + bool plugged; + struct mutex plug_lock; + + struct apple_epic_service *srv; + struct rw_semaphore srv_rwsem; +}; + +static void av_interface_init(struct apple_epic_service *service, const char *name, + const char *class, s64 unit) +{ +} + +static void av_audiosrv_init(struct apple_epic_service *service, const char *name, + const char *class, s64 unit) +{ + struct apple_dcp *dcp = service->ep->dcp; + struct audiosrv_data *asrv = dcp->audiosrv; + int err; + + mutex_lock(&asrv->plug_lock); + + down_write(&asrv->srv_rwsem); + asrv->srv = service; + up_write(&asrv->srv_rwsem); + + /* TODO: this must be done elsewhere */ + err = afk_service_call(asrv->srv, 0, 6, NULL, 0, 32, NULL, 0, 32); + if (err) + dev_err(dcp->dev, "error opening audio service: %d\n", err); + + asrv->plugged = true; + if (asrv->hotplug_cb) + asrv->hotplug_cb(asrv->audio_dev, true); + + mutex_unlock(&asrv->plug_lock); +} + +static void av_audiosrv_teardown(struct apple_epic_service *service) +{ + struct apple_dcp *dcp = service->ep->dcp; + struct audiosrv_data *asrv = dcp->audiosrv; + + mutex_lock(&asrv->plug_lock); + + down_write(&asrv->srv_rwsem); + asrv->srv = NULL; + up_write(&asrv->srv_rwsem); + + asrv->plugged = false; + if (asrv->hotplug_cb) + asrv->hotplug_cb(asrv->audio_dev, false); + + mutex_unlock(&asrv->plug_lock); +} + +void dcp_audiosrv_set_hotplug_cb(struct device *dev, struct device *audio_dev, + dcp_audio_hotplug_callback cb) +{ + struct apple_dcp *dcp = dev_get_drvdata(dev); + struct audiosrv_data *asrv = dcp->audiosrv; + + mutex_lock(&asrv->plug_lock); + asrv->audio_dev = audio_dev; + asrv->hotplug_cb = cb; + + if (cb) + cb(audio_dev, asrv->plugged); + mutex_unlock(&asrv->plug_lock); +} +EXPORT_SYMBOL_GPL(dcp_audiosrv_set_hotplug_cb); + +int dcp_audiosrv_prepare(struct device *dev, struct dcp_sound_cookie *cookie) +{ + struct apple_dcp *dcp = dev_get_drvdata(dev); + struct audiosrv_data *asrv = dcp->audiosrv; + int ret; + + down_write(&asrv->srv_rwsem); + ret = afk_service_call(asrv->srv, 0, 8, cookie, sizeof(*cookie), + 64 - sizeof(*cookie), NULL, 0, 64); + up_write(&asrv->srv_rwsem); + + return ret; +} +EXPORT_SYMBOL_GPL(dcp_audiosrv_prepare); + +int dcp_audiosrv_startlink(struct device *dev, struct dcp_sound_cookie *cookie) +{ + struct apple_dcp *dcp = dev_get_drvdata(dev); + struct audiosrv_data *asrv = dcp->audiosrv; + int ret; + + down_write(&asrv->srv_rwsem); + ret = afk_service_call(asrv->srv, 0, 9, cookie, sizeof(*cookie), + 64 - sizeof(*cookie), NULL, 0, 64); + up_write(&asrv->srv_rwsem); + + return ret; +} +EXPORT_SYMBOL_GPL(dcp_audiosrv_startlink); + +int dcp_audiosrv_stoplink(struct device *dev) +{ + struct apple_dcp *dcp = dev_get_drvdata(dev); + struct audiosrv_data *asrv = dcp->audiosrv; + int ret; + + down_write(&asrv->srv_rwsem); + ret = afk_service_call(asrv->srv, 0, 12, NULL, 0, 64, NULL, 0, 64); + up_write(&asrv->srv_rwsem); + + return ret; +} +EXPORT_SYMBOL_GPL(dcp_audiosrv_stoplink); + +int dcp_audiosrv_unprepare(struct device *dev) +{ + struct apple_dcp *dcp = dev_get_drvdata(dev); + struct audiosrv_data *asrv = dcp->audiosrv; + int ret; + + down_write(&asrv->srv_rwsem); + ret = afk_service_call(asrv->srv, 0, 13, NULL, 0, 64, NULL, 0, 64); + up_write(&asrv->srv_rwsem); + + return ret; +} +EXPORT_SYMBOL_GPL(dcp_audiosrv_unprepare); + +static int +dcp_audiosrv_osobject_call(struct apple_epic_service *service, u16 group, + u32 command, void *output, size_t output_maxsize, + size_t *output_size) +{ + struct { + __le64 max_size; + u8 _pad1[24]; + __le64 used_size; + u8 _pad2[8]; + } __attribute__((packed)) *hdr; + static_assert(sizeof(*hdr) == 48); + size_t bfr_len = output_maxsize + sizeof(*hdr); + void *bfr; + int ret; + + bfr = kzalloc(bfr_len, GFP_KERNEL); + if (!bfr) + return -ENOMEM; + + hdr = bfr; + hdr->max_size = cpu_to_le64(output_maxsize); + ret = afk_service_call(service, group, command, hdr, sizeof(*hdr), output_maxsize, + bfr, sizeof(*hdr) + output_maxsize, 0); + if (ret) + return ret; + + if (output) + memcpy(output, bfr + sizeof(*hdr), output_maxsize); + + if (output_size) + *output_size = le64_to_cpu(hdr->used_size); + + return 0; +} + +int dcp_audiosrv_get_elements(struct device *dev, void *elements, size_t maxsize) +{ + struct apple_dcp *dcp = dev_get_drvdata(dev); + struct audiosrv_data *asrv = dcp->audiosrv; + size_t size; + int ret; + + down_write(&asrv->srv_rwsem); + ret = dcp_audiosrv_osobject_call(asrv->srv, 1, 18, elements, maxsize, &size); + up_write(&asrv->srv_rwsem); + + if (ret) + dev_err(dev, "audiosrv: error getting elements: %d\n", ret); + else + dev_dbg(dev, "audiosrv: got %zd bytes worth of elements\n", size); + + return ret; +} +EXPORT_SYMBOL_GPL(dcp_audiosrv_get_elements); + +int dcp_audiosrv_get_product_attrs(struct device *dev, void *attrs, size_t maxsize) +{ + struct apple_dcp *dcp = dev_get_drvdata(dev); + struct audiosrv_data *asrv = dcp->audiosrv; + size_t size; + int ret; + + down_write(&asrv->srv_rwsem); + ret = dcp_audiosrv_osobject_call(asrv->srv, 1, 20, attrs, maxsize, &size); + up_write(&asrv->srv_rwsem); + + if (ret) + dev_err(dev, "audiosrv: error getting product attributes: %d\n", ret); + else + dev_dbg(dev, "audiosrv: got %zd bytes worth of product attributes\n", size); + + return ret; +} +EXPORT_SYMBOL_GPL(dcp_audiosrv_get_product_attrs); + +static int av_audiosrv_report(struct apple_epic_service *service, u32 idx, + const void *data, size_t data_size) +{ + dev_dbg(service->ep->dcp->dev, "got audio report %d size %zx\n", idx, data_size); +#ifdef DEBUG + print_hex_dump(KERN_DEBUG, "audio report: ", DUMP_PREFIX_NONE, 16, 1, data, data_size, true); +#endif + + return 0; +} + +static const struct apple_epic_service_ops avep_ops[] = { + { + .name = "DCPAVSimpleVideoInterface", + .init = av_interface_init, + }, + { + .name = "DCPAVAudioInterface", + .init = av_audiosrv_init, + .report = av_audiosrv_report, + .teardown = av_audiosrv_teardown, + }, + {} +}; + +int avep_init(struct apple_dcp *dcp) +{ + struct dcp_audio_pdata *audio_pdata; + struct platform_device *audio_pdev; + struct audiosrv_data *audiosrv_data; + struct device *dev = dcp->dev; + + audiosrv_data = devm_kzalloc(dcp->dev, sizeof(*audiosrv_data), GFP_KERNEL); + audio_pdata = devm_kzalloc(dcp->dev, sizeof(*audio_pdata), GFP_KERNEL); + if (!audiosrv_data || !audio_pdata) + return -ENOMEM; + init_rwsem(&audiosrv_data->srv_rwsem); + mutex_init(&audiosrv_data->plug_lock); + dcp->audiosrv = audiosrv_data; + + audio_pdata->dcp_dev = dcp->dev; + /* TODO: free OF reference */ + audio_pdata->dpaudio_node = \ + of_parse_phandle(dev->of_node, "apple,audio-xmitter", 0); + if (!audio_pdata->dpaudio_node || + !of_device_is_available(audio_pdata->dpaudio_node)) { + dev_info(dev, "No audio support\n"); + return 0; + } + + audio_pdev = platform_device_register_data(dev, "dcp-hdmi-audio", + PLATFORM_DEVID_AUTO, + audio_pdata, sizeof(*audio_pdata)); + if (IS_ERR(audio_pdev)) + return dev_err_probe(dev, PTR_ERR(audio_pdev), "registering audio device\n"); + + dcp->avep = afk_init(dcp, AV_ENDPOINT, avep_ops); + if (IS_ERR(dcp->avep)) + return PTR_ERR(dcp->avep); + dcp->avep->debugfs_entry = dcp->ep_debugfs[AV_ENDPOINT - 0x20]; + return afk_start(dcp->avep); +} diff --git a/drivers/gpu/drm/apple/av.h b/drivers/gpu/drm/apple/av.h new file mode 100644 index 00000000000000..b1f92fb5d07f90 --- /dev/null +++ b/drivers/gpu/drm/apple/av.h @@ -0,0 +1,9 @@ +#ifndef __AV_H__ +#define __AV_H__ + +#include "parser.h" + +//int avep_audiosrv_startlink(struct apple_dcp *dcp, struct dcp_sound_cookie *cookie); +//int avep_audiosrv_stoplink(struct apple_dcp *dcp); + +#endif /* __AV_H__ */ diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index a3991aab78df5d..b8df2f5c6e022b 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -34,6 +34,7 @@ enum { TEST_ENDPOINT = 0x21, DCP_EXPERT_ENDPOINT = 0x22, DISP0_ENDPOINT = 0x23, + AV_ENDPOINT = 0x29, DPTX_ENDPOINT = 0x2a, HDCP_ENDPOINT = 0x2b, REMOTE_ALLOC_ENDPOINT = 0x2d, @@ -89,6 +90,8 @@ struct dcp_brightness { bool update; }; +struct audiosrv_data; + /** laptop/AiO integrated panel parameters from DT */ struct dcp_panel { /// panel width in millimeter @@ -223,6 +226,9 @@ struct apple_dcp { struct apple_dcp_afkep *ibootep; + struct apple_dcp_afkep *avep; + struct audiosrv_data *audiosrv; + struct apple_dcp_afkep *dptxep; struct dptx_port dptxport[2]; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 82590dce9493b7..88d46043581f2b 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,10 @@ static bool show_notch; module_param(show_notch, bool, 0644); MODULE_PARM_DESC(show_notch, "Use the full display height and shows the notch"); +static bool noaudio; +module_param(noaudio, bool, 0644); +MODULE_PARM_DESC(noaudio, "Skip audio support"); + /* HACK: moved here to avoid circular dependency between apple_drv and dcp */ void dcp_drm_crtc_vblank(struct apple_crtc *crtc) { @@ -118,6 +123,9 @@ static void dcp_recv_msg(void *cookie, u8 endpoint, u64 message) switch (endpoint) { case IOMFB_ENDPOINT: return iomfb_recv_msg(dcp, message); + case AV_ENDPOINT: + afk_receive_message(dcp->avep, message); + return; case SYSTEM_ENDPOINT: afk_receive_message(dcp->systemep, message); return; @@ -363,6 +371,14 @@ int dcp_start(struct platform_device *pdev) if (ret) dev_warn(dcp->dev, "Failed to start system endpoint: %d\n", ret); +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) + if (!noaudio) { + ret = avep_init(dcp); + if (ret) + dev_warn(dcp->dev, "Failed to start AV endpoint: %d", ret); + } +#endif + if (dcp->phy && dcp->fw_compat >= DCP_FIRMWARE_V_13_5) { ret = ibootep_init(dcp); if (ret) diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index 557d42c1d87523..257439118f0c83 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -60,4 +60,6 @@ void iomfb_recv_msg(struct apple_dcp *dcp, u64 message); int systemep_init(struct apple_dcp *dcp); int dptxep_init(struct apple_dcp *dcp); int ibootep_init(struct apple_dcp *dcp); +int avep_init(struct apple_dcp *dcp); + #endif From bc804b4e6e66b926147090bf4b56a59c969c9962 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 13 Nov 2023 21:59:46 +0100 Subject: [PATCH 189/352] drm: apple: av: Support macOS 12.3 and 13.5 firmware APIs Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/av.c | 74 +++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index bd4c7ec51bdb7d..a00932476da3ab 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -11,6 +11,39 @@ #include "audio.h" #include "afk.h" #include "dcp.h" +#include "dcp-internal.h" + +struct dcp_av_audio_cmds { + /* commands in group 0*/ + u32 open; + u32 prepare; + u32 start_link; + u32 stop_link; + u32 unprepare; + /* commands in group 1*/ + u32 get_elements; + u32 get_product_attrs; +}; + +static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v12_3 = { + .open = 6, + .prepare = 8, + .start_link = 9, + .stop_link = 12, + .unprepare = 13, + .get_elements = 18, + .get_product_attrs = 20, +}; + +static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v13_5 = { + .open = 4, + .prepare = 6, + .start_link = 7, + .stop_link = 10, + .unprepare = 11, + .get_elements = 16, + .get_product_attrs = 18, +}; struct audiosrv_data { struct device *audio_dev; @@ -20,6 +53,8 @@ struct audiosrv_data { struct apple_epic_service *srv; struct rw_semaphore srv_rwsem; + + struct dcp_av_audio_cmds cmds; }; static void av_interface_init(struct apple_epic_service *service, const char *name, @@ -41,7 +76,8 @@ static void av_audiosrv_init(struct apple_epic_service *service, const char *nam up_write(&asrv->srv_rwsem); /* TODO: this must be done elsewhere */ - err = afk_service_call(asrv->srv, 0, 6, NULL, 0, 32, NULL, 0, 32); + err = afk_service_call(asrv->srv, 0, asrv->cmds.open, NULL, 0, 32, NULL, + 0, 32); if (err) dev_err(dcp->dev, "error opening audio service: %d\n", err); @@ -93,8 +129,9 @@ int dcp_audiosrv_prepare(struct device *dev, struct dcp_sound_cookie *cookie) int ret; down_write(&asrv->srv_rwsem); - ret = afk_service_call(asrv->srv, 0, 8, cookie, sizeof(*cookie), - 64 - sizeof(*cookie), NULL, 0, 64); + ret = afk_service_call(asrv->srv, 0, asrv->cmds.prepare, cookie, + sizeof(*cookie), 64 - sizeof(*cookie), NULL, 0, + 64); up_write(&asrv->srv_rwsem); return ret; @@ -108,8 +145,9 @@ int dcp_audiosrv_startlink(struct device *dev, struct dcp_sound_cookie *cookie) int ret; down_write(&asrv->srv_rwsem); - ret = afk_service_call(asrv->srv, 0, 9, cookie, sizeof(*cookie), - 64 - sizeof(*cookie), NULL, 0, 64); + ret = afk_service_call(asrv->srv, 0, asrv->cmds.start_link, cookie, + sizeof(*cookie), 64 - sizeof(*cookie), NULL, 0, + 64); up_write(&asrv->srv_rwsem); return ret; @@ -123,7 +161,8 @@ int dcp_audiosrv_stoplink(struct device *dev) int ret; down_write(&asrv->srv_rwsem); - ret = afk_service_call(asrv->srv, 0, 12, NULL, 0, 64, NULL, 0, 64); + ret = afk_service_call(asrv->srv, 0, asrv->cmds.stop_link, NULL, 0, 64, + NULL, 0, 64); up_write(&asrv->srv_rwsem); return ret; @@ -137,7 +176,8 @@ int dcp_audiosrv_unprepare(struct device *dev) int ret; down_write(&asrv->srv_rwsem); - ret = afk_service_call(asrv->srv, 0, 13, NULL, 0, 64, NULL, 0, 64); + ret = afk_service_call(asrv->srv, 0, asrv->cmds.unprepare, NULL, 0, 64, + NULL, 0, 64); up_write(&asrv->srv_rwsem); return ret; @@ -188,7 +228,8 @@ int dcp_audiosrv_get_elements(struct device *dev, void *elements, size_t maxsize int ret; down_write(&asrv->srv_rwsem); - ret = dcp_audiosrv_osobject_call(asrv->srv, 1, 18, elements, maxsize, &size); + ret = dcp_audiosrv_osobject_call(asrv->srv, 1, asrv->cmds.get_elements, + elements, maxsize, &size); up_write(&asrv->srv_rwsem); if (ret) @@ -208,7 +249,9 @@ int dcp_audiosrv_get_product_attrs(struct device *dev, void *attrs, size_t maxsi int ret; down_write(&asrv->srv_rwsem); - ret = dcp_audiosrv_osobject_call(asrv->srv, 1, 20, attrs, maxsize, &size); + ret = dcp_audiosrv_osobject_call(asrv->srv, 1, + asrv->cmds.get_product_attrs, attrs, + maxsize, &size); up_write(&asrv->srv_rwsem); if (ret) @@ -258,6 +301,19 @@ int avep_init(struct apple_dcp *dcp) return -ENOMEM; init_rwsem(&audiosrv_data->srv_rwsem); mutex_init(&audiosrv_data->plug_lock); + + switch (dcp->fw_compat) { + case DCP_FIRMWARE_V_12_3: + audiosrv_data->cmds = dcp_av_audio_cmds_v12_3; + break; + case DCP_FIRMWARE_V_13_5: + audiosrv_data->cmds = dcp_av_audio_cmds_v13_5; + break; + default: + dev_err(dcp->dev, "Audio not supported for firmware\n"); + return -ENODEV; + } + dcp->audiosrv = audiosrv_data; audio_pdata->dcp_dev = dcp->dev; From e9f05f737be348fb914b928fb950002c05c20521 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 13 Nov 2023 23:00:13 +0100 Subject: [PATCH 190/352] drm: apple: av: Do not open AV service from afk receive handler Use a completion to do it from avep_init() instead. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/av.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index a00932476da3ab..5f3783221ac400 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -51,6 +51,7 @@ struct audiosrv_data { bool plugged; struct mutex plug_lock; + struct completion init_completion; struct apple_epic_service *srv; struct rw_semaphore srv_rwsem; @@ -67,7 +68,6 @@ static void av_audiosrv_init(struct apple_epic_service *service, const char *nam { struct apple_dcp *dcp = service->ep->dcp; struct audiosrv_data *asrv = dcp->audiosrv; - int err; mutex_lock(&asrv->plug_lock); @@ -75,16 +75,8 @@ static void av_audiosrv_init(struct apple_epic_service *service, const char *nam asrv->srv = service; up_write(&asrv->srv_rwsem); - /* TODO: this must be done elsewhere */ - err = afk_service_call(asrv->srv, 0, asrv->cmds.open, NULL, 0, 32, NULL, - 0, 32); - if (err) - dev_err(dcp->dev, "error opening audio service: %d\n", err); - + complete(&asrv->init_completion); asrv->plugged = true; - if (asrv->hotplug_cb) - asrv->hotplug_cb(asrv->audio_dev, true); - mutex_unlock(&asrv->plug_lock); } @@ -313,6 +305,7 @@ int avep_init(struct apple_dcp *dcp) dev_err(dcp->dev, "Audio not supported for firmware\n"); return -ENODEV; } + init_completion(&audiosrv_data->init_completion); dcp->audiosrv = audiosrv_data; @@ -337,4 +330,28 @@ int avep_init(struct apple_dcp *dcp) return PTR_ERR(dcp->avep); dcp->avep->debugfs_entry = dcp->ep_debugfs[AV_ENDPOINT - 0x20]; return afk_start(dcp->avep); + + ret = wait_for_completion_timeout(&dcp->audiosrv->init_completion, + msecs_to_jiffies(500)); + if (ret < 0) { + dev_err(dcp->dev, "error waiting on audio service init: %d\n", ret); + return ret; + } else if (!ret) { + dev_err(dcp->dev, "timeout while waiting for audio service init\n"); + return -ETIMEDOUT; + } + + /* open AV audio service */ + ret = afk_service_call(dcp->audiosrv->srv, 0, dcp->audiosrv->cmds.open, + NULL, 0, 32, NULL, 0, 32); + if (ret) { + dev_err(dcp->dev, "error opening audio service: %d\n", ret); + return ret; + } + + mutex_lock(&dcp->audiosrv->plug_lock); + if (dcp->audiosrv->hotplug_cb) + dcp->audiosrv->hotplug_cb(dcp->audiosrv->audio_dev, + dcp->audiosrv->plugged); + mutex_unlock(&dcp->audiosrv->plug_lock); } From d606f130bb6b0ea51b81d05d4d0cd4348b436068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 23 Feb 2023 12:49:43 +0100 Subject: [PATCH 191/352] gpu: drm: apple: Add DCP audio driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- drivers/gpu/drm/apple/Kconfig | 1 + drivers/gpu/drm/apple/Makefile | 4 + drivers/gpu/drm/apple/audio.c | 608 +++++++++++++++++++++++ drivers/gpu/drm/apple/hdmi-codec-chmap.h | 123 +++++ 4 files changed, 736 insertions(+) create mode 100644 drivers/gpu/drm/apple/audio.c create mode 100644 drivers/gpu/drm/apple/hdmi-codec-chmap.h diff --git a/drivers/gpu/drm/apple/Kconfig b/drivers/gpu/drm/apple/Kconfig index d8ae51282e5300..9828a5fa193284 100644 --- a/drivers/gpu/drm/apple/Kconfig +++ b/drivers/gpu/drm/apple/Kconfig @@ -20,6 +20,7 @@ config DRM_APPLE_AUDIO depends on DRM_APPLE depends on SND select SND_PCM + select SND_DMAENGINE_PCM config DRM_APPLE_DEBUG bool "Enable additional driver debugging" diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index 4c6d3947b024b1..1e9a892c750c77 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -12,6 +12,10 @@ apple_dcp-y += iomfb_v12_3.o apple_dcp-y += iomfb_v13_3.o apple_dcp-$(CONFIG_TRACING) += trace.o +apple_dcp_audio-y := audio.o obj-$(CONFIG_DRM_APPLE) += appledrm.o obj-$(CONFIG_DRM_APPLE) += apple_dcp.o +ifeq ($(CONFIG_DRM_APPLE_AUDIO),y) +obj-$(CONFIG_DRM_APPLE) += apple_dcp_audio.o +endif diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c new file mode 100644 index 00000000000000..223b033732216e --- /dev/null +++ b/drivers/gpu/drm/apple/audio.c @@ -0,0 +1,608 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * DCP Audio Bits + * + * Copyright (C) The Asahi Linux Contributors + * + * TODO: + * - figure some nice identification of the sound card (in case + * there's many DCP instances) + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "av.h" +#include "audio.h" +#include "parser.h" + +#define DCPAUD_ELEMENTS_MAXSIZE 16384 +#define DCPAUD_PRODUCTATTRS_MAXSIZE 1024 + +#define DRV_NAME "dcp-hdmi-audio" + +struct dcp_audio { + struct device *dev; + struct dcp_audio_pdata *pdata; + struct dma_chan *chan; + struct snd_card *card; + struct snd_jack *jack; + struct snd_pcm_substream *substream; + unsigned int open_cookie; + + struct mutex data_lock; + bool connected; + unsigned int connection_cookie; + + struct snd_pcm_chmap_elem selected_chmap; + struct dcp_sound_cookie selected_cookie; + void *elements; + void *productattrs; + + struct snd_pcm_chmap *chmap_info; +}; + +static const struct snd_pcm_hardware dcp_pcm_hw = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 0, + .rate_max = UINT_MAX, + .channels_min = 1, + .channels_max = 16, + .buffer_bytes_max = SIZE_MAX, + .period_bytes_min = 4096, /* TODO */ + .period_bytes_max = SIZE_MAX, + .periods_min = 2, + .periods_max = UINT_MAX, +}; + +static int dcpaud_read_remote_info(struct dcp_audio *dcpaud) +{ + int ret; + + ret = dcp_audiosrv_get_elements(dcpaud->pdata->dcp_dev, dcpaud->elements, + DCPAUD_ELEMENTS_MAXSIZE); + if (ret < 0) + return ret; + + ret = dcp_audiosrv_get_product_attrs(dcpaud->pdata->dcp_dev, dcpaud->productattrs, + DCPAUD_PRODUCTATTRS_MAXSIZE); + if (ret < 0) + return ret; + + return 0; +} + +static int dcpaud_interval_bitmask(struct snd_interval *i, + unsigned int mask) +{ + struct snd_interval range; + if (!mask) + return -EINVAL; + + snd_interval_any(&range); + range.min = __ffs(mask); + range.max = __fls(mask); + return snd_interval_refine(i, &range); +} + +extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; + +static void dcpaud_fill_fmt_sieve(struct snd_pcm_hw_params *params, + struct dcp_sound_format_mask *sieve) +{ + struct snd_interval *c = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *r = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_mask *f = hw_param_mask(params, + SNDRV_PCM_HW_PARAM_FORMAT); + int i; + + sieve->nchans = GENMASK(c->max, c->min); + sieve->formats = f->bits[0] | ((u64) f->bits[1]) << 32; /* TODO: don't open-code */ + + for (i = 0; i < snd_pcm_known_rates.count; i++) { + unsigned int rate = snd_pcm_known_rates.list[i]; + + if (snd_interval_test(r, rate)) + sieve->rates |= 1u << i; + } +} + +static void dcpaud_consult_elements(struct dcp_audio *dcpaud, + struct snd_pcm_hw_params *params, + struct dcp_sound_format_mask *hits) +{ + struct dcp_sound_format_mask sieve; + struct dcp_parse_ctx elements = { + .dcp = dev_get_drvdata(dcpaud->pdata->dcp_dev), + .blob = dcpaud->elements + 4, + .len = DCPAUD_ELEMENTS_MAXSIZE - 4, + .pos = 0, + }; + + dcpaud_fill_fmt_sieve(params, &sieve); + dev_dbg(dcpaud->dev, "elements in: %llx %x %x\n", sieve.formats, sieve.nchans, sieve.rates); + parse_sound_constraints(&elements, &sieve, hits); + dev_dbg(dcpaud->dev, "elements out: %llx %x %x\n", hits->formats, hits->nchans, hits->rates); +} + +static int dcpaud_select_cookie(struct dcp_audio *dcpaud, + struct snd_pcm_hw_params *params) +{ + struct dcp_sound_format_mask sieve; + struct dcp_parse_ctx elements = { + .dcp = dev_get_drvdata(dcpaud->pdata->dcp_dev), + .blob = dcpaud->elements + 4, + .len = DCPAUD_ELEMENTS_MAXSIZE - 4, + .pos = 0, + }; + + dcpaud_fill_fmt_sieve(params, &sieve); + return parse_sound_mode(&elements, &sieve, &dcpaud->selected_chmap, + &dcpaud->selected_cookie); +} + +static int dcpaud_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct dcp_audio *dcpaud = rule->private; + struct snd_interval *c = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct dcp_sound_format_mask hits = {0, 0, 0}; + + dcpaud_consult_elements(dcpaud, params, &hits); + + return dcpaud_interval_bitmask(c, hits.nchans); +} + +static int dcpaud_refine_fmt_mask(struct snd_mask *m, u64 mask) +{ + struct snd_mask mask_mask; + + if (!mask) + return -EINVAL; + mask_mask.bits[0] = mask; + mask_mask.bits[1] = mask >> 32; + + return snd_mask_refine(m, &mask_mask); +} + +static int dcpaud_rule_format(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct dcp_audio *dcpaud = rule->private; + struct snd_mask *f = hw_param_mask(params, + SNDRV_PCM_HW_PARAM_FORMAT); + struct dcp_sound_format_mask hits; + + dcpaud_consult_elements(dcpaud, params, &hits); + + return dcpaud_refine_fmt_mask(f, hits.formats); +} + +static int dcpaud_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct dcp_audio *dcpaud = rule->private; + struct snd_interval *r = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct dcp_sound_format_mask hits; + + dcpaud_consult_elements(dcpaud, params, &hits); + + return snd_interval_rate_bits(r, hits.rates); +} + +static int dcp_pcm_open(struct snd_pcm_substream *substream) +{ + struct dcp_audio *dcpaud = substream->pcm->private_data; + struct dma_chan *chan = dcpaud->chan; + struct snd_dmaengine_dai_dma_data dma_data = { + .flags = SND_DMAENGINE_PCM_DAI_FLAG_PACK, + }; + struct snd_pcm_hardware hw; + int ret; + + mutex_lock(&dcpaud->data_lock); + if (!dcpaud->connected) { + mutex_unlock(&dcpaud->data_lock); + return -ENXIO; + } + dcpaud->open_cookie = dcpaud->connection_cookie; + mutex_unlock(&dcpaud->data_lock); + + ret = dcpaud_read_remote_info(dcpaud); + if (ret < 0) + return ret; + + snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + dcpaud_rule_format, dcpaud, + SNDRV_PCM_HW_PARAM_CHANNELS, SNDRV_PCM_HW_PARAM_RATE, -1); + snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + dcpaud_rule_channels, dcpaud, + SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_RATE, -1); + snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + dcpaud_rule_rate, dcpaud, + SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS, -1); + + hw = dcp_pcm_hw; + hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED; + hw.periods_min = 2; + hw.periods_max = UINT_MAX; + hw.period_bytes_min = 256; + hw.period_bytes_max = SIZE_MAX; // TODO dma_get_max_seg_size(dma_dev); + hw.buffer_bytes_max = SIZE_MAX; + hw.fifo_size = 16; + ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, &dma_data, + &hw, chan); + if (ret) + return ret; + substream->runtime->hw = hw; + + return snd_dmaengine_pcm_open(substream, chan); +} + +static int dcp_pcm_close(struct snd_pcm_substream *substream) +{ + struct dcp_audio *dcpaud = substream->pcm->private_data; + dcpaud->selected_chmap.channels = 0; + + return snd_dmaengine_pcm_close(substream); +} + +static int dcpaud_connection_up(struct dcp_audio *dcpaud) +{ + bool ret; + mutex_lock(&dcpaud->data_lock); + ret = dcpaud->connected && + dcpaud->open_cookie == dcpaud->connection_cookie; + mutex_unlock(&dcpaud->data_lock); + return ret; +} + +static int dcp_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct dcp_audio *dcpaud = substream->pcm->private_data; + struct dma_slave_config slave_config; + struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); + int ret; + + if (!dcpaud_connection_up(dcpaud)) + return -ENXIO; + + ret = dcpaud_select_cookie(dcpaud, params); + if (ret < 0) + return ret; + if (!ret) + return -EINVAL; + + memset(&slave_config, 0, sizeof(slave_config)); + ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config); + dev_info(dcpaud->dev, "snd_hwparams_to_dma_slave_config: %d\n", ret); + if (ret < 0) + return ret; + + slave_config.direction = DMA_MEM_TO_DEV; + /* + * The data entry from the DMA controller to the DPA peripheral + * is 32-bit wide no matter the actual sample size. + */ + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + ret = dmaengine_slave_config(chan, &slave_config); + dev_info(dcpaud->dev, "dmaengine_slave_config: %d\n", ret); + return ret; +} + +static int dcp_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct dcp_audio *dcpaud = substream->pcm->private_data; + + if (!dcpaud_connection_up(dcpaud)) + return 0; + + return dcp_audiosrv_unprepare(dcpaud->pdata->dcp_dev); +} + +static int dcp_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct dcp_audio *dcpaud = substream->pcm->private_data; + + if (!dcpaud_connection_up(dcpaud)) + return -ENXIO; + + return dcp_audiosrv_prepare(dcpaud->pdata->dcp_dev, + &dcpaud->selected_cookie); +} + +static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct dcp_audio *dcpaud = substream->pcm->private_data; + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + if (!dcpaud_connection_up(dcpaud)) + return -ENXIO; + + ret = dcp_audiosrv_startlink(dcpaud->pdata->dcp_dev, + &dcpaud->selected_cookie); + if (ret < 0) + return ret; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + break; + + default: + return -EINVAL; + } + + ret = snd_dmaengine_pcm_trigger(substream, cmd); + if (ret < 0) + return ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + ret = dcp_audiosrv_stoplink(dcpaud->pdata->dcp_dev); + if (ret < 0) + return ret; + break; + } + + return 0; +} + +struct snd_pcm_ops dcp_playback_ops = { + .open = dcp_pcm_open, + .close = dcp_pcm_close, + .hw_params = dcp_pcm_hw_params, + .hw_free = dcp_pcm_hw_free, + .prepare = dcp_pcm_prepare, + .trigger = dcp_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer, +}; + +// Transitional workaround: for the chmap control TLV, advertise options +// copied from hdmi-codec.c +#include "hdmi-codec-chmap.h" + +static int dcpaud_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct dcp_audio *dcpaud = info->private_data; + unsigned int i; + + for (i = 0; i < info->max_channels; i++) + ucontrol->value.integer.value[i] = \ + (i < dcpaud->selected_chmap.channels) ? + dcpaud->selected_chmap.map[i] : SNDRV_CHMAP_UNKNOWN; + + return 0; +} + + +static int dcpaud_create_chmap_ctl(struct dcp_audio *dcpaud) +{ + struct snd_pcm *pcm = dcpaud->substream->pcm; + struct snd_pcm_chmap *chmap_info; + int ret; + + ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, NULL, + dcp_pcm_hw.channels_max, 0, &chmap_info); + if (ret < 0) + return ret; + + chmap_info->kctl->get = dcpaud_chmap_ctl_get; + chmap_info->chmap = hdmi_codec_8ch_chmaps; + chmap_info->private_data = dcpaud; + + return 0; +} + +static int dcpaud_create_pcm(struct dcp_audio *dcpaud) +{ + struct snd_card *card = dcpaud->card; + struct snd_pcm *pcm; + struct dma_chan *chan; + int ret; + + chan = of_dma_request_slave_channel(dcpaud->pdata->dpaudio_node, "tx"); + if (IS_ERR_OR_NULL(chan)) { + if (!chan) + return -EINVAL; + + dev_err(dcpaud->dev, "can't request audio TX DMA channel: %pE\n", chan); + return PTR_ERR(chan); + } + dcpaud->chan = chan; + +#define NUM_PLAYBACK 1 +#define NUM_CAPTURE 0 + + ret = snd_pcm_new(card, card->shortname, 0, NUM_PLAYBACK, NUM_CAPTURE, &pcm); + if (ret) + return ret; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dcp_playback_ops); + dcpaud->substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM, + chan->device->dev, 1024 * 1024, + SIZE_MAX); + + pcm->nonatomic = true; + pcm->private_data = dcpaud; + strscpy(pcm->name, card->shortname, sizeof(pcm->name)); + + return 0; +} + +static void dcpaud_report_hotplug(struct device *dev, bool connected) +{ + struct dcp_audio *dcpaud = dev_get_drvdata(dev); + struct snd_pcm_substream *substream = dcpaud->substream; + + mutex_lock(&dcpaud->data_lock); + if (dcpaud->connected == connected) { + mutex_unlock(&dcpaud->data_lock); + return; + } + + dcpaud->connected = connected; + if (connected) + dcpaud->connection_cookie++; + mutex_unlock(&dcpaud->data_lock); + + snd_jack_report(dcpaud->jack, connected ? SND_JACK_AVOUT : 0); + + if (!connected) { + snd_pcm_stream_lock(substream); + snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + snd_pcm_stream_unlock(substream); + } +} + +static int dcpaud_create_jack(struct dcp_audio *dcpaud) +{ + struct snd_card *card = dcpaud->card; + + return snd_jack_new(card, "HDMI/DP", SND_JACK_AVOUT, + &dcpaud->jack, true, false); +} + +static void dcpaud_set_card_names(struct dcp_audio *dcpaud) +{ + struct snd_card *card = dcpaud->card; + + strscpy(card->driver, "apple_dcp", sizeof(card->driver)); + strscpy(card->longname, "Apple DisplayPort", sizeof(card->longname)); + strscpy(card->shortname, "Apple DisplayPort", sizeof(card->shortname)); +} + +#ifdef CONFIG_SND_DEBUG +static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) +{ + struct debugfs_blob_wrapper *wrapper; + wrapper = devm_kzalloc(dcpaud->dev, sizeof(*wrapper), GFP_KERNEL); + if (!wrapper) + return; + wrapper->data = base; + wrapper->size = size; + debugfs_create_blob(name, 0600, dcpaud->card->debugfs_root, wrapper); +} +#else +static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) {} +#endif + +static int dcpaud_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dcp_audio_pdata *pdata = dev->platform_data; + struct dcp_audio *dcpaud; + int ret; + + dcpaud = devm_kzalloc(dev, sizeof(*dcpaud), GFP_KERNEL); + if (!dcpaud) + return -ENOMEM; + dcpaud->dev = dev; + dcpaud->pdata = pdata; + mutex_init(&dcpaud->data_lock); + platform_set_drvdata(pdev, dcpaud); + + dcpaud->elements = devm_kzalloc(dev, DCPAUD_ELEMENTS_MAXSIZE, + GFP_KERNEL); + if (!dcpaud->elements) + return -ENOMEM; + + dcpaud->productattrs = devm_kzalloc(dev, DCPAUD_PRODUCTATTRS_MAXSIZE, + GFP_KERNEL); + if (!dcpaud->productattrs) + return -ENOMEM; + + ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &dcpaud->card); + if (ret) + return ret; + + dcpaud_set_card_names(dcpaud); + + ret = dcpaud_create_pcm(dcpaud); + if (ret) + goto err_free_card; + + ret = dcpaud_create_chmap_ctl(dcpaud); + if (ret) + goto err_free_card; + + ret = dcpaud_create_jack(dcpaud); + if (ret) + goto err_free_card; + + ret = snd_card_register(dcpaud->card); + if (ret) + goto err_free_card; + + dcpaud_expose_debugfs_blob(dcpaud, "selected_cookie", &dcpaud->selected_cookie, + sizeof(dcpaud->selected_cookie)); + dcpaud_expose_debugfs_blob(dcpaud, "elements", dcpaud->elements, + DCPAUD_ELEMENTS_MAXSIZE); + dcpaud_expose_debugfs_blob(dcpaud, "product_attrs", dcpaud->productattrs, + DCPAUD_PRODUCTATTRS_MAXSIZE); + + dcp_audiosrv_set_hotplug_cb(pdata->dcp_dev, dev, dcpaud_report_hotplug); + + return 0; + +err_free_card: + snd_card_free(dcpaud->card); + return ret; +} + +static int dcpaud_remove(struct platform_device *dev) +{ + struct dcp_audio *dcpaud = platform_get_drvdata(dev); + + dcp_audiosrv_set_hotplug_cb(dcpaud->pdata->dcp_dev, NULL, NULL); + snd_card_free(dcpaud->card); + + return 0; +} + +static struct platform_driver dcpaud_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = dcpaud_probe, + .remove = dcpaud_remove, +}; + +module_platform_driver(dcpaud_driver); + +MODULE_AUTHOR("Martin Povišer "); +MODULE_DESCRIPTION("Apple DCP HDMI Audio Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/gpu/drm/apple/hdmi-codec-chmap.h b/drivers/gpu/drm/apple/hdmi-codec-chmap.h new file mode 100644 index 00000000000000..f98e1e86b89602 --- /dev/null +++ b/drivers/gpu/drm/apple/hdmi-codec-chmap.h @@ -0,0 +1,123 @@ +// copied from sound/soc/codecs/hdmi-codec.c + +#include + +/* Channel maps for multi-channel playbacks, up to 8 n_ch */ +static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { + { .channels = 2, /* CA_ID 0x00 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { .channels = 4, /* CA_ID 0x01 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA } }, + { .channels = 4, /* CA_ID 0x02 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC } }, + { .channels = 4, /* CA_ID 0x03 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC } }, + { .channels = 6, /* CA_ID 0x04 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x05 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x06 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x07 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 6, /* CA_ID 0x08 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x09 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x0A */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 6, /* CA_ID 0x0B */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, + { .channels = 8, /* CA_ID 0x0C */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0D */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0E */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x0F */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } }, + { .channels = 8, /* CA_ID 0x10 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x11 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x12 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x13 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, + SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } }, + { .channels = 8, /* CA_ID 0x14 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x15 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x16 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x17 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x18 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x19 */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1A */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1B */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1C */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1D */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1E */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { .channels = 8, /* CA_ID 0x1F */ + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE, + SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, + SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } }, + { } +}; From ff72a3e1dda8fe7ebd483ab2f348cecc97c1b981 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 14 Apr 2024 16:22:25 +0200 Subject: [PATCH 192/352] drm: apple: dptx: Remove DPTX disconnect/connect on init This was only necessary for dcp0 on M2* devices presumably because the reset in m1n1 doesn't work as intended. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 88d46043581f2b..f5a0e537ec72f1 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -386,10 +386,17 @@ int dcp_start(struct platform_device *pdev) ret); ret = dptxep_init(dcp); - if (ret) + if (ret) { dev_warn(dcp->dev, "Failed to start DPTX endpoint: %d\n", ret); - else if (dcp->dptxport[0].enabled) { +#ifdef DCP_DPTX_DISCONNECT_ON_INIT + /* + * This disconnect / connect cycle on init is only necessary + * when using dcp0 on j473, j474s and presumedly j475c. + * Since dcp0 is not used at the moment let's avoid this + * since it is possibly the cause for startup issues. + */ + } else if (dcp->dptxport[0].enabled) { bool connected; /* force disconnect on start - necessary if the display * is already up from m1n1 @@ -404,10 +411,11 @@ int dcp_start(struct platform_device *pdev) // necessary on j473/j474 but not on j314c if (connected) dcp_dptx_connect(dcp, 0); +#endif } - } else if (dcp->phy) + } else if (dcp->phy) { dev_warn(dcp->dev, "OS firmware incompatible with dptxport EP\n"); - + } ret = iomfb_start_rtkit(dcp); if (ret) dev_err(dcp->dev, "Failed to start IOMFB endpoint: %d\n", ret); From 5c6c15fe4451875785b7d76b59a3dc3ff8cb90cb Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 14 Apr 2024 16:47:01 +0200 Subject: [PATCH 193/352] drm: apple: audio: init AV endpoint later This seems to get rid of initialization timeouts / failures. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index f5a0e537ec72f1..da7f5b814986fe 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -371,14 +371,6 @@ int dcp_start(struct platform_device *pdev) if (ret) dev_warn(dcp->dev, "Failed to start system endpoint: %d\n", ret); -#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) - if (!noaudio) { - ret = avep_init(dcp); - if (ret) - dev_warn(dcp->dev, "Failed to start AV endpoint: %d", ret); - } -#endif - if (dcp->phy && dcp->fw_compat >= DCP_FIRMWARE_V_13_5) { ret = ibootep_init(dcp); if (ret) @@ -420,6 +412,15 @@ int dcp_start(struct platform_device *pdev) if (ret) dev_err(dcp->dev, "Failed to start IOMFB endpoint: %d\n", ret); +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) + if (!noaudio) { + ret = avep_init(dcp); + if (ret) + dev_warn(dcp->dev, "Failed to start AV endpoint: %d", ret); + ret = 0; + } +#endif + return ret; } EXPORT_SYMBOL(dcp_start); From f565cf3b663e6ae00dbeb5989d082ae18e0cfec5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 20 Apr 2024 21:00:37 +0200 Subject: [PATCH 194/352] drm: apple: av: Use a workqueue Functionally a revert of "drm: apple: av: Do not open AV service from afk receive handler" with more workqueues. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/av.c | 63 ++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index 5f3783221ac400..926c4b238227b1 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "audio.h" #include "afk.h" @@ -51,9 +52,10 @@ struct audiosrv_data { bool plugged; struct mutex plug_lock; - struct completion init_completion; struct apple_epic_service *srv; struct rw_semaphore srv_rwsem; + /* Workqueue for starting the audio service */ + struct work_struct start_av_service_wq; struct dcp_av_audio_cmds cmds; }; @@ -75,9 +77,9 @@ static void av_audiosrv_init(struct apple_epic_service *service, const char *nam asrv->srv = service; up_write(&asrv->srv_rwsem); - complete(&asrv->init_completion); asrv->plugged = true; mutex_unlock(&asrv->plug_lock); + schedule_work(&asrv->start_av_service_wq); } static void av_audiosrv_teardown(struct apple_epic_service *service) @@ -280,6 +282,37 @@ static const struct apple_epic_service_ops avep_ops[] = { {} }; +static void av_work_service_start(struct work_struct *work) +{ + int ret; + struct audiosrv_data *audiosrv_data; + struct apple_dcp *dcp; + + audiosrv_data = container_of(work, struct audiosrv_data, start_av_service_wq); + if (!audiosrv_data->srv || + !audiosrv_data->srv->ep || + !audiosrv_data->srv->ep->dcp) { + pr_err("%s: dcp: av: NULL ptr during startup\n", __func__); + return; + } + dcp = audiosrv_data->srv->ep->dcp; + + /* open AV audio service */ + dev_info(dcp->dev, "%s: starting audio service\n", __func__); + ret = afk_service_call(dcp->audiosrv->srv, 0, dcp->audiosrv->cmds.open, + NULL, 0, 32, NULL, 0, 32); + if (ret) { + dev_err(dcp->dev, "error opening audio service: %d\n", ret); + return; + } + + mutex_lock(&dcp->audiosrv->plug_lock); + if (dcp->audiosrv->hotplug_cb) + dcp->audiosrv->hotplug_cb(dcp->audiosrv->audio_dev, + dcp->audiosrv->plugged); + mutex_unlock(&dcp->audiosrv->plug_lock); +} + int avep_init(struct apple_dcp *dcp) { struct dcp_audio_pdata *audio_pdata; @@ -305,7 +338,7 @@ int avep_init(struct apple_dcp *dcp) dev_err(dcp->dev, "Audio not supported for firmware\n"); return -ENODEV; } - init_completion(&audiosrv_data->init_completion); + INIT_WORK(&audiosrv_data->start_av_service_wq, av_work_service_start); dcp->audiosrv = audiosrv_data; @@ -330,28 +363,4 @@ int avep_init(struct apple_dcp *dcp) return PTR_ERR(dcp->avep); dcp->avep->debugfs_entry = dcp->ep_debugfs[AV_ENDPOINT - 0x20]; return afk_start(dcp->avep); - - ret = wait_for_completion_timeout(&dcp->audiosrv->init_completion, - msecs_to_jiffies(500)); - if (ret < 0) { - dev_err(dcp->dev, "error waiting on audio service init: %d\n", ret); - return ret; - } else if (!ret) { - dev_err(dcp->dev, "timeout while waiting for audio service init\n"); - return -ETIMEDOUT; - } - - /* open AV audio service */ - ret = afk_service_call(dcp->audiosrv->srv, 0, dcp->audiosrv->cmds.open, - NULL, 0, 32, NULL, 0, 32); - if (ret) { - dev_err(dcp->dev, "error opening audio service: %d\n", ret); - return ret; - } - - mutex_lock(&dcp->audiosrv->plug_lock); - if (dcp->audiosrv->hotplug_cb) - dcp->audiosrv->hotplug_cb(dcp->audiosrv->audio_dev, - dcp->audiosrv->plugged); - mutex_unlock(&dcp->audiosrv->plug_lock); } From 9fafe3caf2de487e39330cabbfdfa77d9dfddb5b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 20 Apr 2024 21:06:19 +0200 Subject: [PATCH 195/352] drm: apple: audio: move the audio driver into the DCP module Those two drivers are closely linked and should always exists together. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Makefile | 6 +----- drivers/gpu/drm/apple/audio.c | 14 +++++++++----- drivers/gpu/drm/apple/dcp.c | 22 +++++++++++++++++++++- drivers/gpu/drm/apple/dcp.h | 4 ++++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index 1e9a892c750c77..b3b3026fdc60ca 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -5,6 +5,7 @@ CFLAGS_trace.o = -I$(src) appledrm-y := apple_drv.o apple_dcp-y := afk.o dcp.o dcp_backlight.o dptxep.o iomfb.o parser.o systemep.o +apple_dcp-$(CONFIG_DRM_APPLE_AUDIO) += audio.o apple_dcp-$(CONFIG_DRM_APPLE_AUDIO) += av.o apple_dcp-y += connector.o apple_dcp-y += ibootep.o @@ -12,10 +13,5 @@ apple_dcp-y += iomfb_v12_3.o apple_dcp-y += iomfb_v13_3.o apple_dcp-$(CONFIG_TRACING) += trace.o -apple_dcp_audio-y := audio.o - obj-$(CONFIG_DRM_APPLE) += appledrm.o obj-$(CONFIG_DRM_APPLE) += apple_dcp.o -ifeq ($(CONFIG_DRM_APPLE_AUDIO),y) -obj-$(CONFIG_DRM_APPLE) += apple_dcp_audio.o -endif diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c index 223b033732216e..e997a6deae7b69 100644 --- a/drivers/gpu/drm/apple/audio.c +++ b/drivers/gpu/drm/apple/audio.c @@ -600,9 +600,13 @@ static struct platform_driver dcpaud_driver = { .remove = dcpaud_remove, }; -module_platform_driver(dcpaud_driver); +void __init dcp_audio_register(void) +{ + platform_driver_register(&dcpaud_driver); +} + +void __exit dcp_audio_unregister(void) +{ + platform_driver_unregister(&dcpaud_driver); +} -MODULE_AUTHOR("Martin Povišer "); -MODULE_DESCRIPTION("Apple DCP HDMI Audio Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index da7f5b814986fe..cc75e8e919d663 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -1138,7 +1138,27 @@ static struct platform_driver apple_platform_driver = { }, }; -drm_module_platform_driver(apple_platform_driver); +static int __init apple_dcp_register(void) +{ + if (drm_firmware_drivers_only()) + return -ENODEV; + +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) + dcp_audio_register(); +#endif + return platform_driver_register(&apple_platform_driver); +} + +static void __exit apple_dcp_unregister(void) +{ + platform_driver_unregister(&apple_platform_driver); +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) + dcp_audio_unregister(); +#endif +} + +module_init(apple_dcp_register); +module_exit(apple_dcp_unregister); MODULE_AUTHOR("Asahi Linux contributors"); MODULE_DESCRIPTION("Apple Display Controller DRM driver"); diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index 257439118f0c83..866a1a87d3fd7b 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -62,4 +62,8 @@ int dptxep_init(struct apple_dcp *dcp); int ibootep_init(struct apple_dcp *dcp); int avep_init(struct apple_dcp *dcp); + +void __init dcp_audio_register(void); +void __exit dcp_audio_unregister(void); + #endif From 9555a787c5480fe8fa6677b710491e8b65ef77f5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Apr 2024 15:47:20 +0200 Subject: [PATCH 196/352] drm: apple: audio: Make the DP/HDMI audio driver a full driver The main advantage is that it allows runtime PM which would have been manually implemented with the ad-hoc instantiated platform driver. This also probes the devices as component of the DRM driver which allows to simplify the the interface between the av endpoint and the audio driver. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 20 +++- drivers/gpu/drm/apple/audio.c | 149 +++++++++++++++++++++--------- drivers/gpu/drm/apple/audio.h | 14 +-- drivers/gpu/drm/apple/av.c | 71 ++++++-------- 4 files changed, 155 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 8a995bea255e4b..a91aa39690541b 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -575,7 +576,7 @@ const struct component_master_ops apple_drm_ops = { static int add_dcp_components(struct device *dev, struct component_match **matchptr) { - struct device_node *np; + struct device_node *np, *endpoint, *port; int num = 0; for_each_matching_node(np, apple_dcp_id_tbl) { @@ -583,6 +584,23 @@ static int add_dcp_components(struct device *dev, drm_of_component_match_add(dev, matchptr, component_compare_of, np); num++; + for_each_endpoint_of_node(np, endpoint) { + port = of_graph_get_remote_port_parent(endpoint); + if (!port) + continue; + +#if !IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) + if (of_device_is_compatible(port, "apple,dpaudio")) { + of_node_put(port); + continue; + } +#endif + if (of_device_is_available(port)) + drm_of_component_match_add(dev, matchptr, + component_compare_of, + port); + of_node_put(port); + } } of_node_put(np); } diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c index e997a6deae7b69..b4a860d198c32b 100644 --- a/drivers/gpu/drm/apple/audio.c +++ b/drivers/gpu/drm/apple/audio.c @@ -11,9 +11,12 @@ #define DEBUG +#include #include #include #include +#include +#include #include #include #include @@ -22,17 +25,16 @@ #include #include "av.h" +#include "dcp.h" #include "audio.h" #include "parser.h" #define DCPAUD_ELEMENTS_MAXSIZE 16384 #define DCPAUD_PRODUCTATTRS_MAXSIZE 1024 -#define DRV_NAME "dcp-hdmi-audio" - struct dcp_audio { struct device *dev; - struct dcp_audio_pdata *pdata; + struct device *dcp_dev; struct dma_chan *chan; struct snd_card *card; struct snd_jack *jack; @@ -72,12 +74,12 @@ static int dcpaud_read_remote_info(struct dcp_audio *dcpaud) { int ret; - ret = dcp_audiosrv_get_elements(dcpaud->pdata->dcp_dev, dcpaud->elements, + ret = dcp_audiosrv_get_elements(dcpaud->dcp_dev, dcpaud->elements, DCPAUD_ELEMENTS_MAXSIZE); if (ret < 0) return ret; - ret = dcp_audiosrv_get_product_attrs(dcpaud->pdata->dcp_dev, dcpaud->productattrs, + ret = dcp_audiosrv_get_product_attrs(dcpaud->dcp_dev, dcpaud->productattrs, DCPAUD_PRODUCTATTRS_MAXSIZE); if (ret < 0) return ret; @@ -128,7 +130,7 @@ static void dcpaud_consult_elements(struct dcp_audio *dcpaud, { struct dcp_sound_format_mask sieve; struct dcp_parse_ctx elements = { - .dcp = dev_get_drvdata(dcpaud->pdata->dcp_dev), + .dcp = dev_get_drvdata(dcpaud->dcp_dev), .blob = dcpaud->elements + 4, .len = DCPAUD_ELEMENTS_MAXSIZE - 4, .pos = 0, @@ -145,7 +147,7 @@ static int dcpaud_select_cookie(struct dcp_audio *dcpaud, { struct dcp_sound_format_mask sieve; struct dcp_parse_ctx elements = { - .dcp = dev_get_drvdata(dcpaud->pdata->dcp_dev), + .dcp = dev_get_drvdata(dcpaud->dcp_dev), .blob = dcpaud->elements + 4, .len = DCPAUD_ELEMENTS_MAXSIZE - 4, .pos = 0, @@ -317,7 +319,7 @@ static int dcp_pcm_hw_free(struct snd_pcm_substream *substream) if (!dcpaud_connection_up(dcpaud)) return 0; - return dcp_audiosrv_unprepare(dcpaud->pdata->dcp_dev); + return dcp_audiosrv_unprepare(dcpaud->dcp_dev); } static int dcp_pcm_prepare(struct snd_pcm_substream *substream) @@ -327,7 +329,7 @@ static int dcp_pcm_prepare(struct snd_pcm_substream *substream) if (!dcpaud_connection_up(dcpaud)) return -ENXIO; - return dcp_audiosrv_prepare(dcpaud->pdata->dcp_dev, + return dcp_audiosrv_prepare(dcpaud->dcp_dev, &dcpaud->selected_cookie); } @@ -342,7 +344,7 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (!dcpaud_connection_up(dcpaud)) return -ENXIO; - ret = dcp_audiosrv_startlink(dcpaud->pdata->dcp_dev, + ret = dcp_audiosrv_startlink(dcpaud->dcp_dev, &dcpaud->selected_cookie); if (ret < 0) return ret; @@ -367,7 +369,7 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - ret = dcp_audiosrv_stoplink(dcpaud->pdata->dcp_dev); + ret = dcp_audiosrv_stoplink(dcpaud->dcp_dev); if (ret < 0) return ret; break; @@ -431,7 +433,7 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud) struct dma_chan *chan; int ret; - chan = of_dma_request_slave_channel(dcpaud->pdata->dpaudio_node, "tx"); + chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx"); if (IS_ERR_OR_NULL(chan)) { if (!chan) return -EINVAL; @@ -461,9 +463,8 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud) return 0; } -static void dcpaud_report_hotplug(struct device *dev, bool connected) +static void dcpaud_report_hotplug(struct dcp_audio *dcpaud, bool connected) { - struct dcp_audio *dcpaud = dev_get_drvdata(dev); struct snd_pcm_substream *substream = dcpaud->substream; mutex_lock(&dcpaud->data_lock); @@ -518,30 +519,44 @@ static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *nam static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) {} #endif -static int dcpaud_probe(struct platform_device *pdev) +void dcpaud_connect(struct platform_device *pdev, bool connected) { - struct device *dev = &pdev->dev; - struct dcp_audio_pdata *pdata = dev->platform_data; - struct dcp_audio *dcpaud; - int ret; + struct dcp_audio *dcpaud = platform_get_drvdata(pdev); + dcpaud_report_hotplug(dcpaud, connected); +} - dcpaud = devm_kzalloc(dev, sizeof(*dcpaud), GFP_KERNEL); - if (!dcpaud) - return -ENOMEM; - dcpaud->dev = dev; - dcpaud->pdata = pdata; - mutex_init(&dcpaud->data_lock); - platform_set_drvdata(pdev, dcpaud); +void dcpaud_disconnect(struct platform_device *pdev) +{ + struct dcp_audio *dcpaud = platform_get_drvdata(pdev); + dcpaud_report_hotplug(dcpaud, false); +} - dcpaud->elements = devm_kzalloc(dev, DCPAUD_ELEMENTS_MAXSIZE, - GFP_KERNEL); - if (!dcpaud->elements) - return -ENOMEM; +static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) +{ + struct dcp_audio *dcpaud = dev_get_drvdata(dev); + struct device_node *endpoint, *dcp_node = NULL; + struct platform_device *dcp_pdev; + int ret; - dcpaud->productattrs = devm_kzalloc(dev, DCPAUD_PRODUCTATTRS_MAXSIZE, - GFP_KERNEL); - if (!dcpaud->productattrs) - return -ENOMEM; + /* find linked DCP instance */ + endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); + if (endpoint) { + dcp_node = of_graph_get_remote_port_parent(endpoint); + of_node_put(endpoint); + } + if (!dcp_node || !of_device_is_available(dcp_node)) { + of_node_put(dcp_node); + dev_info(dev, "No audio support\n"); + return 0; + } + + dcp_pdev = of_find_device_by_node(dcp_node); + of_node_put(dcp_node); + if (!dcp_pdev) { + dev_info(dev, "No DP/HDMI audio device not ready\n"); + return 0; + } + dcpaud->dcp_dev = &dcp_pdev->dev; ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, 0, &dcpaud->card); @@ -573,8 +588,6 @@ static int dcpaud_probe(struct platform_device *pdev) dcpaud_expose_debugfs_blob(dcpaud, "product_attrs", dcpaud->productattrs, DCPAUD_PRODUCTATTRS_MAXSIZE); - dcp_audiosrv_set_hotplug_cb(pdata->dcp_dev, dev, dcpaud_report_hotplug); - return 0; err_free_card: @@ -582,22 +595,70 @@ static int dcpaud_probe(struct platform_device *pdev) return ret; } -static int dcpaud_remove(struct platform_device *dev) +static void dcpaud_comp_unbind(struct device *dev, struct device *main, + void *data) { - struct dcp_audio *dcpaud = platform_get_drvdata(dev); + struct dcp_audio *dcpaud = dev_get_drvdata(dev); - dcp_audiosrv_set_hotplug_cb(dcpaud->pdata->dcp_dev, NULL, NULL); - snd_card_free(dcpaud->card); + /* snd_card_free_when_closed() checks for NULL */ + snd_card_free_when_closed(dcpaud->card); +} - return 0; +static const struct component_ops dcpaud_comp_ops = { + .bind = dcpaud_comp_bind, + .unbind = dcpaud_comp_unbind, +}; + +static int dcpaud_probe(struct platform_device *pdev) +{ + struct dcp_audio *dcpaud; + + dcpaud = devm_kzalloc(&pdev->dev, sizeof(*dcpaud), GFP_KERNEL); + if (!dcpaud) + return -ENOMEM; + + dcpaud->elements = devm_kzalloc(&pdev->dev, DCPAUD_ELEMENTS_MAXSIZE, + GFP_KERNEL); + if (!dcpaud->elements) + return -ENOMEM; + + dcpaud->productattrs = devm_kzalloc(&pdev->dev, DCPAUD_PRODUCTATTRS_MAXSIZE, + GFP_KERNEL); + if (!dcpaud->productattrs) + return -ENOMEM; + + dcpaud->dev = &pdev->dev; + mutex_init(&dcpaud->data_lock); + platform_set_drvdata(pdev, dcpaud); + + return component_add(&pdev->dev, &dcpaud_comp_ops); } +static void dcpaud_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &dcpaud_comp_ops); +} + +static void dcpaud_shutdown(struct platform_device *pdev) +{ + component_del(&pdev->dev, &dcpaud_comp_ops); +} + +// static DEFINE_SIMPLE_DEV_PM_OPS(dcpaud_pm_ops, dcpaud_suspend, dcpaud_resume); + +static const struct of_device_id dcpaud_of_match[] = { + { .compatible = "apple,dpaudio" }, + {} +}; + static struct platform_driver dcpaud_driver = { .driver = { - .name = DRV_NAME, + .name = "dcp-dp-audio", + .of_match_table = dcpaud_of_match, }, - .probe = dcpaud_probe, - .remove = dcpaud_remove, + .probe = dcpaud_probe, + .remove = dcpaud_remove, + .shutdown = dcpaud_shutdown, }; void __init dcp_audio_register(void) diff --git a/drivers/gpu/drm/apple/audio.h b/drivers/gpu/drm/apple/audio.h index 3cf4d31417694e..83b990dc6c343f 100644 --- a/drivers/gpu/drm/apple/audio.h +++ b/drivers/gpu/drm/apple/audio.h @@ -4,18 +4,9 @@ #include struct device; -struct device_node; +struct platform_device; struct dcp_sound_cookie; -typedef void (*dcp_audio_hotplug_callback)(struct device *dev, bool connected); - -struct dcp_audio_pdata { - struct device *dcp_dev; - struct device_node *dpaudio_node; -}; - -void dcp_audiosrv_set_hotplug_cb(struct device *dev, struct device *audio_dev, - dcp_audio_hotplug_callback cb); int dcp_audiosrv_prepare(struct device *dev, struct dcp_sound_cookie *cookie); int dcp_audiosrv_startlink(struct device *dev, struct dcp_sound_cookie *cookie); int dcp_audiosrv_stoplink(struct device *dev); @@ -23,4 +14,7 @@ int dcp_audiosrv_unprepare(struct device *dev); int dcp_audiosrv_get_elements(struct device *dev, void *elements, size_t maxsize); int dcp_audiosrv_get_product_attrs(struct device *dev, void *attrs, size_t maxsize); +void dcpaud_connect(struct platform_device *pdev, bool connected); +void dcpaud_disconnect(struct platform_device *pdev); + #endif /* __AUDIO_H__ */ diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index 926c4b238227b1..66a99cb2ed7b0f 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include #include @@ -47,8 +49,7 @@ static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v13_5 = { }; struct audiosrv_data { - struct device *audio_dev; - dcp_audio_hotplug_callback hotplug_cb; + struct platform_device *audio_dev; bool plugged; struct mutex plug_lock; @@ -94,28 +95,12 @@ static void av_audiosrv_teardown(struct apple_epic_service *service) up_write(&asrv->srv_rwsem); asrv->plugged = false; - if (asrv->hotplug_cb) - asrv->hotplug_cb(asrv->audio_dev, false); + if (asrv->audio_dev) + dcpaud_disconnect(asrv->audio_dev); mutex_unlock(&asrv->plug_lock); } -void dcp_audiosrv_set_hotplug_cb(struct device *dev, struct device *audio_dev, - dcp_audio_hotplug_callback cb) -{ - struct apple_dcp *dcp = dev_get_drvdata(dev); - struct audiosrv_data *asrv = dcp->audiosrv; - - mutex_lock(&asrv->plug_lock); - asrv->audio_dev = audio_dev; - asrv->hotplug_cb = cb; - - if (cb) - cb(audio_dev, asrv->plugged); - mutex_unlock(&asrv->plug_lock); -} -EXPORT_SYMBOL_GPL(dcp_audiosrv_set_hotplug_cb); - int dcp_audiosrv_prepare(struct device *dev, struct dcp_sound_cookie *cookie) { struct apple_dcp *dcp = dev_get_drvdata(dev); @@ -130,7 +115,6 @@ int dcp_audiosrv_prepare(struct device *dev, struct dcp_sound_cookie *cookie) return ret; } -EXPORT_SYMBOL_GPL(dcp_audiosrv_prepare); int dcp_audiosrv_startlink(struct device *dev, struct dcp_sound_cookie *cookie) { @@ -146,7 +130,6 @@ int dcp_audiosrv_startlink(struct device *dev, struct dcp_sound_cookie *cookie) return ret; } -EXPORT_SYMBOL_GPL(dcp_audiosrv_startlink); int dcp_audiosrv_stoplink(struct device *dev) { @@ -161,7 +144,6 @@ int dcp_audiosrv_stoplink(struct device *dev) return ret; } -EXPORT_SYMBOL_GPL(dcp_audiosrv_stoplink); int dcp_audiosrv_unprepare(struct device *dev) { @@ -176,7 +158,6 @@ int dcp_audiosrv_unprepare(struct device *dev) return ret; } -EXPORT_SYMBOL_GPL(dcp_audiosrv_unprepare); static int dcp_audiosrv_osobject_call(struct apple_epic_service *service, u16 group, @@ -233,7 +214,6 @@ int dcp_audiosrv_get_elements(struct device *dev, void *elements, size_t maxsize return ret; } -EXPORT_SYMBOL_GPL(dcp_audiosrv_get_elements); int dcp_audiosrv_get_product_attrs(struct device *dev, void *attrs, size_t maxsize) { @@ -255,7 +235,6 @@ int dcp_audiosrv_get_product_attrs(struct device *dev, void *attrs, size_t maxsi return ret; } -EXPORT_SYMBOL_GPL(dcp_audiosrv_get_product_attrs); static int av_audiosrv_report(struct apple_epic_service *service, u32 idx, const void *data, size_t data_size) @@ -307,22 +286,20 @@ static void av_work_service_start(struct work_struct *work) } mutex_lock(&dcp->audiosrv->plug_lock); - if (dcp->audiosrv->hotplug_cb) - dcp->audiosrv->hotplug_cb(dcp->audiosrv->audio_dev, - dcp->audiosrv->plugged); + if (dcp->audiosrv->audio_dev) + dcpaud_connect(dcp->audiosrv->audio_dev, dcp->audiosrv->plugged); mutex_unlock(&dcp->audiosrv->plug_lock); } int avep_init(struct apple_dcp *dcp) { - struct dcp_audio_pdata *audio_pdata; - struct platform_device *audio_pdev; struct audiosrv_data *audiosrv_data; + struct platform_device *audio_pdev; struct device *dev = dcp->dev; + struct device_node *endpoint, *audio_node = NULL; audiosrv_data = devm_kzalloc(dcp->dev, sizeof(*audiosrv_data), GFP_KERNEL); - audio_pdata = devm_kzalloc(dcp->dev, sizeof(*audio_pdata), GFP_KERNEL); - if (!audiosrv_data || !audio_pdata) + if (!audiosrv_data) return -ENOMEM; init_rwsem(&audiosrv_data->srv_rwsem); mutex_init(&audiosrv_data->plug_lock); @@ -342,21 +319,27 @@ int avep_init(struct apple_dcp *dcp) dcp->audiosrv = audiosrv_data; - audio_pdata->dcp_dev = dcp->dev; - /* TODO: free OF reference */ - audio_pdata->dpaudio_node = \ - of_parse_phandle(dev->of_node, "apple,audio-xmitter", 0); - if (!audio_pdata->dpaudio_node || - !of_device_is_available(audio_pdata->dpaudio_node)) { + endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); + if (endpoint) { + audio_node = of_graph_get_remote_port_parent(endpoint); + of_node_put(endpoint); + } + if (!audio_node || !of_device_is_available(audio_node)) { + of_node_put(audio_node); dev_info(dev, "No audio support\n"); return 0; } - audio_pdev = platform_device_register_data(dev, "dcp-hdmi-audio", - PLATFORM_DEVID_AUTO, - audio_pdata, sizeof(*audio_pdata)); - if (IS_ERR(audio_pdev)) - return dev_err_probe(dev, PTR_ERR(audio_pdev), "registering audio device\n"); + audio_pdev = of_find_device_by_node(audio_node); + of_node_put(audio_node); + if (!audio_pdev) { + dev_info(dev, "No DP/HDMI audio device not ready\n"); + return 0; + } + dcp->audiosrv->audio_dev = audio_pdev; + + device_link_add(&audio_pdev->dev, dev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME); dcp->avep = afk_init(dcp, AV_ENDPOINT, avep_ops); if (IS_ERR(dcp->avep)) From 6f7a65e7d10092a297d62e32d16893bf2a5f3435 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 22 Apr 2024 19:47:22 +0200 Subject: [PATCH 197/352] drm: apple: audio: Avoid probe errors Now that the DP audio driver is a component of the display sub-system probe errors will bring down the whole display initialization. To prevent that the audio driver must not fail. Allow delayed sound card initialization if the DMA controller is not ready, for example because the apple-sio module is missing (at all or just in the initeramfs). In the case apple-sio is available later provide as sysfs file "probe_snd_card" to trigger initialization. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/audio.c | 147 ++++++++++++++++++++++++---------- 1 file changed, 105 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c index b4a860d198c32b..9266af8038083d 100644 --- a/drivers/gpu/drm/apple/audio.c +++ b/drivers/gpu/drm/apple/audio.c @@ -42,6 +42,7 @@ struct dcp_audio { unsigned int open_cookie; struct mutex data_lock; + bool dcp_connected; /// dcp status keep for delayed initialization bool connected; unsigned int connection_cookie; @@ -430,19 +431,8 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud) { struct snd_card *card = dcpaud->card; struct snd_pcm *pcm; - struct dma_chan *chan; int ret; - chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx"); - if (IS_ERR_OR_NULL(chan)) { - if (!chan) - return -EINVAL; - - dev_err(dcpaud->dev, "can't request audio TX DMA channel: %pE\n", chan); - return PTR_ERR(chan); - } - dcpaud->chan = chan; - #define NUM_PLAYBACK 1 #define NUM_CAPTURE 0 @@ -453,7 +443,7 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dcp_playback_ops); dcpaud->substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM, - chan->device->dev, 1024 * 1024, + dcpaud->chan->device->dev, 1024 * 1024, SIZE_MAX); pcm->nonatomic = true; @@ -463,12 +453,12 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud) return 0; } +/* expects to be called with data_lock locked and unlocks it */ static void dcpaud_report_hotplug(struct dcp_audio *dcpaud, bool connected) { struct snd_pcm_substream *substream = dcpaud->substream; - mutex_lock(&dcpaud->data_lock); - if (dcpaud->connected == connected) { + if (!dcpaud->card || dcpaud->connected == connected) { mutex_unlock(&dcpaud->data_lock); return; } @@ -504,6 +494,53 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud) strscpy(card->shortname, "Apple DisplayPort", sizeof(card->shortname)); } +static int dcpaud_init_snd_card(struct dcp_audio *dcpaud) +{ + int ret; + struct dma_chan *chan; + + chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx"); + /* squelch dma channel request errors, the driver will try again alter */ + if (!chan) { + dev_warn(dcpaud->dev, "audio TX DMA channel request failed\n"); + return 0; + } else if (IS_ERR(chan)) { + dev_warn(dcpaud->dev, "audio TX DMA channel request failed: %pE\n", chan); + return 0; + } + dcpaud->chan = chan; + + ret = snd_card_new(dcpaud->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &dcpaud->card); + if (ret) + return ret; + + dcpaud_set_card_names(dcpaud); + + ret = dcpaud_create_pcm(dcpaud); + if (ret) + goto err_free_card; + + ret = dcpaud_create_chmap_ctl(dcpaud); + if (ret) + goto err_free_card; + + ret = dcpaud_create_jack(dcpaud); + if (ret) + goto err_free_card; + + ret = snd_card_register(dcpaud->card); + if (ret) + goto err_free_card; + + return 0; +err_free_card: + dev_warn(dcpaud->dev, "Failed to initialize sound card: %d\n", ret); + snd_card_free(dcpaud->card); + dcpaud->card = NULL; + return ret; +} + #ifdef CONFIG_SND_DEBUG static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) { @@ -522,15 +559,59 @@ static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *nam void dcpaud_connect(struct platform_device *pdev, bool connected) { struct dcp_audio *dcpaud = platform_get_drvdata(pdev); + + mutex_lock(&dcpaud->data_lock); + + if (!dcpaud->chan) { + int ret = dcpaud_init_snd_card(dcpaud); + if (ret) { + dcpaud->dcp_connected = connected; + mutex_unlock(&dcpaud->data_lock); + return; + } + } dcpaud_report_hotplug(dcpaud, connected); } void dcpaud_disconnect(struct platform_device *pdev) { struct dcp_audio *dcpaud = platform_get_drvdata(pdev); + + mutex_lock(&dcpaud->data_lock); + + dcpaud->dcp_connected = false; dcpaud_report_hotplug(dcpaud, false); } +static ssize_t probe_snd_card_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + bool connected = false; + struct dcp_audio *dcpaud = dev_get_drvdata(dev); + + mutex_lock(&dcpaud->data_lock); + + if (!dcpaud->chan) { + ret = dcpaud_init_snd_card(dcpaud); + if (ret) + goto out_unlock; + + connected = dcpaud->dcp_connected; + if (connected) { + dcpaud_report_hotplug(dcpaud, connected); + goto out; + } + } +out_unlock: + mutex_unlock(&dcpaud->data_lock); +out: + return count; +} + +static const DEVICE_ATTR_WO(probe_snd_card); + static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) { struct dcp_audio *dcpaud = dev_get_drvdata(dev); @@ -553,34 +634,11 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) dcp_pdev = of_find_device_by_node(dcp_node); of_node_put(dcp_node); if (!dcp_pdev) { - dev_info(dev, "No DP/HDMI audio device not ready\n"); + dev_info(dev, "No DP/HDMI audio device, dcp not ready\n"); return 0; } dcpaud->dcp_dev = &dcp_pdev->dev; - ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, - THIS_MODULE, 0, &dcpaud->card); - if (ret) - return ret; - - dcpaud_set_card_names(dcpaud); - - ret = dcpaud_create_pcm(dcpaud); - if (ret) - goto err_free_card; - - ret = dcpaud_create_chmap_ctl(dcpaud); - if (ret) - goto err_free_card; - - ret = dcpaud_create_jack(dcpaud); - if (ret) - goto err_free_card; - - ret = snd_card_register(dcpaud->card); - if (ret) - goto err_free_card; - dcpaud_expose_debugfs_blob(dcpaud, "selected_cookie", &dcpaud->selected_cookie, sizeof(dcpaud->selected_cookie)); dcpaud_expose_debugfs_blob(dcpaud, "elements", dcpaud->elements, @@ -588,11 +646,16 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) dcpaud_expose_debugfs_blob(dcpaud, "product_attrs", dcpaud->productattrs, DCPAUD_PRODUCTATTRS_MAXSIZE); - return 0; + mutex_lock(&dcpaud->data_lock); + /* ignore errors to prevent audio issues affecting the display side */ + dcpaud_init_snd_card(dcpaud); + mutex_unlock(&dcpaud->data_lock); -err_free_card: - snd_card_free(dcpaud->card); - return ret; + ret = device_create_file(dev, &dev_attr_probe_snd_card); + if (ret) + dev_info(dev, "creating force probe sysfs file failed: %d\n", ret); + + return 0; } static void dcpaud_comp_unbind(struct device *dev, struct device *main, From 1952494f25c34b51b761beb4932879033656dcb9 Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Sun, 21 Apr 2024 11:15:04 +1000 Subject: [PATCH 198/352] drm/apple: fix double words in comments Signed-off-by: Jonathan Gray --- drivers/gpu/drm/apple/afk.c | 2 +- drivers/gpu/drm/apple/dcp-internal.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index 218c28dfe84249..d3e45a6180af69 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -641,7 +641,7 @@ static bool afk_recv(struct apple_dcp_afkep *ep) * TODO: this is theoretically unsafe since DCP could overwrite data * after the read pointer was updated above. Do it anyway since * it avoids 2 problems in the DCP tracer: - * 1. the tracer sees replies before the the notifies from dcp + * 1. the tracer sees replies before the notifies from dcp * 2. the tracer tries to read buffers after they are unmapped. */ afk_recv_handle(ep, channel, type, hdr->data, size); diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index b8df2f5c6e022b..c1d6da9a433db7 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -128,7 +128,7 @@ struct apple_dcp { /************* IOMFB ************************************************** * everything below is mostly used inside IOMFB but it could make * - * sense keep some of the the members in apple_dcp. * + * sense to keep some of the members in apple_dcp. * **********************************************************************/ /* clock rate request by dcp in */ @@ -212,7 +212,7 @@ struct apple_dcp { struct list_head swapped_out_fbs; struct dcp_brightness brightness; - /* Workqueue for updating the initial initial brightness */ + /* Workqueue for updating the initial brightness */ struct work_struct bl_register_wq; struct mutex bl_register_mutex; /* Workqueue for updating the brightness */ From 7061a4a4439231361090711d55e537c04af53f4a Mon Sep 17 00:00:00 2001 From: Caspar Schutijser Date: Thu, 18 Apr 2024 22:26:58 +0100 Subject: [PATCH 199/352] drm: apple: backlight: release lock in error path Signed-off-by: Caspar Schutijser --- drivers/gpu/drm/apple/dcp_backlight.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp_backlight.c b/drivers/gpu/drm/apple/dcp_backlight.c index ed3b240ead8557..1397000c27935c 100644 --- a/drivers/gpu/drm/apple/dcp_backlight.c +++ b/drivers/gpu/drm/apple/dcp_backlight.c @@ -150,8 +150,10 @@ static int drm_crtc_set_brightness(struct apple_dcp *dcp) goto done; state = drm_atomic_state_alloc(crtc->dev); - if (!state) - return -ENOMEM; + if (!state) { + ret = -ENOMEM; + goto done; + } state->acquire_ctx = &ctx; crtc_state = drm_atomic_get_crtc_state(state, crtc); From 533c919b9729d52df584d4c662658171827c3934 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 27 Apr 2024 17:55:25 +0200 Subject: [PATCH 200/352] drm: apple: Switch back to drm_atomic_helper_commit_tail_rpm() The custom commit_tail implementation stopped making after "drm/apple: Disable fake vblank IRQ machinery" which stopped calling drm_vblank_init(). Revert back to the standard helper implementation. Avoids or at least significantly reduces page flips taking approximately one frame time in kwin_wayland 6. Fixes: ("drm/apple: Switch to nonblocking commit handling") Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index a91aa39690541b..e3988701e0ccdc 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -239,26 +239,6 @@ static void apple_crtc_atomic_begin(struct drm_crtc *crtc, } } -static void dcp_atomic_commit_tail(struct drm_atomic_state *old_state) -{ - struct drm_device *dev = old_state->dev; - - drm_atomic_helper_commit_modeset_disables(dev, old_state); - - drm_atomic_helper_commit_modeset_enables(dev, old_state); - - drm_atomic_helper_commit_planes(dev, old_state, - DRM_PLANE_COMMIT_ACTIVE_ONLY); - - drm_atomic_helper_fake_vblank(old_state); - - drm_atomic_helper_commit_hw_done(old_state); - - drm_atomic_helper_wait_for_flip_done(dev, old_state); - - drm_atomic_helper_cleanup_planes(dev, old_state); -} - static void apple_crtc_cleanup(struct drm_crtc *crtc) { drm_crtc_cleanup(crtc); @@ -281,7 +261,7 @@ static const struct drm_mode_config_funcs apple_mode_config_funcs = { }; static const struct drm_mode_config_helper_funcs apple_mode_config_helpers = { - .atomic_commit_tail = dcp_atomic_commit_tail, + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; static void appledrm_connector_cleanup(struct drm_connector *connector) From a3af56f060be6c62d4957449d63b771f767e78e7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 4 May 2024 13:09:15 +0200 Subject: [PATCH 201/352] drm: apple: Fix broken MemDescRelay::release_descriptor callback number Two callbacks for IOMFB::MemDescRelay seems to be dropped between 12.3 and 13.5 DCP firmware. This results in the renumbering of MemDescRelay::release_descriptor from D456 to D454. Noticed while when switching the display refresh rate to 50 Hz with a 14.5 system firmware on a M1 Max Macbook Pro. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_v13_3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb_v13_3.c b/drivers/gpu/drm/apple/iomfb_v13_3.c index 115490fd9cc6e3..0ac869d24eb01b 100644 --- a/drivers/gpu/drm/apple/iomfb_v13_3.c +++ b/drivers/gpu/drm/apple/iomfb_v13_3.c @@ -81,7 +81,7 @@ static const iomfb_cb_handler cb_handlers[IOMFB_MAX_CB] = { [415] = trampoline_true, /* sr_set_property_bool */ [451] = trampoline_allocate_buffer, [452] = trampoline_map_physical, - [456] = trampoline_release_mem_desc, + [454] = trampoline_release_mem_desc, [552] = trampoline_true, /* set_property_dict_0 */ [561] = trampoline_true, /* set_property_dict */ [563] = trampoline_true, /* set_property_int */ From 7592b55640241b238d0d423073561ff5b7c240df Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 4 May 2024 13:23:03 +0200 Subject: [PATCH 202/352] drm: apple: Reduce log spam about busy command channel The most likely cause for this is an unexpected callback form which the current driver doesn't recover. Warn only once about it. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp-internal.h | 2 ++ drivers/gpu/drm/apple/iomfb.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index c1d6da9a433db7..379d6ff5dec68a 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -71,6 +71,8 @@ struct dcp_channel { /* Current depth of the call stack. Less than DCP_MAX_CALL_DEPTH */ u8 depth; + /* Already warned about busy channel */ + bool warned_busy; }; struct dcp_fb_reference { diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 788d63d90e3747..2fadc9e614d571 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -482,12 +482,17 @@ void dcp_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) if (dcp_channel_busy(&dcp->ch_cmd)) { - dev_err(dcp->dev, "unexpected busy command channel\n"); + if (!dcp->ch_cmd.warned_busy) { + dev_err(dcp->dev, "unexpected busy command channel\n"); + dcp->ch_cmd.warned_busy = true; + } /* HACK: issue a delayed vblank event to avoid timeouts in * drm_atomic_helper_wait_for_vblanks(). */ schedule_work(&dcp->vblank_wq); return; + } else if (dcp->ch_cmd.warned_busy) { + dcp->ch_cmd.warned_busy = false; } switch (dcp->fw_compat) { From ee2ee06530eb3c93d66787721bd0c1307fd35380 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 4 May 2024 13:33:57 +0200 Subject: [PATCH 203/352] drm: apple: av: Warn only once about failed calls Reduce log spam while errors are still likely due missing state checks. --- drivers/gpu/drm/apple/av.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index 66a99cb2ed7b0f..8a2c1126f5adea 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -59,6 +59,9 @@ struct audiosrv_data { struct work_struct start_av_service_wq; struct dcp_av_audio_cmds cmds; + + bool warned_get_elements; + bool warned_get_product_attrs; }; static void av_interface_init(struct apple_epic_service *service, const char *name, @@ -207,10 +210,12 @@ int dcp_audiosrv_get_elements(struct device *dev, void *elements, size_t maxsize elements, maxsize, &size); up_write(&asrv->srv_rwsem); - if (ret) + if (ret && asrv->warned_get_elements) { dev_err(dev, "audiosrv: error getting elements: %d\n", ret); - else + asrv->warned_get_elements = true; + } else { dev_dbg(dev, "audiosrv: got %zd bytes worth of elements\n", size); + } return ret; } @@ -228,10 +233,12 @@ int dcp_audiosrv_get_product_attrs(struct device *dev, void *attrs, size_t maxsi maxsize, &size); up_write(&asrv->srv_rwsem); - if (ret) + if (ret && asrv->warned_get_product_attrs) { dev_err(dev, "audiosrv: error getting product attributes: %d\n", ret); - else + asrv->warned_get_product_attrs = true; + } else { dev_dbg(dev, "audiosrv: got %zd bytes worth of product attributes\n", size); + } return ret; } From 89554a5cacb5786cf7cfaf2348c516d9df354e3e Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 8 May 2024 16:55:11 +0200 Subject: [PATCH 204/352] drm: apple: disable HDMI audio by default Can be still enabled by adding `apple_dcp.hdmi_audio` the kernel command line. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/audio.c | 5 +++++ drivers/gpu/drm/apple/dcp.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c index 9266af8038083d..923f5421298305 100644 --- a/drivers/gpu/drm/apple/audio.c +++ b/drivers/gpu/drm/apple/audio.c @@ -494,11 +494,16 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud) strscpy(card->shortname, "Apple DisplayPort", sizeof(card->shortname)); } +extern bool hdmi_audio; + static int dcpaud_init_snd_card(struct dcp_audio *dcpaud) { int ret; struct dma_chan *chan; + if (!hdmi_audio) + return -ENODEV; + chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx"); /* squelch dma channel request errors, the driver will try again alter */ if (!chan) { diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index cc75e8e919d663..c9ab975caca636 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -46,9 +46,9 @@ static bool show_notch; module_param(show_notch, bool, 0644); MODULE_PARM_DESC(show_notch, "Use the full display height and shows the notch"); -static bool noaudio; -module_param(noaudio, bool, 0644); -MODULE_PARM_DESC(noaudio, "Skip audio support"); +bool hdmi_audio; +module_param(hdmi_audio, bool, 0644); +MODULE_PARM_DESC(hdmi_audio, "Enable unstable HDMI audio support"); /* HACK: moved here to avoid circular dependency between apple_drv and dcp */ void dcp_drm_crtc_vblank(struct apple_crtc *crtc) @@ -413,7 +413,7 @@ int dcp_start(struct platform_device *pdev) dev_err(dcp->dev, "Failed to start IOMFB endpoint: %d\n", ret); #if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) - if (!noaudio) { + if (hdmi_audio) { ret = avep_init(dcp); if (ret) dev_warn(dcp->dev, "Failed to start AV endpoint: %d", ret); From 08b82ac83277591161b566d1b1174686feaf2bbf Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 12 May 2024 09:39:59 +0200 Subject: [PATCH 205/352] drm: apple: Override drm_vblank's page flip event handling [HACK] Since we don't init/uses drm's vblank support our page flip timestamps are CLOCK_MONOTONIC timestamps during the event generation. Since compositors use the timestamp to schedule their next kms commit this is timing sensitive sop move it under the drivers control. Take the timestamp directly in the swap_complete callback. Framebuffer swaps are unfortunately not fast with DCP. Measured time from swap_submit to swap_complete is ~1.5 ms for dcp and ~2.3 ms for dcpext. This warrants further investigation. Presentation timestamps might help if delay on dcp firmware side occurs after the actual swap. In the meantime doctor the time stamps and move the page flip completion up to 1 ms earler. This fixes half rate refresh on external displays displays using dcpext. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp-internal.h | 3 + drivers/gpu/drm/apple/dcp.c | 87 ++++++++++++++++++++++++++ drivers/gpu/drm/apple/iomfb_template.c | 4 +- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 379d6ff5dec68a..0eb8227ef816e4 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -175,6 +175,7 @@ struct apple_dcp { /* swap id of the last completed swap */ u32 last_swap_id; + ktime_t swap_start; /* Current display mode */ bool during_modeset; @@ -253,6 +254,8 @@ struct apple_dcp { int hdmi_hpd_irq; }; +void dcp_drm_crtc_page_flip(struct apple_dcp *dcp, ktime_t now); + int dcp_backlight_register(struct apple_dcp *dcp); int dcp_backlight_update(struct apple_dcp *dcp); bool dcp_has_panel(struct apple_dcp *dcp); diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index c9ab975caca636..1f9fbe7d0800ec 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -50,6 +50,76 @@ bool hdmi_audio; module_param(hdmi_audio, bool, 0644); MODULE_PARM_DESC(hdmi_audio, "Enable unstable HDMI audio support"); +/* copied and simplified from drm_vblank.c */ +static void send_vblank_event(struct drm_device *dev, + struct drm_pending_vblank_event *e, + u64 seq, ktime_t now) +{ + struct timespec64 tv; + + if (e->event.base.type != DRM_EVENT_FLIP_COMPLETE) + return; + + tv = ktime_to_timespec64(now); + e->event.vbl.sequence = seq; + /* + * e->event is a user space structure, with hardcoded unsigned + * 32-bit seconds/microseconds. This is safe as we always use + * monotonic timestamps since linux-4.15 + */ + e->event.vbl.tv_sec = tv.tv_sec; + e->event.vbl.tv_usec = tv.tv_nsec / 1000; + + /* + * Use the same timestamp for any associated fence signal to avoid + * mismatch in timestamps for vsync & fence events triggered by the + * same HW event. Frameworks like SurfaceFlinger in Android expects the + * retire-fence timestamp to match exactly with HW vsync as it uses it + * for its software vsync modeling. + */ + drm_send_event_timestamp_locked(dev, &e->base, now); +} + +/** + * dcp_crtc_send_page_flip_event - helper to send vblank event after pageflip + * + * Compensate for unknown slack between page flip and arrival of the + * swap_complete callback. Minimal observed duration on DCP with HDMI output + * was around 2.3 ms. If the fb swap was submitted closer to the expected + * swap_complete it gets a penalty of one frame duration. This is on the border + * of unreasonable considering that Apple advertises support for 240 Hz (frame + * duration of 4.167 ms). + * It is unreasonable considering kwin's kms commit scheduling. Kwin commits + * 1.5 ms + the mode's vblank time before the expected next page flip + * completion. This results in presenting at half the display's rate for HDMI + * outputs. + * This might be a difference between dcp and dcpext. + */ +static void dcp_crtc_send_page_flip_event(struct apple_crtc *crtc, + struct drm_pending_vblank_event *e, + ktime_t now, ktime_t start) +{ + struct drm_device *dev = crtc->base.dev; + u64 seq; + unsigned int pipe = drm_crtc_index(&crtc->base); + ktime_t flip; + + seq = 0; + if (start != KTIME_MIN) { + s64 delta = ktime_us_delta(now, start); + if (delta <= 500) + flip = now; + else if (delta >= 2500) + flip = ktime_sub_us(now, 1000); + else + flip = ktime_sub_us(now, (delta - 500) / 2); + } else { + flip = now; + } + e->pipe = pipe; + send_vblank_event(dev, e, seq, flip); +} + /* HACK: moved here to avoid circular dependency between apple_drv and dcp */ void dcp_drm_crtc_vblank(struct apple_crtc *crtc) { @@ -63,6 +133,23 @@ void dcp_drm_crtc_vblank(struct apple_crtc *crtc) spin_unlock_irqrestore(&crtc->base.dev->event_lock, flags); } +void dcp_drm_crtc_page_flip(struct apple_dcp *dcp, ktime_t now) +{ + unsigned long flags; + struct apple_crtc *crtc = dcp->crtc; + + spin_lock_irqsave(&crtc->base.dev->event_lock, flags); + if (crtc->event) { + if (crtc->event->event.base.type == DRM_EVENT_FLIP_COMPLETE) + dcp_crtc_send_page_flip_event(crtc, crtc->event, now, dcp->swap_start); + else + drm_crtc_send_vblank_event(&crtc->base, crtc->event); + crtc->event = NULL; + dcp->swap_start = KTIME_MIN; + } + spin_unlock_irqrestore(&crtc->base.dev->event_lock, flags); +} + void dcp_set_dimensions(struct apple_dcp *dcp) { int i; diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index e74c3f7863160c..5f02e2ac3de9b0 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -120,10 +120,11 @@ static u32 dcpep_cb_zero(struct apple_dcp *dcp) static void dcpep_cb_swap_complete(struct apple_dcp *dcp, struct DCP_FW_NAME(dc_swap_complete_resp) *resp) { + ktime_t now = ktime_get(); trace_iomfb_swap_complete(dcp, resp->swap_id); dcp->last_swap_id = resp->swap_id; - dcp_drm_crtc_vblank(dcp->crtc); + dcp_drm_crtc_page_flip(dcp, now); } /* special */ @@ -1124,6 +1125,7 @@ static void dcp_swapped(struct apple_dcp *dcp, void *data, void *cookie) dcp_drm_crtc_vblank(dcp->crtc); return; } + dcp->swap_start = ktime_get(); while (!list_empty(&dcp->swapped_out_fbs)) { struct dcp_fb_reference *entry; From b8dd510e67a62058e8f7f99d0fbe3cd809966329 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 15 Jun 2024 14:29:48 +0900 Subject: [PATCH 206/352] drm/apple: Explicitly stop AFK endpoints on shutdown Signed-off-by: Asahi Lina --- drivers/gpu/drm/apple/afk.c | 13 +++++++++++++ drivers/gpu/drm/apple/afk.h | 1 + drivers/gpu/drm/apple/dcp.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index d3e45a6180af69..83afb51883048f 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -86,6 +86,19 @@ struct apple_dcp_afkep *afk_init(struct apple_dcp *dcp, u32 endpoint, return ERR_PTR(ret); } +void afk_shutdown(struct apple_dcp_afkep *afkep) +{ + afk_send(afkep, FIELD_PREP(RBEP_TYPE, RBEP_SHUTDOWN)); + int ret; + + ret = wait_for_completion_timeout(&afkep->stopped, msecs_to_jiffies(1000)); + if (ret <= 0) { + dev_err(afkep->dcp->dev, "Timed out shutting down AFK endpoint %02x", afkep->endpoint); + } + + destroy_workqueue(afkep->wq); +} + int afk_start(struct apple_dcp_afkep *ep) { int ret; diff --git a/drivers/gpu/drm/apple/afk.h b/drivers/gpu/drm/apple/afk.h index 0f91f32e08e301..be3f0b105de581 100644 --- a/drivers/gpu/drm/apple/afk.h +++ b/drivers/gpu/drm/apple/afk.h @@ -187,6 +187,7 @@ struct apple_dcp_afkep { struct apple_dcp_afkep *afk_init(struct apple_dcp *dcp, u32 endpoint, const struct apple_epic_service_ops *ops); int afk_start(struct apple_dcp_afkep *ep); +void afk_shutdown(struct apple_dcp_afkep *ep); int afk_receive_message(struct apple_dcp_afkep *ep, u64 message); int afk_send_epic(struct apple_dcp_afkep *ep, u32 channel, u16 tag, enum epic_type etype, enum epic_category ecat, u8 stype, diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 1f9fbe7d0800ec..e3f8196bbecfb1 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -1022,10 +1022,33 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) { struct apple_dcp *dcp = dev_get_drvdata(dev); + if (!dcp) + return; + if (dcp->hdmi_hpd_irq) disable_irq(dcp->hdmi_hpd_irq); - if (dcp && dcp->shmem) + if (dcp->avep) { + afk_shutdown(dcp->avep); + dcp->avep = NULL; + } + + if (dcp->dptxep) { + afk_shutdown(dcp->dptxep); + dcp->dptxep = NULL; + } + + if (dcp->ibootep) { + afk_shutdown(dcp->ibootep); + dcp->ibootep = NULL; + } + + if (dcp->systemep) { + afk_shutdown(dcp->systemep); + dcp->systemep = NULL; + } + + if (dcp->shmem) iomfb_shutdown(dcp); if (dcp->piodma) { @@ -1038,6 +1061,12 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) dcp->piodma = NULL; } + if (dcp->connector_type == DRM_MODE_CONNECTOR_eDP) { + cancel_work_sync(&dcp->bl_register_wq); + cancel_work_sync(&dcp->bl_update_wq); + } + cancel_work_sync(&dcp->vblank_wq); + devm_clk_put(dev, dcp->clk); dcp->clk = NULL; } From c7b8234f501749aac445e29569033564b9598aae Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 15 Jun 2024 19:51:12 +0900 Subject: [PATCH 207/352] drm/apple: audio: Create a device link to the DMA device This works even before the DMA device probes. Might help deal with runtime-pm ordering, though it doesn't solve the deferred ordering problem (since we're creating the link while already probing)... Signed-off-by: Asahi Lina --- drivers/gpu/drm/apple/audio.c | 69 +++++++++++++++++------------------ 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c index 923f5421298305..8c6018fa36bf3d 100644 --- a/drivers/gpu/drm/apple/audio.c +++ b/drivers/gpu/drm/apple/audio.c @@ -35,6 +35,8 @@ struct dcp_audio { struct device *dev; struct device *dcp_dev; + struct device *dma_dev; + struct device_link *dma_link; struct dma_chan *chan; struct snd_card *card; struct snd_jack *jack; @@ -588,40 +590,13 @@ void dcpaud_disconnect(struct platform_device *pdev) dcpaud_report_hotplug(dcpaud, false); } -static ssize_t probe_snd_card_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int ret; - bool connected = false; - struct dcp_audio *dcpaud = dev_get_drvdata(dev); - - mutex_lock(&dcpaud->data_lock); - - if (!dcpaud->chan) { - ret = dcpaud_init_snd_card(dcpaud); - if (ret) - goto out_unlock; - - connected = dcpaud->dcp_connected; - if (connected) { - dcpaud_report_hotplug(dcpaud, connected); - goto out; - } - } -out_unlock: - mutex_unlock(&dcpaud->data_lock); -out: - return count; -} - -static const DEVICE_ATTR_WO(probe_snd_card); - static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) { struct dcp_audio *dcpaud = dev_get_drvdata(dev); struct device_node *endpoint, *dcp_node = NULL; - struct platform_device *dcp_pdev; + struct platform_device *dcp_pdev, *dma_pdev; + struct of_phandle_args dma_spec; + int index; int ret; /* find linked DCP instance */ @@ -636,6 +611,18 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) return 0; } + index = of_property_match_string(dev->of_node, "dma-names", "tx"); + if (index < 0) { + dev_err(dev, "No dma-names property\n"); + return 0; + } + + if (of_parse_phandle_with_args(dev->of_node, "dmas", "#dma-cells", index, + &dma_spec) || !dma_spec.np) { + dev_err(dev, "Failed to parse dmas property\n"); + return 0; + } + dcp_pdev = of_find_device_by_node(dcp_node); of_node_put(dcp_node); if (!dcp_pdev) { @@ -644,12 +631,19 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) } dcpaud->dcp_dev = &dcp_pdev->dev; - dcpaud_expose_debugfs_blob(dcpaud, "selected_cookie", &dcpaud->selected_cookie, - sizeof(dcpaud->selected_cookie)); - dcpaud_expose_debugfs_blob(dcpaud, "elements", dcpaud->elements, - DCPAUD_ELEMENTS_MAXSIZE); - dcpaud_expose_debugfs_blob(dcpaud, "product_attrs", dcpaud->productattrs, - DCPAUD_PRODUCTATTRS_MAXSIZE); + + dma_pdev = of_find_device_by_node(dma_spec.np); + of_node_put(dma_spec.np); + if (!dma_pdev) { + dev_info(dev, "No DMA device\n"); + return 0; + } + dcpaud->dma_dev = &dma_pdev->dev; + + dcpaud->dma_link = device_link_add(dev, dcpaud->dma_dev, + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE | + DL_FLAG_STATELESS); mutex_lock(&dcpaud->data_lock); /* ignore errors to prevent audio issues affecting the display side */ @@ -670,6 +664,9 @@ static void dcpaud_comp_unbind(struct device *dev, struct device *main, /* snd_card_free_when_closed() checks for NULL */ snd_card_free_when_closed(dcpaud->card); + + if (dcpaud->dma_link) + device_link_del(dcpaud->dma_link); } static const struct component_ops dcpaud_comp_ops = { From 370f3cf4ecb2020f20e8986b82104cebf75c993e Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 15 Jun 2024 19:52:16 +0900 Subject: [PATCH 208/352] drm/apple: audio: Defer DMA channel acquisition to device open Allow the DMA device driver to probe late, and still create the sound device upfront. Instead try to request the DMA channel on first PCM open. This should be safe as long as we bail early and don't allow the process to continue to configuring buffers (since that requires the DMA to be configured). Signed-off-by: Asahi Lina --- drivers/gpu/drm/apple/audio.c | 105 ++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c index 8c6018fa36bf3d..eee1109780b061 100644 --- a/drivers/gpu/drm/apple/audio.c +++ b/drivers/gpu/drm/apple/audio.c @@ -212,10 +212,36 @@ static int dcpaud_rule_rate(struct snd_pcm_hw_params *params, return snd_interval_rate_bits(r, hits.rates); } +static int dcpaud_init_dma(struct dcp_audio *dcpaud) +{ + struct dma_chan *chan; + if (dcpaud->chan) + return 0; + + chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx"); + /* squelch dma channel request errors, the driver will try again alter */ + if (!chan) { + dev_warn(dcpaud->dev, "audio TX DMA channel request failed\n"); + return -ENXIO; + } else if (chan == ERR_PTR(-EPROBE_DEFER)) { + dev_info(dcpaud->dev, "audio TX DMA channel is not ready yet\n"); + return -ENXIO; + } else if (IS_ERR(chan)) { + dev_warn(dcpaud->dev, "audio TX DMA channel request failed: %ld\n", PTR_ERR(chan)); + return PTR_ERR(chan); + } + dcpaud->chan = chan; + + snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM, + dcpaud->chan->device->dev, 1024 * 1024, + SIZE_MAX); + + return 0; +} + static int dcp_pcm_open(struct snd_pcm_substream *substream) { struct dcp_audio *dcpaud = substream->pcm->private_data; - struct dma_chan *chan = dcpaud->chan; struct snd_dmaengine_dai_dma_data dma_data = { .flags = SND_DMAENGINE_PCM_DAI_FLAG_PACK, }; @@ -223,6 +249,10 @@ static int dcp_pcm_open(struct snd_pcm_substream *substream) int ret; mutex_lock(&dcpaud->data_lock); + ret = dcpaud_init_dma(dcpaud); + if (ret < 0) + return ret; + if (!dcpaud->connected) { mutex_unlock(&dcpaud->data_lock); return -ENXIO; @@ -254,12 +284,12 @@ static int dcp_pcm_open(struct snd_pcm_substream *substream) hw.buffer_bytes_max = SIZE_MAX; hw.fifo_size = 16; ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, &dma_data, - &hw, chan); + &hw, dcpaud->chan); if (ret) return ret; substream->runtime->hw = hw; - return snd_dmaengine_pcm_open(substream, chan); + return snd_dmaengine_pcm_open(substream, dcpaud->chan); } static int dcp_pcm_close(struct snd_pcm_substream *substream) @@ -444,10 +474,6 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dcp_playback_ops); dcpaud->substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM, - dcpaud->chan->device->dev, 1024 * 1024, - SIZE_MAX); - pcm->nonatomic = true; pcm->private_data = dcpaud; strscpy(pcm->name, card->shortname, sizeof(pcm->name)); @@ -496,26 +522,29 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud) strscpy(card->shortname, "Apple DisplayPort", sizeof(card->shortname)); } +#ifdef CONFIG_SND_DEBUG +static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) +{ + struct debugfs_blob_wrapper *wrapper; + wrapper = devm_kzalloc(dcpaud->dev, sizeof(*wrapper), GFP_KERNEL); + if (!wrapper) + return; + wrapper->data = base; + wrapper->size = size; + debugfs_create_blob(name, 0600, dcpaud->card->debugfs_root, wrapper); +} +#else +static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) {} +#endif + extern bool hdmi_audio; static int dcpaud_init_snd_card(struct dcp_audio *dcpaud) { int ret; - struct dma_chan *chan; - if (!hdmi_audio) return -ENODEV; - chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx"); - /* squelch dma channel request errors, the driver will try again alter */ - if (!chan) { - dev_warn(dcpaud->dev, "audio TX DMA channel request failed\n"); - return 0; - } else if (IS_ERR(chan)) { - dev_warn(dcpaud->dev, "audio TX DMA channel request failed: %pE\n", chan); - return 0; - } - dcpaud->chan = chan; ret = snd_card_new(dcpaud->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, 0, &dcpaud->card); @@ -548,35 +577,12 @@ static int dcpaud_init_snd_card(struct dcp_audio *dcpaud) return ret; } -#ifdef CONFIG_SND_DEBUG -static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) -{ - struct debugfs_blob_wrapper *wrapper; - wrapper = devm_kzalloc(dcpaud->dev, sizeof(*wrapper), GFP_KERNEL); - if (!wrapper) - return; - wrapper->data = base; - wrapper->size = size; - debugfs_create_blob(name, 0600, dcpaud->card->debugfs_root, wrapper); -} -#else -static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size) {} -#endif - void dcpaud_connect(struct platform_device *pdev, bool connected) { struct dcp_audio *dcpaud = platform_get_drvdata(pdev); mutex_lock(&dcpaud->data_lock); - if (!dcpaud->chan) { - int ret = dcpaud_init_snd_card(dcpaud); - if (ret) { - dcpaud->dcp_connected = connected; - mutex_unlock(&dcpaud->data_lock); - return; - } - } dcpaud_report_hotplug(dcpaud, connected); } @@ -645,14 +651,17 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) DL_FLAG_RPM_ACTIVE | DL_FLAG_STATELESS); - mutex_lock(&dcpaud->data_lock); /* ignore errors to prevent audio issues affecting the display side */ - dcpaud_init_snd_card(dcpaud); - mutex_unlock(&dcpaud->data_lock); + ret = dcpaud_init_snd_card(dcpaud); - ret = device_create_file(dev, &dev_attr_probe_snd_card); - if (ret) - dev_info(dev, "creating force probe sysfs file failed: %d\n", ret); + if (!ret) { + dcpaud_expose_debugfs_blob(dcpaud, "selected_cookie", &dcpaud->selected_cookie, + sizeof(dcpaud->selected_cookie)); + dcpaud_expose_debugfs_blob(dcpaud, "elements", dcpaud->elements, + DCPAUD_ELEMENTS_MAXSIZE); + dcpaud_expose_debugfs_blob(dcpaud, "product_attrs", dcpaud->productattrs, + DCPAUD_PRODUCTATTRS_MAXSIZE); + } return 0; } From 14c4d70e60d9f93440a362f2e650ab644d0aee79 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 15 Jun 2024 21:12:46 +0900 Subject: [PATCH 209/352] drm/apple: audio: Fix hotplug notifications Signed-off-by: Asahi Lina --- drivers/gpu/drm/apple/audio.c | 4 ++-- drivers/gpu/drm/apple/av.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c index eee1109780b061..b78e3895987103 100644 --- a/drivers/gpu/drm/apple/audio.c +++ b/drivers/gpu/drm/apple/audio.c @@ -500,7 +500,8 @@ static void dcpaud_report_hotplug(struct dcp_audio *dcpaud, bool connected) if (!connected) { snd_pcm_stream_lock(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + if (substream->runtime) + snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); snd_pcm_stream_unlock(substream); } } @@ -592,7 +593,6 @@ void dcpaud_disconnect(struct platform_device *pdev) mutex_lock(&dcpaud->data_lock); - dcpaud->dcp_connected = false; dcpaud_report_hotplug(dcpaud, false); } diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index 8a2c1126f5adea..586f39cc11ca11 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -69,6 +69,20 @@ static void av_interface_init(struct apple_epic_service *service, const char *na { } +static void av_interface_teardown(struct apple_epic_service *service) +{ + struct apple_dcp *dcp = service->ep->dcp; + struct audiosrv_data *asrv = dcp->audiosrv; + + mutex_lock(&asrv->plug_lock); + + asrv->plugged = false; + if (asrv->audio_dev) + dcpaud_disconnect(asrv->audio_dev); + + mutex_unlock(&asrv->plug_lock); +} + static void av_audiosrv_init(struct apple_epic_service *service, const char *name, const char *class, s64 unit) { @@ -258,6 +272,7 @@ static const struct apple_epic_service_ops avep_ops[] = { { .name = "DCPAVSimpleVideoInterface", .init = av_interface_init, + .teardown = av_interface_teardown, }, { .name = "DCPAVAudioInterface", From 020c1bb49544f5d541de82dcc507038da1d5cdbc Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sat, 5 Nov 2022 13:15:34 +0100 Subject: [PATCH 210/352] drm: apple: Add oob hotplug event Signed-off-by: Sven Peter --- drivers/gpu/drm/apple/apple_drv.c | 17 +++++++++++++++++ drivers/gpu/drm/apple/dcp.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/apple/dcp.h | 3 +++ 3 files changed, 42 insertions(+) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index e3988701e0ccdc..613856d0af5895 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -190,6 +190,22 @@ apple_connector_detect(struct drm_connector *connector, bool force) connector_status_disconnected; } +static void apple_connector_oob_hotplug(struct drm_connector *connector, + enum drm_connector_status status) +{ + struct apple_connector *apple_connector = to_apple_connector(connector); + + printk("#### oob_hotplug status:0x%x ####\n", (u32)status); + + if (status == connector_status_connected) + dcp_dptx_connect_oob(apple_connector->dcp, 0); + else if (status == connector_status_disconnected) + dcp_dptx_disconnect_oob(apple_connector->dcp, 0); + else + dev_err(&apple_connector->dcp->dev, "unexpected connector status" + ":0x%x in oob_hotplug event\n", (u32)status); +} + static void apple_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { @@ -278,6 +294,7 @@ static const struct drm_connector_funcs apple_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .detect = apple_connector_detect, .debugfs_init = apple_connector_debugfs_init, + .oob_hotplug_event = apple_connector_oob_hotplug, }; static const struct drm_connector_helper_funcs apple_connector_helper_funcs = { diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index e3f8196bbecfb1..19e75ffd55e4e0 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -397,6 +397,17 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) return ret; } +int dcp_dptx_connect_oob(struct platform_device *pdev, u32 port) +{ + struct apple_dcp *dcp = platform_get_drvdata(pdev); + int err = dcp_dptx_connect(dcp, port); + if (err < 0) + return err; + dptxport_set_hpd(dcp->dptxport[port].service, true); + return 0; +} +EXPORT_SYMBOL_GPL(dcp_dptx_connect_oob); + static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) { dev_info(dcp->dev, "%s(port=%d)\n", __func__, port); @@ -411,6 +422,17 @@ static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) return 0; } +int dcp_dptx_disconnect_oob(struct platform_device *pdev, u32 port) +{ + struct apple_dcp *dcp = platform_get_drvdata(pdev); + + if (dcp->dptxport[port].enabled) + dptxport_set_hpd(dcp->dptxport[port].service, false); + + return dcp_dptx_disconnect(dcp, port); +} +EXPORT_SYMBOL_GPL(dcp_dptx_disconnect_oob); + static irqreturn_t dcp_dp2hdmi_hpd(int irq, void *data) { struct apple_dcp *dcp = data; diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index 866a1a87d3fd7b..df3d767ac4baac 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -52,6 +52,9 @@ bool dcp_crtc_mode_fixup(struct drm_crtc *crtc, void dcp_set_dimensions(struct apple_dcp *dcp); void dcp_send_message(struct apple_dcp *dcp, u8 endpoint, u64 message); +int dcp_dptx_connect_oob(struct platform_device *pdev, u32 port); +int dcp_dptx_disconnect_oob(struct platform_device *pdev, u32 port); + int iomfb_start_rtkit(struct apple_dcp *dcp); void iomfb_shutdown(struct apple_dcp *dcp); /* rtkit message handler for IOMFB messages */ From b762bb52db63aa1acb03e3fa8ad7491fb976684c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 9 Jun 2024 21:49:43 +0200 Subject: [PATCH 211/352] drm: apple: dptx: Fix get_drive_settings retcode This appears to be lane count as "2" is observed for USB-C DP alt mode in shared DP/USB3 mode. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 56b86966e807a7..fd54f69b19919b 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -189,12 +189,16 @@ dptxport_call_get_drive_settings(struct apple_epic_service *service, /* Clear the rest of the buffer */ memset(reply_ + sizeof(*reply), 0, reply_size - sizeof(*reply)); - if (reply->retcode != 4) + /* + * retcode appears to be lane count, seeing 2 for USB-C dp alt mode + * with lanes splitted for DP/USB3. + */ + if (reply->retcode != dptx->lane_count) dev_err(service->ep->dcp->dev, "get_drive_settings: unexpected retcode %d\n", reply->retcode); - reply->retcode = 4; /* Should already be 4? */ + reply->retcode = dptx->lane_count; reply->unk5 = dptx->drive_settings[0]; reply->unk6 = 0; reply->unk7 = dptx->drive_settings[1]; From f4f0b6a567b087bd370ff40c26d6e1ec4d22b7ac Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 9 Jun 2024 22:01:59 +0200 Subject: [PATCH 212/352] drm: apple: dptxport: get_max_lane_count: Retrieve lane count from phy This unfortunately doesn't work relieably with typec-altmode-displayport since the oob hotplug notification arrives before atc-phy is configured to the appropiate DP mode. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index fd54f69b19919b..b8cb7f00133760 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -249,6 +249,9 @@ static int dptxport_call_get_max_lane_count(struct apple_epic_service *service, void *reply_, size_t reply_size) { struct dptxport_apcall_lane_count *reply = reply_; + struct dptx_port *dptx = service->cookie; + union phy_configure_opts phy_ops; + int ret; if (reply_size < sizeof(*reply)) return -EINVAL; @@ -256,6 +259,17 @@ static int dptxport_call_get_max_lane_count(struct apple_epic_service *service, reply->retcode = cpu_to_le32(0); reply->lane_count = cpu_to_le64(4); + ret = phy_validate(dptx->atcphy, PHY_MODE_DP, 0, &phy_ops); + if (ret < 0 || phy_ops.dp.lanes < 2) { + // phy_validate might return 0 lines if atc-phy is not yet + // switched to DP alt mode + dev_dbg(service->ep->dcp->dev, "get_max_lane_count: " + "phy_validate ret:%d lanes:%d\n", ret, phy_ops.dp.lanes); + } else { + reply->retcode = cpu_to_le32(0); + reply->lane_count = cpu_to_le64(phy_ops.dp.lanes); + } + return 0; } From 78540eb81529c6c7622310a83e2e1e25eaa03c3c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 14 Jul 2024 00:01:08 +0200 Subject: [PATCH 213/352] drm: apple: iomfb: Align buffer size on unmap/free as well Fixes failure to unmap buffers in dcpep_cb_unmap_piodma() due to the unaligned size. Further along this causes kernel log splat when DCP tries to map the buffers again since thye IOVA is still in use. This causes no apparent issue although map_piodma callback signals an errror and returns 0 (unmapped as DVA). It's not clear why this presents only randomly. Possibly some build or uninitialized memory triggers this unmap/free and immediate allocate/map cycle in the DCP firmware. I never notices this with a clang-built kernel on j314c. It showed with gcc build with the Fedora config at least on 6.8.8 based kernels. This did not reproduce on j375d. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 5f02e2ac3de9b0..6d23e0d43467e1 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -322,7 +322,10 @@ static void dcpep_cb_unmap_piodma(struct apple_dcp *dcp, } /* use the piodma iommu domain to unmap from the right IOMMU */ - iommu_unmap(dcp->iommu_dom, memdesc->dva, memdesc->size); + /* HACK: expect size to be 16K aligned since the iommu API only maps + * full pages + */ + iommu_unmap(dcp->iommu_dom, memdesc->dva, ALIGN(memdesc->size, SZ_16K)); } /* @@ -370,6 +373,7 @@ dcpep_cb_allocate_buffer(struct apple_dcp *dcp, static u8 dcpep_cb_release_mem_desc(struct apple_dcp *dcp, u32 *mem_desc_id) { struct dcp_mem_descriptor *memdesc; + size_t size; u32 id = *mem_desc_id; if (id >= DCP_MAX_MAPPINGS) { @@ -385,10 +389,9 @@ static u8 dcpep_cb_release_mem_desc(struct apple_dcp *dcp, u32 *mem_desc_id) } memdesc = &dcp->memdesc[id]; + size = ALIGN(memdesc->size, SZ_16K); if (memdesc->buf) { - dma_free_coherent(dcp->dev, memdesc->size, memdesc->buf, - memdesc->dva); - + dma_free_coherent(dcp->dev, size, memdesc->buf, memdesc->dva); memdesc->buf = NULL; memset(&memdesc->map, 0, sizeof(memdesc->map)); } else { From 31f3f216274e4810b2f1ffe41e7d29ae33162ce5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 21 Aug 2024 21:51:11 +0200 Subject: [PATCH 214/352] Revert "drm: apple: HACK: Do not delete piodma platform device" This reverts commit fa86f31f64a691eb65a217c66468b3e9e58cc9e1. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 19e75ffd55e4e0..db155413f03ee0 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -1076,10 +1076,7 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) if (dcp->piodma) { iommu_detach_device(dcp->iommu_dom, &dcp->piodma->dev); iommu_domain_free(dcp->iommu_dom); - /* TODO: the piodma platform device has to be destroyed but - * doing so leads to all kind of breakage. - */ - // of_platform_device_destroy(&dcp->piodma->dev, NULL); + of_platform_device_destroy(&dcp->piodma->dev, NULL); dcp->piodma = NULL; } From 810a66a81b2cb62086467bd3d206a43a920556a2 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 20 Aug 2024 23:04:29 +0200 Subject: [PATCH 215/352] drm: apple: afk: Optionally match against EPICName The dpavserv endpoint uses various EPICProviderClass depending on the connected display. Observed values: - "AppleDCPAgileCDIDPDisplay" (j134c, dcp, panel) - "AppleDCPMCDP29XX" (j274, dcp, hdmi) - "AppleDCPPS190" (j474s, dcpext0, hdmi) - "DCPDPService" (j474s, dcpext1, typec) So match against against EPICName which is consistent in all cases. This also allows the distinction between 'dcpav-service-epic' and 'dcpdp-service-epic'. Not sure what the second EPIC service is used for. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/afk.c | 6 +++++- drivers/gpu/drm/apple/afk.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index 83afb51883048f..bd1f16e8937c74 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -293,7 +293,11 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel, service_name = name; } - ops = afk_match_service(ep, service_name); + if (ep->match_epic_name) + ops = afk_match_service(ep, epic_name); + else + ops = afk_match_service(ep, service_name); + if (!ops) { dev_err(ep->dcp->dev, "AFK[ep:%02x]: unable to match service %s on channel %d\n", diff --git a/drivers/gpu/drm/apple/afk.h b/drivers/gpu/drm/apple/afk.h index be3f0b105de581..5a286799835248 100644 --- a/drivers/gpu/drm/apple/afk.h +++ b/drivers/gpu/drm/apple/afk.h @@ -182,6 +182,8 @@ struct apple_dcp_afkep { u32 num_channels; struct dentry *debugfs_entry; + + bool match_epic_name; }; struct apple_dcp_afkep *afk_init(struct apple_dcp *dcp, u32 endpoint, From f5da679eb7dec0500cc254f0f2411e84932312e1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 3 Dec 2023 23:24:11 +0100 Subject: [PATCH 216/352] drm: apple: Add dcpav-service-ep Known uses EDID retrieval and raw I2C access. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Makefile | 2 + drivers/gpu/drm/apple/connector.c | 3 +- drivers/gpu/drm/apple/connector.h | 2 + drivers/gpu/drm/apple/dcp-internal.h | 6 + drivers/gpu/drm/apple/dcp.c | 19 ++ drivers/gpu/drm/apple/dcp.h | 1 + drivers/gpu/drm/apple/epic/dpavservep.c | 230 ++++++++++++++++++++++++ drivers/gpu/drm/apple/epic/dpavservep.h | 22 +++ drivers/gpu/drm/apple/trace.h | 12 ++ 9 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/apple/epic/dpavservep.c create mode 100644 drivers/gpu/drm/apple/epic/dpavservep.h diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index b3b3026fdc60ca..4f78757829ea4c 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -11,6 +11,8 @@ apple_dcp-y += connector.o apple_dcp-y += ibootep.o apple_dcp-y += iomfb_v12_3.o apple_dcp-y += iomfb_v13_3.o +apple_dcp-y += epic/dpavservep.o + apple_dcp-$(CONFIG_TRACING) += trace.o obj-$(CONFIG_DRM_APPLE) += appledrm.o diff --git a/drivers/gpu/drm/apple/connector.c b/drivers/gpu/drm/apple/connector.c index 46de8e8756f1ed..9e786670893387 100644 --- a/drivers/gpu/drm/apple/connector.c +++ b/drivers/gpu/drm/apple/connector.c @@ -3,6 +3,8 @@ * Copyright (C) The Asahi Linux Contributors */ +#include "connector.h" + #include "linux/err.h" #include #include @@ -12,7 +14,6 @@ #include -#include "connector.h" #include "dcp-internal.h" enum dcp_chunk_type { diff --git a/drivers/gpu/drm/apple/connector.h b/drivers/gpu/drm/apple/connector.h index 5324b1b81f493c..02f2d3904b09a3 100644 --- a/drivers/gpu/drm/apple/connector.h +++ b/drivers/gpu/drm/apple/connector.h @@ -9,6 +9,8 @@ #include #include "drm/drm_connector.h" +struct apple_connector; + #include "dcp-internal.h" void dcp_hotplug(struct work_struct *work); diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 0eb8227ef816e4..d678a1965b5f0d 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -17,12 +17,15 @@ #include "iomfb.h" #include "iomfb_v12_3.h" #include "iomfb_v13_3.h" +#include "epic/dpavservep.h" #define DCP_MAX_PLANES 2 struct apple_dcp; struct apple_dcp_afkep; +struct dcpav_service_epic; + enum dcp_firmware_version { DCP_FIRMWARE_UNKNOWN, DCP_FIRMWARE_V_12_3, @@ -34,6 +37,7 @@ enum { TEST_ENDPOINT = 0x21, DCP_EXPERT_ENDPOINT = 0x22, DISP0_ENDPOINT = 0x23, + DPAVSERV_ENDPOINT = 0x28, AV_ENDPOINT = 0x29, DPTX_ENDPOINT = 0x2a, HDCP_ENDPOINT = 0x2b, @@ -228,6 +232,8 @@ struct apple_dcp { struct completion systemep_done; struct apple_dcp_afkep *ibootep; + struct apple_dcp_afkep *dcpavservep; + struct dcpavserv dcpavserv; struct apple_dcp_afkep *avep; struct audiosrv_data *audiosrv; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index db155413f03ee0..65c0558391c0ea 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -50,6 +50,10 @@ bool hdmi_audio; module_param(hdmi_audio, bool, 0644); MODULE_PARM_DESC(hdmi_audio, "Enable unstable HDMI audio support"); +static bool unstable_edid; +module_param(unstable_edid, bool, 0644); +MODULE_PARM_DESC(unstable_edid, "Enable unstable EDID retrival support"); + /* copied and simplified from drm_vblank.c */ static void send_vblank_event(struct drm_device *dev, struct drm_pending_vblank_event *e, @@ -219,6 +223,9 @@ static void dcp_recv_msg(void *cookie, u8 endpoint, u64 message) case DISP0_ENDPOINT: afk_receive_message(dcp->ibootep, message); return; + case DPAVSERV_ENDPOINT: + afk_receive_message(dcp->dcpavservep, message); + return; case DPTX_ENDPOINT: afk_receive_message(dcp->dptxep, message); return; @@ -480,6 +487,13 @@ int dcp_start(struct platform_device *pdev) if (ret) dev_warn(dcp->dev, "Failed to start system endpoint: %d\n", ret); + if (unstable_edid && !dcp_has_panel(dcp)) { + ret = dpavservep_init(dcp); + if (ret) + dev_warn(dcp->dev, "Failed to start DPAVSERV endpoint: %d", + ret); + } + if (dcp->phy && dcp->fw_compat >= DCP_FIRMWARE_V_13_5) { ret = ibootep_init(dcp); if (ret) @@ -1070,6 +1084,11 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) dcp->systemep = NULL; } + if (dcp->dcpavservep) { + afk_shutdown(dcp->dcpavservep); + dcp->dcpavservep = NULL; + } + if (dcp->shmem) iomfb_shutdown(dcp); diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index df3d767ac4baac..b1a151140c9048 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -63,6 +63,7 @@ void iomfb_recv_msg(struct apple_dcp *dcp, u64 message); int systemep_init(struct apple_dcp *dcp); int dptxep_init(struct apple_dcp *dcp); int ibootep_init(struct apple_dcp *dcp); +int dpavservep_init(struct apple_dcp *dcp); int avep_init(struct apple_dcp *dcp); diff --git a/drivers/gpu/drm/apple/epic/dpavservep.c b/drivers/gpu/drm/apple/epic/dpavservep.c new file mode 100644 index 00000000000000..aa2cbc729a37d4 --- /dev/null +++ b/drivers/gpu/drm/apple/epic/dpavservep.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright The Asahi Linux Contributors */ + +#include "dpavservep.h" + +#include + +#include +#include +#include + +#include "../afk.h" +#include "../dcp.h" +#include "../dcp-internal.h" +#include "../trace.h" + +static void dcpavserv_init(struct apple_epic_service *service, const char *name, + const char *class, s64 unit) +{ + struct apple_dcp *dcp = service->ep->dcp; + trace_dcpavserv_init(dcp, unit); + + if (unit == 0 && name && !strcmp(name, "dcpav-service-epic")) { + if (dcp->dcpavserv.enabled) { + dev_err(dcp->dev, + "DCPAVSERV: unit %lld already exists\n", unit); + return; + } + dcp->dcpavserv.service = service; + dcp->dcpavserv.enabled = true; + service->cookie = &dcp->dcpavserv; + complete(&dcp->dcpavserv.enable_completion); + } +} + +static void dcpavserv_teardown(struct apple_epic_service *service) +{ + struct apple_dcp *dcp = service->ep->dcp; + if (dcp->dcpavserv.enabled) { + dcp->dcpavserv.enabled = false; + dcp->dcpavserv.service = NULL; + service->cookie = NULL; + reinit_completion(&dcp->dcpavserv.enable_completion); + } +} + +static void dcpdpserv_init(struct apple_epic_service *service, const char *name, + const char *class, s64 unit) +{ +} + +static void dcpdpserv_teardown(struct apple_epic_service *service) +{ +} + +struct dcpavserv_status_report { + u32 unk00[4]; + u8 flag0; + u8 flag1; + u8 flag2; + u8 flag3; + u32 unk14[3]; + u32 status; + u32 unk24[3]; +} __packed; + +struct dpavserv_copy_edid_cmd { + __le64 max_size; + u8 _pad1[24]; + __le64 used_size; + u8 _pad2[8]; +} __packed; + +#define EDID_LEADING_DATA_SIZE 8 +#define EDID_BLOCK_SIZE 128 +#define EDID_EXT_BLOCK_COUNT_OFFSET 0x7E +#define EDID_MAX_SIZE SZ_32K +#define EDID_BUF_SIZE (EDID_LEADING_DATA_SIZE + EDID_MAX_SIZE) + +struct dpavserv_copy_edid_resp { + __le64 max_size; + u8 _pad1[24]; + __le64 used_size; + u8 _pad2[8]; + u8 data[]; +} __packed; + +static int parse_report(struct apple_epic_service *service, enum epic_subtype type, + const void *data, size_t data_size) +{ +#if defined(DEBUG) + struct apple_dcp *dcp = service->ep->dcp; + const struct epic_service_call *call; + const void *payload; + size_t payload_size; + + dev_dbg(dcp->dev, "dcpavserv[ch:%u]: report type:%02x len:%zu\n", + service->channel, type, data_size); + + if (type != EPIC_SUBTYPE_STD_SERVICE) + return 0; + + if (data_size < sizeof(*call)) + return 0; + + call = data; + + if (le32_to_cpu(call->magic) != EPIC_SERVICE_CALL_MAGIC) { + dev_warn(dcp->dev, "dcpavserv[ch:%u]: report magic 0x%08x != 0x%08x\n", + service->channel, le32_to_cpu(call->magic), EPIC_SERVICE_CALL_MAGIC); + return 0; + } + + payload_size = data_size - sizeof(*call); + if (payload_size < le32_to_cpu(call->data_len)) { + dev_warn(dcp->dev, "dcpavserv[ch:%u]: report payload size %zu call len %u\n", + service->channel, payload_size, le32_to_cpu(call->data_len)); + return 0; + } + payload_size = le32_to_cpu(call->data_len); + payload = data + sizeof(*call); + + if (le16_to_cpu(call->group) == 2 && le16_to_cpu(call->command) == 0) { + if (payload_size == sizeof(struct dcpavserv_status_report)) { + const struct dcpavserv_status_report *stat = payload; + dev_info(dcp->dev, "dcpavserv[ch:%u]: flags: 0x%02x,0x%02x,0x%02x,0x%02x status:%u\n", + service->channel, stat->flag0, stat->flag1, + stat->flag2, stat->flag3, stat->status); + } else { + dev_dbg(dcp->dev, "dcpavserv[ch:%u]: report payload size %zu\n", service->channel, payload_size); + } + } else { + print_hex_dump(KERN_DEBUG, "dcpavserv report: ", DUMP_PREFIX_NONE, + 16, 1, payload, payload_size, true); + } +#endif + + return 0; +} + +static int dcpavserv_report(struct apple_epic_service *service, + enum epic_subtype type, const void *data, + size_t data_size) +{ + return parse_report(service, type, data, data_size); +} + +static int dcpdpserv_report(struct apple_epic_service *service, + enum epic_subtype type, const void *data, + size_t data_size) +{ + return parse_report(service, type, data, data_size); +} + +const struct drm_edid *dcpavserv_copy_edid(struct apple_epic_service *service) +{ + struct dpavserv_copy_edid_cmd cmd; + struct dpavserv_copy_edid_resp *resp __free(kfree) = NULL; + int num_blocks; + u64 data_size; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + cmd.max_size = cpu_to_le64(EDID_BUF_SIZE); + resp = kzalloc(sizeof(*resp) + EDID_BUF_SIZE, GFP_KERNEL); + if (!resp) + return ERR_PTR(-ENOMEM); + + ret = afk_service_call(service, 1, 7, &cmd, sizeof(cmd), EDID_BUF_SIZE, resp, + sizeof(resp) + EDID_BUF_SIZE, 0); + if (ret < 0) + return ERR_PTR(ret); + + if (le64_to_cpu(resp->max_size) != EDID_BUF_SIZE) + return ERR_PTR(-EIO); + + // print_hex_dump(KERN_DEBUG, "dpavserv EDID cmd: ", DUMP_PREFIX_NONE, + // 16, 1, resp, 192, true); + + data_size = le64_to_cpu(resp->used_size); + if (data_size < EDID_LEADING_DATA_SIZE + EDID_BLOCK_SIZE) + return ERR_PTR(-EIO); + + num_blocks = resp->data[EDID_LEADING_DATA_SIZE + EDID_EXT_BLOCK_COUNT_OFFSET]; + if ((1 + num_blocks) * EDID_BLOCK_SIZE != data_size - EDID_LEADING_DATA_SIZE) + return ERR_PTR(-EIO); + + return drm_edid_alloc(resp->data + EDID_LEADING_DATA_SIZE, + data_size - EDID_LEADING_DATA_SIZE); +} + +static const struct apple_epic_service_ops dpavservep_ops[] = { + { + .name = "dcpav-service-epic", + .init = dcpavserv_init, + .teardown = dcpavserv_teardown, + .report = dcpavserv_report, + }, + { + .name = "dcpdp-service-epic", + .init = dcpdpserv_init, + .teardown = dcpdpserv_teardown, + .report = dcpdpserv_report, + }, + {}, +}; + +int dpavservep_init(struct apple_dcp *dcp) +{ + int ret; + + init_completion(&dcp->dcpavserv.enable_completion); + + dcp->dcpavservep = afk_init(dcp, DPAVSERV_ENDPOINT, dpavservep_ops); + if (IS_ERR(dcp->dcpavservep)) + return PTR_ERR(dcp->dcpavservep); + + dcp->dcpavservep->match_epic_name = true; + + ret = afk_start(dcp->dcpavservep); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&dcp->dcpavserv.enable_completion, + msecs_to_jiffies(1000)); + if (ret >= 0) + return 0; + + return ret; +} diff --git a/drivers/gpu/drm/apple/epic/dpavservep.h b/drivers/gpu/drm/apple/epic/dpavservep.h new file mode 100644 index 00000000000000..858ff14b0bd7be --- /dev/null +++ b/drivers/gpu/drm/apple/epic/dpavservep.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright The Asahi Linux Contributors */ + +#ifndef _DRM_APPLE_EPIC_DPAVSERV_H +#define _DRM_APPLE_EPIC_DPAVSERV_H + +#include +#include + +struct drm_edid; +struct apple_epic_service; + +struct dcpavserv { + bool enabled; + struct completion enable_completion; + u32 unit; + struct apple_epic_service *service; +}; + +const struct drm_edid *dcpavserv_copy_edid(struct apple_epic_service *service); + +#endif /* _DRM_APPLE_EPIC_DPAVSERV_H */ diff --git a/drivers/gpu/drm/apple/trace.h b/drivers/gpu/drm/apple/trace.h index e03bf8b199c88f..a13dd34fb7aab1 100644 --- a/drivers/gpu/drm/apple/trace.h +++ b/drivers/gpu/drm/apple/trace.h @@ -351,6 +351,18 @@ DEFINE_EVENT(iomfb_parse_mode_template, iomfb_parse_mode_fail, TP_PROTO(s64 id, struct dimension *horiz, struct dimension *vert, s64 best_color_mode, bool is_virtual, s64 score), TP_ARGS(id, horiz, vert, best_color_mode, is_virtual, score)); +TRACE_EVENT(dcpavserv_init, TP_PROTO(struct apple_dcp *dcp, u64 unit), + TP_ARGS(dcp, unit), + + TP_STRUCT__entry(__string(devname, dev_name(dcp->dev)) + __field(u64, unit)), + + TP_fast_assign(__assign_str(devname); + __entry->unit = unit;), + + TP_printk("%s: dcpav-service unit %lld initialized", __get_str(devname), + __entry->unit)); + TRACE_EVENT(dptxport_init, TP_PROTO(struct apple_dcp *dcp, u64 unit), TP_ARGS(dcp, unit), From 4099fc5eff89b7e9256a985857d9b1ee20a0bcdd Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 20 Aug 2024 22:39:06 +0200 Subject: [PATCH 217/352] drm: apple: iomfb: Provide the EDID as connector property External display only since the EDID provided by integrated panels holds no useful / correct information. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/connector.h | 3 +++ drivers/gpu/drm/apple/dcp.c | 2 ++ drivers/gpu/drm/apple/iomfb.c | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/drivers/gpu/drm/apple/connector.h b/drivers/gpu/drm/apple/connector.h index 02f2d3904b09a3..ef2c23737aac64 100644 --- a/drivers/gpu/drm/apple/connector.h +++ b/drivers/gpu/drm/apple/connector.h @@ -8,6 +8,7 @@ #include #include "drm/drm_connector.h" +#include "drm/drm_edid.h" struct apple_connector; @@ -21,6 +22,8 @@ struct apple_connector { struct platform_device *dcp; + const struct drm_edid *drm_edid; + /* Workqueue for sending hotplug events to the associated device */ struct work_struct hotplug_wq; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 65c0558391c0ea..9e56066c32048a 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -242,6 +242,8 @@ static void dcp_rtk_crashed(void *cookie, const void *crashlog, size_t crashlog_ dev_err(dcp->dev, "DCP has crashed\n"); if (dcp->connector) { dcp->connector->connected = 0; + drm_edid_free(dcp->connector->drm_edid); + dcp->connector->drm_edid = NULL; schedule_work(&dcp->connector->hotplug_wq); } complete(&dcp->start_done); diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 2fadc9e614d571..52818d34ccf7a3 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -241,6 +242,11 @@ void dcp_hotplug(struct work_struct *work) dev_info(dcp->dev, "%s() connected:%d valid_mode:%d nr_modes:%u\n", __func__, connector->connected, dcp->valid_mode, dcp->nr_modes); + if (!connector->connected) { + drm_edid_free(connector->drm_edid); + connector->drm_edid = NULL; + } + /* * DCP defers link training until we set a display mode. But we set * display modes from atomic_flush, so userspace needs to trigger a @@ -391,6 +397,20 @@ int dcp_get_modes(struct drm_connector *connector) drm_mode_probed_add(connector, mode); } + if (dcp->nr_modes && dcp->dcpavserv.enabled && + !apple_connector->drm_edid) { + const struct drm_edid *edid; + edid = dcpavserv_copy_edid(dcp->dcpavserv.service); + if (IS_ERR_OR_NULL(edid)) { + dev_info(dcp->dev, "copy_edid failed: %pe\n", edid); + } else { + drm_edid_free(apple_connector->drm_edid); + apple_connector->drm_edid = edid; + } + } + if (dcp->nr_modes && apple_connector->drm_edid) + drm_edid_connector_update(connector, apple_connector->drm_edid); + return dcp->nr_modes; } EXPORT_SYMBOL_GPL(dcp_get_modes); From b4c4ae71e48a293e8d297f618524f22a3b3bc04a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 23 Feb 2023 12:34:28 +0100 Subject: [PATCH 218/352] ALSA: Introduce 'snd_interval_rate_bits' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- include/sound/pcm.h | 1 + sound/core/pcm_lib.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index a7860c047503a8..a0c987c9bd1fee 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1073,6 +1073,7 @@ int snd_interval_ranges(struct snd_interval *i, unsigned int count, int snd_interval_ratnum(struct snd_interval *i, unsigned int rats_count, const struct snd_ratnum *rats, unsigned int *nump, unsigned int *denp); +int snd_interval_rate_bits(struct snd_interval *i, unsigned int rate_bits); void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params); void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 09c421cd9319e7..ae80091e2ff825 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1149,6 +1149,43 @@ static int snd_interval_step(struct snd_interval *i, unsigned int step) return changed; } +/** + * snd_interval_rate_bits - refine the rate interval from a rate bitmask + * @i: the rate interval to refine + * @mask: the rate bitmask + * + * Refines the interval value, assumed to be the sample rate, according to + * a bitmask of available rates (an ORed combination of SNDRV_PCM_RATE_*). + * + * Return: Positive if the value is changed, zero if it's not changed, or a + * negative error code. + */ +int snd_interval_rate_bits(struct snd_interval *i, unsigned int mask) +{ + unsigned int k; + struct snd_interval mask_range; + + if (!mask) + return -EINVAL; + + snd_interval_any(&mask_range); + mask_range.min = UINT_MAX; + mask_range.max = 0; + for (k = 0; k < snd_pcm_known_rates.count; k++) { + unsigned int rate = snd_pcm_known_rates.list[k]; + if (!(mask & (1 << k))) + continue; + + if (rate > mask_range.max) + mask_range.max = rate; + + if (rate < mask_range.min) + mask_range.min = rate; + } + return snd_interval_refine(i, &mask_range); +} +EXPORT_SYMBOL(snd_interval_rate_bits); + /* Info constraints helpers */ /** From 62a79564a36f29a8aefc293a40bda71b3a257f33 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 9 Nov 2024 10:17:06 +0100 Subject: [PATCH 219/352] drm: apple: Enable EDID support by default Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 9e56066c32048a..97a2ee5cd45f40 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -50,7 +50,7 @@ bool hdmi_audio; module_param(hdmi_audio, bool, 0644); MODULE_PARM_DESC(hdmi_audio, "Enable unstable HDMI audio support"); -static bool unstable_edid; +static bool unstable_edid = true; module_param(unstable_edid, bool, 0644); MODULE_PARM_DESC(unstable_edid, "Enable unstable EDID retrival support"); From 965ac5b12ce10472dc05cdaf2c8ea9818d77e4fc Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 31 Aug 2024 14:26:01 +0200 Subject: [PATCH 220/352] drm: apple: audio: Implement runtime PM support Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/audio.c | 45 ++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/apple/audio.c b/drivers/gpu/drm/apple/audio.c index b78e3895987103..38718e2f56117b 100644 --- a/drivers/gpu/drm/apple/audio.c +++ b/drivers/gpu/drm/apple/audio.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -377,6 +378,7 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (!dcpaud_connection_up(dcpaud)) return -ENXIO; + WARN_ON(pm_runtime_get_sync(dcpaud->dev) < 0); ret = dcp_audiosrv_startlink(dcpaud->dcp_dev, &dcpaud->selected_cookie); if (ret < 0) @@ -403,6 +405,8 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: ret = dcp_audiosrv_stoplink(dcpaud->dcp_dev); + pm_runtime_mark_last_busy(dcpaud->dev); + __pm_runtime_put_autosuspend(dcpaud->dev); if (ret < 0) return ret; break; @@ -605,6 +609,13 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) int index; int ret; + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable runtime PM: %d\n", ret); + /* find linked DCP instance */ endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); if (endpoint) { @@ -614,35 +625,34 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) if (!dcp_node || !of_device_is_available(dcp_node)) { of_node_put(dcp_node); dev_info(dev, "No audio support\n"); - return 0; + goto rpm_put; } index = of_property_match_string(dev->of_node, "dma-names", "tx"); if (index < 0) { dev_err(dev, "No dma-names property\n"); - return 0; + goto rpm_put; } if (of_parse_phandle_with_args(dev->of_node, "dmas", "#dma-cells", index, &dma_spec) || !dma_spec.np) { dev_err(dev, "Failed to parse dmas property\n"); - return 0; + goto rpm_put; } dcp_pdev = of_find_device_by_node(dcp_node); of_node_put(dcp_node); if (!dcp_pdev) { dev_info(dev, "No DP/HDMI audio device, dcp not ready\n"); - return 0; + goto rpm_put; } dcpaud->dcp_dev = &dcp_pdev->dev; - dma_pdev = of_find_device_by_node(dma_spec.np); of_node_put(dma_spec.np); if (!dma_pdev) { dev_info(dev, "No DMA device\n"); - return 0; + goto rpm_put; } dcpaud->dma_dev = &dma_pdev->dev; @@ -663,6 +673,9 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data) DCPAUD_PRODUCTATTRS_MAXSIZE); } +rpm_put: + pm_runtime_put(dev); + return 0; } @@ -718,7 +731,22 @@ static void dcpaud_shutdown(struct platform_device *pdev) component_del(&pdev->dev, &dcpaud_comp_ops); } -// static DEFINE_SIMPLE_DEV_PM_OPS(dcpaud_pm_ops, dcpaud_suspend, dcpaud_resume); +static __maybe_unused int dcpaud_suspend(struct device *dev) +{ + /* + * Using snd_power_change_state() does not work since the sound card + * is what resumes runtime PM. + */ + + return 0; +} + +static __maybe_unused int dcpaud_resume(struct device *dev) +{ + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(dcpaud_pm_ops, dcpaud_suspend, dcpaud_resume, NULL); static const struct of_device_id dcpaud_of_match[] = { { .compatible = "apple,dpaudio" }, @@ -728,7 +756,8 @@ static const struct of_device_id dcpaud_of_match[] = { static struct platform_driver dcpaud_driver = { .driver = { .name = "dcp-dp-audio", - .of_match_table = dcpaud_of_match, + .of_match_table = dcpaud_of_match, + .pm = pm_ptr(&dcpaud_pm_ops), }, .probe = dcpaud_probe, .remove = dcpaud_remove, From e81bddfd2629c80c2051a25008283f48c8c40fcf Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 22 Jul 2024 20:26:55 +0200 Subject: [PATCH 221/352] drm: apple: Add CRTC CRC support The DCP firmware has CRC support. While this is not yet reverse engineering report always 0 to at least be able to run tests from igt-gpu-tools with "--skip-crc-compare". Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 57 ++++++++++++++++++++++++++ drivers/gpu/drm/apple/dcp-internal.h | 3 ++ drivers/gpu/drm/apple/dcp.c | 11 +++++ drivers/gpu/drm/apple/dcp.h | 1 + drivers/gpu/drm/apple/iomfb_template.c | 4 ++ 5 files changed, 76 insertions(+) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 613856d0af5895..8d36c579b90f14 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -261,6 +261,59 @@ static void apple_crtc_cleanup(struct drm_crtc *crtc) kfree(to_apple_crtc(crtc)); } +static int apple_crtc_parse_crc_source(const char *source, bool *enabled) +{ + int ret = 0; + + if (!source) { + *enabled = false; + } else if (strcmp(source, "auto") == 0) { + *enabled = true; + } else { + *enabled = false; + ret = -EINVAL; + } + + return ret; +} + +static int apple_crtc_set_crc_source(struct drm_crtc *crtc, const char *source) +{ + bool enabled = false; + + int ret = apple_crtc_parse_crc_source(source, &enabled); + + if (!ret) + dcp_set_crc(crtc, enabled); + + return ret; +} + +static int apple_crtc_verify_crc_source(struct drm_crtc *crtc, + const char *source, + size_t *values_cnt) +{ + bool enabled; + + if (apple_crtc_parse_crc_source(source, &enabled) < 0) { + pr_warn("dcp: Invalid CRC source name %s\n", source); + return -EINVAL; + } + + *values_cnt = 1; + + return 0; +} + +static const char * const apple_crtc_crc_sources[] = {"auto"}; + +static const char *const * apple_crtc_get_crc_sources(struct drm_crtc *crtc, + size_t *count) +{ + *count = ARRAY_SIZE(apple_crtc_crc_sources); + return apple_crtc_crc_sources; +} + static const struct drm_crtc_funcs apple_crtc_funcs = { .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, @@ -268,6 +321,10 @@ static const struct drm_crtc_funcs apple_crtc_funcs = { .page_flip = drm_atomic_helper_page_flip, .reset = drm_atomic_helper_crtc_reset, .set_config = drm_atomic_helper_set_config, + .set_crc_source = apple_crtc_set_crc_source, + .verify_crc_source = apple_crtc_verify_crc_source, + .get_crc_sources = apple_crtc_get_crc_sources, + }; static const struct drm_mode_config_funcs apple_mode_config_funcs = { diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index d678a1965b5f0d..793d32dafe8472 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -198,6 +198,9 @@ struct apple_dcp { /* clear all surfaces on init */ bool surfaces_cleared; + /* enable CRC calculation */ + bool crc_enabled; + /* Modes valid for the connected display */ struct dcp_display_mode *modes; unsigned int nr_modes; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 97a2ee5cd45f40..f86b07fe4d211b 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -191,6 +191,17 @@ bool dcp_has_panel(struct apple_dcp *dcp) return dcp->panel.width_mm > 0; } +int dcp_set_crc(struct drm_crtc *crtc, bool enabled) +{ + struct apple_crtc *ac = to_apple_crtc(crtc); + struct apple_dcp *dcp = platform_get_drvdata(ac->dcp); + + dcp->crc_enabled = enabled; + + return 0; +} +EXPORT_SYMBOL_GPL(dcp_set_crc); + /* * Helper to send a DRM vblank event. We do not know how call swap_submit_dcp * without surfaces. To avoid timeouts in drm_atomic_helper_wait_for_vblanks diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index b1a151140c9048..0505032abe5497 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -31,6 +31,7 @@ struct apple_encoder { void dcp_poweroff(struct platform_device *pdev); void dcp_poweron(struct platform_device *pdev); +int dcp_set_crc(struct drm_crtc *crtc, bool enabled); int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state); int dcp_get_connector_type(struct platform_device *pdev); void dcp_link(struct platform_device *pdev, struct apple_crtc *apple, diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 6d23e0d43467e1..56d3fed171ad0b 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -125,6 +125,10 @@ static void dcpep_cb_swap_complete(struct apple_dcp *dcp, dcp->last_swap_id = resp->swap_id; dcp_drm_crtc_page_flip(dcp, now); + if (dcp->crc_enabled) { + u32 crc32 = 0; + drm_crtc_add_crc_entry(&dcp->crtc->base, true, resp->swap_id, &crc32); + } } /* special */ From 68fcae4a67b28c714bfe40483238d2e7ab443790 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 7 Dec 2024 21:50:40 +0100 Subject: [PATCH 222/352] drm: apple: Add .get_scanout_buffer for drm_panic support Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 8d36c579b90f14..ea3483f83be961 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -119,6 +119,7 @@ static void apple_plane_atomic_update(struct drm_plane *plane, static const struct drm_plane_helper_funcs apple_plane_helper_funcs = { .atomic_check = apple_plane_atomic_check, .atomic_update = apple_plane_atomic_update, + .get_scanout_buffer = drm_fb_dma_get_scanout_buffer, }; static void apple_plane_cleanup(struct drm_plane *plane) From 6112b933f922d463f4e8fc91fcb37f35176d206b Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 12 May 2024 21:02:40 +1000 Subject: [PATCH 223/352] drm: apple: respect drm_plane_state zpos The for_each_oldnew_plane_in_state iterator is nondeterministic in terms of the order of planes. DCP expects surfaces to be fed to it in the correct order. Relying on the iterator to lazily increment the index into surf[] means we cannot meet this expectation. The constant reordering of planes in the surf[] array seems to cause DCP to crash under certain circumstances. Cursors will also often be drawn under the main plane, which is less than ideal. Populate surf[] in the order everyone expects us to. This fixes a whole host of odd behaviour when wiring up multiple DRM universal planes. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_template.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 56d3fed171ad0b..483179bed1048e 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1295,8 +1295,6 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru dcp->surfaces_cleared = true; } - // Surface 0 has limitations at least on t600x. - l = 1; for_each_oldnew_plane_in_state(state, plane, old_state, new_state, plane_idx) { struct drm_framebuffer *fb = new_state->fb; struct drm_gem_dma_object *obj; @@ -1307,6 +1305,17 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru if (old_state->crtc != crtc && new_state->crtc != crtc) continue; + /* + * Plane order is nondeterministic for this iterator. DCP will + * almost always crash at some point if the z order of planes + * flip-flops around. Make sure we are always blending them + * in the correct order. + * + * Despite having 4 surfaces, we can only blend two. Surface 0 is + * also unusable on some machines, so ignore it. + */ + l = 2 - new_state->zpos; + WARN_ON(l >= SWAP_SURFACES); req->swap.swap_enabled |= BIT(l); @@ -1333,7 +1342,6 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru } if (!new_state->fb) { - l += 1; continue; } req->surf_null[l] = false; @@ -1383,7 +1391,6 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru .has_planes = 1, }; - l += 1; } if (!has_surface && !crtc_state->color_mgmt_changed) { From 67cb76eb9397db1bdb7c9b7f3e14dab1caacf448 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Tue, 14 May 2024 19:23:04 +1000 Subject: [PATCH 224/352] drm: apple: constrain swaps to maximum blendable surfaces Despite having 4 surfaces, DCP can only blend two of them at once. Constrain swaps to two surfaces, and warn if userspace somehow tries to give us more to swap. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb.h | 2 ++ drivers/gpu/drm/apple/iomfb_template.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index ffd049e0cf32d1..3728c20d2f0391 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -77,6 +77,8 @@ enum iomfb_property_id { /* Structures used in v12.0 firmware */ #define SWAP_SURFACES 4 +/* We have 4 surfaces, but we can only ever blend two */ +#define MAX_BLEND_SURFACES 2 #define MAX_PLANES 3 enum dcp_colorspace { diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 483179bed1048e..ee906a21bb4190 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -904,6 +904,7 @@ void DCP_FW_NAME(iomfb_poweroff)(struct apple_dcp *dcp) swap->swap.bl_power = 0; } + /* Null all surfaces */ for (int l = 0; l < SWAP_SURFACES; l++) swap->surf_null[l] = true; #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) @@ -1274,7 +1275,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - /* Reset to defaults */ + /* Reset all surfaces to defaults */ memset(req, 0, sizeof(*req)); for (l = 0; l < SWAP_SURFACES; l++) req->surf_null[l] = true; @@ -1314,9 +1315,10 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru * Despite having 4 surfaces, we can only blend two. Surface 0 is * also unusable on some machines, so ignore it. */ - l = 2 - new_state->zpos; - WARN_ON(l >= SWAP_SURFACES); + l = MAX_BLEND_SURFACES - new_state->zpos; + + WARN_ON(l > MAX_BLEND_SURFACES); req->swap.swap_enabled |= BIT(l); From 4c0c3480f4f38842f3be3107196436c3361b9b96 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Tue, 14 May 2024 20:42:20 +1000 Subject: [PATCH 225/352] drm: apple: reject plane commit if it will crash DCP Owing to its origin in mobile devices and the Apple TV, DCP seems to have been designed under the assumption that no one could possibly want a rectangle to clip the screen. If a rectangle's bottom-right edge clips the screen, DCP will instead try to scale the destination rectangle to the best of its ability... until it can't anymore. DCP is not tolerant to faults and will crash if the onscreen portion of the framebuffer ends up smaller than 32x32, or if any dimension ends up entirely offscreen. Use apple_plane_atomic_check() to reject requested plane states that could crash DCP. This is the final piece of the puzzle required to enable preliminary support for overlay planes on Apple Silicon devices. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/apple_drv.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index ea3483f83be961..6ceb604b93ce6a 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -91,6 +91,19 @@ static int apple_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); + /* + * DCP does not allow a surface to clip off the screen, and will crash + * if any blended surface is smaller than 32x32. Reject the atomic op + * if the plane will crash DCP. + * + * This is most pertinent to cursors. Userspace should fall back to + * software cursors if the plane check is rejected. + */ + if ((new_plane_state->crtc_x + 32) > crtc_state->mode.hdisplay || + (new_plane_state->crtc_y + 32) > crtc_state->mode.vdisplay) { + return -EINVAL; + } + /* * DCP limits downscaling to 2x and upscaling to 4x. Attempting to * scale outside these bounds errors out when swapping. From 4ea02c8de1e3d25355a9c5ed03ac2eb596c46856 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Tue, 14 May 2024 21:03:25 +1000 Subject: [PATCH 226/352] drm: apple: add support for overlay planes DCP is capable of compositing two surfaces in hardware. This is important for zero-copy video playback, etc. Set up an overlay plane so that userspace can do cool things with it. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/apple_drv.c | 62 +++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 6ceb604b93ce6a..350da9e71e4236 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -129,12 +129,17 @@ static void apple_plane_atomic_update(struct drm_plane *plane, /* Handled in atomic_flush */ } -static const struct drm_plane_helper_funcs apple_plane_helper_funcs = { +static const struct drm_plane_helper_funcs apple_primary_plane_helper_funcs = { .atomic_check = apple_plane_atomic_check, .atomic_update = apple_plane_atomic_update, .get_scanout_buffer = drm_fb_dma_get_scanout_buffer, }; +static const struct drm_plane_helper_funcs apple_plane_helper_funcs = { + .atomic_check = apple_plane_atomic_check, + .atomic_update = apple_plane_atomic_update, +}; + static void apple_plane_cleanup(struct drm_plane *plane) { drm_plane_cleanup(plane); @@ -161,7 +166,7 @@ static const struct drm_plane_funcs apple_plane_funcs = { * doesn't matter for the primary plane, but cursors/overlays must not * advertise formats without alpha. */ -static const u32 dcp_formats[] = { +static const u32 dcp_primary_formats[] = { DRM_FORMAT_XRGB2101010, DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, @@ -169,6 +174,11 @@ static const u32 dcp_formats[] = { DRM_FORMAT_ABGR8888, }; +static const u32 dcp_overlay_formats[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, +}; + u64 apple_format_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID @@ -183,14 +193,31 @@ static struct drm_plane *apple_plane_init(struct drm_device *dev, plane = kzalloc(sizeof(*plane), GFP_KERNEL); - ret = drm_universal_plane_init(dev, plane, possible_crtcs, + switch (type) { + case DRM_PLANE_TYPE_PRIMARY: + ret = drm_universal_plane_init(dev, plane, possible_crtcs, &apple_plane_funcs, - dcp_formats, ARRAY_SIZE(dcp_formats), + dcp_primary_formats, ARRAY_SIZE(dcp_primary_formats), apple_format_modifiers, type, NULL); + break; + case DRM_PLANE_TYPE_OVERLAY: + case DRM_PLANE_TYPE_CURSOR: + ret = drm_universal_plane_init(dev, plane, possible_crtcs, + &apple_plane_funcs, + dcp_overlay_formats, ARRAY_SIZE(dcp_overlay_formats), + apple_format_modifiers, type, NULL); + break; + default: + return NULL; + } + if (ret) return ERR_PTR(ret); - drm_plane_helper_add(plane, &apple_plane_helper_funcs); + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(plane, &apple_primary_plane_helper_funcs); + else + drm_plane_helper_add(plane, &apple_plane_helper_funcs); return plane; } @@ -390,16 +417,29 @@ static int apple_probe_per_dcp(struct device *dev, struct apple_crtc *crtc; struct apple_connector *connector; struct apple_encoder *enc; - struct drm_plane *primary; - int ret; + struct drm_plane *planes[DCP_MAX_PLANES]; + int ret, i; + + planes[0] = apple_plane_init(drm, 1U << num, DRM_PLANE_TYPE_PRIMARY); + if (IS_ERR(planes[0])) + return PTR_ERR(planes[0]); - primary = apple_plane_init(drm, 1U << num, DRM_PLANE_TYPE_PRIMARY); - if (IS_ERR(primary)) - return PTR_ERR(primary); + /* Set up our other planes */ + for (i = 1; i < DCP_MAX_PLANES; i++) { + planes[i] = apple_plane_init(drm, 1U << num, DRM_PLANE_TYPE_OVERLAY); + if (IS_ERR(planes[i])) + return PTR_ERR(planes[i]); + } + /* + * Even though we have an overlay plane, we cannot expose it to legacy + * userspace for cursors as we cannot make the same guarantees as ye olde + * hardware cursor planes such userspace would expect us to. Modern userspace + * knows what to do with overlays. + */ crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); - ret = drm_crtc_init_with_planes(drm, &crtc->base, primary, NULL, + ret = drm_crtc_init_with_planes(drm, &crtc->base, planes[0], NULL, &apple_crtc_funcs, NULL); if (ret) return ret; From 8829108d0ae96aa3cbe4e6d24057a91ad875fa6e Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Tue, 14 May 2024 22:04:28 +1000 Subject: [PATCH 227/352] drm: apple: use correct min/max plane scaling factors Fix the call to drm_atomic_helper_check_plane_state to use the correct scaling factors. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/apple_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 350da9e71e4236..45bdc4340bf38a 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -118,8 +118,8 @@ static int apple_plane_atomic_check(struct drm_plane *plane, */ return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - FRAC_16_16(1, 4), - FRAC_16_16(2, 1), + FRAC_16_16(1, 2), + FRAC_16_16(4, 1), true, true); } From ed938f2e770d5745eaa64cad76a45c8db0a4de16 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Wed, 15 May 2024 20:42:07 +1000 Subject: [PATCH 228/352] drm: apple: warn about broken sw cursor fallback Some userspace may not handle invalid plane checks gracefully when falling back to a software cursor. This will manifest as the screen freezing, recoverable by moving the cursor away from a screen edge. Throw a warning once to let the user know why this has happened. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/apple_drv.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 45bdc4340bf38a..9fe6de168e123a 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -101,6 +101,18 @@ static int apple_plane_atomic_check(struct drm_plane *plane, */ if ((new_plane_state->crtc_x + 32) > crtc_state->mode.hdisplay || (new_plane_state->crtc_y + 32) > crtc_state->mode.vdisplay) { + dev_err_once(state->dev->dev, + "Plane operation would have crashed DCP! Rejected!\n\ + DCP requires 32x32 of every plane to be within screen space.\n\ + Your compositor asked for a screen space area of [%d, %d].\n\ + This is not supported, and your compositor should have\n\ + switched to software compositing when this operation failed.\n\ + You should not have noticed this at all. If your screen\n\ + froze/hitched, or your compositor crashed, please report\n\ + this to the your compositor's developers. We will not\n\ + throw this error again until you next reboot.\n", + crtc_state->mode.hdisplay - new_plane_state->crtc_x, + crtc_state->mode.vdisplay - new_plane_state->crtc_y); return -EINVAL; } From bc1ec24c7ca4827fb230007d53a1f6d47037fac4 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Mon, 1 Jul 2024 17:27:05 +1000 Subject: [PATCH 229/352] drm: apple: make plane zpos immutable Userspace cannot be trusted to give us a sane zpos value, but given DCP's requirement that the primary plane always be the bottommost surface, we can't rely on drm_atomic_normalize_zpos() to do the job for us either. Make the zpos property immutable, and keep the primary plane at zpos 0. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/apple_drv.c | 11 +++++++++++ drivers/gpu/drm/apple/iomfb_template.c | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 9fe6de168e123a..b38e2170a41728 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -431,10 +432,15 @@ static int apple_probe_per_dcp(struct device *dev, struct apple_encoder *enc; struct drm_plane *planes[DCP_MAX_PLANES]; int ret, i; + int immutable_zpos = 0; planes[0] = apple_plane_init(drm, 1U << num, DRM_PLANE_TYPE_PRIMARY); if (IS_ERR(planes[0])) return PTR_ERR(planes[0]); + ret = drm_plane_create_zpos_immutable_property(planes[0], immutable_zpos); + if (ret) { + return ret; + } /* Set up our other planes */ @@ -442,6 +448,11 @@ static int apple_probe_per_dcp(struct device *dev, planes[i] = apple_plane_init(drm, 1U << num, DRM_PLANE_TYPE_OVERLAY); if (IS_ERR(planes[i])) return PTR_ERR(planes[i]); + immutable_zpos++; + ret = drm_plane_create_zpos_immutable_property(planes[i], immutable_zpos); + if (ret) { + return ret; + } } /* diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index ee906a21bb4190..91d140498be2e9 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1316,7 +1316,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru * also unusable on some machines, so ignore it. */ - l = MAX_BLEND_SURFACES - new_state->zpos; + l = MAX_BLEND_SURFACES - new_state->normalized_zpos; WARN_ON(l > MAX_BLEND_SURFACES); From 52ed1836c44a33ea3a09cd51742923bdc8234619 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 8 Dec 2024 15:51:37 +0100 Subject: [PATCH 230/352] drm: apple: refactor apple_plane_atomic_check Call drm_atomic_helper_check_plane_state() first as this allows using the dst rectangle in the new plane state for the off-screen render check. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 41 ++++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index b38e2170a41728..954c388786a827 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -82,6 +82,7 @@ static int apple_plane_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state; struct drm_crtc_state *crtc_state; + int ret; new_plane_state = drm_atomic_get_new_plane_state(state, plane); @@ -92,6 +93,28 @@ static int apple_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); + /* + * DCP limits downscaling to 2x and upscaling to 4x. Attempting to + * scale outside these bounds errors out when swapping. + * + * This function also takes care of clipping the src/dest rectangles, + * which is required for correct operation. Partially off-screen + * surfaces may appear corrupted. + * + * DCP does not distinguish plane types in the hardware, so we set + * can_position. If the primary plane does not fill the screen, the + * hardware will fill in zeroes (black). + */ + ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, + FRAC_16_16(1, 2), + FRAC_16_16(4, 1), + true, true); + if (ret < 0) + return ret; + + if (!new_plane_state->visible) + return 0; + /* * DCP does not allow a surface to clip off the screen, and will crash * if any blended surface is smaller than 32x32. Reject the atomic op @@ -117,23 +140,7 @@ static int apple_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } - /* - * DCP limits downscaling to 2x and upscaling to 4x. Attempting to - * scale outside these bounds errors out when swapping. - * - * This function also takes care of clipping the src/dest rectangles, - * which is required for correct operation. Partially off-screen - * surfaces may appear corrupted. - * - * DCP does not distinguish plane types in the hardware, so we set - * can_position. If the primary plane does not fill the screen, the - * hardware will fill in zeroes (black). - */ - return drm_atomic_helper_check_plane_state(new_plane_state, - crtc_state, - FRAC_16_16(1, 2), - FRAC_16_16(4, 1), - true, true); + return 0; } static void apple_plane_atomic_update(struct drm_plane *plane, From ed6420388148d7d6c24ea9c4b2c4e1e229065ff7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 8 Dec 2024 15:54:35 +0100 Subject: [PATCH 231/352] drm: apple: Use dest rct in offscreen test The plane state's dst rectangle is what's used to set dcp parameters and the KMS documentation actively recommends that over crtc_x / crtc_y. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 954c388786a827..3b7947cebde15e 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -82,6 +82,7 @@ static int apple_plane_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state; struct drm_crtc_state *crtc_state; + struct drm_rect *dst; int ret; new_plane_state = drm_atomic_get_new_plane_state(state, plane); @@ -123,20 +124,20 @@ static int apple_plane_atomic_check(struct drm_plane *plane, * This is most pertinent to cursors. Userspace should fall back to * software cursors if the plane check is rejected. */ - if ((new_plane_state->crtc_x + 32) > crtc_state->mode.hdisplay || - (new_plane_state->crtc_y + 32) > crtc_state->mode.vdisplay) { + dst = &new_plane_state->dst; + if (drm_rect_width(dst) < 32 || drm_rect_height(dst) < 32) { dev_err_once(state->dev->dev, "Plane operation would have crashed DCP! Rejected!\n\ DCP requires 32x32 of every plane to be within screen space.\n\ - Your compositor asked for a screen space area of [%d, %d].\n\ + Your compositor asked to overlay [%dx%d, %dx%d] on %dx%d.\n\ This is not supported, and your compositor should have\n\ switched to software compositing when this operation failed.\n\ You should not have noticed this at all. If your screen\n\ froze/hitched, or your compositor crashed, please report\n\ this to the your compositor's developers. We will not\n\ throw this error again until you next reboot.\n", - crtc_state->mode.hdisplay - new_plane_state->crtc_x, - crtc_state->mode.vdisplay - new_plane_state->crtc_y); + dst->x1, dst->y1, dst->x2, dst->y2, + crtc_state->mode.hdisplay, crtc_state->mode.vdisplay); return -EINVAL; } From f80dbbea8effd0255fb46a5e7fe1ac3c00382df2 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 18 Jan 2025 09:10:09 +0100 Subject: [PATCH 232/352] drm: apple: iomfb: Clear non-visible planes Fixes failed DCP swap validity checks and subsequent DCP crashes. Fixes: 5536a93235a3c ("drm: apple: refactor apple_plane_atomic_check") Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 91d140498be2e9..03766fd33978bb 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1343,7 +1343,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru drm_framebuffer_get(old_state->fb); } - if (!new_state->fb) { + if (!new_state->fb || !new_state->visible) { continue; } req->surf_null[l] = false; From 9681bcf16aadf5a4b3f6a10d3b9a8dfbb94ad0f1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 4 Aug 2024 18:46:04 +0200 Subject: [PATCH 233/352] drm: apple: Call dptxport_set_hpd in dcp_dptx_connect Also increases the connection timeout to 2 seconds. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index f86b07fe4d211b..1844f2b0f48452 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -370,7 +370,7 @@ int dcp_get_connector_type(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(dcp_get_connector_type); -#define DPTX_CONNECT_TIMEOUT msecs_to_jiffies(1000) +#define DPTX_CONNECT_TIMEOUT msecs_to_jiffies(2000) static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) { @@ -410,6 +410,9 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) usleep_range(5, 10); + if (dcp->connector_type == DRM_MODE_CONNECTOR_DisplayPort) + dptxport_set_hpd(dcp->dptxport[port].service, true); + return 0; out_unlock: @@ -417,17 +420,6 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) return ret; } -int dcp_dptx_connect_oob(struct platform_device *pdev, u32 port) -{ - struct apple_dcp *dcp = platform_get_drvdata(pdev); - int err = dcp_dptx_connect(dcp, port); - if (err < 0) - return err; - dptxport_set_hpd(dcp->dptxport[port].service, true); - return 0; -} -EXPORT_SYMBOL_GPL(dcp_dptx_connect_oob); - static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) { dev_info(dcp->dev, "%s(port=%d)\n", __func__, port); @@ -442,6 +434,13 @@ static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) return 0; } +int dcp_dptx_connect_oob(struct platform_device *pdev, u32 port) +{ + struct apple_dcp *dcp = platform_get_drvdata(pdev); + return dcp_dptx_connect(dcp, port); +} +EXPORT_SYMBOL_GPL(dcp_dptx_connect_oob); + int dcp_dptx_disconnect_oob(struct platform_device *pdev, u32 port) { struct apple_dcp *dcp = platform_get_drvdata(pdev); From ee548bf815fbaec232c37a5d1541669be5c811ac Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 30 Jul 2024 22:00:45 +0200 Subject: [PATCH 234/352] drm: apple: Support up to 3 DCP instances. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 3b7947cebde15e..a10ed402814880 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -46,7 +46,7 @@ #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) -#define MAX_COPROCESSORS 2 +#define MAX_COPROCESSORS 3 struct apple_drm_private { struct drm_device drm; From 19466861872a838538137faf3c6b146afcc718d0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 3 Aug 2024 15:41:00 +0200 Subject: [PATCH 235/352] drm: apple: Handle dcps with "phys" property as dcpext Required for dp-altmode on M2 Mac Mini which will use dcp to drive dp-altmode. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index a10ed402814880..e5e8496c98507b 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -562,7 +562,8 @@ static int apple_drm_init_dcp(struct device *dev) of_node_put(np); continue; } - dcp_ext = of_device_is_compatible(np, "apple,dcpext"); + dcp_ext = of_device_is_compatible(np, "apple,dcpext") || + of_property_present(np, "phys"); dcp[num_dcp] = of_find_device_by_node(np); of_node_put(np); From 03d12c4332e2191a220586570ac87460d27ebd6a Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 16 Jan 2025 23:29:40 +0100 Subject: [PATCH 236/352] drm: apple: dptx: Silence DPTX_APCALL_{GET,SET}_DOWN_SPREAD Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index b8cb7f00133760..0f286401448ff7 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -542,6 +542,9 @@ static int dptxport_call(struct apple_epic_service *service, u32 idx, /* just try to ACK and hope for the best... */ dev_info(service->ep->dcp->dev, "DPTXPort: acking unhandled call %u\n", idx); + fallthrough; + case DPTX_APCALL_GET_DOWN_SPREAD: + case DPTX_APCALL_SET_DOWN_SPREAD: memcpy(reply, data, min(reply_size, data_size)); if (reply_size >= 4) memset(reply, 0, 4); From 0d6a4d8e9dcb1c287cbd7b112440b0f097646f6c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 16 Jan 2025 23:23:15 +0100 Subject: [PATCH 237/352] drm: apple: dptx: Tidy up lane count handling Do not try to configure the DP phy's lane count as this is configured by cd321x via the USB type-c mux. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 0f286401448ff7..2669cbecd05ffa 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -257,7 +257,7 @@ static int dptxport_call_get_max_lane_count(struct apple_epic_service *service, return -EINVAL; reply->retcode = cpu_to_le32(0); - reply->lane_count = cpu_to_le64(4); + reply->lane_count = cpu_to_le64(2); ret = phy_validate(dptx->atcphy, PHY_MODE_DP, 0, &phy_ops); if (ret < 0 || phy_ops.dp.lanes < 2) { @@ -265,9 +265,11 @@ static int dptxport_call_get_max_lane_count(struct apple_epic_service *service, // switched to DP alt mode dev_dbg(service->ep->dcp->dev, "get_max_lane_count: " "phy_validate ret:%d lanes:%d\n", ret, phy_ops.dp.lanes); + dptx->lane_count = 0; } else { reply->retcode = cpu_to_le32(0); reply->lane_count = cpu_to_le64(phy_ops.dp.lanes); + dptx->lane_count = phy_ops.dp.lanes; } return 0; @@ -278,6 +280,7 @@ static int dptxport_call_set_active_lane_count(struct apple_epic_service *servic void *reply_, size_t reply_size) { struct dptx_port *dptx = service->cookie; + struct apple_dcp *dcp = service->ep->dcp; const struct dptxport_apcall_set_active_lane_count *request = data; struct dptxport_apcall_set_active_lane_count *reply = reply_; int ret = 0; @@ -290,34 +293,26 @@ static int dptxport_call_set_active_lane_count(struct apple_epic_service *servic u64 lane_count = cpu_to_le64(request->lane_count); + if (dptx->lane_count < lane_count) + dev_err(dcp->dev, "set_active_lane_count: unexpected lane " + "count:%llu phy: %d\n", lane_count, dptx->lane_count); + switch (lane_count) { case 0 ... 2: case 4: dptx->phy_ops.dp.lanes = lane_count; - dptx->phy_ops.dp.set_lanes = 1; break; default: - dev_err(service->ep->dcp->dev, "set_active_lane_count: invalid lane count:%llu\n", lane_count); + dev_err(dcp->dev, "set_active_lane_count: invalid lane count:%llu\n", lane_count); retcode = 1; lane_count = 0; break; } - if (dptx->phy_ops.dp.set_lanes) { - if (dptx->atcphy) { - ret = phy_configure(dptx->atcphy, &dptx->phy_ops); - if (ret) - return ret; - } - dptx->phy_ops.dp.set_lanes = 0; - } - - dptx->lane_count = lane_count; - reply->retcode = cpu_to_le32(retcode); reply->lane_count = cpu_to_le64(lane_count); - if (dptx->lane_count > 0) + if (lane_count > 0) complete(&dptx->linkcfg_completion); return ret; From 1b3fd28601a4dcfe14111a830ce3b276174c3b39 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 18 Jan 2025 10:04:57 +0100 Subject: [PATCH 238/352] drm: apple: afk: Allow replies after service 'teardown' 'teardown' on DCP's 'av' endpoint's DCPAVAudioInterface is send during the close afk_service_call. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/afk.c | 14 +++++++++++++- drivers/gpu/drm/apple/afk.h | 1 + drivers/gpu/drm/apple/av.c | 2 ++ drivers/gpu/drm/apple/epic/dpavservep.c | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/afk.c b/drivers/gpu/drm/apple/afk.c index bd1f16e8937c74..d0de72072877b8 100644 --- a/drivers/gpu/drm/apple/afk.c +++ b/drivers/gpu/drm/apple/afk.c @@ -308,6 +308,7 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel, ch_idx = ep->num_channels++; spin_lock_init(&ep->services[ch_idx].lock); ep->services[ch_idx].enabled = true; + ep->services[ch_idx].torndown = false; ep->services[ch_idx].ops = ops; ep->services[ch_idx].ep = ep; ep->services[ch_idx].channel = channel; @@ -340,7 +341,12 @@ static void afk_recv_handle_teardown(struct apple_dcp_afkep *ep, u32 channel) // TODO: think through what locking is necessary spin_lock_irqsave(&service->lock, flags); - service->enabled = false; + /* + * teardown must not disable the service since since it may be sent as + * side effect of a COMMAND which for which a reply is expected. + * Seen with DCP's "av" endpoint during the close afk_service_call. + */ + service->torndown = true; ops = service->ops; spin_unlock_irqrestore(&service->lock, flags); @@ -445,6 +451,12 @@ static void afk_recv_handle_std_service(struct apple_dcp_afkep *ep, u32 channel, ep->endpoint, channel); return; } + if (service->torndown) { + dev_warn(ep->dcp->dev, + "AFK[ep:%02x]: std service notify on torn down service " + "(chan:%u)\n", ep->endpoint, channel); + return; + } if (type == EPIC_TYPE_NOTIFY && eshdr->category == EPIC_CAT_NOTIFY) { struct epic_std_service_ap_call *call = payload; diff --git a/drivers/gpu/drm/apple/afk.h b/drivers/gpu/drm/apple/afk.h index 5a286799835248..a339c00a2a0138 100644 --- a/drivers/gpu/drm/apple/afk.h +++ b/drivers/gpu/drm/apple/afk.h @@ -46,6 +46,7 @@ struct apple_epic_service { u32 channel; bool enabled; + bool torndown; void *cookie; diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index 586f39cc11ca11..f498271da9081c 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -74,6 +74,8 @@ static void av_interface_teardown(struct apple_epic_service *service) struct apple_dcp *dcp = service->ep->dcp; struct audiosrv_data *asrv = dcp->audiosrv; + service->enabled = false; + mutex_lock(&asrv->plug_lock); asrv->plugged = false; diff --git a/drivers/gpu/drm/apple/epic/dpavservep.c b/drivers/gpu/drm/apple/epic/dpavservep.c index aa2cbc729a37d4..2de9d2fe4c24a3 100644 --- a/drivers/gpu/drm/apple/epic/dpavservep.c +++ b/drivers/gpu/drm/apple/epic/dpavservep.c @@ -36,6 +36,8 @@ static void dcpavserv_init(struct apple_epic_service *service, const char *name, static void dcpavserv_teardown(struct apple_epic_service *service) { struct apple_dcp *dcp = service->ep->dcp; + service->enabled = false; + if (dcp->dcpavserv.enabled) { dcp->dcpavserv.enabled = false; dcp->dcpavserv.service = NULL; @@ -51,6 +53,7 @@ static void dcpdpserv_init(struct apple_epic_service *service, const char *name, static void dcpdpserv_teardown(struct apple_epic_service *service) { + service->enabled = false; } struct dcpavserv_status_report { From 72760ccf0a89518ffe2d2f87c5504a329ca30736 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 14 Jan 2025 23:10:18 +0100 Subject: [PATCH 239/352] drm: apple: audio: Rework audio service handling 'open' and 'close' the service/link in iomfb's power-on and shutdown and on HPD deassert. This avoids leaking DCPAVAudioInterface services over display power cycles and tears the service properly down. For unknown reasons this is only observed with DCPs connected to atc phys as for DP altmode and the HDMI ports on Macbook Pros. Signed-off-by: Janne Grunau drm: apple: Rework audio service initialization Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/av.c | 96 ++++++++++++++++++++++++++++++------- drivers/gpu/drm/apple/av.h | 3 ++ drivers/gpu/drm/apple/dcp.c | 20 ++++++++ 3 files changed, 101 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/apple/av.c b/drivers/gpu/drm/apple/av.c index f498271da9081c..0d3c752f62d5f5 100644 --- a/drivers/gpu/drm/apple/av.c +++ b/drivers/gpu/drm/apple/av.c @@ -13,12 +13,14 @@ #include "audio.h" #include "afk.h" +#include "av.h" #include "dcp.h" #include "dcp-internal.h" struct dcp_av_audio_cmds { /* commands in group 0*/ u32 open; + u32 close; u32 prepare; u32 start_link; u32 stop_link; @@ -30,6 +32,7 @@ struct dcp_av_audio_cmds { static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v12_3 = { .open = 6, + .close = 7, .prepare = 8, .start_link = 9, .stop_link = 12, @@ -40,6 +43,7 @@ static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v12_3 = { static const struct dcp_av_audio_cmds dcp_av_audio_cmds_v13_5 = { .open = 4, + .close = 5, .prepare = 6, .start_link = 7, .stop_link = 10, @@ -62,6 +66,7 @@ struct audiosrv_data { bool warned_get_elements; bool warned_get_product_attrs; + bool is_open; }; static void av_interface_init(struct apple_epic_service *service, const char *name, @@ -285,34 +290,89 @@ static const struct apple_epic_service_ops avep_ops[] = { {} }; -static void av_work_service_start(struct work_struct *work) +void av_service_connect(struct apple_dcp *dcp) { + struct apple_epic_service *service; + struct audiosrv_data *asrv = dcp->audiosrv; int ret; - struct audiosrv_data *audiosrv_data; - struct apple_dcp *dcp; - audiosrv_data = container_of(work, struct audiosrv_data, start_av_service_wq); - if (!audiosrv_data->srv || - !audiosrv_data->srv->ep || - !audiosrv_data->srv->ep->dcp) { - pr_err("%s: dcp: av: NULL ptr during startup\n", __func__); - return; + scoped_guard(rwsem_write, &asrv->srv_rwsem) { + if (!asrv->srv) + return; + service = asrv->srv; } - dcp = audiosrv_data->srv->ep->dcp; /* open AV audio service */ - dev_info(dcp->dev, "%s: starting audio service\n", __func__); - ret = afk_service_call(dcp->audiosrv->srv, 0, dcp->audiosrv->cmds.open, - NULL, 0, 32, NULL, 0, 32); + dev_info(dcp->dev, "%s: starting audio service, plugged:%d\n", __func__, asrv->plugged); + if (asrv->is_open) + return; + + ret = afk_service_call(service, 0, asrv->cmds.open, NULL, 0, 32, + NULL, 0, 32); if (ret) { dev_err(dcp->dev, "error opening audio service: %d\n", ret); return; } + mutex_lock(&asrv->plug_lock); + asrv->is_open = true; - mutex_lock(&dcp->audiosrv->plug_lock); - if (dcp->audiosrv->audio_dev) - dcpaud_connect(dcp->audiosrv->audio_dev, dcp->audiosrv->plugged); - mutex_unlock(&dcp->audiosrv->plug_lock); + if (asrv->audio_dev) + dcpaud_connect(asrv->audio_dev, asrv->plugged); + mutex_unlock(&asrv->plug_lock); +} + +void av_service_disconnect(struct apple_dcp *dcp) +{ + struct apple_epic_service *service; + struct audiosrv_data *asrv = dcp->audiosrv; + int ret; + + scoped_guard(rwsem_write, &asrv->srv_rwsem) { + if (!asrv->srv) + return; + service = asrv->srv; + } + + /* close AV audio service */ + dev_info(dcp->dev, "%s: stopping audio service\n", __func__); + if (!asrv->is_open) + return; + + mutex_lock(&asrv->plug_lock); + + if (asrv->audio_dev) + dcpaud_disconnect(asrv->audio_dev); + + mutex_unlock(&asrv->plug_lock); + + ret = afk_service_call(service, 0, asrv->cmds.close, NULL, 0, 16, + NULL, 0, 16); + if (ret) { + dev_err(dcp->dev, "error closing audio service: %d\n", ret); + } + if (service->torndown) + service->enabled = false; + asrv->is_open = false; +} + +static void av_work_service_start(struct work_struct *work) +{ + struct audiosrv_data *audiosrv_data; + struct apple_dcp *dcp; + + audiosrv_data = container_of(work, struct audiosrv_data, start_av_service_wq); + + scoped_guard(rwsem_read, &audiosrv_data->srv_rwsem) { + if (!audiosrv_data->srv || + !audiosrv_data->srv->ep || + !audiosrv_data->srv->ep->dcp) { + pr_err("%s: dcp: av: NULL ptr during startup\n", __func__); + return; + } + dcp = audiosrv_data->srv->ep->dcp; + } + + av_service_connect(dcp); } int avep_init(struct apple_dcp *dcp) @@ -339,9 +399,9 @@ int avep_init(struct apple_dcp *dcp) dev_err(dcp->dev, "Audio not supported for firmware\n"); return -ENODEV; } - INIT_WORK(&audiosrv_data->start_av_service_wq, av_work_service_start); dcp->audiosrv = audiosrv_data; + INIT_WORK(&audiosrv_data->start_av_service_wq, av_work_service_start); endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); if (endpoint) { diff --git a/drivers/gpu/drm/apple/av.h b/drivers/gpu/drm/apple/av.h index b1f92fb5d07f90..baeefeca0a334d 100644 --- a/drivers/gpu/drm/apple/av.h +++ b/drivers/gpu/drm/apple/av.h @@ -6,4 +6,7 @@ //int avep_audiosrv_startlink(struct apple_dcp *dcp, struct dcp_sound_cookie *cookie); //int avep_audiosrv_stoplink(struct apple_dcp *dcp); +void av_service_connect(struct apple_dcp *dcp); +void av_service_disconnect(struct apple_dcp *dcp); + #endif /* __AV_H__ */ diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 1844f2b0f48452..99c978a3f31006 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -31,6 +31,7 @@ #include #include "afk.h" +#include "av.h" #include "dcp.h" #include "dcp-internal.h" #include "iomfb.h" @@ -413,6 +414,9 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) if (dcp->connector_type == DRM_MODE_CONNECTOR_DisplayPort) dptxport_set_hpd(dcp->dptxport[port].service, true); + if (dcp->avep) + av_service_connect(dcp); + return 0; out_unlock: @@ -445,6 +449,9 @@ int dcp_dptx_disconnect_oob(struct platform_device *pdev, u32 port) { struct apple_dcp *dcp = platform_get_drvdata(pdev); + if (dcp->avep) + av_service_disconnect(dcp); + if (dcp->dptxport[port].enabled) dptxport_set_hpd(dcp->dptxport[port].service, false); @@ -632,6 +639,9 @@ void dcp_poweron(struct platform_device *pdev) WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); break; } + + if (dcp->avep) + av_service_connect(dcp); } EXPORT_SYMBOL(dcp_poweron); @@ -639,6 +649,9 @@ void dcp_poweroff(struct platform_device *pdev) { struct apple_dcp *dcp = platform_get_drvdata(pdev); + if (dcp->avep) + av_service_disconnect(dcp); + switch (dcp->fw_compat) { case DCP_FIRMWARE_V_12_3: iomfb_poweroff_v12_3(dcp); @@ -1077,6 +1090,7 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) disable_irq(dcp->hdmi_hpd_irq); if (dcp->avep) { + av_service_disconnect(dcp); afk_shutdown(dcp->avep); dcp->avep = NULL; } @@ -1233,6 +1247,9 @@ static int dcp_platform_suspend(struct device *dev) { struct apple_dcp *dcp = dev_get_drvdata(dev); + if (dcp->avep) + av_service_disconnect(dcp); + if (dcp->hdmi_hpd_irq) { disable_irq(dcp->hdmi_hpd_irq); dcp_dptx_disconnect(dcp, 0); @@ -1261,6 +1278,9 @@ static int dcp_platform_resume(struct device *dev) dcp_dptx_connect(dcp, 0); } + if (dcp->avep) + av_service_connect(dcp); + return 0; } From c9040cc364947b1bfa56e8404678bafdbed83a46 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 27 Jan 2025 22:47:06 +0100 Subject: [PATCH 240/352] drm: apple: iomfb: Adapt `IOMFB_METHOD` for gcc 15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes "error: initializer-string for array of ‘char’ is too long" errors while compiling with Fedora's gcc 15. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index 3728c20d2f0391..7049ebc21dc229 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -199,7 +199,7 @@ enum dcpep_method { dcpep_num_methods }; -#define IOMFB_METHOD(tag, name) [name] = { #name, tag } +#define IOMFB_METHOD(tag, name) [name] = { #name, { tag[0], tag[1], tag[2], tag[3] } } struct dcp_method_entry { const char *name; From 72dd3be2500916778784e2387fb7ff721691cc72 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 21 Jan 2025 20:20:20 +0100 Subject: [PATCH 241/352] drm: apple: dptx: Rework/document get_max_lane_count() phy_validate() on the DP only ATC phy returns 0 lanes if it happens before the phy_set_mode(PHY_MODE_DP). Since this is the only known case default to 4 lanes as the phy is used exclusively for DP. Fixes: https://github.com/AsahiLinux/linux/issues/367 Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 2669cbecd05ffa..e1723f16aa58ff 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -250,26 +250,31 @@ static int dptxport_call_get_max_lane_count(struct apple_epic_service *service, { struct dptxport_apcall_lane_count *reply = reply_; struct dptx_port *dptx = service->cookie; + struct apple_dcp *dcp = service->ep->dcp; union phy_configure_opts phy_ops; int ret; if (reply_size < sizeof(*reply)) return -EINVAL; - reply->retcode = cpu_to_le32(0); - reply->lane_count = cpu_to_le64(2); - ret = phy_validate(dptx->atcphy, PHY_MODE_DP, 0, &phy_ops); - if (ret < 0 || phy_ops.dp.lanes < 2) { - // phy_validate might return 0 lines if atc-phy is not yet - // switched to DP alt mode - dev_dbg(service->ep->dcp->dev, "get_max_lane_count: " - "phy_validate ret:%d lanes:%d\n", ret, phy_ops.dp.lanes); - dptx->lane_count = 0; + if (ret < 0) { + dev_err(dcp->dev, "phy_validate failed: %d\n", ret); + reply->retcode = cpu_to_le32(1); + reply->lane_count = cpu_to_le64(0); } else { + if (phy_ops.dp.lanes < 2) { + // phy_validate might return 0 lanes if atc phy is not + // yet switched to DP mode + dev_dbg(dcp->dev, "get_max_lane_count: phy lanes: %d\n", + phy_ops.dp.lanes); + // default to 4 lanes + dptx->lane_count = 4; + } else { + dptx->lane_count = phy_ops.dp.lanes; + } reply->retcode = cpu_to_le32(0); - reply->lane_count = cpu_to_le64(phy_ops.dp.lanes); - dptx->lane_count = phy_ops.dp.lanes; + reply->lane_count = cpu_to_le64(dptx->lane_count); } return 0; From 41fb889b7e1e1b7f190747374bb4ce3e99d56ba4 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 21 Jan 2025 20:32:16 +0100 Subject: [PATCH 242/352] drm: apple: HDMI: Check HPD state before enabling the IRQ The HPD IRQ is edge triggered so its state needs to queried explicitly to detect the current state. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 99c978a3f31006..d991302563a0b7 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -569,6 +569,15 @@ EXPORT_SYMBOL(dcp_start); static int dcp_enable_dp2hdmi_hpd(struct apple_dcp *dcp) { + // check HPD state before enabling the edge triggered IRQ + if (dcp->hdmi_hpd) { + bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); + dev_info(dcp->dev, "%s: DP2HDMI HPD connected:%d\n", __func__, connected); + + if (connected) + dcp_dptx_connect(dcp, 0); + } + if (dcp->hdmi_hpd_irq) enable_irq(dcp->hdmi_hpd_irq); From 76adc09d7bf6bf0af7a031c0a19936cbdd25ed65 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 21 Jan 2025 23:35:27 +0100 Subject: [PATCH 243/352] drm: apple: dptx: Configure number of lanes for dptx-phy Configuring the number of lanes is required for M2* desktop devices either if those were not initialized by m1n1 or after hotplug. Fixes: 07e4bfb1599bc ("drm: apple: dptx: Tidy up lane count handling") Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index e1723f16aa58ff..e6e863dea76887 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -306,6 +306,9 @@ static int dptxport_call_set_active_lane_count(struct apple_epic_service *servic case 0 ... 2: case 4: dptx->phy_ops.dp.lanes = lane_count; + // Use dptx phy index > 3 as indication for dptx-phy or + // lpdptx-phy and configure the number of lanes for those + dptx->phy_ops.dp.set_lanes = (dcp->dptx_phy > 3); break; default: dev_err(dcp->dev, "set_active_lane_count: invalid lane count:%llu\n", lane_count); @@ -314,6 +317,16 @@ static int dptxport_call_set_active_lane_count(struct apple_epic_service *servic break; } + if (dptx->phy_ops.dp.set_lanes) { + if (dptx->atcphy) { + ret = phy_configure(dptx->atcphy, &dptx->phy_ops); + if (ret) + return ret; + } + dptx->phy_ops.dp.set_lanes = 0; + dptx->lane_count = lane_count; + } + reply->retcode = cpu_to_le32(retcode); reply->lane_count = cpu_to_le64(lane_count); From ae081034db9307d2f79d0d1049409a7b0851c88b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 9 Feb 2025 21:29:55 +0100 Subject: [PATCH 244/352] drm: apple: dptx: Issue HPD event early on gpio/type-c disconnect Atomic modesets during a display disconnect may result in unrecoverable state if the set_digital_out_mode() DCP firmware call fails. Mark the connector as early as possible as disconnected to make this more unlikely. TODO: investigate set_digital_out_mode() failure handling Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index d991302563a0b7..f8fb2eea60119f 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -424,6 +424,14 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) return ret; } +static void disconnected_hpd_event(struct apple_connector *con) +{ + if (con) { + con->connected = 0; + drm_kms_helper_connector_hotplug_event(&con->base); + } +} + static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) { dev_info(dcp->dev, "%s(port=%d)\n", __func__, port); @@ -449,6 +457,8 @@ int dcp_dptx_disconnect_oob(struct platform_device *pdev, u32 port) { struct apple_dcp *dcp = platform_get_drvdata(pdev); + disconnected_hpd_event(dcp->connector); + if (dcp->avep) av_service_disconnect(dcp); @@ -675,8 +685,10 @@ void dcp_poweroff(struct platform_device *pdev) if (dcp->hdmi_hpd) { bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); - if (!connected) + if (!connected) { + disconnected_hpd_event(dcp->connector); dcp_dptx_disconnect(dcp, 0); + } } } EXPORT_SYMBOL(dcp_poweroff); @@ -1261,6 +1273,7 @@ static int dcp_platform_suspend(struct device *dev) if (dcp->hdmi_hpd_irq) { disable_irq(dcp->hdmi_hpd_irq); + disconnected_hpd_event(dcp->connector); dcp_dptx_disconnect(dcp, 0); } /* From 743c117c93191ddbfc0df6b2fc2bb351958deaf5 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Mon, 17 Feb 2025 11:45:49 -0500 Subject: [PATCH 245/352] drm/apple: fix audioless build Signed-off-by: Alyssa Rosenzweig --- drivers/gpu/drm/apple/av.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/apple/av.h b/drivers/gpu/drm/apple/av.h index baeefeca0a334d..c00cbef549fd2e 100644 --- a/drivers/gpu/drm/apple/av.h +++ b/drivers/gpu/drm/apple/av.h @@ -6,7 +6,12 @@ //int avep_audiosrv_startlink(struct apple_dcp *dcp, struct dcp_sound_cookie *cookie); //int avep_audiosrv_stoplink(struct apple_dcp *dcp); +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) void av_service_connect(struct apple_dcp *dcp); void av_service_disconnect(struct apple_dcp *dcp); +#else +static inline void av_service_connect(struct apple_dcp *dcp) { } +static inline void av_service_disconnect(struct apple_dcp *dcp) { } +#endif #endif /* __AV_H__ */ From 6c697a2869b5613891640c678a8f418477b7acd8 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 9 Apr 2025 18:40:16 +0200 Subject: [PATCH 246/352] drm: apple: Use piodma default iommu domain Required to keep the bootloader mappings. iommu_paging_domain_alloc() will end up with an empty domain and remapping the boot loader mapping from reserved-memory is quite verbose to type. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index f8fb2eea60119f..2ef895c87998d8 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -751,22 +751,16 @@ static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp) } of_node_put(node); - dcp->iommu_dom = iommu_paging_domain_alloc(&dcp->piodma->dev); + dcp->iommu_dom = iommu_get_domain_for_dev(&dcp->piodma->dev); if (IS_ERR(dcp->iommu_dom)) { - ret = PTR_ERR(dcp->iommu_dom); + ret = dev_err_probe(dcp->dev, PTR_ERR(dcp->iommu_dom), + "Failed to get default iommu domain for " + "piodma device\n"); + dcp->iommu_dom = NULL; goto err_destroy_pdev; } - ret = iommu_attach_device(dcp->iommu_dom, &dcp->piodma->dev); - if (ret) { - ret = dev_err_probe(dcp->dev, ret, - "Failed to attach IOMMU child domain\n"); - goto err_free_domain; - } - return 0; -err_free_domain: - iommu_domain_free(dcp->iommu_dom); err_destroy_pdev: of_node_put(node); of_platform_device_destroy(&dcp->piodma->dev, NULL); @@ -1140,8 +1134,7 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) iomfb_shutdown(dcp); if (dcp->piodma) { - iommu_detach_device(dcp->iommu_dom, &dcp->piodma->dev); - iommu_domain_free(dcp->iommu_dom); + dcp->iommu_dom = NULL; of_platform_device_destroy(&dcp->piodma->dev, NULL); dcp->piodma = NULL; } From 66be8bba31ab6dd88c09a97953417cfc1f046ef3 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 25 May 2025 17:39:50 +0200 Subject: [PATCH 247/352] drm: dcp: Adjust .mode_valid signature Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.h | 4 ++-- drivers/gpu/drm/apple/iomfb.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index 0505032abe5497..cf598e037aeef0 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -43,8 +43,8 @@ bool dcp_is_initialized(struct platform_device *pdev); void apple_crtc_vblank(struct apple_crtc *apple); void dcp_drm_crtc_vblank(struct apple_crtc *crtc); int dcp_get_modes(struct drm_connector *connector); -int dcp_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode); +enum drm_mode_status dcp_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode); int dcp_crtc_atomic_modeset(struct drm_crtc *crtc, struct drm_atomic_state *state); bool dcp_crtc_mode_fixup(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 52818d34ccf7a3..8310508c7a8f0c 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -431,8 +431,8 @@ struct dcp_display_mode *lookup_mode(struct apple_dcp *dcp, return NULL; } -int dcp_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +enum drm_mode_status dcp_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) { struct apple_connector *apple_connector = to_apple_connector(connector); struct platform_device *pdev = apple_connector->dcp; From 699d486632431e11e09bdaec9b83b8f5dea7f0b2 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 26 Jul 2025 15:44:57 +0200 Subject: [PATCH 248/352] drm: apple: Support sync objects Both mutter[0] and KWin[1] are using the KMS drm device for explicit sync in their screen casting implementation. This fails in both cases since the KMS device does not provide DRM_CAP_SYNCOBJ_TIMELINE. Support for this is implemented in generic DRM so setting the two necessary feature flags. 0: https://gitlab.gnome.org/GNOME/mutter/-/issues/4224 1: https://invent.kde.org/plasma/kwin/-/merge_requests/7941 Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index e5e8496c98507b..ab17a53cd2c745 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -73,7 +73,7 @@ static const struct drm_driver apple_drm_driver = { .desc = DRIVER_DESC, .major = 1, .minor = 0, - .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE, .fops = &apple_fops, }; From 90674f69847aa1c85bf4daf366384b73f722545e Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 25 Aug 2025 22:14:01 +0200 Subject: [PATCH 249/352] drm: apple: Remove conflicting devices as late as possible Call aperture_remove_conflicting_devices() just before drm_dev_register(). This reduces the the time at startup without KMS drm device to a minimum. sddm/kwin(-wayland) fails with "kwin_wayland_drm: No suitable DRM devices have been found" in this case and never retries. Reverts commit "drm/apple: Remove simpledrm framebuffer before DRM device alloc". User space needs to deal with KMS device not being card0. The attempt to take card0 over from simpledrm was futile as the GPU driver is racing for this and won in many cases. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index ab17a53cd2c745..173cf5fba96941 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -624,14 +624,6 @@ static int apple_drm_init(struct device *dev) if (ret) return ret; - fb_size = fb_r.end - fb_r.start + 1; - ret = aperture_remove_conflicting_devices(fb_r.start, fb_size, - apple_drm_driver.name); - if (ret) { - dev_err(dev, "Failed remove fb: %d\n", ret); - goto err_unbind; - } - apple = devm_drm_dev_alloc(dev, &apple_drm_driver, struct apple_drm_private, drm); if (IS_ERR(apple)) @@ -673,6 +665,14 @@ static int apple_drm_init(struct device *dev) drm_mode_config_reset(&apple->drm); + fb_size = fb_r.end - fb_r.start + 1; + ret = aperture_remove_conflicting_devices(fb_r.start, fb_size, + apple_drm_driver.name); + if (ret) { + dev_err(dev, "Failed remove fb: %d\n", ret); + goto err_unbind; + } + ret = drm_dev_register(&apple->drm, 0); if (ret) goto err_unbind; From ed70ff24183b96687d099f0728dc83190d1c7ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 23 Feb 2023 17:57:56 +0100 Subject: [PATCH 250/352] HACK: ALSA: Export 'snd_pcm_known_rates' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Povišer --- sound/core/pcm_native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5a64453da7283a..94d09f065acada 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2470,6 +2470,7 @@ const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { .count = ARRAY_SIZE(rates), .list = rates, }; +EXPORT_SYMBOL_GPL(snd_pcm_known_rates); static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) From dba5c1cbef030c5a580a30e67975c6b3db422500 Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Tue, 16 Dec 2025 11:59:22 +0100 Subject: [PATCH 251/352] drm: apple: set timestamps for 120hz The dcp does not seem to care much about the values in ts1, ts2 and ts3, as long as they are non zero. This commit fills the timestamp with a dummy value of 120 if a refresh-rate of 120hz is selected. This is enough to get a refresh rate of 120hz. MacOS also sets flags1 and flags2. I have no idea what exactly those values indicate, but I did do not need to set any of them to get 120hz. Signed-off-by: Oliver Bestmann Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp-internal.h | 1 + drivers/gpu/drm/apple/iomfb_template.c | 17 +++++++++++++++-- drivers/gpu/drm/apple/iomfb_template.h | 9 ++++++++- drivers/gpu/drm/apple/parser.c | 15 +++++++-------- drivers/gpu/drm/apple/parser.h | 1 + 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 793d32dafe8472..4a37741d01e015 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -184,6 +184,7 @@ struct apple_dcp { /* Current display mode */ bool during_modeset; bool valid_mode; + bool use_timestamps; struct dcp_set_digital_out_mode_req mode; /* completion for active turning true */ diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 03766fd33978bb..e3f0044d373492 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1210,15 +1210,18 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, if (cmode) dev_info(dcp->dev, "set_digital_out_mode() color mode depth:%hhu format:%u " - "colorimetry:%u eotf:%u range:%u\n", cmode->depth, + "colorimetry:%u eotf:%u range:%u vrr:%u\n", cmode->depth, cmode->format, cmode->colorimetry, cmode->eotf, - cmode->range); + cmode->range, mode->vrr); dcp->mode = (struct dcp_set_digital_out_mode_req){ .color_mode_id = mode->color_mode_id, .timing_mode_id = mode->timing_mode_id }; + /* Keep track of suspected vrr modes */ + dcp->use_timestamps = mode->vrr; + cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); if (!cookie) { return -ENOMEM; @@ -1408,6 +1411,16 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru req->clear = 1; } + if (has_surface && dcp->use_timestamps) { + /* + * Fake timstamps to get 120hz refresh rate. It looks + * like the actual value does not matter, as long as it is non zero. + */ + req->swap.ts1 = 120; + req->swap.ts2 = 120; + req->swap.ts3 = 120; + } + /* These fields should be set together */ req->swap.swap_completed = req->swap.swap_enabled; diff --git a/drivers/gpu/drm/apple/iomfb_template.h b/drivers/gpu/drm/apple/iomfb_template.h index 3ff0fadff65243..19383639ab07c5 100644 --- a/drivers/gpu/drm/apple/iomfb_template.h +++ b/drivers/gpu/drm/apple/iomfb_template.h @@ -18,7 +18,14 @@ struct DCP_FW_NAME(dcp_swap) { u64 ts1; u64 ts2; - u64 unk_10[6]; + + u64 unk_10; + u64 unk_18; + u64 ts64_unk; + u64 unk_28; + u64 ts3; + u64 unk_38; + u64 flags1; u64 flags2; diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 2e3c22d576cb91..bc875ccc937696 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -500,17 +500,16 @@ static int parse_mode(struct dcp_parse_ctx *handle, return -EINVAL; /* - * HACK: - * Ignore the 120 Hz mode on j314/j316 (identified by resolution). - * DCP limits normal swaps to 60 Hz anyway and the 120 Hz mode might - * cause choppiness with X11. - * Just downscoring it and thus making the 60 Hz mode the preferred mode - * seems not enough for some user space. - */ + * HACK: + * Mark the 120 Hz mode on j314/j316 (identified by resolution) as vrr. + * We still do not know how to drive VRR but at least seetinng timestamps + * in the the swap_surface message to non-zero values drives the display + * at 120 fps. + */ if (vert.precise_sync_rate >> 16 == 120 && ((horiz.active == 3024 && vert.active == 1964) || (horiz.active == 3456 && vert.active == 2234))) - return -EINVAL; + out->vrr = true; vert.active -= notch_height; vert.sync_width += notch_height; diff --git a/drivers/gpu/drm/apple/parser.h b/drivers/gpu/drm/apple/parser.h index 11857f0aa6afa9..e03ee06ae98a75 100644 --- a/drivers/gpu/drm/apple/parser.h +++ b/drivers/gpu/drm/apple/parser.h @@ -91,6 +91,7 @@ struct dcp_display_mode { struct dcp_color_mode sdr_444; struct dcp_color_mode sdr; struct dcp_color_mode best; + bool vrr; }; struct dimension { From 52951a59ac0488b8b0fca5a2f781cadeeb07b0db Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 10 Sep 2025 17:56:28 +0200 Subject: [PATCH 252/352] drm/apple: Unify driver into a single module Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Makefile | 19 +++++++++--------- drivers/gpu/drm/apple/apple_drv.c | 28 ++++++++++++++++++++++++++- drivers/gpu/drm/apple/connector.c | 1 - drivers/gpu/drm/apple/dcp.c | 32 +++---------------------------- drivers/gpu/drm/apple/dcp.h | 3 +++ drivers/gpu/drm/apple/iomfb.c | 7 ------- drivers/gpu/drm/apple/parser.c | 2 -- 7 files changed, 42 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index 4f78757829ea4c..8d963ad6fded87 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -3,17 +3,16 @@ CFLAGS_trace.o = -I$(src) appledrm-y := apple_drv.o +appledrm-y += afk.o dcp.o dcp_backlight.o dptxep.o iomfb.o parser.o systemep.o +appledrm-$(CONFIG_DRM_APPLE_AUDIO) += audio.o +appledrm-$(CONFIG_DRM_APPLE_AUDIO) += av.o +appledrm-y += connector.o +appledrm-y += ibootep.o +appledrm-y += iomfb_v12_3.o +appledrm-y += iomfb_v13_3.o +appledrm-y += epic/dpavservep.o -apple_dcp-y := afk.o dcp.o dcp_backlight.o dptxep.o iomfb.o parser.o systemep.o -apple_dcp-$(CONFIG_DRM_APPLE_AUDIO) += audio.o -apple_dcp-$(CONFIG_DRM_APPLE_AUDIO) += av.o -apple_dcp-y += connector.o -apple_dcp-y += ibootep.o -apple_dcp-y += iomfb_v12_3.o -apple_dcp-y += iomfb_v13_3.o -apple_dcp-y += epic/dpavservep.o -apple_dcp-$(CONFIG_TRACING) += trace.o +appledrm-$(CONFIG_TRACING) += trace.o obj-$(CONFIG_DRM_APPLE) += appledrm.o -obj-$(CONFIG_DRM_APPLE) += apple_dcp.o diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 173cf5fba96941..a791a4a028104b 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -812,7 +812,33 @@ static struct platform_driver apple_platform_driver = { .remove = apple_platform_remove, }; -drm_module_platform_driver(apple_platform_driver); + + +static int __init appledrm_register(void) +{ + if (drm_firmware_drivers_only()) + return -ENODEV; + +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) + dcp_audio_register(); +#endif + dcp_register(); + platform_driver_register(&apple_platform_driver); + + return 0; +} + +static void __exit appledrm_unregister(void) +{ +#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) + dcp_audio_unregister(); +#endif + dcp_unregister(); + platform_driver_unregister(&apple_platform_driver); +} + +module_init(appledrm_register); +module_exit(appledrm_unregister); MODULE_AUTHOR("Asahi Linux contributors"); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/gpu/drm/apple/connector.c b/drivers/gpu/drm/apple/connector.c index 9e786670893387..15b3664d85631e 100644 --- a/drivers/gpu/drm/apple/connector.c +++ b/drivers/gpu/drm/apple/connector.c @@ -120,7 +120,6 @@ void apple_connector_debugfs_init(struct drm_connector *connector, struct dentry break; } } -EXPORT_SYMBOL(apple_connector_debugfs_init); static void dcp_connector_set_dict(struct apple_connector *connector, struct dcp_chunks *dict, diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 2ef895c87998d8..50dbd79527f3da 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -201,7 +201,6 @@ int dcp_set_crc(struct drm_crtc *crtc, bool enabled) return 0; } -EXPORT_SYMBOL_GPL(dcp_set_crc); /* * Helper to send a DRM vblank event. We do not know how call swap_submit_dcp @@ -361,7 +360,6 @@ int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) return 0; } -EXPORT_SYMBOL_GPL(dcp_crtc_atomic_check); int dcp_get_connector_type(struct platform_device *pdev) { @@ -369,7 +367,6 @@ int dcp_get_connector_type(struct platform_device *pdev) return (dcp->connector_type); } -EXPORT_SYMBOL_GPL(dcp_get_connector_type); #define DPTX_CONNECT_TIMEOUT msecs_to_jiffies(2000) @@ -451,7 +448,6 @@ int dcp_dptx_connect_oob(struct platform_device *pdev, u32 port) struct apple_dcp *dcp = platform_get_drvdata(pdev); return dcp_dptx_connect(dcp, port); } -EXPORT_SYMBOL_GPL(dcp_dptx_connect_oob); int dcp_dptx_disconnect_oob(struct platform_device *pdev, u32 port) { @@ -467,7 +463,6 @@ int dcp_dptx_disconnect_oob(struct platform_device *pdev, u32 port) return dcp_dptx_disconnect(dcp, port); } -EXPORT_SYMBOL_GPL(dcp_dptx_disconnect_oob); static irqreturn_t dcp_dp2hdmi_hpd(int irq, void *data) { @@ -502,7 +497,6 @@ void dcp_link(struct platform_device *pdev, struct apple_crtc *crtc, dcp->crtc = crtc; dcp->connector = connector; } -EXPORT_SYMBOL_GPL(dcp_link); int dcp_start(struct platform_device *pdev) { @@ -575,7 +569,6 @@ int dcp_start(struct platform_device *pdev) return ret; } -EXPORT_SYMBOL(dcp_start); static int dcp_enable_dp2hdmi_hpd(struct apple_dcp *dcp) { @@ -618,7 +611,6 @@ int dcp_wait_ready(struct platform_device *pdev, u64 timeout) return dcp->active ? 0 : -ETIMEDOUT; } -EXPORT_SYMBOL(dcp_wait_ready); static void __maybe_unused dcp_sleep(struct apple_dcp *dcp) { @@ -662,7 +654,6 @@ void dcp_poweron(struct platform_device *pdev) if (dcp->avep) av_service_connect(dcp); } -EXPORT_SYMBOL(dcp_poweron); void dcp_poweroff(struct platform_device *pdev) { @@ -691,7 +682,6 @@ void dcp_poweroff(struct platform_device *pdev) } } } -EXPORT_SYMBOL(dcp_poweroff); static void dcp_work_register_backlight(struct work_struct *work) { @@ -1339,28 +1329,12 @@ static struct platform_driver apple_platform_driver = { }, }; -static int __init apple_dcp_register(void) +void __init dcp_register(void) { - if (drm_firmware_drivers_only()) - return -ENODEV; - -#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) - dcp_audio_register(); -#endif - return platform_driver_register(&apple_platform_driver); + platform_driver_register(&apple_platform_driver); } -static void __exit apple_dcp_unregister(void) +void __exit dcp_unregister(void) { platform_driver_unregister(&apple_platform_driver); -#if IS_ENABLED(CONFIG_DRM_APPLE_AUDIO) - dcp_audio_unregister(); -#endif } - -module_init(apple_dcp_register); -module_exit(apple_dcp_unregister); - -MODULE_AUTHOR("Asahi Linux contributors"); -MODULE_DESCRIPTION("Apple Display Controller DRM driver"); -MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index cf598e037aeef0..ce18fa49e4da39 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -68,6 +68,9 @@ int dpavservep_init(struct apple_dcp *dcp); int avep_init(struct apple_dcp *dcp); +void __init dcp_register(void); +void __exit dcp_unregister(void); + void __init dcp_audio_register(void); void __exit dcp_audio_unregister(void); diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 8310508c7a8f0c..18685aa8079376 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -258,7 +258,6 @@ void dcp_hotplug(struct work_struct *work) drm_kms_helper_connector_hotplug_event(&connector->base); } -EXPORT_SYMBOL_GPL(dcp_hotplug); static void dcpep_handle_cb(struct apple_dcp *dcp, enum dcp_context_id context, void *data, u32 length, u16 offset) @@ -413,7 +412,6 @@ int dcp_get_modes(struct drm_connector *connector) return dcp->nr_modes; } -EXPORT_SYMBOL_GPL(dcp_get_modes); /* The user may own drm_display_mode, so we need to search for our copy */ struct dcp_display_mode *lookup_mode(struct apple_dcp *dcp, @@ -440,7 +438,6 @@ enum drm_mode_status dcp_mode_valid(struct drm_connector *connector, return lookup_mode(dcp, mode) ? MODE_OK : MODE_BAD; } -EXPORT_SYMBOL_GPL(dcp_mode_valid); int dcp_crtc_atomic_modeset(struct drm_crtc *crtc, struct drm_atomic_state *state) @@ -479,7 +476,6 @@ int dcp_crtc_atomic_modeset(struct drm_crtc *crtc, return ret; } -EXPORT_SYMBOL_GPL(dcp_crtc_atomic_modeset); bool dcp_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, @@ -492,7 +488,6 @@ bool dcp_crtc_mode_fixup(struct drm_crtc *crtc, /* TODO: support synthesized modes through scaling */ return lookup_mode(dcp, mode) != NULL; } -EXPORT_SYMBOL(dcp_crtc_mode_fixup); void dcp_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) @@ -527,7 +522,6 @@ void dcp_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) break; } } -EXPORT_SYMBOL_GPL(dcp_flush); static void iomfb_start(struct apple_dcp *dcp) { @@ -550,7 +544,6 @@ bool dcp_is_initialized(struct platform_device *pdev) return dcp->active; } -EXPORT_SYMBOL_GPL(dcp_is_initialized); void iomfb_recv_msg(struct apple_dcp *dcp, u64 message) { diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index bc875ccc937696..7c7af18a7c7e15 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -959,7 +959,6 @@ int parse_sound_constraints(struct dcp_parse_ctx *handle, return 0; } -EXPORT_SYMBOL_GPL(parse_sound_constraints); int parse_sound_mode(struct dcp_parse_ctx *handle, struct dcp_sound_format_mask *sieve, @@ -989,7 +988,6 @@ int parse_sound_mode(struct dcp_parse_ctx *handle, return 0; } -EXPORT_SYMBOL_GPL(parse_sound_mode); #endif int parse_system_log_mnits(struct dcp_parse_ctx *handle, struct dcp_system_ev_mnits *entry) From b95ef255b91fd9b1125da80a5a4ee7f61b2bf413 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Dec 2025 20:14:16 +0100 Subject: [PATCH 253/352] drm: apple: Use typec mux to switch atc-phy into DP The upstream atc phy driver has no longer special handling for the phy only use case on 14/16-inch Macbook Pros. So simply let dcp handle this and switch the type-c mux to full 4 lane DisplayPort mode. This requires devicetree changes in the form of a graph based connection between dcpext0 and atc-phy. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 11 +++++++++++ drivers/gpu/drm/apple/dcp-internal.h | 2 ++ drivers/gpu/drm/apple/dcp.c | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/apple/dptxep.c | 4 +++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index a791a4a028104b..1e466c7d706ba8 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -735,6 +735,17 @@ static int add_dcp_components(struct device *dev, continue; } #endif + + /* + * The ATC phy driver is not part of the component + * collection for the Apple display-subsystem so + * ignore it here. + */ + if (of_device_is_compatible(port, "apple,t8103-atcphy")) { + of_node_put(port); + continue; + } + if (of_device_is_available(port)) drm_of_component_match_add(dev, matchptr, component_compare_of, diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 4a37741d01e015..f2eb2483c9a880 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "dptxep.h" #include "iomfb.h" @@ -252,6 +253,7 @@ struct apple_dcp { /* these fields are output port specific */ struct phy *phy; struct mux_control *xbar; + struct typec_mux *typec_mux; struct gpio_desc *hdmi_hpd; struct gpio_desc *hdmi_pwren; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 50dbd79527f3da..526e4958a8e645 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include #include @@ -1094,6 +1097,8 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) if (dcp->hdmi_hpd_irq) disable_irq(dcp->hdmi_hpd_irq); + typec_mux_put(dcp->typec_mux); + if (dcp->avep) { av_service_disconnect(dcp); afk_shutdown(dcp->avep); @@ -1231,6 +1236,27 @@ static int dcp_platform_probe(struct platform_device *pdev) ret = mux_control_select(dcp->xbar, mux_index); if (ret) dev_warn(dev, "mux_control_select failed: %d\n", ret); + + /* + * Switch atcphy to DP-only. should move to a Macbook Pro + * 14-/16-inch specific DP-to-HDMI drm_bridge. + */ + dcp->typec_mux = fwnode_typec_mux_get(dev_fwnode(dcp->dev)); + if (!IS_ERR_OR_NULL(dcp->typec_mux)) { + struct typec_altmode alt = { + .svid = USB_TYPEC_DP_SID, + }; + struct typec_mux_state state = { + .alt = &alt, + .mode = TYPEC_DP_STATE_C, + }; + int ret = typec_mux_set(dcp->typec_mux, &state); + dev_info(dev, "typec_mux_set() returned: %d\n", ret); + } else { + dev_info(dev, "fwnode_typec_mux_get() returned: %ld\n", + IS_ERR(dcp->typec_mux) ? PTR_ERR(dcp->typec_mux) : 0); + dcp->typec_mux = NULL; + } } } diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index e6e863dea76887..e21299e0124035 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -479,7 +479,9 @@ dptxport_call_activate(struct apple_epic_service *service, const struct apple_dcp *dcp = service->ep->dcp; // TODO: hack, use phy_set_mode to select the correct DCP(EXT) input - phy_set_mode_ext(dptx->atcphy, PHY_MODE_DP, dcp->index); + // for standalone phy (i.e. not atc phy). + if (!dcp->typec_mux) + phy_set_mode_ext(dptx->atcphy, PHY_MODE_DP, dcp->index); memcpy(reply, data, min(reply_size, data_size)); if (reply_size >= 4) From 2fa280c28741690af4c124f931c03b51cbfaa44d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 27 Dec 2025 11:42:53 +0100 Subject: [PATCH 254/352] fixup! drm: apple: Brightness control via atomic commits Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/apple/Kconfig b/drivers/gpu/drm/apple/Kconfig index 9828a5fa193284..df247b6ed77deb 100644 --- a/drivers/gpu/drm/apple/Kconfig +++ b/drivers/gpu/drm/apple/Kconfig @@ -10,6 +10,7 @@ config DRM_APPLE select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select VIDEOMODE_HELPERS + select BACKLIGHT_CLASS_DEVICE select MULTIPLEXER help Say Y if you have an Apple Silicon chipset. From 83f8d0a1e75b00784245f3158bf5922c7c1ee75c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 27 Dec 2025 14:58:47 +0100 Subject: [PATCH 255/352] drm: apple: Increase timeout for dcp_set_power_state_req to 5000ms ossibly helps with slow wakeup on dp-altmode. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index e3f0044d373492..1205f8cf8a1fd4 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -825,7 +825,7 @@ void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp) dcp_set_display_device(dcp, false, &handle, dcp_on_set_parameter, cookie); } - ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(500)); + ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(5000)); if (ret == 0) dev_warn(dcp->dev, "wait for power timed out\n"); From cfc4e9a587b39f8dd1a53bc09542c4342c2c1f0b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 27 Dec 2025 15:00:14 +0100 Subject: [PATCH 256/352] drm: apple: Switch link status to BAD if power on fails Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 1205f8cf8a1fd4..10786c897d5741 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -829,6 +829,11 @@ void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp) if (ret == 0) dev_warn(dcp->dev, "wait for power timed out\n"); + else if (ret > 0) + dev_info(dcp->dev, "dcp_set_power_state_req returned, %d ms remaining\n", jiffies_to_msecs(ret)); + if (ret <= 0) + drm_connector_set_link_status_property(&dcp->connector->base, + DRM_MODE_LINK_STATUS_BAD); kref_put(&cookie->refcount, release_wait_cookie);; From dc60250e800a9c9873a7820ee83f2ce83ce0d61d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 24 Dec 2025 13:12:11 +0100 Subject: [PATCH 257/352] drm: apple: Move plane bits out of apple_drv/iomfb_flush Now that dcp may use multiple planes with more complex paramters move this out of iomfb_flush and use the appropriate KMS atomic plane helper functions. Also move most plane handling functions from apple_drv.c to its own file. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Makefile | 1 + drivers/gpu/drm/apple/apple_drv.c | 170 +-------------- drivers/gpu/drm/apple/iomfb.c | 19 -- drivers/gpu/drm/apple/iomfb.h | 20 -- drivers/gpu/drm/apple/iomfb_internal.h | 2 - drivers/gpu/drm/apple/iomfb_plane.h | 64 ++++++ drivers/gpu/drm/apple/iomfb_template.c | 30 +-- drivers/gpu/drm/apple/iomfb_template.h | 29 +-- drivers/gpu/drm/apple/plane.c | 278 +++++++++++++++++++++++++ drivers/gpu/drm/apple/plane.h | 26 +++ 10 files changed, 374 insertions(+), 265 deletions(-) create mode 100644 drivers/gpu/drm/apple/iomfb_plane.h create mode 100644 drivers/gpu/drm/apple/plane.c create mode 100644 drivers/gpu/drm/apple/plane.h diff --git a/drivers/gpu/drm/apple/Makefile b/drivers/gpu/drm/apple/Makefile index 8d963ad6fded87..b22839bdd611a7 100644 --- a/drivers/gpu/drm/apple/Makefile +++ b/drivers/gpu/drm/apple/Makefile @@ -11,6 +11,7 @@ appledrm-y += ibootep.o appledrm-y += iomfb_v12_3.o appledrm-y += iomfb_v13_3.o appledrm-y += epic/dpavservep.o +appledrm-y += plane.o appledrm-$(CONFIG_TRACING) += trace.o diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 1e466c7d706ba8..1eccd28b736700 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -40,12 +39,11 @@ #include #include "dcp.h" +#include "plane.h" #define DRIVER_NAME "apple" #define DRIVER_DESC "Apple display controller DRM driver" -#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) - #define MAX_COPROCESSORS 3 struct apple_drm_private { @@ -77,172 +75,6 @@ static const struct drm_driver apple_drm_driver = { .fops = &apple_fops, }; -static int apple_plane_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_plane_state; - struct drm_crtc_state *crtc_state; - struct drm_rect *dst; - int ret; - - new_plane_state = drm_atomic_get_new_plane_state(state, plane); - - if (!new_plane_state->crtc) - return 0; - - crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - /* - * DCP limits downscaling to 2x and upscaling to 4x. Attempting to - * scale outside these bounds errors out when swapping. - * - * This function also takes care of clipping the src/dest rectangles, - * which is required for correct operation. Partially off-screen - * surfaces may appear corrupted. - * - * DCP does not distinguish plane types in the hardware, so we set - * can_position. If the primary plane does not fill the screen, the - * hardware will fill in zeroes (black). - */ - ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - FRAC_16_16(1, 2), - FRAC_16_16(4, 1), - true, true); - if (ret < 0) - return ret; - - if (!new_plane_state->visible) - return 0; - - /* - * DCP does not allow a surface to clip off the screen, and will crash - * if any blended surface is smaller than 32x32. Reject the atomic op - * if the plane will crash DCP. - * - * This is most pertinent to cursors. Userspace should fall back to - * software cursors if the plane check is rejected. - */ - dst = &new_plane_state->dst; - if (drm_rect_width(dst) < 32 || drm_rect_height(dst) < 32) { - dev_err_once(state->dev->dev, - "Plane operation would have crashed DCP! Rejected!\n\ - DCP requires 32x32 of every plane to be within screen space.\n\ - Your compositor asked to overlay [%dx%d, %dx%d] on %dx%d.\n\ - This is not supported, and your compositor should have\n\ - switched to software compositing when this operation failed.\n\ - You should not have noticed this at all. If your screen\n\ - froze/hitched, or your compositor crashed, please report\n\ - this to the your compositor's developers. We will not\n\ - throw this error again until you next reboot.\n", - dst->x1, dst->y1, dst->x2, dst->y2, - crtc_state->mode.hdisplay, crtc_state->mode.vdisplay); - return -EINVAL; - } - - return 0; -} - -static void apple_plane_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - /* Handled in atomic_flush */ -} - -static const struct drm_plane_helper_funcs apple_primary_plane_helper_funcs = { - .atomic_check = apple_plane_atomic_check, - .atomic_update = apple_plane_atomic_update, - .get_scanout_buffer = drm_fb_dma_get_scanout_buffer, -}; - -static const struct drm_plane_helper_funcs apple_plane_helper_funcs = { - .atomic_check = apple_plane_atomic_check, - .atomic_update = apple_plane_atomic_update, -}; - -static void apple_plane_cleanup(struct drm_plane *plane) -{ - drm_plane_cleanup(plane); - kfree(plane); -} - -static const struct drm_plane_funcs apple_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = apple_plane_cleanup, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -}; - -/* - * Table of supported formats, mapping from DRM fourccs to DCP fourccs. - * - * For future work, DCP supports more formats not listed, including YUV - * formats, an extra RGBA format, and a biplanar RGB10_A8 format (fourcc b3a8) - * used for HDR. - * - * Note: we don't have non-alpha formats but userspace breaks without XRGB. It - * doesn't matter for the primary plane, but cursors/overlays must not - * advertise formats without alpha. - */ -static const u32 dcp_primary_formats[] = { - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ABGR8888, -}; - -static const u32 dcp_overlay_formats[] = { - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, -}; - -u64 apple_format_modifiers[] = { - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - -static struct drm_plane *apple_plane_init(struct drm_device *dev, - unsigned long possible_crtcs, - enum drm_plane_type type) -{ - int ret; - struct drm_plane *plane; - - plane = kzalloc(sizeof(*plane), GFP_KERNEL); - - switch (type) { - case DRM_PLANE_TYPE_PRIMARY: - ret = drm_universal_plane_init(dev, plane, possible_crtcs, - &apple_plane_funcs, - dcp_primary_formats, ARRAY_SIZE(dcp_primary_formats), - apple_format_modifiers, type, NULL); - break; - case DRM_PLANE_TYPE_OVERLAY: - case DRM_PLANE_TYPE_CURSOR: - ret = drm_universal_plane_init(dev, plane, possible_crtcs, - &apple_plane_funcs, - dcp_overlay_formats, ARRAY_SIZE(dcp_overlay_formats), - apple_format_modifiers, type, NULL); - break; - default: - return NULL; - } - - if (ret) - return ERR_PTR(ret); - - if (type == DRM_PLANE_TYPE_PRIMARY) - drm_plane_helper_add(plane, &apple_primary_plane_helper_funcs); - else - drm_plane_helper_add(plane, &apple_plane_helper_funcs); - - return plane; -} - static enum drm_connector_status apple_connector_detect(struct drm_connector *connector, bool force) { diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 18685aa8079376..ee64127936a932 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -356,25 +356,6 @@ struct dcp_rect drm_to_dcp_rect(struct drm_rect *rect) .h = drm_rect_height(rect) }; } -u32 drm_format_to_dcp(u32 drm) -{ - switch (drm) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: - return fourcc_code('A', 'R', 'G', 'B'); - - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ABGR8888: - return fourcc_code('A', 'B', 'G', 'R'); - - case DRM_FORMAT_XRGB2101010: - return fourcc_code('r', '0', '3', 'w'); - } - - pr_warn("DRM format %X not supported in DCP\n", drm); - return 0; -} - int dcp_get_modes(struct drm_connector *connector) { struct apple_connector *apple_connector = to_apple_connector(connector); diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index 7049ebc21dc229..88f688eec461bd 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -79,7 +79,6 @@ enum iomfb_property_id { #define SWAP_SURFACES 4 /* We have 4 surfaces, but we can only ever blend two */ #define MAX_BLEND_SURFACES 2 -#define MAX_PLANES 3 enum dcp_colorspace { DCP_COLORSPACE_BG_SRGB = 0, @@ -113,25 +112,6 @@ struct dcp_rect { */ #define IOMFB_SET_BACKGROUND BIT(31) -/* Information describing a plane of a planar compressed surface */ -struct dcp_plane_info { - u32 width; - u32 height; - u32 base; - u32 offset; - u32 stride; - u32 size; - u16 tile_size; - u8 tile_w; - u8 tile_h; - u32 unk[13]; -} __packed; - -struct dcp_component_types { - u8 count; - u8 types[7]; -} __packed; - struct dcp_allocate_bandwidth_req { u64 unk1; u64 unk2; diff --git a/drivers/gpu/drm/apple/iomfb_internal.h b/drivers/gpu/drm/apple/iomfb_internal.h index 09f8857d30c341..9bd211f2f44e82 100644 --- a/drivers/gpu/drm/apple/iomfb_internal.h +++ b/drivers/gpu/drm/apple/iomfb_internal.h @@ -116,8 +116,6 @@ void dcp_ack(struct apple_dcp *dcp, enum dcp_context_id context); */ struct dcp_rect drm_to_dcp_rect(struct drm_rect *rect); -u32 drm_format_to_dcp(u32 drm); - /* The user may own drm_display_mode, so we need to search for our copy */ struct dcp_display_mode *lookup_mode(struct apple_dcp *dcp, const struct drm_display_mode *mode); diff --git a/drivers/gpu/drm/apple/iomfb_plane.h b/drivers/gpu/drm/apple/iomfb_plane.h new file mode 100644 index 00000000000000..e23fcffaddbf62 --- /dev/null +++ b/drivers/gpu/drm/apple/iomfb_plane.h @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) The Asahi Linux Contributors + */ + + +#ifndef __APPLE_IOMFB_PLANE_H__ +#define __APPLE_IOMFB_PLANE_H__ + +#include + +#define DCP_SURF_MAX_PLANES 3 + +/* Information describing a plane of a planar compressed surface */ +struct dcp_plane_info { + u32 width; + u32 height; + u32 base; + u32 offset; + u32 stride; + u32 size; + u16 tile_size; + u8 tile_w; + u8 tile_h; + u32 unk[13]; +} __packed; + +struct dcp_component_types { + u8 count; + u8 types[7]; +} __packed; + +/* Information describing a surface */ +struct dcp_surface { + u8 is_tiled; + u8 is_tearing_allowed; + u8 is_premultiplied; + u32 plane_cnt; + u32 plane_cnt2; + u32 format; /* DCP fourcc */ + u32 ycbcr_matrix; + u8 xfer_func; + u8 colorspace; + u32 stride; + u16 pix_size; + u8 pel_w; + u8 pel_h; + u32 offset; + u32 width; + u32 height; + u32 buf_size; + u64 protection_opts; + u32 surface_id; + struct dcp_component_types comp_types[DCP_SURF_MAX_PLANES]; + u64 has_comp; + struct dcp_plane_info planes[DCP_SURF_MAX_PLANES]; + u64 has_planes; + u32 compression_info[DCP_SURF_MAX_PLANES][13]; + u64 has_compr_info; + u32 unk_num; + u32 unk_denom; +} __packed; + +#endif /* __APPLE_IOMFB_PLANE_H__ */ diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 10786c897d5741..7d38b7655f21a4 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1305,10 +1305,10 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru } for_each_oldnew_plane_in_state(state, plane, old_state, new_state, plane_idx) { + struct apple_plane_state *apple_state = to_apple_plane_state(new_state); struct drm_framebuffer *fb = new_state->fb; struct drm_gem_dma_object *obj; struct drm_rect src_rect; - bool is_premultiplied = false; /* skip planes not for this crtc */ if (old_state->crtc != crtc && new_state->crtc != crtc) @@ -1357,15 +1357,6 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru req->surf_null[l] = false; has_surface = 1; - /* - * DCP doesn't support XBGR8 / XRGB8 natively. Blending as - * pre-multiplied alpha with a black background can be used as - * workaround for the bottommost plane. - */ - if (fb->format->format == DRM_FORMAT_XRGB8888 || - fb->format->format == DRM_FORMAT_XBGR8888) - is_premultiplied = true; - drm_rect_fp_to_int(&src_rect, &new_state->src); req->swap.src_rect[l] = drm_to_dcp_rect(&src_rect); @@ -1382,24 +1373,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru if (obj) req->surf_iova[l] = obj->dma_addr + fb->offsets[0]; - req->surf[l] = (struct DCP_FW_NAME(dcp_surface)){ - .is_premultiplied = is_premultiplied, - .format = drm_format_to_dcp(fb->format->format), - .xfer_func = DCP_XFER_FUNC_SDR, - .colorspace = DCP_COLORSPACE_NATIVE, - .stride = fb->pitches[0], - .width = fb->width, - .height = fb->height, - .buf_size = fb->height * fb->pitches[0], - .surface_id = req->swap.surf_ids[l], - - /* Only used for compressed or multiplanar surfaces */ - .pix_size = 1, - .pel_w = 1, - .pel_h = 1, - .has_comp = 1, - .has_planes = 1, - }; + req->surf[l].base = apple_state->surf; } diff --git a/drivers/gpu/drm/apple/iomfb_template.h b/drivers/gpu/drm/apple/iomfb_template.h index 19383639ab07c5..ba50032d385705 100644 --- a/drivers/gpu/drm/apple/iomfb_template.h +++ b/drivers/gpu/drm/apple/iomfb_template.h @@ -13,6 +13,7 @@ #include #include "iomfb.h" +#include "plane.h" #include "version_utils.h" struct DCP_FW_NAME(dcp_swap) { @@ -61,33 +62,7 @@ struct DCP_FW_NAME(dcp_swap) { /* Information describing a surface */ struct DCP_FW_NAME(dcp_surface) { - u8 is_tiled; - u8 is_tearing_allowed; - u8 is_premultiplied; - u32 plane_cnt; - u32 plane_cnt2; - u32 format; /* DCP fourcc */ - u32 ycbcr_matrix; - u8 xfer_func; - u8 colorspace; - u32 stride; - u16 pix_size; - u8 pel_w; - u8 pel_h; - u32 offset; - u32 width; - u32 height; - u32 buf_size; - u64 protection_opts; - u32 surface_id; - struct dcp_component_types comp_types[MAX_PLANES]; - u64 has_comp; - struct dcp_plane_info planes[MAX_PLANES]; - u64 has_planes; - u32 compression_info[MAX_PLANES][13]; - u64 has_compr_info; - u32 unk_num; - u32 unk_denom; + struct dcp_surface base; #if DCP_FW_VER < DCP_FW_VERSION(13, 2, 0) u8 padding[7]; #else diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c new file mode 100644 index 00000000000000..05e929513eb90d --- /dev/null +++ b/drivers/gpu/drm/apple/plane.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) The Asahi Linux Contributors + */ + +#include "plane.h" + +#include "iomfb_internal.h" + +#include +#include +#include +#include +#include +#include + +#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) + +static int apple_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state; + struct drm_crtc_state *crtc_state; + struct drm_rect *dst; + int ret; + + new_plane_state = drm_atomic_get_new_plane_state(state, plane); + + if (!new_plane_state->crtc) + return 0; + + crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + /* + * DCP limits downscaling to 2x and upscaling to 4x. Attempting to + * scale outside these bounds errors out when swapping. + * + * This function also takes care of clipping the src/dest rectangles, + * which is required for correct operation. Partially off-screen + * surfaces may appear corrupted. + * + * DCP does not distinguish plane types in the hardware, so we set + * can_position. If the primary plane does not fill the screen, the + * hardware will fill in zeroes (black). + */ + ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, + FRAC_16_16(1, 2), + FRAC_16_16(4, 1), + true, true); + if (ret < 0) + return ret; + + if (!new_plane_state->visible) + return 0; + + /* + * DCP does not allow a surface to clip off the screen, and will crash + * if any blended surface is smaller than 32x32. Reject the atomic op + * if the plane will crash DCP. + * + * This is most pertinent to cursors. Userspace should fall back to + * software cursors if the plane check is rejected. + */ + dst = &new_plane_state->dst; + if (drm_rect_width(dst) < 32 || drm_rect_height(dst) < 32) { + dev_err_once(state->dev->dev, + "Plane operation would have crashed DCP! Rejected!\n\ + DCP requires 32x32 of every plane to be within screen space.\n\ + Your compositor asked to overlay [%dx%d, %dx%d] on %dx%d.\n\ + This is not supported, and your compositor should have\n\ + switched to software compositing when this operation failed.\n\ + You should not have noticed this at all. If your screen\n\ + froze/hitched, or your compositor crashed, please report\n\ + this to the your compositor's developers. We will not\n\ + throw this error again until you next reboot.\n", + dst->x1, dst->y1, dst->x2, dst->y2, + crtc_state->mode.hdisplay, crtc_state->mode.vdisplay); + return -EINVAL; + } + + return 0; +} + +static u32 drm_format_to_dcp(u32 drm) +{ + switch (drm) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + return fourcc_code('A', 'R', 'G', 'B'); + + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return fourcc_code('A', 'B', 'G', 'R'); + + case DRM_FORMAT_XRGB2101010: + return fourcc_code('r', '0', '3', 'w'); + } + + pr_warn("DRM format %X not supported in DCP\n", drm); + return 0; +} + +static void apple_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *base = drm_atomic_get_new_plane_state(state, plane); + struct apple_plane_state *new_state; + bool is_premultiplied = false; + + if (!base) + return; + + new_state = to_apple_plane_state(base); + + if (!base->fb) { + memset(&new_state->surf, 0, sizeof(new_state->surf)); + return; + } + + struct drm_framebuffer *fb = base->fb; + /* + * DCP doesn't support XBGR8 / XRGB8 natively. Blending as + * pre-multiplied alpha with a black background can be used as + * workaround for the bottommost plane. + */ + if (fb->format->format == DRM_FORMAT_XRGB8888 || + fb->format->format == DRM_FORMAT_XBGR8888) + is_premultiplied = true; + + new_state->surf = (struct dcp_surface){ + .is_premultiplied = is_premultiplied, + .format = drm_format_to_dcp(fb->format->format), + .xfer_func = DCP_XFER_FUNC_SDR, + .colorspace = DCP_COLORSPACE_NATIVE, + .stride = fb->pitches[0], + .width = fb->width, + .height = fb->height, + .buf_size = fb->height * fb->pitches[0], + // .surface_id = req->swap.surf_ids[l], + + /* Only used for compressed or multiplanar surfaces */ + .pix_size = 1, + .pel_w = 1, + .pel_h = 1, + .has_comp = 1, + .has_planes = 1, + }; +} + +static const struct drm_plane_helper_funcs apple_primary_plane_helper_funcs = { + .atomic_check = apple_plane_atomic_check, + .atomic_update = apple_plane_atomic_update, + .get_scanout_buffer = drm_fb_dma_get_scanout_buffer, +}; + +static const struct drm_plane_helper_funcs apple_plane_helper_funcs = { + .atomic_check = apple_plane_atomic_check, + .atomic_update = apple_plane_atomic_update, +}; + +// Duplicate drm_atomic_helper_plane_reset but allocate struct apple_plane_state +static void apple_plane_reset(struct drm_plane *plane) +{ + struct apple_plane_state *state = to_apple_plane_state(plane->state); + if (state) + __drm_atomic_helper_plane_destroy_state(&state->base); + + kfree(state); + plane->state = NULL; + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_plane_reset(plane, &state->base); +} + +static struct drm_plane_state * +apple_plane_duplicate_state(struct drm_plane *plane) +{ + struct apple_plane_state *apple_plane_state, *old_apple_plane_state; + + if (!plane->state) + return NULL; + + old_apple_plane_state = to_apple_plane_state(plane->state); + apple_plane_state = kzalloc(sizeof(*apple_plane_state), GFP_KERNEL); + if (!apple_plane_state) + return NULL; + + __drm_atomic_helper_plane_duplicate_state(plane, &apple_plane_state->base); + + apple_plane_state->surf = old_apple_plane_state->surf; + + return &apple_plane_state->base; +} + +// void apple_plane_destroy_state(struct drm_plane *plane, +// struct drm_plane_state *state) +// { +// drm_atomic_helper_plane_destroy_state(plane, state); +// } + +static const struct drm_plane_funcs apple_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = apple_plane_reset, + .atomic_duplicate_state = apple_plane_duplicate_state, + // .atomic_destroy_state = apple_plane_destroy_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +/* + * Table of supported formats, mapping from DRM fourccs to DCP fourccs. + * + * For future work, DCP supports more formats not listed, including YUV + * formats, an extra RGBA format, and a biplanar RGB10_A8 format (fourcc b3a8) + * used for HDR. + * + * Note: we don't have non-alpha formats but userspace breaks without XRGB. It + * doesn't matter for the primary plane, but cursors/overlays must not + * advertise formats without alpha. + */ +static const u32 dcp_primary_formats[] = { + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, +}; + +static const u32 dcp_overlay_formats[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, +}; + +u64 apple_format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +struct apple_plane { + struct drm_plane base; +}; + +struct drm_plane *apple_plane_init(struct drm_device *dev, + unsigned long possible_crtcs, + enum drm_plane_type type) +{ + struct apple_plane *plane; + + switch (type) { + case DRM_PLANE_TYPE_PRIMARY: + plane = drmm_universal_plane_alloc(dev, struct apple_plane, base, possible_crtcs, + &apple_plane_funcs, + dcp_primary_formats, ARRAY_SIZE(dcp_primary_formats), + apple_format_modifiers, type, NULL); + break; + case DRM_PLANE_TYPE_OVERLAY: + case DRM_PLANE_TYPE_CURSOR: + plane = drmm_universal_plane_alloc(dev, struct apple_plane, base, possible_crtcs, + &apple_plane_funcs, + dcp_overlay_formats, ARRAY_SIZE(dcp_overlay_formats), + apple_format_modifiers, type, NULL); + break; + default: + return ERR_PTR(-EINVAL); + } + + if (IS_ERR(plane)) + return ERR_PTR(PTR_ERR(plane)); + + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(&plane->base, &apple_primary_plane_helper_funcs); + else + drm_plane_helper_add(&plane->base, &apple_plane_helper_funcs); + + return &plane->base; +} diff --git a/drivers/gpu/drm/apple/plane.h b/drivers/gpu/drm/apple/plane.h new file mode 100644 index 00000000000000..e32c1e609e6704 --- /dev/null +++ b/drivers/gpu/drm/apple/plane.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) The Asahi Linux Contributors + */ + +#ifndef __APPLE_PLANE_H__ +#define __APPLE_PLANE_H__ + +#include + +#include + +#include "iomfb_plane.h" + +struct apple_plane_state { + struct drm_plane_state base; + struct dcp_surface surf; +}; + +#define to_apple_plane_state(x) container_of(x, struct apple_plane_state, base) + +struct drm_plane *apple_plane_init(struct drm_device *dev, + unsigned long possible_crtcs, + enum drm_plane_type type); + +#endif /* __APPLE_PLANE_H__ */ From 9cd4216785082194a1f5ff57684111f0201424ca Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 26 Dec 2025 21:54:13 +1000 Subject: [PATCH 258/352] drm: apple: move dcp rectangle creation to atomic_plane_update We should not be programming rectangles in atomic_flush. Move this step to atomic_plane_update and store the resultant rectangles with the rest of the surface's state. Signed-off-by: James Calligeros Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb.c | 13 ------------- drivers/gpu/drm/apple/iomfb.h | 7 ------- drivers/gpu/drm/apple/iomfb_internal.h | 7 ------- drivers/gpu/drm/apple/iomfb_plane.h | 7 +++++++ drivers/gpu/drm/apple/iomfb_template.c | 7 ++----- drivers/gpu/drm/apple/iomfb_template.h | 1 + drivers/gpu/drm/apple/plane.c | 24 ++++++++++++++++++++++++ drivers/gpu/drm/apple/plane.h | 2 ++ 8 files changed, 36 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index ee64127936a932..1d9448f0f4dc47 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -343,19 +343,6 @@ static void dcpep_got_msg(struct apple_dcp *dcp, u64 message) dcpep_handle_cb(dcp, ctx_id, data, length, offset); } -/* - * DRM specifies rectangles as start and end coordinates. DCP specifies - * rectangles as a start coordinate and a width/height. Convert a DRM rectangle - * to a DCP rectangle. - */ -struct dcp_rect drm_to_dcp_rect(struct drm_rect *rect) -{ - return (struct dcp_rect){ .x = rect->x1, - .y = rect->y1, - .w = drm_rect_width(rect), - .h = drm_rect_height(rect) }; -} - int dcp_get_modes(struct drm_connector *connector) { struct apple_connector *apple_connector = to_apple_connector(connector); diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index 88f688eec461bd..161fbbe24931cc 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -100,13 +100,6 @@ struct dcp_iouserclient { u8 padding[2]; } __packed; -struct dcp_rect { - u32 x; - u32 y; - u32 w; - u32 h; -} __packed; - /* * Update background color to struct dcp_swap.bg_color */ diff --git a/drivers/gpu/drm/apple/iomfb_internal.h b/drivers/gpu/drm/apple/iomfb_internal.h index 9bd211f2f44e82..75e9d7b0e8cc84 100644 --- a/drivers/gpu/drm/apple/iomfb_internal.h +++ b/drivers/gpu/drm/apple/iomfb_internal.h @@ -109,13 +109,6 @@ int dcp_parse_tag(char tag[4]); void dcp_ack(struct apple_dcp *dcp, enum dcp_context_id context); -/* - * DRM specifies rectangles as start and end coordinates. DCP specifies - * rectangles as a start coordinate and a width/height. Convert a DRM rectangle - * to a DCP rectangle. - */ -struct dcp_rect drm_to_dcp_rect(struct drm_rect *rect); - /* The user may own drm_display_mode, so we need to search for our copy */ struct dcp_display_mode *lookup_mode(struct apple_dcp *dcp, const struct drm_display_mode *mode); diff --git a/drivers/gpu/drm/apple/iomfb_plane.h b/drivers/gpu/drm/apple/iomfb_plane.h index e23fcffaddbf62..9de35d64c12ba4 100644 --- a/drivers/gpu/drm/apple/iomfb_plane.h +++ b/drivers/gpu/drm/apple/iomfb_plane.h @@ -11,6 +11,13 @@ #define DCP_SURF_MAX_PLANES 3 +struct dcp_rect { + u32 x; + u32 y; + u32 w; + u32 h; +} __packed; + /* Information describing a plane of a planar compressed surface */ struct dcp_plane_info { u32 width; diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 7d38b7655f21a4..b1630c75bcef9c 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1308,7 +1308,6 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru struct apple_plane_state *apple_state = to_apple_plane_state(new_state); struct drm_framebuffer *fb = new_state->fb; struct drm_gem_dma_object *obj; - struct drm_rect src_rect; /* skip planes not for this crtc */ if (old_state->crtc != crtc && new_state->crtc != crtc) @@ -1357,10 +1356,8 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru req->surf_null[l] = false; has_surface = 1; - drm_rect_fp_to_int(&src_rect, &new_state->src); - - req->swap.src_rect[l] = drm_to_dcp_rect(&src_rect); - req->swap.dst_rect[l] = drm_to_dcp_rect(&new_state->dst); + req->swap.src_rect[l] = apple_state->src_rect; + req->swap.dst_rect[l] = apple_state->dst_rect; if (dcp->notch_height > 0) req->swap.dst_rect[l].y += dcp->notch_height; diff --git a/drivers/gpu/drm/apple/iomfb_template.h b/drivers/gpu/drm/apple/iomfb_template.h index ba50032d385705..8efab49cc53d08 100644 --- a/drivers/gpu/drm/apple/iomfb_template.h +++ b/drivers/gpu/drm/apple/iomfb_template.h @@ -13,6 +13,7 @@ #include #include "iomfb.h" +#include "iomfb_plane.h" #include "plane.h" #include "version_utils.h" diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index 05e929513eb90d..b51029f326f2a8 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -83,6 +83,27 @@ static int apple_plane_atomic_check(struct drm_plane *plane, return 0; } +/* + * DRM specifies rectangles as start and end coordinates. DCP specifies + * rectangles as a start coordinate and a width/height. Convert a DRM rectangle + * to a DCP rectangle. + */ +static struct dcp_rect drm_to_dcp_rect(const struct drm_rect *rect) +{ + return (struct dcp_rect){ .x = rect->x1, + .y = rect->y1, + .w = drm_rect_width(rect), + .h = drm_rect_height(rect), + }; +} + +static struct dcp_rect drm_to_dcp_rect_fp(const struct drm_rect *fp_rect) +{ + struct drm_rect rect; + drm_rect_fp_to_int(&rect, fp_rect); + return drm_to_dcp_rect(&rect); +} + static u32 drm_format_to_dcp(u32 drm) { switch (drm) { @@ -129,6 +150,9 @@ static void apple_plane_atomic_update(struct drm_plane *plane, fb->format->format == DRM_FORMAT_XBGR8888) is_premultiplied = true; + new_state->src_rect = drm_to_dcp_rect_fp(&base->src); + new_state->dst_rect = drm_to_dcp_rect(&base->dst); + new_state->surf = (struct dcp_surface){ .is_premultiplied = is_premultiplied, .format = drm_format_to_dcp(fb->format->format), diff --git a/drivers/gpu/drm/apple/plane.h b/drivers/gpu/drm/apple/plane.h index e32c1e609e6704..96461d7da59648 100644 --- a/drivers/gpu/drm/apple/plane.h +++ b/drivers/gpu/drm/apple/plane.h @@ -15,6 +15,8 @@ struct apple_plane_state { struct drm_plane_state base; struct dcp_surface surf; + struct dcp_rect src_rect; + struct dcp_rect dst_rect; }; #define to_apple_plane_state(x) container_of(x, struct apple_plane_state, base) From c38401cbddfd4475a1ae4275ec25499b41ff171d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 1 Jan 2026 13:53:50 +0100 Subject: [PATCH 259/352] drm: apple: Use defines for dcp's fourcc formats Add defines for Apple's full gamut packed 10-bit ARGB format ("l10r") and 2 and 3 plane YCbCr 8-bit formats with 4:2:0, 4:2:2 and 4:4:4 subsampling in limited and full range. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_plane.h | 10 ++++++++++ drivers/gpu/drm/apple/plane.c | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_plane.h b/drivers/gpu/drm/apple/iomfb_plane.h index 9de35d64c12ba4..adf6916d375891 100644 --- a/drivers/gpu/drm/apple/iomfb_plane.h +++ b/drivers/gpu/drm/apple/iomfb_plane.h @@ -7,10 +7,20 @@ #ifndef __APPLE_IOMFB_PLANE_H__ #define __APPLE_IOMFB_PLANE_H__ +#include + #include #define DCP_SURF_MAX_PLANES 3 +#define DCP_FORMAT_BGRA fourcc_code('A', 'R', 'G', 'B') +#define DCP_FORMAT_RGBA fourcc_code('A', 'B', 'G', 'R') + +#define DCP_FORMAT_W30R fourcc_code('r', '0', '3', 'w') // wide gamut packed 10-bit RGB without alpha +#define DCP_FORMAT_L10R fourcc_code('r', '0', '1', 'l') // full range packed 10-bit RGB with alpha + + + struct dcp_rect { u32 x; u32 y; diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index b51029f326f2a8..8df0a70b749049 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -109,14 +109,14 @@ static u32 drm_format_to_dcp(u32 drm) switch (drm) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_ARGB8888: - return fourcc_code('A', 'R', 'G', 'B'); + return DCP_FORMAT_BGRA; case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ABGR8888: - return fourcc_code('A', 'B', 'G', 'R'); + return DCP_FORMAT_RGBA; case DRM_FORMAT_XRGB2101010: - return fourcc_code('r', '0', '3', 'w'); + return DCP_FORMAT_W30R; } pr_warn("DRM format %X not supported in DCP\n", drm); From c1eeefaa76730412ea285a1d4721580d71555a69 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 26 Dec 2025 22:00:26 +1000 Subject: [PATCH 260/352] drm: apple: get framebuffer iova in atomic_plane_update Signed-off-by: James Calligeros Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 14 ++------------ drivers/gpu/drm/apple/plane.c | 10 ++++++++++ drivers/gpu/drm/apple/plane.h | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index b1630c75bcef9c..e8043ef92d66c6 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -1306,8 +1305,6 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru for_each_oldnew_plane_in_state(state, plane, old_state, new_state, plane_idx) { struct apple_plane_state *apple_state = to_apple_plane_state(new_state); - struct drm_framebuffer *fb = new_state->fb; - struct drm_gem_dma_object *obj; /* skip planes not for this crtc */ if (old_state->crtc != crtc && new_state->crtc != crtc) @@ -1329,7 +1326,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru req->swap.swap_enabled |= BIT(l); - if (old_state->fb && fb != old_state->fb) { + if (old_state->fb && new_state->fb != old_state->fb) { /* * Race condition between a framebuffer unbind getting * swapped out and GEM unreferencing a framebuffer. If @@ -1362,14 +1359,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru if (dcp->notch_height > 0) req->swap.dst_rect[l].y += dcp->notch_height; - /* the obvious helper call drm_fb_dma_get_gem_addr() adjusts - * the address for source x/y offsets. Since IOMFB has a direct - * support source position prefer that. - */ - obj = drm_fb_dma_get_gem_obj(fb, 0); - if (obj) - req->surf_iova[l] = obj->dma_addr + fb->offsets[0]; - + req->surf_iova[l] = apple_state->iova; req->surf[l].base = apple_state->surf; } diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index 8df0a70b749049..aedb6bf40167dc 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) @@ -128,6 +129,7 @@ static void apple_plane_atomic_update(struct drm_plane *plane, { struct drm_plane_state *base = drm_atomic_get_new_plane_state(state, plane); struct apple_plane_state *new_state; + struct drm_gem_dma_object *obj; bool is_premultiplied = false; if (!base) @@ -171,6 +173,14 @@ static void apple_plane_atomic_update(struct drm_plane *plane, .has_comp = 1, .has_planes = 1, }; + + /* the obvious helper call drm_fb_dma_get_gem_addr() adjusts + * the address for source x/y offsets. Since IOMFB has a direct + * support source position prefer that. + */ + obj = drm_fb_dma_get_gem_obj(base->fb, 0); + if (obj) + new_state->iova = obj->dma_addr + base->fb->offsets[0]; } static const struct drm_plane_helper_funcs apple_primary_plane_helper_funcs = { diff --git a/drivers/gpu/drm/apple/plane.h b/drivers/gpu/drm/apple/plane.h index 96461d7da59648..b03c3fdfed7dec 100644 --- a/drivers/gpu/drm/apple/plane.h +++ b/drivers/gpu/drm/apple/plane.h @@ -17,6 +17,7 @@ struct apple_plane_state { struct dcp_surface surf; struct dcp_rect src_rect; struct dcp_rect dst_rect; + u64 iova; }; #define to_apple_plane_state(x) container_of(x, struct apple_plane_state, base) From 45a8835c3939705c954993afb0af8296f1dd69be Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sat, 27 Dec 2025 16:22:14 +1000 Subject: [PATCH 261/352] drm: apple: Advertise ARGB2101010 support The full range packed 10-bit dcp format ("l10r") supports alpha so use that instead of the already slightly misused wide gamut format "w30r" to support DRM_FORMAT_ARGB2101010. Signed-off-by: James Calligeros Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/plane.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index aedb6bf40167dc..9a7e8e3680dbfb 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -117,7 +117,8 @@ static u32 drm_format_to_dcp(u32 drm) return DCP_FORMAT_RGBA; case DRM_FORMAT_XRGB2101010: - return DCP_FORMAT_W30R; + case DRM_FORMAT_ARGB2101010: + return DCP_FORMAT_L10R; } pr_warn("DRM format %X not supported in DCP\n", drm); @@ -143,13 +144,15 @@ static void apple_plane_atomic_update(struct drm_plane *plane, } struct drm_framebuffer *fb = base->fb; + const struct drm_format_info *fmt = fb->format; /* - * DCP doesn't support XBGR8 / XRGB8 natively. Blending as + * DCP doesn't support XBGR8 / XRGB8 / XBGR2101010 natively. Blending as * pre-multiplied alpha with a black background can be used as * workaround for the bottommost plane. */ - if (fb->format->format == DRM_FORMAT_XRGB8888 || - fb->format->format == DRM_FORMAT_XBGR8888) + if (fmt->format == DRM_FORMAT_XRGB8888 || + fmt->format == DRM_FORMAT_XBGR8888 || + fmt->format == DRM_FORMAT_XBGR2101010) is_premultiplied = true; new_state->src_rect = drm_to_dcp_rect_fp(&base->src); @@ -256,6 +259,7 @@ static const struct drm_plane_funcs apple_plane_funcs = { */ static const u32 dcp_primary_formats[] = { DRM_FORMAT_XRGB2101010, + DRM_FORMAT_ARGB2101010, DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, @@ -263,6 +267,7 @@ static const u32 dcp_primary_formats[] = { }; static const u32 dcp_overlay_formats[] = { + DRM_FORMAT_ARGB2101010, DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, }; From d83a93f4000c2688745ce463d27911de1aa73e80 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Mon, 22 Dec 2025 19:30:47 +1000 Subject: [PATCH 262/352] drm: apple: Support YCbCr formats Support 8-bit YCbCr planar and semi-planar formats in 4:2:0, 4:2:2 and 4:4:4 sub-sampling with limited and full range. Use the signalled color space and transfer functions for YCbCr formats. DCP allows a unique colour space to be specified for each surface. The firmware then tonemaps this to the connected display's native colour space. KMS sets color_encoding and color_range only for YCbCr formats. Signed-off-by: James Calligeros Co-developed-by: Janne Grunau Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb.h | 11 --- drivers/gpu/drm/apple/iomfb_plane.h | 28 ++++++ drivers/gpu/drm/apple/plane.c | 136 +++++++++++++++++++++++++++- 3 files changed, 160 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index 161fbbe24931cc..bda46748a391d2 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -80,17 +80,6 @@ enum iomfb_property_id { /* We have 4 surfaces, but we can only ever blend two */ #define MAX_BLEND_SURFACES 2 -enum dcp_colorspace { - DCP_COLORSPACE_BG_SRGB = 0, - DCP_COLORSPACE_BG_BT2020 = 9, - DCP_COLORSPACE_NATIVE = 12, -}; - -enum dcp_xfer_func { - DCP_XFER_FUNC_SDR = 13, - DCP_XFER_FUNC_HDR = 16, -}; - struct dcp_iouserclient { /* Handle for the IOUserClient. macOS sets this to a kernel VA. */ u64 handle; diff --git a/drivers/gpu/drm/apple/iomfb_plane.h b/drivers/gpu/drm/apple/iomfb_plane.h index adf6916d375891..0701978200311a 100644 --- a/drivers/gpu/drm/apple/iomfb_plane.h +++ b/drivers/gpu/drm/apple/iomfb_plane.h @@ -19,7 +19,35 @@ #define DCP_FORMAT_W30R fourcc_code('r', '0', '3', 'w') // wide gamut packed 10-bit RGB without alpha #define DCP_FORMAT_L10R fourcc_code('r', '0', '1', 'l') // full range packed 10-bit RGB with alpha +#define DCP_FORMAT_420V fourcc_code('v', '0', '2', '4') // NV12 video range 2 plane 8-bit YCbCr +#define DCP_FORMAT_420F fourcc_code('f', '0', '2', '4') // NV12 full range 2 plane 8-bit YCbCr +#define DCP_FORMAT_422V fourcc_code('v', '2', '2', '4') // NV16 video range 2 plane 8-bit YCbCr +#define DCP_FORMAT_422F fourcc_code('f', '2', '2', '4') // NV16 full range 2 plane 8-bit YCbCr +#define DCP_FORMAT_444V fourcc_code('v', '4', '4', '4') // NV24 video range 2 plane 8-bit YCbCr +#define DCP_FORMAT_444F fourcc_code('f', '4', '4', '4') // NV24 full range 2 plane 8-bit YCbCr +#define DCP_FORMAT_X420 fourcc_code('0', '2', '4', 'x') // P010 video range 2 plane 10-bit YCbCR +#define DCP_FORMAT_X422 fourcc_code('2', '2', '4', 'x') // P210 video range 2 plane 10-bit YCbCR +#define DCP_FORMAT_X444 fourcc_code('4', '4', '4', 'x') // P410 video range 2 plane 10-bit YCbCR + +#define DCP_FORMAT_XF20 fourcc_code('0', '2', 'f', 'x') // P010 full range 2 plane 10-bit YCbCR +#define DCP_FORMAT_XF22 fourcc_code('2', '2', 'f', 'x') // P210 full range 2 plane 10-bit YCbCR +#define DCP_FORMAT_XF44 fourcc_code('4', '4', 'f', 'x') // P410 full range 2 plane 10-bit YCbCR + +enum dcp_colorspace { + DCP_COLORSPACE_BG_SRGB = 0, + DCP_COLORSPACE_BT601 = 1, + DCP_COLORSPACE_BT709 = 2, + DCP_COLORSPACE_BG_BT2020 = 9, + DCP_COLORSPACE_NATIVE = 12, +}; + +enum dcp_xfer_func { + DCP_XFER_FUNC_BT601 = 1, + DCP_XFER_FUNC_BT1886 = 2, + DCP_XFER_FUNC_SDR = 13, + DCP_XFER_FUNC_HDR = 16, +}; struct dcp_rect { u32 x; diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index 9a7e8e3680dbfb..ec972b3467d479 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,29 @@ static int apple_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } + /* + * Pitches have to be 64-byte aligned. + */ + for (u32 i = 0; i < new_plane_state->fb->format->num_planes; i++) + if (new_plane_state->fb->pitches[i] & 63) + return -EINVAL; + + /* + * FIXME: dcp can currently only use multi-planar buffers using the same + * object for all planes. It has a mandatory iommu so it should + * be no problem to map multiple objects "linearly" into DCP + * virtual address space and calculate the offsets accordingly. + * Or maybe it can accept multiple BOs via the per plane field + * `base`. + */ + if (new_plane_state->fb->format->num_planes > 1) { + const struct drm_gem_object *first = new_plane_state->fb->obj[0]; + for (u32 i = 1; i < new_plane_state->fb->format->num_planes; i++) + if (new_plane_state->fb->obj[i] != NULL && + new_plane_state->fb->obj[i] != first) + return -EINVAL; + } + return 0; } @@ -105,8 +129,9 @@ static struct dcp_rect drm_to_dcp_rect_fp(const struct drm_rect *fp_rect) return drm_to_dcp_rect(&rect); } -static u32 drm_format_to_dcp(u32 drm) +static u32 drm_format_to_dcp(u32 drm, enum drm_color_range range) { + bool fr = range == DRM_COLOR_YCBCR_FULL_RANGE; switch (drm) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_ARGB8888: @@ -119,12 +144,67 @@ static u32 drm_format_to_dcp(u32 drm) case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_ARGB2101010: return DCP_FORMAT_L10R; + + /* semi planar YCbCr formats, limited and full range */ + case DRM_FORMAT_NV12: + return fr ? DCP_FORMAT_420F : DCP_FORMAT_420V; + case DRM_FORMAT_NV16: + return fr ? DCP_FORMAT_422F : DCP_FORMAT_422V; + case DRM_FORMAT_NV24: + return fr ? DCP_FORMAT_444F : DCP_FORMAT_444V; + + /* semi planar 10-bit YCbCr formats, limited and full range */ + case DRM_FORMAT_P010: + return fr ? DCP_FORMAT_XF20 : DCP_FORMAT_X420; + case DRM_FORMAT_P210: + return fr ? DCP_FORMAT_XF22 : DCP_FORMAT_X422; + /* + * TODO: missing DRM fourcc for P410 + */ +#if defined(DRM_FORMAT_P410) + case DRM_FORMAT_P410: + return fr ? DCP_FORMAT_XF44 : DCP_FORMAT_X444; +#endif } pr_warn("DRM format %X not supported in DCP\n", drm); return 0; } +static enum dcp_xfer_func get_xfer_func(bool is_yuv, enum drm_color_encoding enc) +{ + if (!is_yuv) + return DCP_XFER_FUNC_SDR; + + switch (enc) { + case DRM_COLOR_YCBCR_BT601: + return DCP_XFER_FUNC_BT601; + case DRM_COLOR_YCBCR_BT709: + case DRM_COLOR_YCBCR_BT2020: + return DCP_XFER_FUNC_BT1886; + default: + return DCP_XFER_FUNC_SDR; + } +} + +static enum dcp_colorspace get_colorspace(bool is_yuv, + enum drm_color_encoding enc) +{ + if (!is_yuv) + return DCP_COLORSPACE_NATIVE; + + switch (enc) { + case DRM_COLOR_YCBCR_BT601: + return DCP_COLORSPACE_BT601; + case DRM_COLOR_YCBCR_BT709: + return DCP_COLORSPACE_BT709; + case DRM_COLOR_YCBCR_BT2020: + return DCP_COLORSPACE_BG_BT2020; + default: + return DCP_COLORSPACE_NATIVE; + } +} + static void apple_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -160,9 +240,11 @@ static void apple_plane_atomic_update(struct drm_plane *plane, new_state->surf = (struct dcp_surface){ .is_premultiplied = is_premultiplied, - .format = drm_format_to_dcp(fb->format->format), - .xfer_func = DCP_XFER_FUNC_SDR, - .colorspace = DCP_COLORSPACE_NATIVE, + .plane_cnt = fb->format->num_planes, + .plane_cnt2 = fb->format->num_planes, + .format = drm_format_to_dcp(fmt->format, base->color_range), + .xfer_func = get_xfer_func(fmt->is_yuv, base->color_encoding), + .colorspace = get_colorspace(fmt->is_yuv, base->color_encoding), .stride = fb->pitches[0], .width = fb->width, .height = fb->height, @@ -177,6 +259,30 @@ static void apple_plane_atomic_update(struct drm_plane *plane, .has_planes = 1, }; + /* Populate plane information for planar formats */ + struct dcp_surface *surf = &new_state->surf; + for (int i = 0; fb->format->num_planes && i < fb->format->num_planes; i++) { + u32 width = drm_format_info_plane_width(fb->format, fb->width, i); + u32 height = drm_format_info_plane_height(fb->format, fb->height, i); + u32 bh = drm_format_info_block_height(fb->format, i); + u32 bw = drm_format_info_block_width(fb->format, i); + + surf->planes[i] = (struct dcp_plane_info){ + .width = width, + .height = height, + .base = fb->offsets[i] - fb->offsets[0], + .offset = fb->offsets[i] - fb->offsets[0], + .stride = fb->pitches[i], + .size = height * fb->pitches[i], + .tile_size = bw * bh, + .tile_w = bw, + .tile_h = bh, + }; + + if (i > 0) + surf->buf_size += surf->planes[i].size; + } + /* the obvious helper call drm_fb_dma_get_gem_addr() adjusts * the address for source x/y offsets. Since IOMFB has a direct * support source position prefer that. @@ -264,12 +370,28 @@ static const u32 dcp_primary_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV24, + DRM_FORMAT_P010, + DRM_FORMAT_P210, +#if defined(DRM_FORMAT_P410) + DRM_FORMAT_P410, +#endif }; static const u32 dcp_overlay_formats[] = { DRM_FORMAT_ARGB2101010, DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV24, + DRM_FORMAT_P010, + DRM_FORMAT_P210, +#if defined(DRM_FORMAT_P410) + DRM_FORMAT_P410, +#endif }; u64 apple_format_modifiers[] = { @@ -308,6 +430,12 @@ struct drm_plane *apple_plane_init(struct drm_device *dev, if (IS_ERR(plane)) return ERR_PTR(PTR_ERR(plane)); + drm_plane_create_color_properties(&plane->base, + (1 << DRM_COLOR_ENCODING_MAX) - 1, + (1 << DRM_COLOR_RANGE_MAX) - 1, + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + if (type == DRM_PLANE_TYPE_PRIMARY) drm_plane_helper_add(&plane->base, &apple_primary_plane_helper_funcs); else From 5fe5ea4a4d1983f34d2c8fca0d1356421347aadd Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Thu, 1 Jan 2026 16:18:52 +1000 Subject: [PATCH 263/352] drm: apple: Assume all RGB planes are sRGB DCP enables us to specify a colourspace and transfer function for each plane, and will automatically tonemap them to the connected display's native colourspace. It also has a fallback "NATIVE" colourspace that tells it to assume the input framebuffer has already been transformed correctly. We were previously using this fallback for all RGB framebuffers, however this is incorrect. By convention, userspace treats the default colourspace as sRGB. This is fine when a display is in sRGB mode, however modern displays almost always cover a wider colour gamut out of the box, This is true of the MacBook builtin displays, which have full DCI-P3 coverage. The result of passing through sRGB framebuffers as "native" is oversaturated colours and bloomy highlights. It is exceedingly rare for userspace to ever output RGB framebuffers in non-sRGB colourspaces unless HDR is enabled, which we currently do not support. Let's just tell DCP that all RGB framebuffers are sRGB until the per-plane colour management patches are merged, at which point we can revisit this logic to make it more accurate. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/plane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index ec972b3467d479..2fe5cd059feee3 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -191,7 +191,7 @@ static enum dcp_colorspace get_colorspace(bool is_yuv, enum drm_color_encoding enc) { if (!is_yuv) - return DCP_COLORSPACE_NATIVE; + return DCP_COLORSPACE_BG_SRGB; switch (enc) { case DRM_COLOR_YCBCR_BT601: From 5b063521d7f3ae66d8ab0c632d67d64f48be3265 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 6 Jan 2026 20:04:47 +0100 Subject: [PATCH 264/352] drm/apple: Relax locking for back light updates Locking all modeset locks was the obviously correct solution and the overlocking wasn't much of an issue when only a single CRTC/display output was supported. Now with more output the over locking is becomming an issue and I even ran into a deadlock. Ideally the backlight related data either should live in a private object or in sub-classed CRTC state. In practice just locking the CRTC for the internal display with backlight should be good enough. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp_backlight.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp_backlight.c b/drivers/gpu/drm/apple/dcp_backlight.c index 1397000c27935c..9eb0c7d4eb5345 100644 --- a/drivers/gpu/drm/apple/dcp_backlight.c +++ b/drivers/gpu/drm/apple/dcp_backlight.c @@ -144,7 +144,14 @@ static int drm_crtc_set_brightness(struct apple_dcp *dcp) struct drm_crtc *crtc = &dcp->crtc->base; int ret = 0; - DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, ret); + drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + return -EDEADLK; + } else if (ret == -ERESTARTSYS) { + return -ERESTARTSYS; + } if (!dcp->brightness.update) goto done; @@ -169,7 +176,7 @@ static int drm_crtc_set_brightness(struct apple_dcp *dcp) fail: drm_atomic_state_put(state); done: - DRM_MODESET_LOCK_ALL_END(crtc->dev, ctx, ret); + drm_modeset_drop_locks(&ctx); return ret; } @@ -199,12 +206,19 @@ static int dcp_set_brightness(struct backlight_device *bd) struct drm_modeset_acquire_ctx ctx; int brightness = backlight_get_brightness(bd); - DRM_MODESET_LOCK_ALL_BEGIN(dcp->crtc->base.dev, ctx, 0, ret); + drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); + ret = drm_modeset_lock(&dcp->crtc->base.mutex, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + return -EDEADLK; + } else if (ret == -ERESTARTSYS) { + return -ERESTARTSYS; + } dcp->brightness.dac = calculate_dac(dcp, brightness); dcp->brightness.update = true; - DRM_MODESET_LOCK_ALL_END(dcp->crtc->base.dev, ctx, ret); + drm_modeset_drop_locks(&ctx); return dcp_backlight_update(dcp); } From 034c0c6a823a129e47d93ca7e23a2985a5d37c94 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 6 Jan 2026 22:23:53 +0100 Subject: [PATCH 265/352] drm/apple: Send HPD event on disconnect only connector is cconected Fixes a deadlock while disabling the CRTC from HPD event via drm_client. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 526e4958a8e645..48305e8338a5b0 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -426,7 +426,7 @@ static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) static void disconnected_hpd_event(struct apple_connector *con) { - if (con) { + if (con && con->connected) { con->connected = 0; drm_kms_helper_connector_hotplug_event(&con->base); } From 9a065da2525b50412b8eacd1c88daff0c6728d08 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 6 Jan 2026 22:32:41 +0100 Subject: [PATCH 266/352] drm/apple: dcp: Do not call dcp_dptx_connect() from resume() It will be called from dcp_poweron() triggered by drm_mode_config_helper_resume() from the apple_drv's resume(). Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 48305e8338a5b0..da71f0d3d5fe9d 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -1302,13 +1302,6 @@ static int dcp_platform_resume(struct device *dev) if (dcp->hdmi_hpd_irq) enable_irq(dcp->hdmi_hpd_irq); - if (dcp->hdmi_hpd) { - bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); - dev_info(dcp->dev, "resume: HPD connected:%d\n", connected); - if (connected) - dcp_dptx_connect(dcp, 0); - } - if (dcp->avep) av_service_connect(dcp); From 0ebf2cd6e5cc34054f172f7df57b8ca135cf8afa Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 6 Jan 2026 22:47:35 +0100 Subject: [PATCH 267/352] drm/apple: Add device link between display-subsystem and each dcp* Fixes resume/suspend order between both devices. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 1eccd28b736700..e943ca9e9973cb 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -402,6 +402,8 @@ static int apple_drm_init_dcp(struct device *dev) if (!dcp[num_dcp]) continue; + device_link_add(dev, &dcp[num_dcp]->dev, DL_FLAG_AUTOREMOVE_SUPPLIER); + ret = apple_probe_per_dcp(dev, &apple->drm, dcp[num_dcp], num_dcp, dcp_ext); if (ret) From c6d74c0c0b7cb46adf2b4032f0f69b1d7f3e4abd Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 24 Jan 2026 14:14:52 +0100 Subject: [PATCH 268/352] drm/apple: Only assume RGB planes on internal displays are sRGB For external displays with EDID user space might use the colorimetry information therein and use color mapping with the expectation of using that color space. DCP's native color space is the correct choice for that. Fixes: 667ca85b1804 ("drm: apple: Assume all RGB planes are sRGB") Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 8 ++++++++ drivers/gpu/drm/apple/plane.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index e8043ef92d66c6..c016e75bc2d480 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1362,6 +1362,14 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru req->surf_iova[l] = apple_state->iova; req->surf[l].base = apple_state->surf; + /* Use sRGB colorspace only for internal panels. External + * displays are expected to have EDID and user space can use + * the contained colorimetry information to provide native + * colors. + */ + if (dcp->connector_type == DRM_MODE_CONNECTOR_eDP && + req->surf[l].base.colorspace == DCP_COLORSPACE_BG_SRGB) + req->surf[l].base.colorspace = DCP_COLORSPACE_NATIVE; } if (!has_surface && !crtc_state->color_mgmt_changed) { diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index 2fe5cd059feee3..ec972b3467d479 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -191,7 +191,7 @@ static enum dcp_colorspace get_colorspace(bool is_yuv, enum drm_color_encoding enc) { if (!is_yuv) - return DCP_COLORSPACE_BG_SRGB; + return DCP_COLORSPACE_NATIVE; switch (enc) { case DRM_COLOR_YCBCR_BT601: From e91869927573b97ab3811599126b68191ac17eb7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 28 Jan 2026 21:35:20 +0100 Subject: [PATCH 269/352] drm/asahi: Do not use l10r for 12.3 DCP firmware DCP firmware 12.3 (tested as 12.4 on a M2) does not support l10r as buffer format. Drop 30-bit support for 12.x firmware. 12.3 based installs are considered legacy and support for 12.4 (M2 only) was dropped. This ensures such installs remain usable without complicating the driver too much. DCP complains on syslog with > UPPipeDCP_H13P.cpp:3302: IOMFB verify_surfaces: No support for format l10r Fixes: b6a8d6ba54f3 ("drm: apple: Advertise ARGB2101010 support") Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 7 ++-- drivers/gpu/drm/apple/dcp.c | 8 +++++ drivers/gpu/drm/apple/dcp.h | 1 + drivers/gpu/drm/apple/plane.c | 54 ++++++++++++++++++++++++++++--- drivers/gpu/drm/apple/plane.h | 1 + 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index e943ca9e9973cb..ab9fd49467dcfc 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -273,8 +273,10 @@ static int apple_probe_per_dcp(struct device *dev, struct drm_plane *planes[DCP_MAX_PLANES]; int ret, i; int immutable_zpos = 0; + bool supports_l10r = !dcp_fw_compat_is_12_x(dcp); - planes[0] = apple_plane_init(drm, 1U << num, DRM_PLANE_TYPE_PRIMARY); + planes[0] = apple_plane_init(drm, 1U << num, supports_l10r, + DRM_PLANE_TYPE_PRIMARY); if (IS_ERR(planes[0])) return PTR_ERR(planes[0]); ret = drm_plane_create_zpos_immutable_property(planes[0], immutable_zpos); @@ -285,7 +287,8 @@ static int apple_probe_per_dcp(struct device *dev, /* Set up our other planes */ for (i = 1; i < DCP_MAX_PLANES; i++) { - planes[i] = apple_plane_init(drm, 1U << num, DRM_PLANE_TYPE_OVERLAY); + planes[i] = apple_plane_init(drm, 1U << num, supports_l10r, + DRM_PLANE_TYPE_OVERLAY); if (IS_ERR(planes[i])) return PTR_ERR(planes[i]); immutable_zpos++; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index da71f0d3d5fe9d..e2a29653705b29 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -501,6 +501,14 @@ void dcp_link(struct platform_device *pdev, struct apple_crtc *crtc, dcp->connector = connector; } + +bool dcp_fw_compat_is_12_x(struct platform_device *pdev) +{ + struct apple_dcp *dcp = platform_get_drvdata(pdev); + + return dcp->fw_compat == DCP_FIRMWARE_V_12_3; +} + int dcp_start(struct platform_device *pdev) { struct apple_dcp *dcp = platform_get_drvdata(pdev); diff --git a/drivers/gpu/drm/apple/dcp.h b/drivers/gpu/drm/apple/dcp.h index ce18fa49e4da39..bd20876847e0c3 100644 --- a/drivers/gpu/drm/apple/dcp.h +++ b/drivers/gpu/drm/apple/dcp.h @@ -34,6 +34,7 @@ void dcp_poweron(struct platform_device *pdev); int dcp_set_crc(struct drm_crtc *crtc, bool enabled); int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state); int dcp_get_connector_type(struct platform_device *pdev); +bool dcp_fw_compat_is_12_x(struct platform_device *pdev); void dcp_link(struct platform_device *pdev, struct apple_crtc *apple, struct apple_connector *connector); int dcp_start(struct platform_device *pdev); diff --git a/drivers/gpu/drm/apple/plane.c b/drivers/gpu/drm/apple/plane.c index ec972b3467d479..2f0b76ad84ad65 100644 --- a/drivers/gpu/drm/apple/plane.c +++ b/drivers/gpu/drm/apple/plane.c @@ -394,6 +394,37 @@ static const u32 dcp_overlay_formats[] = { #endif }; +/* + * Formats for the 12.x firmware which does not support "l10r" / ARGB2101010 + */ +static const u32 dcp_primary_formats_12_x[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV24, + DRM_FORMAT_P010, + DRM_FORMAT_P210, +#if defined(DRM_FORMAT_P410) + DRM_FORMAT_P410, +#endif +}; + +static const u32 dcp_overlay_formats_12_x[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV24, + DRM_FORMAT_P010, + DRM_FORMAT_P210, +#if defined(DRM_FORMAT_P410) + DRM_FORMAT_P410, +#endif +}; + u64 apple_format_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID @@ -405,22 +436,37 @@ struct apple_plane { struct drm_plane *apple_plane_init(struct drm_device *dev, unsigned long possible_crtcs, + bool supports_l10r, enum drm_plane_type type) { struct apple_plane *plane; + const u32 *fmts; + u32 num_fmts; switch (type) { case DRM_PLANE_TYPE_PRIMARY: + if (supports_l10r) { + fmts = dcp_primary_formats; + num_fmts = ARRAY_SIZE(dcp_primary_formats); + } else { + fmts = dcp_primary_formats_12_x; + num_fmts = ARRAY_SIZE(dcp_primary_formats_12_x); + } plane = drmm_universal_plane_alloc(dev, struct apple_plane, base, possible_crtcs, - &apple_plane_funcs, - dcp_primary_formats, ARRAY_SIZE(dcp_primary_formats), + &apple_plane_funcs, fmts, num_fmts, apple_format_modifiers, type, NULL); break; case DRM_PLANE_TYPE_OVERLAY: case DRM_PLANE_TYPE_CURSOR: + if (supports_l10r) { + fmts = dcp_overlay_formats; + num_fmts = ARRAY_SIZE(dcp_overlay_formats); + } else { + fmts = dcp_overlay_formats_12_x; + num_fmts = ARRAY_SIZE(dcp_overlay_formats_12_x); + } plane = drmm_universal_plane_alloc(dev, struct apple_plane, base, possible_crtcs, - &apple_plane_funcs, - dcp_overlay_formats, ARRAY_SIZE(dcp_overlay_formats), + &apple_plane_funcs, fmts, num_fmts, apple_format_modifiers, type, NULL); break; default: diff --git a/drivers/gpu/drm/apple/plane.h b/drivers/gpu/drm/apple/plane.h index b03c3fdfed7dec..67d15938cf0dcb 100644 --- a/drivers/gpu/drm/apple/plane.h +++ b/drivers/gpu/drm/apple/plane.h @@ -24,6 +24,7 @@ struct apple_plane_state { struct drm_plane *apple_plane_init(struct drm_device *dev, unsigned long possible_crtcs, + bool supports_l10r, enum drm_plane_type type); #endif /* __APPLE_PLANE_H__ */ From 73029129dbb59a318112bc39cc9baf4d4088dd95 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 3 Mar 2026 22:57:44 +0100 Subject: [PATCH 270/352] fixup! drm/apple: Support color transformation matrices Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb.h | 6 ++---- drivers/gpu/drm/apple/iomfb_template.c | 17 ++++------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index bda46748a391d2..5799586106713e 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -368,10 +368,8 @@ struct iomfb_abort_swaps_dcp_resp { } __packed; struct iomfb_set_matrix_req { - u32 unk_u32; // maybe length? - u64 r[3]; - u64 g[3]; - u64 b[3]; + u32 location; + u64 matrix[9]; u8 matrix_null; u8 padding[3]; } __packed; diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index c016e75bc2d480..6598127bfdd376 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1407,20 +1407,11 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru } if (crtc_state->color_mgmt_changed && crtc_state->ctm) { - struct iomfb_set_matrix_req mat; struct drm_color_ctm *ctm = (struct drm_color_ctm *)crtc_state->ctm->data; - - mat.unk_u32 = 9; - mat.r[0] = ctm->matrix[0]; - mat.r[1] = ctm->matrix[1]; - mat.r[2] = ctm->matrix[2]; - mat.g[0] = ctm->matrix[3]; - mat.g[1] = ctm->matrix[4]; - mat.g[2] = ctm->matrix[5]; - mat.b[0] = ctm->matrix[6]; - mat.b[1] = ctm->matrix[7]; - mat.b[2] = ctm->matrix[8]; - + struct iomfb_set_matrix_req mat = { + .location = 9, + }; + memcpy(mat.matrix, ctm->matrix, sizeof(mat.matrix)); iomfb_set_matrix(dcp, false, &mat, do_swap, NULL); } else do_swap(dcp, NULL, NULL); From 756d8d667f3288e6798cf7e686508d6592c1773b Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Mon, 2 Mar 2026 21:15:07 +1000 Subject: [PATCH 271/352] drm: apple: Force colour management changes on CRTC enable Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/apple_drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index ab9fd49467dcfc..3c2ede2ee81bf7 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -111,8 +111,11 @@ static void apple_crtc_atomic_enable(struct drm_crtc *crtc, dcp_poweron(apple_crtc->dcp); } - if (crtc_state->active) + if (crtc_state->active) { + /* Force the CTM to be set on first swap */ + crtc_state->color_mgmt_changed = true; dcp_crtc_atomic_modeset(crtc, state); + } } static void apple_crtc_atomic_disable(struct drm_crtc *crtc, From 7ebdd98524c5bee624bb86f7e5303d97b31e2cd9 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 3 Mar 2026 23:03:34 +0100 Subject: [PATCH 272/352] fixup! drm: apple: Force colour management changes on CRTC enable Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/apple_drv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 3c2ede2ee81bf7..0f36dad6f96351 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -109,13 +109,12 @@ static void apple_crtc_atomic_enable(struct drm_crtc *crtc, if (crtc_state->active_changed && crtc_state->active) { struct apple_crtc *apple_crtc = to_apple_crtc(crtc); dcp_poweron(apple_crtc->dcp); - } - - if (crtc_state->active) { /* Force the CTM to be set on first swap */ crtc_state->color_mgmt_changed = true; - dcp_crtc_atomic_modeset(crtc, state); } + + if (crtc_state->active) + dcp_crtc_atomic_modeset(crtc, state); } static void apple_crtc_atomic_disable(struct drm_crtc *crtc, From d6685d3feb343994ac8f488f2c1e4d873a081fe3 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Mon, 2 Mar 2026 21:15:49 +1000 Subject: [PATCH 273/352] drm: apple: Explicitly set identity matrix when CTM blob is not set Unset CTM means a unit/pass-thru matrix should be used. Since we were checking for a valid CTM blob, this was resulting in a misconfigured colour management pipeline. This was most noticeable when using kwin's Night Light feature, specifically when waking the display after the morning transition was supposed to happen. Despite triggering a colour management change on CRTC enable, kwin clearing the CTM blob meant that there was nothing for us to passs in to IOMFB to set DCP's internal CTM. Explicitly pass the identity matrix to IOMFB if we have a pending colour management change and no CTM blob. Signed-off-by: James Calligeros Signed-off-by: Janne Grunau --- - simplify after refactoring and fix value for 1 (S31.32 sign-magnitude) - adjusted commit message to documented DRM KMS behaviour --- drivers/gpu/drm/apple/iomfb_template.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 6598127bfdd376..24ca6b866d1604 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1406,12 +1406,18 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru dcp->brightness.update = false; } - if (crtc_state->color_mgmt_changed && crtc_state->ctm) { - struct drm_color_ctm *ctm = (struct drm_color_ctm *)crtc_state->ctm->data; + if (crtc_state->color_mgmt_changed) { struct iomfb_set_matrix_req mat = { .location = 9, }; - memcpy(mat.matrix, ctm->matrix, sizeof(mat.matrix)); + + if (crtc_state->ctm) { + struct drm_color_ctm *ctm = (struct drm_color_ctm *)crtc_state->ctm->data; + memcpy(mat.matrix, ctm->matrix, sizeof(mat.matrix)); + } else { + mat.matrix[0] = mat.matrix[4] = mat.matrix[8] = 1LLU << 32; + } + iomfb_set_matrix(dcp, false, &mat, do_swap, NULL); } else do_swap(dcp, NULL, NULL); From ae85932e25e8d9add54a1f66c6ce5015bb10d11e Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 14 Mar 2026 08:13:03 +0100 Subject: [PATCH 274/352] drm/apple: Increase poweron timeout to 10 seconds Occasionally dcp_poweron takes a long time. Double the timeout to 10 seconds. This is most likely a sequencing error / race condition on driver side. On the system the timeout was observed dcp_set_power_state_req usually takes 1ms or less. Occasionally it takes much longer and sometimes exceeds 5 seconds. DCP clearly does more when poweron takes longer based on its syslog messages. This could be tied to the hotplug state or racing against DPTX commands. TODO: find a way to recover from timeouts. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/iomfb_template.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 24ca6b866d1604..1b7ecbcba925d1 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -824,15 +824,21 @@ void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp) dcp_set_display_device(dcp, false, &handle, dcp_on_set_parameter, cookie); } - ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(5000)); + ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(10000)); - if (ret == 0) - dev_warn(dcp->dev, "wait for power timed out\n"); - else if (ret > 0) - dev_info(dcp->dev, "dcp_set_power_state_req returned, %d ms remaining\n", jiffies_to_msecs(ret)); - if (ret <= 0) + if (ret == 0) { + dev_warn(dcp->dev, "wait for power timed out, connector will be broken\n"); + } else if (ret > 0) { + int msecs = jiffies_to_msecs(ret); + if (msecs > 6000) + dev_info(dcp->dev, "dcp_set_power_state_req returned, %d ms remaining\n", msecs); + else + dev_warn(dcp->dev, "dcp_set_power_state_req returned, %d ms remaining\n", msecs); + } else { drm_connector_set_link_status_property(&dcp->connector->base, DRM_MODE_LINK_STATUS_BAD); + dev_warn(dcp->dev, "wait for completion error: %d\n", ret); + } kref_put(&cookie->refcount, release_wait_cookie);; From 4c51472ace5768f8521e67fb139287a2fbeb4af5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 21 Mar 2026 21:04:28 +0100 Subject: [PATCH 275/352] fixup! drm/apple: Use iommu domain for piodma maps Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index e2a29653705b29..e31e4f1d26ea49 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -728,17 +728,15 @@ static void dcp_work_update_backlight(struct work_struct *work) static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp) { int ret; - struct device_node *node = of_get_child_by_name(dcp->dev->of_node, "piodma"); + struct device_node *node __free(device_node) = of_get_child_by_name(dcp->dev->of_node, "piodma"); if (!node) return dev_err_probe(dcp->dev, -ENODEV, "Failed to get piodma child DT node\n"); dcp->piodma = of_platform_device_create(node, NULL, dcp->dev); - if (!dcp->piodma) { - of_node_put(node); + if (!dcp->piodma) return dev_err_probe(dcp->dev, -ENODEV, "Failed to create piodma pdev for %pOF\n", node); - } ret = dma_set_mask_and_coherent(&dcp->piodma->dev, DMA_BIT_MASK(42)); if (ret) @@ -750,7 +748,6 @@ static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp) "Failed to configure IOMMU child DMA\n"); goto err_destroy_pdev; } - of_node_put(node); dcp->iommu_dom = iommu_get_domain_for_dev(&dcp->piodma->dev); if (IS_ERR(dcp->iommu_dom)) { @@ -763,7 +760,6 @@ static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp) return 0; err_destroy_pdev: - of_node_put(node); of_platform_device_destroy(&dcp->piodma->dev, NULL); return ret; } From c368e260dcf565c70e0648426d6dec7307464392 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 21 Mar 2026 21:05:37 +0100 Subject: [PATCH 276/352] fixup! drm/apple: Get rid of the piodma dummy driver Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index e31e4f1d26ea49..5d5825d06a8dc5 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -1046,7 +1046,7 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data) dcp->connector_type = DRM_MODE_CONNECTOR_Unknown; ret = dcp_create_piodma_iommu_dev(dcp); - if (ret) + if (ret || !dcp->iommu_dom) return dev_err_probe(dev, ret, "Failed to created PIODMA iommu child device"); From 846dcb94d08602885a61430fd0b62b566a1ded85 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 22 Mar 2026 10:25:53 +0100 Subject: [PATCH 277/352] drm/apple: select APPLE_PMP_REPORT DCP will report to PMP in the future so ensure it is enabled. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/apple/Kconfig b/drivers/gpu/drm/apple/Kconfig index df247b6ed77deb..a1d4498c5d788e 100644 --- a/drivers/gpu/drm/apple/Kconfig +++ b/drivers/gpu/drm/apple/Kconfig @@ -5,6 +5,7 @@ config DRM_APPLE depends on ARCH_APPLE || COMPILE_TEST depends on APPLE_RTKIT depends on OF_ADDRESS + select APPLE_PMP_REPORT select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_KMS_DMA_HELPER From 4b1d0b029fb1b7f93e72be2d9553a358b8054d7c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Mar 2026 13:49:17 +0200 Subject: [PATCH 278/352] drm/apple: Power DCP off when HDMI port is not connected Power DCP off after init when the HDMI port is not connected. According to user reports connecting and disconnecting the HMI port saves ~0.5W on 14-/16-inch Macbook Pros. This was not reproducibable here though but powering DCP down is correct in any case. Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dcp.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 5d5825d06a8dc5..9dfc3fd002f530 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -581,6 +581,21 @@ int dcp_start(struct platform_device *pdev) return ret; } +static void _dcp_poweroff(struct apple_dcp *dcp) +{ + switch (dcp->fw_compat) { + case DCP_FIRMWARE_V_12_3: + iomfb_poweroff_v12_3(dcp); + break; + case DCP_FIRMWARE_V_13_5: + iomfb_poweroff_v13_3(dcp); + break; + default: + WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); + break; + } +} + static int dcp_enable_dp2hdmi_hpd(struct apple_dcp *dcp) { // check HPD state before enabling the edge triggered IRQ @@ -590,6 +605,8 @@ static int dcp_enable_dp2hdmi_hpd(struct apple_dcp *dcp) if (connected) dcp_dptx_connect(dcp, 0); + else + _dcp_poweroff(dcp); } if (dcp->hdmi_hpd_irq) @@ -673,17 +690,7 @@ void dcp_poweroff(struct platform_device *pdev) if (dcp->avep) av_service_disconnect(dcp); - switch (dcp->fw_compat) { - case DCP_FIRMWARE_V_12_3: - iomfb_poweroff_v12_3(dcp); - break; - case DCP_FIRMWARE_V_13_5: - iomfb_poweroff_v13_3(dcp); - break; - default: - WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); - break; - } + _dcp_poweroff(dcp); if (dcp->hdmi_hpd) { bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); From 45af4de5649cf1b84dd0076a4c77e3e3d550ba0d Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 31 Aug 2023 19:08:46 +0900 Subject: [PATCH 279/352] media: apple: Add Apple ISP driver Signed-off-by: Eileen Yoon --- drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 1 + drivers/media/platform/apple/Kconfig | 5 + drivers/media/platform/apple/Makefile | 3 + drivers/media/platform/apple/isp/.gitignore | 1 + drivers/media/platform/apple/isp/Kconfig | 11 + drivers/media/platform/apple/isp/Makefile | 3 + drivers/media/platform/apple/isp/isp-cam.c | 540 +++++++++++++++++ drivers/media/platform/apple/isp/isp-cam.h | 20 + drivers/media/platform/apple/isp/isp-cmd.c | 544 +++++++++++++++++ drivers/media/platform/apple/isp/isp-cmd.h | 532 ++++++++++++++++ drivers/media/platform/apple/isp/isp-drv.c | 333 ++++++++++ drivers/media/platform/apple/isp/isp-drv.h | 258 ++++++++ drivers/media/platform/apple/isp/isp-fw.c | 606 +++++++++++++++++++ drivers/media/platform/apple/isp/isp-fw.h | 12 + drivers/media/platform/apple/isp/isp-iommu.c | 275 +++++++++ drivers/media/platform/apple/isp/isp-iommu.h | 38 ++ drivers/media/platform/apple/isp/isp-ipc.c | 329 ++++++++++ drivers/media/platform/apple/isp/isp-ipc.h | 26 + drivers/media/platform/apple/isp/isp-regs.h | 62 ++ drivers/media/platform/apple/isp/isp-v4l2.c | 600 ++++++++++++++++++ drivers/media/platform/apple/isp/isp-v4l2.h | 12 + 22 files changed, 4212 insertions(+) create mode 100644 drivers/media/platform/apple/Kconfig create mode 100644 drivers/media/platform/apple/Makefile create mode 100644 drivers/media/platform/apple/isp/.gitignore create mode 100644 drivers/media/platform/apple/isp/Kconfig create mode 100644 drivers/media/platform/apple/isp/Makefile create mode 100644 drivers/media/platform/apple/isp/isp-cam.c create mode 100644 drivers/media/platform/apple/isp/isp-cam.h create mode 100644 drivers/media/platform/apple/isp/isp-cmd.c create mode 100644 drivers/media/platform/apple/isp/isp-cmd.h create mode 100644 drivers/media/platform/apple/isp/isp-drv.c create mode 100644 drivers/media/platform/apple/isp/isp-drv.h create mode 100644 drivers/media/platform/apple/isp/isp-fw.c create mode 100644 drivers/media/platform/apple/isp/isp-fw.h create mode 100644 drivers/media/platform/apple/isp/isp-iommu.c create mode 100644 drivers/media/platform/apple/isp/isp-iommu.h create mode 100644 drivers/media/platform/apple/isp/isp-ipc.c create mode 100644 drivers/media/platform/apple/isp/isp-ipc.h create mode 100644 drivers/media/platform/apple/isp/isp-regs.h create mode 100644 drivers/media/platform/apple/isp/isp-v4l2.c create mode 100644 drivers/media/platform/apple/isp/isp-v4l2.h diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 3f0b7bb68cc940..8b31f087e7da20 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -65,6 +65,7 @@ config VIDEO_MUX source "drivers/media/platform/allegro-dvt/Kconfig" source "drivers/media/platform/amlogic/Kconfig" source "drivers/media/platform/amphion/Kconfig" +source "drivers/media/platform/apple/Kconfig" source "drivers/media/platform/arm/Kconfig" source "drivers/media/platform/aspeed/Kconfig" source "drivers/media/platform/atmel/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 6d5f79ddfcc37a..0e93f7d860caf4 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -8,6 +8,7 @@ obj-y += allegro-dvt/ obj-y += amlogic/ obj-y += amphion/ +obj-y += apple/ obj-y += arm/ obj-y += aspeed/ obj-y += atmel/ diff --git a/drivers/media/platform/apple/Kconfig b/drivers/media/platform/apple/Kconfig new file mode 100644 index 00000000000000..f16508bff5242a --- /dev/null +++ b/drivers/media/platform/apple/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +comment "Apple media platform drivers" + +source "drivers/media/platform/apple/isp/Kconfig" diff --git a/drivers/media/platform/apple/Makefile b/drivers/media/platform/apple/Makefile new file mode 100644 index 00000000000000..d8fe985b0e6c37 --- /dev/null +++ b/drivers/media/platform/apple/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += isp/ diff --git a/drivers/media/platform/apple/isp/.gitignore b/drivers/media/platform/apple/isp/.gitignore new file mode 100644 index 00000000000000..bd7fab40e0d98a --- /dev/null +++ b/drivers/media/platform/apple/isp/.gitignore @@ -0,0 +1 @@ +.clang-format diff --git a/drivers/media/platform/apple/isp/Kconfig b/drivers/media/platform/apple/isp/Kconfig new file mode 100644 index 00000000000000..5695bef44adf5b --- /dev/null +++ b/drivers/media/platform/apple/isp/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config VIDEO_APPLE_ISP + tristate "Apple Silicon Image Signal Processor driver" + select VIDEOBUF2_CORE + select VIDEOBUF2_V4L2 + select VIDEOBUF2_DMA_SG + depends on ARCH_APPLE || COMPILE_TEST + depends on OF_ADDRESS + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV diff --git a/drivers/media/platform/apple/isp/Makefile b/drivers/media/platform/apple/isp/Makefile new file mode 100644 index 00000000000000..4649f32987f025 --- /dev/null +++ b/drivers/media/platform/apple/isp/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +apple-isp-y := isp-cam.o isp-cmd.o isp-drv.o isp-fw.o isp-iommu.o isp-ipc.o isp-v4l2.o +obj-$(CONFIG_VIDEO_APPLE_ISP) += apple-isp.o diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c new file mode 100644 index 00000000000000..6d08248ef44776 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -0,0 +1,540 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include + +#include "isp-cam.h" +#include "isp-cmd.h" +#include "isp-fw.h" +#include "isp-iommu.h" + +struct isp_setfile { + u32 version; + u32 magic; + const char *path; + size_t size; +}; + +struct isp_preset { + u32 index; + u32 width; + u32 height; + u32 x1; + u32 y1; + u32 x2; + u32 y2; + u32 orig_width; + u32 orig_height; +}; + +// clang-format off +static const struct isp_setfile isp_setfiles[] = { + [ISP_IMX248_1820_01] = {0x248, 0x18200103, "isp/1820_01XX.dat", 0x442c}, + [ISP_IMX248_1822_02] = {0x248, 0x18220201, "isp/1822_02XX.dat", 0x442c}, + [ISP_IMX343_5221_02] = {0x343, 0x52210211, "isp/5221_02XX.dat", 0x4870}, + [ISP_IMX354_9251_02] = {0x354, 0x92510208, "isp/9251_02XX.dat", 0xa5ec}, + [ISP_IMX356_4820_01] = {0x356, 0x48200107, "isp/4820_01XX.dat", 0x9324}, + [ISP_IMX356_4820_02] = {0x356, 0x48200206, "isp/4820_02XX.dat", 0x9324}, + [ISP_IMX364_8720_01] = {0x364, 0x87200103, "isp/8720_01XX.dat", 0x36ac}, + [ISP_IMX364_8723_01] = {0x364, 0x87230101, "isp/8723_01XX.dat", 0x361c}, + [ISP_IMX372_3820_01] = {0x372, 0x38200108, "isp/3820_01XX.dat", 0xfdb0}, + [ISP_IMX372_3820_02] = {0x372, 0x38200205, "isp/3820_02XX.dat", 0xfdb0}, + [ISP_IMX372_3820_11] = {0x372, 0x38201104, "isp/3820_11XX.dat", 0xfdb0}, + [ISP_IMX372_3820_12] = {0x372, 0x38201204, "isp/3820_12XX.dat", 0xfdb0}, + [ISP_IMX405_9720_01] = {0x405, 0x97200102, "isp/9720_01XX.dat", 0x92c8}, + [ISP_IMX405_9721_01] = {0x405, 0x97210102, "isp/9721_01XX.dat", 0x9818}, + [ISP_IMX405_9723_01] = {0x405, 0x97230101, "isp/9723_01XX.dat", 0x92c8}, + [ISP_IMX414_2520_01] = {0x414, 0x25200102, "isp/2520_01XX.dat", 0xa444}, + [ISP_IMX503_7820_01] = {0x503, 0x78200109, "isp/7820_01XX.dat", 0xb268}, + [ISP_IMX503_7820_02] = {0x503, 0x78200206, "isp/7820_02XX.dat", 0xb268}, + [ISP_IMX505_3921_01] = {0x505, 0x39210102, "isp/3921_01XX.dat", 0x89b0}, + [ISP_IMX514_2820_01] = {0x514, 0x28200108, "isp/2820_01XX.dat", 0xa198}, + [ISP_IMX514_2820_02] = {0x514, 0x28200205, "isp/2820_02XX.dat", 0xa198}, + [ISP_IMX514_2820_03] = {0x514, 0x28200305, "isp/2820_03XX.dat", 0xa198}, + [ISP_IMX514_2820_04] = {0x514, 0x28200405, "isp/2820_04XX.dat", 0xa198}, + [ISP_IMX558_1921_01] = {0x558, 0x19210106, "isp/1921_01XX.dat", 0xad40}, + [ISP_IMX558_1922_02] = {0x558, 0x19220201, "isp/1922_02XX.dat", 0xad40}, + [ISP_IMX603_7920_01] = {0x603, 0x79200109, "isp/7920_01XX.dat", 0xad2c}, + [ISP_IMX603_7920_02] = {0x603, 0x79200205, "isp/7920_02XX.dat", 0xad2c}, + [ISP_IMX603_7921_01] = {0x603, 0x79210104, "isp/7921_01XX.dat", 0xad90}, + [ISP_IMX613_4920_01] = {0x613, 0x49200108, "isp/4920_01XX.dat", 0x9324}, + [ISP_IMX613_4920_02] = {0x613, 0x49200204, "isp/4920_02XX.dat", 0x9324}, + [ISP_IMX614_2921_01] = {0x614, 0x29210107, "isp/2921_01XX.dat", 0xed6c}, + [ISP_IMX614_2921_02] = {0x614, 0x29210202, "isp/2921_02XX.dat", 0xed6c}, + [ISP_IMX614_2922_02] = {0x614, 0x29220201, "isp/2922_02XX.dat", 0xed6c}, + [ISP_IMX633_3622_01] = {0x633, 0x36220111, "isp/3622_01XX.dat", 0x100d4}, + [ISP_IMX703_7721_01] = {0x703, 0x77210106, "isp/7721_01XX.dat", 0x936c}, + [ISP_IMX703_7722_01] = {0x703, 0x77220106, "isp/7722_01XX.dat", 0xac20}, + [ISP_IMX713_4721_01] = {0x713, 0x47210107, "isp/4721_01XX.dat", 0x936c}, + [ISP_IMX713_4722_01] = {0x713, 0x47220109, "isp/4722_01XX.dat", 0x9218}, + [ISP_IMX714_2022_01] = {0x714, 0x20220107, "isp/2022_01XX.dat", 0xa198}, + [ISP_IMX772_3721_01] = {0x772, 0x37210106, "isp/3721_01XX.dat", 0xfdf8}, + [ISP_IMX772_3721_11] = {0x772, 0x37211106, "isp/3721_11XX.dat", 0xfe14}, + [ISP_IMX772_3722_01] = {0x772, 0x37220104, "isp/3722_01XX.dat", 0xfca4}, + [ISP_IMX772_3723_01] = {0x772, 0x37230106, "isp/3723_01XX.dat", 0xfca4}, + [ISP_IMX814_2123_01] = {0x814, 0x21230101, "isp/2123_01XX.dat", 0xed54}, + [ISP_IMX853_7622_01] = {0x853, 0x76220112, "isp/7622_01XX.dat", 0x247f8}, + [ISP_IMX913_7523_01] = {0x913, 0x75230107, "isp/7523_01XX.dat", 0x247f8}, + [ISP_VD56G0_6221_01] = {0xd56, 0x62210102, "isp/6221_01XX.dat", 0x1b80}, + [ISP_VD56G0_6222_01] = {0xd56, 0x62220102, "isp/6222_01XX.dat", 0x1b80}, +}; +// clang-format on + +// one day we will do this intelligently +static const struct isp_preset isp_presets[] = { + [ISP_IMX248_1820_01] = { 0, 1280, 720, 8, 8, 1280, 720, 1296, 736 }, +}; + +static int isp_ch_get_sensor_id(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + enum isp_sensor_id id; + int err = 0; + + /* TODO need more datapoints to figure out the sub-versions + * Defaulting to 1st release for now, the calib files aren't too different. + */ + switch (fmt->version) { + case 0x248: + id = ISP_IMX248_1820_01; + break; + case 0x343: + id = ISP_IMX343_5221_02; + break; + case 0x354: + id = ISP_IMX354_9251_02; + break; + case 0x356: + id = ISP_IMX356_4820_01; + break; + case 0x364: + id = ISP_IMX364_8720_01; + break; + case 0x372: + id = ISP_IMX372_3820_01; + break; + case 0x405: + id = ISP_IMX405_9720_01; + break; + case 0x414: + id = ISP_IMX414_2520_01; + break; + case 0x503: + id = ISP_IMX503_7820_01; + break; + case 0x505: + id = ISP_IMX505_3921_01; + break; + case 0x514: + id = ISP_IMX514_2820_01; + break; + case 0x558: + id = ISP_IMX558_1921_01; + break; + case 0x603: + id = ISP_IMX603_7920_01; + break; + case 0x613: + id = ISP_IMX613_4920_01; + break; + case 0x614: + id = ISP_IMX614_2921_01; + break; + case 0x633: + id = ISP_IMX633_3622_01; + break; + case 0x703: + id = ISP_IMX703_7721_01; + break; + case 0x713: + id = ISP_IMX713_4721_01; + break; + case 0x714: + id = ISP_IMX714_2022_01; + break; + case 0x772: + id = ISP_IMX772_3721_01; + break; + case 0x814: + id = ISP_IMX814_2123_01; + break; + case 0x853: + id = ISP_IMX853_7622_01; + break; + case 0x913: + id = ISP_IMX913_7523_01; + break; + case 0xd56: + id = ISP_VD56G0_6221_01; + break; + default: + err = -EINVAL; + break; + } + + if (err) + dev_err(isp->dev, "invalid sensor version: 0x%x\n", + fmt->version); + else + fmt->id = id; + + return err; +} + +static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + int err = 0; + + struct cmd_ch_info *args; /* Too big to allocate on stack */ + args = kzalloc(sizeof(*args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + err = isp_cmd_ch_info_get(isp, ch, args); + if (err) + goto exit; + + dev_info(isp->dev, "found sensor %x %s on ch %d\n", args->version, + args->module_sn, ch); + + fmt->version = args->version; + fmt->num_presets = args->num_presets; + + pr_info("apple-isp: ch: CISP_CMD_CH_INFO_GET: %d\n", ch); + print_hex_dump(KERN_INFO, "apple-isp: ch: ", DUMP_PREFIX_NONE, 32, 4, + args, sizeof(*args), false); + + err = isp_ch_get_sensor_id(isp, ch); + if (err || (fmt->id != ISP_IMX248_1820_01)) { + dev_err(isp->dev, + "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", + ch); + return -ENODEV; + } + +exit: + kfree(args); + + return err; +} + +static int isp_ch_get_camera_preset(struct apple_isp *isp, u32 ch, u32 ps) +{ + int err = 0; + + struct cmd_ch_camera_config *args; /* Too big to allocate on stack */ + args = kzalloc(sizeof(*args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + err = isp_cmd_ch_camera_config_get(isp, ch, ps, args); + if (err) + goto exit; + + pr_info("apple-isp: ps: CISP_CMD_CH_CAMERA_CONFIG_GET: %d\n", ps); + print_hex_dump(KERN_INFO, "apple-isp: ps: ", DUMP_PREFIX_NONE, 32, 4, + args, sizeof(*args), false); + +exit: + kfree(args); + + return err; +} + +static void isp_ch_dump_camera_presets(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + for (u32 ps = 0; ps < fmt->num_presets; ps++) { + isp_ch_get_camera_preset(isp, ch, ps); + } +} + +static int isp_ch_cache_camera_preset(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + const struct isp_preset *preset = &isp_presets[fmt->id]; + size_t total_size; + + isp_ch_dump_camera_presets(isp, ch); + + fmt->preset = preset->index; + + fmt->width = preset->width; + fmt->height = preset->height; + + fmt->x1 = preset->x1; + fmt->y1 = preset->y1; + fmt->x2 = preset->x2; + fmt->y2 = preset->y2; + + /* I really fucking hope they all use NV12. */ + fmt->num_planes = 2; + fmt->plane_size[0] = fmt->width * fmt->height; + fmt->plane_size[1] = fmt->plane_size[0] / 2; + + total_size = 0; + for (int i = 0; i < fmt->num_planes; i++) + total_size += fmt->plane_size[i]; + fmt->total_size = total_size; + + return 0; +} + +static int isp_ch_cache_camera_info(struct apple_isp *isp, u32 ch) +{ + int err; + + err = isp_ch_cache_sensor_info(isp, ch); + if (err) { + dev_err(isp->dev, "ch %d: failed to cache sensor info: %d\n", + ch, err); + return err; + } + + err = isp_ch_cache_camera_preset(isp, ch); + if (err) { + dev_err(isp->dev, "ch %d: failed to cache camera preset: %d\n", + ch, err); + return err; + } + + return 0; +} + +static int isp_detect_camera(struct apple_isp *isp) +{ + int err; + + struct cmd_config_get args; + memset(&args, 0, sizeof(args)); + + err = isp_cmd_config_get(isp, &args); + if (err) + return err; + + pr_info("apple-isp: CISP_CMD_CONFIG_GET: \n"); + print_hex_dump(KERN_INFO, "apple-isp: ", DUMP_PREFIX_NONE, 32, 4, &args, + sizeof(args), false); + + if (!args.num_channels) { + dev_err(isp->dev, "did not detect any channels\n"); + return -ENODEV; + } + + if (args.num_channels > ISP_MAX_CHANNELS) { + dev_warn(isp->dev, "found %d channels when maximum is %d\n", + args.num_channels, ISP_MAX_CHANNELS); + args.num_channels = ISP_MAX_CHANNELS; + } + + if (args.num_channels > 1) { + dev_warn( + isp->dev, + "warning: driver doesn't support multiple channels. Please file a bug report with hardware info & dmesg trace.\n"); + } + + isp->num_channels = args.num_channels; + isp->current_ch = 0; + + return isp_ch_cache_camera_info(isp, isp->current_ch); /* I told you */ +} + +int apple_isp_detect_camera(struct apple_isp *isp) +{ + int err; + + /* RPM must be enabled prior to calling this */ + err = apple_isp_firmware_boot(isp); + if (err) { + dev_err(isp->dev, + "failed to boot firmware for initial sensor detection: %d\n", + err); + return -EPROBE_DEFER; + } + + err = isp_detect_camera(isp); + apple_isp_firmware_shutdown(isp); + + return err; +} + +static int isp_ch_load_setfile(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + const struct isp_setfile *setfile = &isp_setfiles[fmt->id]; + const struct firmware *fw; + u32 magic; + int err; + + err = request_firmware(&fw, setfile->path, isp->dev); + if (err) { + dev_err(isp->dev, "failed to request setfile '%s': %d\n", + setfile->path, err); + return err; + } + + if (fw->size < setfile->size) { + dev_err(isp->dev, "setfile too small (0x%lx/0x%zx)\n", fw->size, + setfile->size); + release_firmware(fw); + return -EINVAL; + } + + magic = be32_to_cpup((__be32 *)fw->data); + if (magic != setfile->magic) { + dev_err(isp->dev, "setfile '%s' corrupted?\n", setfile->path); + release_firmware(fw); + return -EINVAL; + } + + isp_iowrite(isp, isp->data_surf->iova, (void *)fw->data, setfile->size); + release_firmware(fw); + + return isp_cmd_ch_set_file_load(isp, ch, isp->data_surf->iova, + setfile->size); +} + +static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + int err; + + /* The setfile isn't requisite but then we don't get calibration */ + err = isp_ch_load_setfile(isp, ch); + if (err) { + dev_err(isp->dev, "warning: calibration data not loaded: %d\n", + err); + } + + err = isp_cmd_ch_sbs_enable(isp, ch, 1); + if (err) + return err; + + err = isp_cmd_ch_buffer_recycle_mode_set( + isp, ch, CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY); + if (err) + return err; + + err = isp_cmd_ch_buffer_recycle_start(isp, ch); + if (err) + return err; + + err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset); + if (err) + return err; + + err = isp_cmd_ch_crop_set(isp, ch, fmt->x1, fmt->y1, fmt->x2, fmt->y2); + if (err) + return err; + + err = isp_cmd_ch_output_config_set(isp, ch, fmt->width, fmt->height, + CISP_COLORSPACE_REC709, + CISP_OUTPUT_FORMAT_NV12); + if (err) + return err; + + err = isp_cmd_ch_preview_stream_set(isp, ch, 1); + if (err) + return err; + + err = isp_cmd_ch_cnr_start(isp, ch); + if (err) + return err; + + err = isp_cmd_ch_mbnr_enable(isp, ch, 0, 1, 1); + if (err) + return err; + + err = isp_cmd_apple_ch_temporal_filter_start(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_motion_history_start(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_temporal_filter_enable(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_ae_fd_scene_metering_config_set(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_ae_metering_mode_set(isp, ch, 3); + if (err) + return err; + + err = isp_cmd_ch_ae_stability_set(isp, ch, 32); + if (err) + return err; + + err = isp_cmd_ch_ae_stability_to_stable_set(isp, ch, 20); + if (err) + return err; + + err = isp_cmd_ch_sif_pixel_format_set(isp, ch); + if (err) + return err; + + err = isp_cmd_ch_ae_frame_rate_max_set(isp, ch, ISP_FRAME_RATE_DEN); + if (err) + return err; + + err = isp_cmd_ch_ae_frame_rate_min_set(isp, ch, ISP_FRAME_RATE_DEN); + if (err) + return err; + + err = isp_cmd_ch_buffer_pool_config_set(isp, ch, CISP_POOL_TYPE_META); + if (err) + return err; + + err = isp_cmd_ch_buffer_pool_config_set(isp, ch, + CISP_POOL_TYPE_META_CAPTURE); + if (err) + return err; + + return 0; +} + +static int isp_configure_capture(struct apple_isp *isp) +{ + return isp_ch_configure_capture(isp, isp->current_ch); +} + +int apple_isp_start_camera(struct apple_isp *isp) +{ + int err; + + err = apple_isp_firmware_boot(isp); + if (err < 0) { + dev_err(isp->dev, "failed to boot firmware: %d\n", err); + return err; + } + + err = isp_configure_capture(isp); + if (err) { + dev_err(isp->dev, "failed to configure capture: %d\n", err); + apple_isp_firmware_shutdown(isp); + return err; + } + + return 0; +} + +void apple_isp_stop_camera(struct apple_isp *isp) +{ + apple_isp_firmware_shutdown(isp); +} + +int apple_isp_start_capture(struct apple_isp *isp) +{ + return isp_cmd_ch_start(isp, 0); // TODO channel mask +} + +void apple_isp_stop_capture(struct apple_isp *isp) +{ + isp_cmd_ch_stop(isp, 0); // TODO channel mask + isp_cmd_ch_buffer_return(isp, isp->current_ch); +} diff --git a/drivers/media/platform/apple/isp/isp-cam.h b/drivers/media/platform/apple/isp/isp-cam.h new file mode 100644 index 00000000000000..126e5806c8c416 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-cam.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_CAM_H__ +#define __ISP_CAM_H__ + +#include "isp-drv.h" + +#define ISP_FRAME_RATE_NUM 256 +#define ISP_FRAME_RATE_DEN 7680 + +int apple_isp_detect_camera(struct apple_isp *isp); + +int apple_isp_start_camera(struct apple_isp *isp); +void apple_isp_stop_camera(struct apple_isp *isp); + +int apple_isp_start_capture(struct apple_isp *isp); +void apple_isp_stop_capture(struct apple_isp *isp); + +#endif /* __ISP_CAM_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c new file mode 100644 index 00000000000000..79ffb2b1c33881 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include "isp-cmd.h" +#include "isp-iommu.h" +#include "isp-ipc.h" + +#define CISP_OPCODE_SHIFT 32UL +#define CISP_OPCODE(x) (((u64)(x)) << CISP_OPCODE_SHIFT) +#define CISP_OPCODE_GET(x) (((u64)(x)) >> CISP_OPCODE_SHIFT) + +#define CISP_TIMEOUT msecs_to_jiffies(3000) +#define CISP_SEND_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0)) +#define CISP_SEND_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a))) +#define CISP_SEND_OUT(x, a) (cisp_send_read((x), (a), sizeof(*a), sizeof(*a))) + +static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize) +{ + struct isp_channel *chan = isp->chan_io; + struct isp_message *req = &chan->req; + int err; + + req->arg0 = isp->cmd_iova; + req->arg1 = insize; + req->arg2 = outsize; + + isp_iowrite(isp, isp->cmd_iova, args, insize); + err = ipc_chan_send(isp, chan, CISP_TIMEOUT); + if (err) { + u64 opcode; + memcpy(&opcode, args, sizeof(opcode)); + dev_err(isp->dev, + "%s: failed to send OPCODE 0x%04llx: [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, CISP_OPCODE_GET(opcode), req->arg0, + req->arg1, req->arg2); + } + + return err; +} + +static int cisp_send_read(struct apple_isp *isp, void *args, u32 insize, + u32 outsize) +{ + /* TODO do I need to lock the iova space? */ + int err = cisp_send(isp, args, insize, outsize); + if (err) + return err; + isp_ioread(isp, isp->cmd_iova, args, outsize); + return 0; +} + +int isp_cmd_start(struct apple_isp *isp, u32 mode) +{ + struct cmd_start args = { + .opcode = CISP_OPCODE(CISP_CMD_START), + .mode = mode, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_suspend(struct apple_isp *isp) +{ + struct cmd_suspend args = { + .opcode = CISP_OPCODE(CISP_CMD_SUSPEND), + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_print_enable(struct apple_isp *isp, u32 enable) +{ + struct cmd_print_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_PRINT_ENABLE), + .enable = enable, + }; + return CISP_SEND_INOUT(isp, args); +} + +int isp_cmd_trace_enable(struct apple_isp *isp, u32 enable) +{ + struct cmd_trace_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_TRACE_ENABLE), + .enable = enable, + }; + return CISP_SEND_INOUT(isp, args); +} + +int isp_cmd_config_get(struct apple_isp *isp, struct cmd_config_get *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CONFIG_GET); + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_set_isp_pmu_base(struct apple_isp *isp, u64 pmu_base) +{ + struct cmd_set_isp_pmu_base args = { + .opcode = CISP_OPCODE(CISP_CMD_SET_ISP_PMU_BASE), + .pmu_base = pmu_base, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_set_dsid_clr_req_base2(struct apple_isp *isp, u64 dsid_clr_base0, + u64 dsid_clr_base1, u64 dsid_clr_base2, + u64 dsid_clr_base3, u32 dsid_clr_range0, + u32 dsid_clr_range1, u32 dsid_clr_range2, + u32 dsid_clr_range3) +{ + struct cmd_set_dsid_clr_req_base2 args = { + .opcode = CISP_OPCODE(CISP_CMD_SET_DSID_CLR_REG_BASE2), + .dsid_clr_base0 = dsid_clr_base0, + .dsid_clr_base1 = dsid_clr_base1, + .dsid_clr_base2 = dsid_clr_base2, + .dsid_clr_base3 = dsid_clr_base3, + .dsid_clr_range0 = dsid_clr_range0, + .dsid_clr_range1 = dsid_clr_range1, + .dsid_clr_range2 = dsid_clr_range2, + .dsid_clr_range3 = dsid_clr_range3, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_pmp_ctrl_set(struct apple_isp *isp, u64 clock_scratch, + u64 clock_base, u8 clock_bit, u8 clock_size, + u64 bandwidth_scratch, u64 bandwidth_base, + u8 bandwidth_bit, u8 bandwidth_size) +{ + struct cmd_pmp_ctrl_set args = { + .opcode = CISP_OPCODE(CISP_CMD_PMP_CTRL_SET), + .clock_scratch = clock_scratch, + .clock_base = clock_base, + .clock_bit = clock_bit, + .clock_size = clock_size, + .clock_pad = 0, + .bandwidth_scratch = bandwidth_scratch, + .bandwidth_base = bandwidth_base, + .bandwidth_bit = bandwidth_bit, + .bandwidth_size = bandwidth_size, + .bandwidth_pad = 0, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_fid_enter(struct apple_isp *isp) +{ + struct cmd_fid_enter args = { + .opcode = CISP_OPCODE(CISP_CMD_FID_ENTER), + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_fid_exit(struct apple_isp *isp) +{ + struct cmd_fid_exit args = { + .opcode = CISP_OPCODE(CISP_CMD_FID_EXIT), + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_start args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_START), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_stop(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_stop args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_STOP), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_info_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_info *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CH_INFO_GET); + args->chan = chan; + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_ch_camera_config_get(struct apple_isp *isp, u32 chan, u32 preset, + struct cmd_ch_camera_config *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CH_CAMERA_CONFIG_GET); + args->preset = preset; + args->chan = chan; + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_ch_camera_config_current_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_camera_config *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CH_CAMERA_CONFIG_CURRENT_GET); + args->chan = chan; + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_ch_camera_config_select(struct apple_isp *isp, u32 chan, u32 preset) +{ + struct cmd_ch_camera_config_select args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_CAMERA_CONFIG_SELECT), + .chan = chan, + .preset = preset, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_buffer_return args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_RETURN), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u32 addr, + u32 size) +{ + struct cmd_ch_set_file_load args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), + .chan = chan, + .addr = addr, + .size = size, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_sbs_enable(struct apple_isp *isp, u32 chan, u32 enable) +{ + struct cmd_ch_sbs_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SBS_ENABLE), + .chan = chan, + .enable = enable, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, + u32 y2) +{ + struct cmd_ch_crop_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_CROP_SET), + .chan = chan, + .x1 = x1, + .y1 = y1, + .x2 = x2, + .y2 = y2, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_output_config_set(struct apple_isp *isp, u32 chan, u32 width, + u32 height, u32 colorspace, u32 format) +{ + struct cmd_ch_output_config_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_OUTPUT_CONFIG_SET), + .chan = chan, + .width = width, + .height = height, + .colorspace = colorspace, + .format = format, + .unk_w0 = width, + .unk_w1 = width, + .unk_24 = 0, + .padding_rows = 0, + .unk_h0 = height, + .compress = 0, + .unk_w2 = width, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_preview_stream_set(struct apple_isp *isp, u32 chan, u32 stream) +{ + struct cmd_ch_preview_stream_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_PREVIEW_STREAM_SET), + .chan = chan, + .stream = stream, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_als_disable(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_als_disable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_ALS_DISABLE), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_cnr_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_cnr_start args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_CNR_START), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_mbnr_enable(struct apple_isp *isp, u32 chan, u32 use_case, + u32 mode, u32 enable_chroma) +{ + struct cmd_ch_mbnr_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_MBNR_ENABLE), + .chan = chan, + .use_case = use_case, + .mode = mode, + .enable_chroma = enable_chroma, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_sif_pixel_format_set(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_sif_pixel_format_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SIF_PIXEL_FORMAT_SET), + .chan = chan, + .format = 3, + .type = 1, + .compress = 0, + .unk_10 = 0, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_buffer_recycle_mode_set(struct apple_isp *isp, u32 chan, + u32 mode) +{ + struct cmd_ch_buffer_recycle_mode_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_RECYCLE_MODE_SET), + .chan = chan, + .mode = mode, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_buffer_recycle_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_buffer_recycle_start args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_RECYCLE_START), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, u16 type) +{ + struct cmd_ch_buffer_pool_config_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_POOL_CONFIG_SET), + .chan = chan, + .type = type, + .count = 16, + .meta_size0 = ISP_META_SIZE, + .meta_size1 = ISP_META_SIZE, + .data_blocks = 1, + .compress = 0, + }; + memset(args.zero, 0, sizeof(u32) * 0x1f); + return CISP_SEND_INOUT(isp, args); +} + +int isp_cmd_ch_buffer_pool_return(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_buffer_pool_return args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_POOL_RETURN), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_temporal_filter_start args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_START), + .chan = chan, + .unk_c = 1, + .unk_10 = 0, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_temporal_filter_stop(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_temporal_filter_stop args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_STOP), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_motion_history_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_motion_history_start args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_MOTION_HISTORY_START), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_motion_history_stop(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_motion_history_stop args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_MOTION_HISTORY_STOP), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_temporal_filter_enable(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_temporal_filter_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_ENABLE), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_temporal_filter_disable(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_temporal_filter_disable args = { + .opcode = + CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_DISABLE), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_ae_stability_set(struct apple_isp *isp, u32 chan, u32 stability) +{ + struct cmd_ch_ae_stability_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_AE_STABILITY_SET), + .chan = chan, + .stability = stability, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_ae_stability_to_stable_set(struct apple_isp *isp, u32 chan, + u32 stability) +{ + struct cmd_ch_ae_stability_to_stable_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_AE_STABILITY_TO_STABLE_SET), + .chan = chan, + .stability = stability, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_ae_frame_rate_max_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_ae_frame_rate_max_get *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CH_AE_FRAME_RATE_MAX_GET); + args->chan = chan; + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_ch_ae_frame_rate_max_set(struct apple_isp *isp, u32 chan, + u32 framerate) +{ + struct cmd_ch_ae_frame_rate_max_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_AE_FRAME_RATE_MAX_SET), + .chan = chan, + .framerate = framerate, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_ae_frame_rate_min_set(struct apple_isp *isp, u32 chan, + u32 framerate) +{ + struct cmd_ch_ae_frame_rate_min_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_AE_FRAME_RATE_MIN_SET), + .chan = chan, + .framerate = framerate, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_ae_fd_scene_metering_config_set(struct apple_isp *isp, + u32 chan) +{ + struct cmd_apple_ch_ae_fd_scene_metering_config_set args = { + .opcode = CISP_OPCODE( + CISP_CMD_APPLE_CH_AE_FD_SCENE_METERING_CONFIG_SET), + .chan = chan, + .unk_c = 0xb8, + .unk_10 = 0x2000200, + .unk_14 = 0x280800, + .unk_18 = 0xe10028, + .unk_1c = 0xa0399, + .unk_20 = 0x3cc02cc, + }; + return CISP_SEND_INOUT(isp, args); +} + +int isp_cmd_apple_ch_ae_metering_mode_set(struct apple_isp *isp, u32 chan, + u32 mode) +{ + struct cmd_apple_ch_ae_metering_mode_set args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_AE_METERING_MODE_SET), + .chan = chan, + .mode = mode, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_ae_flicker_freq_update_current_set(struct apple_isp *isp, + u32 chan, u32 freq) +{ + struct cmd_apple_ch_ae_flicker_freq_update_current_set args = { + .opcode = CISP_OPCODE( + CISP_CMD_APPLE_CH_AE_FLICKER_FREQ_UPDATE_CURRENT_SET), + .chan = chan, + .freq = freq, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_semantic_video_enable(struct apple_isp *isp, u32 chan, + u32 enable) +{ + struct cmd_ch_semantic_video_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SEMANTIC_VIDEO_ENABLE), + .chan = chan, + .enable = enable, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_semantic_awb_enable(struct apple_isp *isp, u32 chan, u32 enable) +{ + struct cmd_ch_semantic_awb_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SEMANTIC_AWB_ENABLE), + .chan = chan, + .enable = enable, + }; + return CISP_SEND_IN(isp, args); +} diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h new file mode 100644 index 00000000000000..dde6aad506c23e --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -0,0 +1,532 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_CMD_H__ +#define __ISP_CMD_H__ + +#include "isp-drv.h" + +#define CISP_CMD_START 0x0000 +#define CISP_CMD_STOP 0x0001 +#define CISP_CMD_CONFIG_GET 0x0003 +#define CISP_CMD_PRINT_ENABLE 0x0004 +#define CISP_CMD_BUILDINFO 0x0006 +#define CISP_CMD_GET_BES_PARAM 0x000f +#define CISP_CMD_SET_ISP_PMU_BASE 0x0011 +#define CISP_CMD_PMP_CTRL_SET 0x001c +#define CISP_CMD_TRACE_ENABLE 0x001d +#define CISP_CMD_SUSPEND 0x0021 +#define CISP_CMD_FID_ENTER 0x0022 +#define CISP_CMD_FID_EXIT 0x0023 +#define CISP_CMD_FLICKER_SENSOR_SET 0x0024 +#define CISP_CMD_CH_START 0x0100 +#define CISP_CMD_CH_STOP 0x0101 +#define CISP_CMD_CH_BUFFER_RETURN 0x0104 +#define CISP_CMD_CH_CAMERA_CONFIG_CURRENT_GET 0x0105 +#define CISP_CMD_CH_CAMERA_CONFIG_GET 0x0106 +#define CISP_CMD_CH_CAMERA_CONFIG_SELECT 0x0107 +#define CISP_CMD_CH_INFO_GET 0x010d +#define CISP_CMD_CH_BUFFER_RECYCLE_MODE_SET 0x010e +#define CISP_CMD_CH_BUFFER_RECYCLE_START 0x010f +#define CISP_CMD_CH_BUFFER_RECYCLE_STOP 0x0110 +#define CISP_CMD_CH_SET_FILE_LOAD 0x0111 +#define CISP_CMD_CH_SIF_PIXEL_FORMAT_SET 0x0115 +#define CISP_CMD_CH_BUFFER_POOL_CONFIG_GET 0x0116 +#define CISP_CMD_CH_BUFFER_POOL_CONFIG_SET 0x0117 +#define CISP_CMD_CH_CAMERA_MIPI_FREQUENCY_GET 0x011a +#define CISP_CMD_CH_CAMERA_PIX_FREQUENCY_GET 0x011f +#define CISP_CMD_CH_LOCAL_RAW_BUFFER_ENABLE 0x0125 +#define CISP_CMD_CH_CAMERA_MIPI_FREQUENCY_TOTAL_GET 0x0133 +#define CISP_CMD_CH_SBS_ENABLE 0x013b +#define CISP_CMD_CH_LSC_POLYNOMIAL_COEFF_GET 0x0142 +#define CISP_CMD_CH_BUFFER_POOL_RETURN 0x015b +#define CISP_CMD_CH_CAMERA_AGILE_FREQ_ARRAY_CURRENT_GET 0x015e +#define CISP_CMD_CH_AE_START 0x0200 +#define CISP_CMD_CH_AE_STOP 0x0201 +#define CISP_CMD_CH_AE_FRAME_RATE_MAX_GET 0x0207 +#define CISP_CMD_CH_AE_FRAME_RATE_MAX_SET 0x0208 +#define CISP_CMD_CH_AE_FRAME_RATE_MIN_GET 0x0209 +#define CISP_CMD_CH_AE_FRAME_RATE_MIN_SET 0x020a +#define CISP_CMD_CH_AE_STABILITY_SET 0x021a +#define CISP_CMD_CH_AE_STABILITY_TO_STABLE_SET 0x0229 +#define CISP_CMD_CH_SENSOR_NVM_GET 0x0501 +#define CISP_CMD_CH_SENSOR_PERMODULE_LSC_INFO_GET 0x0507 +#define CISP_CMD_CH_SENSOR_PERMODULE_LSC_GRID_GET 0x0511 +#define CISP_CMD_CH_FOCUS_LIMITS_GET 0x0701 +#define CISP_CMD_CH_CROP_SET 0x0801 +#define CISP_CMD_CH_ALS_ENABLE 0x0a1c +#define CISP_CMD_CH_ALS_DISABLE 0x0a1d +#define CISP_CMD_CH_CNR_START 0x0a2f +#define CISP_CMD_CH_MBNR_ENABLE 0x0a3a +#define CISP_CMD_CH_OUTPUT_CONFIG_SET 0x0b01 +#define CISP_CMD_CH_PREVIEW_STREAM_SET 0x0b0d +#define CISP_CMD_CH_SEMANTIC_VIDEO_ENABLE 0x0b17 +#define CISP_CMD_CH_SEMANTIC_AWB_ENABLE 0x0b18 +#define CISP_CMD_CH_FACE_DETECTION_START 0x0d00 +#define CISP_CMD_CH_FACE_DETECTION_CONFIG_GET 0x0d02 +#define CISP_CMD_CH_FACE_DETECTION_CONFIG_SET 0x0d03 +#define CISP_CMD_CH_FACE_DETECTION_ENABLE 0x0d05 +#define CISP_CMD_CH_FID_START 0x3000 +#define CISP_CMD_CH_FID_STOP 0x3001 +#define CISP_CMD_IPC_ENDPOINT_SET2 0x300c +#define CISP_CMD_IPC_ENDPOINT_UNSET2 0x300d +#define CISP_CMD_SET_DSID_CLR_REG_BASE2 0x3204 +#define CISP_CMD_APPLE_CH_AE_METERING_MODE_SET 0x8206 +#define CISP_CMD_APPLE_CH_AE_FD_SCENE_METERING_CONFIG_SET 0x820e +#define CISP_CMD_APPLE_CH_AE_FLICKER_FREQ_UPDATE_CURRENT_SET 0x8212 +#define CISP_CMD_APPLE_CH_TEMPORAL_FILTER_START 0xc100 +#define CISP_CMD_APPLE_CH_TEMPORAL_FILTER_STOP 0xc101 +#define CISP_CMD_APPLE_CH_MOTION_HISTORY_START 0xc102 +#define CISP_CMD_APPLE_CH_MOTION_HISTORY_STOP 0xc103 +#define CISP_CMD_APPLE_CH_TEMPORAL_FILTER_ENABLE 0xc113 +#define CISP_CMD_APPLE_CH_TEMPORAL_FILTER_DISABLE 0xc114 + +#define CISP_POOL_TYPE_META 0x0 +#define CISP_POOL_TYPE_RENDERED 0x1 +#define CISP_POOL_TYPE_FD 0x2 +#define CISP_POOL_TYPE_RAW 0x3 +#define CISP_POOL_TYPE_STAT 0x4 +#define CISP_POOL_TYPE_META_CAPTURE 0x8 + +#define CISP_COLORSPACE_REC709 0x1 +#define CISP_OUTPUT_FORMAT_NV12 0x0 +#define CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY 0x1 + +struct cmd_start { + u64 opcode; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_start) == 0xc); + +struct cmd_suspend { + u64 opcode; +} __packed; +static_assert(sizeof(struct cmd_suspend) == 0x8); + +struct cmd_print_enable { + u64 opcode; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_print_enable) == 0xc); + +struct cmd_trace_enable { + u64 opcode; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_trace_enable) == 0xc); + +struct cmd_config_get { + u64 opcode; + u32 timestamp_freq; + u32 num_channels; + u32 unk_10; + u32 unk_14; + u32 unk_18; +} __packed; +static_assert(sizeof(struct cmd_config_get) == 0x1c); + +struct cmd_set_isp_pmu_base { + u64 opcode; + u64 pmu_base; +} __packed; +static_assert(sizeof(struct cmd_set_isp_pmu_base) == 0x10); + +struct cmd_set_dsid_clr_req_base2 { + u64 opcode; + u64 dsid_clr_base0; + u64 dsid_clr_base1; + u64 dsid_clr_base2; + u64 dsid_clr_base3; + u32 dsid_clr_range0; + u32 dsid_clr_range1; + u32 dsid_clr_range2; + u32 dsid_clr_range3; +} __packed; +static_assert(sizeof(struct cmd_set_dsid_clr_req_base2) == 0x38); + +struct cmd_pmp_ctrl_set { + u64 opcode; + u64 clock_scratch; + u64 clock_base; + u8 clock_bit; + u8 clock_size; + u16 clock_pad; + u64 bandwidth_scratch; + u64 bandwidth_base; + u8 bandwidth_bit; + u8 bandwidth_size; + u16 bandwidth_pad; +} __packed; +static_assert(sizeof(struct cmd_pmp_ctrl_set) == 0x30); + +struct cmd_fid_enter { + u64 opcode; +} __packed; +static_assert(sizeof(struct cmd_fid_enter) == 0x8); + +struct cmd_fid_exit { + u64 opcode; +} __packed; +static_assert(sizeof(struct cmd_fid_exit) == 0x8); + +int isp_cmd_start(struct apple_isp *isp, u32 mode); +int isp_cmd_suspend(struct apple_isp *isp); +int isp_cmd_print_enable(struct apple_isp *isp, u32 enable); +int isp_cmd_trace_enable(struct apple_isp *isp, u32 enable); +int isp_cmd_config_get(struct apple_isp *isp, struct cmd_config_get *args); +int isp_cmd_set_isp_pmu_base(struct apple_isp *isp, u64 pmu_base); +int isp_cmd_set_dsid_clr_req_base2(struct apple_isp *isp, u64 dsid_clr_base0, + u64 dsid_clr_base1, u64 dsid_clr_base2, + u64 dsid_clr_base3, u32 dsid_clr_range0, + u32 dsid_clr_range1, u32 dsid_clr_range2, + u32 dsid_clr_range3); +int isp_cmd_pmp_ctrl_set(struct apple_isp *isp, u64 clock_scratch, + u64 clock_base, u8 clock_bit, u8 clock_size, + u64 bandwidth_scratch, u64 bandwidth_base, + u8 bandwidth_bit, u8 bandwidth_size); +int isp_cmd_fid_enter(struct apple_isp *isp); +int isp_cmd_fid_exit(struct apple_isp *isp); + +struct cmd_ch_start { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_start) == 0xc); + +struct cmd_ch_stop { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_stop) == 0xc); + +struct cmd_ch_info { + u64 opcode; + u32 chan; + u32 unk_c; + u32 unk_10[4]; + u32 version; + u32 unk_24[3]; + u32 unk_30[12]; + u32 num_presets; + u32 unk_64[7]; + u32 unk_80[6]; + u32 unk_98_freq; + u16 pad_9c; + char module_sn[20]; + u16 pad_b0; + u32 unk_b4[25]; +} __packed; +static_assert(sizeof(struct cmd_ch_info) == 0x118); + +struct cmd_ch_camera_config { + u64 opcode; + u32 chan; + u32 preset; + u16 in_width; + u16 in_height; + u16 out_width; + u16 out_height; + u32 unk[49]; +} __packed; +static_assert(sizeof(struct cmd_ch_camera_config) == 0xdc); + +struct cmd_ch_camera_config_select { + u64 opcode; + u32 chan; + u32 preset; +} __packed; +static_assert(sizeof(struct cmd_ch_camera_config_select) == 0x10); + +struct cmd_ch_set_file_load { + u64 opcode; + u32 chan; + u32 addr; + u32 size; +} __packed; +static_assert(sizeof(struct cmd_ch_set_file_load) == 0x14); + +struct cmd_ch_buffer_return { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_return) == 0xc); + +struct cmd_ch_sbs_enable { + u64 opcode; + u32 chan; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_ch_sbs_enable) == 0x10); + +struct cmd_ch_crop_set { + u64 opcode; + u32 chan; + u32 x1; + u32 y1; + u32 x2; + u32 y2; +} __packed; +static_assert(sizeof(struct cmd_ch_crop_set) == 0x1c); + +struct cmd_ch_output_config_set { + u64 opcode; + u32 chan; + u32 width; + u32 height; + u32 colorspace; + u32 format; + u32 unk_w0; + u32 unk_w1; + u32 unk_24; + u32 padding_rows; + u32 unk_h0; + u32 compress; + u32 unk_w2; +} __packed; +static_assert(sizeof(struct cmd_ch_output_config_set) == 0x38); + +struct cmd_ch_preview_stream_set { + u64 opcode; + u32 chan; + u32 stream; +} __packed; +static_assert(sizeof(struct cmd_ch_preview_stream_set) == 0x10); + +struct cmd_ch_als_disable { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_als_disable) == 0xc); + +struct cmd_ch_cnr_start { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_cnr_start) == 0xc); + +struct cmd_ch_mbnr_enable { + u64 opcode; + u32 chan; + u32 use_case; + u32 mode; + u32 enable_chroma; +} __packed; +static_assert(sizeof(struct cmd_ch_mbnr_enable) == 0x18); + +struct cmd_ch_sif_pixel_format_set { + u64 opcode; + u32 chan; + u8 format; + u8 type; + u16 compress; + u32 unk_10; +} __packed; +static_assert(sizeof(struct cmd_ch_sif_pixel_format_set) == 0x14); + +int isp_cmd_ch_start(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_stop(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_info_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_info *args); +int isp_cmd_ch_camera_config_get(struct apple_isp *isp, u32 chan, u32 preset, + struct cmd_ch_camera_config *args); +int isp_cmd_ch_camera_config_current_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_camera_config *args); +int isp_cmd_ch_camera_config_select(struct apple_isp *isp, u32 chan, + u32 preset); +int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u32 addr, + u32 size); +int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_sbs_enable(struct apple_isp *isp, u32 chan, u32 enable); +int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, + u32 y2); +int isp_cmd_ch_output_config_set(struct apple_isp *isp, u32 chan, u32 width, + u32 height, u32 colorspace, u32 format); +int isp_cmd_ch_preview_stream_set(struct apple_isp *isp, u32 chan, u32 stream); +int isp_cmd_ch_als_disable(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_cnr_start(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_mbnr_enable(struct apple_isp *isp, u32 chan, u32 use_case, + u32 mode, u32 enable_chroma); +int isp_cmd_ch_sif_pixel_format_set(struct apple_isp *isp, u32 chan); + +struct cmd_ch_buffer_recycle_mode_set { + u64 opcode; + u32 chan; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_recycle_mode_set) == 0x10); + +struct cmd_ch_buffer_recycle_start { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_recycle_start) == 0xc); + +struct cmd_ch_buffer_pool_config_set { + u64 opcode; + u32 chan; + u16 type; + u16 count; + u32 meta_size0; + u32 meta_size1; + u32 zero[0x1f]; + u32 data_blocks; + u32 compress; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_pool_config_set) == 0x9c); + +struct cmd_ch_buffer_pool_return { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_pool_return) == 0xc); + +int isp_cmd_ch_buffer_recycle_mode_set(struct apple_isp *isp, u32 chan, + u32 mode); +int isp_cmd_ch_buffer_recycle_start(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, + u16 type); +int isp_cmd_ch_buffer_pool_return(struct apple_isp *isp, u32 chan); + +struct cmd_apple_ch_temporal_filter_start { + u64 opcode; + u32 chan; + u32 unk_c; + u32 unk_10; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_temporal_filter_start) == 0x14); + +struct cmd_apple_ch_temporal_filter_stop { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_temporal_filter_stop) == 0xc); + +struct cmd_apple_ch_motion_history_start { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_motion_history_start) == 0xc); + +struct cmd_apple_ch_motion_history_stop { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_motion_history_stop) == 0xc); + +struct cmd_apple_ch_temporal_filter_enable { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_temporal_filter_enable) == 0xc); + +struct cmd_apple_ch_temporal_filter_disable { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_temporal_filter_disable) == 0xc); + +int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_temporal_filter_stop(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_motion_history_start(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_motion_history_stop(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_temporal_filter_enable(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_temporal_filter_disable(struct apple_isp *isp, u32 chan); + +struct cmd_ch_ae_stability_set { + u64 opcode; + u32 chan; + u32 stability; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_stability_set) == 0x10); + +struct cmd_ch_ae_stability_to_stable_set { + u64 opcode; + u32 chan; + u32 stability; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_stability_to_stable_set) == 0x10); + +struct cmd_ch_ae_frame_rate_max_get { + u64 opcode; + u32 chan; + u32 framerate; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_frame_rate_max_get) == 0x10); + +struct cmd_ch_ae_frame_rate_max_set { + u64 opcode; + u32 chan; + u32 framerate; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_frame_rate_max_set) == 0x10); + +struct cmd_ch_ae_frame_rate_min_set { + u64 opcode; + u32 chan; + u32 framerate; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_frame_rate_min_set) == 0x10); + +struct cmd_apple_ch_ae_fd_scene_metering_config_set { + u64 opcode; + u32 chan; + u32 unk_c; + u32 unk_10; + u32 unk_14; + u32 unk_18; + u32 unk_1c; + u32 unk_20; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_ae_fd_scene_metering_config_set) == + 0x24); + +struct cmd_apple_ch_ae_metering_mode_set { + u64 opcode; + u32 chan; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_ae_metering_mode_set) == 0x10); + +struct cmd_apple_ch_ae_flicker_freq_update_current_set { + u64 opcode; + u32 chan; + u32 freq; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_ae_flicker_freq_update_current_set) == + 0x10); + +int isp_cmd_ch_ae_stability_set(struct apple_isp *isp, u32 chan, u32 stability); +int isp_cmd_ch_ae_stability_to_stable_set(struct apple_isp *isp, u32 chan, + u32 stability); +int isp_cmd_ch_ae_frame_rate_max_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_ae_frame_rate_max_get *args); +int isp_cmd_ch_ae_frame_rate_max_set(struct apple_isp *isp, u32 chan, + u32 framerate); +int isp_cmd_ch_ae_frame_rate_min_set(struct apple_isp *isp, u32 chan, + u32 framerate); +int isp_cmd_apple_ch_ae_fd_scene_metering_config_set(struct apple_isp *isp, + u32 chan); +int isp_cmd_apple_ch_ae_metering_mode_set(struct apple_isp *isp, u32 chan, + u32 mode); +int isp_cmd_apple_ch_ae_flicker_freq_update_current_set(struct apple_isp *isp, + u32 chan, u32 freq); + +struct cmd_ch_semantic_video_enable { + u64 opcode; + u32 chan; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_ch_semantic_video_enable) == 0x10); + +struct cmd_ch_semantic_awb_enable { + u64 opcode; + u32 chan; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_ch_semantic_awb_enable) == 0x10); + +int isp_cmd_ch_semantic_video_enable(struct apple_isp *isp, u32 chan, + u32 enable); +int isp_cmd_ch_semantic_awb_enable(struct apple_isp *isp, u32 chan, u32 enable); + +#endif /* __ISP_CMD_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c new file mode 100644 index 00000000000000..e8e32ba73ad962 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Apple Image Signal Processor driver + * + * Copyright (C) 2023 The Asahi Linux Contributors + * + * Based on aspeed/aspeed-video.c + * Copyright 2020 IBM Corp. + * Copyright (c) 2019-2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "isp-cam.h" +#include "isp-iommu.h" +#include "isp-v4l2.h" + +static void apple_isp_detach_genpd(struct apple_isp *isp) +{ + if (isp->pd_count <= 1) + return; + + for (int i = isp->pd_count - 1; i >= 0; i--) { + if (isp->pd_link[i]) + device_link_del(isp->pd_link[i]); + if (!IS_ERR_OR_NULL(isp->pd_dev[i])) + dev_pm_domain_detach(isp->pd_dev[i], true); + } + + return; +} + +static int apple_isp_attach_genpd(struct apple_isp *isp) +{ + struct device *dev = isp->dev; + + isp->pd_count = of_count_phandle_with_args( + dev->of_node, "power-domains", "#power-domain-cells"); + if (isp->pd_count <= 1) + return 0; + + isp->pd_dev = devm_kcalloc(dev, isp->pd_count, sizeof(*isp->pd_dev), + GFP_KERNEL); + if (!isp->pd_dev) + return -ENOMEM; + + isp->pd_link = devm_kcalloc(dev, isp->pd_count, sizeof(*isp->pd_link), + GFP_KERNEL); + if (!isp->pd_link) + return -ENOMEM; + + for (int i = 0; i < isp->pd_count; i++) { + isp->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); + if (IS_ERR(isp->pd_dev[i])) { + apple_isp_detach_genpd(isp); + return PTR_ERR(isp->pd_dev[i]); + } + + isp->pd_link[i] = + device_link_add(dev, isp->pd_dev[i], + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!isp->pd_link[i]) { + apple_isp_detach_genpd(isp); + return -EINVAL; + } + } + + return 0; +} + +static int apple_isp_init_iommu(struct apple_isp *isp) +{ + struct device *dev = isp->dev; + struct isp_firmware *fw = &isp->fw; + u64 heap_base, heap_size, vm_size; + int err; + int i = 0; + + isp->domain = iommu_get_domain_for_dev(isp->dev); + if (!isp->domain) + return -EPROBE_DEFER; + isp->shift = __ffs(isp->domain->pgsize_bitmap); + + err = of_property_read_u64(dev->of_node, "apple,isp-heap-base", + &heap_base); + if (err) { + dev_err(dev, "failed to read 'apple,isp-heap-base': %d\n", err); + return err; + } + + err = of_property_read_u64(dev->of_node, "apple,isp-heap-size", + &heap_size); + if (err) { + dev_err(dev, "failed to read 'apple,isp-heap-size': %d\n", err); + return err; + } + + err = of_property_read_u64(dev->of_node, "apple,dart-vm-size", + &vm_size); + if (err) { + dev_err(dev, "failed to read 'apple,dart-vm-size': %d\n", err); + return err; + } + + drm_mm_init(&isp->iovad, heap_base, vm_size - heap_base); + + /* Allocate read-only coprocessor private heap */ + fw->heap = isp_alloc_surface(isp, heap_size); + if (!fw->heap) { + drm_mm_takedown(&isp->iovad); + err = -ENOMEM; + return err; + } + + apple_isp_iommu_sync_ttbr(isp); + + return 0; +} + +static void apple_isp_free_iommu(struct apple_isp *isp) +{ + isp_free_surface(isp, isp->fw.heap); + drm_mm_takedown(&isp->iovad); +} + +static int apple_isp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apple_isp *isp; + struct resource *res; + int err; + + isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); + if (!isp) + return -ENOMEM; + + isp->dev = dev; + isp->hw = of_device_get_match_data(dev); + platform_set_drvdata(pdev, isp); + dev_set_drvdata(dev, isp); + + err = apple_isp_attach_genpd(isp); + if (err) { + dev_err(dev, "failed to attatch power domains\n"); + return err; + } + + isp->asc = devm_platform_ioremap_resource_byname(pdev, "asc"); + if (IS_ERR(isp->asc)) { + err = PTR_ERR(isp->asc); + goto detach_genpd; + } + + isp->core = devm_platform_ioremap_resource_byname(pdev, "core"); + if (IS_ERR(isp->core)) { + err = PTR_ERR(isp->core); + goto detach_genpd; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dart0"); + if (!res) { + err = -ENODEV; + goto detach_genpd; + } + + /* Simply ioremap since it's a shared register zone */ + isp->dart0 = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(isp->dart0)) { + err = PTR_ERR(isp->dart0); + goto detach_genpd; + } + + isp->dart1 = devm_platform_ioremap_resource_byname(pdev, "dart1"); + if (IS_ERR(isp->dart1)) { + err = PTR_ERR(isp->dart1); + goto detach_genpd; + } + + isp->dart2 = devm_platform_ioremap_resource_byname(pdev, "dart2"); + if (IS_ERR(isp->dart2)) { + err = PTR_ERR(isp->dart2); + goto detach_genpd; + } + + isp->irq = platform_get_irq(pdev, 0); + if (isp->irq < 0) { + err = isp->irq; + goto detach_genpd; + } + if (!isp->irq) { + err = -ENODEV; + goto detach_genpd; + } + + mutex_init(&isp->iovad_lock); + mutex_init(&isp->video_lock); + spin_lock_init(&isp->buf_lock); + init_waitqueue_head(&isp->wait); + INIT_LIST_HEAD(&isp->gc); + INIT_LIST_HEAD(&isp->buffers); + isp->wq = alloc_workqueue("apple-isp-wq", WQ_UNBOUND, 0); + if (!isp->wq) { + dev_err(dev, "failed to create workqueue\n"); + err = -ENOMEM; + goto detach_genpd; + } + + err = apple_isp_init_iommu(isp); + if (err) { + dev_err(dev, "failed to init iommu: %d\n", err); + goto destroy_wq; + } + + pm_runtime_enable(dev); + + err = apple_isp_detect_camera(isp); + if (err) { + dev_err(dev, "failed to detect camera: %d\n", err); + goto free_iommu; + } + + err = apple_isp_setup_video(isp); + if (err) { + dev_err(dev, "failed to register video device: %d\n", err); + goto free_iommu; + } + + dev_info(dev, "apple-isp probe!\n"); + + return 0; + +free_iommu: + pm_runtime_disable(dev); + apple_isp_free_iommu(isp); +destroy_wq: + destroy_workqueue(isp->wq); +detach_genpd: + apple_isp_detach_genpd(isp); + return err; +} + +static void apple_isp_remove(struct platform_device *pdev) +{ + struct apple_isp *isp = platform_get_drvdata(pdev); + + apple_isp_remove_video(isp); + pm_runtime_disable(isp->dev); + apple_isp_free_iommu(isp); + destroy_workqueue(isp->wq); + apple_isp_detach_genpd(isp); + return 0; +} + +/* T8020/T6000 registers */ +#define DART_T8020_STREAM_COMMAND 0x20 +#define DART_T8020_STREAM_SELECT 0x34 +#define DART_T8020_TTBR 0x200 +#define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20) + +static const struct apple_isp_hw apple_isp_hw_t8103 = { + .pmu_base = 0x23b704000, + + .dsid_clr_base0 = 0x200014000, + .dsid_clr_base1 = 0x200054000, + .dsid_clr_base2 = 0x200094000, + .dsid_clr_base3 = 0x2000d4000, + .dsid_clr_range0 = 0x1000, + .dsid_clr_range1 = 0x1000, + .dsid_clr_range2 = 0x1000, + .dsid_clr_range3 = 0x1000, + + .clock_scratch = 0x23b738010, + .clock_base = 0x23bc3c000, + .clock_bit = 0x1, + .clock_size = 0x4, + .bandwidth_scratch = 0x23b73800c, + .bandwidth_base = 0x23bc3c000, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x4, + + .stream_command = DART_T8020_STREAM_COMMAND, + .stream_select = DART_T8020_STREAM_SELECT, + .ttbr = DART_T8020_TTBR, + .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, +}; + +static const struct of_device_id apple_isp_of_match[] = { + { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, + {}, +}; +MODULE_DEVICE_TABLE(of, apple_isp_of_match); + +static __maybe_unused int apple_isp_suspend(struct device *dev) +{ + struct apple_isp *isp = dev_get_drvdata(dev); + + apple_isp_iommu_invalidate_tlb(isp); + + return 0; +} + +static __maybe_unused int apple_isp_resume(struct device *dev) +{ + struct apple_isp *isp = dev_get_drvdata(dev); + + apple_isp_iommu_sync_ttbr(isp); + + return 0; +} +DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, NULL); + +static struct platform_driver apple_isp_driver = { + .driver = { + .name = "apple-isp", + .of_match_table = apple_isp_of_match, + .pm = pm_ptr(&apple_isp_pm_ops), + }, + .probe = apple_isp_probe, + .remove = apple_isp_remove, +}; +module_platform_driver(apple_isp_driver); + +MODULE_AUTHOR("Eileen Yoon "); +MODULE_DESCRIPTION("Apple ISP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h new file mode 100644 index 00000000000000..5db64dcc844863 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_DRV_H__ +#define __ISP_DRV_H__ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* #define APPLE_ISP_DEBUG */ +#define APPLE_ISP_DEVICE_NAME "apple-isp" + +#define ISP_MAX_CHANNELS 6 +#define ISP_IPC_MESSAGE_SIZE 64 +#define ISP_IPC_FLAG_ACK 0x1 +#define ISP_META_SIZE 0x4640 + +struct isp_surf { + struct drm_mm_node *mm; + struct list_head head; + u64 size; + u32 num_pages; + struct page **pages; + struct sg_table sgt; + dma_addr_t iova; + void *virt; + refcount_t refcount; + bool gc; +}; + +struct isp_message { + u64 arg0; + u64 arg1; + u64 arg2; + u64 arg3; + u64 arg4; + u64 arg5; + u64 arg6; + u64 arg7; +} __packed; +static_assert(sizeof(struct isp_message) == ISP_IPC_MESSAGE_SIZE); + +struct isp_channel { + char *name; + u32 type; + u32 src; + u32 num; + u64 size; + dma_addr_t iova; + u32 doorbell; + u32 cursor; + spinlock_t lock; + struct isp_message req; + struct isp_message rsp; + const struct isp_chan_ops *ops; +}; + +struct apple_isp_hw { + u64 pmu_base; + + u64 dsid_clr_base0; + u64 dsid_clr_base1; + u64 dsid_clr_base2; + u64 dsid_clr_base3; + u32 dsid_clr_range0; + u32 dsid_clr_range1; + u32 dsid_clr_range2; + u32 dsid_clr_range3; + + u64 clock_scratch; + u64 clock_base; + u8 clock_bit; + u8 clock_size; + u64 bandwidth_scratch; + u64 bandwidth_base; + u8 bandwidth_bit; + u8 bandwidth_size; + + u32 stream_command; + u32 stream_select; + u32 ttbr; + u32 stream_command_invalidate; +}; + +struct isp_resv { + phys_addr_t phys; + dma_addr_t iova; + u64 size; +}; + +enum isp_sensor_id { + ISP_IMX248_1820_01, + ISP_IMX248_1822_02, + ISP_IMX343_5221_02, + ISP_IMX354_9251_02, + ISP_IMX356_4820_01, + ISP_IMX356_4820_02, + ISP_IMX364_8720_01, + ISP_IMX364_8723_01, + ISP_IMX372_3820_01, + ISP_IMX372_3820_02, + ISP_IMX372_3820_11, + ISP_IMX372_3820_12, + ISP_IMX405_9720_01, + ISP_IMX405_9721_01, + ISP_IMX405_9723_01, + ISP_IMX414_2520_01, + ISP_IMX503_7820_01, + ISP_IMX503_7820_02, + ISP_IMX505_3921_01, + ISP_IMX514_2820_01, + ISP_IMX514_2820_02, + ISP_IMX514_2820_03, + ISP_IMX514_2820_04, + ISP_IMX558_1921_01, + ISP_IMX558_1922_02, + ISP_IMX603_7920_01, + ISP_IMX603_7920_02, + ISP_IMX603_7921_01, + ISP_IMX613_4920_01, + ISP_IMX613_4920_02, + ISP_IMX614_2921_01, + ISP_IMX614_2921_02, + ISP_IMX614_2922_02, + ISP_IMX633_3622_01, + ISP_IMX703_7721_01, + ISP_IMX703_7722_01, + ISP_IMX713_4721_01, + ISP_IMX713_4722_01, + ISP_IMX714_2022_01, + ISP_IMX772_3721_01, + ISP_IMX772_3721_11, + ISP_IMX772_3722_01, + ISP_IMX772_3723_01, + ISP_IMX814_2123_01, + ISP_IMX853_7622_01, + ISP_IMX913_7523_01, + ISP_VD56G0_6221_01, + ISP_VD56G0_6222_01, +}; + +struct isp_format { + enum isp_sensor_id id; + u32 version; + u32 num_presets; + u32 preset; + u32 width; + u32 height; + u32 x1; + u32 y1; + u32 x2; + u32 y2; + unsigned int num_planes; + size_t plane_size[VB2_MAX_PLANES]; + size_t total_size; +}; + +struct apple_isp { + struct device *dev; + const struct apple_isp_hw *hw; + + int num_channels; + struct isp_format fmts[ISP_MAX_CHANNELS]; + unsigned int current_ch; + + struct video_device vdev; + struct media_device mdev; + struct v4l2_device v4l2_dev; + struct vb2_queue vbq; + struct mutex video_lock; + unsigned int sequence; + bool multiplanar; + + int pd_count; + struct device **pd_dev; + struct device_link **pd_link; + + int irq; + + void __iomem *asc; + void __iomem *core; + void __iomem *dart0; + void __iomem *dart1; + void __iomem *dart2; + + struct iommu_domain *domain; + unsigned long shift; + struct drm_mm iovad; /* TODO iova.c can't allocate bottom-up */ + struct mutex iovad_lock; + + struct isp_firmware { + struct isp_surf *heap; + } fw; + + struct isp_surf *ipc_surf; + struct isp_surf *extra_surf; + struct isp_surf *data_surf; + struct list_head gc; + struct workqueue_struct *wq; + + int num_ipc_chans; + struct isp_channel **ipc_chans; + struct isp_channel *chan_tm; /* TERMINAL */ + struct isp_channel *chan_io; /* IO */ + struct isp_channel *chan_dg; /* DEBUG */ + struct isp_channel *chan_bh; /* BUF_H2T */ + struct isp_channel *chan_bt; /* BUF_T2H */ + struct isp_channel *chan_sm; /* SHAREDMALLOC */ + struct isp_channel *chan_it; /* IO_T2H */ + + wait_queue_head_t wait; + dma_addr_t cmd_iova; + + unsigned long state; + spinlock_t buf_lock; + struct list_head buffers; +}; + +struct isp_chan_ops { + int (*handle)(struct apple_isp *isp, struct isp_channel *chan); +}; + +struct isp_buffer { + struct vb2_v4l2_buffer vb; + struct list_head link; + struct isp_surf surfs[VB2_MAX_PLANES]; + struct isp_surf *meta; +}; + +#define to_isp_buffer(x) container_of((x), struct isp_buffer, vb) + +enum { + ISP_STATE_STREAMING, + ISP_STATE_LOGGING, +}; + +#ifdef APPLE_ISP_DEBUG +#define isp_dbg(isp, fmt, ...) \ + dev_info((isp)->dev, "[%s] " fmt, __func__, ##__VA_ARGS__) +#else +#define isp_dbg(isp, fmt, ...) \ + dev_dbg((isp)->dev, "[%s] " fmt, __func__, ##__VA_ARGS__) +#endif + +#define isp_err(isp, fmt, ...) \ + dev_err((isp)->dev, "[%s] " fmt, __func__, ##__VA_ARGS__) + +#define isp_get_format(isp, ch) (&(isp)->fmts[(ch)]) +#define isp_get_current_format(isp) (isp_get_format(isp, isp->current_ch)) + +#endif /* __ISP_DRV_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c new file mode 100644 index 00000000000000..12b9c0694d68e8 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include +#include +#include + +#include "isp-cmd.h" +#include "isp-iommu.h" +#include "isp-ipc.h" +#include "isp-regs.h" + +#define ISP_FIRMWARE_MDELAY 1 +#define ISP_FIRMWARE_MAX_TRIES 1000 + +#define ISP_FIRMWARE_BOOTARGS_SIZE 0x180 +#define ISP_FIRMWARE_IPC_SIZE 0x1c000 +#define ISP_FIRMWARE_DATA_SIZE 0x28000 + +static inline u32 isp_asc_read32(struct apple_isp *isp, u32 reg) +{ + return readl(isp->asc + reg); +} + +static inline void isp_asc_write32(struct apple_isp *isp, u32 reg, u32 val) +{ + writel(val, isp->asc + reg); +} + +struct isp_firmware_bootargs { + u32 pad_0[2]; + u64 ipc_iova; + u64 unk_size; + u64 unk_inv; + u64 extra_iova; + u64 extra_size; + u32 unk4; + u32 pad_40[7]; + u32 ipc_size; + u32 pad_60[5]; + u32 unk5; + u32 pad_7c[13]; + u32 pad_b0; + u32 unk7; + u32 pad_b8[5]; + u32 unk_iova1; + u32 pad_c0[47]; + u32 unk9; +} __packed; +static_assert(sizeof(struct isp_firmware_bootargs) == + ISP_FIRMWARE_BOOTARGS_SIZE); + +struct isp_chan_desc { + char name[64]; + u32 type; + u32 src; + u32 num; + u32 pad; + u64 iova; + u32 padding[0x2a]; +} __packed; +static_assert(sizeof(struct isp_chan_desc) == 0x100); + +static const struct isp_chan_ops tm_ops = { + .handle = ipc_tm_handle, +}; + +static const struct isp_chan_ops sm_ops = { + .handle = ipc_sm_handle, +}; + +static const struct isp_chan_ops bt_ops = { + .handle = ipc_bt_handle, +}; + +static irqreturn_t apple_isp_isr(int irq, void *dev) +{ + struct apple_isp *isp = dev; + + isp_core_write32(isp, ISP_CORE_IRQ_ACK, + isp_core_read32(isp, ISP_CORE_IRQ_INTERRUPT)); + + wake_up_interruptible_all(&isp->wait); + + ipc_chan_handle(isp, isp->chan_sm); + wake_up_interruptible_all(&isp->wait); /* Some commands depend on sm */ + + ipc_chan_handle(isp, isp->chan_tm); + + ipc_chan_handle(isp, isp->chan_bt); + wake_up_interruptible_all(&isp->wait); + + return IRQ_HANDLED; +} + +static void isp_disable_irq(struct apple_isp *isp) +{ + isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0x0); + free_irq(isp->irq, isp); + isp_core_write32(isp, ISP_CORE_GPIO_1, 0xfeedbabe); /* real funny */ +} + +static int isp_enable_irq(struct apple_isp *isp) +{ + int err; + + err = request_irq(isp->irq, apple_isp_isr, 0, "apple-isp", isp); + if (err < 0) { + isp_err(isp, "failed to request IRQ#%u (%d)\n", isp->irq, err); + return err; + } + + isp_dbg(isp, "about to enable interrupts...\n"); + + isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0xf); + + return 0; +} + +static int isp_coproc_ready(struct apple_isp *isp) +{ + int retries; + u32 status; + + isp_asc_write32(isp, ISP_ASC_EDPRCR, 0x2); + + isp_asc_write32(isp, ISP_ASC_PMGR_0, 0xff00ff); + isp_asc_write32(isp, ISP_ASC_PMGR_1, 0xff00ff); + isp_asc_write32(isp, ISP_ASC_PMGR_2, 0xff00ff); + isp_asc_write32(isp, ISP_ASC_PMGR_3, 0xff00ff); + + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_0, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_1, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_2, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_3, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_4, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_5, 0xffffffff); + + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + status = isp_asc_read32(isp, ISP_ASC_STATUS); + if (!((status & 0x3) == 0)) { + isp_dbg(isp, "%d: coproc in WFI (status: 0x%x)\n", + retries, status); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, "coproc NOT in WFI (status: 0x%x)\n", status); + return -ENODEV; + } + + return 0; +} + +static void isp_firmware_shutdown_stage1(struct apple_isp *isp) +{ + isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); +} + +static int isp_firmware_boot_stage1(struct apple_isp *isp) +{ + int err, retries; + + err = isp_coproc_ready(isp); + if (err < 0) + return err; + + isp_core_write32(isp, ISP_CORE_CLOCK_EN, 0x1); + + isp_core_write32(isp, ISP_CORE_GPIO_0, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_1, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_2, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_3, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_4, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_5, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_6, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_7, 0x0); + + isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0x0); + + isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); + isp_asc_write32(isp, ISP_ASC_CONTROL, 0x10); + + /* Wait for ISP_CORE_GPIO_7 to 0x0 -> 0x8042006 */ + isp_core_write32(isp, ISP_CORE_GPIO_7, 0x0); + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + u32 val = isp_core_read32(isp, ISP_CORE_GPIO_7); + if (val == 0x8042006) { + isp_dbg(isp, + "got first magic number (0x%x) from firmware\n", + val); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, + "never received first magic number from firmware\n"); + return -ENODEV; + } + + return 0; +} + +static void isp_firmware_shutdown_stage2(struct apple_isp *isp) +{ + isp_free_surface(isp, isp->data_surf); + isp_free_surface(isp, isp->extra_surf); + isp_free_surface(isp, isp->ipc_surf); +} + +static int isp_firmware_boot_stage2(struct apple_isp *isp) +{ + struct isp_firmware_bootargs args; + dma_addr_t args_iova; + int err, retries; + + u32 num_ipc_chans = isp_core_read32(isp, ISP_CORE_GPIO_0); + u32 args_offset = isp_core_read32(isp, ISP_CORE_GPIO_1); + u32 extra_size = isp_core_read32(isp, ISP_CORE_GPIO_3); + isp->num_ipc_chans = num_ipc_chans; + + if (!isp->num_ipc_chans) { + dev_err(isp->dev, "No IPC channels found\n"); + return -ENODEV; + } + + if (isp->num_ipc_chans != 7) + dev_warn(isp->dev, "unexpected channel count (%d)\n", + num_ipc_chans); + + isp->ipc_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_IPC_SIZE); + if (!isp->ipc_surf) { + isp_err(isp, "failed to alloc surface for ipc\n"); + return -ENOMEM; + } + + isp->extra_surf = isp_alloc_surface_vmap(isp, extra_size); + if (!isp->extra_surf) { + isp_err(isp, "failed to alloc surface for extra heap\n"); + goto free_ipc; + } + + isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE); + if (!isp->data_surf) { + isp_err(isp, "failed to alloc surface for data files\n"); + goto free_extra; + } + + args_iova = isp->ipc_surf->iova + args_offset + 0x40; + isp->cmd_iova = args_iova + sizeof(args) + 0x40; + + memset(&args, 0, sizeof(args)); + args.ipc_iova = isp->ipc_surf->iova; + args.ipc_size = isp->ipc_surf->size; + args.unk_size = 0x1800000; + args.unk_inv = 0x10000000 - args.unk_size; + args.extra_iova = isp->extra_surf->iova; + args.extra_size = isp->extra_surf->size; + args.unk4 = 0x1; + args.unk5 = 0x40; + args.unk7 = 0x1; + args.unk_iova1 = args_iova + ISP_FIRMWARE_BOOTARGS_SIZE - 0xc; + args.unk9 = 0x3; + isp_iowrite(isp, args_iova, &args, sizeof(args)); + + isp_core_write32(isp, ISP_CORE_GPIO_0, args_iova); + isp_core_write32(isp, ISP_CORE_GPIO_1, 0x0); + + /* Wait for ISP_CORE_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ + isp_core_write32(isp, ISP_CORE_GPIO_7, 0xf7fbdff9); + + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + u32 val = isp_core_read32(isp, ISP_CORE_GPIO_7); + if (val == 0x8042006) { + isp_dbg(isp, + "got second magic number (0x%x) from firmware\n", + val); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, + "never received second magic number from firmware\n"); + err = -ENODEV; + goto free_file; + } + + return 0; + +free_file: + isp_free_surface(isp, isp->data_surf); +free_extra: + isp_free_surface(isp, isp->extra_surf); +free_ipc: + isp_free_surface(isp, isp->ipc_surf); + return err; +} + +static inline struct isp_channel *isp_get_chan_index(struct apple_isp *isp, + const char *name) +{ + for (int i = 0; i < isp->num_ipc_chans; i++) { + if (!strcasecmp(isp->ipc_chans[i]->name, name)) + return isp->ipc_chans[i]; + } + return NULL; +} + +static void isp_free_channel_info(struct apple_isp *isp) +{ + for (int i = 0; i < isp->num_ipc_chans; i++) { + struct isp_channel *chan = isp->ipc_chans[i]; + if (!chan) + continue; + kfree(chan->name); + kfree(chan); + isp->ipc_chans[i] = NULL; + } + kfree(isp->ipc_chans); + isp->ipc_chans = NULL; +} + +static int isp_fill_channel_info(struct apple_isp *isp) +{ + u32 table_iova = isp_core_read32(isp, ISP_CORE_GPIO_0); + + isp->ipc_chans = kcalloc(isp->num_ipc_chans, + sizeof(struct isp_channel *), GFP_KERNEL); + if (!isp->ipc_chans) + goto out; + + for (int i = 0; i < isp->num_ipc_chans; i++) { + struct isp_chan_desc desc; + dma_addr_t desc_iova = table_iova + (i * sizeof(desc)); + struct isp_channel *chan = + kzalloc(sizeof(struct isp_channel), GFP_KERNEL); + if (!chan) + goto out; + isp->ipc_chans[i] = chan; + + isp_ioread(isp, desc_iova, &desc, sizeof(desc)); + chan->name = kstrdup(desc.name, GFP_KERNEL); + chan->type = desc.type; + chan->src = desc.src; + chan->doorbell = 1 << chan->src; + chan->num = desc.num; + chan->size = desc.num * ISP_IPC_MESSAGE_SIZE; + chan->iova = desc.iova; + chan->cursor = 0; + spin_lock_init(&chan->lock); + + if ((chan->type != ISP_IPC_CHAN_TYPE_COMMAND) && + (chan->type != ISP_IPC_CHAN_TYPE_REPLY) && + (chan->type != ISP_IPC_CHAN_TYPE_REPORT)) { + isp_err(isp, "invalid ipc chan type (%d)\n", + chan->type); + goto out; + } + + isp_dbg(isp, "chan: %s type: %d src: %d num: %d iova: 0x%llx\n", + chan->name, chan->type, chan->src, chan->num, + chan->iova); + } + + isp->chan_tm = isp_get_chan_index(isp, "TERMINAL"); + isp->chan_io = isp_get_chan_index(isp, "IO"); + isp->chan_dg = isp_get_chan_index(isp, "DEBUG"); + isp->chan_bh = isp_get_chan_index(isp, "BUF_H2T"); + isp->chan_bt = isp_get_chan_index(isp, "BUF_T2H"); + isp->chan_sm = isp_get_chan_index(isp, "SHAREDMALLOC"); + isp->chan_it = isp_get_chan_index(isp, "IO_T2H"); + + if (!isp->chan_tm || !isp->chan_io || !isp->chan_dg || !isp->chan_bh || + !isp->chan_bt || !isp->chan_sm || !isp->chan_it) { + isp_err(isp, "did not find all of the required ipc chans\n"); + goto out; + } + + isp->chan_tm->ops = &tm_ops; + isp->chan_sm->ops = &sm_ops; + isp->chan_bt->ops = &bt_ops; + + return 0; +out: + isp_free_channel_info(isp); + return -ENOMEM; +} + +static void isp_firmware_shutdown_stage3(struct apple_isp *isp) +{ + isp_free_channel_info(isp); +} + +static int isp_firmware_boot_stage3(struct apple_isp *isp) +{ + int err, retries; + + err = isp_fill_channel_info(isp); + if (err < 0) + return err; + + /* Mask the command channels to prepare for submission */ + for (int i = 0; i < isp->num_ipc_chans; i++) { + struct isp_channel *chan = isp->ipc_chans[i]; + if (chan->type != ISP_IPC_CHAN_TYPE_COMMAND) + continue; + for (int j = 0; j < chan->num; j++) { + struct isp_message msg; + dma_addr_t msg_iova = chan->iova + (j * sizeof(msg)); + + memset(&msg, 0, sizeof(msg)); + msg.arg0 = ISP_IPC_FLAG_ACK; + isp_iowrite(isp, msg_iova, &msg, sizeof(msg)); + } + } + + /* Wait for ISP_CORE_GPIO_3 to 0x8042006 -> 0x0 */ + isp_core_write32(isp, ISP_CORE_GPIO_3, 0x8042006); + + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + u32 val = isp_core_read32(isp, ISP_CORE_GPIO_3); + if (val == 0x0) { + isp_dbg(isp, + "got third magic number (0x%x) from firmware\n", + val); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, + "never received third magic number from firmware\n"); + isp_free_channel_info(isp); + return -ENODEV; + } + + isp_dbg(isp, "firmware booted!\n"); + + return 0; +} + +static int isp_stop_command_processor(struct apple_isp *isp) +{ + int retries; + + /* Wait for ISP_CORE_GPIO_0 to 0xf7fbdff9 -> 0x8042006 */ + isp_core_write32(isp, ISP_CORE_GPIO_0, 0xf7fbdff9); + + /* Their CISP_CMD_STOP implementation is buggy */ + isp_cmd_suspend(isp); + + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + u32 val = isp_core_read32(isp, ISP_CORE_GPIO_0); + if (val == 0x8042006) { + isp_dbg(isp, "got magic number (0x%x) from firmware\n", + val); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, "never received magic number from firmware\n"); + return -ENODEV; + } + + return 0; +} + +static int isp_start_command_processor(struct apple_isp *isp) +{ + int err; + + err = isp_cmd_print_enable(isp, 1); + if (err) + return err; + + err = isp_cmd_set_isp_pmu_base(isp, isp->hw->pmu_base); + if (err) + return err; + + err = isp_cmd_set_dsid_clr_req_base2( + isp, isp->hw->dsid_clr_base0, isp->hw->dsid_clr_base1, + isp->hw->dsid_clr_base2, isp->hw->dsid_clr_base3, + isp->hw->dsid_clr_range0, isp->hw->dsid_clr_range1, + isp->hw->dsid_clr_range2, isp->hw->dsid_clr_range3); + if (err) + return err; + + err = isp_cmd_pmp_ctrl_set( + isp, isp->hw->clock_scratch, isp->hw->clock_base, + isp->hw->clock_bit, isp->hw->clock_size, + isp->hw->bandwidth_scratch, isp->hw->bandwidth_base, + isp->hw->bandwidth_bit, isp->hw->bandwidth_size); + if (err) + return err; + + err = isp_cmd_start(isp, 0); + if (err) + return err; + + /* Now we can access CISP_CMD_CH_* commands */ + + return 0; +} + +static void isp_collect_gc_surface(struct apple_isp *isp) +{ + struct isp_surf *tmp, *surf; + list_for_each_entry_safe_reverse(surf, tmp, &isp->gc, head) { + isp_dbg(isp, "freeing iova: 0x%llx size: 0x%llx virt: %pS\n", + surf->iova, surf->size, (void *)surf->virt); + isp_free_surface(isp, surf); + } +} + +static int isp_firmware_boot(struct apple_isp *isp) +{ + int err; + + err = isp_firmware_boot_stage1(isp); + if (err < 0) { + isp_err(isp, "failed firmware boot stage 1: %d\n", err); + goto garbage_collect; + } + + err = isp_firmware_boot_stage2(isp); + if (err < 0) { + isp_err(isp, "failed firmware boot stage 2: %d\n", err); + goto shutdown_stage1; + } + + err = isp_firmware_boot_stage3(isp); + if (err < 0) { + isp_err(isp, "failed firmware boot stage 3: %d\n", err); + goto shutdown_stage2; + } + + err = isp_enable_irq(isp); + if (err < 0) { + isp_err(isp, "failed to enable interrupts: %d\n", err); + goto shutdown_stage3; + } + + err = isp_start_command_processor(isp); + if (err < 0) { + isp_err(isp, "failed to start command processor: %d\n", err); + goto disable_irqs; + } + + flush_workqueue(isp->wq); + + return 0; + +disable_irqs: + isp_disable_irq(isp); +shutdown_stage3: + isp_firmware_shutdown_stage3(isp); +shutdown_stage2: + isp_firmware_shutdown_stage2(isp); +shutdown_stage1: + isp_firmware_shutdown_stage1(isp); +garbage_collect: + isp_collect_gc_surface(isp); + return err; +} + +static void isp_firmware_shutdown(struct apple_isp *isp) +{ + flush_workqueue(isp->wq); + isp_stop_command_processor(isp); + isp_disable_irq(isp); + isp_firmware_shutdown_stage3(isp); + isp_firmware_shutdown_stage2(isp); + isp_firmware_shutdown_stage1(isp); + isp_collect_gc_surface(isp); +} + +int apple_isp_firmware_boot(struct apple_isp *isp) +{ + int err; + + /* Needs to be power cycled for IOMMU to behave correctly */ + err = pm_runtime_resume_and_get(isp->dev); + if (err < 0) { + dev_err(isp->dev, "failed to enable power: %d\n", err); + return err; + } + + err = isp_firmware_boot(isp); + if (err) { + dev_err(isp->dev, "failed to boot firmware: %d\n", err); + pm_runtime_put_sync(isp->dev); + return err; + } + + return 0; +} + +void apple_isp_firmware_shutdown(struct apple_isp *isp) +{ + isp_firmware_shutdown(isp); + pm_runtime_put_sync(isp->dev); +} diff --git a/drivers/media/platform/apple/isp/isp-fw.h b/drivers/media/platform/apple/isp/isp-fw.h new file mode 100644 index 00000000000000..ad9f4fdf641aaa --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-fw.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_FW_H__ +#define __ISP_FW_H__ + +#include "isp-drv.h" + +int apple_isp_firmware_boot(struct apple_isp *isp); +void apple_isp_firmware_shutdown(struct apple_isp *isp); + +#endif /* __ISP_FW_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c new file mode 100644 index 00000000000000..28935d37205024 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include +#include + +#include "isp-iommu.h" + +void apple_isp_iommu_sync_ttbr(struct apple_isp *isp) +{ + writel(readl(isp->dart0 + isp->hw->ttbr), isp->dart1 + isp->hw->ttbr); + writel(readl(isp->dart0 + isp->hw->ttbr), isp->dart2 + isp->hw->ttbr); +} + +void apple_isp_iommu_invalidate_tlb(struct apple_isp *isp) +{ + iommu_flush_iotlb_all(isp->domain); + writel(0x1, isp->dart1 + isp->hw->stream_select); + writel(isp->hw->stream_command_invalidate, + isp->dart1 + isp->hw->stream_command); + writel(0x1, isp->dart2 + isp->hw->stream_select); + writel(isp->hw->stream_command_invalidate, + isp->dart2 + isp->hw->stream_command); +} + +static void isp_surf_free_pages(struct isp_surf *surf) +{ + for (u32 i = 0; i < surf->num_pages && surf->pages[i] != NULL; i++) { + __free_page(surf->pages[i]); + } + kvfree(surf->pages); +} + +static int isp_surf_alloc_pages(struct isp_surf *surf) +{ + surf->pages = kvmalloc_array(surf->num_pages, sizeof(*surf->pages), + GFP_KERNEL); + if (!surf->pages) + return -ENOMEM; + + for (u32 i = 0; i < surf->num_pages; i++) { + surf->pages[i] = alloc_page(GFP_KERNEL); + if (surf->pages[i] == NULL) + goto free_pages; + } + + return 0; + +free_pages: + isp_surf_free_pages(surf); + return -ENOMEM; +} + +int isp_surf_vmap(struct apple_isp *isp, struct isp_surf *surf) +{ + surf->virt = vmap(surf->pages, surf->num_pages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (surf->virt == NULL) { + dev_err(isp->dev, "failed to vmap size 0x%llx\n", surf->size); + return -EINVAL; + } + + return 0; +} + +static void isp_surf_vunmap(struct apple_isp *isp, struct isp_surf *surf) +{ + if (surf->virt) + vunmap(surf->virt); + surf->virt = NULL; +} + +static void isp_surf_unreserve_iova(struct apple_isp *isp, + struct isp_surf *surf) +{ + if (surf->mm) { + mutex_lock(&isp->iovad_lock); + drm_mm_remove_node(surf->mm); + mutex_unlock(&isp->iovad_lock); + kfree(surf->mm); + } + surf->mm = NULL; +} + +static int isp_surf_reserve_iova(struct apple_isp *isp, struct isp_surf *surf) +{ + int err; + + surf->mm = kzalloc(sizeof(*surf->mm), GFP_KERNEL); + if (!surf->mm) + return -ENOMEM; + + mutex_lock(&isp->iovad_lock); + err = drm_mm_insert_node_generic(&isp->iovad, surf->mm, + ALIGN(surf->size, 1UL << isp->shift), + 1UL << isp->shift, 0, 0); + mutex_unlock(&isp->iovad_lock); + if (err < 0) { + dev_err(isp->dev, "failed to reserve 0x%llx of iova space\n", + surf->size); + goto mm_free; + } + + surf->iova = surf->mm->start; + + return 0; +mm_free: + kfree(surf->mm); + surf->mm = NULL; + return err; +} + +static void isp_surf_iommu_unmap(struct apple_isp *isp, struct isp_surf *surf) +{ + iommu_unmap(isp->domain, surf->iova, surf->size); + apple_isp_iommu_invalidate_tlb(isp); + sg_free_table(&surf->sgt); +} + +static int isp_surf_iommu_map(struct apple_isp *isp, struct isp_surf *surf) +{ + unsigned long size; + int err; + + err = sg_alloc_table_from_pages(&surf->sgt, surf->pages, + surf->num_pages, 0, surf->size, + GFP_KERNEL); + if (err < 0) { + dev_err(isp->dev, "failed to alloc sgt from pages\n"); + return err; + } + + size = iommu_map_sgtable(isp->domain, surf->iova, &surf->sgt, + IOMMU_READ | IOMMU_WRITE); + if (size < surf->size) { + dev_err(isp->dev, "failed to iommu_map sgt to iova 0x%llx\n", + surf->iova); + sg_free_table(&surf->sgt); + return -ENXIO; + } + + return 0; +} + +static void __isp_surf_init(struct apple_isp *isp, struct isp_surf *surf, + u64 size, bool gc) +{ + surf->mm = NULL; + surf->virt = NULL; + surf->size = ALIGN(size, 1UL << isp->shift); + surf->num_pages = surf->size >> isp->shift; + surf->gc = gc; +} + +struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc) +{ + int err; + + struct isp_surf *surf = kzalloc(sizeof(struct isp_surf), GFP_KERNEL); + if (!surf) + return NULL; + + __isp_surf_init(isp, surf, size, gc); + + err = isp_surf_alloc_pages(surf); + if (err < 0) { + dev_err(isp->dev, "failed to allocate %d pages\n", + surf->num_pages); + goto free_surf; + } + + err = isp_surf_reserve_iova(isp, surf); + if (err < 0) { + dev_err(isp->dev, "failed to reserve 0x%llx of iova space\n", + surf->size); + goto free_pages; + } + + err = isp_surf_iommu_map(isp, surf); + if (err < 0) { + dev_err(isp->dev, + "failed to iommu_map size 0x%llx to iova 0x%llx\n", + surf->size, surf->iova); + goto unreserve_iova; + } + + refcount_set(&surf->refcount, 1); + if (surf->gc) + list_add_tail(&surf->head, &isp->gc); + + return surf; + +unreserve_iova: + isp_surf_unreserve_iova(isp, surf); +free_pages: + isp_surf_free_pages(surf); +free_surf: + kfree(surf); + return NULL; +} + +struct isp_surf *isp_alloc_surface_vmap(struct apple_isp *isp, u64 size) +{ + int err; + + struct isp_surf *surf = __isp_alloc_surface(isp, size, false); + if (!surf) + return NULL; + + err = isp_surf_vmap(isp, surf); + if (err < 0) { + dev_err(isp->dev, "failed to vmap iova 0x%llx - 0x%llx\n", + surf->iova, surf->iova + surf->size); + isp_free_surface(isp, surf); + return NULL; + } + + return surf; +} + +void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf) +{ + if (refcount_dec_and_test(&surf->refcount)) { + isp_surf_vunmap(isp, surf); + isp_surf_iommu_unmap(isp, surf); + isp_surf_unreserve_iova(isp, surf); + isp_surf_free_pages(surf); + if (surf->gc) + list_del(&surf->head); + kfree(surf); + } +} + +void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova) +{ + phys_addr_t phys = iommu_iova_to_phys(isp->domain, iova); + return phys_to_virt(phys); +} + +int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, + struct sg_table *sgt, u64 size) +{ + int err; + ssize_t mapped; + + // TODO userptr sends unaligned sizes + surf->mm = NULL; + surf->size = size; + + err = isp_surf_reserve_iova(isp, surf); + if (err < 0) { + dev_err(isp->dev, "failed to reserve 0x%llx of iova space\n", + surf->size); + return err; + } + + mapped = iommu_map_sgtable(isp->domain, surf->iova, sgt, + IOMMU_READ | IOMMU_WRITE); + if (mapped < surf->size) { + dev_err(isp->dev, "failed to iommu_map sgt to iova 0x%llx\n", + surf->iova); + isp_surf_unreserve_iova(isp, surf); + return -ENXIO; + } + surf->size = mapped; + + return 0; +} + +void apple_isp_iommu_unmap_sgt(struct apple_isp *isp, struct isp_surf *surf) +{ + iommu_unmap(isp->domain, surf->iova, surf->size); + apple_isp_iommu_invalidate_tlb(isp); + isp_surf_unreserve_iova(isp, surf); +} diff --git a/drivers/media/platform/apple/isp/isp-iommu.h b/drivers/media/platform/apple/isp/isp-iommu.h new file mode 100644 index 00000000000000..f9972bd9ff93e7 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-iommu.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_IOMMU_H__ +#define __ISP_IOMMU_H__ + +#include "isp-drv.h" + +void apple_isp_iommu_sync_ttbr(struct apple_isp *isp); +void apple_isp_iommu_invalidate_tlb(struct apple_isp *isp); + +struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc); +#define isp_alloc_surface(isp, size) (__isp_alloc_surface(isp, size, false)) +#define isp_alloc_surface_gc(isp, size) (__isp_alloc_surface(isp, size, true)) +struct isp_surf *isp_alloc_surface_vmap(struct apple_isp *isp, u64 size); +int isp_surf_vmap(struct apple_isp *isp, struct isp_surf *surf); +void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf); +void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova); + +static inline void isp_ioread(struct apple_isp *isp, dma_addr_t iova, + void *data, u64 size) +{ + void *virt = isp_iotranslate(isp, iova); + memcpy(data, virt, size); +} + +static inline void isp_iowrite(struct apple_isp *isp, dma_addr_t iova, + void *data, u64 size) +{ + void *virt = isp_iotranslate(isp, iova); + memcpy(virt, data, size); +} + +int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, + struct sg_table *sgt, u64 size); +void apple_isp_iommu_unmap_sgt(struct apple_isp *isp, struct isp_surf *surf); + +#endif /* __ISP_IOMMU_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c new file mode 100644 index 00000000000000..ef3498c4fcd191 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include "isp-iommu.h" +#include "isp-ipc.h" +#include "isp-regs.h" + +#define ISP_IPC_FLAG_TERMINAL_ACK 0x3 +#define ISP_IPC_BUFEXC_STAT_META_OFFSET 0x10 + +struct isp_sm_deferred_work { + struct work_struct work; + struct apple_isp *isp; + struct isp_surf *surf; +}; + +struct isp_bufexc_stat { + u64 unk_0; // 2 + u64 unk_8; // 2 + + u64 meta_iova; + u64 pad_20[3]; + u64 meta_size; // 0x4640 + u64 unk_38; + + u32 unk_40; // 1 + u32 unk_44; + u64 unk_48; + + u64 iova0; + u64 iova1; + u64 iova2; + u64 iova3; + u32 pad_70[4]; + + u32 unk_80; // 2 + u32 unk_84; // 1 + u32 unk_88; // 0x10 || 0x13 + u32 unk_8c; + u32 pad_90[96]; + + u32 unk_210; // 0x28 + u32 unk_214; + u32 index; + u16 bes_width; // 1296, 0x510 + u16 bes_height; // 736, 0x2e0 + + u32 unk_220; // 0x0 || 0x1 + u32 pad_224[3]; + u32 unk_230; // 0xf7ed38 + u32 unk_234; // 3 + u32 pad_238[2]; + u32 pad_240[16]; +} __packed; +static_assert(sizeof(struct isp_bufexc_stat) == ISP_IPC_BUFEXC_STAT_SIZE); + +static inline dma_addr_t chan_msg_iova(struct isp_channel *chan, u32 index) +{ + return chan->iova + (index * ISP_IPC_MESSAGE_SIZE); +} + +static inline void chan_read_msg_index(struct apple_isp *isp, + struct isp_channel *chan, + struct isp_message *msg, u32 index) +{ + isp_ioread(isp, chan_msg_iova(chan, index), msg, sizeof(*msg)); +} + +static inline void chan_read_msg(struct apple_isp *isp, + struct isp_channel *chan, + struct isp_message *msg) +{ + chan_read_msg_index(isp, chan, msg, chan->cursor); +} + +static inline void chan_write_msg_index(struct apple_isp *isp, + struct isp_channel *chan, + struct isp_message *msg, u32 index) +{ + isp_iowrite(isp, chan_msg_iova(chan, index), msg, sizeof(*msg)); +} + +static inline void chan_write_msg(struct apple_isp *isp, + struct isp_channel *chan, + struct isp_message *msg) +{ + chan_write_msg_index(isp, chan, msg, chan->cursor); +} + +static inline void chan_update_cursor(struct isp_channel *chan) +{ + if (chan->cursor >= (chan->num - 1)) { + chan->cursor = 0; + } else { + chan->cursor += 1; + } +} + +static int chan_handle_once(struct apple_isp *isp, struct isp_channel *chan) +{ + int err; + + lockdep_assert_held(&chan->lock); + + err = chan->ops->handle(isp, chan); + if (err < 0) { + dev_err(isp->dev, "%s: handler failed: %d)\n", chan->name, err); + return err; + } + + chan_write_msg(isp, chan, &chan->rsp); + + isp_core_write32(isp, ISP_CORE_IRQ_DOORBELL, chan->doorbell); + + chan_update_cursor(chan); + + return 0; +} + +static inline bool chan_rx_done(struct apple_isp *isp, struct isp_channel *chan) +{ + if (((chan->req.arg0 & 0xf) == ISP_IPC_FLAG_ACK) || + ((chan->req.arg0 & 0xf) == ISP_IPC_FLAG_TERMINAL_ACK)) { + return true; + } + return false; +} + +int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + int err = 0; + + spin_lock(&chan->lock); + while (1) { + chan_read_msg(isp, chan, &chan->req); + if (chan_rx_done(isp, chan)) { + err = 0; + break; + } + err = chan_handle_once(isp, chan); + if (err < 0) { + break; + } + } + spin_unlock(&chan->lock); + + return err; +} + +static inline bool chan_tx_done(struct apple_isp *isp, struct isp_channel *chan) +{ + chan_read_msg(isp, chan, &chan->rsp); + if ((chan->rsp.arg0) == (chan->req.arg0 | ISP_IPC_FLAG_ACK)) { + chan_update_cursor(chan); + return true; + } + return false; +} + +int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, + unsigned long timeout) +{ + long t; + + chan_write_msg(isp, chan, &chan->req); + wmb(); + + isp_core_write32(isp, ISP_CORE_IRQ_DOORBELL, chan->doorbell); + + t = wait_event_interruptible_timeout(isp->wait, chan_tx_done(isp, chan), + timeout); + if (t == 0) { + dev_err(isp->dev, + "%s: timed out on request [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, chan->req.arg0, chan->req.arg1, + chan->req.arg2); + return -ETIME; + } + + isp_dbg(isp, "%s: request success (%ld)\n", chan->name, t); + + return 0; +} + +int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + struct isp_message *rsp = &chan->rsp; + +#ifdef APPLE_ISP_DEBUG + struct isp_message *req = &chan->req; + char buf[512]; + dma_addr_t iova = req->arg0 & ~ISP_IPC_FLAG_TERMINAL_ACK; + u32 size = req->arg1; + if (iova && size && test_bit(ISP_STATE_LOGGING, &isp->state)) { + size = min_t(u32, size, 512); + isp_ioread(isp, iova, buf, size); + isp_dbg(isp, "ISPASC: %.*s", size, buf); + } +#endif + + rsp->arg0 = ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = 0x0; + + return 0; +} + +/* The kernel accesses exactly two dynamically allocated shared surfaces: + * 1) LOG: Surface for terminal logs. Optional, only enabled in debug builds. + * 2) STAT: Surface for BUFT2H rendered frame stat buffer. We isp_ioread() in + * the BUFT2H ISR below. Since the BUFT2H IRQ is triggered by the BUF_H2T + * doorbell, the STAT vmap must complete before the first buffer submission + * under VIDIOC_STREAMON(). The CISP_CMD_PRINT_ENABLE completion depends on the + * STAT buffer SHAREDMALLOC ISR, which is part of the firmware initialization + * sequence. We also call flush_workqueue(), so a fault should not occur. + */ +static void sm_malloc_deferred_worker(struct work_struct *work) +{ + struct isp_sm_deferred_work *dwork = + container_of(work, struct isp_sm_deferred_work, work); + struct apple_isp *isp = dwork->isp; + struct isp_surf *surf = dwork->surf; + int err; + + err = isp_surf_vmap(isp, surf); /* Can't vmap in interrupt ctx */ + if (err < 0) { + isp_err(isp, "failed to vmap iova=0x%llx size=0x%llx\n", + surf->iova, surf->size); + goto out; + } + +#ifdef APPLE_ISP_DEBUG + /* Only enabled in debug builds so it shouldn't matter, but + * the LOG surface is always the first surface requested. + */ + if (!test_bit(ISP_STATE_LOGGING, &isp->state)) + set_bit(ISP_STATE_LOGGING, &isp->state); +#endif + +out: + kfree(dwork); +} + +int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + struct isp_message *req = &chan->req, *rsp = &chan->rsp; + + if (req->arg0 == 0x0) { + struct isp_sm_deferred_work *dwork; + struct isp_surf *surf; + + dwork = kzalloc(sizeof(*dwork), GFP_KERNEL); + if (!dwork) + return -ENOMEM; + dwork->isp = isp; + + surf = isp_alloc_surface_gc(isp, req->arg1); + if (!surf) { + isp_err(isp, "failed to alloc requested size 0x%llx\n", + req->arg1); + kfree(dwork); + return -ENOMEM; + } + dwork->surf = surf; + + rsp->arg0 = surf->iova | ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = 0x0; /* macOS uses this to index surfaces */ + + INIT_WORK(&dwork->work, sm_malloc_deferred_worker); + if (!queue_work(isp->wq, &dwork->work)) { + isp_err(isp, "failed to queue deferred work\n"); + isp_free_surface(isp, surf); + kfree(dwork); + return -ENOMEM; + } + /* To the gc it goes... */ + + } else { + /* This should be the shared surface free request, but + * 1) The fw doesn't request to free all of what it requested + * 2) The fw continues to access the surface after + * So we link it to the gc, which runs after fw shutdown + */ +#ifdef APPLE_ISP_DEBUG + if (test_bit(ISP_STATE_LOGGING, &isp->state)) + clear_bit(ISP_STATE_LOGGING, &isp->state); +#endif + rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = 0x0; + } + + return 0; +} + +int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + struct isp_message *req = &chan->req, *rsp = &chan->rsp; + struct isp_buffer *tmp, *buf; + int err = 0; + + /* No need to read the whole struct */ + u64 meta_iova; + isp_ioread(isp, req->arg0 + ISP_IPC_BUFEXC_STAT_META_OFFSET, &meta_iova, + sizeof(meta_iova)); + + spin_lock(&isp->buf_lock); + list_for_each_entry_safe_reverse(buf, tmp, &isp->buffers, link) { + if (buf->meta->iova == meta_iova) { + enum vb2_buffer_state state = VB2_BUF_STATE_ERROR; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = isp->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + if (req->arg2 == ISP_IPC_BUFEXC_FLAG_RENDER) + state = VB2_BUF_STATE_DONE; + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->link); + break; + } + } + spin_unlock(&isp->buf_lock); + + rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = ISP_IPC_BUFEXC_FLAG_ACK; + + return err; +} diff --git a/drivers/media/platform/apple/isp/isp-ipc.h b/drivers/media/platform/apple/isp/isp-ipc.h new file mode 100644 index 00000000000000..32d1e1bf321006 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-ipc.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_IPC_H__ +#define __ISP_IPC_H__ + +#include "isp-drv.h" + +#define ISP_IPC_CHAN_TYPE_COMMAND 0 +#define ISP_IPC_CHAN_TYPE_REPLY 1 +#define ISP_IPC_CHAN_TYPE_REPORT 2 + +#define ISP_IPC_BUFEXC_STAT_SIZE 0x280 +#define ISP_IPC_BUFEXC_FLAG_RENDER 0x10000000 +#define ISP_IPC_BUFEXC_FLAG_COMMAND 0x30000000 +#define ISP_IPC_BUFEXC_FLAG_ACK 0x80000000 + +int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan); +int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, + unsigned long timeout); + +int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan); +int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan); +int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan); + +#endif /* __ISP_IPC_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h new file mode 100644 index 00000000000000..b9bd505844d9de --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_REGS_H__ +#define __ISP_REGS_H__ + +#include "isp-drv.h" + +#define ISP_ASC_PMGR_0 0x738 +#define ISP_ASC_PMGR_1 0x798 +#define ISP_ASC_PMGR_2 0x7f8 +#define ISP_ASC_PMGR_3 0x858 + +#define ISP_ASC_RVBAR 0x1050000 +#define ISP_ASC_EDPRCR 0x1010310 +#define ISP_ASC_CONTROL 0x1400044 +#define ISP_ASC_STATUS 0x1400048 + +#define ISP_ASC_IRQ_MASK_0 0x1400a00 +#define ISP_ASC_IRQ_MASK_1 0x1400a04 +#define ISP_ASC_IRQ_MASK_2 0x1400a08 +#define ISP_ASC_IRQ_MASK_3 0x1400a0c +#define ISP_ASC_IRQ_MASK_4 0x1400a10 +#define ISP_ASC_IRQ_MASK_5 0x1400a14 + +#define ISP_CORE_IRQ_INTERRUPT 0x2104000 +#define ISP_CORE_IRQ_ENABLE 0x2104004 +#define ISP_CORE_IRQ_DOORBELL 0x21043f0 +#define ISP_CORE_IRQ_ACK 0x21043fc + +#define ISP_CORE_GPIO_0 0x2104170 +#define ISP_CORE_GPIO_1 0x2104174 +#define ISP_CORE_GPIO_2 0x2104178 +#define ISP_CORE_GPIO_3 0x210417c +#define ISP_CORE_GPIO_4 0x2104180 +#define ISP_CORE_GPIO_5 0x2104184 +#define ISP_CORE_GPIO_6 0x2104188 +#define ISP_CORE_GPIO_7 0x210418c + +#define ISP_CORE_CLOCK_EN 0x2104190 + +#define ISP_CORE_DPE_CTRL_0 0x2504000 +#define ISP_CORE_DPE_CTRL_1 0x2508000 + +static inline u32 isp_core_read32(struct apple_isp *isp, u32 reg) +{ + return readl(isp->core + reg - 0x2104000); // TODO this sucks +} + +static inline void isp_core_write32(struct apple_isp *isp, u32 reg, u32 val) +{ + writel(val, isp->core + reg - 0x2104000); +} + +static inline void isp_core_mask32(struct apple_isp *isp, u32 reg, u32 clear, + u32 set) +{ + isp_core_write32(isp, reg, isp_core_read32(isp, reg) & ~clear); + isp_core_write32(isp, reg, isp_core_read32(isp, reg) | set); +} + +#endif /* __ISP_REGS_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c new file mode 100644 index 00000000000000..0d1593803f1143 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include +#include +#include +#include +#include + +#include "isp-cam.h" +#include "isp-cmd.h" +#include "isp-iommu.h" +#include "isp-ipc.h" +#include "isp-v4l2.h" + +#define ISP_MIN_FRAMES 2 +#define ISP_MAX_PLANES 4 +#define ISP_MAX_PIX_FORMATS 2 +#define ISP_BUFFER_TIMEOUT msecs_to_jiffies(1500) + +struct isp_h2t_buffer { + u64 iovas[ISP_MAX_PLANES]; + u32 flags[ISP_MAX_PLANES]; + u32 num_planes; + u32 pool_type; + u32 tag; + u32 pad; +} __packed; +static_assert(sizeof(struct isp_h2t_buffer) == 0x40); + +struct isp_h2t_args { + u64 enable; + u64 num_buffers; + struct isp_h2t_buffer meta; + struct isp_h2t_buffer render; +} __packed; + +static int isp_submit_buffers(struct apple_isp *isp) +{ + struct isp_format *fmt = isp_get_current_format(isp); + struct isp_channel *chan = isp->chan_bh; + struct isp_message *req = &chan->req; + struct isp_buffer *buf; + unsigned long flags; + size_t offset; + int err; + + struct isp_h2t_args *args = + kzalloc(sizeof(struct isp_h2t_args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + spin_lock_irqsave(&isp->buf_lock, flags); + buf = list_first_entry_or_null(&isp->buffers, struct isp_buffer, link); + if (!buf) { + spin_unlock_irqrestore(&isp->buf_lock, flags); + kfree(args); + return -EPROTO; + } + + args->meta.num_planes = 1; + args->meta.pool_type = CISP_POOL_TYPE_META; + args->meta.iovas[0] = buf->meta->iova; + args->meta.flags[0] = 0x40000000; + + args->render.num_planes = fmt->num_planes; + args->render.pool_type = CISP_POOL_TYPE_RENDERED; + offset = 0; + for (int j = 0; j < fmt->num_planes; j++) { + args->render.iovas[j] = buf->surfs[0].iova + offset; + args->render.flags[j] = 0x40000000; + offset += fmt->plane_size[j]; + } + spin_unlock_irqrestore(&isp->buf_lock, flags); + + args->enable = 0x1; + args->num_buffers = 2; + + req->arg0 = isp->cmd_iova; + req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; + req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; + + isp_iowrite(isp, req->arg0, args, sizeof(*args)); + err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); + if (err) { + dev_err(isp->dev, + "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, req->arg0, req->arg1, req->arg2); + } + + kfree(args); + + return err; +} + +/* + * Videobuf2 section + */ +static int isp_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct apple_isp *isp = vb2_get_drv_priv(vq); + struct isp_format *fmt = isp_get_current_format(isp); + + if (*num_planes) { + if (sizes[0] < fmt->total_size) + return -EINVAL; + + return 0; + } + + *num_planes = 1; + sizes[0] = fmt->total_size; + + return 0; +} + +static void __isp_vb2_buf_cleanup(struct vb2_buffer *vb, unsigned int i) +{ + struct apple_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct isp_buffer *buf = + container_of(vb, struct isp_buffer, vb.vb2_buf); + + while (i--) + apple_isp_iommu_unmap_sgt(isp, &buf->surfs[i]); + isp_free_surface(isp, buf->meta); +} + +static void isp_vb2_buf_cleanup(struct vb2_buffer *vb) +{ + __isp_vb2_buf_cleanup(vb, vb->num_planes); +} + +static int isp_vb2_buf_init(struct vb2_buffer *vb) +{ + struct apple_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct isp_buffer *buf = + container_of(vb, struct isp_buffer, vb.vb2_buf); + unsigned int i; + int err; + + buf->meta = isp_alloc_surface(isp, ISP_META_SIZE); + if (!buf->meta) + return -ENOMEM; + + for (i = 0; i < vb->num_planes; i++) { + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, i); + err = apple_isp_iommu_map_sgt(isp, &buf->surfs[i], sgt, + vb2_plane_size(vb, i)); + if (err) + goto cleanup; + } + + return 0; + +cleanup: + __isp_vb2_buf_cleanup(vb, i); + return err; +} + +static int isp_vb2_buf_prepare(struct vb2_buffer *vb) +{ + struct apple_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct isp_format *fmt = isp_get_current_format(isp); + + if (vb2_plane_size(vb, 0) < fmt->total_size) + return -EINVAL; + + vb2_set_plane_payload(vb, 0, fmt->total_size); + + return 0; +} + +static void isp_vb2_release_buffers(struct apple_isp *isp, + enum vb2_buffer_state state) +{ + struct isp_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&isp->buf_lock, flags); + list_for_each_entry(buf, &isp->buffers, link) + vb2_buffer_done(&buf->vb.vb2_buf, state); + INIT_LIST_HEAD(&isp->buffers); + spin_unlock_irqrestore(&isp->buf_lock, flags); +} + +static void isp_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct apple_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct isp_buffer *buf = + container_of(vb, struct isp_buffer, vb.vb2_buf); + unsigned long flags; + bool empty; + + spin_lock_irqsave(&isp->buf_lock, flags); + empty = list_empty(&isp->buffers); + list_add_tail(&buf->link, &isp->buffers); + spin_unlock_irqrestore(&isp->buf_lock, flags); + + if (test_bit(ISP_STATE_STREAMING, &isp->state) && !empty) + isp_submit_buffers(isp); +} + +static int isp_vb2_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct apple_isp *isp = vb2_get_drv_priv(q); + int err; + + isp->sequence = 0; + + err = apple_isp_start_camera(isp); + if (err) { + dev_err(isp->dev, "failed to start camera: %d\n", err); + goto release_buffers; + } + + err = isp_submit_buffers(isp); + if (err) { + dev_err(isp->dev, "failed to send initial batch: %d\n", err); + goto stop_camera; + } + + err = apple_isp_start_capture(isp); + if (err) { + dev_err(isp->dev, "failed to start capture: %d\n", err); + goto stop_camera; + } + + set_bit(ISP_STATE_STREAMING, &isp->state); + + return 0; + +stop_camera: + apple_isp_stop_camera(isp); +release_buffers: + isp_vb2_release_buffers(isp, VB2_BUF_STATE_QUEUED); + return err; +} + +static void isp_vb2_stop_streaming(struct vb2_queue *q) +{ + struct apple_isp *isp = vb2_get_drv_priv(q); + + clear_bit(ISP_STATE_STREAMING, &isp->state); + apple_isp_stop_capture(isp); + apple_isp_stop_camera(isp); + isp_vb2_release_buffers(isp, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops isp_vb2_ops = { + .queue_setup = isp_vb2_queue_setup, + .buf_init = isp_vb2_buf_init, + .buf_cleanup = isp_vb2_buf_cleanup, + .buf_prepare = isp_vb2_buf_prepare, + .buf_queue = isp_vb2_buf_queue, + .start_streaming = isp_vb2_start_streaming, + .stop_streaming = isp_vb2_stop_streaming, +}; + +/* + * V4L2 ioctl section + */ +static int isp_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->card, APPLE_ISP_DEVICE_NAME, sizeof(cap->card)); + strscpy(cap->driver, APPLE_ISP_DEVICE_NAME, sizeof(cap->driver)); + + return 0; +} + +static int isp_vidioc_enum_format(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index >= ISP_MAX_PIX_FORMATS) + return -EINVAL; + + if (!f->index) + f->pixelformat = V4L2_PIX_FMT_NV12; + else + f->pixelformat = V4L2_PIX_FMT_NV12M; + + return 0; +} + +static int isp_vidioc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *f) +{ + struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); + + if (f->index >= ISP_MAX_PIX_FORMATS) + return -EINVAL; + + if ((!f->index && f->pixel_format != V4L2_PIX_FMT_NV12) || + (f->index && f->pixel_format != V4L2_PIX_FMT_NV12M)) + return -EINVAL; + + f->discrete.width = fmt->width; + f->discrete.height = fmt->height; + f->type = V4L2_FRMSIZE_TYPE_DISCRETE; + + return 0; +} + +static inline void isp_set_sp_pix_format(struct apple_isp *isp, + struct v4l2_format *f) +{ + struct isp_format *fmt = isp_get_current_format(isp); + + f->fmt.pix.width = fmt->width; + f->fmt.pix.height = fmt->height; + f->fmt.pix.sizeimage = fmt->total_size; + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12; + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_709; + f->fmt.pix.xfer_func = V4L2_XFER_FUNC_709; +} + +static inline void isp_set_mp_pix_format(struct apple_isp *isp, + struct v4l2_format *f) +{ + struct isp_format *fmt = isp_get_current_format(isp); + + f->fmt.pix_mp.width = fmt->width; + f->fmt.pix_mp.height = fmt->height; + f->fmt.pix_mp.num_planes = fmt->num_planes; + for (int i = 0; i < fmt->num_planes; i++) + f->fmt.pix_mp.plane_fmt[i].sizeimage = fmt->plane_size[i]; + + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_709; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_709; +} + +static int isp_vidioc_get_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (isp->multiplanar) + return -ENOTTY; + + isp_set_sp_pix_format(isp, f); + + return 0; +} + +static int isp_vidioc_set_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (isp->multiplanar) + return -ENOTTY; + + isp_set_sp_pix_format(isp, f); // no + + return 0; +} + +static int isp_vidioc_try_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (isp->multiplanar) + return -ENOTTY; + + isp_set_sp_pix_format(isp, f); // still no + + return 0; +} + +static int isp_vidioc_get_format_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (!isp->multiplanar) + return -ENOTTY; + + isp_set_mp_pix_format(isp, f); + + return 0; +} + +static int isp_vidioc_set_format_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (!isp->multiplanar) + return -ENOTTY; + + isp_set_mp_pix_format(isp, f); // no + + return 0; +} + +static int isp_vidioc_try_format_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (!isp->multiplanar) + return -ENOTTY; + + isp_set_mp_pix_format(isp, f); // still no + + return 0; +} + +static int isp_vidioc_enum_input(struct file *file, void *fh, + struct v4l2_input *inp) +{ + if (inp->index) + return -EINVAL; + + strscpy(inp->name, APPLE_ISP_DEVICE_NAME, sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +static int isp_vidioc_get_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int isp_vidioc_set_input(struct file *file, void *fh, unsigned int i) +{ + if (i) + return -EINVAL; + + return 0; +} + +static int isp_vidioc_get_param(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct apple_isp *isp = video_drvdata(file); + + if (a->type != (isp->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.capture.readbuffers = ISP_MIN_FRAMES; + a->parm.capture.timeperframe.numerator = ISP_FRAME_RATE_NUM; + a->parm.capture.timeperframe.denominator = ISP_FRAME_RATE_DEN; + + return 0; +} + +static int isp_vidioc_set_param(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct apple_isp *isp = video_drvdata(file); + + if (a->type != (isp->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + /* Not supporting frame rate sets. No use. Plus floats. */ + a->parm.capture.timeperframe.numerator = ISP_FRAME_RATE_NUM; + a->parm.capture.timeperframe.denominator = ISP_FRAME_RATE_DEN; + + return 0; +} + +static const struct v4l2_ioctl_ops isp_v4l2_ioctl_ops = { + .vidioc_querycap = isp_vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = isp_vidioc_enum_format, + .vidioc_g_fmt_vid_cap = isp_vidioc_get_format, + .vidioc_s_fmt_vid_cap = isp_vidioc_set_format, + .vidioc_try_fmt_vid_cap = isp_vidioc_try_format, + .vidioc_g_fmt_vid_cap_mplane = isp_vidioc_get_format_mplane, + .vidioc_s_fmt_vid_cap_mplane = isp_vidioc_set_format_mplane, + .vidioc_try_fmt_vid_cap_mplane = isp_vidioc_try_format_mplane, + + .vidioc_enum_framesizes = isp_vidioc_enum_framesizes, + .vidioc_enum_input = isp_vidioc_enum_input, + .vidioc_g_input = isp_vidioc_get_input, + .vidioc_s_input = isp_vidioc_set_input, + .vidioc_g_parm = isp_vidioc_get_param, + .vidioc_s_parm = isp_vidioc_set_param, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static const struct v4l2_file_operations isp_v4l2_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct media_device_ops isp_media_device_ops = { + .link_notify = v4l2_pipeline_link_notify, +}; + +int apple_isp_setup_video(struct apple_isp *isp) +{ + struct video_device *vdev = &isp->vdev; + struct vb2_queue *vbq = &isp->vbq; + int err; + + media_device_init(&isp->mdev); + isp->v4l2_dev.mdev = &isp->mdev; + isp->mdev.ops = &isp_media_device_ops; + isp->mdev.dev = isp->dev; + strscpy(isp->mdev.model, APPLE_ISP_DEVICE_NAME, sizeof(isp->mdev.model)); + + err = media_device_register(&isp->mdev); + if (err) { + dev_err(isp->dev, "failed to register media device: %d\n", err); + goto media_cleanup; + } + + isp->multiplanar = 0; + + err = v4l2_device_register(isp->dev, &isp->v4l2_dev); + if (err) { + dev_err(isp->dev, "failed to register v4l2 device: %d\n", err); + goto media_unregister; + } + + vbq->drv_priv = isp; + vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vbq->io_modes = VB2_MMAP; + vbq->dev = isp->dev; + vbq->ops = &isp_vb2_ops; + vbq->mem_ops = &vb2_dma_sg_memops; + vbq->buf_struct_size = sizeof(struct isp_buffer); + vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vbq->min_queued_buffers = ISP_MIN_FRAMES; + vbq->lock = &isp->video_lock; + + err = vb2_queue_init(vbq); + if (err) { + dev_err(isp->dev, "failed to init vb2 queue: %d\n", err); + goto v4l2_unregister; + } + + vdev->queue = vbq; + vdev->fops = &isp_v4l2_fops; + vdev->ioctl_ops = &isp_v4l2_ioctl_ops; + vdev->device_caps = V4L2_BUF_TYPE_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + vdev->v4l2_dev = &isp->v4l2_dev; + vdev->vfl_type = VFL_TYPE_VIDEO; + vdev->vfl_dir = VFL_DIR_RX; + vdev->release = video_device_release_empty; + vdev->lock = &isp->video_lock; + strscpy(vdev->name, APPLE_ISP_DEVICE_NAME, sizeof(vdev->name)); + video_set_drvdata(vdev, isp); + + err = video_register_device(vdev, VFL_TYPE_VIDEO, 0); + if (err) { + dev_err(isp->dev, "failed to register video device: %d\n", err); + goto v4l2_unregister; + } + + return 0; + +v4l2_unregister: + v4l2_device_unregister(&isp->v4l2_dev); +media_unregister: + media_device_unregister(&isp->mdev); +media_cleanup: + media_device_cleanup(&isp->mdev); + return err; +} + +void apple_isp_remove_video(struct apple_isp *isp) +{ + vb2_video_unregister_device(&isp->vdev); + v4l2_device_unregister(&isp->v4l2_dev); + media_device_unregister(&isp->mdev); + media_device_cleanup(&isp->mdev); +} diff --git a/drivers/media/platform/apple/isp/isp-v4l2.h b/drivers/media/platform/apple/isp/isp-v4l2.h new file mode 100644 index 00000000000000..df9b961d77bc17 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-v4l2.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_V4L2_H__ +#define __ISP_V4L2_H__ + +#include "isp-drv.h" + +int apple_isp_setup_video(struct apple_isp *isp); +void apple_isp_remove_video(struct apple_isp *isp); + +#endif /* __ISP_V4L2_H__ */ From 11159ce3a3a6186211d85b41eb9063f9a987e0ac Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sat, 2 Sep 2023 00:47:39 +0900 Subject: [PATCH 280/352] media: apple: isp: IMX558 initial support Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-cam.c | 5 +- drivers/media/platform/apple/isp/isp-drv.c | 54 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 6d08248ef44776..bb90337cb7c19f 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -78,12 +78,13 @@ static const struct isp_setfile isp_setfiles[] = { [ISP_VD56G0_6221_01] = {0xd56, 0x62210102, "isp/6221_01XX.dat", 0x1b80}, [ISP_VD56G0_6222_01] = {0xd56, 0x62220102, "isp/6222_01XX.dat", 0x1b80}, }; -// clang-format on // one day we will do this intelligently static const struct isp_preset isp_presets[] = { - [ISP_IMX248_1820_01] = { 0, 1280, 720, 8, 8, 1280, 720, 1296, 736 }, + [ISP_IMX248_1820_01] = {0, 1280, 720, 8, 8, 1280, 720, 1296, 736}, // J293AP + [ISP_IMX558_1921_01] = {1, 1920, 1080, 0, 0, 1920, 1080, 1920, 1080}, // J316sAP, J415AP }; +// clang-format on static int isp_ch_get_sensor_id(struct apple_isp *isp, u32 ch) { diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index e8e32ba73ad962..31aaf1e78b9e98 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -292,6 +292,60 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, }; +static const struct apple_isp_hw apple_isp_hw_t6000 = { + .pmu_base = 0x28e584000, + + .dsid_clr_base0 = 0x200014000, + .dsid_clr_base1 = 0x200054000, + .dsid_clr_base2 = 0x200094000, + .dsid_clr_base3 = 0x2000d4000, + .dsid_clr_range0 = 0x1000, + .dsid_clr_range1 = 0x1000, + .dsid_clr_range2 = 0x1000, + .dsid_clr_range3 = 0x1000, + + .clock_scratch = 0x28e3d0868, + .clock_base = 0x0, + .clock_bit = 0x0, + .clock_size = 0x8, + .bandwidth_scratch = 0x28e3d0980, + .bandwidth_base = 0x0, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x8, + + .stream_command = DART_T8020_STREAM_COMMAND, + .stream_select = DART_T8020_STREAM_SELECT, + .ttbr = DART_T8020_TTBR, + .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, +}; + +static const struct apple_isp_hw apple_isp_hw_t8110 = { + .pmu_base = 0x23b704000, + + .dsid_clr_base0 = 0x200014000, // TODO + .dsid_clr_base1 = 0x200054000, + .dsid_clr_base2 = 0x200094000, + .dsid_clr_base3 = 0x2000d4000, + .dsid_clr_range0 = 0x1000, + .dsid_clr_range1 = 0x1000, + .dsid_clr_range2 = 0x1000, + .dsid_clr_range3 = 0x1000, + + .clock_scratch = 0x23b3d0560, + .clock_base = 0x0, + .clock_bit = 0x0, + .clock_size = 0x8, + .bandwidth_scratch = 0x23b3d05d0, + .bandwidth_base = 0x0, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x8, + + .stream_command = DART_T8020_STREAM_COMMAND, // TODO + .stream_select = DART_T8020_STREAM_SELECT, + .ttbr = DART_T8020_TTBR, + .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, +}; + static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, {}, From 3aec58c4abe65f0390177bf68888f00b828f47b5 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 8 Sep 2023 00:45:36 +0900 Subject: [PATCH 281/352] media: apple: isp: Use preallocated heap Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.c | 51 ++++++++++++---------- drivers/media/platform/apple/isp/isp-drv.h | 2 +- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 31aaf1e78b9e98..d02a60bb34b10e 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -79,30 +79,44 @@ static int apple_isp_attach_genpd(struct apple_isp *isp) static int apple_isp_init_iommu(struct apple_isp *isp) { struct device *dev = isp->dev; - struct isp_firmware *fw = &isp->fw; - u64 heap_base, heap_size, vm_size; + phys_addr_t heap_base; + size_t heap_size; + u64 vm_size; int err; - int i = 0; + int idx; + int size; + struct device_node *mem_node; + const __be32 *maps, *end; isp->domain = iommu_get_domain_for_dev(isp->dev); if (!isp->domain) return -EPROBE_DEFER; isp->shift = __ffs(isp->domain->pgsize_bitmap); - err = of_property_read_u64(dev->of_node, "apple,isp-heap-base", - &heap_base); - if (err) { - dev_err(dev, "failed to read 'apple,isp-heap-base': %d\n", err); - return err; + idx = of_property_match_string(dev->of_node, "memory-region-names", "heap"); + mem_node = of_parse_phandle(dev->of_node, "memory-region", idx); + if (!mem_node) { + dev_err(dev, "No memory-region found for heap\n"); + return -ENODEV; } - err = of_property_read_u64(dev->of_node, "apple,isp-heap-size", - &heap_size); - if (err) { - dev_err(dev, "failed to read 'apple,isp-heap-size': %d\n", err); - return err; + maps = of_get_property(mem_node, "iommu-addresses", &size); + if (!maps || !size) { + dev_err(dev, "No valid iommu-addresses found for heap\n"); + return -ENODEV; + } + + end = maps + size / sizeof(__be32); + + while (maps < end) { + maps++; + maps = of_translate_dma_region(dev->of_node, maps, &heap_base, &heap_size); } + printk("heap: 0x%llx 0x%lx\n", heap_base, heap_size); + + isp->fw.heap_top = heap_base + heap_size; + err = of_property_read_u64(dev->of_node, "apple,dart-vm-size", &vm_size); if (err) { @@ -110,15 +124,7 @@ static int apple_isp_init_iommu(struct apple_isp *isp) return err; } - drm_mm_init(&isp->iovad, heap_base, vm_size - heap_base); - - /* Allocate read-only coprocessor private heap */ - fw->heap = isp_alloc_surface(isp, heap_size); - if (!fw->heap) { - drm_mm_takedown(&isp->iovad); - err = -ENOMEM; - return err; - } + drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - heap_base); apple_isp_iommu_sync_ttbr(isp); @@ -127,7 +133,6 @@ static int apple_isp_init_iommu(struct apple_isp *isp) static void apple_isp_free_iommu(struct apple_isp *isp) { - isp_free_surface(isp, isp->fw.heap); drm_mm_takedown(&isp->iovad); } diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 5db64dcc844863..7b463eaef1c9ce 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -196,7 +196,7 @@ struct apple_isp { struct mutex iovad_lock; struct isp_firmware { - struct isp_surf *heap; + u64 heap_top; } fw; struct isp_surf *ipc_surf; From 275d860d9ed49772c91ce2c8577f65f7f3eee141 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 8 Sep 2023 00:45:49 +0900 Subject: [PATCH 282/352] media: apple: isp: Fixup shared region arg Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-fw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 12b9c0694d68e8..4315653a0510a0 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -30,8 +30,8 @@ static inline void isp_asc_write32(struct apple_isp *isp, u32 reg, u32 val) struct isp_firmware_bootargs { u32 pad_0[2]; u64 ipc_iova; - u64 unk_size; - u64 unk_inv; + u64 shared_base; + u64 shared_size; u64 extra_iova; u64 extra_size; u32 unk4; @@ -254,8 +254,8 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) memset(&args, 0, sizeof(args)); args.ipc_iova = isp->ipc_surf->iova; args.ipc_size = isp->ipc_surf->size; - args.unk_size = 0x1800000; - args.unk_inv = 0x10000000 - args.unk_size; + args.shared_base = isp->fw.heap_top; + args.shared_size = 0x10000000 - isp->fw.heap_top; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; args.unk4 = 0x1; From c7227d4ff833c72ae42bd8d93277a457d23c73bf Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 10 Sep 2023 22:57:06 +0900 Subject: [PATCH 283/352] media: apple: isp: Enable t6000 Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index d02a60bb34b10e..094af7f7c33523 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -353,6 +353,7 @@ static const struct apple_isp_hw apple_isp_hw_t8110 = { static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, + { .compatible = "apple,t6000-isp", .data = &apple_isp_hw_t6000 }, {}, }; MODULE_DEVICE_TABLE(of, apple_isp_of_match); From 0af68a26c69381a055f6397f024f48eeb9e47010 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sat, 2 Sep 2023 01:07:08 +0900 Subject: [PATCH 284/352] media: apple: isp: Split gpio/mbox MMIO range Offsets differ across socs. Makes more sense than "core" too. Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 12 +++- drivers/media/platform/apple/isp/isp-drv.h | 3 +- drivers/media/platform/apple/isp/isp-fw.c | 76 ++++++++++++--------- drivers/media/platform/apple/isp/isp-ipc.c | 4 +- drivers/media/platform/apple/isp/isp-regs.h | 49 ++++++------- 5 files changed, 75 insertions(+), 69 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 094af7f7c33523..eb585d37d3239f 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -164,9 +164,15 @@ static int apple_isp_probe(struct platform_device *pdev) goto detach_genpd; } - isp->core = devm_platform_ioremap_resource_byname(pdev, "core"); - if (IS_ERR(isp->core)) { - err = PTR_ERR(isp->core); + isp->mbox = devm_platform_ioremap_resource_byname(pdev, "mbox"); + if (IS_ERR(isp->mbox)) { + err = PTR_ERR(isp->mbox); + goto detach_genpd; + } + + isp->gpio = devm_platform_ioremap_resource_byname(pdev, "gpio"); + if (IS_ERR(isp->gpio)) { + err = PTR_ERR(isp->gpio); goto detach_genpd; } diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 7b463eaef1c9ce..de9b3fd2def5ee 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -185,7 +185,8 @@ struct apple_isp { int irq; void __iomem *asc; - void __iomem *core; + void __iomem *mbox; + void __iomem *gpio; void __iomem *dart0; void __iomem *dart1; void __iomem *dart2; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 4315653a0510a0..1f01d175416174 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -27,6 +27,16 @@ static inline void isp_asc_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->asc + reg); } +static inline u32 isp_gpio_read32(struct apple_isp *isp, u32 reg) +{ + return readl(isp->gpio + reg); +} + +static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) +{ + writel(val, isp->gpio + reg); +} + struct isp_firmware_bootargs { u32 pad_0[2]; u64 ipc_iova; @@ -77,8 +87,8 @@ static irqreturn_t apple_isp_isr(int irq, void *dev) { struct apple_isp *isp = dev; - isp_core_write32(isp, ISP_CORE_IRQ_ACK, - isp_core_read32(isp, ISP_CORE_IRQ_INTERRUPT)); + isp_mbox_write32(isp, ISP_MBOX_IRQ_ACK, + isp_mbox_read32(isp, ISP_MBOX_IRQ_INTERRUPT)); wake_up_interruptible_all(&isp->wait); @@ -95,9 +105,9 @@ static irqreturn_t apple_isp_isr(int irq, void *dev) static void isp_disable_irq(struct apple_isp *isp) { - isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0x0); + isp_mbox_write32(isp, ISP_MBOX_IRQ_ENABLE, 0x0); free_irq(isp->irq, isp); - isp_core_write32(isp, ISP_CORE_GPIO_1, 0xfeedbabe); /* real funny */ + isp_gpio_write32(isp, ISP_GPIO_1, 0xfeedbabe); /* real funny */ } static int isp_enable_irq(struct apple_isp *isp) @@ -112,7 +122,7 @@ static int isp_enable_irq(struct apple_isp *isp) isp_dbg(isp, "about to enable interrupts...\n"); - isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0xf); + isp_mbox_write32(isp, ISP_MBOX_IRQ_ENABLE, 0xf); return 0; } @@ -166,26 +176,26 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) if (err < 0) return err; - isp_core_write32(isp, ISP_CORE_CLOCK_EN, 0x1); + isp_gpio_write32(isp, ISP_GPIO_CLOCK_EN, 0x1); - isp_core_write32(isp, ISP_CORE_GPIO_0, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_1, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_2, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_3, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_4, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_5, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_6, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_7, 0x0); + isp_gpio_write32(isp, ISP_GPIO_0, 0x0); + isp_gpio_write32(isp, ISP_GPIO_1, 0x0); + isp_gpio_write32(isp, ISP_GPIO_2, 0x0); + isp_gpio_write32(isp, ISP_GPIO_3, 0x0); + isp_gpio_write32(isp, ISP_GPIO_4, 0x0); + isp_gpio_write32(isp, ISP_GPIO_5, 0x0); + isp_gpio_write32(isp, ISP_GPIO_6, 0x0); + isp_gpio_write32(isp, ISP_GPIO_7, 0x0); - isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0x0); + isp_mbox_write32(isp, ISP_MBOX_IRQ_ENABLE, 0x0); isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); isp_asc_write32(isp, ISP_ASC_CONTROL, 0x10); - /* Wait for ISP_CORE_GPIO_7 to 0x0 -> 0x8042006 */ - isp_core_write32(isp, ISP_CORE_GPIO_7, 0x0); + /* Wait for ISP_GPIO_7 to 0x0 -> 0x8042006 */ + isp_gpio_write32(isp, ISP_GPIO_7, 0x0); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - u32 val = isp_core_read32(isp, ISP_CORE_GPIO_7); + u32 val = isp_gpio_read32(isp, ISP_GPIO_7); if (val == 0x8042006) { isp_dbg(isp, "got first magic number (0x%x) from firmware\n", @@ -216,9 +226,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) dma_addr_t args_iova; int err, retries; - u32 num_ipc_chans = isp_core_read32(isp, ISP_CORE_GPIO_0); - u32 args_offset = isp_core_read32(isp, ISP_CORE_GPIO_1); - u32 extra_size = isp_core_read32(isp, ISP_CORE_GPIO_3); + u32 num_ipc_chans = isp_gpio_read32(isp, ISP_GPIO_0); + u32 args_offset = isp_gpio_read32(isp, ISP_GPIO_1); + u32 extra_size = isp_gpio_read32(isp, ISP_GPIO_3); isp->num_ipc_chans = num_ipc_chans; if (!isp->num_ipc_chans) { @@ -265,14 +275,14 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.unk9 = 0x3; isp_iowrite(isp, args_iova, &args, sizeof(args)); - isp_core_write32(isp, ISP_CORE_GPIO_0, args_iova); - isp_core_write32(isp, ISP_CORE_GPIO_1, 0x0); + isp_gpio_write32(isp, ISP_GPIO_0, args_iova); + isp_gpio_write32(isp, ISP_GPIO_1, 0x0); - /* Wait for ISP_CORE_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ - isp_core_write32(isp, ISP_CORE_GPIO_7, 0xf7fbdff9); + /* Wait for ISP_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ + isp_gpio_write32(isp, ISP_GPIO_7, 0xf7fbdff9); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - u32 val = isp_core_read32(isp, ISP_CORE_GPIO_7); + u32 val = isp_gpio_read32(isp, ISP_GPIO_7); if (val == 0x8042006) { isp_dbg(isp, "got second magic number (0x%x) from firmware\n", @@ -325,7 +335,7 @@ static void isp_free_channel_info(struct apple_isp *isp) static int isp_fill_channel_info(struct apple_isp *isp) { - u32 table_iova = isp_core_read32(isp, ISP_CORE_GPIO_0); + u32 table_iova = isp_gpio_read32(isp, ISP_GPIO_0); isp->ipc_chans = kcalloc(isp->num_ipc_chans, sizeof(struct isp_channel *), GFP_KERNEL); @@ -417,11 +427,11 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp) } } - /* Wait for ISP_CORE_GPIO_3 to 0x8042006 -> 0x0 */ - isp_core_write32(isp, ISP_CORE_GPIO_3, 0x8042006); + /* Wait for ISP_GPIO_3 to 0x8042006 -> 0x0 */ + isp_gpio_write32(isp, ISP_GPIO_3, 0x8042006); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - u32 val = isp_core_read32(isp, ISP_CORE_GPIO_3); + u32 val = isp_gpio_read32(isp, ISP_GPIO_3); if (val == 0x0) { isp_dbg(isp, "got third magic number (0x%x) from firmware\n", @@ -446,14 +456,14 @@ static int isp_stop_command_processor(struct apple_isp *isp) { int retries; - /* Wait for ISP_CORE_GPIO_0 to 0xf7fbdff9 -> 0x8042006 */ - isp_core_write32(isp, ISP_CORE_GPIO_0, 0xf7fbdff9); + /* Wait for ISP_GPIO_0 to 0xf7fbdff9 -> 0x8042006 */ + isp_gpio_write32(isp, ISP_GPIO_0, 0xf7fbdff9); /* Their CISP_CMD_STOP implementation is buggy */ isp_cmd_suspend(isp); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - u32 val = isp_core_read32(isp, ISP_CORE_GPIO_0); + u32 val = isp_gpio_read32(isp, ISP_GPIO_0); if (val == 0x8042006) { isp_dbg(isp, "got magic number (0x%x) from firmware\n", val); diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index ef3498c4fcd191..a9a0fdb73a4d9f 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -110,7 +110,7 @@ static int chan_handle_once(struct apple_isp *isp, struct isp_channel *chan) chan_write_msg(isp, chan, &chan->rsp); - isp_core_write32(isp, ISP_CORE_IRQ_DOORBELL, chan->doorbell); + isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); chan_update_cursor(chan); @@ -165,7 +165,7 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, chan_write_msg(isp, chan, &chan->req); wmb(); - isp_core_write32(isp, ISP_CORE_IRQ_DOORBELL, chan->doorbell); + isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); t = wait_event_interruptible_timeout(isp->wait, chan_tx_done(isp, chan), timeout); diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h index b9bd505844d9de..e21485ec4ce823 100644 --- a/drivers/media/platform/apple/isp/isp-regs.h +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -23,40 +23,29 @@ #define ISP_ASC_IRQ_MASK_4 0x1400a10 #define ISP_ASC_IRQ_MASK_5 0x1400a14 -#define ISP_CORE_IRQ_INTERRUPT 0x2104000 -#define ISP_CORE_IRQ_ENABLE 0x2104004 -#define ISP_CORE_IRQ_DOORBELL 0x21043f0 -#define ISP_CORE_IRQ_ACK 0x21043fc - -#define ISP_CORE_GPIO_0 0x2104170 -#define ISP_CORE_GPIO_1 0x2104174 -#define ISP_CORE_GPIO_2 0x2104178 -#define ISP_CORE_GPIO_3 0x210417c -#define ISP_CORE_GPIO_4 0x2104180 -#define ISP_CORE_GPIO_5 0x2104184 -#define ISP_CORE_GPIO_6 0x2104188 -#define ISP_CORE_GPIO_7 0x210418c - -#define ISP_CORE_CLOCK_EN 0x2104190 - -#define ISP_CORE_DPE_CTRL_0 0x2504000 -#define ISP_CORE_DPE_CTRL_1 0x2508000 - -static inline u32 isp_core_read32(struct apple_isp *isp, u32 reg) +#define ISP_MBOX_IRQ_INTERRUPT 0x000 +#define ISP_MBOX_IRQ_ENABLE 0x004 +#define ISP_MBOX_IRQ_DOORBELL 0x3f0 +#define ISP_MBOX_IRQ_ACK 0x3fc + +#define ISP_GPIO_0 0x00 +#define ISP_GPIO_1 0x04 +#define ISP_GPIO_2 0x08 +#define ISP_GPIO_3 0x0c +#define ISP_GPIO_4 0x10 +#define ISP_GPIO_5 0x14 +#define ISP_GPIO_6 0x18 +#define ISP_GPIO_7 0x1c +#define ISP_GPIO_CLOCK_EN 0x20 + +static inline u32 isp_mbox_read32(struct apple_isp *isp, u32 reg) { - return readl(isp->core + reg - 0x2104000); // TODO this sucks + return readl(isp->mbox + reg); } -static inline void isp_core_write32(struct apple_isp *isp, u32 reg, u32 val) +static inline void isp_mbox_write32(struct apple_isp *isp, u32 reg, u32 val) { - writel(val, isp->core + reg - 0x2104000); -} - -static inline void isp_core_mask32(struct apple_isp *isp, u32 reg, u32 clear, - u32 set) -{ - isp_core_write32(isp, reg, isp_core_read32(isp, reg) & ~clear); - isp_core_write32(isp, reg, isp_core_read32(isp, reg) | set); + writel(val, isp->mbox + reg); } #endif /* __ISP_REGS_H__ */ From 62cc6d603116f2342176f34aa09a47620c343d4f Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 10 Sep 2023 23:36:12 +0900 Subject: [PATCH 285/352] media: apple: isp: Drop the DART mirroring stuff Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.c | 57 -------------------- drivers/media/platform/apple/isp/isp-drv.h | 8 --- drivers/media/platform/apple/isp/isp-iommu.c | 19 ------- drivers/media/platform/apple/isp/isp-iommu.h | 3 -- 4 files changed, 87 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index eb585d37d3239f..1829f36acdd5b8 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -126,8 +126,6 @@ static int apple_isp_init_iommu(struct apple_isp *isp) drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - heap_base); - apple_isp_iommu_sync_ttbr(isp); - return 0; } @@ -140,7 +138,6 @@ static int apple_isp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct apple_isp *isp; - struct resource *res; int err; isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); @@ -176,31 +173,6 @@ static int apple_isp_probe(struct platform_device *pdev) goto detach_genpd; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dart0"); - if (!res) { - err = -ENODEV; - goto detach_genpd; - } - - /* Simply ioremap since it's a shared register zone */ - isp->dart0 = devm_ioremap(dev, res->start, resource_size(res)); - if (IS_ERR(isp->dart0)) { - err = PTR_ERR(isp->dart0); - goto detach_genpd; - } - - isp->dart1 = devm_platform_ioremap_resource_byname(pdev, "dart1"); - if (IS_ERR(isp->dart1)) { - err = PTR_ERR(isp->dart1); - goto detach_genpd; - } - - isp->dart2 = devm_platform_ioremap_resource_byname(pdev, "dart2"); - if (IS_ERR(isp->dart2)) { - err = PTR_ERR(isp->dart2); - goto detach_genpd; - } - isp->irq = platform_get_irq(pdev, 0); if (isp->irq < 0) { err = isp->irq; @@ -270,12 +242,6 @@ static void apple_isp_remove(struct platform_device *pdev) return 0; } -/* T8020/T6000 registers */ -#define DART_T8020_STREAM_COMMAND 0x20 -#define DART_T8020_STREAM_SELECT 0x34 -#define DART_T8020_TTBR 0x200 -#define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20) - static const struct apple_isp_hw apple_isp_hw_t8103 = { .pmu_base = 0x23b704000, @@ -296,11 +262,6 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { .bandwidth_base = 0x23bc3c000, .bandwidth_bit = 0x0, .bandwidth_size = 0x4, - - .stream_command = DART_T8020_STREAM_COMMAND, - .stream_select = DART_T8020_STREAM_SELECT, - .ttbr = DART_T8020_TTBR, - .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, }; static const struct apple_isp_hw apple_isp_hw_t6000 = { @@ -323,11 +284,6 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, - - .stream_command = DART_T8020_STREAM_COMMAND, - .stream_select = DART_T8020_STREAM_SELECT, - .ttbr = DART_T8020_TTBR, - .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, }; static const struct apple_isp_hw apple_isp_hw_t8110 = { @@ -350,11 +306,6 @@ static const struct apple_isp_hw apple_isp_hw_t8110 = { .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, - - .stream_command = DART_T8020_STREAM_COMMAND, // TODO - .stream_select = DART_T8020_STREAM_SELECT, - .ttbr = DART_T8020_TTBR, - .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, }; static const struct of_device_id apple_isp_of_match[] = { @@ -366,19 +317,11 @@ MODULE_DEVICE_TABLE(of, apple_isp_of_match); static __maybe_unused int apple_isp_suspend(struct device *dev) { - struct apple_isp *isp = dev_get_drvdata(dev); - - apple_isp_iommu_invalidate_tlb(isp); - return 0; } static __maybe_unused int apple_isp_resume(struct device *dev) { - struct apple_isp *isp = dev_get_drvdata(dev); - - apple_isp_iommu_sync_ttbr(isp); - return 0; } DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, NULL); diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index de9b3fd2def5ee..bf3824cc0636b9 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -82,11 +82,6 @@ struct apple_isp_hw { u64 bandwidth_base; u8 bandwidth_bit; u8 bandwidth_size; - - u32 stream_command; - u32 stream_select; - u32 ttbr; - u32 stream_command_invalidate; }; struct isp_resv { @@ -187,9 +182,6 @@ struct apple_isp { void __iomem *asc; void __iomem *mbox; void __iomem *gpio; - void __iomem *dart0; - void __iomem *dart1; - void __iomem *dart2; struct iommu_domain *domain; unsigned long shift; diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c index 28935d37205024..0a9d0d6a350c9a 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.c +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -6,23 +6,6 @@ #include "isp-iommu.h" -void apple_isp_iommu_sync_ttbr(struct apple_isp *isp) -{ - writel(readl(isp->dart0 + isp->hw->ttbr), isp->dart1 + isp->hw->ttbr); - writel(readl(isp->dart0 + isp->hw->ttbr), isp->dart2 + isp->hw->ttbr); -} - -void apple_isp_iommu_invalidate_tlb(struct apple_isp *isp) -{ - iommu_flush_iotlb_all(isp->domain); - writel(0x1, isp->dart1 + isp->hw->stream_select); - writel(isp->hw->stream_command_invalidate, - isp->dart1 + isp->hw->stream_command); - writel(0x1, isp->dart2 + isp->hw->stream_select); - writel(isp->hw->stream_command_invalidate, - isp->dart2 + isp->hw->stream_command); -} - static void isp_surf_free_pages(struct isp_surf *surf) { for (u32 i = 0; i < surf->num_pages && surf->pages[i] != NULL; i++) { @@ -113,7 +96,6 @@ static int isp_surf_reserve_iova(struct apple_isp *isp, struct isp_surf *surf) static void isp_surf_iommu_unmap(struct apple_isp *isp, struct isp_surf *surf) { iommu_unmap(isp->domain, surf->iova, surf->size); - apple_isp_iommu_invalidate_tlb(isp); sg_free_table(&surf->sgt); } @@ -270,6 +252,5 @@ int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, void apple_isp_iommu_unmap_sgt(struct apple_isp *isp, struct isp_surf *surf) { iommu_unmap(isp->domain, surf->iova, surf->size); - apple_isp_iommu_invalidate_tlb(isp); isp_surf_unreserve_iova(isp, surf); } diff --git a/drivers/media/platform/apple/isp/isp-iommu.h b/drivers/media/platform/apple/isp/isp-iommu.h index f9972bd9ff93e7..326cf7c12aa745 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.h +++ b/drivers/media/platform/apple/isp/isp-iommu.h @@ -6,9 +6,6 @@ #include "isp-drv.h" -void apple_isp_iommu_sync_ttbr(struct apple_isp *isp); -void apple_isp_iommu_invalidate_tlb(struct apple_isp *isp); - struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc); #define isp_alloc_surface(isp, size) (__isp_alloc_surface(isp, size, false)) #define isp_alloc_surface_gc(isp, size) (__isp_alloc_surface(isp, size, true)) From 8fb2cd1a44d15dc4e974b0ffadfa4459cf1908be Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 11 Sep 2023 00:12:11 +0900 Subject: [PATCH 286/352] media: apple: isp: Do not defer on failure to initialize DART This can fail for non-DEFER reasons. If this can happen due to probe defers, we need to figure out some way to signal that specifically... Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 1829f36acdd5b8..00299fd89e6038 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -90,7 +90,7 @@ static int apple_isp_init_iommu(struct apple_isp *isp) isp->domain = iommu_get_domain_for_dev(isp->dev); if (!isp->domain) - return -EPROBE_DEFER; + return -ENODEV; isp->shift = __ffs(isp->domain->pgsize_bitmap); idx = of_property_match_string(dev->of_node, "memory-region-names", "heap"); From 56211259de17b487f3a38ae97be1820120496522 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 11 Sep 2023 02:06:05 +0900 Subject: [PATCH 287/352] media: apple: WIP: t6000 hax --- drivers/media/platform/apple/isp/isp-cam.c | 2 +- drivers/media/platform/apple/isp/isp-fw.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index bb90337cb7c19f..74125b3c652433 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -207,7 +207,7 @@ static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) args, sizeof(*args), false); err = isp_ch_get_sensor_id(isp, ch); - if (err || (fmt->id != ISP_IMX248_1820_01)) { + if (err || (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { dev_err(isp->dev, "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", ch); diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 1f01d175416174..2fc91a9c434e0e 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -268,8 +268,12 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.shared_size = 0x10000000 - isp->fw.heap_top; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; - args.unk4 = 0x1; + args.unk4 = 0x3; + //args.pad_40[1] = 0x3128000; + //args.pad_40[3] = 0x48000; + args.pad_40[5] = 0x90; args.unk5 = 0x40; + //args.pad_7c[3] = 0x3b54000; args.unk7 = 0x1; args.unk_iova1 = args_iova + ISP_FIRMWARE_BOOTARGS_SIZE - 0xc; args.unk9 = 0x3; From 90de85ec9b3e94d1a46c99393e38cdf9c74f2c3e Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 17:58:26 +0900 Subject: [PATCH 288/352] media: apple: isp: Set platform_id in bootargs Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 3 +++ drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-fw.c | 5 ++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 00299fd89e6038..8e6a846a867d00 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -243,6 +243,7 @@ static void apple_isp_remove(struct platform_device *pdev) } static const struct apple_isp_hw apple_isp_hw_t8103 = { + .platform_id = 0x1, .pmu_base = 0x23b704000, .dsid_clr_base0 = 0x200014000, @@ -265,6 +266,7 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { }; static const struct apple_isp_hw apple_isp_hw_t6000 = { + .platform_id = 0x3, .pmu_base = 0x28e584000, .dsid_clr_base0 = 0x200014000, @@ -287,6 +289,7 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { }; static const struct apple_isp_hw apple_isp_hw_t8110 = { + .platform_id = 0xe, // J413AP .pmu_base = 0x23b704000, .dsid_clr_base0 = 0x200014000, // TODO diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index bf3824cc0636b9..fb7a785b87c1c5 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -63,6 +63,7 @@ struct isp_channel { }; struct apple_isp_hw { + u32 platform_id; u64 pmu_base; u64 dsid_clr_base0; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 2fc91a9c434e0e..06e4d64cf05e73 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -44,7 +44,7 @@ struct isp_firmware_bootargs { u64 shared_size; u64 extra_iova; u64 extra_size; - u32 unk4; + u32 platform_id; u32 pad_40[7]; u32 ipc_size; u32 pad_60[5]; @@ -268,10 +268,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.shared_size = 0x10000000 - isp->fw.heap_top; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; - args.unk4 = 0x3; + args.platform_id = isp->hw->platform_id; //args.pad_40[1] = 0x3128000; //args.pad_40[3] = 0x48000; - args.pad_40[5] = 0x90; args.unk5 = 0x40; //args.pad_7c[3] = 0x3b54000; args.unk7 = 0x1; From 1c16e5dc3a77561417d3c211a459cb53804d2e10 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 18:49:25 +0900 Subject: [PATCH 289/352] media: apple: isp: Better document info struct fields "Document". I also counted wrong multiple times. Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-cmd.h | 64 +++++++++++++++++++--- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index dde6aad506c23e..1fc484fa687853 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -202,19 +202,53 @@ static_assert(sizeof(struct cmd_ch_stop) == 0xc); struct cmd_ch_info { u64 opcode; u32 chan; - u32 unk_c; - u32 unk_10[4]; + u32 unk_c; // 0x7da0001, 0x7db0001 + u32 unk_10; // 0x300ac, 0x5006d + u32 unk_14; // 0x40007, 0x10007 + u32 unk_18; // 0x5, 0x2 + u32 unk_1c; // 0x1, 0x1 u32 version; - u32 unk_24[3]; - u32 unk_30[12]; + u32 unk_24; // 0x7, 0x9 + u32 unk_28; // 0x1, 0x1410 + u32 unk_2c; // 0x7, 0x2 + u32 pad_30[7]; + u32 unk_4c; // 0x10000, 0x50000 + u32 unk_50; // 0x1, 0x1 + u32 unk_54; // 0x0, 0x0 + u32 unk_58; // 0x4, 0x4 + u32 unk_5c; // 0x10, 0x20 u32 num_presets; - u32 unk_64[7]; - u32 unk_80[6]; - u32 unk_98_freq; + u32 unk_64; // 0x0, 0x0 + u32 unk_68; // 0x44c0, 0x4680 + u32 unk_6c; // 0x40, 0x40 + u32 unk_70; // 0x1, 0x1 + u32 unk_74; // 0x2, 0x2 + u32 unk_78; // 0x4000, 0x4000 + u32 unk_7c; // 0x40, 0x40 + u32 unk_80; // 0x1, 0x1 + u32 pad_84[2]; + u32 unk_8c; // 0x36, 0x36 + u32 pad_90[2]; + u32 timestamp_freq; u16 pad_9c; char module_sn[20]; u16 pad_b0; - u32 unk_b4[25]; + u32 unk_b4; // 0x8, 0x8 + u32 pad_b8[2]; + u32 unk_c0; // 0x4, 0x1 + u32 unk_c4; // 0x0, 0x0 + u32 unk_c8; // 0x0, 0x100 + u32 pad_cc[4]; + u32 unk_dc; // 0xff0000, 0xff0000 + u32 unk_e0; // 0xc00, 0xc00 + u32 unk_e4; // 0x0, 0x0 + u32 unk_e8; // 0x1c, 0x1c + u32 unk_ec; // 0x640, 0x680 + u32 unk_f0; // 0x4, 0x4 + u32 unk_f4; // 0x4, 0x4 + u32 pad_f8[6]; + u32 unk_110; // 0x0, 0x7800000 + u32 unk_114; // 0x0, 0x780 } __packed; static_assert(sizeof(struct cmd_ch_info) == 0x118); @@ -226,7 +260,19 @@ struct cmd_ch_camera_config { u16 in_height; u16 out_width; u16 out_height; - u32 unk[49]; + u32 unk_28; + u32 unk_2c; + u32 unk_30[16]; + u32 sensor_clk; + u32 unk_64[4]; + u32 timestamp_freq; + u32 unk_78[2]; + u32 unk_80[16]; + u32 in_width2; // repeated in u32?? + u32 in_height2; + u32 unk_c8[3]; + u32 out_width2; + u32 out_height2; } __packed; static_assert(sizeof(struct cmd_ch_camera_config) == 0xdc); From e62a887c72e116c6fe189a7fd5945b89ca906f17 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 19:44:52 +0900 Subject: [PATCH 290/352] media: apple: isp: Don't use define for bootargs size Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-fw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 06e4d64cf05e73..1d1bbc119cd700 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -13,7 +13,6 @@ #define ISP_FIRMWARE_MDELAY 1 #define ISP_FIRMWARE_MAX_TRIES 1000 -#define ISP_FIRMWARE_BOOTARGS_SIZE 0x180 #define ISP_FIRMWARE_IPC_SIZE 0x1c000 #define ISP_FIRMWARE_DATA_SIZE 0x28000 @@ -57,8 +56,7 @@ struct isp_firmware_bootargs { u32 pad_c0[47]; u32 unk9; } __packed; -static_assert(sizeof(struct isp_firmware_bootargs) == - ISP_FIRMWARE_BOOTARGS_SIZE); +static_assert(sizeof(struct isp_firmware_bootargs) == 0x180); struct isp_chan_desc { char name[64]; @@ -274,7 +272,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.unk5 = 0x40; //args.pad_7c[3] = 0x3b54000; args.unk7 = 0x1; - args.unk_iova1 = args_iova + ISP_FIRMWARE_BOOTARGS_SIZE - 0xc; + args.unk_iova1 = args_iova + sizeof(args) - 0xc; args.unk9 = 0x3; isp_iowrite(isp, args_iova, &args, sizeof(args)); From 79d38b001ccf18ff74cfd8ccbe7f357ec279dea8 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 19:53:11 +0900 Subject: [PATCH 291/352] media: apple: isp: wmb() before GPIO write Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 1d1bbc119cd700..9cbeb74cf96601 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -278,6 +278,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) isp_gpio_write32(isp, ISP_GPIO_0, args_iova); isp_gpio_write32(isp, ISP_GPIO_1, 0x0); + wmb(); /* Wait for ISP_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ isp_gpio_write32(isp, ISP_GPIO_7, 0xf7fbdff9); From 1841ca03ad503676f59578d5395da8aa8e783758 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 20:05:34 +0900 Subject: [PATCH 292/352] media: apple: isp: s/asc/coproc/ Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 6 +-- drivers/media/platform/apple/isp/isp-drv.h | 2 +- drivers/media/platform/apple/isp/isp-fw.c | 46 ++++++++++----------- drivers/media/platform/apple/isp/isp-regs.h | 32 +++++++------- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 8e6a846a867d00..7ade4b6f330371 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -155,9 +155,9 @@ static int apple_isp_probe(struct platform_device *pdev) return err; } - isp->asc = devm_platform_ioremap_resource_byname(pdev, "asc"); - if (IS_ERR(isp->asc)) { - err = PTR_ERR(isp->asc); + isp->coproc = devm_platform_ioremap_resource_byname(pdev, "coproc"); + if (IS_ERR(isp->coproc)) { + err = PTR_ERR(isp->coproc); goto detach_genpd; } diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index fb7a785b87c1c5..ed567c06d8dccf 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -180,7 +180,7 @@ struct apple_isp { int irq; - void __iomem *asc; + void __iomem *coproc; void __iomem *mbox; void __iomem *gpio; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 9cbeb74cf96601..064626c8ed8dec 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -10,20 +10,20 @@ #include "isp-ipc.h" #include "isp-regs.h" -#define ISP_FIRMWARE_MDELAY 1 -#define ISP_FIRMWARE_MAX_TRIES 1000 +#define ISP_FIRMWARE_MDELAY 1 +#define ISP_FIRMWARE_MAX_TRIES 1000 -#define ISP_FIRMWARE_IPC_SIZE 0x1c000 -#define ISP_FIRMWARE_DATA_SIZE 0x28000 +#define ISP_FIRMWARE_IPC_SIZE 0x1c000 +#define ISP_FIRMWARE_DATA_SIZE 0x28000 -static inline u32 isp_asc_read32(struct apple_isp *isp, u32 reg) +static inline u32 isp_coproc_read32(struct apple_isp *isp, u32 reg) { - return readl(isp->asc + reg); + return readl(isp->coproc + reg); } -static inline void isp_asc_write32(struct apple_isp *isp, u32 reg, u32 val) +static inline void isp_coproc_write32(struct apple_isp *isp, u32 reg, u32 val) { - writel(val, isp->asc + reg); + writel(val, isp->coproc + reg); } static inline u32 isp_gpio_read32(struct apple_isp *isp, u32 reg) @@ -130,22 +130,22 @@ static int isp_coproc_ready(struct apple_isp *isp) int retries; u32 status; - isp_asc_write32(isp, ISP_ASC_EDPRCR, 0x2); + isp_coproc_write32(isp, ISP_COPROC_EDPRCR, 0x2); - isp_asc_write32(isp, ISP_ASC_PMGR_0, 0xff00ff); - isp_asc_write32(isp, ISP_ASC_PMGR_1, 0xff00ff); - isp_asc_write32(isp, ISP_ASC_PMGR_2, 0xff00ff); - isp_asc_write32(isp, ISP_ASC_PMGR_3, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_PMGR_0, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_PMGR_1, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_PMGR_2, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_PMGR_3, 0xff00ff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_0, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_1, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_2, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_3, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_4, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_5, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_0, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_1, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_2, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_3, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_4, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_5, 0xffffffff); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - status = isp_asc_read32(isp, ISP_ASC_STATUS); + status = isp_coproc_read32(isp, ISP_COPROC_STATUS); if (!((status & 0x3) == 0)) { isp_dbg(isp, "%d: coproc in WFI (status: 0x%x)\n", retries, status); @@ -163,7 +163,7 @@ static int isp_coproc_ready(struct apple_isp *isp) static void isp_firmware_shutdown_stage1(struct apple_isp *isp) { - isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); + isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x0); } static int isp_firmware_boot_stage1(struct apple_isp *isp) @@ -187,8 +187,8 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) isp_mbox_write32(isp, ISP_MBOX_IRQ_ENABLE, 0x0); - isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); - isp_asc_write32(isp, ISP_ASC_CONTROL, 0x10); + isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x0); + isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x10); /* Wait for ISP_GPIO_7 to 0x0 -> 0x8042006 */ isp_gpio_write32(isp, ISP_GPIO_7, 0x0); diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h index e21485ec4ce823..b3032e9112c012 100644 --- a/drivers/media/platform/apple/isp/isp-regs.h +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -6,22 +6,22 @@ #include "isp-drv.h" -#define ISP_ASC_PMGR_0 0x738 -#define ISP_ASC_PMGR_1 0x798 -#define ISP_ASC_PMGR_2 0x7f8 -#define ISP_ASC_PMGR_3 0x858 - -#define ISP_ASC_RVBAR 0x1050000 -#define ISP_ASC_EDPRCR 0x1010310 -#define ISP_ASC_CONTROL 0x1400044 -#define ISP_ASC_STATUS 0x1400048 - -#define ISP_ASC_IRQ_MASK_0 0x1400a00 -#define ISP_ASC_IRQ_MASK_1 0x1400a04 -#define ISP_ASC_IRQ_MASK_2 0x1400a08 -#define ISP_ASC_IRQ_MASK_3 0x1400a0c -#define ISP_ASC_IRQ_MASK_4 0x1400a10 -#define ISP_ASC_IRQ_MASK_5 0x1400a14 +#define ISP_COPROC_PMGR_0 0x738 +#define ISP_COPROC_PMGR_1 0x798 +#define ISP_COPROC_PMGR_2 0x7f8 +#define ISP_COPROC_PMGR_3 0x858 + +#define ISP_COPROC_RVBAR 0x1050000 +#define ISP_COPROC_EDPRCR 0x1010310 +#define ISP_COPROC_CONTROL 0x1400044 +#define ISP_COPROC_STATUS 0x1400048 + +#define ISP_COPROC_IRQ_MASK_0 0x1400a00 +#define ISP_COPROC_IRQ_MASK_1 0x1400a04 +#define ISP_COPROC_IRQ_MASK_2 0x1400a08 +#define ISP_COPROC_IRQ_MASK_3 0x1400a0c +#define ISP_COPROC_IRQ_MASK_4 0x1400a10 +#define ISP_COPROC_IRQ_MASK_5 0x1400a14 #define ISP_MBOX_IRQ_INTERRUPT 0x000 #define ISP_MBOX_IRQ_ENABLE 0x004 From 92a877a28269bab287b05f746d87ce143d804583 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 18:26:09 +0900 Subject: [PATCH 293/352] media: apple: isp: rm unused bootargs members Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-fw.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 064626c8ed8dec..3d0d550ff52183 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -267,10 +267,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; args.platform_id = isp->hw->platform_id; - //args.pad_40[1] = 0x3128000; - //args.pad_40[3] = 0x48000; args.unk5 = 0x40; - //args.pad_7c[3] = 0x3b54000; args.unk7 = 0x1; args.unk_iova1 = args_iova + sizeof(args) - 0xc; args.unk9 = 0x3; From 77ec022bd2d5bbdbedf26dd1854215dfa9194e5a Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 19:17:46 +0900 Subject: [PATCH 294/352] media: apple: isp: rm old isp_resv struct Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index ed567c06d8dccf..e672c62c0ec41c 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -85,12 +85,6 @@ struct apple_isp_hw { u8 bandwidth_size; }; -struct isp_resv { - phys_addr_t phys; - dma_addr_t iova; - u64 size; -}; - enum isp_sensor_id { ISP_IMX248_1820_01, ISP_IMX248_1822_02, From d9871cf1743ff1a146c6bf434447a37c5971415c Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 19:32:24 +0900 Subject: [PATCH 295/352] media: apple: isp: misc isp-fw.c improvements Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-fw.c | 19 +++++++++++-------- drivers/media/platform/apple/isp/isp-regs.h | 8 ++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 3d0d550ff52183..57c1db6aee3dbc 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -16,6 +16,8 @@ #define ISP_FIRMWARE_IPC_SIZE 0x1c000 #define ISP_FIRMWARE_DATA_SIZE 0x28000 +#define ISP_COPROC_IN_WFI 0x3 + static inline u32 isp_coproc_read32(struct apple_isp *isp, u32 reg) { return readl(isp->coproc + reg); @@ -125,17 +127,17 @@ static int isp_enable_irq(struct apple_isp *isp) return 0; } -static int isp_coproc_ready(struct apple_isp *isp) +static int isp_reset_coproc(struct apple_isp *isp) { int retries; u32 status; isp_coproc_write32(isp, ISP_COPROC_EDPRCR, 0x2); - isp_coproc_write32(isp, ISP_COPROC_PMGR_0, 0xff00ff); - isp_coproc_write32(isp, ISP_COPROC_PMGR_1, 0xff00ff); - isp_coproc_write32(isp, ISP_COPROC_PMGR_2, 0xff00ff); - isp_coproc_write32(isp, ISP_COPROC_PMGR_3, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_FABRIC_0, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_FABRIC_1, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_FABRIC_2, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_FABRIC_3, 0xff00ff); isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_0, 0xffffffff); isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_1, 0xffffffff); @@ -146,7 +148,7 @@ static int isp_coproc_ready(struct apple_isp *isp) for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { status = isp_coproc_read32(isp, ISP_COPROC_STATUS); - if (!((status & 0x3) == 0)) { + if (status & ISP_COPROC_IN_WFI) { isp_dbg(isp, "%d: coproc in WFI (status: 0x%x)\n", retries, status); break; @@ -170,7 +172,7 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) { int err, retries; - err = isp_coproc_ready(isp); + err = isp_reset_coproc(isp); if (err < 0) return err; @@ -263,7 +265,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.ipc_iova = isp->ipc_surf->iova; args.ipc_size = isp->ipc_surf->size; args.shared_base = isp->fw.heap_top; - args.shared_size = 0x10000000 - isp->fw.heap_top; + args.shared_size = 0x10000000UL - isp->fw.heap_top; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; args.platform_id = isp->hw->platform_id; @@ -425,6 +427,7 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp) isp_iowrite(isp, msg_iova, &msg, sizeof(msg)); } } + wmb(); /* Wait for ISP_GPIO_3 to 0x8042006 -> 0x0 */ isp_gpio_write32(isp, ISP_GPIO_3, 0x8042006); diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h index b3032e9112c012..3a99229f6d4c8f 100644 --- a/drivers/media/platform/apple/isp/isp-regs.h +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -6,10 +6,10 @@ #include "isp-drv.h" -#define ISP_COPROC_PMGR_0 0x738 -#define ISP_COPROC_PMGR_1 0x798 -#define ISP_COPROC_PMGR_2 0x7f8 -#define ISP_COPROC_PMGR_3 0x858 +#define ISP_COPROC_FABRIC_0 0x738 +#define ISP_COPROC_FABRIC_1 0x798 +#define ISP_COPROC_FABRIC_2 0x7f8 +#define ISP_COPROC_FABRIC_3 0x858 #define ISP_COPROC_RVBAR 0x1050000 #define ISP_COPROC_EDPRCR 0x1010310 From 879148775ac1116696e8979968e502afa2b748ca Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 20:06:55 +0900 Subject: [PATCH 296/352] media: apple: isp: alloc static surfaces only once Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 16 ++++++-- drivers/media/platform/apple/isp/isp-fw.c | 47 +++++++++++++--------- drivers/media/platform/apple/isp/isp-fw.h | 3 ++ 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 7ade4b6f330371..c188724b4d773b 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -19,6 +19,7 @@ #include #include "isp-cam.h" +#include "isp-fw.h" #include "isp-iommu.h" #include "isp-v4l2.h" @@ -202,26 +203,34 @@ static int apple_isp_probe(struct platform_device *pdev) goto destroy_wq; } + err = apple_isp_alloc_firmware_surface(isp); + if (err) { + dev_err(dev, "failed to alloc firmware surface: %d\n", err); + goto free_iommu; + } + pm_runtime_enable(dev); err = apple_isp_detect_camera(isp); if (err) { dev_err(dev, "failed to detect camera: %d\n", err); - goto free_iommu; + goto free_surface; } err = apple_isp_setup_video(isp); if (err) { dev_err(dev, "failed to register video device: %d\n", err); - goto free_iommu; + goto free_surface; } dev_info(dev, "apple-isp probe!\n"); return 0; -free_iommu: +free_surface: pm_runtime_disable(dev); + apple_isp_free_firmware_surface(isp); +free_iommu: apple_isp_free_iommu(isp); destroy_wq: destroy_workqueue(isp->wq); @@ -236,6 +245,7 @@ static void apple_isp_remove(struct platform_device *pdev) apple_isp_remove_video(isp); pm_runtime_disable(isp->dev); + apple_isp_free_firmware_surface(isp); apple_isp_free_iommu(isp); destroy_workqueue(isp->wq); apple_isp_detach_genpd(isp); diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 57c1db6aee3dbc..93e18df1cf41c1 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -213,13 +213,36 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) return 0; } -static void isp_firmware_shutdown_stage2(struct apple_isp *isp) +int apple_isp_alloc_firmware_surface(struct apple_isp *isp) +{ + /* These are static, so let's do it once and for all */ + isp->ipc_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_IPC_SIZE); + if (!isp->ipc_surf) { + isp_err(isp, "failed to alloc shared surface for ipc\n"); + return -ENOMEM; + } + + isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE); + if (!isp->data_surf) { + isp_err(isp, "failed to alloc shared surface for data files\n"); + isp_free_surface(isp, isp->ipc_surf); + return -ENOMEM; + } + + return 0; +} + +void apple_isp_free_firmware_surface(struct apple_isp *isp) { isp_free_surface(isp, isp->data_surf); - isp_free_surface(isp, isp->extra_surf); isp_free_surface(isp, isp->ipc_surf); } +static void isp_firmware_shutdown_stage2(struct apple_isp *isp) +{ + isp_free_surface(isp, isp->extra_surf); +} + static int isp_firmware_boot_stage2(struct apple_isp *isp) { struct isp_firmware_bootargs args; @@ -240,22 +263,10 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) dev_warn(isp->dev, "unexpected channel count (%d)\n", num_ipc_chans); - isp->ipc_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_IPC_SIZE); - if (!isp->ipc_surf) { - isp_err(isp, "failed to alloc surface for ipc\n"); - return -ENOMEM; - } - isp->extra_surf = isp_alloc_surface_vmap(isp, extra_size); if (!isp->extra_surf) { isp_err(isp, "failed to alloc surface for extra heap\n"); - goto free_ipc; - } - - isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE); - if (!isp->data_surf) { - isp_err(isp, "failed to alloc surface for data files\n"); - goto free_extra; + return -ENOMEM; } args_iova = isp->ipc_surf->iova + args_offset + 0x40; @@ -296,17 +307,13 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) isp_err(isp, "never received second magic number from firmware\n"); err = -ENODEV; - goto free_file; + goto free_extra; } return 0; -free_file: - isp_free_surface(isp, isp->data_surf); free_extra: isp_free_surface(isp, isp->extra_surf); -free_ipc: - isp_free_surface(isp, isp->ipc_surf); return err; } diff --git a/drivers/media/platform/apple/isp/isp-fw.h b/drivers/media/platform/apple/isp/isp-fw.h index ad9f4fdf641aaa..264717793cea02 100644 --- a/drivers/media/platform/apple/isp/isp-fw.h +++ b/drivers/media/platform/apple/isp/isp-fw.h @@ -6,6 +6,9 @@ #include "isp-drv.h" +int apple_isp_alloc_firmware_surface(struct apple_isp *isp); +void apple_isp_free_firmware_surface(struct apple_isp *isp); + int apple_isp_firmware_boot(struct apple_isp *isp); void apple_isp_firmware_shutdown(struct apple_isp *isp); From b537704228dede2e928556a43142e769e84e8423 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 20:32:02 +0900 Subject: [PATCH 297/352] media: apple: isp: fix copyright Not really anymore. Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index c188724b4d773b..936543681cc588 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -3,10 +3,6 @@ * Apple Image Signal Processor driver * * Copyright (C) 2023 The Asahi Linux Contributors - * - * Based on aspeed/aspeed-video.c - * Copyright 2020 IBM Corp. - * Copyright (c) 2019-2020 Intel Corporation */ #include From ea1d8ea146083e1beae8ebba03a97a558205cec6 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sun, 24 Sep 2023 01:01:59 +0900 Subject: [PATCH 298/352] media: apple: isp: Support >32bit VAs for t602x Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-drv.c | 7 ++++++- drivers/media/platform/apple/isp/isp-fw.c | 9 +++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 936543681cc588..109a40a18219bd 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -121,7 +121,8 @@ static int apple_isp_init_iommu(struct apple_isp *isp) return err; } - drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - heap_base); + // FIXME: refactor this, maybe use regular iova stuff? + drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - (heap_base & 0xffffffff)); return 0; } @@ -137,6 +138,10 @@ static int apple_isp_probe(struct platform_device *pdev) struct apple_isp *isp; int err; + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(42)); + if (err) + return err; + isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); if (!isp) return -ENOMEM; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 93e18df1cf41c1..70ffaa97cd260a 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -275,8 +275,8 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) memset(&args, 0, sizeof(args)); args.ipc_iova = isp->ipc_surf->iova; args.ipc_size = isp->ipc_surf->size; - args.shared_base = isp->fw.heap_top; - args.shared_size = 0x10000000UL - isp->fw.heap_top; + args.shared_base = isp->fw.heap_top & 0xffffffff; + args.shared_size = 0x10000000UL - args.shared_base; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; args.platform_id = isp->hw->platform_id; @@ -287,7 +287,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) isp_iowrite(isp, args_iova, &args, sizeof(args)); isp_gpio_write32(isp, ISP_GPIO_0, args_iova); - isp_gpio_write32(isp, ISP_GPIO_1, 0x0); + isp_gpio_write32(isp, ISP_GPIO_1, args_iova >> 32); wmb(); /* Wait for ISP_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ @@ -343,7 +343,8 @@ static void isp_free_channel_info(struct apple_isp *isp) static int isp_fill_channel_info(struct apple_isp *isp) { - u32 table_iova = isp_gpio_read32(isp, ISP_GPIO_0); + u64 table_iova = isp_gpio_read32(isp, ISP_GPIO_0) | + ((u64)isp_gpio_read32(isp, ISP_GPIO_1)) << 32; isp->ipc_chans = kcalloc(isp->num_ipc_chans, sizeof(struct isp_channel *), GFP_KERNEL); From aeb0555489ed666a02007090926b5df8109b0c1a Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sun, 24 Sep 2023 01:02:41 +0900 Subject: [PATCH 299/352] media: apple: isp: t602x hw config Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-drv.c | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 109a40a18219bd..91dd1cb607076b 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -322,9 +322,33 @@ static const struct apple_isp_hw apple_isp_hw_t8110 = { .bandwidth_size = 0x8, }; +static const struct apple_isp_hw apple_isp_hw_t6020 = { + .platform_id = 0x7, // J416cAP + .pmu_base = 0x290284000, + + .dsid_clr_base0 = 0x200014000, // TODO + .dsid_clr_base1 = 0x200054000, + .dsid_clr_base2 = 0x200094000, + .dsid_clr_base3 = 0x2000d4000, + .dsid_clr_range0 = 0x1000, + .dsid_clr_range1 = 0x1000, + .dsid_clr_range2 = 0x1000, + .dsid_clr_range3 = 0x1000, + + .clock_scratch = 0x28e3d0868, // CHECK + .clock_base = 0x0, + .clock_bit = 0x0, + .clock_size = 0x8, + .bandwidth_scratch = 0x28e3d0980, // CHECK + .bandwidth_base = 0x0, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x8, +}; + static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, { .compatible = "apple,t6000-isp", .data = &apple_isp_hw_t6000 }, + { .compatible = "apple,t6020-isp", .data = &apple_isp_hw_t6020 }, {}, }; MODULE_DEVICE_TABLE(of, apple_isp_of_match); From 4214952bb28138c86040c6508bf04fd31e0bd440 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sun, 24 Sep 2023 01:03:11 +0900 Subject: [PATCH 300/352] media: apple: isp: Working t602x and multiple formats and more fixes Sorry for the horrible big commit... Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 256 ++++++--------- drivers/media/platform/apple/isp/isp-cmd.c | 94 +++++- drivers/media/platform/apple/isp/isp-cmd.h | 106 +++++- drivers/media/platform/apple/isp/isp-drv.c | 145 ++++++-- drivers/media/platform/apple/isp/isp-drv.h | 43 ++- drivers/media/platform/apple/isp/isp-fw.c | 30 +- drivers/media/platform/apple/isp/isp-ipc.c | 9 +- drivers/media/platform/apple/isp/isp-v4l2.c | 345 ++++++++++++++------ 8 files changed, 695 insertions(+), 333 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 74125b3c652433..593b780ab73b15 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -8,6 +8,8 @@ #include "isp-fw.h" #include "isp-iommu.h" +#define ISP_MAX_PRESETS 32 + struct isp_setfile { u32 version; u32 magic; @@ -15,74 +17,56 @@ struct isp_setfile { size_t size; }; -struct isp_preset { - u32 index; - u32 width; - u32 height; - u32 x1; - u32 y1; - u32 x2; - u32 y2; - u32 orig_width; - u32 orig_height; -}; - // clang-format off static const struct isp_setfile isp_setfiles[] = { - [ISP_IMX248_1820_01] = {0x248, 0x18200103, "isp/1820_01XX.dat", 0x442c}, - [ISP_IMX248_1822_02] = {0x248, 0x18220201, "isp/1822_02XX.dat", 0x442c}, - [ISP_IMX343_5221_02] = {0x343, 0x52210211, "isp/5221_02XX.dat", 0x4870}, - [ISP_IMX354_9251_02] = {0x354, 0x92510208, "isp/9251_02XX.dat", 0xa5ec}, - [ISP_IMX356_4820_01] = {0x356, 0x48200107, "isp/4820_01XX.dat", 0x9324}, - [ISP_IMX356_4820_02] = {0x356, 0x48200206, "isp/4820_02XX.dat", 0x9324}, - [ISP_IMX364_8720_01] = {0x364, 0x87200103, "isp/8720_01XX.dat", 0x36ac}, - [ISP_IMX364_8723_01] = {0x364, 0x87230101, "isp/8723_01XX.dat", 0x361c}, - [ISP_IMX372_3820_01] = {0x372, 0x38200108, "isp/3820_01XX.dat", 0xfdb0}, - [ISP_IMX372_3820_02] = {0x372, 0x38200205, "isp/3820_02XX.dat", 0xfdb0}, - [ISP_IMX372_3820_11] = {0x372, 0x38201104, "isp/3820_11XX.dat", 0xfdb0}, - [ISP_IMX372_3820_12] = {0x372, 0x38201204, "isp/3820_12XX.dat", 0xfdb0}, - [ISP_IMX405_9720_01] = {0x405, 0x97200102, "isp/9720_01XX.dat", 0x92c8}, - [ISP_IMX405_9721_01] = {0x405, 0x97210102, "isp/9721_01XX.dat", 0x9818}, - [ISP_IMX405_9723_01] = {0x405, 0x97230101, "isp/9723_01XX.dat", 0x92c8}, - [ISP_IMX414_2520_01] = {0x414, 0x25200102, "isp/2520_01XX.dat", 0xa444}, - [ISP_IMX503_7820_01] = {0x503, 0x78200109, "isp/7820_01XX.dat", 0xb268}, - [ISP_IMX503_7820_02] = {0x503, 0x78200206, "isp/7820_02XX.dat", 0xb268}, - [ISP_IMX505_3921_01] = {0x505, 0x39210102, "isp/3921_01XX.dat", 0x89b0}, - [ISP_IMX514_2820_01] = {0x514, 0x28200108, "isp/2820_01XX.dat", 0xa198}, - [ISP_IMX514_2820_02] = {0x514, 0x28200205, "isp/2820_02XX.dat", 0xa198}, - [ISP_IMX514_2820_03] = {0x514, 0x28200305, "isp/2820_03XX.dat", 0xa198}, - [ISP_IMX514_2820_04] = {0x514, 0x28200405, "isp/2820_04XX.dat", 0xa198}, - [ISP_IMX558_1921_01] = {0x558, 0x19210106, "isp/1921_01XX.dat", 0xad40}, - [ISP_IMX558_1922_02] = {0x558, 0x19220201, "isp/1922_02XX.dat", 0xad40}, - [ISP_IMX603_7920_01] = {0x603, 0x79200109, "isp/7920_01XX.dat", 0xad2c}, - [ISP_IMX603_7920_02] = {0x603, 0x79200205, "isp/7920_02XX.dat", 0xad2c}, - [ISP_IMX603_7921_01] = {0x603, 0x79210104, "isp/7921_01XX.dat", 0xad90}, - [ISP_IMX613_4920_01] = {0x613, 0x49200108, "isp/4920_01XX.dat", 0x9324}, - [ISP_IMX613_4920_02] = {0x613, 0x49200204, "isp/4920_02XX.dat", 0x9324}, - [ISP_IMX614_2921_01] = {0x614, 0x29210107, "isp/2921_01XX.dat", 0xed6c}, - [ISP_IMX614_2921_02] = {0x614, 0x29210202, "isp/2921_02XX.dat", 0xed6c}, - [ISP_IMX614_2922_02] = {0x614, 0x29220201, "isp/2922_02XX.dat", 0xed6c}, - [ISP_IMX633_3622_01] = {0x633, 0x36220111, "isp/3622_01XX.dat", 0x100d4}, - [ISP_IMX703_7721_01] = {0x703, 0x77210106, "isp/7721_01XX.dat", 0x936c}, - [ISP_IMX703_7722_01] = {0x703, 0x77220106, "isp/7722_01XX.dat", 0xac20}, - [ISP_IMX713_4721_01] = {0x713, 0x47210107, "isp/4721_01XX.dat", 0x936c}, - [ISP_IMX713_4722_01] = {0x713, 0x47220109, "isp/4722_01XX.dat", 0x9218}, - [ISP_IMX714_2022_01] = {0x714, 0x20220107, "isp/2022_01XX.dat", 0xa198}, - [ISP_IMX772_3721_01] = {0x772, 0x37210106, "isp/3721_01XX.dat", 0xfdf8}, - [ISP_IMX772_3721_11] = {0x772, 0x37211106, "isp/3721_11XX.dat", 0xfe14}, - [ISP_IMX772_3722_01] = {0x772, 0x37220104, "isp/3722_01XX.dat", 0xfca4}, - [ISP_IMX772_3723_01] = {0x772, 0x37230106, "isp/3723_01XX.dat", 0xfca4}, - [ISP_IMX814_2123_01] = {0x814, 0x21230101, "isp/2123_01XX.dat", 0xed54}, - [ISP_IMX853_7622_01] = {0x853, 0x76220112, "isp/7622_01XX.dat", 0x247f8}, - [ISP_IMX913_7523_01] = {0x913, 0x75230107, "isp/7523_01XX.dat", 0x247f8}, - [ISP_VD56G0_6221_01] = {0xd56, 0x62210102, "isp/6221_01XX.dat", 0x1b80}, - [ISP_VD56G0_6222_01] = {0xd56, 0x62220102, "isp/6222_01XX.dat", 0x1b80}, -}; - -// one day we will do this intelligently -static const struct isp_preset isp_presets[] = { - [ISP_IMX248_1820_01] = {0, 1280, 720, 8, 8, 1280, 720, 1296, 736}, // J293AP - [ISP_IMX558_1921_01] = {1, 1920, 1080, 0, 0, 1920, 1080, 1920, 1080}, // J316sAP, J415AP + [ISP_IMX248_1820_01] = {0x248, 0x18200103, "apple/isp_1820_01XX.dat", 0x442c}, + [ISP_IMX248_1822_02] = {0x248, 0x18220201, "apple/isp_1822_02XX.dat", 0x442c}, + [ISP_IMX343_5221_02] = {0x343, 0x52210211, "apple/isp_5221_02XX.dat", 0x4870}, + [ISP_IMX354_9251_02] = {0x354, 0x92510208, "apple/isp_9251_02XX.dat", 0xa5ec}, + [ISP_IMX356_4820_01] = {0x356, 0x48200107, "apple/isp_4820_01XX.dat", 0x9324}, + [ISP_IMX356_4820_02] = {0x356, 0x48200206, "apple/isp_4820_02XX.dat", 0x9324}, + [ISP_IMX364_8720_01] = {0x364, 0x87200103, "apple/isp_8720_01XX.dat", 0x36ac}, + [ISP_IMX364_8723_01] = {0x364, 0x87230101, "apple/isp_8723_01XX.dat", 0x361c}, + [ISP_IMX372_3820_01] = {0x372, 0x38200108, "apple/isp_3820_01XX.dat", 0xfdb0}, + [ISP_IMX372_3820_02] = {0x372, 0x38200205, "apple/isp_3820_02XX.dat", 0xfdb0}, + [ISP_IMX372_3820_11] = {0x372, 0x38201104, "apple/isp_3820_11XX.dat", 0xfdb0}, + [ISP_IMX372_3820_12] = {0x372, 0x38201204, "apple/isp_3820_12XX.dat", 0xfdb0}, + [ISP_IMX405_9720_01] = {0x405, 0x97200102, "apple/isp_9720_01XX.dat", 0x92c8}, + [ISP_IMX405_9721_01] = {0x405, 0x97210102, "apple/isp_9721_01XX.dat", 0x9818}, + [ISP_IMX405_9723_01] = {0x405, 0x97230101, "apple/isp_9723_01XX.dat", 0x92c8}, + [ISP_IMX414_2520_01] = {0x414, 0x25200102, "apple/isp_2520_01XX.dat", 0xa444}, + [ISP_IMX503_7820_01] = {0x503, 0x78200109, "apple/isp_7820_01XX.dat", 0xb268}, + [ISP_IMX503_7820_02] = {0x503, 0x78200206, "apple/isp_7820_02XX.dat", 0xb268}, + [ISP_IMX505_3921_01] = {0x505, 0x39210102, "apple/isp_3921_01XX.dat", 0x89b0}, + [ISP_IMX514_2820_01] = {0x514, 0x28200108, "apple/isp_2820_01XX.dat", 0xa198}, + [ISP_IMX514_2820_02] = {0x514, 0x28200205, "apple/isp_2820_02XX.dat", 0xa198}, + [ISP_IMX514_2820_03] = {0x514, 0x28200305, "apple/isp_2820_03XX.dat", 0xa198}, + [ISP_IMX514_2820_04] = {0x514, 0x28200405, "apple/isp_2820_04XX.dat", 0xa198}, + [ISP_IMX558_1921_01] = {0x558, 0x19210106, "apple/isp_1921_01XX.dat", 0xad40}, + [ISP_IMX558_1922_02] = {0x558, 0x19220201, "apple/isp_1922_02XX.dat", 0xad40}, + [ISP_IMX603_7920_01] = {0x603, 0x79200109, "apple/isp_7920_01XX.dat", 0xad2c}, + [ISP_IMX603_7920_02] = {0x603, 0x79200205, "apple/isp_7920_02XX.dat", 0xad2c}, + [ISP_IMX603_7921_01] = {0x603, 0x79210104, "apple/isp_7921_01XX.dat", 0xad90}, + [ISP_IMX613_4920_01] = {0x613, 0x49200108, "apple/isp_4920_01XX.dat", 0x9324}, + [ISP_IMX613_4920_02] = {0x613, 0x49200204, "apple/isp_4920_02XX.dat", 0x9324}, + [ISP_IMX614_2921_01] = {0x614, 0x29210107, "apple/isp_2921_01XX.dat", 0xed6c}, + [ISP_IMX614_2921_02] = {0x614, 0x29210202, "apple/isp_2921_02XX.dat", 0xed6c}, + [ISP_IMX614_2922_02] = {0x614, 0x29220201, "apple/isp_2922_02XX.dat", 0xed6c}, + [ISP_IMX633_3622_01] = {0x633, 0x36220111, "apple/isp_3622_01XX.dat", 0x100d4}, + [ISP_IMX703_7721_01] = {0x703, 0x77210106, "apple/isp_7721_01XX.dat", 0x936c}, + [ISP_IMX703_7722_01] = {0x703, 0x77220106, "apple/isp_7722_01XX.dat", 0xac20}, + [ISP_IMX713_4721_01] = {0x713, 0x47210107, "apple/isp_4721_01XX.dat", 0x936c}, + [ISP_IMX713_4722_01] = {0x713, 0x47220109, "apple/isp_4722_01XX.dat", 0x9218}, + [ISP_IMX714_2022_01] = {0x714, 0x20220107, "apple/isp_2022_01XX.dat", 0xa198}, + [ISP_IMX772_3721_01] = {0x772, 0x37210106, "apple/isp_3721_01XX.dat", 0xfdf8}, + [ISP_IMX772_3721_11] = {0x772, 0x37211106, "apple/isp_3721_11XX.dat", 0xfe14}, + [ISP_IMX772_3722_01] = {0x772, 0x37220104, "apple/isp_3722_01XX.dat", 0xfca4}, + [ISP_IMX772_3723_01] = {0x772, 0x37230106, "apple/isp_3723_01XX.dat", 0xfca4}, + [ISP_IMX814_2123_01] = {0x814, 0x21230101, "apple/isp_2123_01XX.dat", 0xed54}, + [ISP_IMX853_7622_01] = {0x853, 0x76220112, "apple/isp_7622_01XX.dat", 0x247f8}, + [ISP_IMX913_7523_01] = {0x913, 0x75230107, "apple/isp_7523_01XX.dat", 0x247f8}, + [ISP_VD56G0_6221_01] = {0xd56, 0x62210102, "apple/isp_6221_01XX.dat", 0x1b80}, + [ISP_VD56G0_6222_01] = {0xd56, 0x62220102, "apple/isp_6222_01XX.dat", 0x1b80}, }; // clang-format on @@ -182,125 +166,69 @@ static int isp_ch_get_sensor_id(struct apple_isp *isp, u32 ch) return err; } -static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) +static int isp_ch_get_camera_preset(struct apple_isp *isp, u32 ch, u32 ps) { - struct isp_format *fmt = isp_get_format(isp, ch); int err = 0; - struct cmd_ch_info *args; /* Too big to allocate on stack */ + struct cmd_ch_camera_config *args; /* Too big to allocate on stack */ args = kzalloc(sizeof(*args), GFP_KERNEL); if (!args) return -ENOMEM; - err = isp_cmd_ch_info_get(isp, ch, args); + err = isp_cmd_ch_camera_config_get(isp, ch, ps, args); if (err) goto exit; - dev_info(isp->dev, "found sensor %x %s on ch %d\n", args->version, - args->module_sn, ch); - - fmt->version = args->version; - fmt->num_presets = args->num_presets; - - pr_info("apple-isp: ch: CISP_CMD_CH_INFO_GET: %d\n", ch); - print_hex_dump(KERN_INFO, "apple-isp: ch: ", DUMP_PREFIX_NONE, 32, 4, + pr_info("apple-isp: ps: CISP_CMD_CH_CAMERA_CONFIG_GET: %d\n", ps); + print_hex_dump(KERN_INFO, "apple-isp: ps: ", DUMP_PREFIX_NONE, 32, 4, args, sizeof(*args), false); - err = isp_ch_get_sensor_id(isp, ch); - if (err || (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { - dev_err(isp->dev, - "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", - ch); - return -ENODEV; - } - exit: kfree(args); return err; } -static int isp_ch_get_camera_preset(struct apple_isp *isp, u32 ch, u32 ps) +static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) { + struct isp_format *fmt = isp_get_format(isp, ch); int err = 0; - struct cmd_ch_camera_config *args; /* Too big to allocate on stack */ + struct cmd_ch_info *args; /* Too big to allocate on stack */ args = kzalloc(sizeof(*args), GFP_KERNEL); if (!args) return -ENOMEM; - err = isp_cmd_ch_camera_config_get(isp, ch, ps, args); + err = isp_cmd_ch_info_get(isp, ch, args); if (err) goto exit; - pr_info("apple-isp: ps: CISP_CMD_CH_CAMERA_CONFIG_GET: %d\n", ps); - print_hex_dump(KERN_INFO, "apple-isp: ps: ", DUMP_PREFIX_NONE, 32, 4, - args, sizeof(*args), false); + dev_info(isp->dev, "found sensor %x %s on ch %d\n", args->version, + args->module_sn, ch); -exit: - kfree(args); + fmt->version = args->version; - return err; -} + pr_info("apple-isp: ch: CISP_CMD_CH_INFO_GET: %d\n", ch); + print_hex_dump(KERN_INFO, "apple-isp: ch: ", DUMP_PREFIX_NONE, 32, 4, + args, sizeof(*args), false); -static void isp_ch_dump_camera_presets(struct apple_isp *isp, u32 ch) -{ - struct isp_format *fmt = isp_get_format(isp, ch); - for (u32 ps = 0; ps < fmt->num_presets; ps++) { - isp_ch_get_camera_preset(isp, ch, ps); + err = isp_ch_get_sensor_id(isp, ch); + if (err || + (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { + dev_err(isp->dev, + "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", + ch); + return -ENODEV; } -} - -static int isp_ch_cache_camera_preset(struct apple_isp *isp, u32 ch) -{ - struct isp_format *fmt = isp_get_format(isp, ch); - const struct isp_preset *preset = &isp_presets[fmt->id]; - size_t total_size; - - isp_ch_dump_camera_presets(isp, ch); - - fmt->preset = preset->index; - - fmt->width = preset->width; - fmt->height = preset->height; - - fmt->x1 = preset->x1; - fmt->y1 = preset->y1; - fmt->x2 = preset->x2; - fmt->y2 = preset->y2; - - /* I really fucking hope they all use NV12. */ - fmt->num_planes = 2; - fmt->plane_size[0] = fmt->width * fmt->height; - fmt->plane_size[1] = fmt->plane_size[0] / 2; - - total_size = 0; - for (int i = 0; i < fmt->num_planes; i++) - total_size += fmt->plane_size[i]; - fmt->total_size = total_size; - - return 0; -} - -static int isp_ch_cache_camera_info(struct apple_isp *isp, u32 ch) -{ - int err; - err = isp_ch_cache_sensor_info(isp, ch); - if (err) { - dev_err(isp->dev, "ch %d: failed to cache sensor info: %d\n", - ch, err); - return err; + for (u32 ps = 0; ps < args->num_presets; ps++) { + isp_ch_get_camera_preset(isp, ch, ps); } - err = isp_ch_cache_camera_preset(isp, ch); - if (err) { - dev_err(isp->dev, "ch %d: failed to cache camera preset: %d\n", - ch, err); - return err; - } +exit: + kfree(args); - return 0; + return err; } static int isp_detect_camera(struct apple_isp *isp) @@ -338,7 +266,13 @@ static int isp_detect_camera(struct apple_isp *isp) isp->num_channels = args.num_channels; isp->current_ch = 0; - return isp_ch_cache_camera_info(isp, isp->current_ch); /* I told you */ + err = isp_ch_cache_sensor_info(isp, isp->current_ch); + if (err) { + dev_err(isp->dev, "failed to cache sensor info\n"); + return err; + } + + return 0; } int apple_isp_detect_camera(struct apple_isp *isp) @@ -408,6 +342,12 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) err); } + if (isp->hw->gen >= ISP_GEN_T8112) { + err = isp_cmd_ch_lpdp_hs_receiver_tuning_set(isp, ch, 1, 15); + if (err) + return err; + } + err = isp_cmd_ch_sbs_enable(isp, ch, 1); if (err) return err; @@ -421,17 +361,21 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset); + err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset->index); if (err) return err; - err = isp_cmd_ch_crop_set(isp, ch, fmt->x1, fmt->y1, fmt->x2, fmt->y2); + err = isp_cmd_ch_crop_set(isp, ch, fmt->preset->crop_offset.x, + fmt->preset->crop_offset.y, + fmt->preset->crop_size.x, + fmt->preset->crop_size.y); if (err) return err; - err = isp_cmd_ch_output_config_set(isp, ch, fmt->width, fmt->height, - CISP_COLORSPACE_REC709, - CISP_OUTPUT_FORMAT_NV12); + err = isp_cmd_ch_output_config_set(isp, ch, fmt->preset->output_dim.x, + fmt->preset->output_dim.y, + fmt->strides, CISP_COLORSPACE_REC709, + CISP_OUTPUT_FORMAT_YUV_2PLANE); if (err) return err; @@ -443,7 +387,7 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_ch_mbnr_enable(isp, ch, 0, 1, 1); + err = isp_cmd_ch_mbnr_enable(isp, ch, 0, ISP_MBNR_MODE_ENABLE, 1); if (err) return err; diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 79ffb2b1c33881..1e812400e52f7d 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -119,6 +119,17 @@ int isp_cmd_set_dsid_clr_req_base2(struct apple_isp *isp, u64 dsid_clr_base0, return CISP_SEND_IN(isp, args); } +int isp_cmd_set_dsid_clr_req_base(struct apple_isp *isp, u64 dsid_clr_base, + u32 dsid_clr_range) +{ + struct cmd_set_dsid_clr_req_base args = { + .opcode = CISP_OPCODE(CISP_CMD_SET_DSID_CLR_REG_BASE), + .dsid_clr_base = dsid_clr_base, + .dsid_clr_range = dsid_clr_range, + }; + return CISP_SEND_IN(isp, args); +} + int isp_cmd_pmp_ctrl_set(struct apple_isp *isp, u64 clock_scratch, u64 clock_base, u8 clock_bit, u8 clock_size, u64 bandwidth_scratch, u64 bandwidth_base, @@ -218,16 +229,26 @@ int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan) return CISP_SEND_IN(isp, args); } -int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u32 addr, +int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u64 addr, u32 size) { - struct cmd_ch_set_file_load args = { - .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), - .chan = chan, - .addr = addr, - .size = size, - }; - return CISP_SEND_IN(isp, args); + if (isp->hw->gen >= ISP_GEN_T8112) { + struct cmd_ch_set_file_load64 args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), + .chan = chan, + .addr = addr, + .size = size, + }; + return CISP_SEND_IN(isp, args); + } else { + struct cmd_ch_set_file_load args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), + .chan = chan, + .addr = addr, + .size = size, + }; + return CISP_SEND_IN(isp, args); + } } int isp_cmd_ch_sbs_enable(struct apple_isp *isp, u32 chan, u32 enable) @@ -244,7 +265,8 @@ int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, u32 y2) { struct cmd_ch_crop_set args = { - .opcode = CISP_OPCODE(CISP_CMD_CH_CROP_SET), + .opcode = CISP_OPCODE(isp->hw->scl1 ? CISP_CMD_CH_CROP_SCL1_SET + : CISP_CMD_CH_CROP_SET), .chan = chan, .x1 = x1, .y1 = y1, @@ -255,23 +277,22 @@ int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, } int isp_cmd_ch_output_config_set(struct apple_isp *isp, u32 chan, u32 width, - u32 height, u32 colorspace, u32 format) + u32 height, u32 strides[3], u32 colorspace, u32 format) { struct cmd_ch_output_config_set args = { - .opcode = CISP_OPCODE(CISP_CMD_CH_OUTPUT_CONFIG_SET), + .opcode = CISP_OPCODE(isp->hw->scl1 ? CISP_CMD_CH_OUTPUT_CONFIG_SCL1_SET + : CISP_CMD_CH_OUTPUT_CONFIG_SET), .chan = chan, .width = width, .height = height, .colorspace = colorspace, .format = format, - .unk_w0 = width, - .unk_w1 = width, - .unk_24 = 0, .padding_rows = 0, .unk_h0 = height, .compress = 0, .unk_w2 = width, }; + memcpy(args.strides, strides, sizeof(args.strides)); return CISP_SEND_IN(isp, args); } @@ -356,12 +377,14 @@ int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, u16 type) .chan = chan, .type = type, .count = 16, - .meta_size0 = ISP_META_SIZE, - .meta_size1 = ISP_META_SIZE, + .meta_size0 = isp->hw->meta_size, + .meta_size1 = isp->hw->meta_size, + .unk0 = 0, + .unk1 = 0, + .unk2 = 0, .data_blocks = 1, .compress = 0, }; - memset(args.zero, 0, sizeof(u32) * 0x1f); return CISP_SEND_INOUT(isp, args); } @@ -542,3 +565,40 @@ int isp_cmd_ch_semantic_awb_enable(struct apple_isp *isp, u32 chan, u32 enable) }; return CISP_SEND_IN(isp, args); } + +int isp_cmd_ch_lpdp_hs_receiver_tuning_set(struct apple_isp *isp, u32 chan, u32 unk1, u32 unk2) +{ + struct cmd_ch_lpdp_hs_receiver_tuning_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_LPDP_HS_RECEIVER_TUNING_SET), + .chan = chan, + .unk1 = unk1, + .unk2 = unk2, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_property_write(struct apple_isp *isp, u32 chan, u32 prop, u32 val) +{ + struct cmd_ch_property_write args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_PROPERTY_WRITE), + .chan = chan, + .prop = prop, + .val = val, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_property_read(struct apple_isp *isp, u32 chan, u32 prop, u32 *val) +{ + struct cmd_ch_property_write args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_PROPERTY_READ), + .chan = chan, + .prop = prop, + .val = 0xdeadbeef, + }; + int ret = CISP_SEND_OUT(isp, &args); + + *val = args.val; + + return ret; +} diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index 1fc484fa687853..1586df89f1cdab 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -35,10 +35,14 @@ #define CISP_CMD_CH_BUFFER_POOL_CONFIG_SET 0x0117 #define CISP_CMD_CH_CAMERA_MIPI_FREQUENCY_GET 0x011a #define CISP_CMD_CH_CAMERA_PIX_FREQUENCY_GET 0x011f +#define CISP_CMD_CH_PROPERTY_WRITE 0x0122 +#define CISP_CMD_CH_PROPERTY_READ 0x0123 #define CISP_CMD_CH_LOCAL_RAW_BUFFER_ENABLE 0x0125 +#define CISP_CMD_CH_META_DATA_ENABLE 0x0126 #define CISP_CMD_CH_CAMERA_MIPI_FREQUENCY_TOTAL_GET 0x0133 #define CISP_CMD_CH_SBS_ENABLE 0x013b #define CISP_CMD_CH_LSC_POLYNOMIAL_COEFF_GET 0x0142 +#define CISP_CMD_CH_SET_META_DATA_REQUIRED 0x014f #define CISP_CMD_CH_BUFFER_POOL_RETURN 0x015b #define CISP_CMD_CH_CAMERA_AGILE_FREQ_ARRAY_CURRENT_GET 0x015e #define CISP_CMD_CH_AE_START 0x0200 @@ -52,25 +56,35 @@ #define CISP_CMD_CH_SENSOR_NVM_GET 0x0501 #define CISP_CMD_CH_SENSOR_PERMODULE_LSC_INFO_GET 0x0507 #define CISP_CMD_CH_SENSOR_PERMODULE_LSC_GRID_GET 0x0511 +#define CISP_CMD_CH_LPDP_HS_RECEIVER_TUNING_SET 0x051b #define CISP_CMD_CH_FOCUS_LIMITS_GET 0x0701 +#define CISP_CMD_CH_CROP_GET 0x0800 #define CISP_CMD_CH_CROP_SET 0x0801 +#define CISP_CMD_CH_SCALER_CROP_SET 0x080a +#define CISP_CMD_CH_CROP_SCL1_GET 0x080b +#define CISP_CMD_CH_CROP_SCL1_SET 0x080c +#define CISP_CMD_CH_SCALER_CROP_SCL1_SET 0x080d #define CISP_CMD_CH_ALS_ENABLE 0x0a1c #define CISP_CMD_CH_ALS_DISABLE 0x0a1d #define CISP_CMD_CH_CNR_START 0x0a2f #define CISP_CMD_CH_MBNR_ENABLE 0x0a3a #define CISP_CMD_CH_OUTPUT_CONFIG_SET 0x0b01 +#define CISP_CMD_CH_OUTPUT_CONFIG_SCL1_SET 0x0b09 #define CISP_CMD_CH_PREVIEW_STREAM_SET 0x0b0d #define CISP_CMD_CH_SEMANTIC_VIDEO_ENABLE 0x0b17 #define CISP_CMD_CH_SEMANTIC_AWB_ENABLE 0x0b18 #define CISP_CMD_CH_FACE_DETECTION_START 0x0d00 +#define CISP_CMD_CH_FACE_DETECTION_STOP 0x0d01 #define CISP_CMD_CH_FACE_DETECTION_CONFIG_GET 0x0d02 #define CISP_CMD_CH_FACE_DETECTION_CONFIG_SET 0x0d03 +#define CISP_CMD_CH_FACE_DETECTION_DISABLE 0x0d04 #define CISP_CMD_CH_FACE_DETECTION_ENABLE 0x0d05 #define CISP_CMD_CH_FID_START 0x3000 #define CISP_CMD_CH_FID_STOP 0x3001 #define CISP_CMD_IPC_ENDPOINT_SET2 0x300c #define CISP_CMD_IPC_ENDPOINT_UNSET2 0x300d #define CISP_CMD_SET_DSID_CLR_REG_BASE2 0x3204 +#define CISP_CMD_SET_DSID_CLR_REG_BASE 0x3205 #define CISP_CMD_APPLE_CH_AE_METERING_MODE_SET 0x8206 #define CISP_CMD_APPLE_CH_AE_FD_SCENE_METERING_CONFIG_SET 0x820e #define CISP_CMD_APPLE_CH_AE_FLICKER_FREQ_UPDATE_CURRENT_SET 0x8212 @@ -86,10 +100,28 @@ #define CISP_POOL_TYPE_FD 0x2 #define CISP_POOL_TYPE_RAW 0x3 #define CISP_POOL_TYPE_STAT 0x4 +#define CISP_POOL_TYPE_RAW_AUX 0x5 +#define CISP_POOL_TYPE_YCC 0x6 +#define CISP_POOL_TYPE_CAPTURE_FULL_RES 0x7 #define CISP_POOL_TYPE_META_CAPTURE 0x8 +#define CISP_POOL_TYPE_RENDERED_SCL1 0x9 +#define CISP_POOL_TYPE_STAT_PIXELOUTPUT 0x11 +#define CISP_POOL_TYPE_FSCL 0x12 +#define CISP_POOL_TYPE_CAPTURE_FULL_RES_YCC 0x13 +#define CISP_POOL_TYPE_RENDERED_RAW 0x14 +#define CISP_POOL_TYPE_CAPTURE_PDC_RAW 0x16 +#define CISP_POOL_TYPE_FPC_DATA 0x17 +#define CISP_POOL_TYPE_AICAM_SEG 0x19 +#define CISP_POOL_TYPE_SPD 0x1a +#define CISP_POOL_TYPE_META_DEPTH 0x1c +#define CISP_POOL_TYPE_JASPER_DEPTH 0x1d +#define CISP_POOL_TYPE_RAW_SIFR 0x1f +#define CISP_POOL_TYPE_FEP_THUMBNAIL_DYNAMIC_POOL_RAW 0x21 #define CISP_COLORSPACE_REC709 0x1 -#define CISP_OUTPUT_FORMAT_NV12 0x0 +#define CISP_OUTPUT_FORMAT_YUV_2PLANE 0x0 +#define CISP_OUTPUT_FORMAT_YUV_1PLANE 0x1 +#define CISP_OUTPUT_FORMAT_RGB 0x2 #define CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY 0x1 struct cmd_start { @@ -144,6 +176,13 @@ struct cmd_set_dsid_clr_req_base2 { } __packed; static_assert(sizeof(struct cmd_set_dsid_clr_req_base2) == 0x38); +struct cmd_set_dsid_clr_req_base { + u64 opcode; + u64 dsid_clr_base; + u32 dsid_clr_range; +} __packed; +static_assert(sizeof(struct cmd_set_dsid_clr_req_base) == 0x14); + struct cmd_pmp_ctrl_set { u64 opcode; u64 clock_scratch; @@ -169,12 +208,26 @@ struct cmd_fid_exit { } __packed; static_assert(sizeof(struct cmd_fid_exit) == 0x8); +struct cmd_ipc_endpoint_set2 { + u64 opcode; + u32 unk; + u64 addr1; + u32 size1; + u64 addr2; + u32 size2; + u64 regs; + u32 unk2; +} __packed; +static_assert(sizeof(struct cmd_ipc_endpoint_set2) == 0x30); + int isp_cmd_start(struct apple_isp *isp, u32 mode); int isp_cmd_suspend(struct apple_isp *isp); int isp_cmd_print_enable(struct apple_isp *isp, u32 enable); int isp_cmd_trace_enable(struct apple_isp *isp, u32 enable); int isp_cmd_config_get(struct apple_isp *isp, struct cmd_config_get *args); int isp_cmd_set_isp_pmu_base(struct apple_isp *isp, u64 pmu_base); +int isp_cmd_set_dsid_clr_req_base(struct apple_isp *isp, u64 dsid_clr_base, + u32 dsid_clr_range); int isp_cmd_set_dsid_clr_req_base2(struct apple_isp *isp, u64 dsid_clr_base0, u64 dsid_clr_base1, u64 dsid_clr_base2, u64 dsid_clr_base3, u32 dsid_clr_range0, @@ -291,6 +344,14 @@ struct cmd_ch_set_file_load { } __packed; static_assert(sizeof(struct cmd_ch_set_file_load) == 0x14); +struct cmd_ch_set_file_load64 { + u64 opcode; + u32 chan; + u64 addr; + u32 size; +} __packed; +static_assert(sizeof(struct cmd_ch_set_file_load64) == 0x18); + struct cmd_ch_buffer_return { u64 opcode; u32 chan; @@ -321,9 +382,7 @@ struct cmd_ch_output_config_set { u32 height; u32 colorspace; u32 format; - u32 unk_w0; - u32 unk_w1; - u32 unk_24; + u32 strides[3]; u32 padding_rows; u32 unk_h0; u32 compress; @@ -369,6 +428,24 @@ struct cmd_ch_sif_pixel_format_set { } __packed; static_assert(sizeof(struct cmd_ch_sif_pixel_format_set) == 0x14); +struct cmd_ch_lpdp_hs_receiver_tuning_set { + u64 opcode; + u32 chan; + u32 unk1; + u32 unk2; +} __packed; +static_assert(sizeof(struct cmd_ch_lpdp_hs_receiver_tuning_set) == 0x14); + +struct cmd_ch_property_write { + u64 opcode; + u32 chan; + u32 prop; + u32 val; + u32 unk1; + u32 unk2; +} __packed; +static_assert(sizeof(struct cmd_ch_property_write) == 0x1c); + int isp_cmd_ch_start(struct apple_isp *isp, u32 chan); int isp_cmd_ch_stop(struct apple_isp *isp, u32 chan); int isp_cmd_ch_info_get(struct apple_isp *isp, u32 chan, @@ -379,20 +456,30 @@ int isp_cmd_ch_camera_config_current_get(struct apple_isp *isp, u32 chan, struct cmd_ch_camera_config *args); int isp_cmd_ch_camera_config_select(struct apple_isp *isp, u32 chan, u32 preset); -int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u32 addr, +int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u64 addr, u32 size); int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan); int isp_cmd_ch_sbs_enable(struct apple_isp *isp, u32 chan, u32 enable); int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, u32 y2); int isp_cmd_ch_output_config_set(struct apple_isp *isp, u32 chan, u32 width, - u32 height, u32 colorspace, u32 format); + u32 height, u32 strides[3], u32 colorspace, u32 format); int isp_cmd_ch_preview_stream_set(struct apple_isp *isp, u32 chan, u32 stream); int isp_cmd_ch_als_disable(struct apple_isp *isp, u32 chan); int isp_cmd_ch_cnr_start(struct apple_isp *isp, u32 chan); int isp_cmd_ch_mbnr_enable(struct apple_isp *isp, u32 chan, u32 use_case, u32 mode, u32 enable_chroma); int isp_cmd_ch_sif_pixel_format_set(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_lpdp_hs_receiver_tuning_set(struct apple_isp *isp, u32 chan, u32 unk1, u32 unk2); + +int isp_cmd_ch_property_read(struct apple_isp *isp, u32 chan, u32 prop, u32 *val); +int isp_cmd_ch_property_write(struct apple_isp *isp, u32 chan, u32 prop, u32 val); + +enum isp_mbnr_mode { + ISP_MBNR_MODE_DISABLE = 0, + ISP_MBNR_MODE_ENABLE = 1, + ISP_MBNR_MODE_BYPASS = 2, +}; struct cmd_ch_buffer_recycle_mode_set { u64 opcode; @@ -414,7 +501,10 @@ struct cmd_ch_buffer_pool_config_set { u16 count; u32 meta_size0; u32 meta_size1; - u32 zero[0x1f]; + u64 unk0; + u64 unk1; + u64 unk2; + u32 zero[0x19]; u32 data_blocks; u32 compress; } __packed; @@ -431,6 +521,8 @@ int isp_cmd_ch_buffer_recycle_mode_set(struct apple_isp *isp, u32 chan, int isp_cmd_ch_buffer_recycle_start(struct apple_isp *isp, u32 chan); int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, u16 type); +int isp_cmd_ch_buffer_pool_config_get(struct apple_isp *isp, u32 chan, + u16 type); int isp_cmd_ch_buffer_pool_return(struct apple_isp *isp, u32 chan); struct cmd_apple_ch_temporal_filter_start { diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 91dd1cb607076b..5a15b812c3dcfa 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -90,7 +90,8 @@ static int apple_isp_init_iommu(struct apple_isp *isp) return -ENODEV; isp->shift = __ffs(isp->domain->pgsize_bitmap); - idx = of_property_match_string(dev->of_node, "memory-region-names", "heap"); + idx = of_property_match_string(dev->of_node, "memory-region-names", + "heap"); mem_node = of_parse_phandle(dev->of_node, "memory-region", idx); if (!mem_node) { dev_err(dev, "No memory-region found for heap\n"); @@ -107,11 +108,10 @@ static int apple_isp_init_iommu(struct apple_isp *isp) while (maps < end) { maps++; - maps = of_translate_dma_region(dev->of_node, maps, &heap_base, &heap_size); + maps = of_translate_dma_region(dev->of_node, maps, &heap_base, + &heap_size); } - printk("heap: 0x%llx 0x%lx\n", heap_base, heap_size); - isp->fw.heap_top = heap_base + heap_size; err = of_property_read_u64(dev->of_node, "apple,dart-vm-size", @@ -122,7 +122,8 @@ static int apple_isp_init_iommu(struct apple_isp *isp) } // FIXME: refactor this, maybe use regular iova stuff? - drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - (heap_base & 0xffffffff)); + drm_mm_init(&isp->iovad, isp->fw.heap_top, + vm_size - (heap_base & 0xffffffff)); return 0; } @@ -132,6 +133,83 @@ static void apple_isp_free_iommu(struct apple_isp *isp) drm_mm_takedown(&isp->iovad); } +static int isp_of_read_coord(struct device *dev, struct device_node *np, + const char *prop, struct coord *val) +{ + u32 xy[2]; + int ret; + + ret = of_property_read_u32_array(np, prop, xy, 2); + if (ret) { + dev_err(dev, "failed to read '%s' property\n", prop); + return ret; + } + + val->x = xy[0]; + val->y = xy[1]; + return 0; +} + +static int apple_isp_init_presets(struct apple_isp *isp) +{ + struct device *dev = isp->dev; + struct isp_preset *preset; + int err = 0; + + struct device_node *np __free(device_node) = + of_get_child_by_name(dev->of_node, "sensor-presets"); + if (!np) { + dev_err(dev, "failed to get DT node 'presets'\n"); + return -EINVAL; + } + + isp->num_presets = of_get_child_count(np); + if (!isp->num_presets) { + dev_err(dev, "no sensor presets found\n"); + return -EINVAL; + } + + isp->presets = devm_kzalloc( + dev, sizeof(*isp->presets) * isp->num_presets, GFP_KERNEL); + if (!isp->presets) + return -ENOMEM; + + preset = isp->presets; + for_each_child_of_node_scoped(np, child) { + u32 xywh[4]; + + err = of_property_read_u32(child, "apple,config-index", + &preset->index); + if (err) { + dev_err(dev, "no apple,config-index property\n"); + return err; + } + + err = isp_of_read_coord(dev, child, "apple,input-size", + &preset->input_dim); + if (err) + return err; + err = isp_of_read_coord(dev, child, "apple,output-size", + &preset->output_dim); + if (err) + return err; + + err = of_property_read_u32_array(child, "apple,crop", xywh, 4); + if (err) { + dev_err(dev, "failed to read 'apple,crop' property\n"); + return err; + } + preset->crop_offset.x = xywh[0]; + preset->crop_offset.y = xywh[1]; + preset->crop_size.x = xywh[2]; + preset->crop_size.y = xywh[3]; + + preset++; + } + + return 0; +} + static int apple_isp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -151,6 +229,20 @@ static int apple_isp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, isp); dev_set_drvdata(dev, isp); + err = of_property_read_u32(dev->of_node, "apple,platform-id", + &isp->platform_id); + if (err) { + dev_err(dev, "failed to get 'apple,platform-id' property: %d\n", + err); + return err; + } + + err = apple_isp_init_presets(isp); + if (err) { + dev_err(dev, "failed to initialize presets\n"); + return err; + } + err = apple_isp_attach_genpd(isp); if (err) { dev_err(dev, "failed to attatch power domains\n"); @@ -190,7 +282,8 @@ static int apple_isp_probe(struct platform_device *pdev) spin_lock_init(&isp->buf_lock); init_waitqueue_head(&isp->wait); INIT_LIST_HEAD(&isp->gc); - INIT_LIST_HEAD(&isp->buffers); + INIT_LIST_HEAD(&isp->bufs_pending); + INIT_LIST_HEAD(&isp->bufs_submitted); isp->wq = alloc_workqueue("apple-isp-wq", WQ_UNBOUND, 0); if (!isp->wq) { dev_err(dev, "failed to create workqueue\n"); @@ -250,13 +343,13 @@ static void apple_isp_remove(struct platform_device *pdev) apple_isp_free_iommu(isp); destroy_workqueue(isp->wq); apple_isp_detach_genpd(isp); - return 0; } static const struct apple_isp_hw apple_isp_hw_t8103 = { - .platform_id = 0x1, + .gen = ISP_GEN_T8103, .pmu_base = 0x23b704000, + .dsid_count = 4, .dsid_clr_base0 = 0x200014000, .dsid_clr_base1 = 0x200054000, .dsid_clr_base2 = 0x200094000, @@ -274,12 +367,16 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { .bandwidth_base = 0x23bc3c000, .bandwidth_bit = 0x0, .bandwidth_size = 0x4, + + .scl1 = false, + .meta_size = ISP_META_SIZE_T8103, }; static const struct apple_isp_hw apple_isp_hw_t6000 = { - .platform_id = 0x3, + .gen = ISP_GEN_T8103, .pmu_base = 0x28e584000, + .dsid_count = 1, .dsid_clr_base0 = 0x200014000, .dsid_clr_base1 = 0x200054000, .dsid_clr_base2 = 0x200094000, @@ -297,12 +394,16 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, + + .scl1 = false, + .meta_size = ISP_META_SIZE_T8103, }; static const struct apple_isp_hw apple_isp_hw_t8110 = { - .platform_id = 0xe, // J413AP + .gen = ISP_GEN_T8112, .pmu_base = 0x23b704000, + .dsid_count = 4, .dsid_clr_base0 = 0x200014000, // TODO .dsid_clr_base1 = 0x200054000, .dsid_clr_base2 = 0x200094000, @@ -320,29 +421,30 @@ static const struct apple_isp_hw apple_isp_hw_t8110 = { .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, + + .scl1 = true, + .meta_size = ISP_META_SIZE_T8112, }; static const struct apple_isp_hw apple_isp_hw_t6020 = { - .platform_id = 0x7, // J416cAP + .gen = ISP_GEN_T8112, .pmu_base = 0x290284000, - .dsid_clr_base0 = 0x200014000, // TODO - .dsid_clr_base1 = 0x200054000, - .dsid_clr_base2 = 0x200094000, - .dsid_clr_base3 = 0x2000d4000, + .dsid_count = 1, + .dsid_clr_base0 = 0x200f14000, .dsid_clr_range0 = 0x1000, - .dsid_clr_range1 = 0x1000, - .dsid_clr_range2 = 0x1000, - .dsid_clr_range3 = 0x1000, - .clock_scratch = 0x28e3d0868, // CHECK + .clock_scratch = 0x28e3d10a8, .clock_base = 0x0, .clock_bit = 0x0, .clock_size = 0x8, - .bandwidth_scratch = 0x28e3d0980, // CHECK + .bandwidth_scratch = 0x28e3d1200, .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, + + .scl1 = true, + .meta_size = ISP_META_SIZE_T8112, }; static const struct of_device_id apple_isp_of_match[] = { @@ -362,7 +464,8 @@ static __maybe_unused int apple_isp_resume(struct device *dev) { return 0; } -DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, NULL); +DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, + NULL); static struct platform_driver apple_isp_driver = { .driver = { diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index e672c62c0ec41c..926c921849544a 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -20,7 +20,13 @@ #define ISP_MAX_CHANNELS 6 #define ISP_IPC_MESSAGE_SIZE 64 #define ISP_IPC_FLAG_ACK 0x1 -#define ISP_META_SIZE 0x4640 +#define ISP_META_SIZE_T8103 0x4640 +#define ISP_META_SIZE_T8112 0x4840 + +enum isp_generation { + ISP_GEN_T8103, + ISP_GEN_T8112, +}; struct isp_surf { struct drm_mm_node *mm; @@ -62,10 +68,24 @@ struct isp_channel { const struct isp_chan_ops *ops; }; +struct coord { + u32 x; + u32 y; +}; + +struct isp_preset { + u32 index; + struct coord input_dim; + struct coord output_dim; + struct coord crop_offset; + struct coord crop_size; +}; + struct apple_isp_hw { - u32 platform_id; + enum isp_generation gen; u64 pmu_base; + int dsid_count; u64 dsid_clr_base0; u64 dsid_clr_base1; u64 dsid_clr_base2; @@ -83,6 +103,9 @@ struct apple_isp_hw { u64 bandwidth_base; u8 bandwidth_bit; u8 bandwidth_size; + + u32 meta_size; + bool scl1; }; enum isp_sensor_id { @@ -139,15 +162,9 @@ enum isp_sensor_id { struct isp_format { enum isp_sensor_id id; u32 version; - u32 num_presets; - u32 preset; - u32 width; - u32 height; - u32 x1; - u32 y1; - u32 x2; - u32 y2; + struct isp_preset *preset; unsigned int num_planes; + u32 strides[VB2_MAX_PLANES]; size_t plane_size[VB2_MAX_PLANES]; size_t total_size; }; @@ -155,6 +172,9 @@ struct isp_format { struct apple_isp { struct device *dev; const struct apple_isp_hw *hw; + u32 platform_id; + struct isp_preset *presets; + int num_presets; int num_channels; struct isp_format fmts[ISP_MAX_CHANNELS]; @@ -208,7 +228,8 @@ struct apple_isp { unsigned long state; spinlock_t buf_lock; - struct list_head buffers; + struct list_head bufs_pending; + struct list_head bufs_submitted; }; struct isp_chan_ops { diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 70ffaa97cd260a..972867a93a0193 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -46,7 +46,10 @@ struct isp_firmware_bootargs { u64 extra_iova; u64 extra_size; u32 platform_id; - u32 pad_40[7]; + u32 pad_40; + u64 logbuf_addr; + u64 logbuf_size; + u64 logbuf_entsize; u32 ipc_size; u32 pad_60[5]; u32 unk5; @@ -279,9 +282,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.shared_size = 0x10000000UL - args.shared_base; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; - args.platform_id = isp->hw->platform_id; + args.platform_id = isp->platform_id; args.unk5 = 0x40; - args.unk7 = 0x1; + args.unk7 = 0x1; // 0? args.unk_iova1 = args_iova + sizeof(args) - 0xc; args.unk9 = 0x3; isp_iowrite(isp, args_iova, &args, sizeof(args)); @@ -501,13 +504,20 @@ static int isp_start_command_processor(struct apple_isp *isp) if (err) return err; - err = isp_cmd_set_dsid_clr_req_base2( - isp, isp->hw->dsid_clr_base0, isp->hw->dsid_clr_base1, - isp->hw->dsid_clr_base2, isp->hw->dsid_clr_base3, - isp->hw->dsid_clr_range0, isp->hw->dsid_clr_range1, - isp->hw->dsid_clr_range2, isp->hw->dsid_clr_range3); - if (err) - return err; + if (isp->hw->dsid_count == 1) { + err = isp_cmd_set_dsid_clr_req_base( + isp, isp->hw->dsid_clr_base0, isp->hw->dsid_clr_range0); + if (err) + return err; + } else { + err = isp_cmd_set_dsid_clr_req_base2( + isp, isp->hw->dsid_clr_base0, isp->hw->dsid_clr_base1, + isp->hw->dsid_clr_base2, isp->hw->dsid_clr_base3, + isp->hw->dsid_clr_range0, isp->hw->dsid_clr_range1, + isp->hw->dsid_clr_range2, isp->hw->dsid_clr_range3); + if (err) + return err; + } err = isp_cmd_pmp_ctrl_set( isp, isp->hw->clock_scratch, isp->hw->clock_base, diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index a9a0fdb73a4d9f..14249a44798ba5 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -230,8 +230,8 @@ static void sm_malloc_deferred_worker(struct work_struct *work) } #ifdef APPLE_ISP_DEBUG - /* Only enabled in debug builds so it shouldn't matter, but - * the LOG surface is always the first surface requested. + /* Only enabled in debug builds so it shouldn't matter, but + * the LOG surface is always the first surface requested. */ if (!test_bit(ISP_STATE_LOGGING, &isp->state)) set_bit(ISP_STATE_LOGGING, &isp->state); @@ -306,9 +306,10 @@ int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) sizeof(meta_iova)); spin_lock(&isp->buf_lock); - list_for_each_entry_safe_reverse(buf, tmp, &isp->buffers, link) { - if (buf->meta->iova == meta_iova) { + list_for_each_entry_safe_reverse(buf, tmp, &isp->bufs_submitted, link) { + if ((u32)buf->meta->iova == (u32)meta_iova) { enum vb2_buffer_state state = VB2_BUF_STATE_ERROR; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); buf->vb.sequence = isp->sequence++; buf->vb.field = V4L2_FIELD_NONE; diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 0d1593803f1143..8e71eac165cbd8 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -13,10 +13,11 @@ #include "isp-ipc.h" #include "isp-v4l2.h" -#define ISP_MIN_FRAMES 2 -#define ISP_MAX_PLANES 4 -#define ISP_MAX_PIX_FORMATS 2 -#define ISP_BUFFER_TIMEOUT msecs_to_jiffies(1500) +#define ISP_MIN_FRAMES 2 +#define ISP_MAX_PLANES 4 +#define ISP_MAX_PIX_FORMATS 2 +#define ISP_BUFFER_TIMEOUT msecs_to_jiffies(1500) +#define ISP_STRIDE_ALIGNMENT 64 struct isp_h2t_buffer { u64 iovas[ISP_MAX_PLANES]; @@ -40,7 +41,7 @@ static int isp_submit_buffers(struct apple_isp *isp) struct isp_format *fmt = isp_get_current_format(isp); struct isp_channel *chan = isp->chan_bh; struct isp_message *req = &chan->req; - struct isp_buffer *buf; + struct isp_buffer *buf, *buf2, *tmp; unsigned long flags; size_t offset; int err; @@ -51,43 +52,76 @@ static int isp_submit_buffers(struct apple_isp *isp) return -ENOMEM; spin_lock_irqsave(&isp->buf_lock, flags); - buf = list_first_entry_or_null(&isp->buffers, struct isp_buffer, link); - if (!buf) { + while ((buf = list_first_entry_or_null(&isp->bufs_pending, + struct isp_buffer, link))) { + args->meta.num_planes = 1; + args->meta.pool_type = 0; + args->meta.iovas[0] = buf->meta->iova; + args->meta.flags[0] = 0x40000000; + + args->render.num_planes = fmt->num_planes; + args->render.pool_type = isp->hw->scl1 ? + CISP_POOL_TYPE_RENDERED_SCL1 : + CISP_POOL_TYPE_RENDERED; + offset = 0; + for (int j = 0; j < fmt->num_planes; j++) { + args->render.iovas[j] = buf->surfs[0].iova + offset; + args->render.flags[j] = 0x40000000; + offset += fmt->plane_size[j]; + } + + /* + * Queue the buffer as submitted and release the lock for now. + * We need to do this before actually submitting to avoid a + * race with the buffer return codepath. + */ + list_move_tail(&buf->link, &isp->bufs_submitted); spin_unlock_irqrestore(&isp->buf_lock, flags); - kfree(args); - return -EPROTO; - } - args->meta.num_planes = 1; - args->meta.pool_type = CISP_POOL_TYPE_META; - args->meta.iovas[0] = buf->meta->iova; - args->meta.flags[0] = 0x40000000; - - args->render.num_planes = fmt->num_planes; - args->render.pool_type = CISP_POOL_TYPE_RENDERED; - offset = 0; - for (int j = 0; j < fmt->num_planes; j++) { - args->render.iovas[j] = buf->surfs[0].iova + offset; - args->render.flags[j] = 0x40000000; - offset += fmt->plane_size[j]; + args->enable = 0x1; + args->num_buffers = 2; + + req->arg0 = isp->cmd_iova; + req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; + req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; + + isp_iowrite(isp, req->arg0, args, sizeof(*args)); + err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); + if (err) { + /* If we fail, consider the buffer not submitted. */ + dev_err(isp->dev, + "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, req->arg0, req->arg1, req->arg2); + + /* + * Try to find the buffer in the list, and if it's + * still there, move it back to the pending list. + */ + spin_lock_irqsave(&isp->buf_lock, flags); + list_for_each_entry_safe_reverse( + buf2, tmp, &isp->bufs_submitted, link) { + if (buf2 == buf) { + list_move_tail(&buf->link, + &isp->bufs_pending); + spin_unlock_irqrestore(&isp->buf_lock, + flags); + return err; + } + } + /* + * We didn't find the buffer, which means it somehow was returned + * by the firmware even though submission failed? + */ + dev_err(isp->dev, + "buffer submission failed but buffer was returned?\n"); + spin_unlock_irqrestore(&isp->buf_lock, flags); + return err; + } + + spin_lock_irqsave(&isp->buf_lock, flags); } spin_unlock_irqrestore(&isp->buf_lock, flags); - args->enable = 0x1; - args->num_buffers = 2; - - req->arg0 = isp->cmd_iova; - req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; - req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; - - isp_iowrite(isp, req->arg0, args, sizeof(*args)); - err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); - if (err) { - dev_err(isp->dev, - "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", - chan->name, req->arg0, req->arg1, req->arg2); - } - kfree(args); return err; @@ -140,7 +174,7 @@ static int isp_vb2_buf_init(struct vb2_buffer *vb) unsigned int i; int err; - buf->meta = isp_alloc_surface(isp, ISP_META_SIZE); + buf->meta = isp_alloc_surface(isp, isp->hw->meta_size); if (!buf->meta) return -ENOMEM; @@ -179,9 +213,12 @@ static void isp_vb2_release_buffers(struct apple_isp *isp, unsigned long flags; spin_lock_irqsave(&isp->buf_lock, flags); - list_for_each_entry(buf, &isp->buffers, link) + list_for_each_entry(buf, &isp->bufs_submitted, link) + vb2_buffer_done(&buf->vb.vb2_buf, state); + INIT_LIST_HEAD(&isp->bufs_submitted); + list_for_each_entry(buf, &isp->bufs_pending, link) vb2_buffer_done(&buf->vb.vb2_buf, state); - INIT_LIST_HEAD(&isp->buffers); + INIT_LIST_HEAD(&isp->bufs_pending); spin_unlock_irqrestore(&isp->buf_lock, flags); } @@ -194,8 +231,9 @@ static void isp_vb2_buf_queue(struct vb2_buffer *vb) bool empty; spin_lock_irqsave(&isp->buf_lock, flags); - empty = list_empty(&isp->buffers); - list_add_tail(&buf->link, &isp->buffers); + empty = list_empty(&isp->bufs_pending) && + list_empty(&isp->bufs_submitted); + list_add_tail(&buf->link, &isp->bufs_pending); spin_unlock_irqrestore(&isp->buf_lock, flags); if (test_bit(ISP_STATE_STREAMING, &isp->state) && !empty) @@ -249,15 +287,62 @@ static void isp_vb2_stop_streaming(struct vb2_queue *q) } static const struct vb2_ops isp_vb2_ops = { - .queue_setup = isp_vb2_queue_setup, - .buf_init = isp_vb2_buf_init, - .buf_cleanup = isp_vb2_buf_cleanup, - .buf_prepare = isp_vb2_buf_prepare, - .buf_queue = isp_vb2_buf_queue, + .queue_setup = isp_vb2_queue_setup, + .buf_init = isp_vb2_buf_init, + .buf_cleanup = isp_vb2_buf_cleanup, + .buf_prepare = isp_vb2_buf_prepare, + .buf_queue = isp_vb2_buf_queue, .start_streaming = isp_vb2_start_streaming, - .stop_streaming = isp_vb2_stop_streaming, + .stop_streaming = isp_vb2_stop_streaming, }; +static int isp_set_preset(struct apple_isp *isp, struct isp_format *fmt, + struct isp_preset *preset) +{ + int i; + size_t total_size; + + fmt->preset = preset; + + /* I really fucking hope they all use NV12. */ + fmt->num_planes = 2; + fmt->strides[0] = ALIGN(preset->output_dim.x, ISP_STRIDE_ALIGNMENT); + /* UV subsampled interleaved */ + fmt->strides[1] = ALIGN(preset->output_dim.x, ISP_STRIDE_ALIGNMENT); + fmt->plane_size[0] = fmt->strides[0] * preset->output_dim.y; + fmt->plane_size[1] = fmt->strides[1] * preset->output_dim.y / 2; + + total_size = 0; + for (i = 0; i < fmt->num_planes; i++) + total_size += fmt->plane_size[i]; + fmt->total_size = total_size; + + return 0; +} + +static struct isp_preset *isp_select_preset(struct apple_isp *isp, u32 width, + u32 height) +{ + struct isp_preset *preset, *best = &isp->presets[0]; + int i, score, best_score = INT_MAX; + + /* Default if no dimensions */ + if (width == 0 || height == 0) + return &isp->presets[0]; + + for (i = 0; i < isp->num_presets; i++) { + preset = &isp->presets[i]; + score = abs((int)preset->output_dim.x - (int)width) + + abs((int)preset->output_dim.y - (int)height); + if (score < best_score) { + best = preset; + best_score = score; + } + } + + return best; +} + /* * V4L2 ioctl section */ @@ -288,29 +373,28 @@ static int isp_vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *f) { struct apple_isp *isp = video_drvdata(file); - struct isp_format *fmt = isp_get_current_format(isp); - if (f->index >= ISP_MAX_PIX_FORMATS) + if (f->index >= isp->num_presets) return -EINVAL; - if ((!f->index && f->pixel_format != V4L2_PIX_FMT_NV12) || - (f->index && f->pixel_format != V4L2_PIX_FMT_NV12M)) + if ((f->pixel_format != V4L2_PIX_FMT_NV12) || + (f->pixel_format != V4L2_PIX_FMT_NV12M)) return -EINVAL; - f->discrete.width = fmt->width; - f->discrete.height = fmt->height; + f->discrete.width = isp->presets[f->index].output_dim.x; + f->discrete.height = isp->presets[f->index].output_dim.y; f->type = V4L2_FRMSIZE_TYPE_DISCRETE; return 0; } -static inline void isp_set_sp_pix_format(struct apple_isp *isp, - struct v4l2_format *f) +static inline void isp_get_sp_pix_format(struct apple_isp *isp, + struct v4l2_format *f, + struct isp_format *fmt) { - struct isp_format *fmt = isp_get_current_format(isp); - - f->fmt.pix.width = fmt->width; - f->fmt.pix.height = fmt->height; + f->fmt.pix.width = fmt->preset->output_dim.x; + f->fmt.pix.height = fmt->preset->output_dim.y; + f->fmt.pix.bytesperline = fmt->strides[0]; f->fmt.pix.sizeimage = fmt->total_size; f->fmt.pix.field = V4L2_FIELD_NONE; @@ -320,16 +404,17 @@ static inline void isp_set_sp_pix_format(struct apple_isp *isp, f->fmt.pix.xfer_func = V4L2_XFER_FUNC_709; } -static inline void isp_set_mp_pix_format(struct apple_isp *isp, - struct v4l2_format *f) +static inline void isp_get_mp_pix_format(struct apple_isp *isp, + struct v4l2_format *f, + struct isp_format *fmt) { - struct isp_format *fmt = isp_get_current_format(isp); - - f->fmt.pix_mp.width = fmt->width; - f->fmt.pix_mp.height = fmt->height; + f->fmt.pix_mp.width = fmt->preset->output_dim.x; + f->fmt.pix_mp.height = fmt->preset->output_dim.y; f->fmt.pix_mp.num_planes = fmt->num_planes; - for (int i = 0; i < fmt->num_planes; i++) + for (int i = 0; i < fmt->num_planes; i++) { f->fmt.pix_mp.plane_fmt[i].sizeimage = fmt->plane_size[i]; + f->fmt.pix_mp.plane_fmt[i].bytesperline = fmt->strides[i]; + } f->fmt.pix_mp.field = V4L2_FIELD_NONE; f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; @@ -342,11 +427,12 @@ static int isp_vidioc_get_format(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); if (isp->multiplanar) return -ENOTTY; - isp_set_sp_pix_format(isp, f); + isp_get_sp_pix_format(isp, f, fmt); return 0; } @@ -355,11 +441,19 @@ static int isp_vidioc_set_format(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); + struct isp_preset *preset; + int err; if (isp->multiplanar) return -ENOTTY; - isp_set_sp_pix_format(isp, f); // no + preset = isp_select_preset(isp, f->fmt.pix.width, f->fmt.pix.height); + err = isp_set_preset(isp, fmt, preset); + if (err) + return err; + + isp_get_sp_pix_format(isp, f, fmt); return 0; } @@ -368,11 +462,19 @@ static int isp_vidioc_try_format(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format fmt = *isp_get_current_format(isp); + struct isp_preset *preset; + int err; if (isp->multiplanar) return -ENOTTY; - isp_set_sp_pix_format(isp, f); // still no + preset = isp_select_preset(isp, f->fmt.pix.width, f->fmt.pix.height); + err = isp_set_preset(isp, &fmt, preset); + if (err) + return err; + + isp_get_sp_pix_format(isp, f, &fmt); return 0; } @@ -381,11 +483,12 @@ static int isp_vidioc_get_format_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); if (!isp->multiplanar) return -ENOTTY; - isp_set_mp_pix_format(isp, f); + isp_get_mp_pix_format(isp, f, fmt); return 0; } @@ -394,11 +497,20 @@ static int isp_vidioc_set_format_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); + struct isp_preset *preset; + int err; if (!isp->multiplanar) return -ENOTTY; - isp_set_mp_pix_format(isp, f); // no + preset = isp_select_preset(isp, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + err = isp_set_preset(isp, fmt, preset); + if (err) + return err; + + isp_get_mp_pix_format(isp, f, fmt); return 0; } @@ -407,11 +519,20 @@ static int isp_vidioc_try_format_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format fmt = *isp_get_current_format(isp); + struct isp_preset *preset; + int err; if (!isp->multiplanar) return -ENOTTY; - isp_set_mp_pix_format(isp, f); // still no + preset = isp_select_preset(isp, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + err = isp_set_preset(isp, &fmt, preset); + if (err) + return err; + + isp_get_mp_pix_format(isp, f, &fmt); return 0; } @@ -470,6 +591,8 @@ static int isp_vidioc_set_param(struct file *file, void *fh, return -EINVAL; /* Not supporting frame rate sets. No use. Plus floats. */ + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.capture.readbuffers = ISP_MIN_FRAMES; a->parm.capture.timeperframe.numerator = ISP_FRAME_RATE_NUM; a->parm.capture.timeperframe.denominator = ISP_FRAME_RATE_DEN; @@ -477,59 +600,67 @@ static int isp_vidioc_set_param(struct file *file, void *fh, } static const struct v4l2_ioctl_ops isp_v4l2_ioctl_ops = { - .vidioc_querycap = isp_vidioc_querycap, - - .vidioc_enum_fmt_vid_cap = isp_vidioc_enum_format, - .vidioc_g_fmt_vid_cap = isp_vidioc_get_format, - .vidioc_s_fmt_vid_cap = isp_vidioc_set_format, - .vidioc_try_fmt_vid_cap = isp_vidioc_try_format, - .vidioc_g_fmt_vid_cap_mplane = isp_vidioc_get_format_mplane, - .vidioc_s_fmt_vid_cap_mplane = isp_vidioc_set_format_mplane, - .vidioc_try_fmt_vid_cap_mplane = isp_vidioc_try_format_mplane, - - .vidioc_enum_framesizes = isp_vidioc_enum_framesizes, - .vidioc_enum_input = isp_vidioc_enum_input, - .vidioc_g_input = isp_vidioc_get_input, - .vidioc_s_input = isp_vidioc_set_input, - .vidioc_g_parm = isp_vidioc_get_param, - .vidioc_s_parm = isp_vidioc_set_param, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_querycap = isp_vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = isp_vidioc_enum_format, + .vidioc_g_fmt_vid_cap = isp_vidioc_get_format, + .vidioc_s_fmt_vid_cap = isp_vidioc_set_format, + .vidioc_try_fmt_vid_cap = isp_vidioc_try_format, + .vidioc_g_fmt_vid_cap_mplane = isp_vidioc_get_format_mplane, + .vidioc_s_fmt_vid_cap_mplane = isp_vidioc_set_format_mplane, + .vidioc_try_fmt_vid_cap_mplane = isp_vidioc_try_format_mplane, + + .vidioc_enum_framesizes = isp_vidioc_enum_framesizes, + .vidioc_enum_input = isp_vidioc_enum_input, + .vidioc_g_input = isp_vidioc_get_input, + .vidioc_s_input = isp_vidioc_set_input, + .vidioc_g_parm = isp_vidioc_get_param, + .vidioc_s_parm = isp_vidioc_set_param, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, }; static const struct v4l2_file_operations isp_v4l2_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .read = vb2_fop_read, - .poll = vb2_fop_poll, - .mmap = vb2_fop_mmap, + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; static const struct media_device_ops isp_media_device_ops = { - .link_notify = v4l2_pipeline_link_notify, + .link_notify = v4l2_pipeline_link_notify, }; int apple_isp_setup_video(struct apple_isp *isp) { struct video_device *vdev = &isp->vdev; struct vb2_queue *vbq = &isp->vbq; + struct isp_format *fmt = isp_get_current_format(isp); int err; + err = isp_set_preset(isp, fmt, &isp->presets[0]); + if (err) { + dev_err(isp->dev, "failed to set default preset: %d\n", err); + return err; + } + media_device_init(&isp->mdev); isp->v4l2_dev.mdev = &isp->mdev; isp->mdev.ops = &isp_media_device_ops; isp->mdev.dev = isp->dev; - strscpy(isp->mdev.model, APPLE_ISP_DEVICE_NAME, sizeof(isp->mdev.model)); + strscpy(isp->mdev.model, APPLE_ISP_DEVICE_NAME, + sizeof(isp->mdev.model)); err = media_device_register(&isp->mdev); if (err) { From f80dcbad37bb3b58884b8a17ac5dccd4183906a0 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 16:06:31 +0900 Subject: [PATCH 301/352] media: apple: isp: Always enable singleplane API, make multiple a module param This requires modifying the vbq type when set_format is called, depending on the style... this is ugly, but it should work? Multiplane is still quite broken, but this enables testing it with gstreamer. Still lots of things to fix to make this actually work. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-v4l2.c | 49 ++++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 8e71eac165cbd8..fcc1d7edc32f5d 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright 2023 Eileen Yoon */ +#include + #include #include #include @@ -19,6 +21,10 @@ #define ISP_BUFFER_TIMEOUT msecs_to_jiffies(1500) #define ISP_STRIDE_ALIGNMENT 64 +static bool multiplanar = false; +module_param(multiplanar, bool, 0644); +MODULE_PARM_DESC(multiplanar, "Enable multiplanar API"); + struct isp_h2t_buffer { u64 iovas[ISP_MAX_PLANES]; u32 flags[ISP_MAX_PLANES]; @@ -358,13 +364,23 @@ static int isp_vidioc_querycap(struct file *file, void *priv, static int isp_vidioc_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) { + struct apple_isp *isp = video_drvdata(file); + if (f->index >= ISP_MAX_PIX_FORMATS) return -EINVAL; - if (!f->index) + switch (f->index) { + case 0: f->pixelformat = V4L2_PIX_FMT_NV12; - else + break; + case 1: + if (!isp->multiplanar) + return -EINVAL; f->pixelformat = V4L2_PIX_FMT_NV12M; + break; + default: + return -EINVAL; + } return 0; } @@ -377,7 +393,7 @@ static int isp_vidioc_enum_framesizes(struct file *file, void *fh, if (f->index >= isp->num_presets) return -EINVAL; - if ((f->pixel_format != V4L2_PIX_FMT_NV12) || + if ((f->pixel_format != V4L2_PIX_FMT_NV12) && (f->pixel_format != V4L2_PIX_FMT_NV12M)) return -EINVAL; @@ -429,9 +445,6 @@ static int isp_vidioc_get_format(struct file *file, void *fh, struct apple_isp *isp = video_drvdata(file); struct isp_format *fmt = isp_get_current_format(isp); - if (isp->multiplanar) - return -ENOTTY; - isp_get_sp_pix_format(isp, f, fmt); return 0; @@ -445,9 +458,6 @@ static int isp_vidioc_set_format(struct file *file, void *fh, struct isp_preset *preset; int err; - if (isp->multiplanar) - return -ENOTTY; - preset = isp_select_preset(isp, f->fmt.pix.width, f->fmt.pix.height); err = isp_set_preset(isp, fmt, preset); if (err) @@ -455,6 +465,8 @@ static int isp_vidioc_set_format(struct file *file, void *fh, isp_get_sp_pix_format(isp, f, fmt); + isp->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; } @@ -466,9 +478,6 @@ static int isp_vidioc_try_format(struct file *file, void *fh, struct isp_preset *preset; int err; - if (isp->multiplanar) - return -ENOTTY; - preset = isp_select_preset(isp, f->fmt.pix.width, f->fmt.pix.height); err = isp_set_preset(isp, &fmt, preset); if (err) @@ -512,6 +521,8 @@ static int isp_vidioc_set_format_mplane(struct file *file, void *fh, isp_get_mp_pix_format(isp, f, fmt); + isp->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + return 0; } @@ -569,8 +580,9 @@ static int isp_vidioc_get_param(struct file *file, void *fh, { struct apple_isp *isp = video_drvdata(file); - if (a->type != (isp->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE)) + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + (!isp->multiplanar || + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) return -EINVAL; a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; @@ -586,8 +598,9 @@ static int isp_vidioc_set_param(struct file *file, void *fh, { struct apple_isp *isp = video_drvdata(file); - if (a->type != (isp->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE)) + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + (!isp->multiplanar || + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) return -EINVAL; /* Not supporting frame rate sets. No use. Plus floats. */ @@ -668,7 +681,7 @@ int apple_isp_setup_video(struct apple_isp *isp) goto media_cleanup; } - isp->multiplanar = 0; + isp->multiplanar = multiplanar; err = v4l2_device_register(isp->dev, &isp->v4l2_dev); if (err) { @@ -697,6 +710,8 @@ int apple_isp_setup_video(struct apple_isp *isp) vdev->fops = &isp_v4l2_fops; vdev->ioctl_ops = &isp_v4l2_ioctl_ops; vdev->device_caps = V4L2_BUF_TYPE_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + if (isp->multiplanar) + vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE_MPLANE; vdev->v4l2_dev = &isp->v4l2_dev; vdev->vfl_type = VFL_TYPE_VIDEO; vdev->vfl_dir = VFL_DIR_RX; From 39c61df89ca97b1db001cb3afd62f08715f95217 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 19:10:58 +0900 Subject: [PATCH 302/352] media: apple: isp: Switch to threaded IRQs There's no reason to run all the command handling in hard IRQ context. Let's switch to threaded IRQs, which should simplify some things. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 972867a93a0193..01b81714547206 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -93,6 +93,13 @@ static irqreturn_t apple_isp_isr(int irq, void *dev) isp_mbox_write32(isp, ISP_MBOX_IRQ_ACK, isp_mbox_read32(isp, ISP_MBOX_IRQ_INTERRUPT)); + return IRQ_WAKE_THREAD; +} + +static irqreturn_t apple_isp_isr_thread(int irq, void *dev) +{ + struct apple_isp *isp = dev; + wake_up_interruptible_all(&isp->wait); ipc_chan_handle(isp, isp->chan_sm); @@ -117,7 +124,8 @@ static int isp_enable_irq(struct apple_isp *isp) { int err; - err = request_irq(isp->irq, apple_isp_isr, 0, "apple-isp", isp); + err = request_threaded_irq(isp->irq, apple_isp_isr, + apple_isp_isr_thread, 0, "apple-isp", isp); if (err < 0) { isp_err(isp, "failed to request IRQ#%u (%d)\n", isp->irq, err); return err; From 46d44c1ff38b67c7b5140c238ed82f9ad6b62642 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 18:38:22 +0900 Subject: [PATCH 303/352] media: apple: isp: Remove ioread/iowrite and stop doing raw address translation Translating IOVAs via the DART and then trying to access physical memory directly is slow and error-prone. We know what surfaces IOVAs are supposed to be part of, so we can use the surface vmap to access the contents. Where we get an IOVA from the firmware, assert that it is within the expected range before accessing it. Since we're using threaded IRQs now, this also lets us get rid of the deferred vmap. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 2 +- drivers/media/platform/apple/isp/isp-cmd.c | 5 +- drivers/media/platform/apple/isp/isp-drv.h | 5 + drivers/media/platform/apple/isp/isp-fw.c | 70 ++++++++++-- drivers/media/platform/apple/isp/isp-fw.h | 9 ++ drivers/media/platform/apple/isp/isp-iommu.c | 6 -- drivers/media/platform/apple/isp/isp-iommu.h | 15 --- drivers/media/platform/apple/isp/isp-ipc.c | 107 ++++++++----------- drivers/media/platform/apple/isp/isp-v4l2.c | 2 +- 9 files changed, 130 insertions(+), 91 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 593b780ab73b15..abdc9e345933d8 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -323,7 +323,7 @@ static int isp_ch_load_setfile(struct apple_isp *isp, u32 ch) return -EINVAL; } - isp_iowrite(isp, isp->data_surf->iova, (void *)fw->data, setfile->size); + memcpy(isp->data_surf->virt, (void *)fw->data, setfile->size); release_firmware(fw); return isp_cmd_ch_set_file_load(isp, ch, isp->data_surf->iova, diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 1e812400e52f7d..1166f0990830ed 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -24,7 +24,7 @@ static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize) req->arg1 = insize; req->arg2 = outsize; - isp_iowrite(isp, isp->cmd_iova, args, insize); + memcpy(isp->cmd_virt, args, insize); err = ipc_chan_send(isp, chan, CISP_TIMEOUT); if (err) { u64 opcode; @@ -45,7 +45,8 @@ static int cisp_send_read(struct apple_isp *isp, void *args, u32 insize, int err = cisp_send(isp, args, insize, outsize); if (err) return err; - isp_ioread(isp, isp->cmd_iova, args, outsize); + + memcpy(args, isp->cmd_virt, outsize); return 0; } diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 926c921849544a..26b9ee0e4d709f 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -32,6 +32,7 @@ struct isp_surf { struct drm_mm_node *mm; struct list_head head; u64 size; + u64 type; u32 num_pages; struct page **pages; struct sg_table sgt; @@ -60,6 +61,7 @@ struct isp_channel { u32 num; u64 size; dma_addr_t iova; + void *virt; u32 doorbell; u32 cursor; spinlock_t lock; @@ -210,6 +212,8 @@ struct apple_isp { struct isp_surf *ipc_surf; struct isp_surf *extra_surf; struct isp_surf *data_surf; + struct isp_surf *log_surf; + struct isp_surf *bt_surf; struct list_head gc; struct workqueue_struct *wq; @@ -225,6 +229,7 @@ struct apple_isp { wait_queue_head_t wait; dma_addr_t cmd_iova; + void *cmd_virt; unsigned long state; spinlock_t buf_lock; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 01b81714547206..70e201ea1ebd6f 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright 2023 Eileen Yoon */ +#include "isp-fw.h" + +#include #include #include #include @@ -38,6 +41,35 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->gpio + reg); } +void *apple_isp_translate(struct apple_isp *isp, struct isp_surf *surf, + dma_addr_t iova, size_t size) +{ + dma_addr_t end = iova + size; + if (!surf) { + dev_err(isp->dev, + "Failed to translate IPC iova 0x%llx (0x%zx): No surface\n", + (long long)iova, size); + return NULL; + } + + if (end < iova || iova < surf->iova || + end > (surf->iova + surf->size)) { + dev_err(isp->dev, + "Failed to translate IPC iova 0x%llx (0x%zx): Out of bounds\n", + (long long)iova, size); + return NULL; + } + + if (!surf->virt) { + dev_err(isp->dev, + "Failed to translate IPC iova 0x%llx (0x%zx): No VMap\n", + (long long)iova, size); + return NULL; + } + + return surf->virt + (iova - surf->iova); +} + struct isp_firmware_bootargs { u32 pad_0[2]; u64 ipc_iova; @@ -232,6 +264,8 @@ int apple_isp_alloc_firmware_surface(struct apple_isp *isp) isp_err(isp, "failed to alloc shared surface for ipc\n"); return -ENOMEM; } + dev_info(isp->dev, "IPC surface iova: 0x%llx\n", + (long long)isp->ipc_surf->iova); isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE); if (!isp->data_surf) { @@ -239,6 +273,8 @@ int apple_isp_alloc_firmware_surface(struct apple_isp *isp) isp_free_surface(isp, isp->ipc_surf); return -ENOMEM; } + dev_info(isp->dev, "Data surface iova: 0x%llx\n", + (long long)isp->data_surf->iova); return 0; } @@ -258,6 +294,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) { struct isp_firmware_bootargs args; dma_addr_t args_iova; + void *args_virt; int err, retries; u32 num_ipc_chans = isp_gpio_read32(isp, ISP_GPIO_0); @@ -281,7 +318,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) } args_iova = isp->ipc_surf->iova + args_offset + 0x40; + args_virt = isp->ipc_surf->virt + args_offset + 0x40; isp->cmd_iova = args_iova + sizeof(args) + 0x40; + isp->cmd_virt = args_virt + sizeof(args) + 0x40; memset(&args, 0, sizeof(args)); args.ipc_iova = isp->ipc_surf->iova; @@ -295,7 +334,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.unk7 = 0x1; // 0? args.unk_iova1 = args_iova + sizeof(args) - 0xc; args.unk9 = 0x3; - isp_iowrite(isp, args_iova, &args, sizeof(args)); + memcpy(args_virt, &args, sizeof(args)); isp_gpio_write32(isp, ISP_GPIO_0, args_iova); isp_gpio_write32(isp, ISP_GPIO_1, args_iova >> 32); @@ -355,7 +394,15 @@ static void isp_free_channel_info(struct apple_isp *isp) static int isp_fill_channel_info(struct apple_isp *isp) { u64 table_iova = isp_gpio_read32(isp, ISP_GPIO_0) | - ((u64)isp_gpio_read32(isp, ISP_GPIO_1)) << 32; + ((u64)isp_gpio_read32(isp, ISP_GPIO_1)) << 32; + void *table_virt = apple_isp_ipc_translate( + isp, table_iova, + sizeof(struct isp_chan_desc) * isp->num_ipc_chans); + + if (!table_virt) { + dev_err(isp->dev, "Failed to find channel table\n"); + return -EIO; + } isp->ipc_chans = kcalloc(isp->num_ipc_chans, sizeof(struct isp_channel *), GFP_KERNEL); @@ -364,14 +411,14 @@ static int isp_fill_channel_info(struct apple_isp *isp) for (int i = 0; i < isp->num_ipc_chans; i++) { struct isp_chan_desc desc; - dma_addr_t desc_iova = table_iova + (i * sizeof(desc)); + void *desc_virt = table_virt + (i * sizeof(desc)); struct isp_channel *chan = kzalloc(sizeof(struct isp_channel), GFP_KERNEL); if (!chan) goto out; isp->ipc_chans[i] = chan; - isp_ioread(isp, desc_iova, &desc, sizeof(desc)); + memcpy(&desc, desc_virt, sizeof(desc)); chan->name = kstrdup(desc.name, GFP_KERNEL); chan->type = desc.type; chan->src = desc.src; @@ -379,9 +426,16 @@ static int isp_fill_channel_info(struct apple_isp *isp) chan->num = desc.num; chan->size = desc.num * ISP_IPC_MESSAGE_SIZE; chan->iova = desc.iova; + chan->virt = + apple_isp_ipc_translate(isp, desc.iova, chan->size); chan->cursor = 0; spin_lock_init(&chan->lock); + if (!chan->virt) { + dev_err(isp->dev, "Failed to find channel buffer\n"); + goto out; + } + if ((chan->type != ISP_IPC_CHAN_TYPE_COMMAND) && (chan->type != ISP_IPC_CHAN_TYPE_REPLY) && (chan->type != ISP_IPC_CHAN_TYPE_REPORT)) { @@ -439,11 +493,11 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp) continue; for (int j = 0; j < chan->num; j++) { struct isp_message msg; - dma_addr_t msg_iova = chan->iova + (j * sizeof(msg)); + void *msg_virt = chan->virt + (j * sizeof(msg)); memset(&msg, 0, sizeof(msg)); msg.arg0 = ISP_IPC_FLAG_ACK; - isp_iowrite(isp, msg_iova, &msg, sizeof(msg)); + memcpy(msg_virt, &msg, sizeof(msg)); } } wmb(); @@ -547,6 +601,10 @@ static int isp_start_command_processor(struct apple_isp *isp) static void isp_collect_gc_surface(struct apple_isp *isp) { struct isp_surf *tmp, *surf; + + isp->log_surf = NULL; + isp->bt_surf = NULL; + list_for_each_entry_safe_reverse(surf, tmp, &isp->gc, head) { isp_dbg(isp, "freeing iova: 0x%llx size: 0x%llx virt: %pS\n", surf->iova, surf->size, (void *)surf->virt); diff --git a/drivers/media/platform/apple/isp/isp-fw.h b/drivers/media/platform/apple/isp/isp-fw.h index 264717793cea02..974216f0989f91 100644 --- a/drivers/media/platform/apple/isp/isp-fw.h +++ b/drivers/media/platform/apple/isp/isp-fw.h @@ -12,4 +12,13 @@ void apple_isp_free_firmware_surface(struct apple_isp *isp); int apple_isp_firmware_boot(struct apple_isp *isp); void apple_isp_firmware_shutdown(struct apple_isp *isp); +void *apple_isp_translate(struct apple_isp *isp, struct isp_surf *surf, + dma_addr_t iova, size_t size); + +static inline void *apple_isp_ipc_translate(struct apple_isp *isp, + dma_addr_t iova, size_t size) +{ + return apple_isp_translate(isp, isp->ipc_surf, iova, size); +} + #endif /* __ISP_FW_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c index 0a9d0d6a350c9a..845c35da0253ae 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.c +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -213,12 +213,6 @@ void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf) } } -void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova) -{ - phys_addr_t phys = iommu_iova_to_phys(isp->domain, iova); - return phys_to_virt(phys); -} - int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, struct sg_table *sgt, u64 size) { diff --git a/drivers/media/platform/apple/isp/isp-iommu.h b/drivers/media/platform/apple/isp/isp-iommu.h index 326cf7c12aa745..b99a182e284b72 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.h +++ b/drivers/media/platform/apple/isp/isp-iommu.h @@ -12,21 +12,6 @@ struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc); struct isp_surf *isp_alloc_surface_vmap(struct apple_isp *isp, u64 size); int isp_surf_vmap(struct apple_isp *isp, struct isp_surf *surf); void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf); -void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova); - -static inline void isp_ioread(struct apple_isp *isp, dma_addr_t iova, - void *data, u64 size) -{ - void *virt = isp_iotranslate(isp, iova); - memcpy(data, virt, size); -} - -static inline void isp_iowrite(struct apple_isp *isp, dma_addr_t iova, - void *data, u64 size) -{ - void *virt = isp_iotranslate(isp, iova); - memcpy(virt, data, size); -} int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, struct sg_table *sgt, u64 size); diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 14249a44798ba5..a5c8a5ed8f98b9 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -4,6 +4,7 @@ #include "isp-iommu.h" #include "isp-ipc.h" #include "isp-regs.h" +#include "isp-fw.h" #define ISP_IPC_FLAG_TERMINAL_ACK 0x3 #define ISP_IPC_BUFEXC_STAT_META_OFFSET 0x10 @@ -54,16 +55,16 @@ struct isp_bufexc_stat { } __packed; static_assert(sizeof(struct isp_bufexc_stat) == ISP_IPC_BUFEXC_STAT_SIZE); -static inline dma_addr_t chan_msg_iova(struct isp_channel *chan, u32 index) +static inline void *chan_msg_virt(struct isp_channel *chan, u32 index) { - return chan->iova + (index * ISP_IPC_MESSAGE_SIZE); + return chan->virt + (index * ISP_IPC_MESSAGE_SIZE); } static inline void chan_read_msg_index(struct apple_isp *isp, struct isp_channel *chan, struct isp_message *msg, u32 index) { - isp_ioread(isp, chan_msg_iova(chan, index), msg, sizeof(*msg)); + memcpy(msg, chan_msg_virt(chan, index), sizeof(*msg)); } static inline void chan_read_msg(struct apple_isp *isp, @@ -77,7 +78,7 @@ static inline void chan_write_msg_index(struct apple_isp *isp, struct isp_channel *chan, struct isp_message *msg, u32 index) { - isp_iowrite(isp, chan_msg_iova(chan, index), msg, sizeof(*msg)); + memcpy(chan_msg_virt(chan, index), msg, sizeof(*msg)); } static inline void chan_write_msg(struct apple_isp *isp, @@ -191,10 +192,14 @@ int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan) char buf[512]; dma_addr_t iova = req->arg0 & ~ISP_IPC_FLAG_TERMINAL_ACK; u32 size = req->arg1; - if (iova && size && test_bit(ISP_STATE_LOGGING, &isp->state)) { - size = min_t(u32, size, 512); - isp_ioread(isp, iova, buf, size); - isp_dbg(isp, "ISPASC: %.*s", size, buf); + if (iova && size && size < sizeof(buf) && + test_bit(ISP_STATE_LOGGING, &isp->state)) { + void *p = apple_isp_translate(isp, isp->log_surf, iova, size); + if (p) { + size = min_t(u32, size, 512); + memcpy(buf, p, size); + isp_dbg(isp, "ISPASC: %.*s", size, buf); + } } #endif @@ -205,75 +210,50 @@ int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan) return 0; } -/* The kernel accesses exactly two dynamically allocated shared surfaces: - * 1) LOG: Surface for terminal logs. Optional, only enabled in debug builds. - * 2) STAT: Surface for BUFT2H rendered frame stat buffer. We isp_ioread() in - * the BUFT2H ISR below. Since the BUFT2H IRQ is triggered by the BUF_H2T - * doorbell, the STAT vmap must complete before the first buffer submission - * under VIDIOC_STREAMON(). The CISP_CMD_PRINT_ENABLE completion depends on the - * STAT buffer SHAREDMALLOC ISR, which is part of the firmware initialization - * sequence. We also call flush_workqueue(), so a fault should not occur. - */ -static void sm_malloc_deferred_worker(struct work_struct *work) -{ - struct isp_sm_deferred_work *dwork = - container_of(work, struct isp_sm_deferred_work, work); - struct apple_isp *isp = dwork->isp; - struct isp_surf *surf = dwork->surf; - int err; - - err = isp_surf_vmap(isp, surf); /* Can't vmap in interrupt ctx */ - if (err < 0) { - isp_err(isp, "failed to vmap iova=0x%llx size=0x%llx\n", - surf->iova, surf->size); - goto out; - } - -#ifdef APPLE_ISP_DEBUG - /* Only enabled in debug builds so it shouldn't matter, but - * the LOG surface is always the first surface requested. - */ - if (!test_bit(ISP_STATE_LOGGING, &isp->state)) - set_bit(ISP_STATE_LOGGING, &isp->state); -#endif - -out: - kfree(dwork); -} - int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) { struct isp_message *req = &chan->req, *rsp = &chan->rsp; + int err; if (req->arg0 == 0x0) { - struct isp_sm_deferred_work *dwork; struct isp_surf *surf; - dwork = kzalloc(sizeof(*dwork), GFP_KERNEL); - if (!dwork) - return -ENOMEM; - dwork->isp = isp; - surf = isp_alloc_surface_gc(isp, req->arg1); if (!surf) { isp_err(isp, "failed to alloc requested size 0x%llx\n", req->arg1); - kfree(dwork); return -ENOMEM; } - dwork->surf = surf; + surf->type = req->arg2; rsp->arg0 = surf->iova | ISP_IPC_FLAG_ACK; rsp->arg1 = 0x0; rsp->arg2 = 0x0; /* macOS uses this to index surfaces */ - INIT_WORK(&dwork->work, sm_malloc_deferred_worker); - if (!queue_work(isp->wq, &dwork->work)) { - isp_err(isp, "failed to queue deferred work\n"); - isp_free_surface(isp, surf); - kfree(dwork); - return -ENOMEM; + err = isp_surf_vmap(isp, surf); + if (err < 0) { + isp_err(isp, "failed to vmap iova=0x%llx size=0x%llx\n", + surf->iova, surf->size); + } else { + switch (surf->type) { + case 0x4c4f47: /* "LOG" */ + isp->log_surf = surf; + break; + case 0x4d495343: /* "MISC" */ + /* Hacky... maybe there's a better way to identify this surface? */ + if (surf->size == 0xc000) + isp->bt_surf = surf; + break; + } } + +#ifdef APPLE_ISP_DEBUG + /* Only enabled in debug builds so it shouldn't matter, but + * the LOG surface is always the first surface requested. + */ + if (!test_bit(ISP_STATE_LOGGING, &isp->state)) + set_bit(ISP_STATE_LOGGING, &isp->state); +#endif /* To the gc it goes... */ } else { @@ -302,8 +282,15 @@ int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) /* No need to read the whole struct */ u64 meta_iova; - isp_ioread(isp, req->arg0 + ISP_IPC_BUFEXC_STAT_META_OFFSET, &meta_iova, - sizeof(meta_iova)); + u64 *p_meta_iova = apple_isp_translate( + isp, isp->bt_surf, req->arg0 + ISP_IPC_BUFEXC_STAT_META_OFFSET, + sizeof(u64)); + + if (!p_meta_iova) { + dev_err(isp->dev, "Failed to find bufexc stat meta\n"); + return -EIO; + } + meta_iova = *p_meta_iova; spin_lock(&isp->buf_lock); list_for_each_entry_safe_reverse(buf, tmp, &isp->bufs_submitted, link) { diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index fcc1d7edc32f5d..1f38d3c432d7d0 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -91,7 +91,7 @@ static int isp_submit_buffers(struct apple_isp *isp) req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; - isp_iowrite(isp, req->arg0, args, sizeof(*args)); + memcpy(isp->cmd_virt, args, sizeof(*args)); err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); if (err) { /* If we fail, consider the buffer not submitted. */ From 3f656027a9178671d20caa1f53ad11e231a7db69 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 19:18:40 +0900 Subject: [PATCH 304/352] media: apple: isp: Propagate EINTR from firmware loads Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index abdc9e345933d8..9ccdc2a1304bed 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -340,6 +340,10 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) { dev_err(isp->dev, "warning: calibration data not loaded: %d\n", err); + + /* If this failed due to a signal, propagate */ + if (err == -EINTR) + return err; } if (isp->hw->gen >= ISP_GEN_T8112) { From 99ab36f7b7e999ffc07abff798c92480d6cf26b3 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 19:19:12 +0900 Subject: [PATCH 305/352] media: apple: isp: Implement posted commands Useful for shutdown type commands which may not be acked... Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cmd.c | 11 ++++++----- drivers/media/platform/apple/isp/isp-ipc.c | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 1166f0990830ed..26ae639b3a63d9 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -10,11 +10,12 @@ #define CISP_OPCODE_GET(x) (((u64)(x)) >> CISP_OPCODE_SHIFT) #define CISP_TIMEOUT msecs_to_jiffies(3000) -#define CISP_SEND_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0)) -#define CISP_SEND_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a))) +#define CISP_SEND_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0, CISP_TIMEOUT)) +#define CISP_SEND_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a), CISP_TIMEOUT)) #define CISP_SEND_OUT(x, a) (cisp_send_read((x), (a), sizeof(*a), sizeof(*a))) +#define CISP_POST_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0, 0)) -static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize) +static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize, int timeout) { struct isp_channel *chan = isp->chan_io; struct isp_message *req = &chan->req; @@ -25,7 +26,7 @@ static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize) req->arg2 = outsize; memcpy(isp->cmd_virt, args, insize); - err = ipc_chan_send(isp, chan, CISP_TIMEOUT); + err = ipc_chan_send(isp, chan, timeout); if (err) { u64 opcode; memcpy(&opcode, args, sizeof(opcode)); @@ -42,7 +43,7 @@ static int cisp_send_read(struct apple_isp *isp, void *args, u32 insize, u32 outsize) { /* TODO do I need to lock the iova space? */ - int err = cisp_send(isp, args, insize, outsize); + int err = cisp_send(isp, args, insize, outsize, CISP_TIMEOUT); if (err) return err; diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index a5c8a5ed8f98b9..64e0f7c701ad23 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -168,6 +168,9 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); + if (!timeout) + return 0; + t = wait_event_interruptible_timeout(isp->wait, chan_tx_done(isp, chan), timeout); if (t == 0) { From c5640f07bbc6c2772d5edfb54c338f2161add1ab Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 19:21:38 +0900 Subject: [PATCH 306/352] media: apple: isp: Add STOP and POWER_DOWN commands Not sure if these work properly yet, but worth having them to experiment. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cmd.c | 17 +++++++++++++++++ drivers/media/platform/apple/isp/isp-cmd.h | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 26ae639b3a63d9..bd82d266522dc0 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -60,6 +60,23 @@ int isp_cmd_start(struct apple_isp *isp, u32 mode) return CISP_SEND_IN(isp, args); } +int isp_cmd_stop(struct apple_isp *isp, u32 mode) +{ + struct cmd_stop args = { + .opcode = CISP_OPCODE(CISP_CMD_STOP), + .mode = mode, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_power_down(struct apple_isp *isp) +{ + struct cmd_power_down args = { + .opcode = CISP_OPCODE(CISP_CMD_POWER_DOWN), + }; + return CISP_POST_INOUT(isp, args); +} + int isp_cmd_suspend(struct apple_isp *isp) { struct cmd_suspend args = { diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index 1586df89f1cdab..2de2a49f2cd398 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -12,6 +12,7 @@ #define CISP_CMD_PRINT_ENABLE 0x0004 #define CISP_CMD_BUILDINFO 0x0006 #define CISP_CMD_GET_BES_PARAM 0x000f +#define CISP_CMD_POWER_DOWN 0x0010 #define CISP_CMD_SET_ISP_PMU_BASE 0x0011 #define CISP_CMD_PMP_CTRL_SET 0x001c #define CISP_CMD_TRACE_ENABLE 0x001d @@ -130,6 +131,17 @@ struct cmd_start { } __packed; static_assert(sizeof(struct cmd_start) == 0xc); +struct cmd_stop { + u64 opcode; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_stop) == 0xc); + +struct cmd_power_down { + u64 opcode; +} __packed; +static_assert(sizeof(struct cmd_power_down) == 0x8); + struct cmd_suspend { u64 opcode; } __packed; @@ -221,6 +233,8 @@ struct cmd_ipc_endpoint_set2 { static_assert(sizeof(struct cmd_ipc_endpoint_set2) == 0x30); int isp_cmd_start(struct apple_isp *isp, u32 mode); +int isp_cmd_stop(struct apple_isp *isp, u32 mode); +int isp_cmd_power_down(struct apple_isp *isp); int isp_cmd_suspend(struct apple_isp *isp); int isp_cmd_print_enable(struct apple_isp *isp, u32 enable); int isp_cmd_trace_enable(struct apple_isp *isp, u32 enable); From c0aa5bb7c9f52644ac292ce40de99899322e2bb9 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 30 Sep 2023 00:15:27 +0900 Subject: [PATCH 307/352] media: apple: isp: Maybe fix some DMA ordering issues Maybe. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 4 ++-- drivers/media/platform/apple/isp/isp-ipc.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 70e201ea1ebd6f..2ee815fcc0c72c 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -338,7 +338,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) isp_gpio_write32(isp, ISP_GPIO_0, args_iova); isp_gpio_write32(isp, ISP_GPIO_1, args_iova >> 32); - wmb(); + dma_wmb(); /* Wait for ISP_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ isp_gpio_write32(isp, ISP_GPIO_7, 0xf7fbdff9); @@ -500,7 +500,7 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp) memcpy(msg_virt, &msg, sizeof(msg)); } } - wmb(); + dma_wmb(); /* Wait for ISP_GPIO_3 to 0x8042006 -> 0x0 */ isp_gpio_write32(isp, ISP_GPIO_3, 0x8042006); diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 64e0f7c701ad23..8167f9d750dded 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -78,7 +78,14 @@ static inline void chan_write_msg_index(struct apple_isp *isp, struct isp_channel *chan, struct isp_message *msg, u32 index) { - memcpy(chan_msg_virt(chan, index), msg, sizeof(*msg)); + u64 *p0 = chan_msg_virt(chan, index); + memcpy(p0 + 1, &msg->arg1, sizeof(*msg) - 8); + + /* Make sure we write arg0 last, since that indicates message validity. */ + + dma_wmb(); + *p0 = msg->arg0; + dma_wmb(); } static inline void chan_write_msg(struct apple_isp *isp, @@ -164,7 +171,7 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, long t; chan_write_msg(isp, chan, &chan->req); - wmb(); + dma_wmb(); isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); From bb4fae653c8c041a258398f95d0594a7d520fb04 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 30 Sep 2023 00:15:41 +0900 Subject: [PATCH 308/352] media: apple: isp: Make channel sends not interruptible Otherwise processes receiving a signal will break our command flows. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 6 +++--- drivers/media/platform/apple/isp/isp-ipc.c | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 2ee815fcc0c72c..dd88ddf8a2a8c6 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -132,15 +132,15 @@ static irqreturn_t apple_isp_isr_thread(int irq, void *dev) { struct apple_isp *isp = dev; - wake_up_interruptible_all(&isp->wait); + wake_up_all(&isp->wait); ipc_chan_handle(isp, isp->chan_sm); - wake_up_interruptible_all(&isp->wait); /* Some commands depend on sm */ + wake_up_all(&isp->wait); /* Some commands depend on sm */ ipc_chan_handle(isp, isp->chan_tm); ipc_chan_handle(isp, isp->chan_bt); - wake_up_interruptible_all(&isp->wait); + wake_up_all(&isp->wait); return IRQ_HANDLED; } diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 8167f9d750dded..4dddeb71261843 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -178,8 +178,7 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, if (!timeout) return 0; - t = wait_event_interruptible_timeout(isp->wait, chan_tx_done(isp, chan), - timeout); + t = wait_event_timeout(isp->wait, chan_tx_done(isp, chan), timeout); if (t == 0) { dev_err(isp->dev, "%s: timed out on request [0x%llx, 0x%llx, 0x%llx]\n", From 41a3544435e3750f539630cda6981206f9961d85 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 28 Sep 2023 08:11:20 +0200 Subject: [PATCH 309/352] media: apple: isp: Use a second region for MBOX_IRQ_{DOORBELL,ACK} t8112 uses a different register layout. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-drv.c | 6 ++++++ drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-fw.c | 2 +- drivers/media/platform/apple/isp/isp-ipc.c | 4 ++-- drivers/media/platform/apple/isp/isp-regs.h | 13 +++++++++---- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 5a15b812c3dcfa..0070cda4e516da 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -267,6 +267,12 @@ static int apple_isp_probe(struct platform_device *pdev) goto detach_genpd; } + isp->mbox2 = devm_platform_ioremap_resource_byname(pdev, "mbox2"); + if (IS_ERR(isp->mbox2)) { + err = PTR_ERR(isp->mbox2); + goto detach_genpd; + } + isp->irq = platform_get_irq(pdev, 0); if (isp->irq < 0) { err = isp->irq; diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 26b9ee0e4d709f..4d3b1bd7603aea 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -199,6 +199,7 @@ struct apple_isp { void __iomem *coproc; void __iomem *mbox; void __iomem *gpio; + void __iomem *mbox2; struct iommu_domain *domain; unsigned long shift; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index dd88ddf8a2a8c6..5c1739e58ab001 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -122,7 +122,7 @@ static irqreturn_t apple_isp_isr(int irq, void *dev) { struct apple_isp *isp = dev; - isp_mbox_write32(isp, ISP_MBOX_IRQ_ACK, + isp_mbox2_write32(isp, ISP_MBOX2_IRQ_ACK, isp_mbox_read32(isp, ISP_MBOX_IRQ_INTERRUPT)); return IRQ_WAKE_THREAD; diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 4dddeb71261843..5901d1b5db9b5b 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -118,7 +118,7 @@ static int chan_handle_once(struct apple_isp *isp, struct isp_channel *chan) chan_write_msg(isp, chan, &chan->rsp); - isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); + isp_mbox2_write32(isp, ISP_MBOX2_IRQ_DOORBELL, chan->doorbell); chan_update_cursor(chan); @@ -173,7 +173,7 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, chan_write_msg(isp, chan, &chan->req); dma_wmb(); - isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); + isp_mbox2_write32(isp, ISP_MBOX2_IRQ_DOORBELL, chan->doorbell); if (!timeout) return 0; diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h index 3a99229f6d4c8f..7357fa10fa5483 100644 --- a/drivers/media/platform/apple/isp/isp-regs.h +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -23,10 +23,10 @@ #define ISP_COPROC_IRQ_MASK_4 0x1400a10 #define ISP_COPROC_IRQ_MASK_5 0x1400a14 -#define ISP_MBOX_IRQ_INTERRUPT 0x000 -#define ISP_MBOX_IRQ_ENABLE 0x004 -#define ISP_MBOX_IRQ_DOORBELL 0x3f0 -#define ISP_MBOX_IRQ_ACK 0x3fc +#define ISP_MBOX_IRQ_INTERRUPT 0x00 +#define ISP_MBOX_IRQ_ENABLE 0x04 +#define ISP_MBOX2_IRQ_DOORBELL 0x00 +#define ISP_MBOX2_IRQ_ACK 0x0c #define ISP_GPIO_0 0x00 #define ISP_GPIO_1 0x04 @@ -48,4 +48,9 @@ static inline void isp_mbox_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->mbox + reg); } +static inline void isp_mbox2_write32(struct apple_isp *isp, u32 reg, u32 val) +{ + writel(val, isp->mbox2 + reg); +} + #endif /* __ISP_REGS_H__ */ From fbedcd651ea848284fc3e19d73bacce0bc5839d8 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 28 Sep 2023 08:27:10 +0200 Subject: [PATCH 310/352] media: apple: isp: t8112 HW config Not yet working. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-drv.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 0070cda4e516da..195e916021d4c6 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -405,19 +405,14 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { .meta_size = ISP_META_SIZE_T8103, }; -static const struct apple_isp_hw apple_isp_hw_t8110 = { +static const struct apple_isp_hw apple_isp_hw_t8112 = { .gen = ISP_GEN_T8112, .pmu_base = 0x23b704000, - .dsid_count = 4, - .dsid_clr_base0 = 0x200014000, // TODO - .dsid_clr_base1 = 0x200054000, - .dsid_clr_base2 = 0x200094000, - .dsid_clr_base3 = 0x2000d4000, + // TODO: verify + .dsid_count = 1, + .dsid_clr_base0 = 0x200f14000, .dsid_clr_range0 = 0x1000, - .dsid_clr_range1 = 0x1000, - .dsid_clr_range2 = 0x1000, - .dsid_clr_range3 = 0x1000, .clock_scratch = 0x23b3d0560, .clock_base = 0x0, @@ -455,6 +450,7 @@ static const struct apple_isp_hw apple_isp_hw_t6020 = { static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, + { .compatible = "apple,t8112-isp", .data = &apple_isp_hw_t8112 }, { .compatible = "apple,t6000-isp", .data = &apple_isp_hw_t6000 }, { .compatible = "apple,t6020-isp", .data = &apple_isp_hw_t6020 }, {}, From 956b7d307bec93e53731b7d5284c4a1769987db2 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 28 Sep 2023 20:45:18 +0200 Subject: [PATCH 311/352] media: apple: isp: Limit maximal number of buffers ISP (FW 12.3) on t6001 times out if more buffers than count in the buffer pool config are submitted before streaming is started. To avoid keeping track of the number of submitted buffers limit the number. 16 buffers / frames should be more than enough. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-cmd.c | 2 +- drivers/media/platform/apple/isp/isp-drv.h | 3 +++ drivers/media/platform/apple/isp/isp-v4l2.c | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index bd82d266522dc0..cbd9348f592dc2 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -395,7 +395,7 @@ int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, u16 type) .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_POOL_CONFIG_SET), .chan = chan, .type = type, - .count = 16, + .count = ISP_MAX_BUFFERS, .meta_size0 = isp->hw->meta_size, .meta_size1 = isp->hw->meta_size, .unk0 = 0, diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 4d3b1bd7603aea..8269b772bbd1bd 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -23,6 +23,9 @@ #define ISP_META_SIZE_T8103 0x4640 #define ISP_META_SIZE_T8112 0x4840 +/* used to limit the user space buffers to the buffer_pool_config */ +#define ISP_MAX_BUFFERS 16 + enum isp_generation { ISP_GEN_T8103, ISP_GEN_T8112, diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 1f38d3c432d7d0..60fb1c344dedf3 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -11,6 +11,7 @@ #include "isp-cam.h" #include "isp-cmd.h" +#include "isp-drv.h" #include "isp-iommu.h" #include "isp-ipc.h" #include "isp-v4l2.h" @@ -143,6 +144,13 @@ static int isp_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, struct apple_isp *isp = vb2_get_drv_priv(vq); struct isp_format *fmt = isp_get_current_format(isp); + /* This is not strictly neccessary but makes it easy to enforce that + * at most 16 buffers are submitted at once. ISP on t6001 (FW 12.3) + * times out if more buffers are submitted than set in the buffer pool + * config before streaming is started. + */ + *nbuffers = min_t(unsigned int, *nbuffers, ISP_MAX_BUFFERS); + if (*num_planes) { if (sizes[0] < fmt->total_size) return -EINVAL; From 5e7a615557ea8f1b16e9150b54a6e0042da7d8f5 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 30 Sep 2023 18:53:26 +0900 Subject: [PATCH 312/352] media: apple: isp: t8112 fixes... Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 4 ++-- drivers/media/platform/apple/isp/isp-cmd.c | 4 ++-- drivers/media/platform/apple/isp/isp-cmd.h | 2 +- drivers/media/platform/apple/isp/isp-drv.c | 12 ++++++++++-- drivers/media/platform/apple/isp/isp-drv.h | 2 ++ 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 9ccdc2a1304bed..4966fe64aac299 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -346,7 +346,7 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) return err; } - if (isp->hw->gen >= ISP_GEN_T8112) { + if (isp->hw->lpdp) { err = isp_cmd_ch_lpdp_hs_receiver_tuning_set(isp, ch, 1, 15); if (err) return err; @@ -395,7 +395,7 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_apple_ch_temporal_filter_start(isp, ch); + err = isp_cmd_apple_ch_temporal_filter_start(isp, ch, isp->temporal_filter); if (err) return err; diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index cbd9348f592dc2..15a5ec22778ced 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -416,13 +416,13 @@ int isp_cmd_ch_buffer_pool_return(struct apple_isp *isp, u32 chan) return CISP_SEND_IN(isp, args); } -int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan) +int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan, u32 arg) { struct cmd_apple_ch_temporal_filter_start args = { .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_START), .chan = chan, .unk_c = 1, - .unk_10 = 0, + .unk_10 = arg, }; return CISP_SEND_IN(isp, args); } diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index 2de2a49f2cd398..718ae88045ac25 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -577,7 +577,7 @@ struct cmd_apple_ch_temporal_filter_disable { } __packed; static_assert(sizeof(struct cmd_apple_ch_temporal_filter_disable) == 0xc); -int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan, u32 arg); int isp_cmd_apple_ch_temporal_filter_stop(struct apple_isp *isp, u32 chan); int isp_cmd_apple_ch_motion_history_start(struct apple_isp *isp, u32 chan); int isp_cmd_apple_ch_motion_history_stop(struct apple_isp *isp, u32 chan); diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 195e916021d4c6..0c0f9d6110f230 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -237,6 +237,11 @@ static int apple_isp_probe(struct platform_device *pdev) return err; } + err = of_property_read_u32(dev->of_node, "apple,temporal-filter", + &isp->temporal_filter); + if (err) + isp->temporal_filter = 0; + err = apple_isp_init_presets(isp); if (err) { dev_err(dev, "failed to initialize presets\n"); @@ -375,6 +380,7 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { .bandwidth_size = 0x4, .scl1 = false, + .lpdp = false, .meta_size = ISP_META_SIZE_T8103, }; @@ -402,6 +408,7 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { .bandwidth_size = 0x8, .scl1 = false, + .lpdp = false, .meta_size = ISP_META_SIZE_T8103, }; @@ -409,7 +416,6 @@ static const struct apple_isp_hw apple_isp_hw_t8112 = { .gen = ISP_GEN_T8112, .pmu_base = 0x23b704000, - // TODO: verify .dsid_count = 1, .dsid_clr_base0 = 0x200f14000, .dsid_clr_range0 = 0x1000, @@ -423,7 +429,8 @@ static const struct apple_isp_hw apple_isp_hw_t8112 = { .bandwidth_bit = 0x0, .bandwidth_size = 0x8, - .scl1 = true, + .scl1 = false, + .lpdp = false, .meta_size = ISP_META_SIZE_T8112, }; @@ -445,6 +452,7 @@ static const struct apple_isp_hw apple_isp_hw_t6020 = { .bandwidth_size = 0x8, .scl1 = true, + .lpdp = true, .meta_size = ISP_META_SIZE_T8112, }; diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 8269b772bbd1bd..b62d389442e810 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -111,6 +111,7 @@ struct apple_isp_hw { u32 meta_size; bool scl1; + bool lpdp; }; enum isp_sensor_id { @@ -178,6 +179,7 @@ struct apple_isp { struct device *dev; const struct apple_isp_hw *hw; u32 platform_id; + u32 temporal_filter; struct isp_preset *presets; int num_presets; From cbdd35a74b1f3e6336f59c7946ec9c8dd47740b1 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:18:25 +0900 Subject: [PATCH 313/352] media: apple: isp: Add flicker_sensor_set cmd Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cmd.c | 10 ++++++++++ drivers/media/platform/apple/isp/isp-cmd.h | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 15a5ec22778ced..9c5808b4e831be 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -14,6 +14,7 @@ #define CISP_SEND_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a), CISP_TIMEOUT)) #define CISP_SEND_OUT(x, a) (cisp_send_read((x), (a), sizeof(*a), sizeof(*a))) #define CISP_POST_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0, 0)) +#define CISP_POST_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a), 0)) static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize, int timeout) { @@ -204,6 +205,15 @@ int isp_cmd_ch_stop(struct apple_isp *isp, u32 chan) return CISP_SEND_IN(isp, args); } +int isp_cmd_flicker_sensor_set(struct apple_isp *isp, u32 mode) +{ + struct cmd_flicker_sensor_set args = { + .opcode = CISP_OPCODE(CISP_CMD_FLICKER_SENSOR_SET), + .mode = mode, + }; + return CISP_SEND_INOUT(isp, args); +} + int isp_cmd_ch_info_get(struct apple_isp *isp, u32 chan, struct cmd_ch_info *args) { diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index 718ae88045ac25..5a3c8cd9177e48 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -232,6 +232,12 @@ struct cmd_ipc_endpoint_set2 { } __packed; static_assert(sizeof(struct cmd_ipc_endpoint_set2) == 0x30); +struct cmd_flicker_sensor_set { + u64 opcode; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_flicker_sensor_set) == 0xc); + int isp_cmd_start(struct apple_isp *isp, u32 mode); int isp_cmd_stop(struct apple_isp *isp, u32 mode); int isp_cmd_power_down(struct apple_isp *isp); @@ -253,6 +259,7 @@ int isp_cmd_pmp_ctrl_set(struct apple_isp *isp, u64 clock_scratch, u8 bandwidth_bit, u8 bandwidth_size); int isp_cmd_fid_enter(struct apple_isp *isp); int isp_cmd_fid_exit(struct apple_isp *isp); +int isp_cmd_flicker_sensor_set(struct apple_isp *isp, u32 mode); struct cmd_ch_start { u64 opcode; From 60fd81258e061cbe526485719d0a65857af29a80 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:18:46 +0900 Subject: [PATCH 314/352] media: apple: isp: Minor changes to cam flow Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 36 +++++++++++++--------- drivers/media/platform/apple/isp/isp-cam.h | 1 + 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 4966fe64aac299..cc0c24c3cfb715 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -289,6 +289,12 @@ int apple_isp_detect_camera(struct apple_isp *isp) } err = isp_detect_camera(isp); + + isp_cmd_flicker_sensor_set(isp, 0); + + isp_cmd_ch_stop(isp, 0); + isp_cmd_ch_buffer_return(isp, isp->current_ch); + apple_isp_firmware_shutdown(isp); return err; @@ -335,6 +341,8 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) struct isp_format *fmt = isp_get_format(isp, ch); int err; + isp_cmd_flicker_sensor_set(isp, 0); + /* The setfile isn't requisite but then we don't get calibration */ err = isp_ch_load_setfile(isp, ch); if (err) { @@ -356,16 +364,16 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_ch_buffer_recycle_mode_set( - isp, ch, CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY); + err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset->index); if (err) return err; - err = isp_cmd_ch_buffer_recycle_start(isp, ch); + err = isp_cmd_ch_buffer_recycle_mode_set( + isp, ch, CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY); if (err) return err; - err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset->index); + err = isp_cmd_ch_buffer_recycle_start(isp, ch); if (err) return err; @@ -395,43 +403,43 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_apple_ch_temporal_filter_start(isp, ch, isp->temporal_filter); + err = isp_cmd_apple_ch_ae_fd_scene_metering_config_set(isp, ch); if (err) return err; - err = isp_cmd_apple_ch_motion_history_start(isp, ch); + err = isp_cmd_apple_ch_ae_metering_mode_set(isp, ch, 3); if (err) return err; - err = isp_cmd_apple_ch_temporal_filter_enable(isp, ch); + err = isp_cmd_ch_ae_stability_set(isp, ch, 32); if (err) return err; - err = isp_cmd_apple_ch_ae_fd_scene_metering_config_set(isp, ch); + err = isp_cmd_ch_ae_stability_to_stable_set(isp, ch, 20); if (err) return err; - err = isp_cmd_apple_ch_ae_metering_mode_set(isp, ch, 3); + err = isp_cmd_ch_sif_pixel_format_set(isp, ch); if (err) return err; - err = isp_cmd_ch_ae_stability_set(isp, ch, 32); + err = isp_cmd_ch_ae_frame_rate_max_set(isp, ch, ISP_FRAME_RATE_DEN); if (err) return err; - err = isp_cmd_ch_ae_stability_to_stable_set(isp, ch, 20); + err = isp_cmd_ch_ae_frame_rate_min_set(isp, ch, ISP_FRAME_RATE_DEN2); if (err) return err; - err = isp_cmd_ch_sif_pixel_format_set(isp, ch); + err = isp_cmd_apple_ch_temporal_filter_start(isp, ch, isp->temporal_filter); if (err) return err; - err = isp_cmd_ch_ae_frame_rate_max_set(isp, ch, ISP_FRAME_RATE_DEN); + err = isp_cmd_apple_ch_motion_history_start(isp, ch); if (err) return err; - err = isp_cmd_ch_ae_frame_rate_min_set(isp, ch, ISP_FRAME_RATE_DEN); + err = isp_cmd_apple_ch_temporal_filter_enable(isp, ch); if (err) return err; diff --git a/drivers/media/platform/apple/isp/isp-cam.h b/drivers/media/platform/apple/isp/isp-cam.h index 126e5806c8c416..f4fa4224c7a934 100644 --- a/drivers/media/platform/apple/isp/isp-cam.h +++ b/drivers/media/platform/apple/isp/isp-cam.h @@ -8,6 +8,7 @@ #define ISP_FRAME_RATE_NUM 256 #define ISP_FRAME_RATE_DEN 7680 +#define ISP_FRAME_RATE_DEN2 3840 int apple_isp_detect_camera(struct apple_isp *isp); From a0813da74f54e3e32ae7122351f955df04885501 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:21:54 +0900 Subject: [PATCH 315/352] media: apple: isp: Make sub-pmdomain handling explicit Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-drv.c | 11 ++++-- drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-fw.c | 45 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 0c0f9d6110f230..2ea4ecad36c75e 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -54,6 +54,12 @@ static int apple_isp_attach_genpd(struct apple_isp *isp) return -ENOMEM; for (int i = 0; i < isp->pd_count; i++) { + int flags = DL_FLAG_STATELESS; + + /* Primary power domain uses RPM integration */ + if (i == 0) + flags |= DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE; + isp->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); if (IS_ERR(isp->pd_dev[i])) { apple_isp_detach_genpd(isp); @@ -61,9 +67,8 @@ static int apple_isp_attach_genpd(struct apple_isp *isp) } isp->pd_link[i] = - device_link_add(dev, isp->pd_dev[i], - DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); + device_link_add(dev, isp->pd_dev[i], flags); + if (!isp->pd_link[i]) { apple_isp_detach_genpd(isp); return -EINVAL; diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index b62d389442e810..775a435c4a06ad 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -198,6 +198,7 @@ struct apple_isp { int pd_count; struct device **pd_dev; struct device_link **pd_link; + bool pds_active; int irq; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 5c1739e58ab001..75405c2258239e 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -41,6 +41,46 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->gpio + reg); } +int apple_isp_power_up_domains(struct apple_isp *isp) +static int apple_isp_power_up_domains(struct apple_isp *isp) + int ret; + + if (isp->pds_active) + return 0; + + for (int i = 1; i < isp->pd_count; i++) { + ret = pm_runtime_get_sync(isp->pd_dev[i]); + if (ret < 0) { + dev_err(isp->dev, + "Failed to power up power domain %d: %d\n", i, ret); + while (--i != 1) + pm_runtime_put_sync(isp->pd_dev[i]); + return ret; + } + } + + isp->pds_active = true; + + return 0; +} + +void apple_isp_power_down_domains(struct apple_isp *isp) +static void apple_isp_power_down_domains(struct apple_isp *isp) + int ret; + + if (!isp->pds_active) + return; + + for (int i = isp->pd_count - 1; i >= 1; i--) { + ret = pm_runtime_put_sync(isp->pd_dev[i]); + if (ret < 0) + dev_err(isp->dev, + "Failed to power up power domain %d: %d\n", i, ret); + } + + isp->pds_active = false; +} + void *apple_isp_translate(struct apple_isp *isp, struct isp_surf *surf, dma_addr_t iova, size_t size) { @@ -209,11 +249,16 @@ static int isp_reset_coproc(struct apple_isp *isp) static void isp_firmware_shutdown_stage1(struct apple_isp *isp) { isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x0); + + apple_isp_power_down_domains(isp); } static int isp_firmware_boot_stage1(struct apple_isp *isp) { int err, retries; + err = apple_isp_power_up_domains(isp); + if (err < 0) + return err; err = isp_reset_coproc(isp); if (err < 0) From 6db91bd526c0a450b10394f85d06146d106deac3 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:22:49 +0900 Subject: [PATCH 316/352] media: apple: isp: Zero out pages allocated to ISP Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c index 845c35da0253ae..19d3c3bfa62ee9 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.c +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -22,7 +22,7 @@ static int isp_surf_alloc_pages(struct isp_surf *surf) return -ENOMEM; for (u32 i = 0; i < surf->num_pages; i++) { - surf->pages[i] = alloc_page(GFP_KERNEL); + surf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); if (surf->pages[i] == NULL) goto free_pages; } From d26c6ad5fca40d4948c1c3b1a12282708927de19 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:22:58 +0900 Subject: [PATCH 317/352] media: apple: isp: Use cached IOMMU mappings Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c index 19d3c3bfa62ee9..1ddd089d77355a 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.c +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -113,7 +113,7 @@ static int isp_surf_iommu_map(struct apple_isp *isp, struct isp_surf *surf) } size = iommu_map_sgtable(isp->domain, surf->iova, &surf->sgt, - IOMMU_READ | IOMMU_WRITE); + IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE); if (size < surf->size) { dev_err(isp->dev, "failed to iommu_map sgt to iova 0x%llx\n", surf->iova); @@ -231,7 +231,7 @@ int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, } mapped = iommu_map_sgtable(isp->domain, surf->iova, sgt, - IOMMU_READ | IOMMU_WRITE); + IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE); if (mapped < surf->size) { dev_err(isp->dev, "failed to iommu_map sgt to iova 0x%llx\n", surf->iova); From 29b1377bd38e3b3c37ee7936794be0eedaa72697 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:23:42 +0900 Subject: [PATCH 318/352] media: apple: isp: Rework meta surface handling & buffer return Now we keep track of meta surfaces independently, and always allocate 16 of them, plus handle buffer return messages more correctly. Fixes t8112 asserts (for some reason). Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-drv.h | 3 +- drivers/media/platform/apple/isp/isp-fw.c | 1 + drivers/media/platform/apple/isp/isp-ipc.c | 42 ---- drivers/media/platform/apple/isp/isp-ipc.h | 1 - drivers/media/platform/apple/isp/isp-v4l2.c | 239 ++++++++++++++------ drivers/media/platform/apple/isp/isp-v4l2.h | 1 + 6 files changed, 176 insertions(+), 111 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 775a435c4a06ad..31c527532aebac 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -43,6 +43,7 @@ struct isp_surf { void *virt; refcount_t refcount; bool gc; + bool submitted; }; struct isp_message { @@ -221,6 +222,7 @@ struct apple_isp { struct isp_surf *data_surf; struct isp_surf *log_surf; struct isp_surf *bt_surf; + struct isp_surf *meta_surfs[ISP_MAX_BUFFERS]; struct list_head gc; struct workqueue_struct *wq; @@ -252,7 +254,6 @@ struct isp_buffer { struct vb2_v4l2_buffer vb; struct list_head link; struct isp_surf surfs[VB2_MAX_PLANES]; - struct isp_surf *meta; }; #define to_isp_buffer(x) container_of((x), struct isp_buffer, vb) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 75405c2258239e..1db1294f843a7a 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -12,6 +12,7 @@ #include "isp-iommu.h" #include "isp-ipc.h" #include "isp-regs.h" +#include "isp-v4l2.h" #define ISP_FIRMWARE_MDELAY 1 #define ISP_FIRMWARE_MAX_TRIES 1000 diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 5901d1b5db9b5b..94ef7dbc4c60a0 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -282,45 +282,3 @@ int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) return 0; } - -int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) -{ - struct isp_message *req = &chan->req, *rsp = &chan->rsp; - struct isp_buffer *tmp, *buf; - int err = 0; - - /* No need to read the whole struct */ - u64 meta_iova; - u64 *p_meta_iova = apple_isp_translate( - isp, isp->bt_surf, req->arg0 + ISP_IPC_BUFEXC_STAT_META_OFFSET, - sizeof(u64)); - - if (!p_meta_iova) { - dev_err(isp->dev, "Failed to find bufexc stat meta\n"); - return -EIO; - } - meta_iova = *p_meta_iova; - - spin_lock(&isp->buf_lock); - list_for_each_entry_safe_reverse(buf, tmp, &isp->bufs_submitted, link) { - if ((u32)buf->meta->iova == (u32)meta_iova) { - enum vb2_buffer_state state = VB2_BUF_STATE_ERROR; - - buf->vb.vb2_buf.timestamp = ktime_get_ns(); - buf->vb.sequence = isp->sequence++; - buf->vb.field = V4L2_FIELD_NONE; - if (req->arg2 == ISP_IPC_BUFEXC_FLAG_RENDER) - state = VB2_BUF_STATE_DONE; - vb2_buffer_done(&buf->vb.vb2_buf, state); - list_del(&buf->link); - break; - } - } - spin_unlock(&isp->buf_lock); - - rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; - rsp->arg1 = 0x0; - rsp->arg2 = ISP_IPC_BUFEXC_FLAG_ACK; - - return err; -} diff --git a/drivers/media/platform/apple/isp/isp-ipc.h b/drivers/media/platform/apple/isp/isp-ipc.h index 32d1e1bf321006..0c1d681835c72f 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.h +++ b/drivers/media/platform/apple/isp/isp-ipc.h @@ -21,6 +21,5 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan); int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan); -int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan); #endif /* __ISP_IPC_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 60fb1c344dedf3..fb85ffaa2db000 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -11,9 +11,9 @@ #include "isp-cam.h" #include "isp-cmd.h" -#include "isp-drv.h" #include "isp-iommu.h" #include "isp-ipc.h" +#include "isp-fw.h" #include "isp-v4l2.h" #define ISP_MIN_FRAMES 2 @@ -26,7 +26,7 @@ static bool multiplanar = false; module_param(multiplanar, bool, 0644); MODULE_PARM_DESC(multiplanar, "Enable multiplanar API"); -struct isp_h2t_buffer { +struct isp_buflist_buffer { u64 iovas[ISP_MAX_PLANES]; u32 flags[ISP_MAX_PLANES]; u32 num_planes; @@ -34,102 +34,190 @@ struct isp_h2t_buffer { u32 tag; u32 pad; } __packed; -static_assert(sizeof(struct isp_h2t_buffer) == 0x40); +static_assert(sizeof(struct isp_buflist_buffer) == 0x40); -struct isp_h2t_args { - u64 enable; +struct isp_buflist { + u64 type; u64 num_buffers; - struct isp_h2t_buffer meta; - struct isp_h2t_buffer render; -} __packed; + struct isp_buflist_buffer buffers[]; +}; + +int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + struct isp_message *req = &chan->req, *rsp = &chan->rsp; + struct isp_buffer *tmp, *buf; + struct isp_buflist *bl; + u32 count; + int err = 0; + + /* printk("H2T: 0x%llx 0x%llx 0x%llx\n", (long long)req->arg0, + (long long)req->arg1, (long long)req->arg2); */ + + if (req->arg1 < sizeof(struct isp_buflist)) { + dev_err(isp->dev, "%s: Bad length 0x%llx\n", chan->name, + req->arg1); + return -EIO; + } + + bl = apple_isp_translate(isp, isp->bt_surf, req->arg0, req->arg1); + + count = bl->num_buffers; + if (count > (req->arg1 - sizeof(struct isp_buffer)) / + sizeof(struct isp_buflist_buffer)) { + dev_err(isp->dev, "%s: Bad length 0x%llx\n", chan->name, + req->arg1); + return -EIO; + } + + spin_lock(&isp->buf_lock); + for (int i = 0; i < count; i++) { + struct isp_buflist_buffer *bufd = &bl->buffers[i]; + + /* printk("Return: 0x%llx (%d)\n", bufd->iovas[0], + bufd->pool_type); */ + + if (bufd->pool_type == 0) { + for (int j = 0; j < ARRAY_SIZE(isp->meta_surfs); j++) { + struct isp_surf *meta = isp->meta_surfs[j]; + if ((u32)bufd->iovas[0] == (u32)meta->iova) { + WARN_ON(!meta->submitted); + meta->submitted = false; + } + } + } else { + list_for_each_entry_safe_reverse( + buf, tmp, &isp->bufs_submitted, link) { + if ((u32)buf->surfs[0].iova == + (u32)bufd->iovas[0]) { + enum vb2_buffer_state state = + VB2_BUF_STATE_ERROR; + + buf->vb.vb2_buf.timestamp = + ktime_get_ns(); + buf->vb.sequence = isp->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + if (req->arg2 == + ISP_IPC_BUFEXC_FLAG_RENDER) + state = VB2_BUF_STATE_DONE; + vb2_buffer_done(&buf->vb.vb2_buf, + state); + list_del(&buf->link); + } + } + } + } + spin_unlock(&isp->buf_lock); + + rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = ISP_IPC_BUFEXC_FLAG_ACK; + + return err; +} static int isp_submit_buffers(struct apple_isp *isp) { struct isp_format *fmt = isp_get_current_format(isp); struct isp_channel *chan = isp->chan_bh; struct isp_message *req = &chan->req; - struct isp_buffer *buf, *buf2, *tmp; + struct isp_buffer *buf, *tmp; unsigned long flags; size_t offset; int err; - struct isp_h2t_args *args = - kzalloc(sizeof(struct isp_h2t_args), GFP_KERNEL); - if (!args) - return -ENOMEM; + struct isp_buflist *bl = isp->cmd_virt; + struct isp_buflist_buffer *bufd = &bl->buffers[0]; + + bl->type = 1; + bl->num_buffers = 0; spin_lock_irqsave(&isp->buf_lock, flags); + for (int i = 0; i < ARRAY_SIZE(isp->meta_surfs); i++) { + struct isp_surf *meta = isp->meta_surfs[i]; + + if (meta->submitted) + continue; + + /* printk("Submit: 0x%llx .. 0x%llx (meta)\n", meta->iova, + meta->iova + meta->size); */ + + bufd->num_planes = 1; + bufd->pool_type = 0; + bufd->iovas[0] = meta->iova; + bufd->flags[0] = 0x40000000; + bufd++; + bl->num_buffers++; + + meta->submitted = true; + } + while ((buf = list_first_entry_or_null(&isp->bufs_pending, struct isp_buffer, link))) { - args->meta.num_planes = 1; - args->meta.pool_type = 0; - args->meta.iovas[0] = buf->meta->iova; - args->meta.flags[0] = 0x40000000; - - args->render.num_planes = fmt->num_planes; - args->render.pool_type = isp->hw->scl1 ? - CISP_POOL_TYPE_RENDERED_SCL1 : - CISP_POOL_TYPE_RENDERED; + memset(bufd, 0, sizeof(*bufd)); + + bufd->num_planes = fmt->num_planes; + bufd->pool_type = isp->hw->scl1 ? CISP_POOL_TYPE_RENDERED_SCL1 : + CISP_POOL_TYPE_RENDERED; offset = 0; for (int j = 0; j < fmt->num_planes; j++) { - args->render.iovas[j] = buf->surfs[0].iova + offset; - args->render.flags[j] = 0x40000000; + bufd->iovas[j] = buf->surfs[0].iova + offset; + bufd->flags[j] = 0x40000000; offset += fmt->plane_size[j]; } + /* printk("Submit: 0x%llx .. 0x%llx (render)\n", + buf->surfs[0].iova, + buf->surfs[0].iova + buf->surfs[0].size); */ + bufd++; + bl->num_buffers++; + /* * Queue the buffer as submitted and release the lock for now. * We need to do this before actually submitting to avoid a * race with the buffer return codepath. */ list_move_tail(&buf->link, &isp->bufs_submitted); - spin_unlock_irqrestore(&isp->buf_lock, flags); + } + + spin_unlock_irqrestore(&isp->buf_lock, flags); + + req->arg0 = isp->cmd_iova; + req->arg1 = max_t(u64, ISP_IPC_BUFEXC_STAT_SIZE, + ((uintptr_t)bufd - (uintptr_t)bl)); + req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; + + err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); + if (err) { + /* If we fail, consider the buffer not submitted. */ + dev_err(isp->dev, + "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, req->arg0, req->arg1, req->arg2); + + /* + * Try to find the buffer in the list, and if it's + * still there, move it back to the pending list. + */ + spin_lock_irqsave(&isp->buf_lock, flags); - args->enable = 0x1; - args->num_buffers = 2; - - req->arg0 = isp->cmd_iova; - req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; - req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; - - memcpy(isp->cmd_virt, args, sizeof(*args)); - err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); - if (err) { - /* If we fail, consider the buffer not submitted. */ - dev_err(isp->dev, - "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", - chan->name, req->arg0, req->arg1, req->arg2); - - /* - * Try to find the buffer in the list, and if it's - * still there, move it back to the pending list. - */ - spin_lock_irqsave(&isp->buf_lock, flags); + bufd = &bl->buffers[0]; + for (int i = 0; i < bl->num_buffers; i++, bufd++) { list_for_each_entry_safe_reverse( - buf2, tmp, &isp->bufs_submitted, link) { - if (buf2 == buf) { + buf, tmp, &isp->bufs_submitted, link) { + if (bufd->iovas[0] == buf->surfs[0].iova) { list_move_tail(&buf->link, &isp->bufs_pending); - spin_unlock_irqrestore(&isp->buf_lock, - flags); - return err; } } - /* - * We didn't find the buffer, which means it somehow was returned - * by the firmware even though submission failed? - */ - dev_err(isp->dev, - "buffer submission failed but buffer was returned?\n"); - spin_unlock_irqrestore(&isp->buf_lock, flags); - return err; + for (int j = 0; j < ARRAY_SIZE(isp->meta_surfs); j++) { + struct isp_surf *meta = isp->meta_surfs[j]; + if (bufd->iovas[0] == meta->iova) { + meta->submitted = false; + } + } } - spin_lock_irqsave(&isp->buf_lock, flags); + spin_unlock_irqrestore(&isp->buf_lock, flags); } - spin_unlock_irqrestore(&isp->buf_lock, flags); - - kfree(args); return err; } @@ -172,7 +260,6 @@ static void __isp_vb2_buf_cleanup(struct vb2_buffer *vb, unsigned int i) while (i--) apple_isp_iommu_unmap_sgt(isp, &buf->surfs[i]); - isp_free_surface(isp, buf->meta); } static void isp_vb2_buf_cleanup(struct vb2_buffer *vb) @@ -188,10 +275,6 @@ static int isp_vb2_buf_init(struct vb2_buffer *vb) unsigned int i; int err; - buf->meta = isp_alloc_surface(isp, isp->hw->meta_size); - if (!buf->meta) - return -ENOMEM; - for (i = 0; i < vb->num_planes; i++) { struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, i); err = apple_isp_iommu_map_sgt(isp, &buf->surfs[i], sgt, @@ -676,6 +759,16 @@ int apple_isp_setup_video(struct apple_isp *isp) return err; } + for (int i = 0; i < ARRAY_SIZE(isp->meta_surfs); i++) { + isp->meta_surfs[i] = + isp_alloc_surface_vmap(isp, isp->hw->meta_size); + if (!isp->meta_surfs[i]) { + isp_err(isp, "failed to alloc meta surface\n"); + err = -ENOMEM; + goto surf_cleanup; + } + } + media_device_init(&isp->mdev); isp->v4l2_dev.mdev = &isp->mdev; isp->mdev.ops = &isp_media_device_ops; @@ -742,6 +835,13 @@ int apple_isp_setup_video(struct apple_isp *isp) media_device_unregister(&isp->mdev); media_cleanup: media_device_cleanup(&isp->mdev); +surf_cleanup: + for (int i = 0; i < ARRAY_SIZE(isp->meta_surfs); i++) { + if (isp->meta_surfs[i]) + isp_free_surface(isp, isp->meta_surfs[i]); + isp->meta_surfs[i] = NULL; + } + return err; } @@ -751,4 +851,9 @@ void apple_isp_remove_video(struct apple_isp *isp) v4l2_device_unregister(&isp->v4l2_dev); media_device_unregister(&isp->mdev); media_device_cleanup(&isp->mdev); + for (int i = 0; i < ARRAY_SIZE(isp->meta_surfs); i++) { + if (isp->meta_surfs[i]) + isp_free_surface(isp, isp->meta_surfs[i]); + isp->meta_surfs[i] = NULL; + } } diff --git a/drivers/media/platform/apple/isp/isp-v4l2.h b/drivers/media/platform/apple/isp/isp-v4l2.h index df9b961d77bc17..e81e4de6ca641f 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.h +++ b/drivers/media/platform/apple/isp/isp-v4l2.h @@ -8,5 +8,6 @@ int apple_isp_setup_video(struct apple_isp *isp); void apple_isp_remove_video(struct apple_isp *isp); +int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan); #endif /* __ISP_V4L2_H__ */ From b9ce64a0596d0048b02cce7aeb805e9bed7ce33d Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:25:07 +0900 Subject: [PATCH 319/352] media: apple: isp: Clear IRQs when resetting coproc XXX this might be wrong on some chips? Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 1db1294f843a7a..addf6ba6b37525 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -215,6 +215,7 @@ static int isp_reset_coproc(struct apple_isp *isp) { int retries; u32 status; + u32 val; isp_coproc_write32(isp, ISP_COPROC_EDPRCR, 0x2); @@ -230,6 +231,18 @@ static int isp_reset_coproc(struct apple_isp *isp) isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_4, 0xffffffff); isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_5, 0xffffffff); + for (retries = 0; retries < 128; retries++) { + val = isp_coproc_read32(isp, 0x818); + if (val == 0) + break; + } + + for (retries = 0; retries < 128; retries++) { + val = isp_coproc_read32(isp, 0x81c); + if (val == 0) + break; + } + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { status = isp_coproc_read32(isp, ISP_COPROC_STATUS); if (status & ISP_COPROC_IN_WFI) { From 64a131ae480d9b572ebb75ca67e3736a1fd01bed Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:25:50 +0900 Subject: [PATCH 320/352] media: apple: isp: Add a missing read barrier (possibly?) Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-ipc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 94ef7dbc4c60a0..7e5a6cb821976d 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -157,6 +157,8 @@ int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan) static inline bool chan_tx_done(struct apple_isp *isp, struct isp_channel *chan) { + dma_rmb(); + chan_read_msg(isp, chan, &chan->rsp); if ((chan->rsp.arg0) == (chan->req.arg0 | ISP_IPC_FLAG_ACK)) { chan_update_cursor(chan); From e85be654ce3e4176d212b4c950a9e2eaebb4a4c1 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:26:47 +0900 Subject: [PATCH 321/352] media: apple: isp: VMap only what is necessary, remove redundant logging state bit Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-ipc.c | 41 ++++++++-------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 7e5a6cb821976d..0609aa3e288220 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -204,7 +204,7 @@ int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan) dma_addr_t iova = req->arg0 & ~ISP_IPC_FLAG_TERMINAL_ACK; u32 size = req->arg1; if (iova && size && size < sizeof(buf) && - test_bit(ISP_STATE_LOGGING, &isp->state)) { + isp->log_surf) { void *p = apple_isp_translate(isp, isp->log_surf, iova, size); if (p) { size = min_t(u32, size, 512); @@ -241,42 +241,31 @@ int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) rsp->arg1 = 0x0; rsp->arg2 = 0x0; /* macOS uses this to index surfaces */ + switch (surf->type) { + case 0x4c4f47: /* "LOG" */ + isp->log_surf = surf; + break; + case 0x4d495343: /* "MISC" */ + /* Hacky... maybe there's a better way to identify this surface? */ + if (surf->size == 0xc000) + isp->bt_surf = surf; + break; + default: + // skip vmap + return 0; + } + err = isp_surf_vmap(isp, surf); if (err < 0) { isp_err(isp, "failed to vmap iova=0x%llx size=0x%llx\n", surf->iova, surf->size); - } else { - switch (surf->type) { - case 0x4c4f47: /* "LOG" */ - isp->log_surf = surf; - break; - case 0x4d495343: /* "MISC" */ - /* Hacky... maybe there's a better way to identify this surface? */ - if (surf->size == 0xc000) - isp->bt_surf = surf; - break; - } } - -#ifdef APPLE_ISP_DEBUG - /* Only enabled in debug builds so it shouldn't matter, but - * the LOG surface is always the first surface requested. - */ - if (!test_bit(ISP_STATE_LOGGING, &isp->state)) - set_bit(ISP_STATE_LOGGING, &isp->state); -#endif - /* To the gc it goes... */ - } else { /* This should be the shared surface free request, but * 1) The fw doesn't request to free all of what it requested * 2) The fw continues to access the surface after * So we link it to the gc, which runs after fw shutdown */ -#ifdef APPLE_ISP_DEBUG - if (test_bit(ISP_STATE_LOGGING, &isp->state)) - clear_bit(ISP_STATE_LOGGING, &isp->state); -#endif rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; rsp->arg1 = 0x0; rsp->arg2 = 0x0; From 35662ee3f4594e1e47bbe284acf723fbb220eff8 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:28:03 +0900 Subject: [PATCH 322/352] media: apple: isp: Only reset coproc when necessary, fix minor race Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index addf6ba6b37525..a61c14453479d9 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -270,16 +270,22 @@ static void isp_firmware_shutdown_stage1(struct apple_isp *isp) static int isp_firmware_boot_stage1(struct apple_isp *isp) { int err, retries; + u32 val; + err = apple_isp_power_up_domains(isp); if (err < 0) return err; - err = isp_reset_coproc(isp); - if (err < 0) - return err; isp_gpio_write32(isp, ISP_GPIO_CLOCK_EN, 0x1); + val = isp_gpio_read32(isp, ISP_GPIO_1); + if (val == 0xfeedbabe) { + err = isp_reset_coproc(isp); + if (err < 0) + return err; + } + isp_gpio_write32(isp, ISP_GPIO_0, 0x0); isp_gpio_write32(isp, ISP_GPIO_1, 0x0); isp_gpio_write32(isp, ISP_GPIO_2, 0x0); @@ -295,7 +301,6 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x10); /* Wait for ISP_GPIO_7 to 0x0 -> 0x8042006 */ - isp_gpio_write32(isp, ISP_GPIO_7, 0x0); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { u32 val = isp_gpio_read32(isp, ISP_GPIO_7); if (val == 0x8042006) { From 4d45f11258c906c6b72fc73fca8287dcdbc2f448 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:28:55 +0900 Subject: [PATCH 323/352] media: apple: isp: Option to use CMD_STOP (ifdeffed out) Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index a61c14453479d9..90895616c7c5ad 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -595,11 +595,26 @@ static int isp_stop_command_processor(struct apple_isp *isp) { int retries; +#if 0 + int res = isp_cmd_stop(isp, 0); + if (res) { + isp_err(isp, "isp_cmd_stop() failed\n"); + return res; + } + /* Wait for ISP_GPIO_0 to 0xf7fbdff9 -> 0x8042006 */ isp_gpio_write32(isp, ISP_GPIO_0, 0xf7fbdff9); - /* Their CISP_CMD_STOP implementation is buggy */ - isp_cmd_suspend(isp); + isp_cmd_power_down(isp); +#else + isp_gpio_write32(isp, ISP_GPIO_0, 0xf7fbdff9); + + int res = isp_cmd_suspend(isp); + if (res) { + isp_err(isp, "isp_cmd_suspend() failed\n"); + return res; + } +#endif for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { u32 val = isp_gpio_read32(isp, ISP_GPIO_0); From 8b7160148da9ef38d87fe9c5bde5c8eb905ee130 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 5 Oct 2023 23:24:32 +0900 Subject: [PATCH 324/352] media: apple: isp: Use a more user-friendly device name Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-v4l2.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 31c527532aebac..847e0a90975fb5 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -16,6 +16,7 @@ /* #define APPLE_ISP_DEBUG */ #define APPLE_ISP_DEVICE_NAME "apple-isp" +#define APPLE_ISP_CARD_NAME "FaceTime HD Camera" #define ISP_MAX_CHANNELS 6 #define ISP_IPC_MESSAGE_SIZE 64 diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index fb85ffaa2db000..52199422d32be8 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -446,7 +446,7 @@ static struct isp_preset *isp_select_preset(struct apple_isp *isp, u32 width, static int isp_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strscpy(cap->card, APPLE_ISP_DEVICE_NAME, sizeof(cap->card)); + strscpy(cap->card, APPLE_ISP_CARD_NAME, sizeof(cap->card)); strscpy(cap->driver, APPLE_ISP_DEVICE_NAME, sizeof(cap->driver)); return 0; From 9ddfa510cbc3b0483c61342d14f983d5ccc5c7a9 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 6 Oct 2023 21:34:11 +0200 Subject: [PATCH 325/352] media: apple: isp: Parse firmware version from device tree Required since t8112-isp uses a 32-bit address in the CISP_CMD_CH_SET_FILE_LOAD command with the macOS 12.4 firmware. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-cmd.c | 3 +- drivers/media/platform/apple/isp/isp-drv.c | 71 ++++++++++++++++++++++ drivers/media/platform/apple/isp/isp-drv.h | 8 +++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 9c5808b4e831be..ee491d2cb42c5b 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -2,6 +2,7 @@ /* Copyright 2023 Eileen Yoon */ #include "isp-cmd.h" +#include "isp-drv.h" #include "isp-iommu.h" #include "isp-ipc.h" @@ -261,7 +262,7 @@ int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan) int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u64 addr, u32 size) { - if (isp->hw->gen >= ISP_GEN_T8112) { + if (isp->fw_compat >= ISP_FIRMWARE_V_13_5) { struct cmd_ch_set_file_load64 args = { .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), .chan = chan, diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 2ea4ecad36c75e..09bc0af68aab74 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -215,6 +215,72 @@ static int apple_isp_init_presets(struct apple_isp *isp) return 0; } +static const char * isp_fw2str(enum isp_firmware_version version) +{ + switch (version) { + case ISP_FIRMWARE_V_12_3: + return "12.3"; + case ISP_FIRMWARE_V_12_4: + return "12.4"; + case ISP_FIRMWARE_V_13_5: + return "13.5"; + default: + return "unknown"; + } +} + +#define ISP_FW_VERSION_MIN_LEN 3 +#define ISP_FW_VERSION_MAX_LEN 5 + +static enum isp_firmware_version isp_read_fw_version(struct device *dev, + const char *name) +{ + u32 ver[ISP_FW_VERSION_MAX_LEN]; + int len = of_property_read_variable_u32_array(dev->of_node, name, ver, + ISP_FW_VERSION_MIN_LEN, + ISP_FW_VERSION_MAX_LEN); + + switch (len) { + case 3: + if (ver[0] == 12 && ver[1] == 3 && ver[2] <= 1) + return ISP_FIRMWARE_V_12_3; + else if (ver[0] == 12 && ver[1] == 4 && ver[2] == 0) + return ISP_FIRMWARE_V_12_4; + else if (ver[0] == 13 && ver[1] == 5 && ver[2] == 0) + return ISP_FIRMWARE_V_13_5; + + dev_warn(dev, "unknown %s: %d.%d.%d\n", name, ver[0], ver[1], ver[2]); + break; + case 4: + dev_warn(dev, "unknown %s: %d.%d.%d.%d\n", name, ver[0], ver[1], + ver[2], ver[3]); + break; + case 5: + dev_warn(dev, "unknown %s: %d.%d.%d.%d.%d\n", name, ver[0], + ver[1], ver[2], ver[3], ver[4]); + break; + default: + dev_warn(dev, "could not parse %s: %d\n", name, len); + break; + } + + return ISP_FIRMWARE_V_UNKNOWN; +} + +static enum isp_firmware_version isp_check_firmware_version(struct device *dev) +{ + enum isp_firmware_version version, compat; + + /* firmware version is just informative */ + version = isp_read_fw_version(dev, "apple,firmware-version"); + compat = isp_read_fw_version(dev, "apple,firmware-compat"); + + dev_info(dev, "ISP firmware-compat: %s (FW: %s)\n", isp_fw2str(compat), + isp_fw2str(version)); + + return compat; +} + static int apple_isp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -234,6 +300,11 @@ static int apple_isp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, isp); dev_set_drvdata(dev, isp); + /* Differences between firmware versions are rather minor so try to work + * with unknown firmware. + */ + isp->fw_compat = isp_check_firmware_version(dev); + err = of_property_read_u32(dev->of_node, "apple,platform-id", &isp->platform_id); if (err) { diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 847e0a90975fb5..2ccd3524be65b8 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -32,6 +32,13 @@ enum isp_generation { ISP_GEN_T8112, }; +enum isp_firmware_version { + ISP_FIRMWARE_V_UNKNOWN, + ISP_FIRMWARE_V_12_3, + ISP_FIRMWARE_V_12_4, + ISP_FIRMWARE_V_13_5, +}; + struct isp_surf { struct drm_mm_node *mm; struct list_head head; @@ -180,6 +187,7 @@ struct isp_format { struct apple_isp { struct device *dev; const struct apple_isp_hw *hw; + enum isp_firmware_version fw_compat; u32 platform_id; u32 temporal_filter; struct isp_preset *presets; From 11c9a6de578d5da625b6d1399fcab4dcd85b65fa Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 8 Oct 2023 18:02:12 +0900 Subject: [PATCH 326/352] media: apple: isp: Show camera presets even for unsupported sensors This makes adding support easier. Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-cam.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index cc0c24c3cfb715..fac81fef11bc7e 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -212,6 +212,10 @@ static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) print_hex_dump(KERN_INFO, "apple-isp: ch: ", DUMP_PREFIX_NONE, 32, 4, args, sizeof(*args), false); + for (u32 ps = 0; ps < args->num_presets; ps++) { + isp_ch_get_camera_preset(isp, ch, ps); + } + err = isp_ch_get_sensor_id(isp, ch); if (err || (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { @@ -221,10 +225,6 @@ static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) return -ENODEV; } - for (u32 ps = 0; ps < args->num_presets; ps++) { - isp_ch_get_camera_preset(isp, ch, ps); - } - exit: kfree(args); From 27989b247e920baddd0c7c4d44f522a93a04e22c Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 8 Oct 2023 18:03:20 +0900 Subject: [PATCH 327/352] media: apple: isp: Enable IMX364 sensor This is used on j45[67]. Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-cam.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index fac81fef11bc7e..c889173bd348f3 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -218,7 +218,8 @@ static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) err = isp_ch_get_sensor_id(isp, ch); if (err || - (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { + (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01 && + fmt->id != ISP_IMX364_8720_01)) { dev_err(isp->dev, "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", ch); From 3a35ea3cf181917b0c710861f195a552d0ca578c Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 12 Oct 2023 02:41:08 +0900 Subject: [PATCH 328/352] media: apple: isp: implement ENUM_FRAMEINTERVALS trivially Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-v4l2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 52199422d32be8..73795288d52f97 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -495,6 +495,18 @@ static int isp_vidioc_enum_framesizes(struct file *file, void *fh, return 0; } +static int isp_vidioc_enum_frameintervals(struct file *filp, void *priv, + struct v4l2_frmivalenum *interval) +{ + if (interval->index != 0) + return -EINVAL; + + interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; + interval->discrete.numerator = 1; + interval->discrete.denominator = 30; + return 0; +} + static inline void isp_get_sp_pix_format(struct apple_isp *isp, struct v4l2_format *f, struct isp_format *fmt) @@ -715,6 +727,7 @@ static const struct v4l2_ioctl_ops isp_v4l2_ioctl_ops = { .vidioc_try_fmt_vid_cap_mplane = isp_vidioc_try_format_mplane, .vidioc_enum_framesizes = isp_vidioc_enum_framesizes, + .vidioc_enum_frameintervals = isp_vidioc_enum_frameintervals, .vidioc_enum_input = isp_vidioc_enum_input, .vidioc_g_input = isp_vidioc_get_input, .vidioc_s_input = isp_vidioc_set_input, From 283879fbcc959b35442bd68c4783a37c85bd5956 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 3 Nov 2023 20:49:38 +0900 Subject: [PATCH 329/352] media: apple: isp: Use a mutex instead of a spinlock for channels Fixes lockdep splats because we do surface stuff with this held, which takes a mutex. Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.h | 2 +- drivers/media/platform/apple/isp/isp-fw.c | 2 +- drivers/media/platform/apple/isp/isp-ipc.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 2ccd3524be65b8..4bdf7616e0efe4 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -76,7 +76,7 @@ struct isp_channel { void *virt; u32 doorbell; u32 cursor; - spinlock_t lock; + struct mutex lock; struct isp_message req; struct isp_message rsp; const struct isp_chan_ops *ops; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 90895616c7c5ad..3e322d40fb881f 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -493,7 +493,7 @@ static int isp_fill_channel_info(struct apple_isp *isp) chan->virt = apple_isp_ipc_translate(isp, desc.iova, chan->size); chan->cursor = 0; - spin_lock_init(&chan->lock); + mutex_init(&chan->lock); if (!chan->virt) { dev_err(isp->dev, "Failed to find channel buffer\n"); diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 0609aa3e288220..a1948717a31968 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -138,7 +138,7 @@ int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan) { int err = 0; - spin_lock(&chan->lock); + mutex_lock(&chan->lock); while (1) { chan_read_msg(isp, chan, &chan->req); if (chan_rx_done(isp, chan)) { @@ -150,7 +150,7 @@ int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan) break; } } - spin_unlock(&chan->lock); + mutex_unlock(&chan->lock); return err; } From abf1283b4b7d535e58953d4b5669fdd0b4778e9f Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Fri, 13 Oct 2023 21:09:43 +0900 Subject: [PATCH 330/352] media: apple: isp: Support system sleep Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 29 +++++++++++- drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-fw.c | 13 ++++-- drivers/media/platform/apple/isp/isp-v4l2.c | 50 ++++++++++++++++++--- drivers/media/platform/apple/isp/isp-v4l2.h | 3 ++ 5 files changed, 84 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 09bc0af68aab74..848f7abd535a7f 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -541,17 +541,42 @@ static const struct of_device_id apple_isp_of_match[] = { }; MODULE_DEVICE_TABLE(of, apple_isp_of_match); +static __maybe_unused int apple_isp_runtime_suspend(struct device *dev) +{ + /* RPM sleep is called when the V4L2 file handle is closed */ + return 0; +} + +static __maybe_unused int apple_isp_runtime_resume(struct device *dev) +{ + return 0; +} + static __maybe_unused int apple_isp_suspend(struct device *dev) { + struct apple_isp *isp = dev_get_drvdata(dev); + + /* We must restore V4L2 context on system resume. If we were streaming + * before, we (essentially) stop streaming and start streaming again. + */ + apple_isp_video_suspend(isp); + return 0; } static __maybe_unused int apple_isp_resume(struct device *dev) { + struct apple_isp *isp = dev_get_drvdata(dev); + + apple_isp_video_resume(isp); + return 0; } -DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, - NULL); + +static const struct dev_pm_ops apple_isp_pm_ops = { + SYSTEM_SLEEP_PM_OPS(apple_isp_suspend, apple_isp_resume) + RUNTIME_PM_OPS(apple_isp_runtime_suspend, apple_isp_runtime_resume, NULL) +}; static struct platform_driver apple_isp_driver = { .driver = { diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 4bdf7616e0efe4..96a1d0b39f860d 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -270,6 +270,7 @@ struct isp_buffer { enum { ISP_STATE_STREAMING, ISP_STATE_LOGGING, + ISP_STATE_SLEEPING, }; #ifdef APPLE_ISP_DEBUG diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 3e322d40fb881f..a39f5fb4445fa7 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -42,8 +42,8 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->gpio + reg); } -int apple_isp_power_up_domains(struct apple_isp *isp) static int apple_isp_power_up_domains(struct apple_isp *isp) +{ int ret; if (isp->pds_active) @@ -65,8 +65,8 @@ static int apple_isp_power_up_domains(struct apple_isp *isp) return 0; } -void apple_isp_power_down_domains(struct apple_isp *isp) static void apple_isp_power_down_domains(struct apple_isp *isp) +{ int ret; if (!isp->pds_active) @@ -270,7 +270,7 @@ static void isp_firmware_shutdown_stage1(struct apple_isp *isp) static int isp_firmware_boot_stage1(struct apple_isp *isp) { int err, retries; - u32 val; + // u32 val; err = apple_isp_power_up_domains(isp); if (err < 0) @@ -279,12 +279,19 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) isp_gpio_write32(isp, ISP_GPIO_CLOCK_EN, 0x1); +#if 0 + /* This doesn't work well with system sleep */ val = isp_gpio_read32(isp, ISP_GPIO_1); if (val == 0xfeedbabe) { err = isp_reset_coproc(isp); if (err < 0) return err; } +#endif + + err = isp_reset_coproc(isp); + if (err < 0) + return err; isp_gpio_write32(isp, ISP_GPIO_0, 0x0); isp_gpio_write32(isp, ISP_GPIO_1, 0x0); diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 73795288d52f97..8e287cfc8a29e9 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -337,13 +337,10 @@ static void isp_vb2_buf_queue(struct vb2_buffer *vb) isp_submit_buffers(isp); } -static int isp_vb2_start_streaming(struct vb2_queue *q, unsigned int count) +static int apple_isp_start_streaming(struct apple_isp *isp) { - struct apple_isp *isp = vb2_get_drv_priv(q); int err; - isp->sequence = 0; - err = apple_isp_start_camera(isp); if (err) { dev_err(isp->dev, "failed to start camera: %d\n", err); @@ -373,16 +370,55 @@ static int isp_vb2_start_streaming(struct vb2_queue *q, unsigned int count) return err; } -static void isp_vb2_stop_streaming(struct vb2_queue *q) +static void apple_isp_stop_streaming(struct apple_isp *isp) { - struct apple_isp *isp = vb2_get_drv_priv(q); - clear_bit(ISP_STATE_STREAMING, &isp->state); apple_isp_stop_capture(isp); apple_isp_stop_camera(isp); +} + +static int isp_vb2_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct apple_isp *isp = vb2_get_drv_priv(q); + + isp->sequence = 0; + + return apple_isp_start_streaming(isp); +} + +static void isp_vb2_stop_streaming(struct vb2_queue *q) +{ + struct apple_isp *isp = vb2_get_drv_priv(q); + + apple_isp_stop_streaming(isp); isp_vb2_release_buffers(isp, VB2_BUF_STATE_ERROR); } +int apple_isp_video_suspend(struct apple_isp *isp) +{ + /* Swap into STATE_SLEEPING as isp_vb2_buf_queue() submits on + * STATE_STREAMING. + */ + if (test_bit(ISP_STATE_STREAMING, &isp->state)) { + /* Signal buffers to be recycled for clean shutdown */ + isp_vb2_release_buffers(isp, VB2_BUF_STATE_QUEUED); + apple_isp_stop_streaming(isp); + set_bit(ISP_STATE_SLEEPING, &isp->state); + } + + return 0; +} + +int apple_isp_video_resume(struct apple_isp *isp) +{ + if (test_bit(ISP_STATE_SLEEPING, &isp->state)) { + clear_bit(ISP_STATE_SLEEPING, &isp->state); + apple_isp_start_streaming(isp); + } + + return 0; +} + static const struct vb2_ops isp_vb2_ops = { .queue_setup = isp_vb2_queue_setup, .buf_init = isp_vb2_buf_init, diff --git a/drivers/media/platform/apple/isp/isp-v4l2.h b/drivers/media/platform/apple/isp/isp-v4l2.h index e81e4de6ca641f..4d47deeb83b055 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.h +++ b/drivers/media/platform/apple/isp/isp-v4l2.h @@ -10,4 +10,7 @@ int apple_isp_setup_video(struct apple_isp *isp); void apple_isp_remove_video(struct apple_isp *isp); int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan); +int apple_isp_video_suspend(struct apple_isp *isp); +int apple_isp_video_resume(struct apple_isp *isp); + #endif /* __ISP_V4L2_H__ */ From 50d4a0c32a10908320be6a9f3971221f726d4a20 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 22 Mar 2026 10:25:53 +0100 Subject: [PATCH 331/352] media: apple: isp: select APPLE_PMP_REPORT The ISP driver will report to PMP in the future so ensure it is enabled. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/apple/isp/Kconfig b/drivers/media/platform/apple/isp/Kconfig index 5695bef44adf5b..8e339db43bc418 100644 --- a/drivers/media/platform/apple/isp/Kconfig +++ b/drivers/media/platform/apple/isp/Kconfig @@ -5,6 +5,7 @@ config VIDEO_APPLE_ISP select VIDEOBUF2_CORE select VIDEOBUF2_V4L2 select VIDEOBUF2_DMA_SG + select APPLE_PMP_REPORT depends on ARCH_APPLE || COMPILE_TEST depends on OF_ADDRESS depends on V4L_PLATFORM_DRIVERS From 9ac13ff0fc75010681a6ea5fd694db592dea9069 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 8 Jul 2022 02:09:24 +0900 Subject: [PATCH 332/352] soc: apple: Add DockChannel driver DockChannel is a simple FIFO interface used to communicate between SoC blocks. Add a driver that represents the shared interrupt controller for the DockChannel block, and then exposes probe and data transfer functions that child device drivers can use to instantiate individual FIFOs. Signed-off-by: Hector Martin --- drivers/soc/apple/Kconfig | 9 + drivers/soc/apple/Makefile | 3 + drivers/soc/apple/dockchannel.c | 404 ++++++++++++++++++++++++++ include/linux/soc/apple/dockchannel.h | 26 ++ 4 files changed, 442 insertions(+) create mode 100644 drivers/soc/apple/dockchannel.c create mode 100644 include/linux/soc/apple/dockchannel.h diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index d0ff32182a2b4a..b44aa998f73bdf 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -4,6 +4,15 @@ if ARCH_APPLE || COMPILE_TEST menu "Apple SoC drivers" +config APPLE_DOCKCHANNEL + tristate "Apple DockChannel FIFO" + depends on ARCH_APPLE || COMPILE_TEST + help + DockChannel is a simple FIFO used on Apple SoCs for debug and inter-processor + communications. + + Say 'y' here if you have an Apple SoC. + config APPLE_MAILBOX tristate "Apple SoC mailboxes" depends on PM diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index 0b85ab61aefe13..b5ffadc16dc84d 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -1,5 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_APPLE_DOCKCHANNEL) += apple-dockchannel.o +apple-dockchannel-y = dockchannel.o + obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o apple-mailbox-y = mailbox.o diff --git a/drivers/soc/apple/dockchannel.c b/drivers/soc/apple/dockchannel.c new file mode 100644 index 00000000000000..ad1763eb411fef --- /dev/null +++ b/drivers/soc/apple/dockchannel.c @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple DockChannel FIFO driver + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DOCKCHANNEL_MAX_IRQ 32 + +#define DOCKCHANNEL_TX_TIMEOUT_MS 1000 +#define DOCKCHANNEL_RX_TIMEOUT_MS 1000 + +#define IRQ_MASK 0x0 +#define IRQ_FLAG 0x4 + +#define IRQ_TX BIT(0) +#define IRQ_RX BIT(1) + +#define CONFIG_TX_THRESH 0x0 +#define CONFIG_RX_THRESH 0x4 + +#define DATA_TX8 0x4 +#define DATA_TX16 0x8 +#define DATA_TX24 0xc +#define DATA_TX32 0x10 +#define DATA_TX_FREE 0x14 +#define DATA_RX8 0x1c +#define DATA_RX16 0x20 +#define DATA_RX24 0x24 +#define DATA_RX32 0x28 +#define DATA_RX_COUNT 0x2c + +struct dockchannel { + struct device *dev; + int tx_irq; + int rx_irq; + + void __iomem *config_base; + void __iomem *data_base; + + u32 fifo_size; + bool awaiting; + struct completion tx_comp; + struct completion rx_comp; + + void *cookie; + void (*data_available)(void *cookie, size_t avail); +}; + +struct dockchannel_common { + struct device *dev; + struct irq_domain *domain; + int irq; + + void __iomem *irq_base; +}; + +/* Dockchannel FIFO functions */ + +static irqreturn_t dockchannel_tx_irq(int irq, void *data) +{ + struct dockchannel *dockchannel = data; + + disable_irq_nosync(irq); + complete(&dockchannel->tx_comp); + + return IRQ_HANDLED; +} + +static irqreturn_t dockchannel_rx_irq(int irq, void *data) +{ + struct dockchannel *dockchannel = data; + + disable_irq_nosync(irq); + + if (dockchannel->awaiting) { + return IRQ_WAKE_THREAD; + } else { + complete(&dockchannel->rx_comp); + return IRQ_HANDLED; + } +} + +static irqreturn_t dockchannel_rx_irq_thread(int irq, void *data) +{ + struct dockchannel *dockchannel = data; + size_t avail = readl_relaxed(dockchannel->data_base + DATA_RX_COUNT); + + dockchannel->awaiting = false; + dockchannel->data_available(dockchannel->cookie, avail); + + return IRQ_HANDLED; +} + +int dockchannel_send(struct dockchannel *dockchannel, const void *buf, size_t count) +{ + size_t left = count; + const u8 *p = buf; + + while (left > 0) { + size_t avail = readl_relaxed(dockchannel->data_base + DATA_TX_FREE); + size_t block = min(left, avail); + + if (avail == 0) { + size_t threshold = min((size_t)(dockchannel->fifo_size / 2), left); + + writel_relaxed(threshold, dockchannel->config_base + CONFIG_TX_THRESH); + reinit_completion(&dockchannel->tx_comp); + enable_irq(dockchannel->tx_irq); + + if (!wait_for_completion_timeout(&dockchannel->tx_comp, + msecs_to_jiffies(DOCKCHANNEL_TX_TIMEOUT_MS))) { + disable_irq(dockchannel->tx_irq); + return -ETIMEDOUT; + } + + continue; + } + + while (block >= 4) { + writel_relaxed(get_unaligned_le32(p), dockchannel->data_base + DATA_TX32); + p += 4; + left -= 4; + block -= 4; + } + while (block > 0) { + writeb_relaxed(*p++, dockchannel->data_base + DATA_TX8); + left--; + block--; + } + } + + return count; +} +EXPORT_SYMBOL(dockchannel_send); + +int dockchannel_recv(struct dockchannel *dockchannel, void *buf, size_t count) +{ + size_t left = count; + u8 *p = buf; + + while (left > 0) { + size_t avail = readl_relaxed(dockchannel->data_base + DATA_RX_COUNT); + size_t block = min(left, avail); + + if (avail == 0) { + size_t threshold = min((size_t)(dockchannel->fifo_size / 2), left); + + writel_relaxed(threshold, dockchannel->config_base + CONFIG_RX_THRESH); + reinit_completion(&dockchannel->rx_comp); + enable_irq(dockchannel->rx_irq); + + if (!wait_for_completion_timeout(&dockchannel->rx_comp, + msecs_to_jiffies(DOCKCHANNEL_RX_TIMEOUT_MS))) { + disable_irq(dockchannel->rx_irq); + return -ETIMEDOUT; + } + + continue; + } + + while (block >= 4) { + put_unaligned_le32(readl_relaxed(dockchannel->data_base + DATA_RX32), p); + p += 4; + left -= 4; + block -= 4; + } + while (block > 0) { + *p++ = readl_relaxed(dockchannel->data_base + DATA_RX8) >> 8; + left--; + block--; + } + } + + return count; +} +EXPORT_SYMBOL(dockchannel_recv); + +int dockchannel_await(struct dockchannel *dockchannel, + void (*callback)(void *cookie, size_t avail), + void *cookie, size_t count) +{ + size_t threshold = min((size_t)dockchannel->fifo_size, count); + + if (!count) { + dockchannel->awaiting = false; + disable_irq(dockchannel->rx_irq); + return 0; + } + + dockchannel->data_available = callback; + dockchannel->cookie = cookie; + dockchannel->awaiting = true; + writel_relaxed(threshold, dockchannel->config_base + CONFIG_RX_THRESH); + enable_irq(dockchannel->rx_irq); + + return threshold; +} +EXPORT_SYMBOL(dockchannel_await); + +struct dockchannel *dockchannel_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dockchannel *dockchannel; + int ret; + + dockchannel = devm_kzalloc(dev, sizeof(*dockchannel), GFP_KERNEL); + if (!dockchannel) + return ERR_PTR(-ENOMEM); + + dockchannel->dev = dev; + dockchannel->config_base = devm_platform_ioremap_resource_byname(pdev, "config"); + if (IS_ERR(dockchannel->config_base)) + return (__force void *)dockchannel->config_base; + + dockchannel->data_base = devm_platform_ioremap_resource_byname(pdev, "data"); + if (IS_ERR(dockchannel->data_base)) + return (__force void *)dockchannel->data_base; + + ret = of_property_read_u32(dev->of_node, "apple,fifo-size", &dockchannel->fifo_size); + if (ret) + return ERR_PTR(dev_err_probe(dev, ret, "Missing apple,fifo-size property")); + + init_completion(&dockchannel->tx_comp); + init_completion(&dockchannel->rx_comp); + + dockchannel->tx_irq = platform_get_irq_byname(pdev, "tx"); + if (dockchannel->tx_irq <= 0) { + return ERR_PTR(dev_err_probe(dev, dockchannel->tx_irq, + "Failed to get TX IRQ")); + } + + dockchannel->rx_irq = platform_get_irq_byname(pdev, "rx"); + if (dockchannel->rx_irq <= 0) { + return ERR_PTR(dev_err_probe(dev, dockchannel->rx_irq, + "Failed to get RX IRQ")); + } + + ret = devm_request_irq(dev, dockchannel->tx_irq, dockchannel_tx_irq, IRQF_NO_AUTOEN, + "apple-dockchannel-tx", dockchannel); + if (ret) + return ERR_PTR(dev_err_probe(dev, ret, "Failed to request TX IRQ")); + + ret = devm_request_threaded_irq(dev, dockchannel->rx_irq, dockchannel_rx_irq, + dockchannel_rx_irq_thread, IRQF_NO_AUTOEN, + "apple-dockchannel-rx", dockchannel); + if (ret) + return ERR_PTR(dev_err_probe(dev, ret, "Failed to request RX IRQ")); + + return dockchannel; +} +EXPORT_SYMBOL(dockchannel_init); + + +/* Dockchannel IRQchip */ + +static void dockchannel_irq(struct irq_desc *desc) +{ + unsigned int irq = irq_desc_get_irq(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct dockchannel_common *dcc = irq_get_handler_data(irq); + unsigned long flags = readl_relaxed(dcc->irq_base + IRQ_FLAG); + int bit; + + chained_irq_enter(chip, desc); + + for_each_set_bit(bit, &flags, DOCKCHANNEL_MAX_IRQ) + generic_handle_domain_irq(dcc->domain, bit); + + chained_irq_exit(chip, desc); +} + +static void dockchannel_irq_ack(struct irq_data *data) +{ + struct dockchannel_common *dcc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + + writel_relaxed(BIT(hwirq), dcc->irq_base + IRQ_FLAG); +} + +static void dockchannel_irq_mask(struct irq_data *data) +{ + struct dockchannel_common *dcc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + u32 val = readl_relaxed(dcc->irq_base + IRQ_MASK); + + writel_relaxed(val & ~BIT(hwirq), dcc->irq_base + IRQ_MASK); +} + +static void dockchannel_irq_unmask(struct irq_data *data) +{ + struct dockchannel_common *dcc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + u32 val = readl_relaxed(dcc->irq_base + IRQ_MASK); + + writel_relaxed(val | BIT(hwirq), dcc->irq_base + IRQ_MASK); +} + +static const struct irq_chip dockchannel_irqchip = { + .name = "dockchannel-irqc", + .irq_ack = dockchannel_irq_ack, + .irq_mask = dockchannel_irq_mask, + .irq_unmask = dockchannel_irq_unmask, +}; + +static int dockchannel_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_data(virq, d->host_data); + irq_set_chip_and_handler(virq, &dockchannel_irqchip, handle_level_irq); + + return 0; +} + +static const struct irq_domain_ops dockchannel_irq_domain_ops = { + .xlate = irq_domain_xlate_twocell, + .map = dockchannel_irq_domain_map, +}; + +static int dockchannel_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dockchannel_common *dcc; + + dcc = devm_kzalloc(dev, sizeof(*dcc), GFP_KERNEL); + if (!dcc) + return -ENOMEM; + + dcc->dev = dev; + platform_set_drvdata(pdev, dcc); + + dcc->irq_base = devm_platform_ioremap_resource_byname(pdev, "irq"); + if (IS_ERR(dcc->irq_base)) + return PTR_ERR(dcc->irq_base); + + writel_relaxed(0, dcc->irq_base + IRQ_MASK); + writel_relaxed(~0, dcc->irq_base + IRQ_FLAG); + + dcc->domain = irq_domain_add_linear(dev->of_node, DOCKCHANNEL_MAX_IRQ, + &dockchannel_irq_domain_ops, dcc); + if (!dcc->domain) + return -ENOMEM; + + dcc->irq = platform_get_irq(pdev, 0); + if (dcc->irq <= 0) + return dev_err_probe(dev, dcc->irq, "Failed to get IRQ"); + + irq_set_handler_data(dcc->irq, dcc); + irq_set_chained_handler(dcc->irq, dockchannel_irq); + + devm_of_platform_populate(dev); + + return 0; +} + +static void dockchannel_remove(struct platform_device *pdev) +{ + struct dockchannel_common *dcc = platform_get_drvdata(pdev); + int hwirq; + + device_for_each_child(&pdev->dev, NULL, of_platform_device_destroy); + + irq_set_chained_handler_and_data(dcc->irq, NULL, NULL); + + for (hwirq = 0; hwirq < DOCKCHANNEL_MAX_IRQ; hwirq++) + irq_dispose_mapping(irq_find_mapping(dcc->domain, hwirq)); + + irq_domain_remove(dcc->domain); + + writel_relaxed(0, dcc->irq_base + IRQ_MASK); + writel_relaxed(~0, dcc->irq_base + IRQ_FLAG); +} + +static const struct of_device_id dockchannel_of_match[] = { + { .compatible = "apple,dockchannel" }, + {}, +}; +MODULE_DEVICE_TABLE(of, dockchannel_of_match); + +static struct platform_driver dockchannel_driver = { + .driver = { + .name = "dockchannel", + .of_match_table = dockchannel_of_match, + }, + .probe = dockchannel_probe, + .remove = dockchannel_remove, +}; +module_platform_driver(dockchannel_driver); + +MODULE_AUTHOR("Hector Martin "); +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("Apple DockChannel driver"); diff --git a/include/linux/soc/apple/dockchannel.h b/include/linux/soc/apple/dockchannel.h new file mode 100644 index 00000000000000..0b7093935ddf47 --- /dev/null +++ b/include/linux/soc/apple/dockchannel.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* + * Apple Dockchannel devices + * Copyright (C) The Asahi Linux Contributors + */ +#ifndef _LINUX_APPLE_DOCKCHANNEL_H_ +#define _LINUX_APPLE_DOCKCHANNEL_H_ + +#include +#include +#include + +#if IS_ENABLED(CONFIG_APPLE_DOCKCHANNEL) + +struct dockchannel; + +struct dockchannel *dockchannel_init(struct platform_device *pdev); + +int dockchannel_send(struct dockchannel *dockchannel, const void *buf, size_t count); +int dockchannel_recv(struct dockchannel *dockchannel, void *buf, size_t count); +int dockchannel_await(struct dockchannel *dockchannel, + void (*callback)(void *cookie, size_t avail), + void *cookie, size_t count); + +#endif +#endif From e9ca8c87d173cbf7eb2089d7ddec9149e1d608a1 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 8 Jul 2022 02:11:21 +0900 Subject: [PATCH 333/352] HID: Add Apple DockChannel HID transport driver Apple M2 devices have an MTP coprocessor embedded in the SoC that handles HID for the integrated touchpad/keyboard, and communicates over the DockChannel interface. This driver implements this new interface. Signed-off-by: Hector Martin --- drivers/hid/Kconfig | 2 + drivers/hid/Makefile | 4 + drivers/hid/dockchannel-hid/Kconfig | 13 + drivers/hid/dockchannel-hid/Makefile | 6 + drivers/hid/dockchannel-hid/dockchannel-hid.c | 1213 +++++++++++++++++ 5 files changed, 1238 insertions(+) create mode 100644 drivers/hid/dockchannel-hid/Kconfig create mode 100644 drivers/hid/dockchannel-hid/Makefile create mode 100644 drivers/hid/dockchannel-hid/dockchannel-hid.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index e2ca5dd016f08d..8d7b34803073a2 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1458,4 +1458,6 @@ source "drivers/hid/usbhid/Kconfig" source "drivers/hid/spi-hid/Kconfig" +source "drivers/hid/dockchannel-hid/Kconfig" + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0907f3a109c26c..947942cec9a78f 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -174,8 +174,12 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ +obj-$(CONFIG_HID_DOCKCHANNEL) += dockchannel-hid/ + obj-$(CONFIG_SPI_HID_APPLE_CORE) += spi-hid/ +obj-$(CONFIG_HID_DOCKCHANNEL) += dockchannel-hid/ + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/ diff --git a/drivers/hid/dockchannel-hid/Kconfig b/drivers/hid/dockchannel-hid/Kconfig new file mode 100644 index 00000000000000..254961ad15e19c --- /dev/null +++ b/drivers/hid/dockchannel-hid/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only OR MIT +menu "DockChannel HID support" + depends on APPLE_DOCKCHANNEL + +config HID_DOCKCHANNEL + tristate "HID over DockChannel transport layer for Apple Silicon SoCs" + depends on APPLE_DOCKCHANNEL && INPUT && OF && HID + help + Say Y here if you use an M2 or later Apple Silicon based laptop. + The keyboard and touchpad are HID based devices connected via the + proprietary DockChannel interface. + +endmenu diff --git a/drivers/hid/dockchannel-hid/Makefile b/drivers/hid/dockchannel-hid/Makefile new file mode 100644 index 00000000000000..7dba766b047fcc --- /dev/null +++ b/drivers/hid/dockchannel-hid/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only OR MIT +# +# Makefile for DockChannel HID transport drivers +# + +obj-$(CONFIG_HID_DOCKCHANNEL) += dockchannel-hid.o diff --git a/drivers/hid/dockchannel-hid/dockchannel-hid.c b/drivers/hid/dockchannel-hid/dockchannel-hid.c new file mode 100644 index 00000000000000..a712a724ded30b --- /dev/null +++ b/drivers/hid/dockchannel-hid/dockchannel-hid.c @@ -0,0 +1,1213 @@ +/* + * SPDX-License-Identifier: GPL-2.0 OR MIT + * + * Apple DockChannel HID transport driver + * + * Copyright The Asahi Linux Contributors + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../hid-ids.h" + +#define COMMAND_TIMEOUT_MS 1000 +#define START_TIMEOUT_MS 2000 + +#define MAX_INTERFACES 16 + +/* Data + checksum */ +#define MAX_PKT_SIZE (0xffff + 4) + +#define DCHID_CHANNEL_CMD 0x11 +#define DCHID_CHANNEL_REPORT 0x12 + +struct dchid_hdr { + u8 hdr_len; + u8 channel; + u16 length; + u8 seq; + u8 iface; + u16 pad; +} __packed; + +#define IFACE_COMM 0 + +#define FLAGS_GROUP GENMASK(7, 6) +#define FLAGS_REQ GENMASK(5, 0) + +#define REQ_SET_REPORT 0 +#define REQ_GET_REPORT 1 + +struct dchid_subhdr { + u8 flags; + u8 unk; + u16 length; + u32 retcode; +} __packed; + +#define EVENT_GPIO_CMD 0xa0 +#define EVENT_INIT 0xf0 +#define EVENT_READY 0xf1 + +struct dchid_init_hdr { + u8 type; + u8 unk1; + u8 unk2; + u8 iface; + char name[16]; + u8 more_packets; + u8 unkpad; +} __packed; + +#define INIT_HID_DESCRIPTOR 0 +#define INIT_GPIO_REQUEST 1 +#define INIT_TERMINATOR 2 +#define INIT_PRODUCT_NAME 7 + +#define CMD_RESET_INTERFACE 0x40 +#define CMD_SEND_FIRMWARE 0x95 +#define CMD_ENABLE_INTERFACE 0xb4 +#define CMD_ACK_GPIO_CMD 0xa1 + +struct dchid_init_block_hdr { + u16 type; + u16 length; +} __packed; + +#define MAX_GPIO_NAME 32 + +struct dchid_gpio_request { + u16 unk; + u16 id; + char name[MAX_GPIO_NAME]; +} __packed; + +struct dchid_gpio_cmd { + u8 type; + u8 iface; + u8 gpio; + u8 unk; + u8 cmd; +} __packed; + +struct dchid_gpio_ack { + u8 type; + u32 retcode; + u8 cmd[]; +} __packed; + +#define STM_REPORT_ID 0x10 +#define STM_REPORT_SERIAL 0x11 +#define STM_REPORT_KEYBTYPE 0x14 + +struct dchid_stm_id { + u8 unk; + u16 vendor_id; + u16 product_id; + u16 version_number; + u8 unk2; + u8 unk3; + u8 keyboard_type; + u8 serial_length; + /* Serial follows, but we grab it with a different report. */ +} __packed; + +#define FW_MAGIC 0x46444948 +#define FW_VER 1 + +struct fw_header { + u32 magic; + u32 version; + u32 hdr_length; + u32 data_length; + u32 iface_offset; +} __packed; + +struct dchid_work { + struct work_struct work; + struct dchid_iface *iface; + + struct dchid_hdr hdr; + u8 data[]; +}; + +struct dchid_iface { + struct dockchannel_hid *dchid; + struct hid_device *hid; + struct workqueue_struct *wq; + + bool creating; + struct work_struct create_work; + + int index; + const char *name; + const struct device_node *of_node; + + uint8_t tx_seq; + bool deferred; + bool starting; + bool open; + struct completion ready; + + void *hid_desc; + size_t hid_desc_len; + + struct gpio_desc *gpio; + char gpio_name[MAX_GPIO_NAME]; + int gpio_id; + + struct mutex out_mutex; + u32 out_flags; + int out_report; + u32 retcode; + void *resp_buf; + size_t resp_size; + struct completion out_complete; + + u32 keyboard_layout_id; +}; + +struct dockchannel_hid { + struct device *dev; + struct dockchannel *dc; + struct device_link *helper_link; + + bool id_ready; + struct dchid_stm_id device_id; + char serial[64]; + + struct dchid_iface *comm; + struct dchid_iface *ifaces[MAX_INTERFACES]; + + u8 pkt_buf[MAX_PKT_SIZE]; + + /* Workqueue to asynchronously create HID devices */ + struct workqueue_struct *new_iface_wq; +}; + +static ssize_t apple_layout_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = to_hid_device(dev); + struct dchid_iface *iface = hdev->driver_data; + + return scnprintf(buf, PAGE_SIZE, "%d\n", iface->keyboard_layout_id); +} + +static DEVICE_ATTR_RO(apple_layout_id); + +static struct dchid_iface * +dchid_get_interface(struct dockchannel_hid *dchid, int index, const char *name) +{ + struct dchid_iface *iface; + + if (index >= MAX_INTERFACES) { + dev_err(dchid->dev, "Interface index %d out of range\n", index); + return NULL; + } + + if (dchid->ifaces[index]) + return dchid->ifaces[index]; + + iface = devm_kzalloc(dchid->dev, sizeof(struct dchid_iface), GFP_KERNEL); + if (!iface) + return NULL; + + iface->index = index; + iface->name = devm_kstrdup(dchid->dev, name, GFP_KERNEL); + iface->dchid = dchid; + iface->out_report= -1; + init_completion(&iface->out_complete); + init_completion(&iface->ready); + mutex_init(&iface->out_mutex); + iface->wq = alloc_ordered_workqueue("dchid-%s", WQ_MEM_RECLAIM, iface->name); + if (!iface->wq) + return NULL; + + /* Comm is not a HID subdevice */ + if (!strcmp(name, "comm")) { + dchid->ifaces[index] = iface; + return iface; + } + + iface->of_node = of_get_child_by_name(dchid->dev->of_node, name); + if (!iface->of_node) { + dev_warn(dchid->dev, "No OF node for subdevice %s, ignoring.", name); + return NULL; + } + + dchid->ifaces[index] = iface; + return iface; +} + +static u32 dchid_checksum(void *p, size_t length) +{ + u32 sum = 0; + + while (length >= 4) { + sum += get_unaligned_le32(p); + p += 4; + length -= 4; + } + + WARN_ON_ONCE(length); + return sum; +} + +static int dchid_send(struct dchid_iface *iface, u32 flags, void *msg, size_t size) +{ + u32 checksum = 0xffffffff; + size_t wsize = round_down(size, 4); + size_t tsize = size - wsize; + int ret; + struct { + struct dchid_hdr hdr; + struct dchid_subhdr sub; + } __packed h; + + memset(&h, 0, sizeof(h)); + h.hdr.hdr_len = sizeof(h.hdr); + h.hdr.channel = DCHID_CHANNEL_CMD; + h.hdr.length = round_up(size, 4) + sizeof(h.sub); + h.hdr.seq = iface->tx_seq; + h.hdr.iface = iface->index; + h.sub.flags = flags; + h.sub.length = size; + + ret = dockchannel_send(iface->dchid->dc, &h, sizeof(h)); + if (ret < 0) + return ret; + checksum -= dchid_checksum(&h, sizeof(h)); + + ret = dockchannel_send(iface->dchid->dc, msg, wsize); + if (ret < 0) + return ret; + checksum -= dchid_checksum(msg, wsize); + + if (tsize) { + u8 tail[4] = {0, 0, 0, 0}; + + memcpy(tail, msg + wsize, tsize); + ret = dockchannel_send(iface->dchid->dc, tail, sizeof(tail)); + if (ret < 0) + return ret; + checksum -= dchid_checksum(tail, sizeof(tail)); + } + + ret = dockchannel_send(iface->dchid->dc, &checksum, sizeof(checksum)); + if (ret < 0) + return ret; + + return 0; +} + +static int dchid_cmd(struct dchid_iface *iface, u32 type, u32 req, + void *data, size_t size, void *resp_buf, size_t resp_size) +{ + int ret; + int report_id = *(u8*)data; + + mutex_lock(&iface->out_mutex); + + WARN_ON(iface->out_report != -1); + iface->out_report = report_id; + iface->out_flags = FIELD_PREP(FLAGS_GROUP, type) | FIELD_PREP(FLAGS_REQ, req); + iface->resp_buf = resp_buf; + iface->resp_size = resp_size; + reinit_completion(&iface->out_complete); + + ret = dchid_send(iface, iface->out_flags, data, size); + if (ret < 0) + goto done; + + if (!wait_for_completion_timeout(&iface->out_complete, msecs_to_jiffies(COMMAND_TIMEOUT_MS))) { + dev_err(iface->dchid->dev, "output report 0x%x to iface %d (%s) timed out\n", + report_id, iface->index, iface->name); + ret = -ETIMEDOUT; + goto done; + } + + ret = iface->resp_size; + if (iface->retcode) { + dev_err(iface->dchid->dev, + "output report 0x%x to iface %d (%s) failed with err 0x%x\n", + report_id, iface->index, iface->name, iface->retcode); + ret = -EIO; + } + +done: + iface->tx_seq++; + iface->out_report = -1; + iface->out_flags = 0; + iface->resp_buf = NULL; + iface->resp_size = 0; + mutex_unlock(&iface->out_mutex); + return ret; +} + +static int dchid_comm_cmd(struct dockchannel_hid *dchid, void *cmd, size_t size) +{ + return dchid_cmd(dchid->comm, HID_FEATURE_REPORT, REQ_SET_REPORT, cmd, size, NULL, 0); +} + +static int dchid_enable_interface(struct dchid_iface *iface) +{ + u8 msg[] = { CMD_ENABLE_INTERFACE, iface->index }; + + return dchid_comm_cmd(iface->dchid, msg, sizeof(msg)); +} + +static int dchid_reset_interface(struct dchid_iface *iface, int state) +{ + u8 msg[] = { CMD_RESET_INTERFACE, 1, iface->index, state }; + + return dchid_comm_cmd(iface->dchid, msg, sizeof(msg)); +} + +static int dchid_send_firmware(struct dchid_iface *iface, void *firmware, size_t size) +{ + struct { + u8 cmd; + u8 unk1; + u8 unk2; + u8 iface; + u64 addr; + u32 size; + } __packed msg = { + .cmd = CMD_SEND_FIRMWARE, + .unk1 = 2, + .unk2 = 0, + .iface = iface->index, + .size = size, + }; + dma_addr_t addr; + void *buf = dmam_alloc_coherent(iface->dchid->dev, size, &addr, GFP_KERNEL); + + if (IS_ERR_OR_NULL(buf)) + return buf ? PTR_ERR(buf) : -ENOMEM; + + msg.addr = addr; + memcpy(buf, firmware, size); + wmb(); + + return dchid_comm_cmd(iface->dchid, &msg, sizeof(msg)); +} + +static int dchid_get_firmware(struct dchid_iface *iface, void **firmware, size_t *size) +{ + int ret; + const char *fw_name; + const struct firmware *fw; + struct fw_header *hdr; + u8 *fw_data; + + ret = of_property_read_string(iface->of_node, "firmware-name", &fw_name); + if (ret) { + /* Firmware is only for some devices */ + *firmware = NULL; + *size = 0; + return 0; + } + + ret = request_firmware(&fw, fw_name, iface->dchid->dev); + if (ret) + return ret; + + hdr = (struct fw_header *)fw->data; + + if (hdr->magic != FW_MAGIC || hdr->version != FW_VER || + hdr->hdr_length < sizeof(*hdr) || hdr->hdr_length > fw->size || + (hdr->hdr_length + (size_t)hdr->data_length) > fw->size || + hdr->iface_offset >= hdr->data_length) { + dev_warn(iface->dchid->dev, "%s: invalid firmware header\n", + fw_name); + ret = -EINVAL; + goto done; + } + + fw_data = devm_kmemdup(iface->dchid->dev, fw->data + hdr->hdr_length, + hdr->data_length, GFP_KERNEL); + if (!fw_data) { + ret = -ENOMEM; + goto done; + } + + if (hdr->iface_offset) + fw_data[hdr->iface_offset] = iface->index; + + *firmware = fw_data; + *size = hdr->data_length; + +done: + release_firmware(fw); + return ret; +} + +static int dchid_request_gpio(struct dchid_iface *iface) +{ + char prop_name[MAX_GPIO_NAME + 16]; + + if (iface->gpio) + return 0; + + dev_info(iface->dchid->dev, "Requesting GPIO %s#%d: %s\n", + iface->name, iface->gpio_id, iface->gpio_name); + + snprintf(prop_name, sizeof(prop_name), "apple,%s", iface->gpio_name); + + iface->gpio = devm_gpiod_get_index(iface->dchid->dev, prop_name, 0, GPIOD_OUT_LOW); + + if (IS_ERR_OR_NULL(iface->gpio)) { + dev_err(iface->dchid->dev, "Failed to request GPIO %s-gpios\n", prop_name); + iface->gpio = NULL; + return -1; + } + + return 0; +} + +static int dchid_start_interface(struct dchid_iface *iface) +{ + void *fw; + size_t size; + int ret; + + if (iface->starting) { + dev_warn(iface->dchid->dev, "Interface %s is already starting", iface->name); + return -EINPROGRESS; + } + + dev_info(iface->dchid->dev, "Starting interface %s\n", iface->name); + + iface->starting = true; + + /* Look to see if we need firmware */ + ret = dchid_get_firmware(iface, &fw, &size); + if (ret < 0) + goto err; + + /* If we need a GPIO, make sure we have it. */ + if (iface->gpio_id) { + ret = dchid_request_gpio(iface); + if (ret < 0) + goto err; + } + + /* Only multi-touch has firmware */ + if (fw && size) { + + /* Send firmware to the device */ + dev_info(iface->dchid->dev, "Sending firmware for %s\n", iface->name); + ret = dchid_send_firmware(iface, fw, size); + if (ret < 0) { + dev_err(iface->dchid->dev, "Failed to send %s firmwareS", iface->name); + goto err; + } + + /* After loading firmware, multi-touch needs a reset */ + dev_info(iface->dchid->dev, "Resetting %s\n", iface->name); + dchid_reset_interface(iface, 0); + dchid_reset_interface(iface, 2); + } + + return 0; + +err: + iface->starting = false; + return ret; +} + +static int dchid_start(struct hid_device *hdev) +{ + struct dchid_iface *iface = hdev->driver_data; + + if (iface->keyboard_layout_id) { + int ret = device_create_file(&hdev->dev, &dev_attr_apple_layout_id); + if (ret) { + dev_warn(iface->dchid->dev, "Failed to create apple_layout_id: %d", ret); + iface->keyboard_layout_id = 0; + } + } + + return 0; +}; + +static void dchid_stop(struct hid_device *hdev) +{ + struct dchid_iface *iface = hdev->driver_data; + + if (iface->keyboard_layout_id) + device_remove_file(&hdev->dev, &dev_attr_apple_layout_id); +} + +static int dchid_open(struct hid_device *hdev) +{ + struct dchid_iface *iface = hdev->driver_data; + int ret; + + if (!completion_done(&iface->ready)) { + ret = dchid_start_interface(iface); + if (ret < 0) + return ret; + + if (!wait_for_completion_timeout(&iface->ready, msecs_to_jiffies(START_TIMEOUT_MS))) { + dev_err(iface->dchid->dev, "iface %s start timed out\n", iface->name); + return -ETIMEDOUT; + } + } + + iface->open = true; + return 0; +} + +static void dchid_close(struct hid_device *hdev) +{ + struct dchid_iface *iface = hdev->driver_data; + + iface->open = false; +} + +static int dchid_parse(struct hid_device *hdev) +{ + struct dchid_iface *iface = hdev->driver_data; + + return hid_parse_report(hdev, iface->hid_desc, iface->hid_desc_len); +} + +/* Note: buf excludes report number! For ease of fetching strings/etc. */ +static int dchid_get_report_cmd(struct dchid_iface *iface, u8 reportnum, void *buf, size_t len) +{ + int ret = dchid_cmd(iface, HID_FEATURE_REPORT, REQ_GET_REPORT, &reportnum, 1, buf, len); + + return ret <= 0 ? ret : ret - 1; +} + +/* Note: buf includes report number! */ +static int dchid_set_report(struct dchid_iface *iface, void *buf, size_t len) +{ + return dchid_cmd(iface, HID_OUTPUT_REPORT, REQ_SET_REPORT, buf, len, NULL, 0); +} + +static int dchid_raw_request(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, size_t len, + unsigned char rtype, int reqtype) +{ + struct dchid_iface *iface = hdev->driver_data; + + switch (reqtype) { + case HID_REQ_GET_REPORT: + buf[0] = reportnum; + return dchid_cmd(iface, rtype, REQ_GET_REPORT, &reportnum, 1, buf + 1, len - 1); + case HID_REQ_SET_REPORT: + return dchid_set_report(iface, buf, len); + default: + return -EIO; + } + + return 0; +} + +static struct hid_ll_driver dchid_ll = { + .start = &dchid_start, + .stop = &dchid_stop, + .open = &dchid_open, + .close = &dchid_close, + .parse = &dchid_parse, + .raw_request = &dchid_raw_request, +}; + +static void dchid_create_interface_work(struct work_struct *ws) +{ + struct dchid_iface *iface = container_of(ws, struct dchid_iface, create_work); + struct dockchannel_hid *dchid = iface->dchid; + struct hid_device *hid; + int ret; + + if (iface->hid) { + dev_warn(dchid->dev, "Interface %s already created!\n", + iface->name); + return; + } + + dev_info(dchid->dev, "New interface %s\n", iface->name); + + /* Start the interface. This is not the entire init process, as firmware is loaded later on device open. */ + ret = dchid_enable_interface(iface); + if (ret < 0) { + dev_warn(dchid->dev, "Failed to enable %s: %d\n", iface->name, ret); + return; + } + + iface->deferred = false; + + hid = hid_allocate_device(); + if (IS_ERR(hid)) + return; + + snprintf(hid->name, sizeof(hid->name), "Apple MTP %s", iface->name); + snprintf(hid->phys, sizeof(hid->phys), "%s.%d (%s)", + dev_name(dchid->dev), iface->index, iface->name); + strscpy(hid->uniq, dchid->serial, sizeof(hid->uniq)); + + hid->ll_driver = &dchid_ll; + hid->bus = BUS_HOST; + hid->vendor = dchid->device_id.vendor_id; + hid->product = dchid->device_id.product_id; + hid->version = dchid->device_id.version_number; + hid->type = HID_TYPE_OTHER; + if (!strcmp(iface->name, "multi-touch")) { + hid->type = HID_TYPE_SPI_MOUSE; + } else if (!strcmp(iface->name, "keyboard")) { + u32 country_code = 0; + + hid->type = HID_TYPE_SPI_KEYBOARD; + + /* + * We have to get the country code from the device tree, since the + * device provides no reliable way to get this info. + */ + if (!of_property_read_u32(iface->of_node, "hid-country-code", &country_code)) + hid->country = country_code; + + of_property_read_u32(iface->of_node, "apple,keyboard-layout-id", + &iface->keyboard_layout_id); + } + + hid->dev.parent = iface->dchid->dev; + hid->driver_data = iface; + + iface->hid = hid; + + ret = hid_add_device(hid); + if (ret < 0) { + iface->hid = NULL; + hid_destroy_device(hid); + dev_warn(iface->dchid->dev, "Failed to register hid device %s", iface->name); + } +} + +static int dchid_create_interface(struct dchid_iface *iface) +{ + if (iface->creating) + return -EBUSY; + + iface->creating = true; + INIT_WORK(&iface->create_work, dchid_create_interface_work); + return queue_work(iface->dchid->new_iface_wq, &iface->create_work); +} + +static void dchid_handle_descriptor(struct dchid_iface *iface, void *hid_desc, size_t desc_len) +{ + if (iface->hid) { + dev_warn(iface->dchid->dev, "Tried to initialize already started interface %s!\n", + iface->name); + return; + } + + iface->hid_desc = devm_kmemdup(iface->dchid->dev, hid_desc, desc_len, GFP_KERNEL); + if (!iface->hid_desc) + return; + + iface->hid_desc_len = desc_len; +} + +static void dchid_handle_ready(struct dockchannel_hid *dchid, void *data, size_t length) +{ + struct dchid_iface *iface; + u8 *pkt = data; + u8 index; + int i, ret; + + if (length < 2) { + dev_err(dchid->dev, "Bad length for ready message: %zu\n", length); + return; + } + + index = pkt[1]; + + if (index >= MAX_INTERFACES) { + dev_err(dchid->dev, "Got ready notification for bad iface %d\n", index); + return; + } + + iface = dchid->ifaces[index]; + if (!iface) { + dev_err(dchid->dev, "Got ready notification for unknown iface %d\n", index); + return; + } + + dev_info(dchid->dev, "Interface %s is now ready\n", iface->name); + complete_all(&iface->ready); + + /* When STM is ready, grab global device info */ + if (!strcmp(iface->name, "stm")) { + ret = dchid_get_report_cmd(iface, STM_REPORT_ID, &dchid->device_id, + sizeof(dchid->device_id)); + if (ret < sizeof(dchid->device_id)) { + dev_warn(iface->dchid->dev, "Failed to get device ID from STM!\n"); + /* Fake it and keep going. Things might still work... */ + memset(&dchid->device_id, 0, sizeof(dchid->device_id)); + dchid->device_id.vendor_id = HOST_VENDOR_ID_APPLE; + } + ret = dchid_get_report_cmd(iface, STM_REPORT_SERIAL, dchid->serial, + sizeof(dchid->serial) - 1); + if (ret < 0) { + dev_warn(iface->dchid->dev, "Failed to get serial from STM!\n"); + dchid->serial[0] = 0; + } + + dchid->id_ready = true; + for (i = 0; i < MAX_INTERFACES; i++) { + if (!dchid->ifaces[i] || !dchid->ifaces[i]->deferred) + continue; + dchid_create_interface(dchid->ifaces[i]); + } + } +} + +static void dchid_handle_init(struct dockchannel_hid *dchid, void *data, size_t length) +{ + struct dchid_init_hdr *hdr = data; + struct dchid_iface *iface; + struct dchid_init_block_hdr *blk; + + if (length < sizeof(*hdr)) + return; + + iface = dchid_get_interface(dchid, hdr->iface, hdr->name); + if (!iface) + return; + + data += sizeof(*hdr); + length -= sizeof(*hdr); + + while (length >= sizeof(*blk)) { + blk = data; + data += sizeof(*blk); + length -= sizeof(*blk); + + if (blk->length > length) + break; + + switch (blk->type) { + case INIT_HID_DESCRIPTOR: + dchid_handle_descriptor(iface, data, blk->length); + break; + + case INIT_GPIO_REQUEST: { + struct dchid_gpio_request *req = data; + + if (sizeof(*req) > length) + break; + + if (iface->gpio_id) { + dev_err(dchid->dev, + "Cannot request more than one GPIO per interface!\n"); + break; + } + + strscpy(iface->gpio_name, req->name, MAX_GPIO_NAME); + iface->gpio_id = req->id; + break; + } + + case INIT_TERMINATOR: + break; + + case INIT_PRODUCT_NAME: { + char *product = data; + + if (product[blk->length - 1] != 0) { + dev_warn(dchid->dev, "Unterminated product name for %s\n", + iface->name); + } else { + dev_info(dchid->dev, "Product name for %s: %s\n", + iface->name, product); + } + break; + } + + default: + dev_warn(dchid->dev, "Unknown init packet %d for %s\n", + blk->type, iface->name); + break; + } + + data += blk->length; + length -= blk->length; + + if (blk->type == INIT_TERMINATOR) + break; + } + + if (hdr->more_packets) + return; + + /* We need to enable STM first, since it'll give us the device IDs */ + if (iface->dchid->id_ready || !strcmp(iface->name, "stm")) { + dchid_create_interface(iface); + } else { + iface->deferred = true; + } +} + +static void dchid_handle_gpio(struct dockchannel_hid *dchid, void *data, size_t length) +{ + struct dchid_gpio_cmd *cmd = data; + struct dchid_iface *iface; + u32 retcode = 0xe000f00d; /* Give it a random Apple-style error code */ + struct dchid_gpio_ack *ack; + + if (length < sizeof(*cmd)) + return; + + if (cmd->iface >= MAX_INTERFACES || !(iface = dchid->ifaces[cmd->iface])) { + dev_err(dchid->dev, "Got GPIO command for bad inteface %d\n", cmd->iface); + goto err; + } + + if (dchid_request_gpio(iface) < 0) + goto err; + + if (!iface->gpio || cmd->gpio != iface->gpio_id) { + dev_err(dchid->dev, "Got GPIO command for bad GPIO %s#%d\n", + iface->name, cmd->gpio); + goto err; + } + + dev_info(dchid->dev, "GPIO command: %s#%d: %d\n", iface->name, cmd->gpio, cmd->cmd); + + switch (cmd->cmd) { + case 3: + /* Pulse. */ + gpiod_set_value_cansleep(iface->gpio, 1); + msleep(10); /* Random guess... */ + gpiod_set_value_cansleep(iface->gpio, 0); + retcode = 0; + break; + default: + dev_err(dchid->dev, "Unknown GPIO command %d\n", cmd->cmd ); + break; + } + +err: + /* Ack it */ + ack = kzalloc(sizeof(*ack) + length, GFP_KERNEL); + if (!ack) + return; + + ack->type = CMD_ACK_GPIO_CMD; + ack->retcode = retcode; + memcpy(ack->cmd, data, length); + + if (dchid_comm_cmd(dchid, ack, sizeof(*ack) + length) < 0) + dev_err(dchid->dev, "Failed to ACK GPIO command\n"); + + kfree(ack); +} + +static void dchid_handle_event(struct dockchannel_hid *dchid, void *data, size_t length) +{ + u8 *p = data; + switch (*p) { + case EVENT_INIT: + dchid_handle_init(dchid, data, length); + break; + case EVENT_READY: + dchid_handle_ready(dchid, data, length); + break; + case EVENT_GPIO_CMD: + dchid_handle_gpio(dchid, data, length); + break; + } +} + +static void dchid_handle_report(struct dchid_iface *iface, void *data, size_t length) +{ + struct dockchannel_hid *dchid = iface->dchid; + + if (!iface->hid) { + dev_warn(dchid->dev, "Report received but %s is not initialized!\n", iface->name); + return; + } + + if (!iface->open) + return; + + hid_input_report(iface->hid, HID_INPUT_REPORT, data, length, 1); +} + +static void dchid_packet_work(struct work_struct *ws) +{ + struct dchid_work *work = container_of(ws, struct dchid_work, work); + struct dchid_subhdr *shdr = (void *)work->data; + struct dockchannel_hid *dchid = work->iface->dchid; + int type = FIELD_GET(FLAGS_GROUP, shdr->flags); + u8 *payload = work->data + sizeof(*shdr); + + if (shdr->length + sizeof(*shdr) > work->hdr.length) { + dev_err(dchid->dev, "Bad sub header length (%d > %zu)\n", + shdr->length, work->hdr.length - sizeof(*shdr)); + return; + } + + switch (type) { + case HID_INPUT_REPORT: + if (work->hdr.iface == IFACE_COMM) + dchid_handle_event(dchid, payload, shdr->length); + else + dchid_handle_report(work->iface, payload, shdr->length); + break; + default: + dev_err(dchid->dev, "Received unknown packet type %d\n", type); + break; + } + + kfree(work); +} + +static void dchid_handle_ack(struct dchid_iface *iface, struct dchid_hdr *hdr, void *data) +{ + struct dchid_subhdr *shdr = (void *)data; + u8 *payload = data + sizeof(*shdr); + + if (shdr->length + sizeof(*shdr) > hdr->length) { + dev_err(iface->dchid->dev, "Bad sub header length (%d > %ld)\n", + shdr->length, hdr->length - sizeof(*shdr)); + return; + } + if (shdr->flags != iface->out_flags) { + dev_err(iface->dchid->dev, + "Received unexpected flags 0x%x on ACK channel (expFected 0x%x)\n", + shdr->flags, iface->out_flags); + return; + } + + if (shdr->length < 1) { + dev_err(iface->dchid->dev, "Received length 0 output report ack\n"); + return; + } + if (iface->tx_seq != hdr->seq) { + dev_err(iface->dchid->dev, "Received ACK with bad seq (expected %d, got %d)\n", + iface->tx_seq, hdr->seq); + return; + } + if (iface->out_report != payload[0]) { + dev_err(iface->dchid->dev, "Received ACK with bad report (expected %d, got %d\n", + iface->out_report, payload[0]); + return; + } + + if (iface->resp_buf && iface->resp_size) + memcpy(iface->resp_buf, payload + 1, min((size_t)shdr->length - 1, iface->resp_size)); + + iface->resp_size = shdr->length; + iface->out_report = -1; + iface->retcode = shdr->retcode; + complete(&iface->out_complete); +} + +static void dchid_handle_packet(void *cookie, size_t avail) +{ + struct dockchannel_hid *dchid = cookie; + struct dchid_hdr hdr; + struct dchid_work *work; + struct dchid_iface *iface; + u32 checksum; + + if (dockchannel_recv(dchid->dc, &hdr, sizeof(hdr)) != sizeof(hdr)) { + dev_err(dchid->dev, "Read failed (header)\n"); + return; + } + + if (hdr.hdr_len != sizeof(hdr)) { + dev_err(dchid->dev, "Bad header length %d\n", hdr.hdr_len); + goto done; + } + + if (dockchannel_recv(dchid->dc, dchid->pkt_buf, hdr.length + 4) != (hdr.length + 4)) { + dev_err(dchid->dev, "Read failed (body)\n"); + goto done; + } + + checksum = dchid_checksum(&hdr, sizeof(hdr)); + checksum += dchid_checksum(dchid->pkt_buf, hdr.length + 4); + + if (checksum != 0xffffffff) { + dev_err(dchid->dev, "Checksum mismatch (iface %d): 0x%08x != 0xffffffff\n", + hdr.iface, checksum); + goto done; + } + + + if (hdr.iface >= MAX_INTERFACES) { + dev_err(dchid->dev, "Bad iface %d\n", hdr.iface); + } + + iface = dchid->ifaces[hdr.iface]; + + if (!iface) { + dev_err(dchid->dev, "Received packet for uninitialized iface %d\n", hdr.iface); + goto done; + } + + switch (hdr.channel) { + case DCHID_CHANNEL_CMD: + dchid_handle_ack(iface, &hdr, dchid->pkt_buf); + goto done; + case DCHID_CHANNEL_REPORT: + break; + default: + dev_warn(dchid->dev, "Unknown channel 0x%x, treating as report...\n", + hdr.channel); + break; + } + + work = kzalloc(sizeof(*work) + hdr.length, GFP_KERNEL); + if (!work) + return; + + work->hdr = hdr; + work->iface = iface; + memcpy(work->data, dchid->pkt_buf, hdr.length); + INIT_WORK(&work->work, dchid_packet_work); + + queue_work(iface->wq, &work->work); + +done: + dockchannel_await(dchid->dc, dchid_handle_packet, dchid, sizeof(struct dchid_hdr)); +} + +static int dockchannel_hid_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dockchannel_hid *dchid; + struct device_node *child, *helper; + struct platform_device *helper_pdev; + struct property *prop; + int ret; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) + return ret; + + dchid = devm_kzalloc(dev, sizeof(*dchid), GFP_KERNEL); + if (!dchid) { + return -ENOMEM; + } + + dchid->dev = dev; + + /* + * First make sure all the GPIOs are available, in cased we need to defer. + * This is necessary because MTP will request them by name later, and by then + * it's too late to defer the probe. + */ + + for_each_child_of_node(dev->of_node, child) { + for_each_property_of_node(child, prop) { + size_t len = strlen(prop->name); + struct gpio_desc *gpio; + + if (len < 12 || strncmp("apple,", prop->name, 6) || + strcmp("-gpios", prop->name + len - 6)) + continue; + + gpio = fwnode_gpiod_get_index(&child->fwnode, prop->name, 0, GPIOD_ASIS, + prop->name); + if (IS_ERR_OR_NULL(gpio)) { + if (PTR_ERR(gpio) == -EPROBE_DEFER) { + of_node_put(child); + return -EPROBE_DEFER; + } + } else { + gpiod_put(gpio); + } + } + } + + /* + * Make sure we also have the MTP coprocessor available, and + * defer probe if the helper hasn't probed yet. + */ + helper = of_parse_phandle(dev->of_node, "apple,helper-cpu", 0); + if (!helper) { + dev_err(dev, "Missing apple,helper-cpu property"); + return -EINVAL; + } + + helper_pdev = of_find_device_by_node(helper); + of_node_put(helper); + if (!helper_pdev) { + dev_err(dev, "Failed to find helper device"); + return -EINVAL; + } + + dchid->helper_link = device_link_add(dev, &helper_pdev->dev, + DL_FLAG_AUTOREMOVE_CONSUMER); + put_device(&helper_pdev->dev); + if (!dchid->helper_link) { + dev_err(dev, "Failed to link to helper device"); + return -EINVAL; + } + + if (dchid->helper_link->supplier->links.status != DL_DEV_DRIVER_BOUND) + return -EPROBE_DEFER; + + /* Now it is safe to begin initializing */ + dchid->dc = dockchannel_init(pdev); + if (IS_ERR_OR_NULL(dchid->dc)) { + return PTR_ERR(dchid->dc); + } + dchid->new_iface_wq = alloc_workqueue("dchid-new", WQ_MEM_RECLAIM, 0); + if (!dchid->new_iface_wq) + return -ENOMEM; + + dchid->comm = dchid_get_interface(dchid, IFACE_COMM, "comm"); + if (!dchid->comm) { + dev_err(dchid->dev, "Failed to initialize comm interface"); + return -EIO; + } + + dev_info(dchid->dev, "Initialized, awaiting packets\n"); + dockchannel_await(dchid->dc, dchid_handle_packet, dchid, sizeof(struct dchid_hdr)); + + return 0; +} + +static void dockchannel_hid_remove(struct platform_device *pdev) +{ + BUG_ON(1); +} + +static const struct of_device_id dockchannel_hid_of_match[] = { + { .compatible = "apple,dockchannel-hid" }, + {}, +}; +MODULE_DEVICE_TABLE(of, dockchannel_hid_of_match); +MODULE_FIRMWARE("apple/tpmtfw-*.bin"); + +static struct platform_driver dockchannel_hid_driver = { + .driver = { + .name = "dockchannel-hid", + .of_match_table = dockchannel_hid_of_match, + }, + .probe = dockchannel_hid_probe, + .remove = dockchannel_hid_remove, +}; +module_platform_driver(dockchannel_hid_driver); + +MODULE_DESCRIPTION("Apple DockChannel HID transport driver"); +MODULE_AUTHOR("Hector Martin "); +MODULE_LICENSE("Dual MIT/GPL"); From 7b3c6e8461f3035d025ece758919facbc1c6d854 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 3 Jul 2022 23:33:37 +0900 Subject: [PATCH 334/352] soc: apple: Add RTKit helper driver This driver can be used for coprocessors that do some background task or communicate out-of-band, and do not do any mailbox I/O beyond the standard RTKit initialization. Signed-off-by: Hector Martin --- drivers/soc/apple/Kconfig | 13 +++ drivers/soc/apple/Makefile | 3 + drivers/soc/apple/rtkit-helper.c | 151 +++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 drivers/soc/apple/rtkit-helper.c diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index b44aa998f73bdf..128dd2771dc894 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -37,6 +37,19 @@ config APPLE_RTKIT Say 'y' here if you have an Apple SoC. +config APPLE_RTKIT_HELPER + tristate "Apple Generic RTKit helper co-processor" + depends on APPLE_RTKIT + depends on ARCH_APPLE || COMPILE_TEST + help + Apple SoCs such as the M1 come with various co-processors running + their proprietary RTKit operating system. This option enables support + for a generic co-processor that does not implement any additional + in-band communications. It can be used for testing purposes, or for + coprocessors such as MTP that communicate over a different interface. + + Say 'y' here if you have an Apple SoC. + config APPLE_SART tristate "Apple SART DMA address filter" depends on ARCH_APPLE || COMPILE_TEST diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index b5ffadc16dc84d..10eae75460a5b3 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -9,6 +9,9 @@ apple-mailbox-y = mailbox.o obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o apple-rtkit-y = rtkit.o rtkit-crashlog.o +obj-$(CONFIG_APPLE_RTKIT_HELPER) += apple-rtkit-helper.o +apple-rtkit-helper-y = rtkit-helper.o + obj-$(CONFIG_APPLE_SART) += apple-sart.o apple-sart-y = sart.o diff --git a/drivers/soc/apple/rtkit-helper.c b/drivers/soc/apple/rtkit-helper.c new file mode 100644 index 00000000000000..080d083ed9bd2f --- /dev/null +++ b/drivers/soc/apple/rtkit-helper.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple Generic RTKit helper coprocessor + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define APPLE_ASC_CPU_CONTROL 0x44 +#define APPLE_ASC_CPU_CONTROL_RUN BIT(4) + +struct apple_rtkit_helper { + struct device *dev; + struct apple_rtkit *rtk; + + void __iomem *asc_base; + + struct resource *sram; + void __iomem *sram_base; +}; + +static int apple_rtkit_helper_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr) +{ + struct apple_rtkit_helper *helper = cookie; + struct resource res = { + .start = bfr->iova, + .end = bfr->iova + bfr->size - 1, + .name = "rtkit_map", + }; + + if (!bfr->iova) { + bfr->buffer = dma_alloc_coherent(helper->dev, bfr->size, + &bfr->iova, GFP_KERNEL); + if (!bfr->buffer) + return -ENOMEM; + return 0; + } + + if (!helper->sram) { + dev_err(helper->dev, + "RTKit buffer request with no SRAM region: %pR", &res); + return -EFAULT; + } + + res.flags = helper->sram->flags; + + if (res.end < res.start || !resource_contains(helper->sram, &res)) { + dev_err(helper->dev, + "RTKit buffer request outside SRAM region: %pR", &res); + return -EFAULT; + } + + bfr->iomem = helper->sram_base + (res.start - helper->sram->start); + bfr->is_mapped = true; + + return 0; +} + +static void apple_rtkit_helper_shmem_destroy(void *cookie, struct apple_rtkit_shmem *bfr) +{ + // no-op +} + +static const struct apple_rtkit_ops apple_rtkit_helper_ops = { + .shmem_setup = apple_rtkit_helper_shmem_setup, + .shmem_destroy = apple_rtkit_helper_shmem_destroy, +}; + +static int apple_rtkit_helper_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apple_rtkit_helper *helper; + int ret; + + /* 44 bits for addresses in standard RTKit requests */ + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44)); + if (ret) + return ret; + + helper = devm_kzalloc(dev, sizeof(*helper), GFP_KERNEL); + if (!helper) + return -ENOMEM; + + helper->dev = dev; + platform_set_drvdata(pdev, helper); + + helper->asc_base = devm_platform_ioremap_resource_byname(pdev, "asc"); + if (IS_ERR(helper->asc_base)) + return PTR_ERR(helper->asc_base); + + helper->sram = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); + if (helper->sram) { + helper->sram_base = devm_ioremap_resource(dev, helper->sram); + if (IS_ERR(helper->sram_base)) + return dev_err_probe(dev, PTR_ERR(helper->sram_base), + "Failed to map SRAM region"); + } + + helper->rtk = + devm_apple_rtkit_init(dev, helper, NULL, 0, &apple_rtkit_helper_ops); + if (IS_ERR(helper->rtk)) + return dev_err_probe(dev, PTR_ERR(helper->rtk), + "Failed to intialize RTKit"); + + writel_relaxed(APPLE_ASC_CPU_CONTROL_RUN, + helper->asc_base + APPLE_ASC_CPU_CONTROL); + + /* Works for both wake and boot */ + ret = apple_rtkit_wake(helper->rtk); + if (ret != 0) + return dev_err_probe(dev, ret, "Failed to wake up coprocessor"); + + return 0; +} + +static void apple_rtkit_helper_remove(struct platform_device *pdev) +{ + struct apple_rtkit_helper *helper = platform_get_drvdata(pdev); + + if (apple_rtkit_is_running(helper->rtk)) + apple_rtkit_quiesce(helper->rtk); + + writel_relaxed(0, helper->asc_base + APPLE_ASC_CPU_CONTROL); +} + +static const struct of_device_id apple_rtkit_helper_of_match[] = { + { .compatible = "apple,rtk-helper-asc4" }, + {}, +}; +MODULE_DEVICE_TABLE(of, apple_rtkit_helper_of_match); + +static struct platform_driver apple_rtkit_helper_driver = { + .driver = { + .name = "rtkit-helper", + .of_match_table = apple_rtkit_helper_of_match, + }, + .probe = apple_rtkit_helper_probe, + .remove = apple_rtkit_helper_remove, +}; +module_platform_driver(apple_rtkit_helper_driver); + +MODULE_AUTHOR("Hector Martin "); +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("Apple RTKit helper driver"); From fa502bb30c6e3e5467be2bc5163baaa008f67f6c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 2 Nov 2025 13:17:35 +0100 Subject: [PATCH 335/352] media: videobuf2: Set vma_flags in vb2_dma_sg_mmap vb2_dma_contig sets VMA flags VM_DONTEXPAND and VM_DONTDUMP and I do not see a reason why vb2_dma_sg should behave differently. This avoids hitting `WARN_ON(!(vma->vm_flags & VM_DONTEXPAND));` in drm_gem_mmap_obj() during mmap() of an imported dma-buf from the out of tree Apple ISP camera capture driver which uses vb2_dma_sg_memops. gst-launch-1.0 v4l2src ! gtk4paintablesink [ 38.201528] ------------[ cut here ]------------ [ 38.202135] WARNING: CPU: 7 PID: 2362 at drivers/gpu/drm/drm_gem.c:1144 drm_gem_mmap_obj+0x1f8/0x210 [ 38.203278] Modules linked in: rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device uinput nf_conntrack_netbios_ns nf_conntrack_broadcast nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables qrtr bnep nls_ascii i2c_dev loop fuse dm_multipath nfnetlink brcmfmac_wcc hid_magicmouse hci_bcm4377 brcmfmac brcmutil bluetooth ecdh_generic cfg80211 ecc btrfs xor xor_neon rfkill hid_apple raid6_pq joydev aop_als apple_nvmem_spmi industrialio snd_soc_aop apple_z2 snd_soc_cs42l84 tps6598x snd_soc_tas2764 macsmc_reboot spi_nor macsmc_hwmon rtc_macsmc gpio_macsmc macsmc_power regmap_spmi macsmc_input dockchannel_hid panel_summit appledrm nvme_apple dwc3 snd_soc_macaudio drm_client_lib nvme_core phy_apple_atc hwmon apple_sart apple_dockchannel macsmc apple_rtkit_helper spmi_apple_controller aop apple_wdt mfd_core nvmem_apple_efuses pinctrl_apple_gpio apple_isp apple_dcp videobuf2_dma_sg mux_core spi_apple [ 38.203300] videobuf2_memops i2c_pasemi_platform snd_soc_apple_mca videobuf2_v4l2 videodev clk_apple_nco videobuf2_common snd_pcm_dmaengine adpdrm asahi apple_admac adpdrm_mipi drm_dma_helper pwm_apple i2c_pasemi_core drm_display_helper mc cec apple_dart ofpart apple_soc_cpufreq leds_pwm phram [ 38.217677] CPU: 7 UID: 1000 PID: 2362 Comm: gst-launch-1.0 Tainted: G W 6.17.6+ #asahi-dev PREEMPT(full) [ 38.219040] Tainted: [W]=WARN [ 38.219398] Hardware name: Apple MacBook Pro (13-inch, M2, 2022) (DT) [ 38.220213] pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) [ 38.221088] pc : drm_gem_mmap_obj+0x1f8/0x210 [ 38.221643] lr : drm_gem_mmap_obj+0x78/0x210 [ 38.222178] sp : ffffc0008dc678e0 [ 38.222579] x29: ffffc0008dc678e0 x28: 0000000000042a97 x27: ffff8000b701b480 [ 38.223465] x26: 00000000000000fb x25: ffffc0008dc67d20 x24: ffffc0008dc67968 [ 38.224402] x23: ffff8000e3ca5600 x22: ffff8000265b7800 x21: ffff80003000c0c0 [ 38.225279] x20: 0000000000000000 x19: ffff8000b68c5200 x18: ffffc0008dc67968 [ 38.226151] x17: 0000000000000000 x16: 0000000000000000 x15: ffffc000810a30a8 [ 38.227042] x14: 00007fff637effff x13: 00005555de91ffff x12: 00007fff63293fff [ 38.227942] x11: 0000000000000000 x10: ffff8000184ecf08 x9 : ffffc0007a1900c8 [ 38.228824] x8 : ffffc0008dc67968 x7 : 0000000000000012 x6 : ffffc0015cf1c000 [ 38.229703] x5 : ffffc0008dc676a0 x4 : ffffc00081a27dc0 x3 : 0000000000000038 [ 38.230607] x2 : 0000000000000003 x1 : 0000000000000003 x0 : 00000000100000fb [ 38.231488] Call trace: [ 38.231806] drm_gem_mmap_obj+0x1f8/0x210 (P) [ 38.232342] drm_gem_mmap+0x140/0x260 [ 38.232813] __mmap_region+0x488/0x9a0 [ 38.233277] mmap_region+0xd0/0x148 [ 38.233703] do_mmap+0x350/0x5c0 [ 38.234148] vm_mmap_pgoff+0x14c/0x200 [ 38.234612] ksys_mmap_pgoff+0x150/0x208 [ 38.235107] __arm64_sys_mmap+0x34/0x50 [ 38.235611] invoke_syscall+0x50/0x120 [ 38.236075] el0_svc_common.constprop.0+0x48/0xf0 [ 38.236680] do_el0_svc+0x24/0x38 [ 38.237113] el0_svc+0x38/0x168 [ 38.237507] el0t_64_sync_handler+0xa0/0xe8 [ 38.238034] el0t_64_sync+0x198/0x1a0 [ 38.238491] ---[ end trace 0000000000000000 ]--- There were discussions in [1] at the end of 2023 that mmap() on imported dma-bufs should not be supported but as of v6.17 drm_gem_shmem_mmap() in drm_gem_shmem_helper.c still supports it. This might affect all gpu or accel drivers using drm_gem_shmem_mmap() or the wrapper drm_gem_shmem_object_mmap(). 1: https://lore.kernel.org/dri-devel/bc7f7844-0aa3-4802-b203-69d58e8be2fa@linux.intel.com/ Cc: stable@vger.kernel.org Fixes: 5ba3f757f059 ("[media] v4l: videobuf2: add DMA scatter/gather allocator") Signed-off-by: Janne Grunau --- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 982021d547e53b..b1d0695cda2604 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -345,6 +345,7 @@ static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma) return err; } + vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); /* * Use common vm_area operations to track buffer refcount. */ From 971e4cf61a597c2af5c9eb6fb12f99cfb1d2b838 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 28 Aug 2025 12:19:02 +0200 Subject: [PATCH 336/352] watchdog: apple: Add "apple,t8103-wdt" compatible After discussion with the devicetree maintainers we agreed to not extend lists with the generic compatible "apple,wdt" anymore [1]. Use "apple,t8103-wdt" as base compatible as it is the SoC the driver and bindings were written for. [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf@kernel.org/ Reviewed-by: Neal Gompa Signed-off-by: Janne Grunau --- drivers/watchdog/apple_wdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c index 66a158f67a712b..6b9b0f9b05cedf 100644 --- a/drivers/watchdog/apple_wdt.c +++ b/drivers/watchdog/apple_wdt.c @@ -218,6 +218,7 @@ static int apple_wdt_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(apple_wdt_pm_ops, apple_wdt_suspend, apple_wdt_resume); static const struct of_device_id apple_wdt_of_match[] = { + { .compatible = "apple,t8103-wdt" }, { .compatible = "apple,wdt" }, {}, }; From a4545b6962758a603955381a6d87b8c1590ac43f Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 31 Aug 2025 21:00:49 +0200 Subject: [PATCH 337/352] nvmem: core: Fix OOB read for bit offsets of more than one byte When the bit offset is BITS_PER_BYTE or larger the read postion is advanced by `bytes_offset`. This is not taken into account in the per-byte read loop which still reads `cell->bytes` resuling in an out of bounds read of `bytes_offset` bytes. The information read OOB does not leak directly as the erroneously read bits are cleared. Detected by KASAN while looking for a use-after-free in simplefb.c. Fixes: 7a06ef7510779 ("nvmem: core: fix bit offsets of more than one byte") Signed-off-by: Janne Grunau --- drivers/nvmem/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 311cb2e5a5c02d..877b867d4080a9 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1615,12 +1615,14 @@ static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *p = *b++ >> bit_offset; /* setup rest of the bytes if any */ - for (i = 1; i < cell->bytes; i++) { + for (i = 1; i < (cell->bytes - bytes_offset); i++) { /* Get bits from next byte and shift them towards msb */ *p++ |= *b << (BITS_PER_BYTE - bit_offset); *p = *b++ >> bit_offset; } + /* point to end of the buffer unused bits will be cleared */ + p = buf + cell->bytes - 1; } else if (p != b) { memmove(p, b, cell->bytes - bytes_offset); p += cell->bytes - 1; From 61097a9c0a182f448be2f42c3e185ca8b8f48418 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 12 Oct 2025 14:45:11 +0200 Subject: [PATCH 338/352] bus: simple-pm-bus: Add "apple,*-pmgr" compatibles These devices are since commit 26769582bf35 ("mfd: syscon: Remove the platform driver support") without driver. There was not device specific code in the syscon driver so its removal did not cause any functional regressions. All control is done in child devices using syscon regmap. These devices use "simple-mfd" as fourth compatible. simple-pm-bus claims devices only based on the first compatible string so add all primary SoC specific apple,pmgr comaptibles. Cc: stable@vger.kernel.org Fixes: 26769582bf35 ("mfd: syscon: Remove the platform driver support") Signed-off-by: Janne Grunau --- drivers/bus/simple-pm-bus.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c index c920bd6fbaafd4..6d351ca51aa4e6 100644 --- a/drivers/bus/simple-pm-bus.c +++ b/drivers/bus/simple-pm-bus.c @@ -142,6 +142,15 @@ static const struct of_device_id simple_pm_bus_of_match[] = { { .compatible = "simple-mfd", .data = ONLY_BUS }, { .compatible = "isa", .data = ONLY_BUS }, { .compatible = "arm,amba-bus", .data = ONLY_BUS }, + { .compatible = "apple,s5l8960x-pmgr", .data = ONLY_BUS }, + { .compatible = "apple,t7000-pmgr", .data = ONLY_BUS }, + { .compatible = "apple,s8000-pmgr", .data = ONLY_BUS }, + { .compatible = "apple,t8010-pmgr", .data = ONLY_BUS }, + { .compatible = "apple,t8015-pmgr", .data = ONLY_BUS }, + { .compatible = "apple,t8103-pmgr", .data = ONLY_BUS }, + { .compatible = "apple,t8112-pmgr", .data = ONLY_BUS }, + { .compatible = "apple,t6000-pmgr", .data = ONLY_BUS }, + { .compatible = "apple,t6020-pmgr", .data = ONLY_BUS },\ { .compatible = "fsl,ls1021a-scfg", }, { .compatible = "fsl,ls1043a-scfg", }, { .compatible = "fsl,ls1046a-scfg", }, From bd8e7fa49e0d5ad013b1089ee5305074823b1382 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 5 May 2023 17:40:26 +0200 Subject: [PATCH 339/352] phy: apple: Add DP TX phy driver This driver is found on Apple's Mac mini (M2, 2023) and controls one output of the main display controller. It is connected to a MCDP 29XX (public known part is MCDP 2900) DP 1.4 to HDMI 2.0a protocol converter. Signed-off-by: Janne Grunau --- drivers/phy/apple/Kconfig | 10 + drivers/phy/apple/Makefile | 3 + drivers/phy/apple/dptx.c | 690 +++++++++++++++++++++++++++++++++++++ drivers/phy/apple/dptx.h | 18 + 4 files changed, 721 insertions(+) create mode 100644 drivers/phy/apple/dptx.c create mode 100644 drivers/phy/apple/dptx.h diff --git a/drivers/phy/apple/Kconfig b/drivers/phy/apple/Kconfig index d82d6f291a7537..8409b67f6d1ecb 100644 --- a/drivers/phy/apple/Kconfig +++ b/drivers/phy/apple/Kconfig @@ -11,3 +11,13 @@ config PHY_APPLE_ATC USB3, USB4, Thunderbolt, and DisplayPort. If M is selected the module will be called 'phy-apple-atc'. + +config PHY_APPLE_DPTX + tristate "Apple DPTX PHY" + depends on ARCH_APPLE || COMPILE_TEST + select GENERIC_PHY + help + Enable this to add support for the Apple DPTX PHY found on Apple SoCs + such as the M2. + This driver provides support for DisplayPort and is used on the + Mac mini (M2 and M2 Pro, 2023). diff --git a/drivers/phy/apple/Makefile b/drivers/phy/apple/Makefile index e02836a63df3b5..b9e7bf3e4ac170 100644 --- a/drivers/phy/apple/Makefile +++ b/drivers/phy/apple/Makefile @@ -2,3 +2,6 @@ obj-$(CONFIG_PHY_APPLE_ATC) += phy-apple-atc.o phy-apple-atc-y := atc.o + +obj-$(CONFIG_PHY_APPLE_DPTX) += phy-apple-dptx.o +phy-apple-dptx-y += dptx.o diff --git a/drivers/phy/apple/dptx.c b/drivers/phy/apple/dptx.c new file mode 100644 index 00000000000000..f0df2d40a18023 --- /dev/null +++ b/drivers/phy/apple/dptx.c @@ -0,0 +1,690 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Apple dptx PHY driver + * + * Copyright (C) The Asahi Linux Contributors + * Author: Janne Grunau + * + * based on drivers/phy/apple/atc.c + * + * Copyright (C) The Asahi Linux Contributors + * Author: Sven Peter + */ + +#include "dptx.h" + +#include +#include "linux/of.h" +#include +#include +#include +#include +#include +#include +#include + +#define DPTX_MAX_LANES 4 +#define DPTX_LANE0_OFFSET 0x5000 +#define DPTX_LANE_STRIDE 0x1000 +#define DPTX_LANE_END (DPTX_LANE0_OFFSET + DPTX_MAX_LANES * DPTX_LANE_STRIDE) + +enum apple_dptx_type { + DPTX_PHY_T8112, + DPTX_PHY_T6020, +}; + +struct apple_dptx_phy_hw { + enum apple_dptx_type type; +}; + +struct apple_dptx_phy { + struct device *dev; + + struct apple_dptx_phy_hw hw; + + int dp_link_rate; + + struct { + void __iomem *core; + void __iomem *dptx; + } regs; + + struct phy *phy_dp; + struct phy_provider *phy_provider; + + struct mutex lock; + + // TODO: m1n1 port things to clean up + u32 active_lanes; +}; + + +static inline void mask32(void __iomem *reg, u32 mask, u32 set) +{ + u32 value = readl(reg); + value &= ~mask; + value |= set; + writel(value, reg); +} + +static inline void set32(void __iomem *reg, u32 set) +{ + mask32(reg, 0, set); +} + +static inline void clear32(void __iomem *reg, u32 clear) +{ + mask32(reg, clear, 0); +} + + +static int dptx_phy_set_active_lane_count(struct apple_dptx_phy *phy, u32 num_lanes) +{ + u32 l, ctrl; + + dev_dbg(phy->dev, "set_active_lane_count(%u)\n", num_lanes); + + if (num_lanes == 3 || num_lanes > DPTX_MAX_LANES) + return -1; + + ctrl = readl(phy->regs.dptx + 0x4000); + writel(ctrl, phy->regs.dptx + 0x4000); + + for (l = 0; l < num_lanes; l++) { + u64 offset = 0x5000 + 0x1000 * l; + readl(phy->regs.dptx + offset); + writel(0x100, phy->regs.dptx + offset); + } + for (; l < DPTX_MAX_LANES; l++) { + u64 offset = 0x5000 + 0x1000 * l; + readl(phy->regs.dptx + offset); + writel(0x300, phy->regs.dptx + offset); + } + for (l = 0; l < num_lanes; l++) { + u64 offset = 0x5000 + 0x1000 * l; + readl(phy->regs.dptx + offset); + writel(0x0, phy->regs.dptx + offset); + } + for (; l < DPTX_MAX_LANES; l++) { + u64 offset = 0x5000 + 0x1000 * l; + readl(phy->regs.dptx + offset); + writel(0x300, phy->regs.dptx + offset); + } + + if (num_lanes > 0) { + // clear32(phy->regs.dptx + 0x4000, 0x4000000); + ctrl = readl(phy->regs.dptx + 0x4000); + ctrl &= ~0x4000000; + writel(ctrl, phy->regs.dptx + 0x4000); + } + phy->active_lanes = num_lanes; + + return 0; +} + +static int dptx_phy_activate(struct apple_dptx_phy *phy, u32 dcp_index) +{ + u32 val_2014; + u32 val_4008; + u32 val_4408; + + dev_dbg(phy->dev, "activate(dcp:%u)\n", dcp_index); + + // MMIO: R.4 0x23c500010 (dptx-phy[1], offset 0x10) = 0x0 + // MMIO: W.4 0x23c500010 (dptx-phy[1], offset 0x10) = 0x0 + readl(phy->regs.core + 0x10); + writel(dcp_index, phy->regs.core + 0x10); + + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x444 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x454 + set32(phy->regs.core + 0x48, 0x010); + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x454 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x474 + set32(phy->regs.core + 0x48, 0x020); + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x474 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x434 + clear32(phy->regs.core + 0x48, 0x040); + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x434 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x534 + set32(phy->regs.core + 0x48, 0x100); + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x534 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x734 + set32(phy->regs.core + 0x48, 0x200); + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x734 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x334 + clear32(phy->regs.core + 0x48, 0x400); + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x334 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x335 + set32(phy->regs.core + 0x48, 0x001); + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x335 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x337 + set32(phy->regs.core + 0x48, 0x002); + // MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x337 + // MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x333 + clear32(phy->regs.core + 0x48, 0x004); + + // MMIO: R.4 0x23c542014 (dptx-phy[0], offset 0x2014) = 0x80a0c + val_2014 = readl(phy->regs.dptx + 0x2014); + // MMIO: W.4 0x23c542014 (dptx-phy[0], offset 0x2014) = 0x300a0c + writel((0x30 << 16) | (val_2014 & 0xffff), phy->regs.dptx + 0x2014); + + // MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x644800 + // MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800 + set32(phy->regs.dptx + 0x20b8, 0x010000); + + // MMIO: R.4 0x23c542220 (dptx-phy[0], offset 0x2220) = 0x11090a2 + // MMIO: W.4 0x23c542220 (dptx-phy[0], offset 0x2220) = 0x11090a0 + clear32(phy->regs.dptx + 0x2220, 0x0000002); + + // MMIO: R.4 0x23c54222c (dptx-phy[0], offset 0x222c) = 0x103003 + // MMIO: W.4 0x23c54222c (dptx-phy[0], offset 0x222c) = 0x103803 + set32(phy->regs.dptx + 0x222c, 0x000800); + // MMIO: R.4 0x23c54222c (dptx-phy[0], offset 0x222c) = 0x103803 + // MMIO: W.4 0x23c54222c (dptx-phy[0], offset 0x222c) = 0x103903 + set32(phy->regs.dptx + 0x222c, 0x000100); + + // MMIO: R.4 0x23c542230 (dptx-phy[0], offset 0x2230) = 0x2308804 + // MMIO: W.4 0x23c542230 (dptx-phy[0], offset 0x2230) = 0x2208804 + clear32(phy->regs.dptx + 0x2230, 0x0100000); + + // MMIO: R.4 0x23c542278 (dptx-phy[0], offset 0x2278) = 0x18300811 + // MMIO: W.4 0x23c542278 (dptx-phy[0], offset 0x2278) = 0x10300811 + clear32(phy->regs.dptx + 0x2278, 0x08000000); + + // MMIO: R.4 0x23c5422a4 (dptx-phy[0], offset 0x22a4) = 0x1044200 + // MMIO: W.4 0x23c5422a4 (dptx-phy[0], offset 0x22a4) = 0x1044201 + set32(phy->regs.dptx + 0x22a4, 0x0000001); + + // MMIO: R.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x18030 + val_4008 = readl(phy->regs.dptx + 0x4008); + // MMIO: W.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x30030 + writel((0x6 << 15) | (val_4008 & 0x7fff), phy->regs.dptx + 0x4008); + // MMIO: R.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x30030 + // MMIO: W.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x30010 + clear32(phy->regs.dptx + 0x4008, 0x00020); + + // MMIO: R.4 0x23c54420c (dptx-phy[0], offset 0x420c) = 0x88e3 + // MMIO: W.4 0x23c54420c (dptx-phy[0], offset 0x420c) = 0x88c3 + clear32(phy->regs.dptx + 0x420c, 0x0020); + + // MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x0 + // MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000000 + set32(phy->regs.dptx + 0x4600, 0x8000000); + + // MMIO: R.4 0x23c545040 (dptx-phy[0], offset 0x5040) = 0x21780 + // MMIO: W.4 0x23c545040 (dptx-phy[0], offset 0x5040) = 0x221780 + // MMIO: R.4 0x23c546040 (dptx-phy[0], offset 0x6040) = 0x21780 + // MMIO: W.4 0x23c546040 (dptx-phy[0], offset 0x6040) = 0x221780 + // MMIO: R.4 0x23c547040 (dptx-phy[0], offset 0x7040) = 0x21780 + // MMIO: W.4 0x23c547040 (dptx-phy[0], offset 0x7040) = 0x221780 + // MMIO: R.4 0x23c548040 (dptx-phy[0], offset 0x8040) = 0x21780 + // MMIO: W.4 0x23c548040 (dptx-phy[0], offset 0x8040) = 0x221780 + for (u32 loff = DPTX_LANE0_OFFSET; loff < DPTX_LANE_END; + loff += DPTX_LANE_STRIDE) + set32(phy->regs.dptx + loff + 0x40, 0x200000); + + // MMIO: R.4 0x23c545040 (dptx-phy[0], offset 0x5040) = 0x221780 + // MMIO: W.4 0x23c545040 (dptx-phy[0], offset 0x5040) = 0x2a1780 + // MMIO: R.4 0x23c546040 (dptx-phy[0], offset 0x6040) = 0x221780 + // MMIO: W.4 0x23c546040 (dptx-phy[0], offset 0x6040) = 0x2a1780 + // MMIO: R.4 0x23c547040 (dptx-phy[0], offset 0x7040) = 0x221780 + // MMIO: W.4 0x23c547040 (dptx-phy[0], offset 0x7040) = 0x2a1780 + // MMIO: R.4 0x23c548040 (dptx-phy[0], offset 0x8040) = 0x221780 + // MMIO: W.4 0x23c548040 (dptx-phy[0], offset 0x8040) = 0x2a1780 + for (u32 loff = DPTX_LANE0_OFFSET; loff < DPTX_LANE_END; + loff += DPTX_LANE_STRIDE) + set32(phy->regs.dptx + loff + 0x40, 0x080000); + + // MMIO: R.4 0x23c545244 (dptx-phy[0], offset 0x5244) = 0x18 + // MMIO: W.4 0x23c545244 (dptx-phy[0], offset 0x5244) = 0x8 + // MMIO: R.4 0x23c546244 (dptx-phy[0], offset 0x6244) = 0x18 + // MMIO: W.4 0x23c546244 (dptx-phy[0], offset 0x6244) = 0x8 + // MMIO: R.4 0x23c547244 (dptx-phy[0], offset 0x7244) = 0x18 + // MMIO: W.4 0x23c547244 (dptx-phy[0], offset 0x7244) = 0x8 + // MMIO: R.4 0x23c548244 (dptx-phy[0], offset 0x8244) = 0x18 + // MMIO: W.4 0x23c548244 (dptx-phy[0], offset 0x8244) = 0x8 + for (u32 loff = DPTX_LANE0_OFFSET; loff < DPTX_LANE_END; + loff += DPTX_LANE_STRIDE) + clear32(phy->regs.dptx + loff + 0x244, 0x10); + + // MMIO: R.4 0x23c542214 (dptx-phy[0], offset 0x2214) = 0x1e0 + // MMIO: W.4 0x23c542214 (dptx-phy[0], offset 0x2214) = 0x1e1 + set32(phy->regs.dptx + 0x2214, 0x001); + + // MMIO: R.4 0x23c542224 (dptx-phy[0], offset 0x2224) = 0x20086001 + // MMIO: W.4 0x23c542224 (dptx-phy[0], offset 0x2224) = 0x20086000 + clear32(phy->regs.dptx + 0x2224, 0x00000001); + + // MMIO: R.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2000 + // MMIO: W.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2002 + set32(phy->regs.dptx + 0x2200, 0x0002); + + // MMIO: R.4 0x23c541000 (dptx-phy[0], offset 0x1000) = 0xe0000003 + // MMIO: W.4 0x23c541000 (dptx-phy[0], offset 0x1000) = 0xe0000001 + clear32(phy->regs.dptx + 0x1000, 0x00000002); + + // MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x41 + // MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49 + set32(phy->regs.dptx + 0x4004, 0x08); + + /* TODO: no idea what happens here, supposedly setting/clearing some bits */ + // MMIO: R.4 0x23c544404 (dptx-phy[0], offset 0x4404) = 0x555d444 + readl(phy->regs.dptx + 0x4404); + // MMIO: W.4 0x23c544404 (dptx-phy[0], offset 0x4404) = 0x555d444 + writel(0x555d444, phy->regs.dptx + 0x4404); + // MMIO: R.4 0x23c544404 (dptx-phy[0], offset 0x4404) = 0x555d444 + readl(phy->regs.dptx + 0x4404); + // MMIO: W.4 0x23c544404 (dptx-phy[0], offset 0x4404) = 0x555d444 + writel(0x555d444, phy->regs.dptx + 0x4404); + + dptx_phy_set_active_lane_count(phy, 0); + + // MMIO: R.4 0x23c544200 (dptx-phy[0], offset 0x4200) = 0x4002430 + // MMIO: W.4 0x23c544200 (dptx-phy[0], offset 0x4200) = 0x4002420 + clear32(phy->regs.dptx + 0x4200, 0x0000010); + + // MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000000 + // MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000000 + clear32(phy->regs.dptx + 0x4600, 0x0000001); + // MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000000 + // MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000001 + set32(phy->regs.dptx + 0x4600, 0x0000001); + // MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000001 + // MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000003 + set32(phy->regs.dptx + 0x4600, 0x0000002); + // MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000043 + // MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000043 + // MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000041 + /* TODO: read first to check if the previous set(...,0x2) sticked? */ + readl(phy->regs.dptx + 0x4600); + clear32(phy->regs.dptx + 0x4600, 0x0000001); + + // MMIO: R.4 0x23c544408 (dptx-phy[0], offset 0x4408) = 0x482 + // MMIO: W.4 0x23c544408 (dptx-phy[0], offset 0x4408) = 0x482 + /* TODO: probably a set32 of an already set bit */ + val_4408 = readl(phy->regs.dptx + 0x4408); + if (val_4408 != 0x482 && val_4408 != 0x483) + dev_warn( + phy->dev, + "unexpected initial value at regs.dptx offset 0x4408: 0x%03x\n", + val_4408); + writel(val_4408, phy->regs.dptx + 0x4408); + // MMIO: R.4 0x23c544408 (dptx-phy[0], offset 0x4408) = 0x482 + // MMIO: W.4 0x23c544408 (dptx-phy[0], offset 0x4408) = 0x483 + set32(phy->regs.dptx + 0x4408, 0x001); + + return 0; +} + +static int dptx_phy_deactivate(struct apple_dptx_phy *phy) +{ + return 0; +} + +static int dptx_phy_set_link_rate(struct apple_dptx_phy *phy, u32 link_rate) +{ + u32 sts_1008, sts_1014, val_100c, val_20b0, val_20b4; + + dev_dbg(phy->dev, "set_link_rate(%u)\n", link_rate); + + // MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49 + // MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49 + set32(phy->regs.dptx + 0x4004, 0x08); + + // MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac + // MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac + clear32(phy->regs.dptx + 0x4000, 0x0000040); + + // MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49 + // MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x41 + clear32(phy->regs.dptx + 0x4004, 0x08); + + // MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac + // MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac + clear32(phy->regs.dptx + 0x4000, 0x2000000); + // MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac + // MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac + set32(phy->regs.dptx + 0x4000, 0x1000000); + + // MMIO: R.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2002 + // MMIO: R.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2002 + // MMIO: W.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2000 + /* TODO: what is this read checking for? */ + readl(phy->regs.dptx + 0x2200); + clear32(phy->regs.dptx + 0x2200, 0x0002); + + // MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000 + // MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000 + // MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000 + // MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf008 + /* TODO: what is the setting/clearing? */ + val_100c = readl(phy->regs.dptx + 0x100c); + writel(val_100c, phy->regs.dptx + 0x100c); + set32(phy->regs.dptx + 0x100c, 0x0008); + + // MMIO: R.4 0x23c541014 (dptx-phy[0], offset 0x1014) = 0x1 + sts_1014 = readl(phy->regs.dptx + 0x1014); + if (sts_1014 != 0x1) + dev_dbg(phy->dev, "unexpected?: dptx[0x1014]: %02x\n", sts_1014); + + // MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf008 + // MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000 + clear32(phy->regs.dptx + 0x100c, 0x0008); + + // MMIO: R.4 0x23c541008 (dptx-phy[0], offset 0x1008) = 0x1 + sts_1008 = readl(phy->regs.dptx + 0x1008); + if (sts_1008 != 0x1) + dev_dbg(phy->dev, "unexpected?: dptx[0x1008]: %02x\n", sts_1008); + + // MMIO: R.4 0x23c542220 (dptx-phy[0], offset 0x2220) = 0x11090a0 + // MMIO: W.4 0x23c542220 (dptx-phy[0], offset 0x2220) = 0x1109020 + clear32(phy->regs.dptx + 0x2220, 0x0000080); + + // MMIO: R.4 0x23c5420b0 (dptx-phy[0], offset 0x20b0) = 0x1e0e01c2 + // MMIO: W.4 0x23c5420b0 (dptx-phy[0], offset 0x20b0) = 0x1e0e01c2 + val_20b0 = readl(phy->regs.dptx + 0x20b0); + /* TODO: what happens on dptx-phy */ + if (phy->hw.type == DPTX_PHY_T6020) + val_20b0 = (val_20b0 & ~0x3ff) | 0x2a3; + writel(val_20b0, phy->regs.dptx + 0x20b0); + + // MMIO: R.4 0x23c5420b4 (dptx-phy[0], offset 0x20b4) = 0x7fffffe + // MMIO: W.4 0x23c5420b4 (dptx-phy[0], offset 0x20b4) = 0x7fffffe + val_20b4 = readl(phy->regs.dptx + 0x20b4); + /* TODO: what happens on dptx-phy */ + if (phy->hw.type == DPTX_PHY_T6020) + val_20b4 = (val_20b4 | 0x4000000) & ~0x0008000; + writel(val_20b4, phy->regs.dptx + 0x20b4); + + // MMIO: R.4 0x23c5420b4 (dptx-phy[0], offset 0x20b4) = 0x7fffffe + // MMIO: W.4 0x23c5420b4 (dptx-phy[0], offset 0x20b4) = 0x7fffffe + val_20b4 = readl(phy->regs.dptx + 0x20b4); + /* TODO: what happens on dptx-phy */ + if (phy->hw.type == DPTX_PHY_T6020) + val_20b4 = (val_20b4 | 0x0000001) & ~0x0000004; + writel(val_20b4, phy->regs.dptx + 0x20b4); + + // MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800 + // MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800 + /* TODO: unclear */ + set32(phy->regs.dptx + 0x20b8, 0); + // MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800 + // MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800 + /* TODO: unclear */ + set32(phy->regs.dptx + 0x20b8, 0); + // MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800 + // MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800 + /* TODO: unclear */ + if (phy->hw.type == DPTX_PHY_T6020) + set32(phy->regs.dptx + 0x20b8, 0x010000); + else + set32(phy->regs.dptx + 0x20b8, 0); + // MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800 + // MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x454800 + clear32(phy->regs.dptx + 0x20b8, 0x200000); + + // MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x454800 + // MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x454800 + /* TODO: unclear */ + set32(phy->regs.dptx + 0x20b8, 0); + + // MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x0 + // MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8 + // MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8 + // MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc + // MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc + // MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x4000c + // MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x4000c + // MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc + // MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc + // MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8000c + // MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8000c + // MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc + // MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc + // MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8 + // MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8 + // MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x0 + set32(phy->regs.core + 0xa0, 0x8); + set32(phy->regs.core + 0xa0, 0x4); + set32(phy->regs.core + 0xa0, 0x40000); + clear32(phy->regs.core + 0xa0, 0x40000); + set32(phy->regs.core + 0xa0, 0x80000); + clear32(phy->regs.core + 0xa0, 0x80000); + clear32(phy->regs.core + 0xa0, 0x4); + clear32(phy->regs.core + 0xa0, 0x8); + + // MMIO: R.4 0x23c542000 (dptx-phy[0], offset 0x2000) = 0x2 + // MMIO: W.4 0x23c542000 (dptx-phy[0], offset 0x2000) = 0x2 + /* TODO: unclear */ + set32(phy->regs.dptx + 0x2000, 0x0); + + // MMIO: R.4 0x23c542018 (dptx-phy[0], offset 0x2018) = 0x0 + // MMIO: W.4 0x23c542018 (dptx-phy[0], offset 0x2018) = 0x0 + clear32(phy->regs.dptx + 0x2018, 0x0); + + // MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000 + // MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf007 + set32(phy->regs.dptx + 0x100c, 0x0007); + // MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf007 + // MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf00f + set32(phy->regs.dptx + 0x100c, 0x0008); + + // MMIO: R.4 0x23c541014 (dptx-phy[0], offset 0x1014) = 0x38f + sts_1014 = readl(phy->regs.dptx + 0x1014); + if (sts_1014 != 0x38f) + dev_dbg(phy->dev, "unexpected?: dptx[0x1014]: %02x\n", sts_1014); + + // MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf00f + // MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf007 + clear32(phy->regs.dptx + 0x100c, 0x0008); + + // MMIO: R.4 0x23c541008 (dptx-phy[0], offset 0x1008) = 0x9 + sts_1008 = readl(phy->regs.dptx + 0x1008); + if (sts_1008 != 0x9) + dev_dbg(phy->dev, "unexpected?: dptx[0x1008]: %02x\n", sts_1008); + + // MMIO: R.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2000 + // MMIO: W.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2002 + set32(phy->regs.dptx + 0x2200, 0x0002); + + // MMIO: R.4 0x23c545010 (dptx-phy[0], offset 0x5010) = 0x18003000 + // MMIO: W.4 0x23c545010 (dptx-phy[0], offset 0x5010) = 0x18003000 + // MMIO: R.4 0x23c546010 (dptx-phy[0], offset 0x6010) = 0x18003000 + // MMIO: W.4 0x23c546010 (dptx-phy[0], offset 0x6010) = 0x18003000 + // MMIO: R.4 0x23c547010 (dptx-phy[0], offset 0x7010) = 0x18003000 + // MMIO: W.4 0x23c547010 (dptx-phy[0], offset 0x7010) = 0x18003000 + // MMIO: R.4 0x23c548010 (dptx-phy[0], offset 0x8010) = 0x18003000 + // MMIO: W.4 0x23c548010 (dptx-phy[0], offset 0x8010) = 0x18003000 + writel(0x18003000, phy->regs.dptx + 0x8010); + for (u32 loff = DPTX_LANE0_OFFSET; loff < DPTX_LANE_END; loff += DPTX_LANE_STRIDE) { + u32 val_l010 = readl(phy->regs.dptx + loff + 0x10); + writel(val_l010, phy->regs.dptx + loff + 0x10); + } + + // MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac + // MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x51021ac + set32(phy->regs.dptx + 0x4000, 0x1000000); + // MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x51021ac + // MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x71021ac + set32(phy->regs.dptx + 0x4000, 0x2000000); + + // MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x41 + // MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49 + set32(phy->regs.dptx + 0x4004, 0x08); + + // MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x71021ac + // MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x71021ec + set32(phy->regs.dptx + 0x4000, 0x0000040); + + // MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49 + // MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x48 + clear32(phy->regs.dptx + 0x4004, 0x01); + + return 0; +} + +static int dptx_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct apple_dptx_phy *dptx_phy = phy_get_drvdata(phy); + + switch (mode) { + case PHY_MODE_INVALID: + return dptx_phy_deactivate(dptx_phy); + case PHY_MODE_DP: + if (submode < 0 || submode > 5) + return -EINVAL; + return dptx_phy_activate(dptx_phy, submode); + default: + break; + } + + return -EINVAL; +} + +static int dptx_phy_validate(struct phy *phy, enum phy_mode mode, int submode, + union phy_configure_opts *opts_) +{ + struct phy_configure_opts_dp *opts = &opts_->dp; + + if (mode == PHY_MODE_INVALID) { + memset(opts, 0, sizeof(*opts)); + return 0; + } + + if (mode != PHY_MODE_DP) + return -EINVAL; + if (submode < 0 || submode > 5) + return -EINVAL; + + opts->lanes = 4; + opts->link_rate = 8100; + + for (int i = 0; i < 4; ++i) { + opts->voltage[i] = 3; + opts->pre[i] = 3; + } + + return 0; +} + +static int dptx_phy_configure(struct phy *phy, union phy_configure_opts *opts_) +{ + struct phy_configure_opts_dp *opts = &opts_->dp; + struct apple_dptx_phy *dptx_phy = phy_get_drvdata(phy); + enum dptx_phy_link_rate link_rate; + int ret = 0; + + if (opts->set_lanes) { + mutex_lock(&dptx_phy->lock); + ret = dptx_phy_set_active_lane_count(dptx_phy, opts->lanes); + mutex_unlock(&dptx_phy->lock); + } + + if (opts->set_rate) { + switch (opts->link_rate) { + case 1620: + link_rate = DPTX_PHY_LINK_RATE_RBR; + break; + case 2700: + link_rate = DPTX_PHY_LINK_RATE_HBR; + break; + case 5400: + link_rate = DPTX_PHY_LINK_RATE_HBR2; + break; + case 8100: + link_rate = DPTX_PHY_LINK_RATE_HBR3; + break; + case 0: + // TODO: disable! + return 0; + break; + default: + dev_err(dptx_phy->dev, "Unsupported link rate: %d\n", + opts->link_rate); + return -EINVAL; + } + + mutex_lock(&dptx_phy->lock); + ret = dptx_phy_set_link_rate(dptx_phy, link_rate); + mutex_unlock(&dptx_phy->lock); + } + + return ret; +} + +static const struct phy_ops apple_atc_dp_phy_ops = { + .owner = THIS_MODULE, + .configure = dptx_phy_configure, + .validate = dptx_phy_validate, + .set_mode = dptx_phy_set_mode, +}; + +static int dptx_phy_probe(struct platform_device *pdev) +{ + struct apple_dptx_phy *dptx_phy; + struct device *dev = &pdev->dev; + + dptx_phy = devm_kzalloc(dev, sizeof(*dptx_phy), GFP_KERNEL); + if (!dptx_phy) + return -ENOMEM; + + dptx_phy->dev = dev; + dptx_phy->hw = + *(struct apple_dptx_phy_hw *)of_device_get_match_data(dev); + platform_set_drvdata(pdev, dptx_phy); + + mutex_init(&dptx_phy->lock); + + dptx_phy->regs.core = + devm_platform_ioremap_resource_byname(pdev, "core"); + if (IS_ERR(dptx_phy->regs.core)) + return PTR_ERR(dptx_phy->regs.core); + dptx_phy->regs.dptx = + devm_platform_ioremap_resource_byname(pdev, "dptx"); + if (IS_ERR(dptx_phy->regs.dptx)) + return PTR_ERR(dptx_phy->regs.dptx); + + /* create phy */ + dptx_phy->phy_dp = + devm_phy_create(dptx_phy->dev, NULL, &apple_atc_dp_phy_ops); + if (IS_ERR(dptx_phy->phy_dp)) + return PTR_ERR(dptx_phy->phy_dp); + phy_set_drvdata(dptx_phy->phy_dp, dptx_phy); + + dptx_phy->phy_provider = + devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(dptx_phy->phy_provider)) + return PTR_ERR(dptx_phy->phy_provider); + + return 0; +} + +static const struct apple_dptx_phy_hw apple_dptx_hw_t6020 = { + .type = DPTX_PHY_T6020, +}; + +static const struct apple_dptx_phy_hw apple_dptx_hw_t8112 = { + .type = DPTX_PHY_T8112, +}; + +static const struct of_device_id dptx_phy_match[] = { + { .compatible = "apple,t6020-dptx-phy", .data = &apple_dptx_hw_t6020 }, + { .compatible = "apple,t8112-dptx-phy", .data = &apple_dptx_hw_t8112 }, + {}, +}; +MODULE_DEVICE_TABLE(of, dptx_phy_match); + +static struct platform_driver dptx_phy_driver = { + .driver = { + .name = "phy-apple-dptx", + .of_match_table = dptx_phy_match, + }, + .probe = dptx_phy_probe, +}; + +module_platform_driver(dptx_phy_driver); + +MODULE_AUTHOR("Janne Grunau "); +MODULE_DESCRIPTION("Apple DP TX PHY driver"); + +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/apple/dptx.h b/drivers/phy/apple/dptx.h new file mode 100644 index 00000000000000..2dd36d753eb357 --- /dev/null +++ b/drivers/phy/apple/dptx.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Apple DP TX PHY driver + * + * Copyright (C) The Asahi Linux Contributors + * Author: Janne Grunau + */ + +#ifndef PHY_APPLE_DPTX_H +#define PHY_APPLE_DPTX_H + +enum dptx_phy_link_rate { + DPTX_PHY_LINK_RATE_RBR, + DPTX_PHY_LINK_RATE_HBR, + DPTX_PHY_LINK_RATE_HBR2, + DPTX_PHY_LINK_RATE_HBR3, +}; +#endif /* PHY_APPLE_DPTX_H */ From 5e690a02708dc184161e00dcfe2623f4ec44a061 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Tue, 7 Apr 2026 13:33:46 +0200 Subject: [PATCH 340/352] Bluetooth: Add Broadcom channel priority commands Certain Broadcom bluetooth chips (bcm4377/bcm4378/bcm438) need ACL streams carrying audio to be set as "high priority" using a vendor specific command to prevent 10-ish second-long dropouts whenever something does a device scan. This patch sends the command when the socket priority is set to TC_PRIO_INTERACTIVE, as BlueZ does for audio. Signed-off-by: Sasha Finkelstein --- MAINTAINERS | 2 ++ drivers/bluetooth/hci_bcm4377.c | 2 ++ include/net/bluetooth/bluetooth.h | 4 ++++ include/net/bluetooth/hci_core.h | 11 +++++++++++ net/bluetooth/Kconfig | 7 +++++++ net/bluetooth/Makefile | 1 + net/bluetooth/brcm.c | 29 +++++++++++++++++++++++++++++ net/bluetooth/brcm.h | 17 +++++++++++++++++ net/bluetooth/hci_conn.c | 27 +++++++++++++++++++++++++++ net/bluetooth/l2cap_sock.c | 13 +++++++++++++ 10 files changed, 113 insertions(+) create mode 100644 net/bluetooth/brcm.c create mode 100644 net/bluetooth/brcm.h diff --git a/MAINTAINERS b/MAINTAINERS index f16f609d68c187..eefdd8a1579ac1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2575,6 +2575,8 @@ F: include/dt-bindings/pinctrl/apple.h F: include/linux/mfd/macsmc.h F: include/linux/soc/apple/* F: include/uapi/drm/asahi_drm.h +F: net/bluetooth/brcm.c +F: net/bluetooth/brcm.h ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c index 925d0a6359453e..5f79920c030681 100644 --- a/drivers/bluetooth/hci_bcm4377.c +++ b/drivers/bluetooth/hci_bcm4377.c @@ -2397,6 +2397,8 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (bcm4377->hw->broken_le_ext_adv_report_phy) hci_set_quirk(hdev, HCI_QUIRK_FIXUP_LE_EXT_ADV_REPORT_PHY); + hci_set_brcm_capable(hdev); + pci_set_drvdata(pdev, bcm4377); hci_set_drvdata(hdev, bcm4377); SET_HCIDEV_DEV(hdev, &pdev->dev); diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 69eed69f7f2656..07a250673950ef 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -457,6 +457,7 @@ struct l2cap_ctrl { }; struct hci_dev; +struct hci_conn; typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode); typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status, @@ -469,6 +470,9 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status, int hci_ethtool_ts_info(unsigned int index, int sk_proto, struct kernel_ethtool_ts_info *ts_info); +int hci_conn_setsockopt(struct hci_conn *conn, struct sock *sk, int level, + int optname, sockptr_t optval, unsigned int optlen); + #define HCI_REQ_START BIT(0) #define HCI_REQ_SKB BIT(1) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a7bffb908c1ec9..947e7c2b08dd81 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -642,6 +642,10 @@ struct hci_dev { bool aosp_quality_report; #endif +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + bool brcm_capable; +#endif + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); @@ -1791,6 +1795,13 @@ static inline void hci_set_aosp_capable(struct hci_dev *hdev) #endif } +static inline void hci_set_brcm_capable(struct hci_dev *hdev) +{ +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + hdev->brcm_capable = true; +#endif +} + static inline void hci_devcd_setup(struct hci_dev *hdev) { #ifdef CONFIG_DEV_COREDUMP diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 6b2b65a667008b..0f2a5fbcafc563 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -110,6 +110,13 @@ config BT_AOSPEXT This options enables support for the Android Open Source Project defined HCI vendor extensions. +config BT_BRCMEXT + bool "Enable Broadcom extensions" + depends on BT + help + This option enables support for the Broadcom defined HCI + vendor extensions. + config BT_DEBUGFS bool "Export Bluetooth internals in debugfs" depends on BT && DEBUG_FS diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index a7eede7616d856..b4c9013a46cec2 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -24,5 +24,6 @@ bluetooth-$(CONFIG_BT_LE) += iso.o bluetooth-$(CONFIG_BT_LEDS) += leds.o bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o +bluetooth-$(CONFIG_BT_BRCMEXT) += brcm.o bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o diff --git a/net/bluetooth/brcm.c b/net/bluetooth/brcm.c new file mode 100644 index 00000000000000..9aa0a265ab3d6b --- /dev/null +++ b/net/bluetooth/brcm.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 The Asahi Linux Contributors + */ + +#include +#include + +#include "brcm.h" + +int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable) +{ + struct sk_buff *skb; + u8 cmd[3]; + + if (!hdev->brcm_capable) + return 0; + + cmd[0] = handle; + cmd[1] = handle >> 8; + cmd[2] = !!enable; + + skb = hci_cmd_sync(hdev, 0xfc57, sizeof(cmd), cmd, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + return 0; +} diff --git a/net/bluetooth/brcm.h b/net/bluetooth/brcm.h new file mode 100644 index 00000000000000..fdaee63bd1d23c --- /dev/null +++ b/net/bluetooth/brcm.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 The Asahi Linux Contributors + */ + +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + +int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable); + +#else + +static inline int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable) +{ + return 0; +} + +#endif diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 11d3ad8d255145..ae4594a9ed832b 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -35,6 +35,7 @@ #include #include +#include "brcm.h" #include "smp.h" #include "eir.h" @@ -3070,6 +3071,32 @@ int hci_conn_set_phy(struct hci_conn *conn, u32 phys) } } +int hci_conn_setsockopt(struct hci_conn *conn, struct sock *sk, int level, + int optname, sockptr_t optval, unsigned int optlen) { + int val; + bool old_high, new_high, changed; + + if (level != SOL_SOCKET) + return 0; + + if (optname != SO_PRIORITY) + return 0; + + if (optlen < sizeof(int)) + return -EINVAL; + + if (copy_from_sockptr(&val, optval, sizeof(val))) + return -EFAULT; + + old_high = sk->sk_priority >= TC_PRIO_INTERACTIVE; + new_high = val >= TC_PRIO_INTERACTIVE; + changed = old_high != new_high; + if (!changed) + return 0; + + return brcm_set_high_priority(conn->hdev, conn->handle, new_high); +} + static int abort_conn_sync(struct hci_dev *hdev, void *data) { struct hci_conn *conn = data; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 71e8c1b45bcee1..d5eef87accc44c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -891,6 +891,16 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, BT_DBG("sk %p", sk); + if (level == SOL_SOCKET) { + conn = chan->conn; + if (conn) + err = hci_conn_setsockopt(conn->hcon, sock->sk, level, + optname, optval, optlen); + if (err) + return err; + return sock_setsockopt(sock, level, optname, optval, optlen); + } + if (level == SOL_L2CAP) return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); @@ -1931,6 +1941,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy); + if (sock) + set_bit(SOCK_CUSTOM_SOCKOPT, &sock->flags); + chan = l2cap_chan_create(); if (!chan) { sk_free(sk); From 2d0636b26e21778f8ea95f87a785e9d115311c88 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 9 May 2026 11:58:52 +0200 Subject: [PATCH 341/352] driver-core: Add error message to device_links_missing_supplier WARN() Signed-off-by: Janne Grunau --- drivers/base/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/base/core.c b/drivers/base/core.c index a1a83b5626b886..d213908c34f726 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1003,6 +1003,7 @@ static void device_links_missing_supplier(struct device *dev) if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } else { + dev_err(dev, "devices misses supplier %s\n", dev_name(link->supplier)); WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); WRITE_ONCE(link->status, DL_STATE_DORMANT); } From 0374c4b9a7225b9cb25c497ba01f6bcec19afc59 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 3 Apr 2026 12:36:06 +0200 Subject: [PATCH 342/352] arm64: dts: apple: t8122: Add PCI power enable GPIOs - WLAN/BT (SMC PMU GPIO #13) (all devices) - ASM3142 (SMC PMU GPIO #14) (j434, iMac with 4 USB-C ports) - SD card reader (SMC PMU GPIO #23) (j504, 14-inch MacBook Pro) Signed-off-by: Janne Grunau --- arch/arm64/boot/dts/apple/t8122-j434.dts | 1 + arch/arm64/boot/dts/apple/t8122-j504.dts | 1 + arch/arm64/boot/dts/apple/t8122-jxxx.dtsi | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8122-j434.dts b/arch/arm64/boot/dts/apple/t8122-j434.dts index f9635b6eb7ffe3..fd79ec61091391 100644 --- a/arch/arm64/boot/dts/apple/t8122-j434.dts +++ b/arch/arm64/boot/dts/apple/t8122-j434.dts @@ -38,6 +38,7 @@ &port02 { bus-range = <3 3>; + pwren-gpios = <&smc_gpio 14 GPIO_ACTIVE_HIGH>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/apple/t8122-j504.dts b/arch/arm64/boot/dts/apple/t8122-j504.dts index 5f19711a489bad..53859f64e76c8f 100644 --- a/arch/arm64/boot/dts/apple/t8122-j504.dts +++ b/arch/arm64/boot/dts/apple/t8122-j504.dts @@ -42,6 +42,7 @@ &port01 { /* SD card reader */ bus-range = <2 2>; + pwren-gpios = <&smc_gpio 23 GPIO_ACTIVE_HIGH>; status = "okay"; sdhci0: mmc@0,0 { diff --git a/arch/arm64/boot/dts/apple/t8122-jxxx.dtsi b/arch/arm64/boot/dts/apple/t8122-jxxx.dtsi index 2d36782c920d4f..3eac7384882040 100644 --- a/arch/arm64/boot/dts/apple/t8122-jxxx.dtsi +++ b/arch/arm64/boot/dts/apple/t8122-jxxx.dtsi @@ -56,6 +56,7 @@ */ &port00 { bus-range = <1 1>; + pwren-gpios = <&smc_gpio 13 GPIO_ACTIVE_HIGH>; wifi0: wifi@0,0 { compatible = "pci14e4,4434"; From 6f93b5ec34a3815a33937fd86cf065502166f107 Mon Sep 17 00:00:00 2001 From: Michael Reeves Date: Fri, 30 Jan 2026 21:43:14 +1100 Subject: [PATCH 343/352] arm64: dts: apple: Add MTP DockChannel to M3 device tree The internal keyboard and trackpad HID on MacBook variants of the Apple M3 (t8122) SoC are connected through a Apple -developed protocol called DockChannel and mediated by a coprocessor known as the Multi-Touch Processor (MTP). This commit adds the nessecary device tree nodes to the M3's device tree for internal HID to work. It is disabled by default, to be enabled only in MacBook board files where it is tested and confirmed to work. Co-developed-by: Alyssa Milburn Signed-off-by: Alyssa Milburn Signed-off-by: Michael Reeves --- arch/arm64/boot/dts/apple/t8122.dtsi | 77 ++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8122.dtsi b/arch/arm64/boot/dts/apple/t8122.dtsi index 46146063d9a16b..a7ec29edbd9d0f 100644 --- a/arch/arm64/boot/dts/apple/t8122.dtsi +++ b/arch/arm64/boot/dts/apple/t8122.dtsi @@ -544,6 +544,83 @@ ; }; + mtp: mtp@2fa400000 { + compatible = "apple,t8122-mtp", "apple,t8122-rtk-helper-asc4", "apple,mtp", "apple,rtk-helper-asc4"; + reg = <0x2 0xfa400000 0x0 0x4000>, + <0x2 0xfac00000 0x0 0x100000>; + reg-names = "asc", "sram"; + + mboxes = <&mtp_mbox>; + iommus = <&mtp_dart 1>; + #helper-cells = <0>; + + status = "disabled"; + }; + + mtp_mbox: mbox@2fa408000 { + compatible = "apple,t8122-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0xfa408000 0x0 0x4000>; + + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + mtp_dart: iommu@2fa808000 { + compatible = "apple,t8122-dart", "apple,t8110-dart"; + reg = <0x2 0xfa808000 0x0 0x4000>; + + interrupt-parent = <&aic>; + interrupts = ; + + #iommu-cells = <1>; + + status = "disabled"; + }; + + mtp_dockchannel: fifo@2fab30000 { + compatible = "apple,t8122-dockchannel", "apple,dockchannel"; + reg = <0x2 0xfab14000 0x0 0x4000>; + reg-names = "irq"; + interrupt-parent = <&aic>; + interrupts = ; + + ranges = <0 0x2 0xfab30000 0x20000>; + nonposted-mmio; + #address-cells = <1>; + #size-cells = <1>; + + interrupt-controller; + #interrupt-cells = <2>; + + status = "disabled"; + + mtp_hid: input@8000 { + compatible = "apple,dockchannel-hid"; + reg = <0x8000 0x4000>, + <0xc000 0x4000>, + <0x0000 0x4000>, + <0x4000 0x4000>; + reg-names = "rmt-config", "rmt-data", "config", "data"; + + iommus = <&mtp_dart 1>; + + interrupt-parent = <&mtp_dockchannel>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, + <3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tx", "rx"; + + apple,fifo-size = <0x800>; + apple,helper-cpu = <&mtp>; + }; + }; + ans_mbox: mbox@309408000 { compatible = "apple,t8122-asc-mailbox", "apple,asc-mailbox-v4"; reg = <0x3 0x09408000 0x0 0x4000>; From df710726468b240b61ebeb86a3610dd523797598 Mon Sep 17 00:00:00 2001 From: Michael Reeves Date: Fri, 30 Jan 2026 22:06:07 +1100 Subject: [PATCH 344/352] arm64: dts: apple: t8122: Add MTP device nodes to Macbook board files Add mtp device nodes for t8122 (M3) based MacBooks. Signed-off-by: Michael Reeves --- arch/arm64/boot/dts/apple/t8122-j504.dts | 39 ++++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8122-j613.dts | 39 ++++++++++++++++++++++++ arch/arm64/boot/dts/apple/t8122-j615.dts | 39 ++++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t8122-j504.dts b/arch/arm64/boot/dts/apple/t8122-j504.dts index 53859f64e76c8f..7cc0ffc4a8a925 100644 --- a/arch/arm64/boot/dts/apple/t8122-j504.dts +++ b/arch/arm64/boot/dts/apple/t8122-j504.dts @@ -62,3 +62,42 @@ status = "okay"; }; +&mtp { + status = "okay"; +}; + +&mtp_mbox { + status = "okay"; +}; + +&mtp_dart { + status = "okay"; +}; + +&mtp_dockchannel { + status = "okay"; +}; + +&mtp_hid { + apple,afe-reset-gpios = <&smc_gpio 8 GPIO_ACTIVE_LOW>; + apple,stm-reset-gpios = <&smc_gpio 24 GPIO_ACTIVE_LOW>; + + multi-touch { + firmware-name = "apple/tpmtfw-j504.bin"; + }; + + keyboard: keyboard { + hid-country-code = <0>; + apple,keyboard-layout-id = <0>; + }; + + stm { + }; + + actuator { + }; + + tp_accel { + }; +}; + diff --git a/arch/arm64/boot/dts/apple/t8122-j613.dts b/arch/arm64/boot/dts/apple/t8122-j613.dts index 3e4e87cab2bf84..0e0ff85f7e793a 100644 --- a/arch/arm64/boot/dts/apple/t8122-j613.dts +++ b/arch/arm64/boot/dts/apple/t8122-j613.dts @@ -41,3 +41,42 @@ &fpwm1 { status = "okay"; }; + +&mtp { + status = "okay"; +}; + +&mtp_mbox { + status = "okay"; +}; + +&mtp_dart { + status = "okay"; +}; + +&mtp_dockchannel { + status = "okay"; +}; + +&mtp_hid { + apple,afe-reset-gpios = <&smc_gpio 8 GPIO_ACTIVE_LOW>; + apple,stm-reset-gpios = <&smc_gpio 24 GPIO_ACTIVE_LOW>; + + multi-touch { + firmware-name = "apple/tpmtfw-j613.bin"; + }; + + keyboard: keyboard { + hid-country-code = <0>; + apple,keyboard-layout-id = <0>; + }; + + stm { + }; + + actuator { + }; + + tp_accel { + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8122-j615.dts b/arch/arm64/boot/dts/apple/t8122-j615.dts index 56ad290655dcb6..77b249dda6fcfc 100644 --- a/arch/arm64/boot/dts/apple/t8122-j615.dts +++ b/arch/arm64/boot/dts/apple/t8122-j615.dts @@ -41,3 +41,42 @@ &fpwm1 { status = "okay"; }; + +&mtp { + status = "okay"; +}; + +&mtp_mbox { + status = "okay"; +}; + +&mtp_dart { + status = "okay"; +}; + +&mtp_dockchannel { + status = "okay"; +}; + +&mtp_hid { + apple,afe-reset-gpios = <&smc_gpio 8 GPIO_ACTIVE_LOW>; + apple,stm-reset-gpios = <&smc_gpio 24 GPIO_ACTIVE_LOW>; + + multi-touch { + firmware-name = "apple/tpmtfw-j615.bin"; + }; + + keyboard: keyboard { + hid-country-code = <0>; + apple,keyboard-layout-id = <0>; + }; + + stm { + }; + + actuator { + }; + + tp_accel { + }; +}; From 0d1ba22cd93220303162c2f1a335bb8b15d89ed8 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Mon, 6 Apr 2026 10:25:39 +1000 Subject: [PATCH 345/352] drm: apple: Define IOMFB parameter for Adaptive Sync IOMFB exposes a method that allows firmware consumers to change display behaviour parameters at runtime. One such parameter is IOMFBParameter_adaptive_sync, which allows DCP to be informed of the desired minimum refresh rate, media target rate, and fractional rate. Add an enum to define the supported parameters, and add IOMFBPARAM_ADAPTIVE_SYNC to it as a starting point. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index 5799586106713e..8a871db0b94a70 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -46,6 +46,15 @@ enum dcpep_type { IOMFB_MESSAGE_TYPE_MSG = 2, }; +/* + * IOMFB supports the setting of a number of parameters + * that alter various aspects of the connected sink's + * behaviour at runtime. + */ +enum iomfb_parameter { + IOMFBPARAM_ADAPTIVE_SYNC = 14, +}; + #define IOMFB_MESSAGE_TYPE GENMASK_ULL( 3, 0) /* Message */ From e574d022cf6382469fb06267ffb394c1ddb418a2 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Mon, 6 Apr 2026 10:21:44 +1000 Subject: [PATCH 346/352] drm: apple: Do not set IOMFBParameter_adaptive_sync on poweron This was actually unnecessary, and having dcp_on_set_parameter as a dcp_callback_t will introduce some complicated duplication when enabling VRR. Remove this callback and just set the display handle on poweron instead. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_template.c | 29 +++++--------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 1b7ecbcba925d1..82a5fce70bd442 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -784,21 +784,6 @@ static void dcp_on_set_power_state(struct apple_dcp *dcp, void *out, void *cooki dcp_set_power_state(dcp, false, &req, dcp_on_final, cookie); } -static void dcp_on_set_parameter(struct apple_dcp *dcp, void *out, void *cookie) -{ - struct dcp_set_parameter_dcp param = { - .param = 14, - .value = { 0 }, -#if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) - .count = 3, -#else - .count = 1, -#endif - }; - - dcp_set_parameter_dcp(dcp, false, ¶m, dcp_on_set_power_state, cookie); -} - void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp) { struct dcp_wait_cookie *cookie; @@ -815,15 +800,11 @@ void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp) /* increase refcount to ensure the receiver has a reference */ kref_get(&cookie->refcount); - if (dcp->main_display) { - handle = 0; - dcp_set_display_device(dcp, false, &handle, dcp_on_set_power_state, - cookie); - } else { - handle = 2; - dcp_set_display_device(dcp, false, &handle, - dcp_on_set_parameter, cookie); - } + handle = dcp->main_display ? 0 : 2; + + dcp_set_display_device(dcp, false, &handle, dcp_on_set_power_state, + cookie); + ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(10000)); if (ret == 0) { From 04f627cfe5548b092ba2757de3af836c754c501a Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 3 Apr 2026 20:31:17 +1000 Subject: [PATCH 347/352] drm: apple: Add preliminary VRR support DCP supports VRR/Adaptive Sync, with its enormous firmware blob handling the low-level details for us. Display refresh rate is determined by the swap timing values provided to DCP on each swap request. VRR is activated by setting IOMFBadaptive_sync_parameter::minRR and then requesting a modeset. Wire up all of the required KMS properties to expose VRR to userspace, and tell DCP to enable it when supported. This enables VRR *unconditionally* for supported sinks, which will be fixed in a future commit. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/apple_drv.c | 4 +++ drivers/gpu/drm/apple/iomfb.c | 1 + drivers/gpu/drm/apple/iomfb_template.c | 46 ++++++++++++++++++++++++-- drivers/gpu/drm/apple/parser.c | 32 ++++++++++++++++-- drivers/gpu/drm/apple/parser.h | 2 ++ 5 files changed, 79 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 0f36dad6f96351..31b86e909014ad 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -335,6 +335,10 @@ static int apple_probe_per_dcp(struct device *dev, if (ret) return ret; + ret = drm_connector_attach_vrr_capable_property(&connector->base); + if (ret) + return ret; + connector->base.polled = DRM_CONNECTOR_POLL_HPD; connector->connected = false; connector->dcp = dcp; diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 1d9448f0f4dc47..1d90e4a2597303 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -244,6 +244,7 @@ void dcp_hotplug(struct work_struct *work) if (!connector->connected) { drm_edid_free(connector->drm_edid); + drm_connector_set_vrr_capable_property(&connector->base, false); connector->drm_edid = NULL; } diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 82a5fce70bd442..e090797743831f 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -546,8 +546,9 @@ static u8 dcpep_cb_prop_chunk(struct apple_dcp *dcp, static bool dcpep_process_chunks(struct apple_dcp *dcp, struct dcp_set_dcpav_prop_end_req *req) { + struct apple_connector *connector = dcp->connector; struct dcp_parse_ctx ctx; - int ret; + int ret, i; if (!dcp->chunks.data) { dev_warn(dcp->dev, "ignoring spurious end\n"); @@ -589,6 +590,15 @@ static bool dcpep_process_chunks(struct apple_dcp *dcp, dcp_set_dimensions(dcp); } + if (connector) { + for (i = 0; i < dcp->nr_modes; i++) { + if (dcp->modes[i].vrr) { + drm_connector_set_vrr_capable_property(&connector->base, true); + break; + } + } + } + return true; } @@ -1171,6 +1181,33 @@ static void complete_set_digital_out_mode(struct apple_dcp *dcp, void *data, } } +/* Changes to Adaptive Sync require a trip through set_digital_out_mode */ +static void dcp_on_set_adaptive_sync(struct apple_dcp *dcp, void *out, void *cookie) +{ + dcp_set_digital_out_mode(dcp, false, &dcp->mode, + complete_set_digital_out_mode, cookie); +} + +static void dcp_set_adaptive_sync(struct apple_dcp *dcp, u32 rate, void *cookie) +{ + struct dcp_set_parameter_dcp param = { + .param = IOMFBPARAM_ADAPTIVE_SYNC, + .value = { + rate, /* minRR */ + 0, /* mediaTargetRate */ + 0, /* Fractional Rate (?) */ + 0, /* unused */ + }, +#if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) + .count = 3, +#else + .count = 1, +#endif + }; + + dcp_set_parameter_dcp(dcp, false, ¶m, dcp_on_set_adaptive_sync, cookie); +} + int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, struct drm_crtc_state *crtc_state) { @@ -1225,8 +1262,11 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, dcp->during_modeset = true; - dcp_set_digital_out_mode(dcp, false, &dcp->mode, - complete_set_digital_out_mode, cookie); + if (mode->vrr) + dcp_set_adaptive_sync(dcp, mode->min_vrr, cookie); + else + dcp_set_digital_out_mode(dcp, false, &dcp->mode, + complete_set_digital_out_mode, cookie); /* * The DCP firmware has an internal timeout of ~8 seconds for diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 7c7af18a7c7e15..85c303fa04649b 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -194,6 +194,26 @@ static int parse_int(struct dcp_parse_ctx *handle, s64 *value) return 0; } +/* + * DCP stores VRR refresh rates in 64-bit regions, however the number is actually an + * unsigned Q16.16 with the high 32 bits unused. + */ +static int parse_q1616(struct dcp_parse_ctx *handle, u32 *value) +{ + s64 dcp_int; + u32 in; + int ret; + + ret = parse_int(handle, &dcp_int); + if (ret) + return ret; + + in = dcp_int & 0xffffffff; + + memcpy(value, &in, sizeof(*value)); + return 0; +} + static int parse_bool(struct dcp_parse_ctx *handle, bool *b) { const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BOOL); @@ -454,6 +474,10 @@ static int parse_mode(struct dcp_parse_ctx *handle, ret = parse_dimension(it.handle, &horiz); else if (!strcmp(key, "VerticalAttributes")) ret = parse_dimension(it.handle, &vert); + else if (!strcmp(key, "MinimumVariableRefreshRate")) + ret = parse_q1616(it.handle, &out->min_vrr); + else if (!strcmp(key, "MaximumVariableRefreshRate")) + ret = parse_q1616(it.handle, &out->max_vrr); else if (!strcmp(key, "ColorModes")) ret = parse_color_modes(it.handle, out); else if (!strcmp(key, "ID")) @@ -502,15 +526,17 @@ static int parse_mode(struct dcp_parse_ctx *handle, /* * HACK: * Mark the 120 Hz mode on j314/j316 (identified by resolution) as vrr. - * We still do not know how to drive VRR but at least seetinng timestamps - * in the the swap_surface message to non-zero values drives the display - * at 120 fps. + * Setting timestamps in the the swap_surface message to non-zero + * values drives the display at 120 fps. */ if (vert.precise_sync_rate >> 16 == 120 && ((horiz.active == 3024 && vert.active == 1964) || (horiz.active == 3456 && vert.active == 2234))) out->vrr = true; + if (out->min_vrr && out->max_vrr) + out->vrr = true; + vert.active -= notch_height; vert.sync_width += notch_height; diff --git a/drivers/gpu/drm/apple/parser.h b/drivers/gpu/drm/apple/parser.h index e03ee06ae98a75..a7af17bfe35d36 100644 --- a/drivers/gpu/drm/apple/parser.h +++ b/drivers/gpu/drm/apple/parser.h @@ -92,6 +92,8 @@ struct dcp_display_mode { struct dcp_color_mode sdr; struct dcp_color_mode best; bool vrr; + u32 min_vrr; + u32 max_vrr; }; struct dimension { From 3c1130048d13ab7053c3fd321702435eb22498eb Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sat, 4 Apr 2026 17:43:49 +1000 Subject: [PATCH 348/352] drm: apple: Force modeset when VRR is toggled DCP requires a "modeset" to trigger the upload of the SDP to the display. On some monitors, this is instant. On others, this seems to take as long as a real modeset. Given that in either case we still blank the display, let's just force a full modeset when VRR is toggled on or off. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/dcp-internal.h | 1 + drivers/gpu/drm/apple/dcp.c | 4 ++++ drivers/gpu/drm/apple/iomfb_template.c | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index f2eb2483c9a880..0a6859448e19eb 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -186,6 +186,7 @@ struct apple_dcp { bool during_modeset; bool valid_mode; bool use_timestamps; + bool vrr_enabled; struct dcp_set_digital_out_mode_req mode; /* completion for active turning true */ diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 9dfc3fd002f530..dc69d1a9ef7f7e 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -361,6 +361,10 @@ int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) return -EINVAL; } + if (dcp->vrr_enabled != crtc_state->vrr_enabled) { + crtc_state->mode_changed = true; + } + return 0; } diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index e090797743831f..fa998dcf5ce4f1 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1263,7 +1263,7 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, dcp->during_modeset = true; if (mode->vrr) - dcp_set_adaptive_sync(dcp, mode->min_vrr, cookie); + dcp_set_adaptive_sync(dcp, crtc_state->vrr_enabled ? mode->min_vrr : 0, cookie); else dcp_set_digital_out_mode(dcp, false, &dcp->mode, complete_set_digital_out_mode, cookie); @@ -1294,6 +1294,7 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, jiffies_to_msecs(ret)); } dcp->valid_mode = true; + dcp->vrr_enabled = crtc_state->vrr_enabled; return 0; } From e771e233d2e8f3a29f1865e804deee8f110e874b Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Fri, 3 Apr 2026 21:59:47 +1000 Subject: [PATCH 349/352] drm: apple: Set swap timestamps to sane values for Adaptive Sync Setting these timestamps to a dummy value worked fine for enabling a fixed 120 Hz mode on the MacBook Pros, however doing so causes Adaptive Sync displays to simply switch between full and minimum refresh rates. Setting these timestamps based on the swap pacing seems to fix this, and makes the display's refresh rate match the incoming swap rate. Note that the names and values are best-guess only. These seem to work fine for driving VRR displays, but may still be incorrect. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_template.c | 21 ++++++++++++++++----- drivers/gpu/drm/apple/iomfb_template.h | 6 +++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index fa998dcf5ce4f1..d37b7c77e73241 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1299,6 +1299,15 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, return 0; } +/* + * DCP timestamps are expressed in system timer ticks. Approximate + * this by converting from ktime nanoseconds to 24 MHz ticks. + */ +static u64 ns_to_mach(u64 ns) +{ + return ns * 3 / 125; +} + void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_plane *plane; @@ -1415,12 +1424,14 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru if (has_surface && dcp->use_timestamps) { /* - * Fake timstamps to get 120hz refresh rate. It looks - * like the actual value does not matter, as long as it is non zero. + * TODO: ascertain with certainty what these timestamps + * are. They are something to do with presentation timing, + * but that is all we know for sure. These values seem to + * work well with VRR. */ - req->swap.ts1 = 120; - req->swap.ts2 = 120; - req->swap.ts3 = 120; + req->swap.unk_pres_ts1 = ns_to_mach(ktime_get_ns()); + req->swap.unk_pres_ts2 = ns_to_mach(ktime_to_ns(dcp->swap_start)); + req->swap.unk_pres_ts3 = req->swap.unk_pres_ts1; } /* These fields should be set together */ diff --git a/drivers/gpu/drm/apple/iomfb_template.h b/drivers/gpu/drm/apple/iomfb_template.h index 8efab49cc53d08..e74672da712efa 100644 --- a/drivers/gpu/drm/apple/iomfb_template.h +++ b/drivers/gpu/drm/apple/iomfb_template.h @@ -18,14 +18,14 @@ #include "version_utils.h" struct DCP_FW_NAME(dcp_swap) { - u64 ts1; - u64 ts2; + u64 unk_pres_ts1; + u64 unk_pres_ts2; u64 unk_10; u64 unk_18; u64 ts64_unk; u64 unk_28; - u64 ts3; + u64 unk_pres_ts3; u64 unk_38; u64 flags1; From 697a50a06e21e99acdf5fb955e3671166da80536 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sat, 4 Apr 2026 23:32:06 +1000 Subject: [PATCH 350/352] drm: apple: Set min and max VRRs for MacBook Pros Since these machines do not have proper EDID/DisplayID data, we need to help the driver along a little bit. We know that "ProMotion" displays can do 24-120 Hz VRR, so let's populate the mode with those values. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/parser.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/parser.c b/drivers/gpu/drm/apple/parser.c index 85c303fa04649b..dd1d76936fb18b 100644 --- a/drivers/gpu/drm/apple/parser.c +++ b/drivers/gpu/drm/apple/parser.c @@ -531,8 +531,11 @@ static int parse_mode(struct dcp_parse_ctx *handle, */ if (vert.precise_sync_rate >> 16 == 120 && ((horiz.active == 3024 && vert.active == 1964) || - (horiz.active == 3456 && vert.active == 2234))) + (horiz.active == 3456 && vert.active == 2234))) { + out->min_vrr = 24 << 16; + out->max_vrr = 120 << 16; out->vrr = true; + } if (out->min_vrr && out->max_vrr) out->vrr = true; From ebc40e9280f85767192e8120d3beeca12e4c90ba Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 5 Apr 2026 13:08:29 +1000 Subject: [PATCH 351/352] drm: apple: Only use swap timestamps if VRR is actually active macOS is inconsistent with how it uses DCP timestamps. Some swaps don't use them at all. We know they are required for VRR display modes to work properly, so let's just turn them on when we are connected to a VRR display. This includes the 120 Hz mode on the 14" and 16" MacBook Pros. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/iomfb_template.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index d37b7c77e73241..2390be534dfdfd 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1247,8 +1247,8 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, .timing_mode_id = mode->timing_mode_id }; - /* Keep track of suspected vrr modes */ - dcp->use_timestamps = mode->vrr; + /* Use DCP swap timestamps on MacBook Pros with VRR */ + dcp->use_timestamps = mode->vrr && dcp->main_display; cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); if (!cookie) { @@ -1422,7 +1422,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru req->clear = 1; } - if (has_surface && dcp->use_timestamps) { + if (has_surface && (dcp->use_timestamps || crtc_state->vrr_enabled)) { /* * TODO: ascertain with certainty what these timestamps * are. They are something to do with presentation timing, From 80bc30346aa9badf208546791a6f4a678ac9d9d6 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Tue, 7 Apr 2026 21:43:32 +1000 Subject: [PATCH 352/352] NOUPSTREAM: drm: apple: Hide VRR behind a module parameter Given that DCP requires a modeset to activate VRR, and given that this is explicitly banned by KMS API contract and VESA DisplayPort specification, hide this experimental support behind a module param. Interestingly, the HDMI spec does not require a modeset-free VRR transition. For this reason, it is expected that the KMS API contract may change in the future, as both Intel and AMD hardware require a modeset to enable VRR in some circumstances. Either VRR will be expected to be enabled whenever it is supported, *or* modesetting to toggle it on or off will be allowed. When that happens, this commit *must* be reverted. Signed-off-by: James Calligeros --- drivers/gpu/drm/apple/dcp.c | 10 +++++--- drivers/gpu/drm/apple/iomfb_template.c | 33 ++++++++++++++------------ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index dc69d1a9ef7f7e..83ba20f7f02568 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -58,6 +58,10 @@ static bool unstable_edid = true; module_param(unstable_edid, bool, 0644); MODULE_PARM_DESC(unstable_edid, "Enable unstable EDID retrival support"); +bool force_vrr; +module_param(force_vrr, bool, 0644); +MODULE_PARM_DESC(force_vrr, "Always enable Adaptive Sync/ProMotion on supported displays"); + /* copied and simplified from drm_vblank.c */ static void send_vblank_event(struct drm_device *dev, struct drm_pending_vblank_event *e, @@ -361,9 +365,9 @@ int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) return -EINVAL; } - if (dcp->vrr_enabled != crtc_state->vrr_enabled) { - crtc_state->mode_changed = true; - } + // if (dcp->vrr_enabled != crtc_state->vrr_enabled) { + // crtc_state->mode_changed = true; + // } return 0; } diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 2390be534dfdfd..0e5d5908a3c9b6 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -34,6 +34,8 @@ /* Register defines used in bandwidth setup structure */ #define REG_DOORBELL_BIT(idx) (2 + (idx)) +extern bool force_vrr; + struct dcp_wait_cookie { struct kref refcount; struct completion done; @@ -546,9 +548,9 @@ static u8 dcpep_cb_prop_chunk(struct apple_dcp *dcp, static bool dcpep_process_chunks(struct apple_dcp *dcp, struct dcp_set_dcpav_prop_end_req *req) { - struct apple_connector *connector = dcp->connector; + // struct apple_connector *connector = dcp->connector; struct dcp_parse_ctx ctx; - int ret, i; + int ret; //, i; if (!dcp->chunks.data) { dev_warn(dcp->dev, "ignoring spurious end\n"); @@ -590,14 +592,14 @@ static bool dcpep_process_chunks(struct apple_dcp *dcp, dcp_set_dimensions(dcp); } - if (connector) { - for (i = 0; i < dcp->nr_modes; i++) { - if (dcp->modes[i].vrr) { - drm_connector_set_vrr_capable_property(&connector->base, true); - break; - } - } - } + // if (connector) { + // for (i = 0; i < dcp->nr_modes; i++) { + // if (dcp->modes[i].vrr) { + // drm_connector_set_vrr_capable_property(&connector->base, true); + // break; + // } + // } + // } return true; } @@ -1262,11 +1264,12 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, dcp->during_modeset = true; - if (mode->vrr) - dcp_set_adaptive_sync(dcp, crtc_state->vrr_enabled ? mode->min_vrr : 0, cookie); - else + if (mode->vrr) { + dcp_set_adaptive_sync(dcp, force_vrr ? mode->min_vrr : 0, cookie); + } else { dcp_set_digital_out_mode(dcp, false, &dcp->mode, complete_set_digital_out_mode, cookie); + } /* * The DCP firmware has an internal timeout of ~8 seconds for @@ -1294,7 +1297,7 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, jiffies_to_msecs(ret)); } dcp->valid_mode = true; - dcp->vrr_enabled = crtc_state->vrr_enabled; + dcp->vrr_enabled = mode->vrr && force_vrr; return 0; } @@ -1422,7 +1425,7 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru req->clear = 1; } - if (has_surface && (dcp->use_timestamps || crtc_state->vrr_enabled)) { + if (has_surface && (dcp->use_timestamps || crtc_state->vrr_enabled || force_vrr)) { /* * TODO: ascertain with certainty what these timestamps * are. They are something to do with presentation timing,