diff --git a/CREDITS b/CREDITS index 5797e8f7e92b06f8736c01c6c191815c4802b6fd..df8d6946739f68655a8b077f0ebcc4bf4612944b 100644 --- a/CREDITS +++ b/CREDITS @@ -2161,6 +2161,19 @@ N: Mike Kravetz E: mike.kravetz@oracle.com D: Maintenance and development of the hugetlb subsystem +N: Seth Jennings +E: sjenning@redhat.com +D: Creation and maintenance of zswap + +N: Dan Streetman +E: ddstreet@ieee.org +D: Maintenance and development of zswap +D: Creation and maintenance of the zpool API + +N: Vitaly Wool +E: vitaly.wool@konsulko.com +D: Maintenance and development of zswap + N: Andreas S. Krebs E: akrebs@altavista.net D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards diff --git a/Documentation/ABI/testing/sysfs-class-net-queues b/Documentation/ABI/testing/sysfs-class-net-queues index 906ff3ca928ac1389567a5f02bdc4e06c3980b38..5bff64d256c207c8a7d2c915e0e8affac191913c 100644 --- a/Documentation/ABI/testing/sysfs-class-net-queues +++ b/Documentation/ABI/testing/sysfs-class-net-queues @@ -1,4 +1,4 @@ -What: /sys/class//queues/rx-/rps_cpus +What: /sys/class/net//queues/rx-/rps_cpus Date: March 2010 KernelVersion: 2.6.35 Contact: netdev@vger.kernel.org @@ -8,7 +8,7 @@ Description: network device queue. Possible values depend on the number of available CPU(s) in the system. -What: /sys/class//queues/rx-/rps_flow_cnt +What: /sys/class/net//queues/rx-/rps_flow_cnt Date: April 2010 KernelVersion: 2.6.35 Contact: netdev@vger.kernel.org @@ -16,7 +16,7 @@ Description: Number of Receive Packet Steering flows being currently processed by this particular network device receive queue. -What: /sys/class//queues/tx-/tx_timeout +What: /sys/class/net//queues/tx-/tx_timeout Date: November 2011 KernelVersion: 3.3 Contact: netdev@vger.kernel.org @@ -24,7 +24,7 @@ Description: Indicates the number of transmit timeout events seen by this network interface transmit queue. -What: /sys/class//queues/tx-/tx_maxrate +What: /sys/class/net//queues/tx-/tx_maxrate Date: March 2015 KernelVersion: 4.1 Contact: netdev@vger.kernel.org @@ -32,7 +32,7 @@ Description: A Mbps max-rate set for the queue, a value of zero means disabled, default is disabled. -What: /sys/class//queues/tx-/xps_cpus +What: /sys/class/net//queues/tx-/xps_cpus Date: November 2010 KernelVersion: 2.6.38 Contact: netdev@vger.kernel.org @@ -42,7 +42,7 @@ Description: network device transmit queue. Possible values depend on the number of available CPU(s) in the system. -What: /sys/class//queues/tx-/xps_rxqs +What: /sys/class/net//queues/tx-/xps_rxqs Date: June 2018 KernelVersion: 4.18.0 Contact: netdev@vger.kernel.org @@ -53,7 +53,7 @@ Description: number of available receive queue(s) in the network device. Default is disabled. -What: /sys/class//queues/tx-/byte_queue_limits/hold_time +What: /sys/class/net//queues/tx-/byte_queue_limits/hold_time Date: November 2011 KernelVersion: 3.3 Contact: netdev@vger.kernel.org @@ -62,7 +62,7 @@ Description: of this particular network device transmit queue. Default value is 1000. -What: /sys/class//queues/tx-/byte_queue_limits/inflight +What: /sys/class/net//queues/tx-/byte_queue_limits/inflight Date: November 2011 KernelVersion: 3.3 Contact: netdev@vger.kernel.org @@ -70,7 +70,7 @@ Description: Indicates the number of bytes (objects) in flight on this network device transmit queue. -What: /sys/class//queues/tx-/byte_queue_limits/limit +What: /sys/class/net//queues/tx-/byte_queue_limits/limit Date: November 2011 KernelVersion: 3.3 Contact: netdev@vger.kernel.org @@ -79,7 +79,7 @@ Description: on this network device transmit queue. This value is clamped to be within the bounds defined by limit_max and limit_min. -What: /sys/class//queues/tx-/byte_queue_limits/limit_max +What: /sys/class/net//queues/tx-/byte_queue_limits/limit_max Date: November 2011 KernelVersion: 3.3 Contact: netdev@vger.kernel.org @@ -88,7 +88,7 @@ Description: queued on this network device transmit queue. See include/linux/dynamic_queue_limits.h for the default value. -What: /sys/class//queues/tx-/byte_queue_limits/limit_min +What: /sys/class/net//queues/tx-/byte_queue_limits/limit_min Date: November 2011 KernelVersion: 3.3 Contact: netdev@vger.kernel.org diff --git a/Documentation/ABI/testing/sysfs-platform-silicom b/Documentation/ABI/testing/sysfs-platform-silicom index 2288b3665d160a87b352def3e122461256a21761..4d1cc5bdbcc5f9f945dd825aed99cad89982fdd4 100644 --- a/Documentation/ABI/testing/sysfs-platform-silicom +++ b/Documentation/ABI/testing/sysfs-platform-silicom @@ -10,6 +10,7 @@ What: /sys/devices/platform/silicom-platform/power_cycle Date: November 2023 KernelVersion: 6.7 Contact: Henry Shi +Description: This file allow user to power cycle the platform. Default value is 0; when set to 1, it powers down the platform, waits 5 seconds, then powers on the diff --git a/Documentation/accel/introduction.rst b/Documentation/accel/introduction.rst index 89984dfececf0b0b07a937179808d27b8268cf4b..ae30301366379d067e5cb71b4fcb534bc53c4d40 100644 --- a/Documentation/accel/introduction.rst +++ b/Documentation/accel/introduction.rst @@ -101,8 +101,8 @@ External References email threads ------------- -* `Initial discussion on the New subsystem for acceleration devices `_ - Oded Gabbay (2022) -* `patch-set to add the new subsystem `_ - Oded Gabbay (2022) +* `Initial discussion on the New subsystem for acceleration devices `_ - Oded Gabbay (2022) +* `patch-set to add the new subsystem `_ - Oded Gabbay (2022) Conference talks ---------------- diff --git a/Documentation/admin-guide/kernel-parameters.rst b/Documentation/admin-guide/kernel-parameters.rst index 102937bc8443a23d88b952b4d7278e5e6cd25c21..4410384596a90b0ab26b4cf43bac54aaf78193fe 100644 --- a/Documentation/admin-guide/kernel-parameters.rst +++ b/Documentation/admin-guide/kernel-parameters.rst @@ -218,8 +218,3 @@ bytes respectively. Such letter suffixes can also be entirely omitted: .. include:: kernel-parameters.txt :literal: - -Todo ----- - - Add more DRM drivers. diff --git a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst index 993c2a05f5eeab65f9e3d3a5464ac26513452472..b6aeae3327ceb537b78fdbd86961ae670614395b 100644 --- a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst +++ b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst @@ -243,13 +243,9 @@ To reduce its OS jitter, do any of the following: 3. Do any of the following needed to avoid jitter that your application cannot tolerate: - a. Build your kernel with CONFIG_SLUB=y rather than - CONFIG_SLAB=y, thus avoiding the slab allocator's periodic - use of each CPU's workqueues to run its cache_reap() - function. - b. Avoid using oprofile, thus avoiding OS jitter from + a. Avoid using oprofile, thus avoiding OS jitter from wq_sync_buffer(). - c. Limit your CPU frequency so that a CPU-frequency + b. Limit your CPU frequency so that a CPU-frequency governor is not required, possibly enlisting the aid of special heatsinks or other cooling technologies. If done correctly, and if you CPU architecture permits, you should @@ -259,7 +255,7 @@ To reduce its OS jitter, do any of the following: WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - d. As of v3.18, Christoph Lameter's on-demand vmstat workers + c. As of v3.18, Christoph Lameter's on-demand vmstat workers commit prevents OS jitter due to vmstat_update() on CONFIG_SMP=y systems. Before v3.18, is not possible to entirely get rid of the OS jitter, but you can @@ -274,7 +270,7 @@ To reduce its OS jitter, do any of the following: (based on an earlier one from Gilad Ben-Yossef) that reduces or even eliminates vmstat overhead for some workloads at https://lore.kernel.org/r/00000140e9dfd6bd-40db3d4f-c1be-434f-8132-7820f81bb586-000000@email.amazonses.com. - e. If running on high-end powerpc servers, build with + d. If running on high-end powerpc servers, build with CONFIG_PPC_RTAS_DAEMON=n. This prevents the RTAS daemon from running on each CPU every second or so. (This will require editing Kconfig files and will defeat @@ -282,12 +278,12 @@ To reduce its OS jitter, do any of the following: due to the rtas_event_scan() function. WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - f. If running on Cell Processor, build your kernel with + e. If running on Cell Processor, build your kernel with CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from spu_gov_work(). WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - g. If running on PowerMAC, build your kernel with + f. If running on PowerMAC, build your kernel with CONFIG_PMAC_RACKMETER=n to disable the CPU-meter, avoiding OS jitter from rackmeter_do_timer(). diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index a9efab50eed83e06a89549aeb1fb4da1b2eba1d9..22955d56b3799bfc3f3b92874b638aa24c1edaa6 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -671,8 +671,23 @@ Testing Static Functions ------------------------ If we do not want to expose functions or variables for testing, one option is to -conditionally ``#include`` the test file at the end of your .c file. For -example: +conditionally export the used symbol. For example: + +.. code-block:: c + + /* In my_file.c */ + + VISIBLE_IF_KUNIT int do_interesting_thing(); + EXPORT_SYMBOL_IF_KUNIT(do_interesting_thing); + + /* In my_file.h */ + + #if IS_ENABLED(CONFIG_KUNIT) + int do_interesting_thing(void); + #endif + +Alternatively, you could conditionally ``#include`` the test file at the end of +your .c file. For example: .. code-block:: c diff --git a/Documentation/devicetree/bindings/display/bridge/fsl,imx8mp-hdmi-tx.yaml b/Documentation/devicetree/bindings/display/bridge/fsl,imx8mp-hdmi-tx.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3791c9f4ebab0e207f16bb02fc319ee24de207e8 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/fsl,imx8mp-hdmi-tx.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/fsl,imx8mp-hdmi-tx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX8MP DWC HDMI TX Encoder + +maintainers: + - Lucas Stach + +description: + The i.MX8MP HDMI transmitter is a Synopsys DesignWare + HDMI 2.0a TX controller IP. + +allOf: + - $ref: /schemas/display/bridge/synopsys,dw-hdmi.yaml# + +properties: + compatible: + enum: + - fsl,imx8mp-hdmi-tx + + reg-io-width: + const: 1 + + clocks: + maxItems: 4 + + clock-names: + items: + - const: iahb + - const: isfr + - const: cec + - const: pix + + power-domains: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Parallel RGB input port + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: HDMI output port + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - power-domains + - ports + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + hdmi@32fd8000 { + compatible = "fsl,imx8mp-hdmi-tx"; + reg = <0x32fd8000 0x7eff>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk IMX8MP_CLK_HDMI_APB>, + <&clk IMX8MP_CLK_HDMI_REF_266M>, + <&clk IMX8MP_CLK_32K>, + <&hdmi_tx_phy>; + clock-names = "iahb", "isfr", "cec", "pix"; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_HDMI_TX>; + reg-io-width = <1>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + + hdmi_tx_from_pvi: endpoint { + remote-endpoint = <&pvi_to_hdmi_tx>; + }; + }; + + port@1 { + reg = <1>; + hdmi_tx_out: endpoint { + remote-endpoint = <&hdmi0_con>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml index 6ec6d287bff4019cfb3e978252f286463193b930..c93878b6d7182bc6c5bad35b3876168a07725f06 100644 --- a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml +++ b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: SN65DSI86 DSI to eDP bridge chip maintainers: - - Sandeep Panda + - Douglas Anderson description: | The Texas Instruments SN65DSI86 bridge takes MIPI DSI in and outputs eDP. diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml b/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml new file mode 100644 index 0000000000000000000000000000000000000000..56da1636014ce7607bf377197d5bfc5d65878b03 --- /dev/null +++ b/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/imx/fsl,imx8mp-hdmi-pvi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX8MP HDMI Parallel Video Interface + +maintainers: + - Lucas Stach + +description: + The HDMI parallel video interface is a timing and sync generator block in the + i.MX8MP SoC, that sits between the video source and the HDMI TX controller. + +properties: + compatible: + const: fsl,imx8mp-hdmi-pvi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Input from the LCDIF controller. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Output to the HDMI TX controller. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - interrupts + - power-domains + - ports + +additionalProperties: false + +examples: + - | + #include + #include + + display-bridge@32fc4000 { + compatible = "fsl,imx8mp-hdmi-pvi"; + reg = <0x32fc4000 0x44>; + interrupt-parent = <&irqsteer_hdmi>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_PVI>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + pvi_from_lcdif3: endpoint { + remote-endpoint = <&lcdif3_to_pvi>; + }; + }; + + port@1 { + reg = <1>; + pvi_to_hdmi_tx: endpoint { + remote-endpoint = <&hdmi_tx_from_pvi>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/panel/boe,th101mb31ig002-28a.yaml b/Documentation/devicetree/bindings/display/panel/boe,th101mb31ig002-28a.yaml new file mode 100644 index 0000000000000000000000000000000000000000..32df26cbfeed737c4761df211efbb8782c12f25e --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/boe,th101mb31ig002-28a.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/boe,th101mb31ig002-28a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: BOE TH101MB31IG002-28A WXGA DSI Display Panel + +maintainers: + - Manuel Traut + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + enum: + # BOE TH101MB31IG002-28A 10.1" WXGA TFT LCD panel + - boe,th101mb31ig002-28a + + reg: true + backlight: true + enable-gpios: true + power-supply: true + port: true + rotation: true + +required: + - compatible + - reg + - enable-gpios + - power-supply + +additionalProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "boe,th101mb31ig002-28a"; + reg = <0>; + backlight = <&backlight_lcd0>; + enable-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>; + rotation = <90>; + power-supply = <&vcc_3v3>; + port { + panel_in_dsi: endpoint { + remote-endpoint = <&dsi_out_con>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml index bc92928c805b9a10900552fce47c06a4d26c5a54..a4afaff483b73f510f265d739f0b1ed84b777b5d 100644 --- a/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml +++ b/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml @@ -15,7 +15,9 @@ allOf: properties: compatible: items: - - const: hydis,hva40wv1 + - enum: + - frida,frd400b25025 + - hydis,hva40wv1 - const: novatek,nt35510 description: This indicates the panel manufacturer of the panel that is in turn using the NT35510 panel driver. The compatible diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt36672e.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt36672e.yaml new file mode 100644 index 0000000000000000000000000000000000000000..dc4672f3d01d7c95c3abbe129b6ebba53d5f083d --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/novatek,nt36672e.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/novatek,nt36672e.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Novatek NT36672E LCD DSI Panel + +maintainers: + - Ritesh Kumar + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: novatek,nt36672e + + reg: + maxItems: 1 + description: DSI virtual channel + + vddi-supply: true + avdd-supply: true + avee-supply: true + port: true + reset-gpios: true + backlight: true + +required: + - compatible + - reg + - vddi-supply + - avdd-supply + - avee-supply + - reset-gpios + - port + +additionalProperties: false + +examples: + - | + #include + dsi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "novatek,nt36672e"; + reg = <0>; + + reset-gpios = <&tlmm 44 GPIO_ACTIVE_HIGH>; + + vddi-supply = <&vreg_l8c_1p8>; + avdd-supply = <&disp_avdd>; + avee-supply = <&disp_avee>; + + backlight = <&pwm_backlight>; + + port { + panel0_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml index 9f1016551e0b27e4518277ccc9b314b3245bb18f..3fb24393529cddf18495b363ed25fcf2bafa908e 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml @@ -42,6 +42,8 @@ properties: - auo,b101ew05 # Chunghwa Picture Tubes Ltd. 7" WXGA (800x1280) TFT LCD LVDS panel - chunghwa,claa070wp03xg + # EDT ETML0700Z9NDHA 7.0" WSVGA (1024x600) color TFT LCD LVDS panel + - edt,etml0700z9ndha # HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel - hannstar,hsd101pww2 # Hydis Technologies 7" WXGA (800x1280) TFT LCD LVDS panel diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 634a10c6f2ddddb125e72cf6929410c8481b4671..233c620722ddc01511e931b8bac0d4431de04a6e 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -141,6 +141,8 @@ properties: - edt,etm0700g0edh6 # Emerging Display Technology Corp. LVDS WSVGA TFT Display with capacitive touch - edt,etml0700y5dha + # Emerging Display Technology Corp. 10.1" LVDS WXGA TFT Display with capacitive touch + - edt,etml1010g3dra # Emerging Display Technology Corp. 5.7" VGA TFT LCD panel with # capacitive touch - edt,etmv570g2dhu diff --git a/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml b/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml index 97cccd8a8479a5bb26f5da2e66dc9beee0345018..6ec471284f97b690136adfcaa97af1d769f5001e 100644 --- a/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml +++ b/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml @@ -22,6 +22,8 @@ properties: enum: # Anberic RG353V-V2 5.0" 640x480 TFT LCD panel - anbernic,rg353v-panel-v2 + # Powkiddy RGB10MAX3 5.0" 720x1280 TFT LCD panel + - powkiddy,rgb10max3-panel # Powkiddy RGB30 3.0" 720x720 TFT LCD panel - powkiddy,rgb30-panel # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel @@ -43,6 +45,7 @@ properties: reset-gpios: true backlight: true + rotation: true required: - compatible diff --git a/Documentation/devicetree/bindings/display/panel/visionox,rm69299.yaml b/Documentation/devicetree/bindings/display/panel/visionox,rm69299.yaml index fa745a6f4456c5cd47855b18b088f3c802b6056e..7723990675158781204b83d6dc0e60089d489ef8 100644 --- a/Documentation/devicetree/bindings/display/panel/visionox,rm69299.yaml +++ b/Documentation/devicetree/bindings/display/panel/visionox,rm69299.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Visionox model RM69299 Panels maintainers: - - Harigovindan P + - Abhinav Kumar + - Jessica Zhang description: | This binding is for display panels using a Visionox RM692999 panel. diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml index 7e59dee15a5f4c906d3bb08d88e54cbff7322065..af638b6c0d2188541b0b6a0adc0cac484351609a 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml @@ -94,11 +94,14 @@ properties: - const: default - const: unwedge + power-domains: + maxItems: 1 + ports: $ref: /schemas/graph.yaml#/properties/ports - patternProperties: - "^port(@0)?$": + properties: + port@0: $ref: /schemas/graph.yaml#/properties/port description: Input of the DWC HDMI TX properties: @@ -108,11 +111,14 @@ properties: description: Connection to the VOPB endpoint@1: description: Connection to the VOPL - properties: port@1: $ref: /schemas/graph.yaml#/properties/port description: Output of the DWC HDMI TX + required: + - port@0 + - port@1 + rockchip,grf: $ref: /schemas/types.yaml#/definitions/phandle description: @@ -135,19 +141,25 @@ examples: #include #include #include + #include hdmi: hdmi@ff980000 { compatible = "rockchip,rk3288-dw-hdmi"; reg = <0xff980000 0x20000>; reg-io-width = <4>; - ddc-i2c-bus = <&i2c5>; - rockchip,grf = <&grf>; interrupts = ; clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>; clock-names = "iahb", "isfr"; + ddc-i2c-bus = <&i2c5>; + power-domains = <&power RK3288_PD_VIO>; + rockchip,grf = <&grf>; ports { - port { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; #address-cells = <1>; #size-cells = <0>; @@ -155,11 +167,20 @@ examples: reg = <0>; remote-endpoint = <&vopb_out_hdmi>; }; + hdmi_in_vopl: endpoint@1 { reg = <1>; remote-endpoint = <&vopl_out_hdmi>; }; }; + + port@1 { + reg = <1>; + + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; + }; }; }; diff --git a/Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml b/Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml index 25d53fde92e1104490e3f8e604184b9449150be3..597c9cc6a312acb66b0355f84f9dd8977dbb2197 100644 --- a/Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml +++ b/Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml @@ -85,7 +85,7 @@ allOf: clocks: minItems: 6 maxItems: 6 - regs: + reg: minItems: 2 maxItems: 2 @@ -99,7 +99,7 @@ allOf: clocks: minItems: 4 maxItems: 4 - regs: + reg: minItems: 2 maxItems: 2 @@ -116,7 +116,7 @@ allOf: clocks: minItems: 3 maxItems: 3 - regs: + reg: minItems: 1 maxItems: 1 diff --git a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml index 3afbb52d1b7fe589bdd4ae4f0b66f287ce282f40..153ff86fb40590dd926483b299896b39744dee5d 100644 --- a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml +++ b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml @@ -131,9 +131,9 @@ allOf: const: sinowealth,sh1106 then: properties: - width: + solomon,width: default: 132 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -149,9 +149,9 @@ allOf: - solomon,ssd1305 then: properties: - width: + solomon,width: default: 132 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -167,9 +167,9 @@ allOf: - solomon,ssd1306 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -185,9 +185,9 @@ allOf: - solomon,ssd1307 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 39 solomon,dclk-div: default: 2 @@ -205,9 +205,9 @@ allOf: - solomon,ssd1309 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 diff --git a/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml b/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml index 37975ee61c5ad48e822792ec4e37bad6f331a91c..dd7939989cf4f1c2469fc30f1e74aa26b32f3a32 100644 --- a/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml +++ b/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml @@ -30,9 +30,9 @@ allOf: const: solomon,ssd1322 then: properties: - width: + solomon,width: default: 480 - height: + solomon,height: default: 128 - if: @@ -42,9 +42,9 @@ allOf: const: solomon,ssd1325 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 80 - if: @@ -54,9 +54,9 @@ allOf: const: solomon,ssd1327 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 128 unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml b/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b7780038a34b40194d9132adaa8c36fa2f665489 --- /dev/null +++ b/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/solomon,ssd133x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Solomon SSD133x OLED Display Controllers + +maintainers: + - Javier Martinez Canillas + +allOf: + - $ref: solomon,ssd-common.yaml# + +properties: + compatible: + enum: + - solomon,ssd1331 + + solomon,width: + default: 96 + + solomon,height: + default: 64 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + oled@0 { + compatible = "solomon,ssd1331"; + reg = <0x0>; + reset-gpios = <&gpio2 7>; + dc-gpios = <&gpio2 8>; + spi-max-frequency = <10000000>; + }; + }; diff --git a/Documentation/devicetree/bindings/media/cnm,wave521c.yaml b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml index 6d5569e77b7a1239219c13ef2a163849ce5bfd86..6a11c1d11fb5f9a9ccd343c2cb461bd7f3411121 100644 --- a/Documentation/devicetree/bindings/media/cnm,wave521c.yaml +++ b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml @@ -17,7 +17,7 @@ properties: compatible: items: - enum: - - ti,k3-j721s2-wave521c + - ti,j721s2-wave521c - const: cnm,wave521c reg: @@ -53,7 +53,7 @@ additionalProperties: false examples: - | vpu: video-codec@12345678 { - compatible = "ti,k3-j721s2-wave521c", "cnm,wave521c"; + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; reg = <0x12345678 0x1000>; clocks = <&clks 42>; interrupts = <42>; diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml index 8108c564dd78a84a1d869a60b975dcb51e6480ff..aa32dc950e72ccdaf7fb1ac7f759d57a855fc9b6 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml @@ -22,6 +22,7 @@ properties: - const: allwinner,sun6i-a31-spdif - const: allwinner,sun8i-h3-spdif - const: allwinner,sun50i-h6-spdif + - const: allwinner,sun50i-h616-spdif - items: - const: allwinner,sun8i-a83t-spdif - const: allwinner,sun8i-h3-spdif @@ -62,6 +63,8 @@ allOf: enum: - allwinner,sun6i-a31-spdif - allwinner,sun8i-h3-spdif + - allwinner,sun50i-h6-spdif + - allwinner,sun50i-h616-spdif then: required: @@ -73,7 +76,7 @@ allOf: contains: enum: - allwinner,sun8i-h3-spdif - - allwinner,sun50i-h6-spdif + - allwinner,sun50i-h616-spdif then: properties: diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index 1c244866041a3cb985568ce5f19e67d947eed5e6..16551440144183c58517fe27e750233619ebf89d 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -145,7 +145,9 @@ filesystem, an overlay filesystem needs to record in the upper filesystem that files have been removed. This is done using whiteouts and opaque directories (non-directories are always opaque). -A whiteout is created as a character device with 0/0 device number. +A whiteout is created as a character device with 0/0 device number or +as a zero-size regular file with the xattr "trusted.overlay.whiteout". + When a whiteout is found in the upper level of a merged directory, any matching name in the lower level is ignored, and the whiteout itself is also hidden. @@ -154,6 +156,13 @@ A directory is made opaque by setting the xattr "trusted.overlay.opaque" to "y". Where the upper filesystem contains an opaque directory, any directory in the lower filesystem with the same name is ignored. +An opaque directory should not conntain any whiteouts, because they do not +serve any purpose. A merge directory containing regular files with the xattr +"trusted.overlay.whiteout", should be additionally marked by setting the xattr +"trusted.overlay.opaque" to "x" on the merge directory itself. +This is needed to avoid the overhead of checking the "trusted.overlay.whiteout" +on all entries during readdir in the common case. + readdir ------- @@ -534,8 +543,9 @@ A lower dir with a regular whiteout will always be handled by the overlayfs mount, so to support storing an effective whiteout file in an overlayfs mount an alternative form of whiteout is supported. This form is a regular, zero-size file with the "overlay.whiteout" xattr set, inside a directory with the -"overlay.whiteouts" xattr set. Such whiteouts are never created by overlayfs, -but can be used by userspace tools (like containers) that generate lower layers. +"overlay.opaque" xattr set to "x" (see `whiteouts and opaque directories`_). +These alternative whiteouts are never created by overlayfs, but can be used by +userspace tools (like containers) that generate lower layers. These alternative whiteouts can be escaped using the standard xattr escape mechanism in order to properly nest to any depth. diff --git a/Documentation/gpu/amdgpu/dgpu-asic-info-table.csv b/Documentation/gpu/amdgpu/dgpu-asic-info-table.csv index 882d2518f8ed26526016f770d97cc168f4597e73..3825f00ca9fe84d7bce332efda1a350ba1ed6b07 100644 --- a/Documentation/gpu/amdgpu/dgpu-asic-info-table.csv +++ b/Documentation/gpu/amdgpu/dgpu-asic-info-table.csv @@ -16,6 +16,7 @@ Radeon (RX|TM) (PRO|WX) Vega /MI25 /V320 /V340L /8200 /9100 /SSG MxGPU, VEGA10, AMD Radeon (Pro) VII /MI50 /MI60, VEGA20, DCE 12, 9.4.0, VCE 4.1.0 / UVD 7.2.0, 4.2.0 MI100, ARCTURUS, *, 9.4.1, VCN 2.5.0, 4.2.2 MI200, ALDEBARAN, *, 9.4.2, VCN 2.6.0, 4.4.0 +MI300, AQUA_VANGARAM, *, 9.4.3, VCN 4.0.3, 4.4.2 AMD Radeon (RX|Pro) 5600(M|XT) /5700 (M|XT|XTB) /W5700, NAVI10, DCN 2.0.0, 10.1.10, VCN 2.0.0, 5.0.0 AMD Radeon (Pro) 5300 /5500XTB/5500(XT|M) /W5500M /W5500, NAVI14, DCN 2.0.0, 10.1.1, VCN 2.0.2, 5.0.2 AMD Radeon RX 6800(XT) /6900(XT) /W6800, SIENNA_CICHLID, DCN 3.0.0, 10.3.0, VCN 3.0.0, 5.2.0 @@ -23,4 +24,5 @@ AMD Radeon RX 6700 XT / 6800M / 6700M, NAVY_FLOUNDER, DCN 3.0.0, 10.3.2, VCN 3.0 AMD Radeon RX 6600(XT) /6600M /W6600 /W6600M, DIMGREY_CAVEFISH, DCN 3.0.2, 10.3.4, VCN 3.0.16, 5.2.4 AMD Radeon RX 6500M /6300M /W6500M /W6300M, BEIGE_GOBY, DCN 3.0.3, 10.3.5, VCN 3.0.33, 5.2.5 AMD Radeon RX 7900 XT /XTX, , DCN 3.2.0, 11.0.0, VCN 4.0.0, 6.0.0 +AMD Radeon RX 7800 XT, , DCN 3.2.0, 11.0.3, VCN 4.0.0, 6.0.3 AMD Radeon RX 7600M (XT) /7700S /7600S, , DCN 3.2.1, 11.0.2, VCN 4.0.4, 6.0.2 diff --git a/Documentation/gpu/amdgpu/display/dcn-blocks.rst b/Documentation/gpu/amdgpu/display/dcn-blocks.rst new file mode 100644 index 0000000000000000000000000000000000000000..a3fbd3ea028bba6fc256b0e018f512606fd57752 --- /dev/null +++ b/Documentation/gpu/amdgpu/display/dcn-blocks.rst @@ -0,0 +1,78 @@ +========== +DCN Blocks +========== + +In this section, you will find some extra details about some of the DCN blocks +and the code documentation when it is automatically generated. + +DCHUBBUB +-------- + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :export: + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :internal: + +HUBP +---- + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :export: + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :internal: + +DPP +--- + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :export: + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h + :internal: + +MPC +--- + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h + :export: + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h + :internal: + +OPP +--- + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/opp.h + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/opp.h + :export: + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/opp.h + :internal: + +DIO +--- + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h + :export: + +.. kernel-doc:: drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h + :internal: diff --git a/Documentation/gpu/amdgpu/display/display-contributing.rst b/Documentation/gpu/amdgpu/display/display-contributing.rst new file mode 100644 index 0000000000000000000000000000000000000000..fdb2bea01d53a835e23f7d1f641188b554773643 --- /dev/null +++ b/Documentation/gpu/amdgpu/display/display-contributing.rst @@ -0,0 +1,168 @@ +.. _display_todos: + +============================== +AMDGPU - Display Contributions +============================== + +First of all, if you are here, you probably want to give some technical +contribution to the display code, and for that, we say thank you :) + +This page summarizes some of the issues you can help with; keep in mind that +this is a static page, and it is always a good idea to try to reach developers +in the amdgfx or some of the maintainers. Finally, this page follows the DRM +way of creating a TODO list; for more information, check +'Documentation/gpu/todo.rst'. + +Gitlab issues +============= + +Users can report issues associated with AMD GPUs at: + +- https://gitlab.freedesktop.org/drm/amd + +Usually, we try to add a proper label to all new tickets to make it easy to +filter issues. If you can reproduce any problem, you could help by adding more +information or fixing the issue. + +Level: diverse + +IGT +=== + +`IGT`_ provides many integration tests that can be run on your GPU. We always +want to pass a large set of tests to increase the test coverage in our CI. If +you wish to contribute to the display code but are unsure where a good place +is, we recommend you run all IGT tests and try to fix any failure you see in +your hardware. Keep in mind that this failure can be an IGT problem or a kernel +issue; it is necessary to analyze case-by-case. + +Level: diverse + +.. _IGT: https://gitlab.freedesktop.org/drm/igt-gpu-tools + +Compilation +=========== + +Fix compilation warnings +------------------------ + +Enable the W1 or W2 warning level in the kernel compilation and try to fix the +issues on the display side. + +Level: Starter + +Fix compilation issues when using um architecture +------------------------------------------------- + +Linux has a User-mode Linux (UML) feature, and the kernel can be compiled to +the **um** architecture. Compiling for **um** can bring multiple advantages +from the test perspective. We currently have some compilation issues in this +area that we need to fix. + +Level: Intermediate + +Code Refactor +============= + +Add prefix to DC functions to improve the debug with ftrace +----------------------------------------------------------- + +The Ftrace debug feature (check 'Documentation/trace/ftrace.rst') is a +fantastic way to check the code path when developers try to make sense of a +bug. Ftrace provides a filter mechanism that can be useful when the developer +has some hunch of which part of the code can cause the issue; for this reason, +if a set of functions has a proper prefix, it becomes easy to create a good +filter. Additionally, prefixes can improve stack trace readability. + +The DC code does not follow some prefix rules, which makes the Ftrace filter +more complicated and reduces the readability of the stack trace. If you want +something simple to start contributing to the display, you can make patches for +adding prefixes to DC functions. To create those prefixes, use part of the file +name as a prefix for all functions in the target file. Check the +'amdgpu_dm_crtc.c` and `amdgpu_dm_plane.c` for some references. However, we +strongly advise not to send huge patches changing these prefixes; otherwise, it +will be hard to review and test, which can generate second thoughts from +maintainers. Try small steps; in case of double, you can ask before you put in +effort. We recommend first looking at folders like dceXYZ, dcnXYZ, basics, +bios, core, clk_mgr, hwss, resource, and irq. + +Level: Starter + +Reduce code duplication +----------------------- + +AMD has an extensive portfolio with various dGPUs and APUs that amdgpu +supports. To maintain the new hardware release cadence, DCE/DCN was designed in +a modular design, making the bring-up for new hardware fast. Over the years, +amdgpu accumulated some technical debt in the code duplication area. For this +task, it would be a good idea to find a tool that can discover code duplication +(including patterns) and use it as guidance to reduce duplications. + +Level: Intermediate + +Make atomic_commit_[check|tail] more readable +--------------------------------------------- + +The functions responsible for atomic commit and tail are intricate and +extensive. In particular `amdgpu_dm_atomic_commit_tail` is a long function and +could benefit from being split into smaller helpers. Improvements in this area +are more than welcome, but keep in mind that changes in this area will affect +all ASICs, meaning that refactoring requires a comprehensive verification; in +other words, this effort can take some time for validation. + +Level: Advanced + +Documentation +============= + +Expand kernel-doc +----------------- + +Many DC functions do not have a proper kernel-doc; understanding a function and +adding documentation is a great way to learn more about the amdgpu driver and +also leave an outstanding contribution to the entire community. + +Level: Starter + +Beyond AMDGPU +============= + +AMDGPU provides features that are not yet enabled in the userspace. This +section highlights some of the coolest display features, which could be enabled +with the userspace developer helper. + +Enable underlay +--------------- + +AMD display has this feature called underlay (which you can read more about at +'Documentation/GPU/amdgpu/display/mpo-overview.rst') which is intended to +save power when playing a video. The basic idea is to put a video in the +underlay plane at the bottom and the desktop in the plane above it with a hole +in the video area. This feature is enabled in ChromeOS, and from our data +measurement, it can save power. + +Level: Unknown + +Adaptive Backlight Modulation (ABM) +----------------------------------- + +ABM is a feature that adjusts the display panel's backlight level and pixel +values depending on the displayed image. This power-saving feature can be very +useful when the system starts to run off battery; since this will impact the +display output fidelity, it would be good if this option was something that +users could turn on or off. + +Level: Unknown + + +HDR & Color management & VRR +---------------------------- + +HDR, Color Management, and VRR are huge topics and it's hard to put these into +concise ToDos. If you are interested in this topic, we recommend checking some +blog posts from the community developers to better understand some of the +specific challenges and people working on the subject. If anyone wants to work +on some particular part, we can try to help with some basic guidance. Finally, +keep in mind that we already have some kernel-doc in place for those areas. + +Level: Unknown diff --git a/Documentation/gpu/amdgpu/display/display-manager.rst b/Documentation/gpu/amdgpu/display/display-manager.rst index be2651ecdd7f2ab8b1560444ac944ba2da1f7f68..67a811e6891fb3b0266bb253fd4c8997501fab8d 100644 --- a/Documentation/gpu/amdgpu/display/display-manager.rst +++ b/Documentation/gpu/amdgpu/display/display-manager.rst @@ -131,9 +131,6 @@ The DRM blend mode and its elements are then mapped by AMDGPU display manager (DM) to program the blending configuration of the Multiple Pipe/Plane Combined (MPC), as follows: -.. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h - :doc: mpc-overview - .. kernel-doc:: drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h :functions: mpcc_blnd_cfg diff --git a/Documentation/gpu/amdgpu/display/index.rst b/Documentation/gpu/amdgpu/display/index.rst index f8a4f53d70d8c6124100a4582b7342253315360b..f0c342e00a392bf5a57cec05c6dbd89a5d8c9f39 100644 --- a/Documentation/gpu/amdgpu/display/index.rst +++ b/Documentation/gpu/amdgpu/display/index.rst @@ -7,18 +7,80 @@ drm/amd/display - Display Core (DC) AMD display engine is partially shared with other operating systems; for this reason, our Display Core Driver is divided into two pieces: -1. **Display Core (DC)** contains the OS-agnostic components. Things like +#. **Display Core (DC)** contains the OS-agnostic components. Things like hardware programming and resource management are handled here. -2. **Display Manager (DM)** contains the OS-dependent components. Hooks to the - amdgpu base driver and DRM are implemented here. +#. **Display Manager (DM)** contains the OS-dependent components. Hooks to the + amdgpu base driver and DRM are implemented here. For example, you can check + display/amdgpu_dm/ folder. + +------------------ +DC Code validation +------------------ + +Maintaining the same code base across multiple OSes requires a lot of +synchronization effort between repositories and exhaustive validation. In the +DC case, we maintain a tree to centralize code from different parts. The shared +repository has integration tests with our Internal Linux CI farm, and we run a +comprehensive set of IGT tests in various AMD GPUs/APUs (mostly recent dGPUs +and APUs). Our CI also checks ARM64/32, PPC64/32, and x86_64/32 compilation +with DCN enabled and disabled. + +When we upstream a new feature or some patches, we pack them in a patchset with +the prefix **DC Patches for **, which is created based on the latest +`amd-staging-drm-next `_. All of +those patches are under a DC version tested as follows: + +* Ensure that every patch compiles and the entire series pass our set of IGT + test in different hardware. +* Prepare a branch with those patches for our validation team. If there is an + error, a developer will debug as fast as possible; usually, a simple bisect + in the series is enough to point to a bad change, and two possible actions + emerge: fix the issue or drop the patch. If it is not an easy fix, the bad + patch is dropped. +* Finally, developers wait a few days for community feedback before we merge + the series. + +It is good to stress that the test phase is something that we take extremely +seriously, and we never merge anything that fails our validation. Follows an +overview of our test set: + +#. Manual test + * Multiple Hotplugs with DP and HDMI. + * Stress test with multiple display configuration changes via the user interface. + * Validate VRR behaviour. + * Check PSR. + * Validate MPO when playing video. + * Test more than two displays connected at the same time. + * Check suspend/resume. + * Validate FPO. + * Check MST. +#. Automated test + * IGT tests in a farm with GPUs and APUs that support DCN and DCE. + * Compilation validation with the latest GCC and Clang from LTS distro. + * Cross-compilation for PowerPC 64/32, ARM 64/32, and x86 32. + +In terms of test setup for CI and manual tests, we usually use: + +#. The latest Ubuntu LTS. +#. In terms of userspace, we only use fully updated open-source components + provided by the distribution official package manager. +#. Regarding IGT, we use the latest code from the upstream. +#. Most of the manual tests are conducted in the GNome but we also use KDE. + +Notice that someone from our test team will always reply to the cover letter +with the test report. + +-------------- +DC Information +-------------- The display pipe is responsible for "scanning out" a rendered frame from the GPU memory (also called VRAM, FrameBuffer, etc.) to a display. In other words, it would: -1. Read frame information from memory; -2. Perform required transformation; -3. Send pixel data to sink devices. +#. Read frame information from memory; +#. Perform required transformation; +#. Send pixel data to sink devices. If you want to learn more about our driver details, take a look at the below table of content: @@ -26,7 +88,9 @@ table of content: .. toctree:: display-manager.rst - dc-debug.rst dcn-overview.rst + dcn-blocks.rst mpo-overview.rst + dc-debug.rst + display-contributing.rst dc-glossary.rst diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 5fd20a306718cde46926c91b8fef23d6ee9814b9..335de7fcddeecc0fbe94f376a8107ed94476b986 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -153,18 +153,6 @@ Managed Resources .. kernel-doc:: include/drm/drm_managed.h :internal: -Bus-specific Device Registration and PCI Support ------------------------------------------------- - -A number of functions are provided to help with device registration. The -functions deal with PCI and platform devices respectively and are only -provided for historical reasons. These are all deprecated and shouldn't -be used in new drivers. Besides that there's a few helpers for pci -drivers. - -.. kernel-doc:: drivers/gpu/drm/drm_pci.c - :export: - Open/Close, File Operations and IOCTLs ====================================== diff --git a/Documentation/gpu/introduction.rst b/Documentation/gpu/introduction.rst index f05eccd2c07c8acfe0f4f342c971861df86cd842..b7c0baf97dbee223eb541cc143cf910553e0b63f 100644 --- a/Documentation/gpu/introduction.rst +++ b/Documentation/gpu/introduction.rst @@ -164,6 +164,8 @@ Conference talks Slides and articles ------------------- +* `The Linux graphics stack in a nutshell, part 1 `_ - Thomas Zimmermann (2023) +* `The Linux graphics stack in a nutshell, part 2 `_ - Thomas Zimmermann (2023) * `Understanding the Linux Graphics Stack `_ - Bootlin (2022) * `DRM KMS overview `_ - STMicroelectronics (2021) * `Linux graphic stack `_ - Nathan Gauër (2017) diff --git a/Documentation/gpu/rfc/index.rst b/Documentation/gpu/rfc/index.rst index e4f7b005138d0698773d0a1432681ca5ed7dddd1..476719771eef388d575bc5c753ff248c60dfd4d5 100644 --- a/Documentation/gpu/rfc/index.rst +++ b/Documentation/gpu/rfc/index.rst @@ -31,7 +31,3 @@ host such documentation: .. toctree:: i915_vm_bind.rst - -.. toctree:: - - xe.rst diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst deleted file mode 100644 index 97cf87578f973b52404bbd8202ea73d3c1097209..0000000000000000000000000000000000000000 --- a/Documentation/gpu/rfc/xe.rst +++ /dev/null @@ -1,234 +0,0 @@ -========================== -Xe – Merge Acceptance Plan -========================== -Xe is a new driver for Intel GPUs that supports both integrated and -discrete platforms starting with Tiger Lake (first Intel Xe Architecture). - -This document aims to establish a merge plan for the Xe, by writing down clear -pre-merge goals, in order to avoid unnecessary delays. - -Xe – Overview -============= -The main motivation of Xe is to have a fresh base to work from that is -unencumbered by older platforms, whilst also taking the opportunity to -rearchitect our driver to increase sharing across the drm subsystem, both -leveraging and allowing us to contribute more towards other shared components -like TTM and drm/scheduler. - -This is also an opportunity to start from the beginning with a clean uAPI that is -extensible by design and already aligned with the modern userspace needs. For -this reason, the memory model is solely based on GPU Virtual Address space -bind/unbind (‘VM_BIND’) of GEM buffer objects (BOs) and execution only supporting -explicit synchronization. With persistent mapping across the execution, the -userspace does not need to provide a list of all required mappings during each -submission. - -The new driver leverages a lot from i915. As for display, the intent is to share -the display code with the i915 driver so that there is maximum reuse there. - -As for the power management area, the goal is to have a much-simplified support -for the system suspend states (S-states), PCI device suspend states (D-states), -GPU/Render suspend states (R-states) and frequency management. It should leverage -as much as possible all the existent PCI-subsystem infrastructure (pm and -runtime_pm) and underlying firmware components such PCODE and GuC for the power -states and frequency decisions. - -Repository: - -https://gitlab.freedesktop.org/drm/xe/kernel (branch drm-xe-next) - -Xe – Platforms -============== -Currently, Xe is already functional and has experimental support for multiple -platforms starting from Tiger Lake, with initial support in userspace implemented -in Mesa (for Iris and Anv, our OpenGL and Vulkan drivers), as well as in NEO -(for OpenCL and Level0). - -During a transition period, platforms will be supported by both Xe and i915. -However, the force_probe mechanism existent in both drivers will allow only one -official and by-default probe at a given time. - -For instance, in order to probe a DG2 which PCI ID is 0x5690 by Xe instead of -i915, the following set of parameters need to be used: - -``` -i915.force_probe=!5690 xe.force_probe=5690 -``` - -In both drivers, the ‘.require_force_probe’ protection forces the user to use the -force_probe parameter while the driver is under development. This protection is -only removed when the support for the platform and the uAPI are stable. Stability -which needs to be demonstrated by CI results. - -In order to avoid user space regressions, i915 will continue to support all the -current platforms that are already out of this protection. Xe support will be -forever experimental and dependent on the usage of force_probe for these -platforms. - -When the time comes for Xe, the protection will be lifted on Xe and kept in i915. - -Xe – Pre-Merge Goals - Work-in-Progress -======================================= - -Display integration with i915 ------------------------------ -In order to share the display code with the i915 driver so that there is maximum -reuse, the i915/display/ code is built twice, once for i915.ko and then for -xe.ko. Currently, the i915/display code in Xe tree is polluted with many 'ifdefs' -depending on the build target. The goal is to refactor both Xe and i915/display -code simultaneously in order to get a clean result before they land upstream, so -that display can already be part of the initial pull request towards drm-next. - -However, display code should not gate the acceptance of Xe in upstream. Xe -patches will be refactored in a way that display code can be removed, if needed, -from the first pull request of Xe towards drm-next. The expectation is that when -both drivers are part of the drm-tip, the introduction of cleaner patches will be -easier and speed up. - -Xe – uAPI high level overview -============================= - -...Warning: To be done in follow up patches after/when/where the main consensus in various items are individually reached. - -Xe – Pre-Merge Goals - Completed -================================ - -Drm_exec --------- -Helper to make dma_resv locking for a big number of buffers is getting removed in -the drm_exec series proposed in https://patchwork.freedesktop.org/patch/524376/ -If that happens, Xe needs to change and incorporate the changes in the driver. -The goal is to engage with the Community to understand if the best approach is to -move that to the drivers that are using it or if we should keep the helpers in -place waiting for Xe to get merged. - -This item ties into the GPUVA, VM_BIND, and even long-running compute support. - -As a key measurable result, we need to have a community consensus documented in -this document and the Xe driver prepared for the changes, if necessary. - -Userptr integration and vm_bind -------------------------------- -Different drivers implement different ways of dealing with execution of userptr. -With multiple drivers currently introducing support to VM_BIND, the goal is to -aim for a DRM consensus on what’s the best way to have that support. To some -extent this is already getting addressed itself with the GPUVA where likely the -userptr will be a GPUVA with a NULL GEM call VM bind directly on the userptr. -However, there are more aspects around the rules for that and the usage of -mmu_notifiers, locking and other aspects. - -This task here has the goal of introducing a documentation of the basic rules. - -The documentation *needs* to first live in this document (API session below) and -then moved to another more specific document or at Xe level or at DRM level. - -Documentation should include: - - * The userptr part of the VM_BIND api. - - * Locking, including the page-faulting case. - - * O(1) complexity under VM_BIND. - -The document is now included in the drm documentation :doc:`here `. - -Some parts of userptr like mmu_notifiers should become GPUVA or DRM helpers when -the second driver supporting VM_BIND+userptr appears. Details to be defined when -the time comes. - -The DRM GPUVM helpers do not yet include the userptr parts, but discussions -about implementing them are ongoing. - -ASYNC VM_BIND -------------- -Although having a common DRM level IOCTL for VM_BIND is not a requirement to get -Xe merged, it is mandatory to have a consensus with other drivers and Mesa. -It needs to be clear how to handle async VM_BIND and interactions with userspace -memory fences. Ideally with helper support so people don't get it wrong in all -possible ways. - -As a key measurable result, the benefits of ASYNC VM_BIND and a discussion of -various flavors, error handling and sample API suggestions are documented in -:doc:`The ASYNC VM_BIND document `. - -Drm_scheduler -------------- -Xe primarily uses Firmware based scheduling (GuC FW). However, it will use -drm_scheduler as the scheduler ‘frontend’ for userspace submission in order to -resolve syncobj and dma-buf implicit sync dependencies. However, drm_scheduler is -not yet prepared to handle the 1-to-1 relationship between drm_gpu_scheduler and -drm_sched_entity. - -Deeper changes to drm_scheduler should *not* be required to get Xe accepted, but -some consensus needs to be reached between Xe and other community drivers that -could also benefit from this work, for coupling FW based/assisted submission such -as the ARM’s new Mali GPU driver, and others. - -As a key measurable result, the patch series introducing Xe itself shall not -depend on any other patch touching drm_scheduler itself that was not yet merged -through drm-misc. This, by itself, already includes the reach of an agreement for -uniform 1 to 1 relationship implementation / usage across drivers. - -Long running compute: minimal data structure/scaffolding --------------------------------------------------------- -The generic scheduler code needs to include the handling of endless compute -contexts, with the minimal scaffolding for preempt-ctx fences (probably on the -drm_sched_entity) and making sure drm_scheduler can cope with the lack of job -completion fence. - -The goal is to achieve a consensus ahead of Xe initial pull-request, ideally with -this minimal drm/scheduler work, if needed, merged to drm-misc in a way that any -drm driver, including Xe, could re-use and add their own individual needs on top -in a next stage. However, this should not block the initial merge. - -Dev_coredump ------------- - -Xe needs to align with other drivers on the way that the error states are -dumped, avoiding a Xe only error_state solution. The goal is to use devcoredump -infrastructure to report error states, since it produces a standardized way -by exposing a virtual and temporary /sys/class/devcoredump device. - -As the key measurable result, Xe driver needs to provide GPU snapshots captured -at hang time through devcoredump, but without depending on any core modification -of devcoredump infrastructure itself. - -Later, when we are in-tree, the goal is to collaborate with devcoredump -infrastructure with overall possible improvements, like multiple file support -for better organization of the dumps, snapshot support, dmesg extra print, -and whatever may make sense and help the overall infrastructure. - -DRM_VM_BIND ------------ -Nouveau, and Xe are all implementing ‘VM_BIND’ and new ‘Exec’ uAPIs in order to -fulfill the needs of the modern uAPI. Xe merge should *not* be blocked on the -development of a common new drm_infrastructure. However, the Xe team needs to -engage with the community to explore the options of a common API. - -As a key measurable result, the DRM_VM_BIND needs to be documented in this file -below, or this entire block deleted if the consensus is for independent drivers -vm_bind ioctls. - -Although having a common DRM level IOCTL for VM_BIND is not a requirement to get -Xe merged, it is mandatory to enforce the overall locking scheme for all major -structs and list (so vm and vma). So, a consensus is needed, and possibly some -common helpers. If helpers are needed, they should be also documented in this -document. - -GPU VA ------- -Two main goals of Xe are meeting together here: - -1) Have an uAPI that aligns with modern UMD needs. - -2) Early upstream engagement. - -RedHat engineers working on Nouveau proposed a new DRM feature to handle keeping -track of GPU virtual address mappings. This is still not merged upstream, but -this aligns very well with our goals and with our VM_BIND. The engagement with -upstream and the port of Xe towards GPUVA is already ongoing. - -As a key measurable result, Xe needs to be aligned with the GPU VA and working in -our tree. Missing Nouveau patches should *not* block Xe and any needed GPUVA -related patch should be independent and present on dri-devel or acked by -maintainers to go along with the first Xe pull request towards drm-next. diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 41a264bf84ce02127ee00ac646b216ed532a9963..fb9ad120b141478a657012f752a5207e98984c73 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -120,6 +120,29 @@ Contact: Daniel Vetter, respective driver maintainers Level: Advanced +Rename drm_atomic_state +----------------------- + +The KMS framework uses two slightly different definitions for the ``state`` +concept. For a given object (plane, CRTC, encoder, etc., so +``drm_$OBJECT_state``), the state is the entire state of that object. However, +at the device level, ``drm_atomic_state`` refers to a state update for a +limited number of objects. + +The state isn't the entire device state, but only the full state of some +objects in that device. This is confusing to newcomers, and +``drm_atomic_state`` should be renamed to something clearer like +``drm_atomic_commit``. + +In addition to renaming the structure itself, it would also imply renaming some +related functions (``drm_atomic_state_alloc``, ``drm_atomic_state_get``, +``drm_atomic_state_put``, ``drm_atomic_state_init``, +``__drm_atomic_state_free``, etc.). + +Contact: Maxime Ripard + +Level: Advanced + Fallout from atomic KMS ----------------------- diff --git a/Documentation/netlink/specs/rt_link.yaml b/Documentation/netlink/specs/rt_link.yaml index 1ad01d52a8638dcf6ee8a1c6c3d58698abd0d8e4..8e4d19adee8cd17eae831db73692c9237b5e0ad1 100644 --- a/Documentation/netlink/specs/rt_link.yaml +++ b/Documentation/netlink/specs/rt_link.yaml @@ -942,6 +942,10 @@ attribute-sets: - name: gro-ipv4-max-size type: u32 + - + name: dpll-pin + type: nest + nested-attributes: link-dpll-pin-attrs - name: af-spec-attrs attributes: @@ -1627,6 +1631,12 @@ attribute-sets: - name: used type: u8 + - + name: link-dpll-pin-attrs + attributes: + - + name: id + type: u32 sub-messages: - diff --git a/Documentation/sphinx/templates/kernel-toc.html b/Documentation/sphinx/templates/kernel-toc.html index b58efa99df527d3d870d9572e6ee7f18912fe99f..41f1efbe64bb2898f1770deb128630b316a68a08 100644 --- a/Documentation/sphinx/templates/kernel-toc.html +++ b/Documentation/sphinx/templates/kernel-toc.html @@ -12,5 +12,7 @@ diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst index 8cd62c466d20aac597fa5aa15ecfb2930c15c252..077dfac7ed98f7911d731312eb09631e41c63772 100644 --- a/Documentation/usb/gadget-testing.rst +++ b/Documentation/usb/gadget-testing.rst @@ -448,17 +448,17 @@ Function-specific configfs interface The function name to use when creating the function directory is "ncm". The NCM function provides these attributes in its function directory: - =============== ================================================== - ifname network device interface name associated with this - function instance - qmult queue length multiplier for high and super speed - host_addr MAC address of host's end of this - Ethernet over USB link - dev_addr MAC address of device's end of this - Ethernet over USB link - max_segment_size Segment size required for P2P connections. This - will set MTU to (max_segment_size - 14 bytes) - =============== ================================================== + ======================= ================================================== + ifname network device interface name associated with this + function instance + qmult queue length multiplier for high and super speed + host_addr MAC address of host's end of this + Ethernet over USB link + dev_addr MAC address of device's end of this + Ethernet over USB link + max_segment_size Segment size required for P2P connections. This + will set MTU to 14 bytes + ======================= ================================================== and after creating the functions/ncm. they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. diff --git a/MAINTAINERS b/MAINTAINERS index 8d1052fa6a6924d17a4d2681fa7907c544e35186..3bc7e122a094e8fa98111374031131c816d105e2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3168,10 +3168,10 @@ F: drivers/hwmon/asus-ec-sensors.c ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS M: Corentin Chary -L: acpi4asus-user@lists.sourceforge.net +M: Luke D. Jones L: platform-driver-x86@vger.kernel.org S: Maintained -W: http://acpi4asus.sf.net +W: https://asus-linux.org/ F: drivers/platform/x86/asus*.c F: drivers/platform/x86/eeepc*.c @@ -4547,7 +4547,7 @@ F: drivers/net/ieee802154/ca8210.c CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS M: David Howells -L: linux-cachefs@redhat.com (moderated for non-subscribers) +L: netfs@lists.linux.dev S: Supported F: Documentation/filesystems/caching/cachefiles.rst F: fs/cachefiles/ @@ -5958,7 +5958,6 @@ S: Maintained F: drivers/platform/x86/dell/dell-wmi-descriptor.c DELL WMI HARDWARE PRIVACY SUPPORT -M: Perry Yuan L: Dell.Client.Kernel@dell.com L: platform-driver-x86@vger.kernel.org S: Maintained @@ -7309,6 +7308,7 @@ F: drivers/gpu/drm/xlnx/ DRM GPU SCHEDULER M: Luben Tuikov +M: Matthew Brost L: dri-devel@lists.freedesktop.org S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc @@ -7955,12 +7955,13 @@ L: rust-for-linux@vger.kernel.org S: Maintained F: rust/kernel/net/phy.rs -EXEC & BINFMT API +EXEC & BINFMT API, ELF R: Eric Biederman R: Kees Cook L: linux-mm@kvack.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/execve +F: Documentation/userspace-api/ELF.rst F: fs/*binfmt_*.c F: fs/exec.c F: include/linux/binfmts.h @@ -8223,7 +8224,8 @@ F: include/linux/iomap.h FILESYSTEMS [NETFS LIBRARY] M: David Howells -L: linux-cachefs@redhat.com (moderated for non-subscribers) +R: Jeff Layton +L: netfs@lists.linux.dev L: linux-fsdevel@vger.kernel.org S: Supported F: Documentation/filesystems/caching/ @@ -10090,7 +10092,7 @@ L: linux-i2c@vger.kernel.org S: Maintained W: https://i2c.wiki.kernel.org/ Q: https://patchwork.ozlabs.org/project/linux-i2c/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git F: Documentation/devicetree/bindings/i2c/ F: drivers/i2c/algos/ F: drivers/i2c/busses/ @@ -10282,7 +10284,7 @@ F: drivers/scsi/ibmvscsi/ibmvscsi* F: include/scsi/viosrp.h IBM Power Virtual SCSI Device Target Driver -M: Michael Cyr +M: Tyrel Datwyler L: linux-scsi@vger.kernel.org L: target-devel@vger.kernel.org S: Supported @@ -10466,7 +10468,6 @@ F: drivers/media/rc/img-ir/ IMGTEC POWERVR DRM DRIVER M: Frank Binns -M: Donald Robson M: Matt Coster S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc @@ -11724,6 +11725,7 @@ F: fs/smb/server/ KERNEL UNIT TESTING FRAMEWORK (KUnit) M: Brendan Higgins M: David Gow +R: Rae Moar L: linux-kselftest@vger.kernel.org L: kunit-dev@googlegroups.com S: Maintained @@ -12902,6 +12904,8 @@ M: Alejandro Colomar L: linux-man@vger.kernel.org S: Maintained W: http://www.kernel.org/doc/man-pages +T: git git://git.kernel.org/pub/scm/docs/man-pages/man-pages.git +T: git git://www.alejandro-colomar.es/src/alx/linux/man-pages/man-pages.git MANAGEMENT COMPONENT TRANSPORT PROTOCOL (MCTP) M: Jeremy Kerr @@ -15177,6 +15181,7 @@ F: Documentation/networking/net_cachelines/net_device.rst F: drivers/connector/ F: drivers/net/ F: include/dt-bindings/net/ +F: include/linux/cn_proc.h F: include/linux/etherdevice.h F: include/linux/fcdevice.h F: include/linux/fddidevice.h @@ -15184,6 +15189,7 @@ F: include/linux/hippidevice.h F: include/linux/if_* F: include/linux/inetdevice.h F: include/linux/netdevice.h +F: include/uapi/linux/cn_proc.h F: include/uapi/linux/if_* F: include/uapi/linux/netdevice.h X: drivers/net/wireless/ @@ -16856,9 +16862,8 @@ F: Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml F: drivers/pci/controller/pcie-xilinx-cpm.c PCI ENDPOINT SUBSYSTEM -M: Lorenzo Pieralisi +M: Manivannan Sadhasivam M: Krzysztof Wilczyński -R: Manivannan Sadhasivam R: Kishon Vijay Abraham I L: linux-pci@vger.kernel.org S: Supported @@ -18081,7 +18086,6 @@ F: drivers/net/ethernet/qualcomm/emac/ QUALCOMM ETHQOS ETHERNET DRIVER M: Vinod Koul -R: Bhupesh Sharma L: netdev@vger.kernel.org L: linux-arm-msm@vger.kernel.org S: Maintained @@ -20549,6 +20553,7 @@ F: Documentation/translations/sp_SP/ SPARC + UltraSPARC (sparc/sparc64) M: "David S. Miller" +M: Andreas Larsson L: sparclinux@vger.kernel.org S: Maintained Q: http://patchwork.ozlabs.org/project/sparclinux/list/ @@ -24339,13 +24344,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git F: Documentation/filesystems/zonefs.rst F: fs/zonefs/ -ZPOOL COMPRESSED PAGE STORAGE API -M: Dan Streetman -L: linux-mm@kvack.org -S: Maintained -F: include/linux/zpool.h -F: mm/zpool.c - ZR36067 VIDEO FOR LINUX DRIVER M: Corentin Labbe L: mjpeg-users@lists.sourceforge.net @@ -24397,7 +24395,9 @@ M: Nhat Pham L: linux-mm@kvack.org S: Maintained F: Documentation/admin-guide/mm/zswap.rst +F: include/linux/zpool.h F: include/linux/zswap.h +F: mm/zpool.c F: mm/zswap.c THE REST diff --git a/Makefile b/Makefile index 9869f57c3fb3e6a37e40aa267737a044a5e099d8..a171eafce2a3b98d025cc071e54d3bf3c84f2446 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 6 PATCHLEVEL = 8 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc3 NAME = Hurr durr I'ma ninja sloth # *DOCUMENTATION* @@ -294,15 +294,15 @@ may-sync-config := 1 single-build := ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) - ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) + ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) need-config := - endif + endif endif ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),) - ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),) + ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),) may-sync-config := - endif + endif endif need-compiler := $(may-sync-config) @@ -323,9 +323,9 @@ endif # We cannot build single targets and the others at the same time ifneq ($(filter $(single-targets), $(MAKECMDGOALS)),) single-build := 1 - ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),) + ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),) mixed-build := 1 - endif + endif endif # For "make -j clean all", "make -j mrproper defconfig all", etc. @@ -986,6 +986,10 @@ NOSTDINC_FLAGS += -nostdinc # perform bounds checking. KBUILD_CFLAGS += $(call cc-option, -fstrict-flex-arrays=3) +#Currently, disable -Wstringop-overflow for GCC 11, globally. +KBUILD_CFLAGS-$(CONFIG_CC_NO_STRINGOP_OVERFLOW) += $(call cc-option, -Wno-stringop-overflow) +KBUILD_CFLAGS-$(CONFIG_CC_STRINGOP_OVERFLOW) += $(call cc-option, -Wstringop-overflow) + # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += -fno-strict-overflow @@ -1662,7 +1666,7 @@ help: @echo ' (sparse by default)' @echo ' make C=2 [targets] Force check of all c source with $$CHECK' @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' - @echo ' make W=n [targets] Enable extra build checks, n=1,2,3 where' + @echo ' make W=n [targets] Enable extra build checks, n=1,2,3,c,e where' @echo ' 1: warnings which may be relevant and do not occur too often' @echo ' 2: warnings which occur quite often but may still be relevant' @echo ' 3: more obscure warnings, can most likely be ignored' diff --git a/arch/Kconfig b/arch/Kconfig index c91917b508736d1fa0d37d5bf3b1e4bf5550e211..a5af0edd3eb8f3b64e6e51bffb2ac491cb31bc26 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -673,6 +673,7 @@ config SHADOW_CALL_STACK bool "Shadow Call Stack" depends on ARCH_SUPPORTS_SHADOW_CALL_STACK depends on DYNAMIC_FTRACE_WITH_ARGS || DYNAMIC_FTRACE_WITH_REGS || !FUNCTION_GRAPH_TRACER + depends on MMU help This option enables the compiler's Shadow Call Stack, which uses a shadow stack to protect function return addresses from diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts index e899de681f4752d4077b55a0cd4f8858c6e23df0..5be0e8fd2633c20e2d87abc843b53fca437942be 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts @@ -45,8 +45,8 @@ num-chipselects = <1>; cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>; - tpmdev@0 { - compatible = "tcg,tpm_tis-spi"; + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; spi-max-frequency = <33000000>; reg = <0>; }; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts index a677c827e758fe2042fcf14a192832668e3ffbd0..5a8169bbda8792c76c1da960508c8a0c6bdd4b86 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts @@ -80,8 +80,8 @@ gpio-miso = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>; num-chipselects = <1>; - tpmdev@0 { - compatible = "tcg,tpm_tis-spi"; + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; spi-max-frequency = <33000000>; reg = <0>; }; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts index 3f6010ef2b86f264fe88935a737b3ce9c60d762b..213023bc5aec4144751c9e7bc8e3e05c156386c8 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts @@ -456,7 +456,7 @@ status = "okay"; tpm: tpm@2e { - compatible = "tcg,tpm-tis-i2c"; + compatible = "nuvoton,npct75x", "tcg,tpm-tis-i2c"; reg = <0x2e>; }; }; diff --git a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi index 31590d3186a2e099e44c663c46a87975b60aae27..00e5887c926f181d57bebe6b0b781ad2f2e8a514 100644 --- a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi +++ b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi @@ -35,8 +35,8 @@ gpio-mosi = <&gpio0 ASPEED_GPIO(X, 4) GPIO_ACTIVE_HIGH>; gpio-miso = <&gpio0 ASPEED_GPIO(X, 5) GPIO_ACTIVE_HIGH>; - tpmdev@0 { - compatible = "tcg,tpm_tis-spi"; + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; spi-max-frequency = <33000000>; reg = <0>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi index 44cc4ff1d0df358ab66bb036d127175da1be74b6..d12fb44aeb140cfacf05a5b257d2106c79392279 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi @@ -116,7 +116,7 @@ tpm_tis: tpm@1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tpm>; - compatible = "tcg,tpm_tis-spi"; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; reg = <1>; spi-max-frequency = <20000000>; interrupt-parent = <&gpio5>; diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts b/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts index 3a723843d5626f6cc4b9ee2750968c01e46306db..9984b343cdf0cad1abd9e0d4d142ded838c47980 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts +++ b/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts @@ -130,7 +130,7 @@ * TCG specification - Section 6.4.1 Clocking: * TPM shall support a SPI clock frequency range of 10-24 MHz. */ - st33htph: tpm-tis@0 { + st33htph: tpm@0 { compatible = "st,st33htpm-spi", "tcg,tpm_tis-spi"; reg = <0>; spi-max-frequency = <24000000>; diff --git a/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi b/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi index d7954ff466b491b32acf6962ab5d64f4843f8157..e5254e32aa8fc326dfcabce33705a9b25e272052 100644 --- a/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi +++ b/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi @@ -434,6 +434,7 @@ }; &fimd { + samsung,invert-vclk; status = "okay"; }; diff --git a/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi b/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi index b8730aa52ce6fe521a1b531be42c4ef891c969b5..a59331aa58e55e3ef514fc06b5a36472c901dcd3 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi @@ -217,7 +217,7 @@ pinctrl-names = "default"; pinctrl-0 = <&spi1_pins>; - tpm_spi_tis@0 { + tpm@0 { compatible = "tcg,tpm_tis-spi"; reg = <0>; spi-max-frequency = <500000>; diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 47ecc4cff9d25b7752c94df9ab574ec52cbabd28..a88cdf91068713ebefc031f438b3b22a0247f943 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -195,7 +195,7 @@ vdso_prepare: prepare0 include/generated/vdso-offsets.h arch/arm64/kernel/vdso/vdso.so ifdef CONFIG_COMPAT_VDSO $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \ - include/generated/vdso32-offsets.h arch/arm64/kernel/vdso32/vdso.so + arch/arm64/kernel/vdso32/vdso.so endif endif diff --git a/arch/arm64/boot/dts/exynos/google/gs101.dtsi b/arch/arm64/boot/dts/exynos/google/gs101.dtsi index 9747cb3fa03ac5c141b9bf660da3531ca2082def..d838e3a7af6e5ddda3751cc6f0bf4c73bccacc03 100644 --- a/arch/arm64/boot/dts/exynos/google/gs101.dtsi +++ b/arch/arm64/boot/dts/exynos/google/gs101.dtsi @@ -289,7 +289,7 @@ #clock-cells = <1>; clocks = <&cmu_top CLK_DOUT_CMU_MISC_BUS>, <&cmu_top CLK_DOUT_CMU_MISC_SSS>; - clock-names = "dout_cmu_misc_bus", "dout_cmu_misc_sss"; + clock-names = "bus", "sss"; }; watchdog_cl0: watchdog@10060000 { diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts b/arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts index 968f475b9a96c3c7334d670fd004ddcde08eed6f..27a902569e2a28434af3b6b15dcdb3a43f7a9606 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts @@ -120,7 +120,7 @@ }; tpm: tpm@1 { - compatible = "tcg,tpm_tis-spi"; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; interrupt-parent = <&gpio2>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi index 3f3f2a2c89cd504f22548178b0d718ed61d122fa..752caa38eb03bfd6831e61f857b517beb5bfe1a1 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi @@ -89,7 +89,7 @@ status = "okay"; tpm@1 { - compatible = "tcg,tpm_tis-spi"; + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; reg = <0x1>; spi-max-frequency = <36000000>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi index 06fed93769966367b02c0a3d5f44f8264c080617..2aa6c1090fc7d7b81f7774354286c13a5463c06b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi @@ -109,7 +109,7 @@ status = "okay"; tpm@1 { - compatible = "tcg,tpm_tis-spi"; + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; reg = <0x1>; spi-max-frequency = <36000000>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts b/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts index feae77e038354c687d69904fdb5b577f32cfe26d..a08057410bdef5b3a2572cb5c5e2fe6ea35b5522 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts @@ -234,7 +234,7 @@ status = "okay"; tpm: tpm@0 { - compatible = "infineon,slb9670"; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tpm>; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi index c24587c895e1f9734da4c4f4cf7becb697825f59..41c79d2ebdd6201dc10278204c064a4c01c71709 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi @@ -103,7 +103,7 @@ status = "okay"; tpm@1 { - compatible = "tcg,tpm_tis-spi"; + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; reg = <0x1>; spi-max-frequency = <36000000>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi index 628ffba69862ad51f2072e88fc812b3a84e1b71c..d5c400b355af564123497cd1805e0b0ad56ded21 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi @@ -115,7 +115,7 @@ status = "okay"; tpm@1 { - compatible = "tcg,tpm_tis-spi"; + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; reg = <0x1>; spi-max-frequency = <36000000>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts index 9caf7ca25444600a4a7979b3749d5175e32b0bbe..cae586cd45bdd59aa479e70bb290fc50b0392a3c 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts @@ -196,7 +196,7 @@ status = "okay"; tpm@0 { - compatible = "tcg,tpm_tis-spi"; + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; reg = <0x0>; spi-max-frequency = <36000000>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts b/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts index 6376417e918c2083bb67c2f978d53602153d3cb9..d8cf1f27c3ec8a33b7ad527c1fc2b489747a2d84 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts @@ -65,7 +65,7 @@ status = "okay"; tpm@0 { - compatible = "infineon,slb9670"; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; reg = <0>; spi-max-frequency = <43000000>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi index 5506de83f61d423634511fba3f783f67a8987792..1b3396b1cee394659d0a77c104f05e1e7762569f 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi @@ -888,7 +888,7 @@ status = "okay"; cs-gpios = <&pio 86 GPIO_ACTIVE_LOW>; - cr50@0 { + tpm@0 { compatible = "google,cr50"; reg = <0>; spi-max-frequency = <1000000>; diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi index f2281250ac35da2514d73191cbcdb2e195afcbcb..d87aab8d7a79ed4ac8365b951f16c370b2efcc91 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi @@ -1402,7 +1402,7 @@ pinctrl-names = "default"; pinctrl-0 = <&spi5_pins>; - cr50@0 { + tpm@0 { compatible = "google,cr50"; reg = <0>; interrupts-extended = <&pio 171 IRQ_TYPE_EDGE_RISING>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts index 0f9cc042d9bf06b3445c2cb125435c823f3b26b4..1cba1d857c96ba06e3f257b8a15f20a99a9250ee 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts @@ -70,7 +70,7 @@ &spi0 { status = "okay"; - cr50@0 { + tpm@0 { compatible = "google,cr50"; reg = <0>; interrupt-parent = <&gpio0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi index c5e7de60c12140c0dae9789cc338ef5f1b9fac3c..5846a11f0e848fc059446a47b57ff732b45e9f4c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi @@ -706,7 +706,7 @@ camera: &i2c7 { &spi2 { status = "okay"; - cr50@0 { + tpm@0 { compatible = "google,cr50"; reg = <0>; interrupt-parent = <&gpio1>; diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h index b4ae3210993273e8fd709b8f4d17a081bf39ff3d..4305995c8f82f416e6ce11280ac1dd19fbe25eec 100644 --- a/arch/arm64/include/asm/vdso.h +++ b/arch/arm64/include/asm/vdso.h @@ -17,9 +17,6 @@ #ifndef __ASSEMBLY__ #include -#ifdef CONFIG_COMPAT_VDSO -#include -#endif #define VDSO_SYMBOL(base, name) \ ({ \ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index e5d03a7039b4bf9cce893b1ea39712eef3e2f4ad..467cb711727309eb991df38ece1af46b858e6178 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -77,9 +77,9 @@ obj-$(CONFIG_UNWIND_PATCH_PAC_INTO_SCS) += patch-scs.o # We need to prevent the SCS patching code from patching itself. Using # -mbranch-protection=none here to avoid the patchable PAC opcodes from being # generated triggers an issue with full LTO on Clang, which stops emitting PAC -# instructions altogether. So instead, omit the unwind tables used by the -# patching code, so it will not be able to locate its own PAC instructions. -CFLAGS_patch-scs.o += -fno-asynchronous-unwind-tables -fno-unwind-tables +# instructions altogether. So disable LTO as well for the compilation unit. +CFLAGS_patch-scs.o += -mbranch-protection=none +CFLAGS_REMOVE_patch-scs.o += $(CC_FLAGS_LTO) # Force dependency (vdso*-wrap.S includes vdso.so through incbin) $(obj)/vdso-wrap.o: $(obj)/vdso/vdso.so diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile index 2266fcdff78a0740fcd72a5c8125d17938d88df4..f5f80fdce0fe7aa2ab3b14ce931999b954312162 100644 --- a/arch/arm64/kernel/vdso32/Makefile +++ b/arch/arm64/kernel/vdso32/Makefile @@ -127,9 +127,6 @@ obj-vdso := $(c-obj-vdso) $(c-obj-vdso-gettimeofday) $(asm-obj-vdso) targets += vdso.lds CPPFLAGS_vdso.lds += -P -C -U$(ARCH) -include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE - $(call if_changed,vdsosym) - # Strip rule for vdso.so $(obj)/vdso.so: OBJCOPYFLAGS := -S $(obj)/vdso.so: $(obj)/vdso32.so.dbg FORCE @@ -166,9 +163,3 @@ quiet_cmd_vdsoas = AS32 $@ quiet_cmd_vdsomunge = MUNGE $@ cmd_vdsomunge = $(obj)/$(munge) $< $@ - -# Generate vDSO offsets using helper script (borrowed from the 64-bit vDSO) -gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh -quiet_cmd_vdsosym = VDSOSYM $@ -# The AArch64 nm should be able to read an AArch32 binary - cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h index e71ceb88f29eecdbebe40c407c1a93e4cd433337..0cb4fdb8a9b5970dfefb24a34c82d1451ff27fa9 100644 --- a/arch/loongarch/include/asm/kvm_vcpu.h +++ b/arch/loongarch/include/asm/kvm_vcpu.h @@ -60,7 +60,7 @@ int kvm_own_lsx(struct kvm_vcpu *vcpu); void kvm_save_lsx(struct loongarch_fpu *fpu); void kvm_restore_lsx(struct loongarch_fpu *fpu); #else -static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { } +static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { return -EINVAL; } static inline void kvm_save_lsx(struct loongarch_fpu *fpu) { } static inline void kvm_restore_lsx(struct loongarch_fpu *fpu) { } #endif @@ -70,7 +70,7 @@ int kvm_own_lasx(struct kvm_vcpu *vcpu); void kvm_save_lasx(struct loongarch_fpu *fpu); void kvm_restore_lasx(struct loongarch_fpu *fpu); #else -static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { } +static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { return -EINVAL; } static inline void kvm_save_lasx(struct loongarch_fpu *fpu) { } static inline void kvm_restore_lasx(struct loongarch_fpu *fpu) { } #endif diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index a16e3dbe9f09eb2fbf1b239b982b727330f7c233..2b49d30eb7c0185e043e462859e76a4ae64ecd67 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -509,7 +509,6 @@ asmlinkage void start_secondary(void) sync_counter(); cpu = raw_smp_processor_id(); set_my_cpu_offset(per_cpu_offset(cpu)); - rcutree_report_cpu_starting(cpu); cpu_probe(); constant_clockevent_init(); diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c index 915f175278931f26164c1b970663542cf0661a12..50a6acd7ffe4c94b986c5f7a9802420f090a7d79 100644 --- a/arch/loongarch/kvm/mmu.c +++ b/arch/loongarch/kvm/mmu.c @@ -675,7 +675,7 @@ static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot, * * There are several ways to safely use this helper: * - * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before + * - Check mmu_invalidate_retry_gfn() after grabbing the mapping level, before * consuming it. In this case, mmu_lock doesn't need to be held during the * lookup, but it does need to be held while checking the MMU notifier. * @@ -855,7 +855,7 @@ retry: /* Check if an invalidation has taken place since we got pfn */ spin_lock(&kvm->mmu_lock); - if (mmu_invalidate_retry_hva(kvm, mmu_seq, hva)) { + if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn)) { /* * This can happen when mappings are changed asynchronously, but * also synchronously if a COW is triggered by diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c index 2c0a411f23aa778bb62160bd511252736fc987be..0b95d32b30c94704a0108fdffcae68c148403ce7 100644 --- a/arch/loongarch/mm/tlb.c +++ b/arch/loongarch/mm/tlb.c @@ -284,12 +284,16 @@ static void setup_tlb_handler(int cpu) set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE); set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE); set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE); - } + } else { + int vec_sz __maybe_unused; + void *addr __maybe_unused; + struct page *page __maybe_unused; + + /* Avoid lockdep warning */ + rcutree_report_cpu_starting(cpu); + #ifdef CONFIG_NUMA - else { - void *addr; - struct page *page; - const int vec_sz = sizeof(exception_handlers); + vec_sz = sizeof(exception_handlers); if (pcpu_handlers[cpu]) return; @@ -305,8 +309,8 @@ static void setup_tlb_handler(int cpu) csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_EENTRY); csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_MERRENTRY); csr_write64(pcpu_handlers[cpu] + 80*VECSIZE, LOONGARCH_CSR_TLBRENTRY); - } #endif + } } void tlb_init(int cpu) diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 43e39040d3ac6cd38a4bd4fc3dc04e03d5c71bf5..76ef1a67c3611bbcd864d27fe59127c4c27f038a 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -15,10 +15,10 @@ KBUILD_DEFCONFIG := multi_defconfig ifdef cross_compiling - ifeq ($(CROSS_COMPILE),) + ifeq ($(CROSS_COMPILE),) CROSS_COMPILE := $(call cc-cross-prefix, \ m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-) - endif + endif endif # diff --git a/arch/mips/alchemy/common/prom.c b/arch/mips/alchemy/common/prom.c index b13d8adf3be47dbfd6f65e1e63ee3217feafe04b..20d30f6265cdce2a915ddffc52d0bb67e6e0edac 100644 --- a/arch/mips/alchemy/common/prom.c +++ b/arch/mips/alchemy/common/prom.c @@ -40,6 +40,7 @@ #include #include +#include int prom_argc; char **prom_argv; diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 2388d68786f4a7c40dcadfed78fd8ecfc91f4896..a7a6d31a7a4148ada6ad340d0723ef8c7a73f0be 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -30,13 +30,11 @@ #include #include /* for dma_default_coherent */ +#include #include #include -extern void __init board_setup(void); -extern void __init alchemy_set_lpj(void); - static bool alchemy_dma_coherent(void) { switch (alchemy_get_cputype()) { diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index 01aff80a59672dee1b675c3625aecb6f70eb52b9..99f321b6e417bd4250ab7cec31ae74ad2d396ec3 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -702,7 +702,7 @@ static struct ssb_sprom bcm63xx_sprom = { .boardflags_hi = 0x0000, }; -int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +static int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) { if (bus->bustype == SSB_BUSTYPE_PCI) { memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom)); diff --git a/arch/mips/bcm63xx/dev-rng.c b/arch/mips/bcm63xx/dev-rng.c index d277b4dc6c688eb394544b556e0941a54654c1b9..f94151f7c96fe1d988cd3d88f8451bbdf012955c 100644 --- a/arch/mips/bcm63xx/dev-rng.c +++ b/arch/mips/bcm63xx/dev-rng.c @@ -26,7 +26,7 @@ static struct platform_device bcm63xx_rng_device = { .resource = rng_resources, }; -int __init bcm63xx_rng_register(void) +static int __init bcm63xx_rng_register(void) { if (!BCMCPU_IS_6368()) return -ENODEV; diff --git a/arch/mips/bcm63xx/dev-uart.c b/arch/mips/bcm63xx/dev-uart.c index 3bc7f3bfc9ad5c5e45737bcf1510bfcd5b5483e7..5d6bf0445b299cf0e91a4f7992f134e5648ca1c2 100644 --- a/arch/mips/bcm63xx/dev-uart.c +++ b/arch/mips/bcm63xx/dev-uart.c @@ -10,6 +10,7 @@ #include #include #include +#include static struct resource uart0_resources[] = { { diff --git a/arch/mips/bcm63xx/dev-wdt.c b/arch/mips/bcm63xx/dev-wdt.c index 42130914a3c210993c07d971449a424d40775060..302bf7ed5ad5abfaa6cb94e4a4e0dcdf1ffbceb1 100644 --- a/arch/mips/bcm63xx/dev-wdt.c +++ b/arch/mips/bcm63xx/dev-wdt.c @@ -34,7 +34,7 @@ static struct platform_device bcm63xx_wdt_device = { }, }; -int __init bcm63xx_wdt_register(void) +static int __init bcm63xx_wdt_register(void) { wdt_resources[0].start = bcm63xx_regset_address(RSET_WDT); wdt_resources[0].end = wdt_resources[0].start; diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 2548013442f6d95bdda071f89cc112d97d8a0d0a..6240a8f88ea366b5d440f6de3416191dead812b8 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -72,7 +72,7 @@ static inline int enable_irq_for_cpu(int cpu, struct irq_data *d, */ #define BUILD_IPIC_INTERNAL(width) \ -void __dispatch_internal_##width(int cpu) \ +static void __dispatch_internal_##width(int cpu) \ { \ u32 pending[width / 32]; \ unsigned int src, tgt; \ diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index d811e3e03f819a5005a480d56d5aee5a090fcc3c..c13ddb544a23bf0ebfd6bd627c9ed022a44cda0e 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -159,7 +159,7 @@ void __init plat_mem_setup(void) board_setup(); } -int __init bcm63xx_register_devices(void) +static int __init bcm63xx_register_devices(void) { /* register gpiochip */ bcm63xx_gpio_init(); diff --git a/arch/mips/bcm63xx/timer.c b/arch/mips/bcm63xx/timer.c index a86065854c0c8c6c92254c4d7746fda8e6801250..74b83807df30a7be13f1f9466753b2560ce9b50b 100644 --- a/arch/mips/bcm63xx/timer.c +++ b/arch/mips/bcm63xx/timer.c @@ -178,7 +178,7 @@ int bcm63xx_timer_set(int id, int monotonic, unsigned int countdown_us) EXPORT_SYMBOL(bcm63xx_timer_set); -int bcm63xx_timer_init(void) +static int bcm63xx_timer_init(void) { int ret, irq; u32 reg; diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index 2e099d55a564a6ecf3dc347ace84ad25e4278dd9..9a266bf7833993b5facbdb63c97e555ad4d9ce27 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -23,9 +23,6 @@ #include -extern void cobalt_machine_restart(char *command); -extern void cobalt_machine_halt(void); - const char *get_system_type(void) { switch (cobalt_board_id) { diff --git a/arch/mips/fw/arc/memory.c b/arch/mips/fw/arc/memory.c index 66188739f54d20a41ce18acb0a88a4fdf16e8718..fb78e6fd5de4804e221fba63bceeb4dcd4a492a9 100644 --- a/arch/mips/fw/arc/memory.c +++ b/arch/mips/fw/arc/memory.c @@ -37,7 +37,7 @@ static unsigned int nr_prom_mem __initdata; */ #define ARC_PAGE_SHIFT 12 -struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) +static struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) { return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current); } diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index a7eec3364a64abb60f1dae67ad26c80738878533..41546777902ba0fe25af0f442c688169f9220b48 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -597,6 +597,9 @@ #include +void alchemy_set_lpj(void); +void board_setup(void); + /* helpers to access the SYS_* registers */ static inline unsigned long alchemy_rdsys(int regofs) { diff --git a/arch/mips/include/asm/mach-cobalt/cobalt.h b/arch/mips/include/asm/mach-cobalt/cobalt.h index 5b9fce73f11d1301fa5724049bfd9f8625ea7061..97f9d5e9446d22e1371b1c9f6fe09d59610d27ed 100644 --- a/arch/mips/include/asm/mach-cobalt/cobalt.h +++ b/arch/mips/include/asm/mach-cobalt/cobalt.h @@ -19,4 +19,7 @@ extern int cobalt_board_id; #define COBALT_BRD_ID_QUBE2 0x5 #define COBALT_BRD_ID_RAQ2 0x6 +void cobalt_machine_halt(void); +void cobalt_machine_restart(char *command); + #endif /* __ASM_COBALT_H */ diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 5582a4ca1e9e36ad5dac4d23caa4d6c4bfb11a5d..7aa2c2360ff60219bb8fb9f03a8a528edf7f53a1 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -11,6 +11,7 @@ #include #include +#include #ifdef CONFIG_MIPS_FP_SUPPORT @@ -309,6 +310,11 @@ void mips_set_personality_nan(struct arch_elf_state *state) struct cpuinfo_mips *c = &boot_cpu_data; struct task_struct *t = current; + /* Do this early so t->thread.fpu.fcr31 won't be clobbered in case + * we are preempted before the lose_fpu(0) in start_thread. + */ + lose_fpu(0); + t->thread.fpu.fcr31 = c->fpu_csr31; switch (state->nan_2008) { case 0: diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index dec6878b35f627089226618ff4dc4628855c8eb4..a1c1cb5de91321468f338d41a01df2f40efaf293 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2007,7 +2007,13 @@ unsigned long vi_handlers[64]; void reserve_exception_space(phys_addr_t addr, unsigned long size) { - memblock_reserve(addr, size); + /* + * reserve exception space on CPUs other than CPU0 + * is too late, since memblock is unavailable when APs + * up + */ + if (smp_processor_id() == 0) + memblock_reserve(addr, size); } void __init *set_except_vector(int n, void *addr) diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c index a3cf293658581ed6a599da2b870f3c10c67a6be1..0c45767eacf67429ea3910628a2f44c219a4da34 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c @@ -108,10 +108,9 @@ void __init prom_init(void) prom_init_cmdline(); #if defined(CONFIG_MIPS_MT_SMP) - if (cpu_has_mipsmt) { - lantiq_smp_ops = vsmp_smp_ops; + lantiq_smp_ops = vsmp_smp_ops; + if (cpu_has_mipsmt) lantiq_smp_ops.init_secondary = lantiq_init_secondary; - register_smp_ops(&lantiq_smp_ops); - } + register_smp_ops(&lantiq_smp_ops); #endif } diff --git a/arch/mips/loongson64/init.c b/arch/mips/loongson64/init.c index f25caa6aa9d306e84d719e97ea54f7b8faa449c1..553142c1f14fe2261d963b3784f3ed9e6c086cd2 100644 --- a/arch/mips/loongson64/init.c +++ b/arch/mips/loongson64/init.c @@ -103,6 +103,9 @@ void __init szmem(unsigned int node) if (loongson_sysconf.vgabios_addr) memblock_reserve(virt_to_phys((void *)loongson_sysconf.vgabios_addr), SZ_256K); + /* set nid for reserved memory */ + memblock_set_node((u64)node << 44, (u64)(node + 1) << 44, + &memblock.reserved, node); } #ifndef CONFIG_NUMA diff --git a/arch/mips/loongson64/numa.c b/arch/mips/loongson64/numa.c index 8f61e93c0c5bcf07134cc22a06913c57e5140af4..68dafd6d3e2571f615e9c9e7d9b2c895de80468a 100644 --- a/arch/mips/loongson64/numa.c +++ b/arch/mips/loongson64/numa.c @@ -132,6 +132,8 @@ static void __init node_mem_init(unsigned int node) /* Reserve pfn range 0~node[0]->node_start_pfn */ memblock_reserve(0, PAGE_SIZE * start_pfn); + /* set nid for reserved memory on node 0 */ + memblock_set_node(0, 1ULL << 44, &memblock.reserved, 0); } } diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile index 27c14ede191eb7b1353e3a2cedd6d9d80bc2b385..9877fcc512b1578731fb6235a35256a61b172afb 100644 --- a/arch/mips/sgi-ip27/Makefile +++ b/arch/mips/sgi-ip27/Makefile @@ -5,7 +5,7 @@ obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o \ ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o ip27-timer.o \ - ip27-hubio.o ip27-xtalk.o + ip27-xtalk.o obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o obj-$(CONFIG_SMP) += ip27-smp.o diff --git a/arch/mips/sgi-ip27/ip27-berr.c b/arch/mips/sgi-ip27/ip27-berr.c index 923a63a51cda39482c227936c17f828ceae3227b..9eb497cb5d525c74e775ca741bd4ec664209280b 100644 --- a/arch/mips/sgi-ip27/ip27-berr.c +++ b/arch/mips/sgi-ip27/ip27-berr.c @@ -22,6 +22,8 @@ #include #include +#include "ip27-common.h" + static void dump_hub_information(unsigned long errst0, unsigned long errst1) { static char *err_type[2][8] = { @@ -57,7 +59,7 @@ static void dump_hub_information(unsigned long errst0, unsigned long errst1) [st0.pi_stat0_fmt.s0_err_type] ? : "invalid"); } -int ip27_be_handler(struct pt_regs *regs, int is_fixup) +static int ip27_be_handler(struct pt_regs *regs, int is_fixup) { unsigned long errst0, errst1; int data = regs->cp0_cause & 4; diff --git a/arch/mips/sgi-ip27/ip27-common.h b/arch/mips/sgi-ip27/ip27-common.h index ed008a08464c208cc1944cfbd6fe5de31e14fee4..a0059fa13934539af5fb616120f66b77054a2219 100644 --- a/arch/mips/sgi-ip27/ip27-common.h +++ b/arch/mips/sgi-ip27/ip27-common.h @@ -10,6 +10,7 @@ extern void hub_rt_clock_event_init(void); extern void hub_rtc_init(nasid_t nasid); extern void install_cpu_nmi_handler(int slice); extern void install_ipi(void); +extern void ip27_be_init(void); extern void ip27_reboot_setup(void); extern const struct plat_smp_ops ip27_smp_ops; extern unsigned long node_getfirstfree(nasid_t nasid); @@ -17,4 +18,5 @@ extern void per_cpu_init(void); extern void replicate_kernel_text(void); extern void setup_replication_mask(void); + #endif /* __IP27_COMMON_H */ diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c deleted file mode 100644 index c57f0d8f3218674fd6eed08c14bae8caf66d0d08..0000000000000000000000000000000000000000 --- a/arch/mips/sgi-ip27/ip27-hubio.c +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. - * Copyright (C) 2004 Christoph Hellwig. - * - * Support functions for the HUB ASIC - mostly PIO mapping related. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -static int force_fire_and_forget = 1; - -/** - * hub_pio_map - establish a HUB PIO mapping - * - * @nasid: nasid to perform PIO mapping on - * @widget: widget ID to perform PIO mapping for - * @xtalk_addr: xtalk_address that needs to be mapped - * @size: size of the PIO mapping - * - **/ -unsigned long hub_pio_map(nasid_t nasid, xwidgetnum_t widget, - unsigned long xtalk_addr, size_t size) -{ - unsigned i; - - /* use small-window mapping if possible */ - if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE) - return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE); - - if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) { - printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx" - " too big (%ld)\n", - nasid, widget, xtalk_addr, size); - return 0; - } - - xtalk_addr &= ~(BWIN_SIZE-1); - for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) { - if (test_and_set_bit(i, hub_data(nasid)->h_bigwin_used)) - continue; - - /* - * The code below does a PIO write to setup an ITTE entry. - * - * We need to prevent other CPUs from seeing our updated - * memory shadow of the ITTE (in the piomap) until the ITTE - * entry is actually set up; otherwise, another CPU might - * attempt a PIO prematurely. - * - * Also, the only way we can know that an entry has been - * received by the hub and can be used by future PIO reads/ - * writes is by reading back the ITTE entry after writing it. - * - * For these two reasons, we PIO read back the ITTE entry - * after we write it. - */ - IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); - __raw_readq(IIO_ITTE_GET(nasid, i)); - - return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); - } - - printk(KERN_WARNING "unable to establish PIO mapping for at" - " hub %d widget %d addr 0x%lx\n", - nasid, widget, xtalk_addr); - return 0; -} - - -/* - * hub_setup_prb(nasid, prbnum, credits, conveyor) - * - * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, - * put it into conveyor belt mode with the specified number of credits. - */ -static void hub_setup_prb(nasid_t nasid, int prbnum, int credits) -{ - union iprb_u prb; - int prb_offset; - - /* - * Get the current register value. - */ - prb_offset = IIO_IOPRB(prbnum); - prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); - - /* - * Clear out some fields. - */ - prb.iprb_ovflow = 1; - prb.iprb_bnakctr = 0; - prb.iprb_anakctr = 0; - - /* - * Enable or disable fire-and-forget mode. - */ - prb.iprb_ff = force_fire_and_forget ? 1 : 0; - - /* - * Set the appropriate number of PIO credits for the widget. - */ - prb.iprb_xtalkctr = credits; - - /* - * Store the new value to the register. - */ - REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); -} - -/** - * hub_set_piomode - set pio mode for a given hub - * - * @nasid: physical node ID for the hub in question - * - * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode. - * To do this, we have to make absolutely sure that no PIOs are in progress - * so we turn off access to all widgets for the duration of the function. - * - * XXX - This code should really check what kind of widget we're talking - * to. Bridges can only handle three requests, but XG will do more. - * How many can crossbow handle to widget 0? We're assuming 1. - * - * XXX - There is a bug in the crossbow that link reset PIOs do not - * return write responses. The easiest solution to this problem is to - * leave widget 0 (xbow) in fire-and-forget mode at all times. This - * only affects pio's to xbow registers, which should be rare. - **/ -static void hub_set_piomode(nasid_t nasid) -{ - u64 ii_iowa; - union hubii_wcr_u ii_wcr; - unsigned i; - - ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); - REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); - - ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); - - if (ii_wcr.iwcr_dir_con) { - /* - * Assume a bridge here. - */ - hub_setup_prb(nasid, 0, 3); - } else { - /* - * Assume a crossbow here. - */ - hub_setup_prb(nasid, 0, 1); - } - - /* - * XXX - Here's where we should take the widget type into - * when account assigning credits. - */ - for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) - hub_setup_prb(nasid, i, 3); - - REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); -} - -/* - * hub_pio_init - PIO-related hub initialization - * - * @hub: hubinfo structure for our hub - */ -void hub_pio_init(nasid_t nasid) -{ - unsigned i; - - /* initialize big window piomaps for this hub */ - bitmap_zero(hub_data(nasid)->h_bigwin_used, HUB_NUM_BIG_WINDOW); - for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) - IIO_ITTE_DISABLE(nasid, i); - - hub_set_piomode(nasid); -} diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index a0dd3bd2b81b359491b447917486890ebc18fd4b..8f5299b269e7e7d1b104d6fa4616de4f7fdfc34d 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -23,6 +23,8 @@ #include #include +#include "ip27-common.h" + struct hub_irq_data { u64 *irq_mask[2]; cpuid_t cpu; diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index f79c4839371661237141b866d89743a101411c53..b8ca94cfb4fef34b42f9e5307e7dcfc09ef8a6d2 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/sgi-ip27/ip27-nmi.c b/arch/mips/sgi-ip27/ip27-nmi.c index 84889b57d5ff684e32bc2a1897583a0f4770853e..fc2816398d0cf04a48c1f704ade54a65b97e15f8 100644 --- a/arch/mips/sgi-ip27/ip27-nmi.c +++ b/arch/mips/sgi-ip27/ip27-nmi.c @@ -11,6 +11,8 @@ #include #include +#include "ip27-common.h" + #if 0 #define NODE_NUM_CPUS(n) CNODE_NUM_CPUS(n) #else @@ -23,16 +25,7 @@ typedef unsigned long machreg_t; static arch_spinlock_t nmi_lock = __ARCH_SPIN_LOCK_UNLOCKED; - -/* - * Let's see what else we need to do here. Set up sp, gp? - */ -void nmi_dump(void) -{ - void cont_nmi_dump(void); - - cont_nmi_dump(); -} +static void nmi_dump(void); void install_cpu_nmi_handler(int slice) { @@ -53,7 +46,7 @@ void install_cpu_nmi_handler(int slice) * into the eframe format for the node under consideration. */ -void nmi_cpu_eframe_save(nasid_t nasid, int slice) +static void nmi_cpu_eframe_save(nasid_t nasid, int slice) { struct reg_struct *nr; int i; @@ -129,7 +122,7 @@ void nmi_cpu_eframe_save(nasid_t nasid, int slice) pr_emerg("\n"); } -void nmi_dump_hub_irq(nasid_t nasid, int slice) +static void nmi_dump_hub_irq(nasid_t nasid, int slice) { u64 mask0, mask1, pend0, pend1; @@ -153,7 +146,7 @@ void nmi_dump_hub_irq(nasid_t nasid, int slice) * Copy the cpu registers which have been saved in the IP27prom format * into the eframe format for the node under consideration. */ -void nmi_node_eframe_save(nasid_t nasid) +static void nmi_node_eframe_save(nasid_t nasid) { int slice; @@ -170,8 +163,7 @@ void nmi_node_eframe_save(nasid_t nasid) /* * Save the nmi cpu registers for all cpus in the system. */ -void -nmi_eframes_save(void) +static void nmi_eframes_save(void) { nasid_t nasid; @@ -179,8 +171,7 @@ nmi_eframes_save(void) nmi_node_eframe_save(nasid); } -void -cont_nmi_dump(void) +static void nmi_dump(void) { #ifndef REAL_NMI_SIGNAL static atomic_t nmied_cpus = ATOMIC_INIT(0); diff --git a/arch/mips/sgi-ip30/ip30-console.c b/arch/mips/sgi-ip30/ip30-console.c index b91f8c4fdc786011172f8111e7e0dfc3e04705e1..7c6dcf6e73f701c68595bd3b26677ff8d667b56a 100644 --- a/arch/mips/sgi-ip30/ip30-console.c +++ b/arch/mips/sgi-ip30/ip30-console.c @@ -3,6 +3,7 @@ #include #include +#include static inline struct ioc3_uartregs *console_uart(void) { diff --git a/arch/mips/sgi-ip30/ip30-setup.c b/arch/mips/sgi-ip30/ip30-setup.c index 75a34684e7045977a89faa54b1ec740eb13af5ff..e8547636a7482a4a4c08738bccf7f246b8061d26 100644 --- a/arch/mips/sgi-ip30/ip30-setup.c +++ b/arch/mips/sgi-ip30/ip30-setup.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c index a8e0c776ca6c628faa0b0ef4828de3fb4e9f51a2..b8a0e4cfa9ce882dcba3c0dc4e911716d47a457b 100644 --- a/arch/mips/sgi-ip32/crime.c +++ b/arch/mips/sgi-ip32/crime.c @@ -18,6 +18,8 @@ #include #include +#include "ip32-common.h" + struct sgi_crime __iomem *crime; struct sgi_mace __iomem *mace; @@ -39,7 +41,7 @@ void __init crime_init(void) id, rev, field, (unsigned long) CRIME_BASE); } -irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id) +irqreturn_t crime_memerr_intr(int irq, void *dev_id) { unsigned long stat, addr; int fatal = 0; @@ -90,7 +92,7 @@ irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id) return IRQ_HANDLED; } -irqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id) +irqreturn_t crime_cpuerr_intr(int irq, void *dev_id) { unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK; unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK; diff --git a/arch/mips/sgi-ip32/ip32-berr.c b/arch/mips/sgi-ip32/ip32-berr.c index 478b63b4c808f35456bb0b4ba69de4450edb7404..7cbc27941f928399c3cd5166741f5495c55b7eaa 100644 --- a/arch/mips/sgi-ip32/ip32-berr.c +++ b/arch/mips/sgi-ip32/ip32-berr.c @@ -18,6 +18,8 @@ #include #include +#include "ip32-common.h" + static int ip32_be_handler(struct pt_regs *regs, int is_fixup) { int data = regs->cp0_cause & 4; diff --git a/arch/mips/sgi-ip32/ip32-common.h b/arch/mips/sgi-ip32/ip32-common.h new file mode 100644 index 0000000000000000000000000000000000000000..cfc0225b14193978adf17f69bf1d1286552b0e2b --- /dev/null +++ b/arch/mips/sgi-ip32/ip32-common.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __IP32_COMMON_H +#define __IP32_COMMON_H + +#include +#include + +void __init crime_init(void); +irqreturn_t crime_memerr_intr(int irq, void *dev_id); +irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); +void __init ip32_be_init(void); +void ip32_prepare_poweroff(void); + +#endif /* __IP32_COMMON_H */ diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index e21ea1de05e31953ce51f04122512cd27b2d9c46..29d04468a06b8f5c4004a25a18ad94dcb08013f9 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -28,6 +28,8 @@ #include #include +#include "ip32-common.h" + /* issue a PIO read to make sure no PIO writes are pending */ static inline void flush_crime_bus(void) { @@ -107,10 +109,6 @@ static inline void flush_mace_bus(void) * is quite different anyway. */ -/* Some initial interrupts to set up */ -extern irqreturn_t crime_memerr_intr(int irq, void *dev_id); -extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); - /* * This is for pure CRIME interrupts - ie not MACE. The advantage? * We get to split the register in half and do faster lookups. diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c index 3fc8d0a0bdfa45cc8b3aead0bd31144a874e17bb..5fee33744f674bdbdd777ba63b7d15f92d661a99 100644 --- a/arch/mips/sgi-ip32/ip32-memory.c +++ b/arch/mips/sgi-ip32/ip32-memory.c @@ -15,6 +15,7 @@ #include #include #include +#include extern void crime_init(void); diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 18d1c115cd534a2d78a1ee5f8b53681e46fc021f..6bdc1421cda46cad28b5b253bf53703005ed09bf 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c @@ -29,6 +29,8 @@ #include #include +#include "ip32-common.h" + #define POWERDOWN_TIMEOUT 120 /* * Blink frequency during reboot grace period and when panicked. diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c index 8019dae1721a811cef26fb75430a2b3ca151d6dd..aeb0805aae57bacfef7b95877042a6dc476a14a5 100644 --- a/arch/mips/sgi-ip32/ip32-setup.c +++ b/arch/mips/sgi-ip32/ip32-setup.c @@ -26,8 +26,7 @@ #include #include -extern void ip32_be_init(void); -extern void crime_init(void); +#include "ip32-common.h" #ifdef CONFIG_SGI_O2MACE_ETH /* diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index d14ccc948a29b920854b6c750febffac625619fd..5c845e8d59d92f8cd3594fccf1476503d8957149 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -25,7 +25,6 @@ config PARISC select RTC_DRV_GENERIC select INIT_ALL_POSSIBLE select BUG - select BUILDTIME_TABLE_SORT select HAVE_KERNEL_UNCOMPRESSED select HAVE_PCI select HAVE_PERF_EVENTS diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 920db57b6b4cc866018c05dd00ca49142c7f949c..7486b3b3059491490f5626224f9177eb5efd6cdb 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -50,12 +50,12 @@ export CROSS32CC # Set default cross compiler for kernel build ifdef cross_compiling - ifeq ($(CROSS_COMPILE),) + ifeq ($(CROSS_COMPILE),) CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux CROSS_COMPILE := $(call cc-cross-prefix, \ $(foreach a,$(CC_ARCHES), \ $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-))) - endif + endif endif ifdef CONFIG_DYNAMIC_FTRACE diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h index 74d17d7e759da9dfa89aa1a504b94de4554db16d..5937d5edaba1eac5a0c4e4b055c3e77fcbe3bf62 100644 --- a/arch/parisc/include/asm/assembly.h +++ b/arch/parisc/include/asm/assembly.h @@ -576,6 +576,7 @@ .section __ex_table,"aw" ! \ .align 4 ! \ .word (fault_addr - .), (except_addr - .) ! \ + or %r0,%r0,%r0 ! \ .previous diff --git a/arch/parisc/include/asm/extable.h b/arch/parisc/include/asm/extable.h new file mode 100644 index 0000000000000000000000000000000000000000..4ea23e3d79dc9034543465db2b0a4856324a4477 --- /dev/null +++ b/arch/parisc/include/asm/extable.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PARISC_EXTABLE_H +#define __PARISC_EXTABLE_H + +#include +#include + +/* + * The exception table consists of three addresses: + * + * - A relative address to the instruction that is allowed to fault. + * - A relative address at which the program should continue (fixup routine) + * - An asm statement which specifies which CPU register will + * receive -EFAULT when an exception happens if the lowest bit in + * the fixup address is set. + * + * Note: The register specified in the err_opcode instruction will be + * modified at runtime if a fault happens. Register %r0 will be ignored. + * + * Since relative addresses are used, 32bit values are sufficient even on + * 64bit kernel. + */ + +struct pt_regs; +int fixup_exception(struct pt_regs *regs); + +#define ARCH_HAS_RELATIVE_EXTABLE +struct exception_table_entry { + int insn; /* relative address of insn that is allowed to fault. */ + int fixup; /* relative address of fixup routine */ + int err_opcode; /* sample opcode with register which holds error code */ +}; + +#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr, opcode )\ + ".section __ex_table,\"aw\"\n" \ + ".align 4\n" \ + ".word (" #fault_addr " - .), (" #except_addr " - .)\n" \ + opcode "\n" \ + ".previous\n" + +/* + * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry + * (with lowest bit set) for which the fault handler in fixup_exception() will + * load -EFAULT on fault into the register specified by the err_opcode instruction, + * and zeroes the target register in case of a read fault in get_user(). + */ +#define ASM_EXCEPTIONTABLE_VAR(__err_var) \ + int __err_var = 0 +#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr, register )\ + ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1, "or %%r0,%%r0," register) + +static inline void swap_ex_entry_fixup(struct exception_table_entry *a, + struct exception_table_entry *b, + struct exception_table_entry tmp, + int delta) +{ + a->fixup = b->fixup + delta; + b->fixup = tmp.fixup - delta; + a->err_opcode = b->err_opcode; + b->err_opcode = tmp.err_opcode; +} +#define swap_ex_entry_fixup swap_ex_entry_fixup + +#endif diff --git a/arch/parisc/include/asm/special_insns.h b/arch/parisc/include/asm/special_insns.h index c822bd0c0e3c6ccb86b4190d15500589c70f353a..51f40eaf7780659263f37b7c10fa7bd4ecf4ced7 100644 --- a/arch/parisc/include/asm/special_insns.h +++ b/arch/parisc/include/asm/special_insns.h @@ -8,7 +8,8 @@ "copy %%r0,%0\n" \ "8:\tlpa %%r0(%1),%0\n" \ "9:\n" \ - ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ + ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ + "or %%r0,%%r0,%%r0") \ : "=&r" (pa) \ : "r" (va) \ : "memory" \ @@ -22,7 +23,8 @@ "copy %%r0,%0\n" \ "8:\tlpa %%r0(%%sr3,%1),%0\n" \ "9:\n" \ - ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ + ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ + "or %%r0,%%r0,%%r0") \ : "=&r" (pa) \ : "r" (va) \ : "memory" \ diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h index 4165079898d9e7af239a31a1bc77821e6081706a..88d0ae5769dde54e29176e286da359eb6a54e7bf 100644 --- a/arch/parisc/include/asm/uaccess.h +++ b/arch/parisc/include/asm/uaccess.h @@ -7,6 +7,7 @@ */ #include #include +#include #include #include @@ -26,37 +27,6 @@ #define STD_USER(sr, x, ptr) __put_user_asm(sr, "std", x, ptr) #endif -/* - * The exception table contains two values: the first is the relative offset to - * the address of the instruction that is allowed to fault, and the second is - * the relative offset to the address of the fixup routine. Since relative - * addresses are used, 32bit values are sufficient even on 64bit kernel. - */ - -#define ARCH_HAS_RELATIVE_EXTABLE -struct exception_table_entry { - int insn; /* relative address of insn that is allowed to fault. */ - int fixup; /* relative address of fixup routine */ -}; - -#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ - ".section __ex_table,\"aw\"\n" \ - ".align 4\n" \ - ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ - ".previous\n" - -/* - * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry - * (with lowest bit set) for which the fault handler in fixup_exception() will - * load -EFAULT into %r29 for a read or write fault, and zeroes the target - * register in case of a read fault in get_user(). - */ -#define ASM_EXCEPTIONTABLE_REG 29 -#define ASM_EXCEPTIONTABLE_VAR(__variable) \ - register long __variable __asm__ ("r29") = 0 -#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\ - ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1) - #define __get_user_internal(sr, val, ptr) \ ({ \ ASM_EXCEPTIONTABLE_VAR(__gu_err); \ @@ -83,7 +53,7 @@ struct exception_table_entry { \ __asm__("1: " ldx " 0(%%sr%2,%3),%0\n" \ "9:\n" \ - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ : "=r"(__gu_val), "+r"(__gu_err) \ : "i"(sr), "r"(ptr)); \ \ @@ -115,8 +85,8 @@ struct exception_table_entry { "1: ldw 0(%%sr%2,%3),%0\n" \ "2: ldw 4(%%sr%2,%3),%R0\n" \ "9:\n" \ - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%1") \ : "=&r"(__gu_tmp.l), "+r"(__gu_err) \ : "i"(sr), "r"(ptr)); \ \ @@ -174,7 +144,7 @@ struct exception_table_entry { __asm__ __volatile__ ( \ "1: " stx " %1,0(%%sr%2,%3)\n" \ "9:\n" \ - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ : "+r"(__pu_err) \ : "r"(x), "i"(sr), "r"(ptr)) @@ -186,15 +156,14 @@ struct exception_table_entry { "1: stw %1,0(%%sr%2,%3)\n" \ "2: stw %R1,4(%%sr%2,%3)\n" \ "9:\n" \ - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%0") \ : "+r"(__pu_err) \ : "r"(__val), "i"(sr), "r"(ptr)); \ } while (0) #endif /* !defined(CONFIG_64BIT) */ - /* * Complex access routines -- external declarations */ @@ -216,7 +185,4 @@ unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src, #define INLINE_COPY_TO_USER #define INLINE_COPY_FROM_USER -struct pt_regs; -int fixup_exception(struct pt_regs *regs); - #endif /* __PARISC_UACCESS_H */ diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 268d90a9325b468603b634b86b48980a31b4fba7..422f3e1e6d9cad718c264c7d7c9bd30872846555 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -58,7 +58,7 @@ int pa_serialize_tlb_flushes __ro_after_init; struct pdc_cache_info cache_info __ro_after_init; #ifndef CONFIG_PA20 -struct pdc_btlb_info btlb_info __ro_after_init; +struct pdc_btlb_info btlb_info; #endif DEFINE_STATIC_KEY_TRUE(parisc_has_cache); @@ -264,6 +264,10 @@ parisc_cache_init(void) icache_stride = CAFL_STRIDE(cache_info.ic_conf); #undef CAFL_STRIDE + /* stride needs to be non-zero, otherwise cache flushes will not work */ + WARN_ON(cache_info.dc_size && dcache_stride == 0); + WARN_ON(cache_info.ic_size && icache_stride == 0); + if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) == PDC_MODEL_NVA_UNSUPPORTED) { printk(KERN_WARNING "parisc_cache_init: Only equivalent aliasing supported!\n"); @@ -850,7 +854,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, #endif " fic,m %3(%4,%0)\n" "2: sync\n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1") : "+r" (start), "+r" (error) : "r" (end), "r" (dcache_stride), "i" (SR_USER)); } @@ -865,7 +869,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, #endif " fdc,m %3(%4,%0)\n" "2: sync\n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1") : "+r" (start), "+r" (error) : "r" (end), "r" (icache_stride), "i" (SR_USER)); } diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index 25f9b9e9d6dfbc70f21787e29a170334cb102dc7..c7ff339732ba5a762eac90e1b3072aef45c58318 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -742,7 +742,7 @@ parse_tree_node(struct device *parent, int index, struct hardware_path *modpath) }; if (device_for_each_child(parent, &recurse_data, descend_children)) - { /* nothing */ }; + { /* nothing */ } return d.dev; } @@ -1004,6 +1004,9 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data) pr_info("\n"); + /* Prevent hung task messages when printing on serial console */ + cond_resched(); + pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n", hpa, parisc_hardware_description(&dev->id)); diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index ce25acfe4889d0df8048e448a16d76e414ee1262..c520e551a165258609cba5e068037493bd7e57a8 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -120,8 +120,8 @@ static int emulate_ldh(struct pt_regs *regs, int toreg) "2: ldbs 1(%%sr1,%3), %0\n" " depw %2, 23, 24, %0\n" "3: \n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") : "+r" (val), "+r" (ret), "=&r" (temp1) : "r" (saddr), "r" (regs->isr) ); @@ -152,8 +152,8 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop) " mtctl %2,11\n" " vshd %0,%3,%0\n" "3: \n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") : "+r" (val), "+r" (ret), "=&r" (temp1), "=&r" (temp2) : "r" (saddr), "r" (regs->isr) ); @@ -189,8 +189,8 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) " mtsar %%r19\n" " shrpd %0,%%r20,%%sar,%0\n" "3: \n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") : "=r" (val), "+r" (ret) : "0" (val), "r" (saddr), "r" (regs->isr) : "r19", "r20" ); @@ -209,9 +209,9 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) " vshd %0,%R0,%0\n" " vshd %R0,%4,%R0\n" "4: \n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b, "%1") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b, "%1") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b, "%1") : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1) : "r" (regs->isr) ); } @@ -244,8 +244,8 @@ static int emulate_sth(struct pt_regs *regs, int frreg) "1: stb %1, 0(%%sr1, %3)\n" "2: stb %2, 1(%%sr1, %3)\n" "3: \n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") : "+r" (ret), "=&r" (temp1) : "r" (val), "r" (regs->ior), "r" (regs->isr) ); @@ -285,8 +285,8 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop) " stw %%r20,0(%%sr1,%2)\n" " stw %%r21,4(%%sr1,%2)\n" "3: \n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") : "+r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) : "r19", "r20", "r21", "r22", "r1" ); @@ -329,10 +329,10 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) "3: std %%r20,0(%%sr1,%2)\n" "4: std %%r21,8(%%sr1,%2)\n" "5: \n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b, "%0") : "+r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) : "r19", "r20", "r21", "r22", "r1" ); @@ -357,11 +357,11 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) "4: stw %%r1,4(%%sr1,%2)\n" "5: stw %R1,8(%%sr1,%2)\n" "6: \n" - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b) - ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b) + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b, "%0") + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b, "%0") : "+r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) : "r19", "r20", "r21", "r1" ); diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 548051b0b4aff692741847a04b09208d1e68d279..b445e47903cfd0b813035c2056f11a4f818cf6d2 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -127,7 +127,7 @@ SECTIONS } #endif - RO_DATA(8) + RO_DATA(PAGE_SIZE) /* unwind info */ . = ALIGN(4); diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 2fe5b44986e0924e3981ebc1edb9d074c08e6fda..c39de84e98b05172bdec0f474261ccde4a06cf00 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -150,11 +150,16 @@ int fixup_exception(struct pt_regs *regs) * Fix up get_user() and put_user(). * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() sets the least-significant * bit in the relative address of the fixup routine to indicate - * that gr[ASM_EXCEPTIONTABLE_REG] should be loaded with - * -EFAULT to report a userspace access error. + * that the register encoded in the "or %r0,%r0,register" + * opcode should be loaded with -EFAULT to report a userspace + * access error. */ if (fix->fixup & 1) { - regs->gr[ASM_EXCEPTIONTABLE_REG] = -EFAULT; + int fault_error_reg = fix->err_opcode & 0x1f; + if (!WARN_ON(!fault_error_reg)) + regs->gr[fault_error_reg] = -EFAULT; + pr_debug("Unalignment fixup of register %d at %pS\n", + fault_error_reg, (void*)regs->iaoq[0]); /* zero target register for get_user() */ if (parisc_acctyp(0, regs->iir) == VM_READ) { diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index ebe259bdd46298e0654fb681b0cf8853c8381079..d71eac3b2887b98ff5ea23ec1874243283524f4c 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -1287,20 +1287,20 @@ spapr_tce_platform_iommu_attach_dev(struct iommu_domain *platform_domain, struct iommu_domain *domain = iommu_get_domain_for_dev(dev); struct iommu_group *grp = iommu_group_get(dev); struct iommu_table_group *table_group; - int ret = -EINVAL; /* At first attach the ownership is already set */ if (!domain) return 0; - if (!grp) - return -ENODEV; - table_group = iommu_group_get_iommudata(grp); - ret = table_group->ops->take_ownership(table_group); + /* + * The domain being set to PLATFORM from earlier + * BLOCKED. The table_group ownership has to be released. + */ + table_group->ops->release_ownership(table_group); iommu_group_put(grp); - return ret; + return 0; } static const struct iommu_domain_ops spapr_tce_platform_domain_ops = { @@ -1312,13 +1312,32 @@ static struct iommu_domain spapr_tce_platform_domain = { .ops = &spapr_tce_platform_domain_ops, }; -static struct iommu_domain spapr_tce_blocked_domain = { - .type = IOMMU_DOMAIN_BLOCKED, +static int +spapr_tce_blocked_iommu_attach_dev(struct iommu_domain *platform_domain, + struct device *dev) +{ + struct iommu_group *grp = iommu_group_get(dev); + struct iommu_table_group *table_group; + int ret = -EINVAL; + /* * FIXME: SPAPR mixes blocked and platform behaviors, the blocked domain * also sets the dma_api ops */ - .ops = &spapr_tce_platform_domain_ops, + table_group = iommu_group_get_iommudata(grp); + ret = table_group->ops->take_ownership(table_group); + iommu_group_put(grp); + + return ret; +} + +static const struct iommu_domain_ops spapr_tce_blocked_domain_ops = { + .attach_dev = spapr_tce_blocked_iommu_attach_dev, +}; + +static struct iommu_domain spapr_tce_blocked_domain = { + .type = IOMMU_DOMAIN_BLOCKED, + .ops = &spapr_tce_blocked_domain_ops, }; static bool spapr_tce_iommu_capable(struct device *dev, enum iommu_cap cap) diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index e9c1087dd42ec68cb90e660c57b6eff0fed41ba9..706194e5f0b46f228ff636be3e790875144c7a35 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -67,6 +67,7 @@ config PS3_VUART config PS3_PS3AV depends on PPC_PS3 tristate "PS3 AV settings driver" if PS3_ADVANCED + select VIDEO select PS3_VUART default y help diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi index 93256540d07882af2b12a6faf0642d93ddc4970b..ead1cc35d88b2f13bfecf935a6e66e6049a24a75 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi +++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi @@ -93,144 +93,160 @@ <&cpu63_intc 3>; }; - clint_mtimer0: timer@70ac000000 { + clint_mtimer0: timer@70ac004000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac004000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu0_intc 7>, <&cpu1_intc 7>, <&cpu2_intc 7>, <&cpu3_intc 7>; }; - clint_mtimer1: timer@70ac010000 { + clint_mtimer1: timer@70ac014000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac014000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu4_intc 7>, <&cpu5_intc 7>, <&cpu6_intc 7>, <&cpu7_intc 7>; }; - clint_mtimer2: timer@70ac020000 { + clint_mtimer2: timer@70ac024000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac024000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu8_intc 7>, <&cpu9_intc 7>, <&cpu10_intc 7>, <&cpu11_intc 7>; }; - clint_mtimer3: timer@70ac030000 { + clint_mtimer3: timer@70ac034000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac034000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu12_intc 7>, <&cpu13_intc 7>, <&cpu14_intc 7>, <&cpu15_intc 7>; }; - clint_mtimer4: timer@70ac040000 { + clint_mtimer4: timer@70ac044000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac044000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu16_intc 7>, <&cpu17_intc 7>, <&cpu18_intc 7>, <&cpu19_intc 7>; }; - clint_mtimer5: timer@70ac050000 { + clint_mtimer5: timer@70ac054000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac054000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu20_intc 7>, <&cpu21_intc 7>, <&cpu22_intc 7>, <&cpu23_intc 7>; }; - clint_mtimer6: timer@70ac060000 { + clint_mtimer6: timer@70ac064000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac064000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu24_intc 7>, <&cpu25_intc 7>, <&cpu26_intc 7>, <&cpu27_intc 7>; }; - clint_mtimer7: timer@70ac070000 { + clint_mtimer7: timer@70ac074000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac074000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu28_intc 7>, <&cpu29_intc 7>, <&cpu30_intc 7>, <&cpu31_intc 7>; }; - clint_mtimer8: timer@70ac080000 { + clint_mtimer8: timer@70ac084000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac084000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu32_intc 7>, <&cpu33_intc 7>, <&cpu34_intc 7>, <&cpu35_intc 7>; }; - clint_mtimer9: timer@70ac090000 { + clint_mtimer9: timer@70ac094000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac094000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu36_intc 7>, <&cpu37_intc 7>, <&cpu38_intc 7>, <&cpu39_intc 7>; }; - clint_mtimer10: timer@70ac0a0000 { + clint_mtimer10: timer@70ac0a4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0a4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu40_intc 7>, <&cpu41_intc 7>, <&cpu42_intc 7>, <&cpu43_intc 7>; }; - clint_mtimer11: timer@70ac0b0000 { + clint_mtimer11: timer@70ac0b4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0b4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu44_intc 7>, <&cpu45_intc 7>, <&cpu46_intc 7>, <&cpu47_intc 7>; }; - clint_mtimer12: timer@70ac0c0000 { + clint_mtimer12: timer@70ac0c4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0c4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu48_intc 7>, <&cpu49_intc 7>, <&cpu50_intc 7>, <&cpu51_intc 7>; }; - clint_mtimer13: timer@70ac0d0000 { + clint_mtimer13: timer@70ac0d4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0d4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu52_intc 7>, <&cpu53_intc 7>, <&cpu54_intc 7>, <&cpu55_intc 7>; }; - clint_mtimer14: timer@70ac0e0000 { + clint_mtimer14: timer@70ac0e4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0e4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu56_intc 7>, <&cpu57_intc 7>, <&cpu58_intc 7>, <&cpu59_intc 7>; }; - clint_mtimer15: timer@70ac0f0000 { + clint_mtimer15: timer@70ac0f4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0f4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu60_intc 7>, <&cpu61_intc 7>, <&cpu62_intc 7>, diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 58dc64dd94a82c8d8cc42a71ec69954dc548934a..719a97e7edb2c12277a8e08dd214e0eb03be094a 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -795,6 +795,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT]; struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN]; + bool is_struct_ops = flags & BPF_TRAMP_F_INDIRECT; void *orig_call = func_addr; bool save_ret; u32 insn; @@ -878,7 +879,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, stack_size = round_up(stack_size, 16); - if (func_addr) { + if (!is_struct_ops) { /* For the trampoline called from function entry, * the frame of traced function and the frame of * trampoline need to be considered. @@ -998,7 +999,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, emit_ld(RV_REG_S1, -sreg_off, RV_REG_FP, ctx); - if (func_addr) { + if (!is_struct_ops) { /* trampoline called from function entry */ emit_ld(RV_REG_T0, stack_size - 8, RV_REG_SP, ctx); emit_ld(RV_REG_FP, stack_size - 16, RV_REG_SP, ctx); diff --git a/arch/um/Makefile b/arch/um/Makefile index 82f05f250634807c9f78774bca9213dfd5de2038..34957dcb88b9c31befa3c2b7e08809de73b23a3e 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -115,7 +115,9 @@ archprepare: $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static -LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie) +ifdef CONFIG_LD_SCRIPT_DYN +LINK-$(call gcc-min-version, 60100)$(CONFIG_CC_IS_CLANG) += -no-pie +endif LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \ diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 1a068de12a564fe452cd5c003feb907fd3de42fd..2264db14a25d3b034ffa93685d6353564d4a9225 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -112,13 +112,13 @@ ifeq ($(CONFIG_X86_32),y) # temporary until string.h is fixed KBUILD_CFLAGS += -ffreestanding - ifeq ($(CONFIG_STACKPROTECTOR),y) - ifeq ($(CONFIG_SMP),y) + ifeq ($(CONFIG_STACKPROTECTOR),y) + ifeq ($(CONFIG_SMP),y) KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard - else + else KBUILD_CFLAGS += -mstack-protector-guard=global - endif - endif + endif + endif else BITS := 64 UTS_MACHINE := x86_64 diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 29cb275a219d7fb38fa0d16e6ba48e91c9d032b4..fdf723b6f6d0ce9f6742ef3c67adce3c8d57c002 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -81,10 +81,8 @@ #define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */ #define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */ #define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */ - -/* CPU types for specific tunings: */ #define X86_FEATURE_K8 ( 3*32+ 4) /* "" Opteron, Athlon64 */ -/* FREE, was #define X86_FEATURE_K7 ( 3*32+ 5) "" Athlon */ +#define X86_FEATURE_ZEN5 ( 3*32+ 5) /* "" CPU based on Zen5 microarchitecture */ #define X86_FEATURE_P3 ( 3*32+ 6) /* "" P3 */ #define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */ #define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */ diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h index 197316121f04e154dad9ba4d9a7169674c623dd5..b65e9c46b92210293d767ab01434593c2aad27a0 100644 --- a/arch/x86/include/asm/intel-family.h +++ b/arch/x86/include/asm/intel-family.h @@ -162,6 +162,8 @@ #define INTEL_FAM6_ATOM_CRESTMONT_X 0xAF /* Sierra Forest */ #define INTEL_FAM6_ATOM_CRESTMONT 0xB6 /* Grand Ridge */ +#define INTEL_FAM6_ATOM_DARKMONT_X 0xDD /* Clearwater Forest */ + /* Xeon Phi */ #define INTEL_FAM6_XEON_PHI_KNL 0x57 /* Knights Landing */ diff --git a/arch/x86/include/asm/kmsan.h b/arch/x86/include/asm/kmsan.h index 8fa6ac0e2d7665f936756748c0e1b4ab08a2c5a7..d91b37f5b4bb45106ee927fcd98b66f1b82a54c1 100644 --- a/arch/x86/include/asm/kmsan.h +++ b/arch/x86/include/asm/kmsan.h @@ -64,6 +64,7 @@ static inline bool kmsan_virt_addr_valid(void *addr) { unsigned long x = (unsigned long)addr; unsigned long y = x - __START_KERNEL_map; + bool ret; /* use the carry flag to determine if x was < __START_KERNEL_map */ if (unlikely(x > y)) { @@ -79,7 +80,21 @@ static inline bool kmsan_virt_addr_valid(void *addr) return false; } - return pfn_valid(x >> PAGE_SHIFT); + /* + * pfn_valid() relies on RCU, and may call into the scheduler on exiting + * the critical section. However, this would result in recursion with + * KMSAN. Therefore, disable preemption here, and re-enable preemption + * below while suppressing reschedules to avoid recursion. + * + * Note, this sacrifices occasionally breaking scheduling guarantees. + * Although, a kernel compiled with KMSAN has already given up on any + * performance guarantees due to being heavily instrumented. + */ + preempt_disable(); + ret = pfn_valid(x >> PAGE_SHIFT); + preempt_enable_no_resched(); + + return ret; } #endif /* !MODULE */ diff --git a/arch/x86/include/asm/syscall_wrapper.h b/arch/x86/include/asm/syscall_wrapper.h index 21f9407be5d357a8f4204addc66841dc50d9bf51..7e88705e907f411b416d25e533e06623997555ea 100644 --- a/arch/x86/include/asm/syscall_wrapper.h +++ b/arch/x86/include/asm/syscall_wrapper.h @@ -58,12 +58,29 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); ,,regs->di,,regs->si,,regs->dx \ ,,regs->r10,,regs->r8,,regs->r9) \ + +/* SYSCALL_PT_ARGS is Adapted from s390x */ +#define SYSCALL_PT_ARG6(m, t1, t2, t3, t4, t5, t6) \ + SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5), m(t6, (regs->bp)) +#define SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5) \ + SYSCALL_PT_ARG4(m, t1, t2, t3, t4), m(t5, (regs->di)) +#define SYSCALL_PT_ARG4(m, t1, t2, t3, t4) \ + SYSCALL_PT_ARG3(m, t1, t2, t3), m(t4, (regs->si)) +#define SYSCALL_PT_ARG3(m, t1, t2, t3) \ + SYSCALL_PT_ARG2(m, t1, t2), m(t3, (regs->dx)) +#define SYSCALL_PT_ARG2(m, t1, t2) \ + SYSCALL_PT_ARG1(m, t1), m(t2, (regs->cx)) +#define SYSCALL_PT_ARG1(m, t1) m(t1, (regs->bx)) +#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__) + +#define __SC_COMPAT_CAST(t, a) \ + (__typeof(__builtin_choose_expr(__TYPE_IS_L(t), 0, 0U))) \ + (unsigned int)a + /* Mapping of registers to parameters for syscalls on i386 */ #define SC_IA32_REGS_TO_ARGS(x, ...) \ - __MAP(x,__SC_ARGS \ - ,,(unsigned int)regs->bx,,(unsigned int)regs->cx \ - ,,(unsigned int)regs->dx,,(unsigned int)regs->si \ - ,,(unsigned int)regs->di,,(unsigned int)regs->bp) + SYSCALL_PT_ARGS(x, __SC_COMPAT_CAST, \ + __MAP(x, __SC_TYPE, __VA_ARGS__)) \ #define __SYS_STUB0(abi, name) \ long __##abi##_##name(const struct pt_regs *regs); \ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index cc130b57542ac4033c1c653809f429306eb3e460..1d85cb7071cb21c84899477ec4a150d2fcc4da43 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -403,7 +403,7 @@ noinstr void BUG_func(void) { BUG(); } -EXPORT_SYMBOL_GPL(BUG_func); +EXPORT_SYMBOL(BUG_func); #define CALL_RIP_REL_OPCODE 0xff #define CALL_RIP_REL_MODRM 0x15 diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 9f42d1c59e095ee6923a78cb2ecb04fbe375a438..f3abca334199d8eae235f1560f99448eb9675a27 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -538,7 +538,7 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) /* Figure out Zen generations: */ switch (c->x86) { - case 0x17: { + case 0x17: switch (c->x86_model) { case 0x00 ... 0x2f: case 0x50 ... 0x5f: @@ -554,8 +554,8 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) goto warn; } break; - } - case 0x19: { + + case 0x19: switch (c->x86_model) { case 0x00 ... 0x0f: case 0x20 ... 0x5f: @@ -569,7 +569,20 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) goto warn; } break; - } + + case 0x1a: + switch (c->x86_model) { + case 0x00 ... 0x0f: + case 0x20 ... 0x2f: + case 0x40 ... 0x4f: + case 0x70 ... 0x7f: + setup_force_cpu_cap(X86_FEATURE_ZEN5); + break; + default: + goto warn; + } + break; + default: break; } @@ -1039,6 +1052,11 @@ static void init_amd_zen4(struct cpuinfo_x86 *c) msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT); } +static void init_amd_zen5(struct cpuinfo_x86 *c) +{ + init_amd_zen_common(); +} + static void init_amd(struct cpuinfo_x86 *c) { u64 vm_cr; @@ -1084,6 +1102,8 @@ static void init_amd(struct cpuinfo_x86 *c) init_amd_zen3(c); else if (boot_cpu_has(X86_FEATURE_ZEN4)) init_amd_zen4(c); + else if (boot_cpu_has(X86_FEATURE_ZEN5)) + init_amd_zen5(c); /* * Enable workaround for FXSAVE leak on CPUs diff --git a/block/blk-core.c b/block/blk-core.c index 11342af420d0c41d1c98a729471dcd6bfb46da05..de771093b52687ae2431af36bf75b73ccaa1bbf0 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -49,6 +49,7 @@ #include "blk-pm.h" #include "blk-cgroup.h" #include "blk-throttle.h" +#include "blk-ioprio.h" struct dentry *blk_debugfs_root; @@ -833,6 +834,14 @@ end_io: } EXPORT_SYMBOL(submit_bio_noacct); +static void bio_set_ioprio(struct bio *bio) +{ + /* Nobody set ioprio so far? Initialize it based on task's nice value */ + if (IOPRIO_PRIO_CLASS(bio->bi_ioprio) == IOPRIO_CLASS_NONE) + bio->bi_ioprio = get_current_ioprio(); + blkcg_set_ioprio(bio); +} + /** * submit_bio - submit a bio to the block device layer for I/O * @bio: The &struct bio which describes the I/O @@ -855,6 +864,7 @@ void submit_bio(struct bio *bio) count_vm_events(PGPGOUT, bio_sectors(bio)); } + bio_set_ioprio(bio); submit_bio_noacct(bio); } EXPORT_SYMBOL(submit_bio); diff --git a/block/blk-map.c b/block/blk-map.c index 8584babf3ea0ca2590f30383b9594231266e9437..71210cdb34426d967b5632667cb7579b11e97a2d 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -205,12 +205,19 @@ static int bio_copy_user_iov(struct request *rq, struct rq_map_data *map_data, /* * success */ - if ((iov_iter_rw(iter) == WRITE && - (!map_data || !map_data->null_mapped)) || - (map_data && map_data->from_user)) { + if (iov_iter_rw(iter) == WRITE && + (!map_data || !map_data->null_mapped)) { ret = bio_copy_from_iter(bio, iter); if (ret) goto cleanup; + } else if (map_data && map_data->from_user) { + struct iov_iter iter2 = *iter; + + /* This is the copy-in part of SG_DXFER_TO_FROM_DEV. */ + iter2.data_source = ITER_SOURCE; + ret = bio_copy_from_iter(bio, &iter2); + if (ret) + goto cleanup; } else { if (bmd->is_our_pages) zero_fill_bio(bio); diff --git a/block/blk-mq.c b/block/blk-mq.c index aa87fcfda1ecfc875c86a0258fe16e707ce3f167..2dc01551e27c7d1e50266e554fe4bb6d378a1482 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -40,7 +40,6 @@ #include "blk-stat.h" #include "blk-mq-sched.h" #include "blk-rq-qos.h" -#include "blk-ioprio.h" static DEFINE_PER_CPU(struct llist_head, blk_cpu_done); static DEFINE_PER_CPU(call_single_data_t, blk_cpu_csd); @@ -2944,14 +2943,6 @@ static bool blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug, return true; } -static void bio_set_ioprio(struct bio *bio) -{ - /* Nobody set ioprio so far? Initialize it based on task's nice value */ - if (IOPRIO_PRIO_CLASS(bio->bi_ioprio) == IOPRIO_CLASS_NONE) - bio->bi_ioprio = get_current_ioprio(); - blkcg_set_ioprio(bio); -} - /** * blk_mq_submit_bio - Create and send a request to block device. * @bio: Bio pointer. @@ -2976,7 +2967,6 @@ void blk_mq_submit_bio(struct bio *bio) blk_status_t ret; bio = blk_queue_bounce(bio, q); - bio_set_ioprio(bio); if (plug) { rq = rq_list_peek(&plug->cached_rq); diff --git a/block/ioctl.c b/block/ioctl.c index 9c73a763ef8838953bd1050b505621c39b8d4cdb..438f79c564cfc05d6f525550417eeee93c7b82bb 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -20,8 +20,6 @@ static int blkpg_do_ioctl(struct block_device *bdev, struct blkpg_partition p; sector_t start, length; - if (disk->flags & GENHD_FL_NO_PART) - return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (copy_from_user(&p, upart, sizeof(struct blkpg_partition))) diff --git a/block/partitions/core.c b/block/partitions/core.c index cab0d76a828e37eb90e38d91b4e92a61e703717e..5f5ed5c75f04d91d7bc8bf87ff4c9fa685c62318 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -439,6 +439,11 @@ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, goto out; } + if (disk->flags & GENHD_FL_NO_PART) { + ret = -EINVAL; + goto out; + } + if (partition_overlaps(disk, start, length, -1)) { ret = -EBUSY; goto out; diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 19035230563d7bf8ca2625a06c241d0eb010c3b7..7cb962e2145349670e4a506c879822a6bb3c6c23 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -102,7 +102,7 @@ static int reset_pending_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = seq_to_ivpu(s); - seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset)); + seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_pending)); return 0; } @@ -130,7 +130,9 @@ dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size fw->dvfs_mode = dvfs_mode; - ivpu_pm_schedule_recovery(vdev); + ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); + if (ret) + return ret; return size; } @@ -190,7 +192,10 @@ fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf, return ret; ivpu_hw_profiling_freq_drive(vdev, enable); - ivpu_pm_schedule_recovery(vdev); + + ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); + if (ret) + return ret; return size; } @@ -301,11 +306,18 @@ static ssize_t ivpu_force_recovery_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) { struct ivpu_device *vdev = file->private_data; + int ret; if (!size) return -EINVAL; - ivpu_pm_schedule_recovery(vdev); + ret = ivpu_rpm_get(vdev); + if (ret) + return ret; + + ivpu_pm_trigger_recovery(vdev, "debugfs"); + flush_work(&vdev->pm->recovery_work); + ivpu_rpm_put(vdev); return size; } diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 64927682161b282e739ef024a0ccff29c49de2cd..9418c73ee8ef8ba025ef896ffe218b61b8058f75 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ #include "ivpu_debugfs.h" #include "ivpu_drv.h" #include "ivpu_fw.h" +#include "ivpu_fw_log.h" #include "ivpu_gem.h" #include "ivpu_hw.h" #include "ivpu_ipc.h" @@ -65,22 +67,20 @@ struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv) return file_priv; } -struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id) +static void file_priv_unbind(struct ivpu_device *vdev, struct ivpu_file_priv *file_priv) { - struct ivpu_file_priv *file_priv; - - xa_lock_irq(&vdev->context_xa); - file_priv = xa_load(&vdev->context_xa, id); - /* file_priv may still be in context_xa during file_priv_release() */ - if (file_priv && !kref_get_unless_zero(&file_priv->ref)) - file_priv = NULL; - xa_unlock_irq(&vdev->context_xa); - - if (file_priv) - ivpu_dbg(vdev, KREF, "file_priv get by id: ctx %u refcount %u\n", - file_priv->ctx.id, kref_read(&file_priv->ref)); - - return file_priv; + mutex_lock(&file_priv->lock); + if (file_priv->bound) { + ivpu_dbg(vdev, FILE, "file_priv unbind: ctx %u\n", file_priv->ctx.id); + + ivpu_cmdq_release_all_locked(file_priv); + ivpu_jsm_context_release(vdev, file_priv->ctx.id); + ivpu_bo_unbind_all_bos_from_context(vdev, &file_priv->ctx); + ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); + file_priv->bound = false; + drm_WARN_ON(&vdev->drm, !xa_erase_irq(&vdev->context_xa, file_priv->ctx.id)); + } + mutex_unlock(&file_priv->lock); } static void file_priv_release(struct kref *ref) @@ -88,13 +88,15 @@ static void file_priv_release(struct kref *ref) struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref); struct ivpu_device *vdev = file_priv->vdev; - ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id); + ivpu_dbg(vdev, FILE, "file_priv release: ctx %u bound %d\n", + file_priv->ctx.id, (bool)file_priv->bound); + + pm_runtime_get_sync(vdev->drm.dev); + mutex_lock(&vdev->context_list_lock); + file_priv_unbind(vdev, file_priv); + mutex_unlock(&vdev->context_list_lock); + pm_runtime_put_autosuspend(vdev->drm.dev); - ivpu_cmdq_release_all(file_priv); - ivpu_jsm_context_release(vdev, file_priv->ctx.id); - ivpu_bo_remove_all_bos_from_context(vdev, &file_priv->ctx); - ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); - drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv); mutex_destroy(&file_priv->lock); kfree(file_priv); } @@ -176,9 +178,6 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS: args->value = vdev->hw->ranges.user.start; break; - case DRM_IVPU_PARAM_CONTEXT_PRIORITY: - args->value = file_priv->priority; - break; case DRM_IVPU_PARAM_CONTEXT_ID: args->value = file_priv->ctx.id; break; @@ -218,17 +217,10 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f static int ivpu_set_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { - struct ivpu_file_priv *file_priv = file->driver_priv; struct drm_ivpu_param *args = data; int ret = 0; switch (args->param) { - case DRM_IVPU_PARAM_CONTEXT_PRIORITY: - if (args->value <= DRM_IVPU_CONTEXT_PRIORITY_REALTIME) - file_priv->priority = args->value; - else - ret = -EINVAL; - break; default: ret = -EINVAL; } @@ -241,50 +233,53 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file) struct ivpu_device *vdev = to_ivpu_device(dev); struct ivpu_file_priv *file_priv; u32 ctx_id; - void *old; - int ret; + int idx, ret; - ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL); - if (ret) { - ivpu_err(vdev, "Failed to allocate context id: %d\n", ret); - return ret; - } + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); if (!file_priv) { ret = -ENOMEM; - goto err_xa_erase; + goto err_dev_exit; } file_priv->vdev = vdev; - file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL; + file_priv->bound = true; kref_init(&file_priv->ref); mutex_init(&file_priv->lock); + mutex_lock(&vdev->context_list_lock); + + ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, file_priv, + vdev->context_xa_limit, GFP_KERNEL); + if (ret) { + ivpu_err(vdev, "Failed to allocate context id: %d\n", ret); + goto err_unlock; + } + ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id); if (ret) - goto err_mutex_destroy; + goto err_xa_erase; - old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL); - if (xa_is_err(old)) { - ret = xa_err(old); - ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret); - goto err_ctx_fini; - } + mutex_unlock(&vdev->context_list_lock); + drm_dev_exit(idx); + + file->driver_priv = file_priv; ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n", ctx_id, current->comm, task_pid_nr(current)); - file->driver_priv = file_priv; return 0; -err_ctx_fini: - ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); -err_mutex_destroy: - mutex_destroy(&file_priv->lock); - kfree(file_priv); err_xa_erase: xa_erase_irq(&vdev->context_xa, ctx_id); +err_unlock: + mutex_unlock(&vdev->context_list_lock); + mutex_destroy(&file_priv->lock); + kfree(file_priv); +err_dev_exit: + drm_dev_exit(idx); return ret; } @@ -340,8 +335,6 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) if (!ret) ivpu_dbg(vdev, PM, "VPU ready message received successfully\n"); - else - ivpu_hw_diagnose_failure(vdev); return ret; } @@ -369,6 +362,9 @@ int ivpu_boot(struct ivpu_device *vdev) ret = ivpu_wait_for_ready(vdev); if (ret) { ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret); + ivpu_hw_diagnose_failure(vdev); + ivpu_mmu_evtq_dump(vdev); + ivpu_fw_log_dump(vdev); return ret; } @@ -540,6 +536,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev) lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key); INIT_LIST_HEAD(&vdev->bo_list); + ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock); + if (ret) + goto err_xa_destroy; + ret = drmm_mutex_init(&vdev->drm, &vdev->bo_list_lock); if (ret) goto err_xa_destroy; @@ -611,14 +611,30 @@ err_xa_destroy: return ret; } +static void ivpu_bo_unbind_all_user_contexts(struct ivpu_device *vdev) +{ + struct ivpu_file_priv *file_priv; + unsigned long ctx_id; + + mutex_lock(&vdev->context_list_lock); + + xa_for_each(&vdev->context_xa, ctx_id, file_priv) + file_priv_unbind(vdev, file_priv); + + mutex_unlock(&vdev->context_list_lock); +} + static void ivpu_dev_fini(struct ivpu_device *vdev) { ivpu_pm_disable(vdev); ivpu_shutdown(vdev); if (IVPU_WA(d3hot_after_power_off)) pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); + + ivpu_jobs_abort_all(vdev); ivpu_job_done_consumer_fini(vdev); ivpu_pm_cancel_recovery(vdev); + ivpu_bo_unbind_all_user_contexts(vdev); ivpu_ipc_fini(vdev); ivpu_fw_fini(vdev); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index ebc4b84f27b209df9d653747772e756702cf4601..069ace4adb2d19c1a0544333d0da65632c524ea7 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -56,6 +56,7 @@ #define IVPU_DBG_JSM BIT(10) #define IVPU_DBG_KREF BIT(11) #define IVPU_DBG_RPM BIT(12) +#define IVPU_DBG_MMU_MAP BIT(13) #define ivpu_err(vdev, fmt, ...) \ drm_err(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__) @@ -114,6 +115,7 @@ struct ivpu_device { struct ivpu_mmu_context gctx; struct ivpu_mmu_context rctx; + struct mutex context_list_lock; /* Protects user context addition/removal */ struct xarray context_xa; struct xa_limit context_xa_limit; @@ -145,8 +147,8 @@ struct ivpu_file_priv { struct mutex lock; /* Protects cmdq */ struct ivpu_cmdq *cmdq[IVPU_NUM_ENGINES]; struct ivpu_mmu_context ctx; - u32 priority; bool has_mmu_faults; + bool bound; }; extern int ivpu_dbg_mask; @@ -162,7 +164,6 @@ extern bool ivpu_disable_mmu_cont_pages; extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); -struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id); void ivpu_file_priv_put(struct ivpu_file_priv **link); int ivpu_boot(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 1dda4f38ea25cd356cc9efadcaa8d35394c6b19f..e9ddbe9f50ebeffaa3a1617431b864ceec73e2e7 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -24,14 +24,11 @@ static const struct drm_gem_object_funcs ivpu_gem_funcs; static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action) { - if (bo->ctx) - ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u ctx %d vpu_addr 0x%llx mmu_mapped %d\n", - action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt, - bo->handle, bo->ctx->id, bo->vpu_addr, bo->mmu_mapped); - else - ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u (not added to context)\n", - action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt, - bo->handle); + ivpu_dbg(vdev, BO, + "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n", + action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0, + (bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc, + (bool)bo->base.base.import_attach); } /* @@ -49,12 +46,7 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo) mutex_lock(&bo->lock); ivpu_dbg_bo(vdev, bo, "pin"); - - if (!bo->ctx) { - ivpu_err(vdev, "vpu_addr not allocated for BO %d\n", bo->handle); - ret = -EINVAL; - goto unlock; - } + drm_WARN_ON(&vdev->drm, !bo->ctx); if (!bo->mmu_mapped) { struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base); @@ -85,7 +77,10 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, const struct ivpu_addr_range *range) { struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - int ret; + int idx, ret; + + if (!drm_dev_enter(&vdev->drm, &idx)) + return -ENODEV; mutex_lock(&bo->lock); @@ -101,6 +96,8 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, mutex_unlock(&bo->lock); + drm_dev_exit(idx); + return ret; } @@ -108,11 +105,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) { struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - lockdep_assert_held(&bo->lock); - - ivpu_dbg_bo(vdev, bo, "unbind"); - - /* TODO: dma_unmap */ + lockdep_assert(lockdep_is_held(&bo->lock) || !kref_read(&bo->base.base.refcount)); if (bo->mmu_mapped) { drm_WARN_ON(&vdev->drm, !bo->ctx); @@ -124,19 +117,23 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) if (bo->ctx) { ivpu_mmu_context_remove_node(bo->ctx, &bo->mm_node); - bo->vpu_addr = 0; bo->ctx = NULL; } -} -static void ivpu_bo_unbind(struct ivpu_bo *bo) -{ - mutex_lock(&bo->lock); - ivpu_bo_unbind_locked(bo); - mutex_unlock(&bo->lock); + if (bo->base.base.import_attach) + return; + + dma_resv_lock(bo->base.base.resv, NULL); + if (bo->base.sgt) { + dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0); + sg_free_table(bo->base.sgt); + kfree(bo->base.sgt); + bo->base.sgt = NULL; + } + dma_resv_unlock(bo->base.base.resv); } -void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) +void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) { struct ivpu_bo *bo; @@ -146,8 +143,10 @@ void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m mutex_lock(&vdev->bo_list_lock); list_for_each_entry(bo, &vdev->bo_list, bo_list_node) { mutex_lock(&bo->lock); - if (bo->ctx == ctx) + if (bo->ctx == ctx) { + ivpu_dbg_bo(vdev, bo, "unbind"); ivpu_bo_unbind_locked(bo); + } mutex_unlock(&bo->lock); } mutex_unlock(&vdev->bo_list_lock); @@ -199,9 +198,6 @@ ivpu_bo_create(struct ivpu_device *vdev, u64 size, u32 flags) list_add_tail(&bo->bo_list_node, &vdev->bo_list); mutex_unlock(&vdev->bo_list_lock); - ivpu_dbg(vdev, BO, "create: vpu_addr 0x%llx size %zu flags 0x%x\n", - bo->vpu_addr, bo->base.base.size, flags); - return bo; } @@ -212,6 +208,12 @@ static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file) struct ivpu_bo *bo = to_ivpu_bo(obj); struct ivpu_addr_range *range; + if (bo->ctx) { + ivpu_warn(vdev, "Can't add BO to ctx %u: already in ctx %u\n", + file_priv->ctx.id, bo->ctx->id); + return -EALREADY; + } + if (bo->flags & DRM_IVPU_BO_SHAVE_MEM) range = &vdev->hw->ranges.shave; else if (bo->flags & DRM_IVPU_BO_DMA_MEM) @@ -227,62 +229,24 @@ static void ivpu_bo_free(struct drm_gem_object *obj) struct ivpu_device *vdev = to_ivpu_device(obj->dev); struct ivpu_bo *bo = to_ivpu_bo(obj); + ivpu_dbg_bo(vdev, bo, "free"); + mutex_lock(&vdev->bo_list_lock); list_del(&bo->bo_list_node); mutex_unlock(&vdev->bo_list_lock); drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); - ivpu_dbg_bo(vdev, bo, "free"); - - ivpu_bo_unbind(bo); + ivpu_bo_unbind_locked(bo); mutex_destroy(&bo->lock); drm_WARN_ON(obj->dev, bo->base.pages_use_count > 1); drm_gem_shmem_free(&bo->base); } -static const struct dma_buf_ops ivpu_bo_dmabuf_ops = { - .cache_sgt_mapping = true, - .attach = drm_gem_map_attach, - .detach = drm_gem_map_detach, - .map_dma_buf = drm_gem_map_dma_buf, - .unmap_dma_buf = drm_gem_unmap_dma_buf, - .release = drm_gem_dmabuf_release, - .mmap = drm_gem_dmabuf_mmap, - .vmap = drm_gem_dmabuf_vmap, - .vunmap = drm_gem_dmabuf_vunmap, -}; - -static struct dma_buf *ivpu_bo_export(struct drm_gem_object *obj, int flags) -{ - struct drm_device *dev = obj->dev; - struct dma_buf_export_info exp_info = { - .exp_name = KBUILD_MODNAME, - .owner = dev->driver->fops->owner, - .ops = &ivpu_bo_dmabuf_ops, - .size = obj->size, - .flags = flags, - .priv = obj, - .resv = obj->resv, - }; - void *sgt; - - /* - * Make sure that pages are allocated and dma-mapped before exporting the bo. - * DMA-mapping is required if the bo will be imported to the same device. - */ - sgt = drm_gem_shmem_get_pages_sgt(to_drm_gem_shmem_obj(obj)); - if (IS_ERR(sgt)) - return sgt; - - return drm_gem_dmabuf_export(dev, &exp_info); -} - static const struct drm_gem_object_funcs ivpu_gem_funcs = { .free = ivpu_bo_free, .open = ivpu_bo_open, - .export = ivpu_bo_export, .print_info = drm_gem_shmem_object_print_info, .pin = drm_gem_shmem_object_pin, .unpin = drm_gem_shmem_object_unpin, @@ -315,11 +279,9 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi return PTR_ERR(bo); } - ret = drm_gem_handle_create(file, &bo->base.base, &bo->handle); - if (!ret) { + ret = drm_gem_handle_create(file, &bo->base.base, &args->handle); + if (!ret) args->vpu_addr = bo->vpu_addr; - args->handle = bo->handle; - } drm_gem_object_put(&bo->base.base); @@ -361,7 +323,9 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla if (ret) goto err_put; + dma_resv_lock(bo->base.base.resv, NULL); ret = drm_gem_shmem_vmap(&bo->base, &map); + dma_resv_unlock(bo->base.base.resv); if (ret) goto err_put; @@ -376,7 +340,10 @@ void ivpu_bo_free_internal(struct ivpu_bo *bo) { struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr); + dma_resv_lock(bo->base.base.resv, NULL); drm_gem_shmem_vunmap(&bo->base, &map); + dma_resv_unlock(bo->base.base.resv); + drm_gem_object_put(&bo->base.base); } @@ -432,19 +399,11 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) { - unsigned long dma_refcount = 0; - mutex_lock(&bo->lock); - if (bo->base.base.dma_buf && bo->base.base.dma_buf->file) - dma_refcount = atomic_long_read(&bo->base.base.dma_buf->file->f_count); - - drm_printf(p, "%-3u %-6d 0x%-12llx %-10lu 0x%-8x %-4u %-8lu", - bo->ctx->id, bo->handle, bo->vpu_addr, bo->base.base.size, - bo->flags, kref_read(&bo->base.base.refcount), dma_refcount); - - if (bo->base.base.import_attach) - drm_printf(p, " imported"); + drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u", + bo, bo->ctx->id, bo->vpu_addr, bo->base.base.size, + bo->flags, kref_read(&bo->base.base.refcount)); if (bo->base.pages) drm_printf(p, " has_pages"); @@ -452,6 +411,9 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) if (bo->mmu_mapped) drm_printf(p, " mmu_mapped"); + if (bo->base.base.import_attach) + drm_printf(p, " imported"); + drm_printf(p, "\n"); mutex_unlock(&bo->lock); @@ -462,8 +424,8 @@ void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p) struct ivpu_device *vdev = to_ivpu_device(dev); struct ivpu_bo *bo; - drm_printf(p, "%-3s %-6s %-14s %-10s %-10s %-4s %-8s %s\n", - "ctx", "handle", "vpu_addr", "size", "flags", "refs", "dma_refs", "attribs"); + drm_printf(p, "%-9s %-3s %-14s %-10s %-10s %-4s %s\n", + "bo", "ctx", "vpu_addr", "size", "flags", "refs", "attribs"); mutex_lock(&vdev->bo_list_lock); list_for_each_entry(bo, &vdev->bo_list, bo_list_node) diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index d75cad0d3c742db703dbe0812a0df6eaaba24d53..a8559211c70d41ac20bae1da57d846ffd4d7e3b3 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -19,14 +19,13 @@ struct ivpu_bo { struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */ u64 vpu_addr; - u32 handle; u32 flags; u32 job_status; /* Valid only for command buffer */ bool mmu_mapped; }; int ivpu_bo_pin(struct ivpu_bo *bo); -void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); +void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size); struct ivpu_bo *ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags); diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 574cdeefb66b39af45beda6534a6ac3eb0e57c7b..f15a93d83057822f2414aedb22359063fb99c6a1 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -875,24 +875,18 @@ static void ivpu_hw_37xx_irq_disable(struct ivpu_device *vdev) static void ivpu_hw_37xx_irq_wdt_nce_handler(struct ivpu_device *vdev) { - ivpu_err_ratelimited(vdev, "WDT NCE irq\n"); - - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ"); } static void ivpu_hw_37xx_irq_wdt_mss_handler(struct ivpu_device *vdev) { - ivpu_err_ratelimited(vdev, "WDT MSS irq\n"); - ivpu_hw_wdt_disable(vdev); - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ"); } static void ivpu_hw_37xx_irq_noc_firewall_handler(struct ivpu_device *vdev) { - ivpu_err_ratelimited(vdev, "NOC Firewall irq\n"); - - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ"); } /* Handler for IRQs from VPU core (irqV) */ @@ -970,7 +964,7 @@ static bool ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, status); if (schedule_recovery) - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "Buttress IRQ"); return true; } diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index eba2fdef2ace1384c93c1cbb30a8e3d9633abba8..704288084f37379eb6c7a1a5beb8f58ec3cea4a2 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -746,7 +746,7 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) return 0; } -static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) +static int ivpu_hw_40xx_ip_reset(struct ivpu_device *vdev) { int ret; u32 val; @@ -768,6 +768,23 @@ static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) return ret; } +static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) +{ + int ret = 0; + + if (ivpu_hw_40xx_ip_reset(vdev)) { + ivpu_err(vdev, "Failed to reset VPU IP\n"); + ret = -EIO; + } + + if (ivpu_pll_disable(vdev)) { + ivpu_err(vdev, "Failed to disable PLL\n"); + ret = -EIO; + } + + return ret; +} + static int ivpu_hw_40xx_d0i3_enable(struct ivpu_device *vdev) { int ret; @@ -913,7 +930,7 @@ static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev) ivpu_hw_40xx_save_d0i3_entry_timestamp(vdev); - if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev)) + if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_ip_reset(vdev)) ivpu_warn(vdev, "Failed to reset the VPU\n"); if (ivpu_pll_disable(vdev)) { @@ -1032,18 +1049,18 @@ static void ivpu_hw_40xx_irq_disable(struct ivpu_device *vdev) static void ivpu_hw_40xx_irq_wdt_nce_handler(struct ivpu_device *vdev) { /* TODO: For LNN hang consider engine reset instead of full recovery */ - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ"); } static void ivpu_hw_40xx_irq_wdt_mss_handler(struct ivpu_device *vdev) { ivpu_hw_wdt_disable(vdev); - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ"); } static void ivpu_hw_40xx_irq_noc_firewall_handler(struct ivpu_device *vdev) { - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ"); } /* Handler for IRQs from VPU core (irqV) */ @@ -1137,7 +1154,7 @@ static bool ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status); if (schedule_recovery) - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "Buttress IRQ"); return true; } diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index e86621f16f85a8d5d41f0d5dcf1ef99d1e45541d..fa66c39b57ecaaecae036d17f79c3e7683fc5279 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -343,10 +343,8 @@ int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *r hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE, &hb_resp, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); - if (hb_ret == -ETIMEDOUT) { - ivpu_hw_diagnose_failure(vdev); - ivpu_pm_schedule_recovery(vdev); - } + if (hb_ret == -ETIMEDOUT) + ivpu_pm_trigger_recovery(vdev, "IPC timeout"); return ret; } diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 7206cf9cdb4a45335b220796621fcd2c55a8ddf0..0440bee3ecafd567da6cbf47584f3daa688b618d 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -112,22 +112,20 @@ static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engin } } -void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv) +void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) { int i; - mutex_lock(&file_priv->lock); + lockdep_assert_held(&file_priv->lock); for (i = 0; i < IVPU_NUM_ENGINES; i++) ivpu_cmdq_release_locked(file_priv, i); - - mutex_unlock(&file_priv->lock); } /* * Mark the doorbell as unregistered and reset job queue pointers. * This function needs to be called when the VPU hardware is restarted - * and FW looses job queue state. The next time job queue is used it + * and FW loses job queue state. The next time job queue is used it * will be registered again. */ static void ivpu_cmdq_reset_locked(struct ivpu_file_priv *file_priv, u16 engine) @@ -161,15 +159,13 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev) struct ivpu_file_priv *file_priv; unsigned long ctx_id; - xa_for_each(&vdev->context_xa, ctx_id, file_priv) { - file_priv = ivpu_file_priv_get_by_ctx_id(vdev, ctx_id); - if (!file_priv) - continue; + mutex_lock(&vdev->context_list_lock); + xa_for_each(&vdev->context_xa, ctx_id, file_priv) ivpu_cmdq_reset_all(file_priv); - ivpu_file_priv_put(&file_priv); - } + mutex_unlock(&vdev->context_list_lock); + } static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) @@ -243,60 +239,32 @@ static struct dma_fence *ivpu_fence_create(struct ivpu_device *vdev) return &fence->base; } -static void job_get(struct ivpu_job *job, struct ivpu_job **link) +static void ivpu_job_destroy(struct ivpu_job *job) { struct ivpu_device *vdev = job->vdev; - - kref_get(&job->ref); - *link = job; - - ivpu_dbg(vdev, KREF, "Job get: id %u refcount %u\n", job->job_id, kref_read(&job->ref)); -} - -static void job_release(struct kref *ref) -{ - struct ivpu_job *job = container_of(ref, struct ivpu_job, ref); - struct ivpu_device *vdev = job->vdev; u32 i; + ivpu_dbg(vdev, JOB, "Job destroyed: id %3u ctx %2d engine %d", + job->job_id, job->file_priv->ctx.id, job->engine_idx); + for (i = 0; i < job->bo_count; i++) if (job->bos[i]) drm_gem_object_put(&job->bos[i]->base.base); dma_fence_put(job->done_fence); ivpu_file_priv_put(&job->file_priv); - - ivpu_dbg(vdev, KREF, "Job released: id %u\n", job->job_id); kfree(job); - - /* Allow the VPU to get suspended, must be called after ivpu_file_priv_put() */ - ivpu_rpm_put(vdev); -} - -static void job_put(struct ivpu_job *job) -{ - struct ivpu_device *vdev = job->vdev; - - ivpu_dbg(vdev, KREF, "Job put: id %u refcount %u\n", job->job_id, kref_read(&job->ref)); - kref_put(&job->ref, job_release); } static struct ivpu_job * -ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) +ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) { struct ivpu_device *vdev = file_priv->vdev; struct ivpu_job *job; - int ret; - - ret = ivpu_rpm_get(vdev); - if (ret < 0) - return NULL; job = kzalloc(struct_size(job, bos, bo_count), GFP_KERNEL); if (!job) - goto err_rpm_put; - - kref_init(&job->ref); + return NULL; job->vdev = vdev; job->engine_idx = engine_idx; @@ -310,17 +278,14 @@ ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) job->file_priv = ivpu_file_priv_get(file_priv); ivpu_dbg(vdev, JOB, "Job created: ctx %2d engine %d", file_priv->ctx.id, job->engine_idx); - return job; err_free_job: kfree(job); -err_rpm_put: - ivpu_rpm_put(vdev); return NULL; } -static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status) +static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32 job_status) { struct ivpu_job *job; @@ -337,9 +302,10 @@ static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status) ivpu_dbg(vdev, JOB, "Job complete: id %3u ctx %2d engine %d status 0x%x\n", job->job_id, job->file_priv->ctx.id, job->engine_idx, job_status); + ivpu_job_destroy(job); ivpu_stop_job_timeout_detection(vdev); - job_put(job); + ivpu_rpm_put(vdev); return 0; } @@ -349,10 +315,10 @@ void ivpu_jobs_abort_all(struct ivpu_device *vdev) unsigned long id; xa_for_each(&vdev->submitted_jobs_xa, id, job) - ivpu_job_done(vdev, id, VPU_JSM_STATUS_ABORTED); + ivpu_job_signal_and_destroy(vdev, id, VPU_JSM_STATUS_ABORTED); } -static int ivpu_direct_job_submission(struct ivpu_job *job) +static int ivpu_job_submit(struct ivpu_job *job) { struct ivpu_file_priv *file_priv = job->file_priv; struct ivpu_device *vdev = job->vdev; @@ -360,53 +326,65 @@ static int ivpu_direct_job_submission(struct ivpu_job *job) struct ivpu_cmdq *cmdq; int ret; + ret = ivpu_rpm_get(vdev); + if (ret < 0) + return ret; + mutex_lock(&file_priv->lock); cmdq = ivpu_cmdq_acquire(job->file_priv, job->engine_idx); if (!cmdq) { - ivpu_warn(vdev, "Failed get job queue, ctx %d engine %d\n", - file_priv->ctx.id, job->engine_idx); + ivpu_warn_ratelimited(vdev, "Failed get job queue, ctx %d engine %d\n", + file_priv->ctx.id, job->engine_idx); ret = -EINVAL; - goto err_unlock; + goto err_unlock_file_priv; } job_id_range.min = FIELD_PREP(JOB_ID_CONTEXT_MASK, (file_priv->ctx.id - 1)); job_id_range.max = job_id_range.min | JOB_ID_JOB_MASK; - job_get(job, &job); - ret = xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL); + xa_lock(&vdev->submitted_jobs_xa); + ret = __xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL); if (ret) { - ivpu_warn_ratelimited(vdev, "Failed to allocate job id: %d\n", ret); - goto err_job_put; + ivpu_dbg(vdev, JOB, "Too many active jobs in ctx %d\n", + file_priv->ctx.id); + ret = -EBUSY; + goto err_unlock_submitted_jobs_xa; } ret = ivpu_cmdq_push_job(cmdq, job); if (ret) - goto err_xa_erase; + goto err_erase_xa; ivpu_start_job_timeout_detection(vdev); - ivpu_dbg(vdev, JOB, "Job submitted: id %3u addr 0x%llx ctx %2d engine %d next %d\n", - job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id, - job->engine_idx, cmdq->jobq->header.tail); - - if (ivpu_test_mode & IVPU_TEST_MODE_NULL_HW) { - ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) { cmdq->jobq->header.head = cmdq->jobq->header.tail; wmb(); /* Flush WC buffer for jobq header */ } else { ivpu_cmdq_ring_db(vdev, cmdq); } + ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d addr 0x%llx next %d\n", + job->job_id, file_priv->ctx.id, job->engine_idx, + job->cmd_buf_vpu_addr, cmdq->jobq->header.tail); + + xa_unlock(&vdev->submitted_jobs_xa); + mutex_unlock(&file_priv->lock); + + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) + ivpu_job_signal_and_destroy(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); + return 0; -err_xa_erase: - xa_erase(&vdev->submitted_jobs_xa, job->job_id); -err_job_put: - job_put(job); -err_unlock: +err_erase_xa: + __xa_erase(&vdev->submitted_jobs_xa, job->job_id); +err_unlock_submitted_jobs_xa: + xa_unlock(&vdev->submitted_jobs_xa); +err_unlock_file_priv: mutex_unlock(&file_priv->lock); + ivpu_rpm_put(vdev); return ret; } @@ -488,6 +466,9 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (params->engine > DRM_IVPU_ENGINE_COPY) return -EINVAL; + if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) + return -EINVAL; + if (params->buffer_count == 0 || params->buffer_count > JOB_MAX_BUFFER_COUNT) return -EINVAL; @@ -509,44 +490,49 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) params->buffer_count * sizeof(u32)); if (ret) { ret = -EFAULT; - goto free_handles; + goto err_free_handles; } if (!drm_dev_enter(&vdev->drm, &idx)) { ret = -ENODEV; - goto free_handles; + goto err_free_handles; } ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n", file_priv->ctx.id, params->buffer_count); - job = ivpu_create_job(file_priv, params->engine, params->buffer_count); + job = ivpu_job_create(file_priv, params->engine, params->buffer_count); if (!job) { ivpu_err(vdev, "Failed to create job\n"); ret = -ENOMEM; - goto dev_exit; + goto err_exit_dev; } ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, params->buffer_count, params->commands_offset); if (ret) { - ivpu_err(vdev, "Failed to prepare job, ret %d\n", ret); - goto job_put; + ivpu_err(vdev, "Failed to prepare job: %d\n", ret); + goto err_destroy_job; } - ret = ivpu_direct_job_submission(job); - if (ret) { - dma_fence_signal(job->done_fence); - ivpu_err(vdev, "Failed to submit job to the HW, ret %d\n", ret); - } + down_read(&vdev->pm->reset_lock); + ret = ivpu_job_submit(job); + up_read(&vdev->pm->reset_lock); + if (ret) + goto err_signal_fence; -job_put: - job_put(job); -dev_exit: drm_dev_exit(idx); -free_handles: kfree(buf_handles); + return ret; +err_signal_fence: + dma_fence_signal(job->done_fence); +err_destroy_job: + ivpu_job_destroy(job); +err_exit_dev: + drm_dev_exit(idx); +err_free_handles: + kfree(buf_handles); return ret; } @@ -568,7 +554,7 @@ ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr, } payload = (struct vpu_ipc_msg_payload_job_done *)&jsm_msg->payload; - ret = ivpu_job_done(vdev, payload->job_id, payload->job_status); + ret = ivpu_job_signal_and_destroy(vdev, payload->job_id, payload->job_status); if (!ret && !xa_empty(&vdev->submitted_jobs_xa)) ivpu_start_job_timeout_detection(vdev); } diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h index 45a2f2ec82e5ba69110d737e154c38bf6765174a..ca4984071cc76b17d858ae86929a48a9cea39c88 100644 --- a/drivers/accel/ivpu/ivpu_job.h +++ b/drivers/accel/ivpu/ivpu_job.h @@ -43,7 +43,6 @@ struct ivpu_cmdq { will update the job status */ struct ivpu_job { - struct kref ref; struct ivpu_device *vdev; struct ivpu_file_priv *file_priv; struct dma_fence *done_fence; @@ -56,7 +55,7 @@ struct ivpu_job { int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file); -void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv); +void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv); void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev); void ivpu_job_done_consumer_init(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index 2228c44b115fa0e4d48f36c115e2fdc7b434a8c0..9a3122ffce03c1dc11311ab36f31f775f4fdf6fe 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -7,6 +7,7 @@ #include #include "ivpu_drv.h" +#include "ivpu_hw.h" #include "ivpu_hw_reg_io.h" #include "ivpu_mmu.h" #include "ivpu_mmu_context.h" @@ -518,6 +519,7 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) ivpu_err(vdev, "Timed out waiting for MMU consumer: %d, error: %s\n", ret, ivpu_mmu_cmdq_err_to_str(err)); + ivpu_hw_diagnose_failure(vdev); } return ret; @@ -885,7 +887,6 @@ static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev) void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev) { - bool schedule_recovery = false; u32 *event; u32 ssid; @@ -895,14 +896,21 @@ void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev) ivpu_mmu_dump_event(vdev, event); ssid = FIELD_GET(IVPU_MMU_EVT_SSID_MASK, event[0]); - if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) - schedule_recovery = true; - else - ivpu_mmu_user_context_mark_invalid(vdev, ssid); + if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) { + ivpu_pm_trigger_recovery(vdev, "MMU event"); + return; + } + + ivpu_mmu_user_context_mark_invalid(vdev, ssid); } +} - if (schedule_recovery) - ivpu_pm_schedule_recovery(vdev); +void ivpu_mmu_evtq_dump(struct ivpu_device *vdev) +{ + u32 *event; + + while ((event = ivpu_mmu_get_event(vdev)) != NULL) + ivpu_mmu_dump_event(vdev, event); } void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_mmu.h b/drivers/accel/ivpu/ivpu_mmu.h index cb551126806baa9bb47a967c7bff916b444c2427..6fa35c240710625670b6879098833c6cd680fb40 100644 --- a/drivers/accel/ivpu/ivpu_mmu.h +++ b/drivers/accel/ivpu/ivpu_mmu.h @@ -46,5 +46,6 @@ int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid); void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev); void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev); +void ivpu_mmu_evtq_dump(struct ivpu_device *vdev); #endif /* __IVPU_MMU_H__ */ diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c index 12a8c09d4547d7d9b81cd91d93307e59e648e14f..fe61612992364c65d184eef9c3a3ad3ebb60ce6a 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -355,6 +355,9 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset; size_t size = sg_dma_len(sg) + sg->offset; + ivpu_dbg(vdev, MMU_MAP, "Map ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n", + ctx->id, dma_addr, vpu_addr, size); + ret = ivpu_mmu_context_map_pages(vdev, ctx, vpu_addr, dma_addr, size, prot); if (ret) { ivpu_err(vdev, "Failed to map context pages\n"); @@ -366,6 +369,7 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, /* Ensure page table modifications are flushed from wc buffers to memory */ wmb(); + mutex_unlock(&ctx->lock); ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); @@ -388,14 +392,19 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct mutex_lock(&ctx->lock); for_each_sgtable_dma_sg(sgt, sg, i) { + dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset; size_t size = sg_dma_len(sg) + sg->offset; + ivpu_dbg(vdev, MMU_MAP, "Unmap ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n", + ctx->id, dma_addr, vpu_addr, size); + ivpu_mmu_context_unmap_pages(ctx, vpu_addr, size); vpu_addr += size; } /* Ensure page table modifications are flushed from wc buffers to memory */ wmb(); + mutex_unlock(&ctx->lock); ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 0af8864cb3b55f636bc7418a03dc3c07360e7ac8..f501f27ebafdf6687b5a46ca7e2387faa931af3e 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -13,6 +13,7 @@ #include "ivpu_drv.h" #include "ivpu_hw.h" #include "ivpu_fw.h" +#include "ivpu_fw_log.h" #include "ivpu_ipc.h" #include "ivpu_job.h" #include "ivpu_jsm_msg.h" @@ -111,6 +112,14 @@ static void ivpu_pm_recovery_work(struct work_struct *work) char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL}; int ret; + ivpu_err(vdev, "Recovering the VPU (reset #%d)\n", atomic_read(&vdev->pm->reset_counter)); + + ret = pm_runtime_resume_and_get(vdev->drm.dev); + if (ret) + ivpu_err(vdev, "Failed to resume VPU: %d\n", ret); + + ivpu_fw_log_dump(vdev); + retry: ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) { @@ -122,11 +131,13 @@ retry: ivpu_err(vdev, "Failed to reset VPU: %d\n", ret); kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt); + pm_runtime_mark_last_busy(vdev->drm.dev); + pm_runtime_put_autosuspend(vdev->drm.dev); } -void ivpu_pm_schedule_recovery(struct ivpu_device *vdev) +void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason) { - struct ivpu_pm_info *pm = vdev->pm; + ivpu_err(vdev, "Recovery triggered by %s\n", reason); if (ivpu_disable_recovery) { ivpu_err(vdev, "Recovery not available when disable_recovery param is set\n"); @@ -138,10 +149,11 @@ void ivpu_pm_schedule_recovery(struct ivpu_device *vdev) return; } - /* Schedule recovery if it's not in progress */ - if (atomic_cmpxchg(&pm->in_reset, 0, 1) == 0) { - ivpu_hw_irq_disable(vdev); - queue_work(system_long_wq, &pm->recovery_work); + /* Trigger recovery if it's not in progress */ + if (atomic_cmpxchg(&vdev->pm->reset_pending, 0, 1) == 0) { + ivpu_hw_diagnose_failure(vdev); + ivpu_hw_irq_disable(vdev); /* Disable IRQ early to protect from IRQ storm */ + queue_work(system_long_wq, &vdev->pm->recovery_work); } } @@ -149,12 +161,8 @@ static void ivpu_job_timeout_work(struct work_struct *work) { struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, job_timeout_work.work); struct ivpu_device *vdev = pm->vdev; - unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; - ivpu_err(vdev, "TDR detected, timeout %lu ms", timeout_ms); - ivpu_hw_diagnose_failure(vdev); - - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "TDR"); } void ivpu_start_job_timeout_detection(struct ivpu_device *vdev) @@ -227,6 +235,9 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) bool hw_is_idle = true; int ret; + drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa)); + drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work)); + ivpu_dbg(vdev, PM, "Runtime suspend..\n"); if (!ivpu_hw_is_idle(vdev) && vdev->pm->suspend_reschedule_counter) { @@ -247,7 +258,8 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) ivpu_err(vdev, "Failed to set suspend VPU: %d\n", ret); if (!hw_is_idle) { - ivpu_warn(vdev, "VPU failed to enter idle, force suspended.\n"); + ivpu_err(vdev, "VPU failed to enter idle, force suspended.\n"); + ivpu_fw_log_dump(vdev); ivpu_pm_prepare_cold_boot(vdev); } else { ivpu_pm_prepare_warm_boot(vdev); @@ -308,11 +320,12 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev) { struct ivpu_device *vdev = pci_get_drvdata(pdev); - pm_runtime_get_sync(vdev->drm.dev); - ivpu_dbg(vdev, PM, "Pre-reset..\n"); atomic_inc(&vdev->pm->reset_counter); - atomic_set(&vdev->pm->in_reset, 1); + atomic_set(&vdev->pm->reset_pending, 1); + + pm_runtime_get_sync(vdev->drm.dev); + down_write(&vdev->pm->reset_lock); ivpu_prepare_for_reset(vdev); ivpu_hw_reset(vdev); ivpu_pm_prepare_cold_boot(vdev); @@ -329,9 +342,11 @@ void ivpu_pm_reset_done_cb(struct pci_dev *pdev) ret = ivpu_resume(vdev); if (ret) ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret); - atomic_set(&vdev->pm->in_reset, 0); + up_write(&vdev->pm->reset_lock); + atomic_set(&vdev->pm->reset_pending, 0); ivpu_dbg(vdev, PM, "Post-reset done.\n"); + pm_runtime_mark_last_busy(vdev->drm.dev); pm_runtime_put_autosuspend(vdev->drm.dev); } @@ -344,7 +359,10 @@ void ivpu_pm_init(struct ivpu_device *vdev) pm->vdev = vdev; pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT; - atomic_set(&pm->in_reset, 0); + init_rwsem(&pm->reset_lock); + atomic_set(&pm->reset_pending, 0); + atomic_set(&pm->reset_counter, 0); + INIT_WORK(&pm->recovery_work, ivpu_pm_recovery_work); INIT_DELAYED_WORK(&pm->job_timeout_work, ivpu_job_timeout_work); diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index 97c6e0b0aa42d0a5a071940c5b54a052f99a748c..ec60fbeefefc65bbca4ed619d7265aabffd1bb61 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -6,6 +6,7 @@ #ifndef __IVPU_PM_H__ #define __IVPU_PM_H__ +#include #include struct ivpu_device; @@ -14,8 +15,9 @@ struct ivpu_pm_info { struct ivpu_device *vdev; struct delayed_work job_timeout_work; struct work_struct recovery_work; - atomic_t in_reset; + struct rw_semaphore reset_lock; atomic_t reset_counter; + atomic_t reset_pending; bool is_warmboot; u32 suspend_reschedule_counter; }; @@ -37,7 +39,7 @@ int __must_check ivpu_rpm_get(struct ivpu_device *vdev); int __must_check ivpu_rpm_get_if_active(struct ivpu_device *vdev); void ivpu_rpm_put(struct ivpu_device *vdev); -void ivpu_pm_schedule_recovery(struct ivpu_device *vdev); +void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason); void ivpu_start_job_timeout_detection(struct ivpu_device *vdev); void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev); diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index cb77d048ed54b72c51123d2328ab1a60634adeb9..51cb85d0387b2c71ed3bc7fc4bedc75fd83ec01c 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -358,8 +358,8 @@ static struct mhi_channel_config aic100_channels[] = { .wake_capable = false, }, { - .num = 21, .name = "QAIC_TIMESYNC", + .num = 21, .num_elements = 32, .local_elements = 0, .event_ring = 0, @@ -390,8 +390,8 @@ static struct mhi_channel_config aic100_channels[] = { .wake_capable = false, }, { - .num = 23, .name = "QAIC_TIMESYNC_PERIODIC", + .num = 23, .num_elements = 32, .local_elements = 0, .event_ring = 0, diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index 582836f9538f958b4c4cebf3857d85610cb01c34..9256653b30362ecea39e92d54bc3568380cae2cd 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -30,6 +30,7 @@ #define to_qaic_drm_device(dev) container_of(dev, struct qaic_drm_device, drm) #define to_drm(qddev) (&(qddev)->drm) #define to_accel_kdev(qddev) (to_drm(qddev)->accel->kdev) /* Return Linux device of accel node */ +#define to_qaic_device(dev) (to_qaic_drm_device((dev))->qdev) enum __packed dev_states { /* Device is offline or will be very soon */ @@ -191,8 +192,6 @@ struct qaic_bo { u32 nr_slice; /* Number of slice that have been transferred by DMA engine */ u32 nr_slice_xfer_done; - /* true = BO is queued for execution, true = BO is not queued */ - bool queued; /* * If true then user has attached slicing information to this BO by * calling DRM_IOCTL_QAIC_ATTACH_SLICE_BO ioctl. diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 03c9a793da35ad081a2224250d424abb751e921c..2459fe4a3f95a7c596de929bf6297cac89f01a38 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -141,6 +141,11 @@ struct dbc_rsp { __le16 status; } __packed; +static inline bool bo_queued(struct qaic_bo *bo) +{ + return !list_empty(&bo->xfer_list); +} + inline int get_dbc_req_elem_size(void) { return sizeof(struct dbc_req); @@ -569,6 +574,9 @@ static void qaic_free_sgt(struct sg_table *sgt) { struct scatterlist *sg; + if (!sgt) + return; + for (sg = sgt->sgl; sg; sg = sg_next(sg)) if (sg_page(sg)) __free_pages(sg_page(sg), get_order(sg->length)); @@ -648,6 +656,7 @@ static void qaic_init_bo(struct qaic_bo *bo, bool reinit) } complete_all(&bo->xfer_done); INIT_LIST_HEAD(&bo->slices); + INIT_LIST_HEAD(&bo->xfer_list); } static struct qaic_bo *qaic_alloc_init_bo(void) @@ -709,9 +718,13 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi if (ret) goto free_bo; + ret = drm_gem_create_mmap_offset(obj); + if (ret) + goto free_bo; + ret = drm_gem_handle_create(file_priv, obj, &args->handle); if (ret) - goto free_sgt; + goto free_bo; bo->handle = args->handle; drm_gem_object_put(obj); @@ -720,10 +733,8 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi return 0; -free_sgt: - qaic_free_sgt(bo->sgt); free_bo: - kfree(bo); + drm_gem_object_put(obj); unlock_dev_srcu: srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id); unlock_usr_srcu: @@ -738,7 +749,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file struct drm_gem_object *obj; struct qaic_device *qdev; struct qaic_user *usr; - int ret; + int ret = 0; usr = file_priv->driver_priv; usr_rcu_id = srcu_read_lock(&usr->qddev_lock); @@ -760,9 +771,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file goto unlock_dev_srcu; } - ret = drm_gem_create_mmap_offset(obj); - if (ret == 0) - args->offset = drm_vma_node_offset_addr(&obj->vma_node); + args->offset = drm_vma_node_offset_addr(&obj->vma_node); drm_gem_object_put(obj); @@ -828,9 +837,6 @@ static int qaic_prepare_import_bo(struct qaic_bo *bo, struct qaic_attach_slice_h struct sg_table *sgt; int ret; - if (obj->import_attach->dmabuf->size < hdr->size) - return -EINVAL; - sgt = dma_buf_map_attachment(obj->import_attach, hdr->dir); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); @@ -847,9 +853,6 @@ static int qaic_prepare_export_bo(struct qaic_device *qdev, struct qaic_bo *bo, { int ret; - if (bo->base.size < hdr->size) - return -EINVAL; - ret = dma_map_sgtable(&qdev->pdev->dev, bo->sgt, hdr->dir, 0); if (ret) return -EFAULT; @@ -950,9 +953,6 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi if (arg_size / args->hdr.count != sizeof(*slice_ent)) return -EINVAL; - if (args->hdr.size == 0) - return -EINVAL; - if (!(args->hdr.dir == DMA_TO_DEVICE || args->hdr.dir == DMA_FROM_DEVICE)) return -EINVAL; @@ -992,16 +992,16 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi goto free_slice_ent; } - ret = qaic_validate_req(qdev, slice_ent, args->hdr.count, args->hdr.size); - if (ret) - goto free_slice_ent; - obj = drm_gem_object_lookup(file_priv, args->hdr.handle); if (!obj) { ret = -ENOENT; goto free_slice_ent; } + ret = qaic_validate_req(qdev, slice_ent, args->hdr.count, obj->size); + if (ret) + goto put_bo; + bo = to_qaic_bo(obj); ret = mutex_lock_interruptible(&bo->lock); if (ret) @@ -1173,7 +1173,6 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil struct bo_slice *slice; unsigned long flags; struct qaic_bo *bo; - bool queued; int i, j; int ret; @@ -1205,9 +1204,7 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil } spin_lock_irqsave(&dbc->xfer_lock, flags); - queued = bo->queued; - bo->queued = true; - if (queued) { + if (bo_queued(bo)) { spin_unlock_irqrestore(&dbc->xfer_lock, flags); ret = -EINVAL; goto unlock_bo; @@ -1230,7 +1227,6 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil else ret = copy_exec_reqs(qdev, slice, dbc->id, head, tail); if (ret) { - bo->queued = false; spin_unlock_irqrestore(&dbc->xfer_lock, flags); goto unlock_bo; } @@ -1253,8 +1249,7 @@ failed_to_send_bo: spin_lock_irqsave(&dbc->xfer_lock, flags); bo = list_last_entry(&dbc->xfer_list, struct qaic_bo, xfer_list); obj = &bo->base; - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); spin_unlock_irqrestore(&dbc->xfer_lock, flags); dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, bo->dir); drm_gem_object_put(obj); @@ -1615,8 +1610,7 @@ read_fifo: */ dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, bo->dir); bo->nr_slice_xfer_done = 0; - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); bo->perf_stats.req_processed_ts = ktime_get_ns(); complete_all(&bo->xfer_done); drm_gem_object_put(&bo->base); @@ -1875,7 +1869,7 @@ int qaic_detach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi /* Check if BO is committed to H/W for DMA */ spin_lock_irqsave(&dbc->xfer_lock, flags); - if (bo->queued) { + if (bo_queued(bo)) { spin_unlock_irqrestore(&dbc->xfer_lock, flags); ret = -EBUSY; goto unlock_ch_srcu; @@ -1905,8 +1899,7 @@ static void empty_xfer_list(struct qaic_device *qdev, struct dma_bridge_chan *db spin_lock_irqsave(&dbc->xfer_lock, flags); while (!list_empty(&dbc->xfer_list)) { bo = list_first_entry(&dbc->xfer_list, typeof(*bo), xfer_list); - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); spin_unlock_irqrestore(&dbc->xfer_lock, flags); bo->nr_slice_xfer_done = 0; bo->req_id = 0; diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 2a313eb69b1219b5b985dc39b9b9742690c97ccf..d1a632dbaec6e17a8d44120dd2b7e3dd02aed835 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -44,6 +44,53 @@ MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode"); static bool link_up; static DEFINE_IDA(qaic_usrs); +static void qaicm_wq_release(struct drm_device *dev, void *res) +{ + struct workqueue_struct *wq = res; + + destroy_workqueue(wq); +} + +static struct workqueue_struct *qaicm_wq_init(struct drm_device *dev, const char *fmt) +{ + struct workqueue_struct *wq; + int ret; + + wq = alloc_workqueue(fmt, WQ_UNBOUND, 0); + if (!wq) + return ERR_PTR(-ENOMEM); + ret = drmm_add_action_or_reset(dev, qaicm_wq_release, wq); + if (ret) + return ERR_PTR(ret); + + return wq; +} + +static void qaicm_srcu_release(struct drm_device *dev, void *res) +{ + struct srcu_struct *lock = res; + + cleanup_srcu_struct(lock); +} + +static int qaicm_srcu_init(struct drm_device *dev, struct srcu_struct *lock) +{ + int ret; + + ret = init_srcu_struct(lock); + if (ret) + return ret; + + return drmm_add_action_or_reset(dev, qaicm_srcu_release, lock); +} + +static void qaicm_pci_release(struct drm_device *dev, void *res) +{ + struct qaic_device *qdev = to_qaic_device(dev); + + pci_set_drvdata(qdev->pdev, NULL); +} + static void free_usr(struct kref *kref) { struct qaic_user *usr = container_of(kref, struct qaic_user, ref_count); @@ -299,74 +346,73 @@ void qaic_dev_reset_clean_local_state(struct qaic_device *qdev) release_dbc(qdev, i); } -static void cleanup_qdev(struct qaic_device *qdev) -{ - int i; - - for (i = 0; i < qdev->num_dbc; ++i) - cleanup_srcu_struct(&qdev->dbc[i].ch_lock); - cleanup_srcu_struct(&qdev->dev_lock); - pci_set_drvdata(qdev->pdev, NULL); - destroy_workqueue(qdev->cntl_wq); - destroy_workqueue(qdev->qts_wq); -} - static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; struct qaic_drm_device *qddev; struct qaic_device *qdev; - int i; + struct drm_device *drm; + int i, ret; - qdev = devm_kzalloc(&pdev->dev, sizeof(*qdev), GFP_KERNEL); + qdev = devm_kzalloc(dev, sizeof(*qdev), GFP_KERNEL); if (!qdev) return NULL; qdev->dev_state = QAIC_OFFLINE; if (id->device == PCI_DEV_AIC100) { qdev->num_dbc = 16; - qdev->dbc = devm_kcalloc(&pdev->dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); + qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); if (!qdev->dbc) return NULL; } - qdev->cntl_wq = alloc_workqueue("qaic_cntl", WQ_UNBOUND, 0); - if (!qdev->cntl_wq) + qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm); + if (IS_ERR(qddev)) + return NULL; + + drm = to_drm(qddev); + pci_set_drvdata(pdev, qdev); + + ret = drmm_mutex_init(drm, &qddev->users_mutex); + if (ret) + return NULL; + ret = drmm_add_action_or_reset(drm, qaicm_pci_release, NULL); + if (ret) + return NULL; + ret = drmm_mutex_init(drm, &qdev->cntl_mutex); + if (ret) return NULL; - qdev->qts_wq = alloc_workqueue("qaic_ts", WQ_UNBOUND, 0); - if (!qdev->qts_wq) { - destroy_workqueue(qdev->cntl_wq); + qdev->cntl_wq = qaicm_wq_init(drm, "qaic_cntl"); + if (IS_ERR(qdev->cntl_wq)) + return NULL; + qdev->qts_wq = qaicm_wq_init(drm, "qaic_ts"); + if (IS_ERR(qdev->qts_wq)) return NULL; - } - pci_set_drvdata(pdev, qdev); + ret = qaicm_srcu_init(drm, &qdev->dev_lock); + if (ret) + return NULL; + + qdev->qddev = qddev; qdev->pdev = pdev; + qddev->qdev = qdev; - mutex_init(&qdev->cntl_mutex); INIT_LIST_HEAD(&qdev->cntl_xfer_list); - init_srcu_struct(&qdev->dev_lock); + INIT_LIST_HEAD(&qddev->users); for (i = 0; i < qdev->num_dbc; ++i) { spin_lock_init(&qdev->dbc[i].xfer_lock); qdev->dbc[i].qdev = qdev; qdev->dbc[i].id = i; INIT_LIST_HEAD(&qdev->dbc[i].xfer_list); - init_srcu_struct(&qdev->dbc[i].ch_lock); + ret = qaicm_srcu_init(drm, &qdev->dbc[i].ch_lock); + if (ret) + return NULL; init_waitqueue_head(&qdev->dbc[i].dbc_release); INIT_LIST_HEAD(&qdev->dbc[i].bo_lists); } - qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm); - if (IS_ERR(qddev)) { - cleanup_qdev(qdev); - return NULL; - } - - drmm_mutex_init(to_drm(qddev), &qddev->users_mutex); - INIT_LIST_HEAD(&qddev->users); - qddev->qdev = qdev; - qdev->qddev = qddev; - return qdev; } @@ -472,35 +518,28 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = init_pci(qdev, pdev); if (ret) - goto cleanup_qdev; + return ret; for (i = 0; i < qdev->num_dbc; ++i) qdev->dbc[i].dbc_base = qdev->bar_2 + QAIC_DBC_OFF(i); mhi_irq = init_msi(qdev, pdev); - if (mhi_irq < 0) { - ret = mhi_irq; - goto cleanup_qdev; - } + if (mhi_irq < 0) + return mhi_irq; ret = qaic_create_drm_device(qdev, QAIC_NO_PARTITION); if (ret) - goto cleanup_qdev; + return ret; qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq, qdev->single_msi); if (IS_ERR(qdev->mhi_cntrl)) { ret = PTR_ERR(qdev->mhi_cntrl); - goto cleanup_drm_dev; + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); + return ret; } return 0; - -cleanup_drm_dev: - qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); -cleanup_qdev: - cleanup_qdev(qdev); - return ret; } static void qaic_pci_remove(struct pci_dev *pdev) @@ -511,9 +550,8 @@ static void qaic_pci_remove(struct pci_dev *pdev) return; qaic_dev_reset_clean_local_state(qdev); - qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); qaic_mhi_free_controller(qdev->mhi_cntrl, link_up); - cleanup_qdev(qdev); + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); } static void qaic_pci_shutdown(struct pci_dev *pdev) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 8dd23b19e99731ce1ce5f5d6062366aece0dd415..eca24f41556df04ac61747e05aace9622fbcc580 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -478,6 +478,16 @@ binder_enqueue_thread_work_ilocked(struct binder_thread *thread, { WARN_ON(!list_empty(&thread->waiting_thread_node)); binder_enqueue_work_ilocked(work, &thread->todo); + + /* (e)poll-based threads require an explicit wakeup signal when + * queuing their own work; they rely on these events to consume + * messages without I/O block. Without it, threads risk waiting + * indefinitely without handling the work. + */ + if (thread->looper & BINDER_LOOPER_STATE_POLL && + thread->pid == current->pid && !thread->process_todo) + wake_up_interruptible_sync(&thread->wait); + thread->process_todo = true; } diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3a5f3255f51b39cc4a5b65554e7d55eed8ea2c57..da2e74fce2d995a932914876b44b3fb5d4275d2e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -48,6 +48,7 @@ enum { enum board_ids { /* board IDs by feature in alphabetical order */ board_ahci, + board_ahci_43bit_dma, board_ahci_ign_iferr, board_ahci_low_power, board_ahci_no_debounce_delay, @@ -128,6 +129,13 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_43bit_dma] = { + AHCI_HFLAGS (AHCI_HFLAG_43BIT_ONLY), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, [board_ahci_ign_iferr] = { AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), .flags = AHCI_FLAG_COMMON, @@ -597,14 +605,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ { PCI_VDEVICE(PROMISE, 0x3781), board_ahci }, /* FastTrak TX8660 ahci-mode */ - /* Asmedia */ - { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */ - { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */ - { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ - { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ - { PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci }, /* ASM1061R */ - { PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci }, /* ASM1062R */ - { PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci }, /* ASM1062+JMB575 */ + /* ASMedia */ + { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci_43bit_dma }, /* ASM1060 */ + { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci_43bit_dma }, /* ASM1060 */ + { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci_43bit_dma }, /* ASM1061 */ + { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci_43bit_dma }, /* ASM1061/1062 */ + { PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci_43bit_dma }, /* ASM1061R */ + { PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci_43bit_dma }, /* ASM1062R */ + { PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci_43bit_dma }, /* ASM1062+JMB575 */ { PCI_VDEVICE(ASMEDIA, 0x1062), board_ahci }, /* ASM1062A */ { PCI_VDEVICE(ASMEDIA, 0x1064), board_ahci }, /* ASM1064 */ { PCI_VDEVICE(ASMEDIA, 0x1164), board_ahci }, /* ASM1164 */ @@ -663,6 +671,11 @@ MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets"); static void ahci_pci_save_initial_config(struct pci_dev *pdev, struct ahci_host_priv *hpriv) { + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1166) { + dev_info(&pdev->dev, "ASM1166 has only six ports\n"); + hpriv->saved_port_map = 0x3f; + } + if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) { dev_info(&pdev->dev, "JMB361 has only one port\n"); hpriv->saved_port_map = 1; @@ -949,11 +962,20 @@ static int ahci_pci_device_resume(struct device *dev) #endif /* CONFIG_PM */ -static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) +static int ahci_configure_dma_masks(struct pci_dev *pdev, + struct ahci_host_priv *hpriv) { - const int dma_bits = using_dac ? 64 : 32; + int dma_bits; int rc; + if (hpriv->cap & HOST_CAP_64) { + dma_bits = 64; + if (hpriv->flags & AHCI_HFLAG_43BIT_ONLY) + dma_bits = 43; + } else { + dma_bits = 32; + } + /* * If the device fixup already set the dma_mask to some non-standard * value, don't extend it here. This happens on STA2X11, for example. @@ -1926,7 +1948,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ahci_gtf_filter_workaround(host); /* initialize adapter */ - rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); + rc = ahci_configure_dma_masks(pdev, hpriv); if (rc) return rc; diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 4bae95b06ae3c953de7a567c35f9b46dd9e3083f..df8f8a1a3a34c3ee26d0d2b899522a82d220b6c2 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -247,6 +247,7 @@ enum { AHCI_HFLAG_SUSPEND_PHYS = BIT(26), /* handle PHYs during suspend/resume */ AHCI_HFLAG_NO_SXS = BIT(28), /* SXS not supported */ + AHCI_HFLAG_43BIT_ONLY = BIT(29), /* 43bit DMA addr limit */ /* ap->flags bits */ diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index b6656c287175c7653324758ccb5422dc36168e3d..0fb1934875f2084a753216cf54ff443aa601361b 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -784,7 +784,7 @@ bool sata_lpm_ignore_phy_events(struct ata_link *link) EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); static const char *ata_lpm_policy_names[] = { - [ATA_LPM_UNKNOWN] = "max_performance", + [ATA_LPM_UNKNOWN] = "keep_firmware_settings", [ATA_LPM_MAX_POWER] = "max_performance", [ATA_LPM_MED_POWER] = "medium_power", [ATA_LPM_MED_POWER_WITH_DIPM] = "med_power_with_dipm", diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index d2dbf8aaccb5b1320909964b3092ea47df90cc4a..b1b47d88f5db44dd9dcb8fc7468718ac36869130 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -333,6 +333,7 @@ aoeblk_gdalloc(void *vp) struct gendisk *gd; mempool_t *mp; struct blk_mq_tag_set *set; + sector_t ssize; ulong flags; int late = 0; int err; @@ -396,7 +397,7 @@ aoeblk_gdalloc(void *vp) gd->minors = AOE_PARTITIONS; gd->fops = &aoe_bdops; gd->private_data = d; - set_capacity(gd, d->ssize); + ssize = d->ssize; snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d", d->aoemajor, d->aoeminor); @@ -405,6 +406,8 @@ aoeblk_gdalloc(void *vp) spin_unlock_irqrestore(&d->lock, flags); + set_capacity(gd, ssize); + err = device_add_disk(NULL, gd, aoe_attr_groups); if (err) goto out_disk_cleanup; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index a999b698b131f7763916c3bd0de5c87478fd0df4..12b5d53ec85645fb22395d41adef81d13cdb7292 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3452,14 +3452,15 @@ static bool rbd_lock_add_request(struct rbd_img_request *img_req) static void rbd_lock_del_request(struct rbd_img_request *img_req) { struct rbd_device *rbd_dev = img_req->rbd_dev; - bool need_wakeup; + bool need_wakeup = false; lockdep_assert_held(&rbd_dev->lock_rwsem); spin_lock(&rbd_dev->lock_lists_lock); - rbd_assert(!list_empty(&img_req->lock_item)); - list_del_init(&img_req->lock_item); - need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING && - list_empty(&rbd_dev->running_list)); + if (!list_empty(&img_req->lock_item)) { + list_del_init(&img_req->lock_item); + need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING && + list_empty(&rbd_dev->running_list)); + } spin_unlock(&rbd_dev->lock_lists_lock); if (need_wakeup) complete(&rbd_dev->releasing_wait); @@ -3842,14 +3843,19 @@ static void wake_lock_waiters(struct rbd_device *rbd_dev, int result) return; } - list_for_each_entry(img_req, &rbd_dev->acquiring_list, lock_item) { + while (!list_empty(&rbd_dev->acquiring_list)) { + img_req = list_first_entry(&rbd_dev->acquiring_list, + struct rbd_img_request, lock_item); mutex_lock(&img_req->state_mutex); rbd_assert(img_req->state == RBD_IMG_EXCLUSIVE_LOCK); + if (!result) + list_move_tail(&img_req->lock_item, + &rbd_dev->running_list); + else + list_del_init(&img_req->lock_item); rbd_img_schedule(img_req, result); mutex_unlock(&img_req->state_mutex); } - - list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list); } static bool locker_equal(const struct ceph_locker *lhs, @@ -5326,7 +5332,7 @@ static void rbd_dev_release(struct device *dev) if (need_put) { destroy_workqueue(rbd_dev->task_wq); - ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id); + ida_free(&rbd_dev_id_ida, rbd_dev->dev_id); } rbd_dev_free(rbd_dev); @@ -5402,9 +5408,9 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, return NULL; /* get an id and fill in device name */ - rbd_dev->dev_id = ida_simple_get(&rbd_dev_id_ida, 0, - minor_to_rbd_dev_id(1 << MINORBITS), - GFP_KERNEL); + rbd_dev->dev_id = ida_alloc_max(&rbd_dev_id_ida, + minor_to_rbd_dev_id(1 << MINORBITS) - 1, + GFP_KERNEL); if (rbd_dev->dev_id < 0) goto fail_rbd_dev; @@ -5425,7 +5431,7 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, return rbd_dev; fail_dev_id: - ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id); + ida_free(&rbd_dev_id_ida, rbd_dev->dev_id); fail_rbd_dev: rbd_dev_free(rbd_dev); return NULL; diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 1f6186475715e0592df1028ade0a336703338b15..1791d37fbc53c57e0f13469934eee357c0de87cc 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -1232,14 +1232,13 @@ static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy) max_limit_perf = div_u64(policy->max * cpudata->highest_perf, cpudata->max_freq); min_limit_perf = div_u64(policy->min * cpudata->highest_perf, cpudata->max_freq); + WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); + WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); + max_perf = clamp_t(unsigned long, max_perf, cpudata->min_limit_perf, cpudata->max_limit_perf); min_perf = clamp_t(unsigned long, min_perf, cpudata->min_limit_perf, cpudata->max_limit_perf); - - WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); - WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); - value = READ_ONCE(cpudata->cppc_req_cached); if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 2ca70b0b5fdc5d39990bb88ba4dcd1f7e7131d31..ca94e60e705a1df435b1dd75a13c0a50dc3f8c27 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -529,6 +529,30 @@ static int intel_pstate_cppc_get_scaling(int cpu) } #endif /* CONFIG_ACPI_CPPC_LIB */ +static int intel_pstate_freq_to_hwp_rel(struct cpudata *cpu, int freq, + unsigned int relation) +{ + if (freq == cpu->pstate.turbo_freq) + return cpu->pstate.turbo_pstate; + + if (freq == cpu->pstate.max_freq) + return cpu->pstate.max_pstate; + + switch (relation) { + case CPUFREQ_RELATION_H: + return freq / cpu->pstate.scaling; + case CPUFREQ_RELATION_C: + return DIV_ROUND_CLOSEST(freq, cpu->pstate.scaling); + } + + return DIV_ROUND_UP(freq, cpu->pstate.scaling); +} + +static int intel_pstate_freq_to_hwp(struct cpudata *cpu, int freq) +{ + return intel_pstate_freq_to_hwp_rel(cpu, freq, CPUFREQ_RELATION_L); +} + /** * intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels. * @cpu: Target CPU. @@ -546,6 +570,7 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling; int perf_ctl_turbo = pstate_funcs.get_turbo(cpu->cpu); int scaling = cpu->pstate.scaling; + int freq; pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys); pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo); @@ -559,16 +584,16 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling, perf_ctl_scaling); - cpu->pstate.max_pstate_physical = - DIV_ROUND_UP(perf_ctl_max_phys * perf_ctl_scaling, - scaling); + freq = perf_ctl_max_phys * perf_ctl_scaling; + cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq); - cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling; + freq = cpu->pstate.min_pstate * perf_ctl_scaling; + cpu->pstate.min_freq = freq; /* * Cast the min P-state value retrieved via pstate_funcs.get_min() to * the effective range of HWP performance levels. */ - cpu->pstate.min_pstate = DIV_ROUND_UP(cpu->pstate.min_freq, scaling); + cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq); } static inline void update_turbo_state(void) @@ -2528,13 +2553,12 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu, * abstract values to represent performance rather than pure ratios. */ if (hwp_active && cpu->pstate.scaling != perf_ctl_scaling) { - int scaling = cpu->pstate.scaling; int freq; freq = max_policy_perf * perf_ctl_scaling; - max_policy_perf = DIV_ROUND_UP(freq, scaling); + max_policy_perf = intel_pstate_freq_to_hwp(cpu, freq); freq = min_policy_perf * perf_ctl_scaling; - min_policy_perf = DIV_ROUND_UP(freq, scaling); + min_policy_perf = intel_pstate_freq_to_hwp(cpu, freq); } pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n", @@ -2908,18 +2932,7 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy, cpufreq_freq_transition_begin(policy, &freqs); - switch (relation) { - case CPUFREQ_RELATION_L: - target_pstate = DIV_ROUND_UP(freqs.new, cpu->pstate.scaling); - break; - case CPUFREQ_RELATION_H: - target_pstate = freqs.new / cpu->pstate.scaling; - break; - default: - target_pstate = DIV_ROUND_CLOSEST(freqs.new, cpu->pstate.scaling); - break; - } - + target_pstate = intel_pstate_freq_to_hwp_rel(cpu, freqs.new, relation); target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, false); freqs.new = target_pstate * cpu->pstate.scaling; @@ -2937,7 +2950,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, update_turbo_state(); - target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling); + target_pstate = intel_pstate_freq_to_hwp(cpu, target_freq); target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, true); diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index a148ff1f0872c419fc2198f64174d26e45342289..a4f6884416a0486181426c8a22d885f4f0534ea0 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -4545,6 +4545,7 @@ struct caam_hash_alg { struct list_head entry; struct device *dev; int alg_type; + bool is_hmac; struct ahash_alg ahash_alg; }; @@ -4571,7 +4572,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) ctx->dev = caam_hash->dev; - if (alg->setkey) { + if (caam_hash->is_hmac) { ctx->adata.key_dma = dma_map_single_attrs(ctx->dev, ctx->key, ARRAY_SIZE(ctx->key), DMA_TO_DEVICE, @@ -4611,7 +4612,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) * For keyed hash algorithms shared descriptors * will be created later in setkey() callback */ - return alg->setkey ? 0 : ahash_set_sh_desc(ahash); + return caam_hash->is_hmac ? 0 : ahash_set_sh_desc(ahash); } static void caam_hash_cra_exit(struct crypto_tfm *tfm) @@ -4646,12 +4647,14 @@ static struct caam_hash_alg *caam_hash_alloc(struct device *dev, template->hmac_name); snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", template->hmac_driver_name); + t_alg->is_hmac = true; } else { snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", template->driver_name); t_alg->ahash_alg.setkey = NULL; + t_alg->is_hmac = false; } alg->cra_module = THIS_MODULE; alg->cra_init = caam_hash_cra_init; diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 290c8500c247f9cbf20fb055e3715400a5f30646..fdd724228c2fa8accc7c7ebc1244c5ee92423247 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -1753,6 +1753,7 @@ static struct caam_hash_template driver_hash[] = { struct caam_hash_alg { struct list_head entry; int alg_type; + bool is_hmac; struct ahash_engine_alg ahash_alg; }; @@ -1804,7 +1805,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) } else { if (priv->era >= 6) { ctx->dir = DMA_BIDIRECTIONAL; - ctx->key_dir = alg->setkey ? DMA_TO_DEVICE : DMA_NONE; + ctx->key_dir = caam_hash->is_hmac ? DMA_TO_DEVICE : DMA_NONE; } else { ctx->dir = DMA_TO_DEVICE; ctx->key_dir = DMA_NONE; @@ -1862,7 +1863,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) * For keyed hash algorithms shared descriptors * will be created later in setkey() callback */ - return alg->setkey ? 0 : ahash_set_sh_desc(ahash); + return caam_hash->is_hmac ? 0 : ahash_set_sh_desc(ahash); } static void caam_hash_cra_exit(struct crypto_tfm *tfm) @@ -1915,12 +1916,14 @@ caam_hash_alloc(struct caam_hash_template *template, template->hmac_name); snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", template->hmac_driver_name); + t_alg->is_hmac = true; } else { snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", template->driver_name); halg->setkey = NULL; + t_alg->is_hmac = false; } alg->cra_module = THIS_MODULE; alg->cra_init = caam_hash_cra_init; diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c index 479062aa5e6b61c2706ff8b4f4fe912f52ded3dc..94a0ebb03d8c96804b455f73a8d8b3155baab866 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -463,6 +463,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id) hw_data->fw_name = ADF_402XX_FW; hw_data->fw_mmp_name = ADF_402XX_MMP; hw_data->uof_get_name = uof_get_name_402xx; + hw_data->get_ena_thd_mask = get_ena_thd_mask; break; case ADF_401XX_PCI_DEVICE_ID: hw_data->fw_name = ADF_4XXX_FW; diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 0f05692bfec3946841a766c8583bc1a3b526073e..ce0e2d82bb2b4cfdc61761d5e32a8c91cc121d82 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -525,7 +525,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); struct cxl_region_params *p = &cxlr->params; struct resource *res; - u32 remainder = 0; + u64 remainder = 0; lockdep_assert_held_write(&cxl_region_rwsem); @@ -545,7 +545,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid))) return -ENXIO; - div_u64_rem(size, SZ_256M * p->interleave_ways, &remainder); + div64_u64_rem(size, (u64)SZ_256M * p->interleave_ways, &remainder); if (remainder) return -EINVAL; diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 4fd1f207c84ee53a857e417a5fc2260fb43b9733..233e7c42c161d8e0b64424776d121f5d08176010 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -382,7 +382,7 @@ static int cxl_pci_mbox_send(struct cxl_memdev_state *mds, return rc; } -static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds) +static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds, bool irq_avail) { struct cxl_dev_state *cxlds = &mds->cxlds; const int cap = readl(cxlds->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); @@ -441,7 +441,7 @@ static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds) INIT_DELAYED_WORK(&mds->security.poll_dwork, cxl_mbox_sanitize_work); /* background command interrupts are optional */ - if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ)) + if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ) || !irq_avail) return 0; msgnum = FIELD_GET(CXLDEV_MBOX_CAP_IRQ_MSGNUM_MASK, cap); @@ -588,7 +588,7 @@ static int cxl_mem_alloc_event_buf(struct cxl_memdev_state *mds) return devm_add_action_or_reset(mds->cxlds.dev, free_event_buf, buf); } -static int cxl_alloc_irq_vectors(struct pci_dev *pdev) +static bool cxl_alloc_irq_vectors(struct pci_dev *pdev) { int nvecs; @@ -605,9 +605,9 @@ static int cxl_alloc_irq_vectors(struct pci_dev *pdev) PCI_IRQ_MSIX | PCI_IRQ_MSI); if (nvecs < 1) { dev_dbg(&pdev->dev, "Failed to alloc irq vectors: %d\n", nvecs); - return -ENXIO; + return false; } - return 0; + return true; } static irqreturn_t cxl_event_thread(int irq, void *id) @@ -743,7 +743,7 @@ static bool cxl_event_int_is_fw(u8 setting) } static int cxl_event_config(struct pci_host_bridge *host_bridge, - struct cxl_memdev_state *mds) + struct cxl_memdev_state *mds, bool irq_avail) { struct cxl_event_interrupt_policy policy; int rc; @@ -755,6 +755,11 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, if (!host_bridge->native_cxl_error) return 0; + if (!irq_avail) { + dev_info(mds->cxlds.dev, "No interrupt support, disable event processing.\n"); + return 0; + } + rc = cxl_mem_alloc_event_buf(mds); if (rc) return rc; @@ -789,6 +794,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct cxl_register_map map; struct cxl_memdev *cxlmd; int i, rc, pmu_count; + bool irq_avail; /* * Double check the anonymous union trickery in struct cxl_regs @@ -846,11 +852,9 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) else dev_warn(&pdev->dev, "Media not active (%d)\n", rc); - rc = cxl_alloc_irq_vectors(pdev); - if (rc) - return rc; + irq_avail = cxl_alloc_irq_vectors(pdev); - rc = cxl_pci_setup_mailbox(mds); + rc = cxl_pci_setup_mailbox(mds, irq_avail); if (rc) return rc; @@ -909,7 +913,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } - rc = cxl_event_config(host_bridge, mds); + rc = cxl_event_config(host_bridge, mds, irq_avail); if (rc) return rc; diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index e0fd99e61a2d4fcc0f8ea3c671fb0fb2238fa332..0393a9bba3a8a9b9977b6f7e00e0d20c6d890a33 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -102,7 +102,7 @@ static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(1); * * * Drivers are allowed to call dma_fence_wait() from their &mmu_notifier * respectively &mmu_interval_notifier callbacks. This means any code required - * for fence completeion cannot allocate memory with GFP_NOFS or GFP_NOIO. + * for fence completion cannot allocate memory with GFP_NOFS or GFP_NOIO. * Only GFP_ATOMIC is permissible, which might fail. * * Note that only GPU drivers have a reasonable excuse for both requiring @@ -522,7 +522,7 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout) EXPORT_SYMBOL(dma_fence_wait_timeout); /** - * dma_fence_release - default relese function for fences + * dma_fence_release - default release function for fences * @kref: &dma_fence.recfount * * This is the default release functions for &dma_fence. Drivers shouldn't call @@ -974,8 +974,8 @@ void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline) EXPORT_SYMBOL(dma_fence_set_deadline); /** - * dma_fence_describe - Dump fence describtion into seq_file - * @fence: the 6fence to describe + * dma_fence_describe - Dump fence description into seq_file + * @fence: the fence to describe * @seq: the seq_file to put the textual description into * * Dump a textual description of the fence and it's state into the seq_file. diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index eb8b733065b24d64de661fd5f0781766f1a6bfa2..e2869fb311403964b492d2e5d9f0d37993c8bff5 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -405,7 +405,7 @@ static void dma_resv_iter_walk_unlocked(struct dma_resv_iter *cursor) * * Beware that the iterator can be restarted. Code which accumulates statistics * or similar needs to check for this with dma_resv_iter_is_restarted(). For - * this reason prefer the locked dma_resv_iter_first() whenver possible. + * this reason prefer the locked dma_resv_iter_first() whenever possible. * * Returns the first fence from an unlocked dma_resv obj. */ @@ -428,7 +428,7 @@ EXPORT_SYMBOL(dma_resv_iter_first_unlocked); * * Beware that the iterator can be restarted. Code which accumulates statistics * or similar needs to check for this with dma_resv_iter_is_restarted(). For - * this reason prefer the locked dma_resv_iter_next() whenver possible. + * this reason prefer the locked dma_resv_iter_next() whenever possible. * * Returns the next fence from an unlocked dma_resv obj. */ diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index ee899f8e67215f6036734795cb5b90ab77a293a3..4a63567e93bae3dd2d5affabeedfd713aaa51460 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -168,10 +168,7 @@ static vm_fault_t cma_heap_vm_fault(struct vm_fault *vmf) if (vmf->pgoff > buffer->pagecount) return VM_FAULT_SIGBUS; - vmf->page = buffer->pages[vmf->pgoff]; - get_page(vmf->page); - - return 0; + return vmf_insert_pfn(vma, vmf->address, page_to_pfn(buffer->pages[vmf->pgoff])); } static const struct vm_operations_struct dma_heap_vm_ops = { @@ -185,6 +182,8 @@ static int cma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) return -EINVAL; + vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); + vma->vm_ops = &dma_heap_vm_ops; vma->vm_private_data = buffer; diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index fb89ecbf0cc5be8ca566eaac6e499f2e2336b625..40052d1bd0b5c161180eec477bedb0f871e91a55 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -222,8 +222,14 @@ struct atdma_sg { * @vd: pointer to the virtual dma descriptor. * @atchan: pointer to the atmel dma channel. * @total_len: total transaction byte count - * @sg_len: number of sg entries. + * @sglen: number of sg entries. * @sg: array of sgs. + * @boundary: number of transfers to perform before the automatic address increment operation + * @dst_hole: value to add to the destination address when the boundary has been reached + * @src_hole: value to add to the source address when the boundary has been reached + * @memset_buffer: buffer used for the memset operation + * @memset_paddr: physical address of the buffer used for the memset operation + * @memset_vaddr: virtual address of the buffer used for the memset operation */ struct at_desc { struct virt_dma_desc vd; @@ -245,7 +251,10 @@ struct at_desc { /*-- Channels --------------------------------------------------------*/ /** - * atc_status - information bits stored in channel status flag + * enum atc_status - information bits stored in channel status flag + * + * @ATC_IS_PAUSED: If channel is pauses + * @ATC_IS_CYCLIC: If channel is cyclic * * Manipulated with atomic operations. */ @@ -282,7 +291,6 @@ struct at_dma_chan { u32 save_cfg; u32 save_dscr; struct dma_slave_config dma_sconfig; - bool cyclic; struct at_desc *desc; }; @@ -328,12 +336,12 @@ static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width) /** * struct at_dma - internal representation of an Atmel HDMA Controller * @dma_device: dmaengine dma_device object members - * @atdma_devtype: identifier of DMA controller compatibility - * @ch_regs: memory mapped register base + * @regs: memory mapped register base * @clk: dma controller clock * @save_imr: interrupt mask register that is saved on suspend/resume cycle * @all_chan_mask: all channels availlable in a mask * @lli_pool: hw lli table + * @memset_pool: hw memset pool * @chan: channels table to store at_dma_chan structures */ struct at_dma { @@ -626,6 +634,9 @@ static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla) /** * atc_get_llis_residue - Get residue for a hardware linked list transfer + * @atchan: pointer to an atmel hdmac channel. + * @desc: pointer to the descriptor for which the residue is calculated. + * @residue: residue to be set to dma_tx_state. * * Calculate the residue by removing the length of the Linked List Item (LLI) * already transferred from the total length. To get the current LLI we can use @@ -661,10 +672,8 @@ static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla) * two DSCR values are different, we read again the CTRLA then the DSCR till two * consecutive read values from DSCR are equal or till the maximum trials is * reach. This algorithm is very unlikely not to find a stable value for DSCR. - * @atchan: pointer to an atmel hdmac channel. - * @desc: pointer to the descriptor for which the residue is calculated. - * @residue: residue to be set to dma_tx_state. - * Returns 0 on success, -errno otherwise. + * + * Returns: %0 on success, -errno otherwise. */ static int atc_get_llis_residue(struct at_dma_chan *atchan, struct at_desc *desc, u32 *residue) @@ -731,7 +740,8 @@ static int atc_get_llis_residue(struct at_dma_chan *atchan, * @chan: DMA channel * @cookie: transaction identifier to check status of * @residue: residue to be updated. - * Return 0 on success, -errono otherwise. + * + * Return: %0 on success, -errno otherwise. */ static int atc_get_residue(struct dma_chan *chan, dma_cookie_t cookie, u32 *residue) @@ -1710,7 +1720,7 @@ static void atc_issue_pending(struct dma_chan *chan) * atc_alloc_chan_resources - allocate resources for DMA channel * @chan: allocate descriptor resources for this channel * - * return - the number of allocated descriptors + * Return: the number of allocated descriptors */ static int atc_alloc_chan_resources(struct dma_chan *chan) { diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c index 7958ac33e36ce3fab462d33161fea8dabe0ee215..5a8061a307cdafeb3a4db5ddd104ae6d7ec8d190 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c +++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c @@ -38,15 +38,17 @@ static int dpaa2_qdma_alloc_chan_resources(struct dma_chan *chan) if (!dpaa2_chan->fd_pool) goto err; - dpaa2_chan->fl_pool = dma_pool_create("fl_pool", dev, - sizeof(struct dpaa2_fl_entry), - sizeof(struct dpaa2_fl_entry), 0); + dpaa2_chan->fl_pool = + dma_pool_create("fl_pool", dev, + sizeof(struct dpaa2_fl_entry) * 3, + sizeof(struct dpaa2_fl_entry), 0); + if (!dpaa2_chan->fl_pool) goto err_fd; dpaa2_chan->sdd_pool = dma_pool_create("sdd_pool", dev, - sizeof(struct dpaa2_qdma_sd_d), + sizeof(struct dpaa2_qdma_sd_d) * 2, sizeof(struct dpaa2_qdma_sd_d), 0); if (!dpaa2_chan->sdd_pool) goto err_fl; diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index a1d0aa63142a981bb59fcde5663e53ee7355947c..f405c77060ad8b3508e7c75bee09968e1ae9bc78 100644 --- a/drivers/dma/fsl-qdma.c +++ b/drivers/dma/fsl-qdma.c @@ -514,11 +514,11 @@ static struct fsl_qdma_queue queue_temp = queue_head + i + (j * queue_num); queue_temp->cq = - dma_alloc_coherent(&pdev->dev, - sizeof(struct fsl_qdma_format) * - queue_size[i], - &queue_temp->bus_addr, - GFP_KERNEL); + dmam_alloc_coherent(&pdev->dev, + sizeof(struct fsl_qdma_format) * + queue_size[i], + &queue_temp->bus_addr, + GFP_KERNEL); if (!queue_temp->cq) return NULL; queue_temp->block_base = fsl_qdma->block_base + @@ -563,15 +563,14 @@ static struct fsl_qdma_queue /* * Buffer for queue command */ - status_head->cq = dma_alloc_coherent(&pdev->dev, - sizeof(struct fsl_qdma_format) * - status_size, - &status_head->bus_addr, - GFP_KERNEL); - if (!status_head->cq) { - devm_kfree(&pdev->dev, status_head); + status_head->cq = dmam_alloc_coherent(&pdev->dev, + sizeof(struct fsl_qdma_format) * + status_size, + &status_head->bus_addr, + GFP_KERNEL); + if (!status_head->cq) return NULL; - } + status_head->n_cq = status_size; status_head->virt_head = status_head->cq; status_head->virt_tail = status_head->cq; @@ -1268,8 +1267,6 @@ static void fsl_qdma_cleanup_vchan(struct dma_device *dmadev) static void fsl_qdma_remove(struct platform_device *pdev) { - int i; - struct fsl_qdma_queue *status; struct device_node *np = pdev->dev.of_node; struct fsl_qdma_engine *fsl_qdma = platform_get_drvdata(pdev); @@ -1277,12 +1274,6 @@ static void fsl_qdma_remove(struct platform_device *pdev) fsl_qdma_cleanup_vchan(&fsl_qdma->dma_dev); of_dma_controller_free(np); dma_async_device_unregister(&fsl_qdma->dma_dev); - - for (i = 0; i < fsl_qdma->block_number; i++) { - status = fsl_qdma->status[i]; - dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_format) * - status->n_cq, status->cq, status->bus_addr); - } } static const struct of_device_id fsl_qdma_dt_ids[] = { diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index f1f920861fa9d8937a34bc29906778720a8dbfd8..5f8d2e93ff3fb516ea6374e007110b057377f11e 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -2404,6 +2404,11 @@ static int edma_probe(struct platform_device *pdev) if (irq > 0) { irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccint", dev_name(dev)); + if (!irq_name) { + ret = -ENOMEM; + goto err_disable_pm; + } + ret = devm_request_irq(dev, irq, dma_irq_handler, 0, irq_name, ecc); if (ret) { @@ -2420,6 +2425,11 @@ static int edma_probe(struct platform_device *pdev) if (irq > 0) { irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccerrint", dev_name(dev)); + if (!irq_name) { + ret = -ENOMEM; + goto err_disable_pm; + } + ret = devm_request_irq(dev, irq, dma_ccerr_handler, 0, irq_name, ecc); if (ret) { diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 2841a539c264891cde8b8166d51d5bbf885a5d85..6400d06588a24d1aa54ceefc3e79ce7661e43f3a 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -3968,6 +3968,7 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc, { struct udma_chan *uc = to_udma_chan(&vc->chan); struct udma_desc *d; + u8 status; if (!vd) return; @@ -3977,12 +3978,12 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc, if (d->metadata_size) udma_fetch_epib(uc, d); - /* Provide residue information for the client */ if (result) { void *desc_vaddr = udma_curr_cppi5_desc_vaddr(d, d->desc_idx); if (cppi5_desc_get_type(desc_vaddr) == CPPI5_INFO0_DESC_TYPE_VAL_HOST) { + /* Provide residue information for the client */ result->residue = d->residue - cppi5_hdesc_get_pktlen(desc_vaddr); if (result->residue) @@ -3991,7 +3992,12 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc, result->result = DMA_TRANS_NOERROR; } else { result->residue = 0; - result->result = DMA_TRANS_NOERROR; + /* Propagate TR Response errors to the client */ + status = d->hwdesc[0].tr_resp_base->status; + if (status) + result->result = DMA_TRANS_ABORTED; + else + result->result = DMA_TRANS_NOERROR; } } } diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 1eca8cc271f841e7b15967b2c33394169065b4ab..5152bd1b0daf599869195e81805fbb2709dbe6b4 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -29,8 +29,6 @@ static u32 dpll_pin_xa_id; WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) #define ASSERT_DPLL_NOT_REGISTERED(d) \ WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) -#define ASSERT_PIN_REGISTERED(p) \ - WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED)) struct dpll_device_registration { struct list_head list; @@ -425,6 +423,53 @@ void dpll_device_unregister(struct dpll_device *dpll, } EXPORT_SYMBOL_GPL(dpll_device_unregister); +static void dpll_pin_prop_free(struct dpll_pin_properties *prop) +{ + kfree(prop->package_label); + kfree(prop->panel_label); + kfree(prop->board_label); + kfree(prop->freq_supported); +} + +static int dpll_pin_prop_dup(const struct dpll_pin_properties *src, + struct dpll_pin_properties *dst) +{ + memcpy(dst, src, sizeof(*dst)); + if (src->freq_supported && src->freq_supported_num) { + size_t freq_size = src->freq_supported_num * + sizeof(*src->freq_supported); + dst->freq_supported = kmemdup(src->freq_supported, + freq_size, GFP_KERNEL); + if (!src->freq_supported) + return -ENOMEM; + } + if (src->board_label) { + dst->board_label = kstrdup(src->board_label, GFP_KERNEL); + if (!dst->board_label) + goto err_board_label; + } + if (src->panel_label) { + dst->panel_label = kstrdup(src->panel_label, GFP_KERNEL); + if (!dst->panel_label) + goto err_panel_label; + } + if (src->package_label) { + dst->package_label = kstrdup(src->package_label, GFP_KERNEL); + if (!dst->package_label) + goto err_package_label; + } + + return 0; + +err_package_label: + kfree(dst->panel_label); +err_panel_label: + kfree(dst->board_label); +err_board_label: + kfree(dst->freq_supported); + return -ENOMEM; +} + static struct dpll_pin * dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, const struct dpll_pin_properties *prop) @@ -441,20 +486,24 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX || prop->type > DPLL_PIN_TYPE_MAX)) { ret = -EINVAL; - goto err; + goto err_pin_prop; } - pin->prop = prop; + ret = dpll_pin_prop_dup(prop, &pin->prop); + if (ret) + goto err_pin_prop; refcount_set(&pin->refcount, 1); xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC); xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC); ret = xa_alloc_cyclic(&dpll_pin_xa, &pin->id, pin, xa_limit_32b, &dpll_pin_xa_id, GFP_KERNEL); if (ret) - goto err; + goto err_xa_alloc; return pin; -err: +err_xa_alloc: xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); + dpll_pin_prop_free(&pin->prop); +err_pin_prop: kfree(pin); return ERR_PTR(ret); } @@ -514,6 +563,7 @@ void dpll_pin_put(struct dpll_pin *pin) xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); xa_erase(&dpll_pin_xa, pin->id); + dpll_pin_prop_free(&pin->prop); kfree(pin); } mutex_unlock(&dpll_lock); @@ -564,8 +614,6 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, WARN_ON(!ops->state_on_dpll_get) || WARN_ON(!ops->direction_get)) return -EINVAL; - if (ASSERT_DPLL_REGISTERED(dpll)) - return -EINVAL; mutex_lock(&dpll_lock); if (WARN_ON(!(dpll->module == pin->module && @@ -636,15 +684,13 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, unsigned long i, stop; int ret; - if (WARN_ON(parent->prop->type != DPLL_PIN_TYPE_MUX)) + if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX)) return -EINVAL; if (WARN_ON(!ops) || WARN_ON(!ops->state_on_pin_get) || WARN_ON(!ops->direction_get)) return -EINVAL; - if (ASSERT_PIN_REGISTERED(parent)) - return -EINVAL; mutex_lock(&dpll_lock); ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv); diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index 5585873c5c1b020e5618896aaa43ff1656ff53dd..717f715015c742238d5585fddc5cd267fbb0db9f 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -44,7 +44,7 @@ struct dpll_device { * @module: module of creator * @dpll_refs: hold referencees to dplls pin was registered with * @parent_refs: hold references to parent pins pin was registered with - * @prop: pointer to pin properties given by registerer + * @prop: pin properties copied from the registerer * @rclk_dev_name: holds name of device when pin can recover clock from it * @refcount: refcount **/ @@ -55,7 +55,7 @@ struct dpll_pin { struct module *module; struct xarray dpll_refs; struct xarray parent_refs; - const struct dpll_pin_properties *prop; + struct dpll_pin_properties prop; refcount_t refcount; }; diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 3370dbddb86bdeb6b627fdf741357eeb15ee3676..314bb377546519ef25987b2e6f77827f590fe5fe 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -303,17 +303,17 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq, DPLL_A_PIN_PAD)) return -EMSGSIZE; - for (fs = 0; fs < pin->prop->freq_supported_num; fs++) { + for (fs = 0; fs < pin->prop.freq_supported_num; fs++) { nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED); if (!nest) return -EMSGSIZE; - freq = pin->prop->freq_supported[fs].min; + freq = pin->prop.freq_supported[fs].min; if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq), &freq, DPLL_A_PIN_PAD)) { nla_nest_cancel(msg, nest); return -EMSGSIZE; } - freq = pin->prop->freq_supported[fs].max; + freq = pin->prop.freq_supported[fs].max; if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq), &freq, DPLL_A_PIN_PAD)) { nla_nest_cancel(msg, nest); @@ -329,9 +329,9 @@ static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq) { int fs; - for (fs = 0; fs < pin->prop->freq_supported_num; fs++) - if (freq >= pin->prop->freq_supported[fs].min && - freq <= pin->prop->freq_supported[fs].max) + for (fs = 0; fs < pin->prop.freq_supported_num; fs++) + if (freq >= pin->prop.freq_supported[fs].min && + freq <= pin->prop.freq_supported[fs].max) return true; return false; } @@ -421,7 +421,7 @@ static int dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, struct netlink_ext_ack *extack) { - const struct dpll_pin_properties *prop = pin->prop; + const struct dpll_pin_properties *prop = &pin->prop; struct dpll_pin_ref *ref; int ret; @@ -553,6 +553,24 @@ __dpll_device_change_ntf(struct dpll_device *dpll) return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); } +static bool dpll_pin_available(struct dpll_pin *pin) +{ + struct dpll_pin_ref *par_ref; + unsigned long i; + + if (!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED)) + return false; + xa_for_each(&pin->parent_refs, i, par_ref) + if (xa_get_mark(&dpll_pin_xa, par_ref->pin->id, + DPLL_REGISTERED)) + return true; + xa_for_each(&pin->dpll_refs, i, par_ref) + if (xa_get_mark(&dpll_device_xa, par_ref->dpll->id, + DPLL_REGISTERED)) + return true; + return false; +} + /** * dpll_device_change_ntf - notify that the dpll device has been changed * @dpll: registered dpll pointer @@ -579,7 +597,7 @@ dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin) int ret = -ENOMEM; void *hdr; - if (WARN_ON(!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED))) + if (!dpll_pin_available(pin)) return -ENODEV; msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); @@ -717,7 +735,7 @@ dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx, int ret; if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) { NL_SET_ERR_MSG(extack, "state changing is not allowed"); return -EOPNOTSUPP; } @@ -753,7 +771,7 @@ dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, int ret; if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) { NL_SET_ERR_MSG(extack, "state changing is not allowed"); return -EOPNOTSUPP; } @@ -780,7 +798,7 @@ dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin, int ret; if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) { NL_SET_ERR_MSG(extack, "prio changing is not allowed"); return -EOPNOTSUPP; } @@ -808,7 +826,7 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll, int ret; if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) { NL_SET_ERR_MSG(extack, "direction changing is not allowed"); return -EOPNOTSUPP; } @@ -838,8 +856,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr, int ret; phase_adj = nla_get_s32(phase_adj_attr); - if (phase_adj > pin->prop->phase_range.max || - phase_adj < pin->prop->phase_range.min) { + if (phase_adj > pin->prop.phase_range.max || + phase_adj < pin->prop.phase_range.min) { NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr, "phase adjust value not supported"); return -EINVAL; @@ -1023,7 +1041,7 @@ dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr, unsigned long i; xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) { - prop = pin->prop; + prop = &pin->prop; cid_match = clock_id ? pin->clock_id == clock_id : true; mod_match = mod_name_attr && module_name(pin->module) ? !nla_strcmp(mod_name_attr, @@ -1130,6 +1148,10 @@ int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info) } pin = dpll_pin_find_from_nlattr(info); if (!IS_ERR(pin)) { + if (!dpll_pin_available(pin)) { + nlmsg_free(msg); + return -ENODEV; + } ret = dpll_msg_add_pin_handle(msg, pin); if (ret) { nlmsg_free(msg); @@ -1179,6 +1201,8 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED, ctx->idx) { + if (!dpll_pin_available(pin)) + continue; hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, &dpll_nl_family, NLM_F_MULTI, @@ -1441,7 +1465,8 @@ int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, } info->user_ptr[0] = xa_load(&dpll_pin_xa, nla_get_u32(info->attrs[DPLL_A_PIN_ID])); - if (!info->user_ptr[0]) { + if (!info->user_ptr[0] || + !dpll_pin_available(info->user_ptr[0])) { NL_SET_ERR_MSG(info->extack, "pin not found"); ret = -ENODEV; goto unlock_dev; diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 0547253d16fe5dc5f606a34035473de7f271acf6..7d3346b3a2bf320910c72783ab857415d331ed14 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -118,10 +118,9 @@ static int textual_leaf_to_string(const u32 *block, char *buf, size_t size) * @buf: where to put the string * @size: size of @buf, in bytes * - * The string is taken from a minimal ASCII text descriptor leaf after - * the immediate entry with @key. The string is zero-terminated. - * An overlong string is silently truncated such that it and the - * zero byte fit into @size. + * The string is taken from a minimal ASCII text descriptor leaf just after the entry with the + * @key. The string is zero-terminated. An overlong string is silently truncated such that it + * and the zero byte fit into @size. * * Returns strlen(buf) or a negative error code. */ @@ -368,8 +367,17 @@ static ssize_t show_text_leaf(struct device *dev, for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) { int result = fw_csr_string(directories[i], attr->key, buf, bufsize); // Detected. - if (result >= 0) + if (result >= 0) { ret = result; + } else if (i == 0 && attr->key == CSR_VENDOR) { + // Sony DVMC-DA1 has configuration ROM such that the descriptor leaf entry + // in the root directory follows to the directory entry for vendor ID + // instead of the immediate value for vendor ID. + result = fw_csr_string(directories[i], CSR_DIRECTORY | attr->key, buf, + bufsize); + if (result >= 0) + ret = result; + } } if (ret >= 0) { diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index afd38539b92e51b36da4c54b1913001445e624e0..71d8b26c4103b9cdb668c2e8eb1b2e519d9823c8 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -182,6 +182,7 @@ config MTK_ADSP_IPC config SYSFB bool select BOOT_VESA_SUPPORT + select SCREEN_INFO config SYSFB_SIMPLEFB bool "Mark VGA/VBE/EFI FB as generic system framebuffer" diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 6146b2927d5c56af6bc3b9722c1789f29a4498fe..f2556a8e940156bc4f9d34ae5dc92aac837b688a 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -107,12 +107,12 @@ struct ffa_drv_info { struct work_struct notif_pcpu_work; struct work_struct irq_work; struct xarray partition_info; - unsigned int partition_count; DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS)); struct mutex notify_lock; /* lock to protect notifier hashtable */ }; static struct ffa_drv_info *drv_info; +static void ffa_partitions_cleanup(void); /* * The driver must be able to support all the versions from the earliest @@ -733,6 +733,11 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) void *cb_data; partition = xa_load(&drv_info->partition_info, part_id); + if (!partition) { + pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id); + return; + } + read_lock(&partition->rw_lock); callback = partition->callback; cb_data = partition->cb_data; @@ -915,6 +920,11 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback, return -EOPNOTSUPP; partition = xa_load(&drv_info->partition_info, part_id); + if (!partition) { + pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id); + return -EINVAL; + } + write_lock(&partition->rw_lock); cb_valid = !!partition->callback; @@ -1186,9 +1196,9 @@ void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid) kfree(pbuf); } -static void ffa_setup_partitions(void) +static int ffa_setup_partitions(void) { - int count, idx; + int count, idx, ret; uuid_t uuid; struct ffa_device *ffa_dev; struct ffa_dev_part_info *info; @@ -1197,7 +1207,7 @@ static void ffa_setup_partitions(void) count = ffa_partition_probe(&uuid_null, &pbuf); if (count <= 0) { pr_info("%s: No partitions found, error %d\n", __func__, count); - return; + return -EINVAL; } xa_init(&drv_info->partition_info); @@ -1226,40 +1236,53 @@ static void ffa_setup_partitions(void) ffa_device_unregister(ffa_dev); continue; } - xa_store(&drv_info->partition_info, tpbuf->id, info, GFP_KERNEL); + rwlock_init(&info->rw_lock); + ret = xa_insert(&drv_info->partition_info, tpbuf->id, + info, GFP_KERNEL); + if (ret) { + pr_err("%s: failed to save partition ID 0x%x - ret:%d\n", + __func__, tpbuf->id, ret); + ffa_device_unregister(ffa_dev); + kfree(info); + } } - drv_info->partition_count = count; kfree(pbuf); /* Allocate for the host */ info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return; - xa_store(&drv_info->partition_info, drv_info->vm_id, info, GFP_KERNEL); - drv_info->partition_count++; + if (!info) { + pr_err("%s: failed to alloc Host partition ID 0x%x. Abort.\n", + __func__, drv_info->vm_id); + /* Already registered devices are freed on bus_exit */ + ffa_partitions_cleanup(); + return -ENOMEM; + } + + rwlock_init(&info->rw_lock); + ret = xa_insert(&drv_info->partition_info, drv_info->vm_id, + info, GFP_KERNEL); + if (ret) { + pr_err("%s: failed to save Host partition ID 0x%x - ret:%d. Abort.\n", + __func__, drv_info->vm_id, ret); + kfree(info); + /* Already registered devices are freed on bus_exit */ + ffa_partitions_cleanup(); + } + + return ret; } static void ffa_partitions_cleanup(void) { - struct ffa_dev_part_info **info; - int idx, count = drv_info->partition_count; - - if (!count) - return; - - info = kcalloc(count, sizeof(*info), GFP_KERNEL); - if (!info) - return; - - xa_extract(&drv_info->partition_info, (void **)info, 0, VM_ID_MASK, - count, XA_PRESENT); + struct ffa_dev_part_info *info; + unsigned long idx; - for (idx = 0; idx < count; idx++) - kfree(info[idx]); - kfree(info); + xa_for_each(&drv_info->partition_info, idx, info) { + xa_erase(&drv_info->partition_info, idx); + kfree(info); + } - drv_info->partition_count = 0; xa_destroy(&drv_info->partition_info); } @@ -1508,7 +1531,11 @@ static int __init ffa_init(void) ffa_notifications_setup(); - ffa_setup_partitions(); + ret = ffa_setup_partitions(); + if (ret) { + pr_err("failed to setup partitions\n"); + goto cleanup_notifs; + } ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle, drv_info, true); @@ -1516,6 +1543,9 @@ static int __init ffa_init(void) pr_info("Failed to register driver sched callback %d\n", ret); return 0; + +cleanup_notifs: + ffa_notifications_cleanup(); free_pages: if (drv_info->tx_buffer) free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); @@ -1535,7 +1565,6 @@ static void __exit ffa_exit(void) ffa_rxtx_unmap(drv_info->vm_id); free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); - xa_destroy(&drv_info->partition_info); kfree(drv_info); arm_ffa_bus_exit(); } diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index c0644558042a06dc1f0c087af4f22264abeee52a..e2050adbf85c6a125fc5ba241fb0c6b133466bfe 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -13,7 +13,7 @@ #include "notify.h" /* Updated only after ALL the mandatory features for that version are merged */ -#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001 +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 enum scmi_clock_protocol_cmd { CLOCK_ATTRIBUTES = 0x3, @@ -954,8 +954,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) scmi_clock_describe_rates_get(ph, clkid, clk); } - if (PROTOCOL_REV_MAJOR(version) >= 0x2 && - PROTOCOL_REV_MINOR(version) >= 0x1) { + if (PROTOCOL_REV_MAJOR(version) >= 0x3) { cinfo->clock_config_set = scmi_clock_config_set_v2; cinfo->clock_config_get = scmi_clock_config_get_v2; } else { diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index c46dc5215af7a7c8a78e0fe26c12fac51c8080b7..00b165d1f502df7816527298996f196585d10f5a 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -314,6 +314,7 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); +bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem); /* declarations for message passing transports */ struct scmi_msg_payld; diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 19246ed1f01ff7cc3ea7346402c32e02b57b336a..b8d470417e8f99bb6408aba541bc4b89541ddf7c 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -45,6 +45,20 @@ static void rx_callback(struct mbox_client *cl, void *m) { struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); + /* + * An A2P IRQ is NOT valid when received while the platform still has + * the ownership of the channel, because the platform at first releases + * the SMT channel and then sends the completion interrupt. + * + * This addresses a possible race condition in which a spurious IRQ from + * a previous timed-out reply which arrived late could be wrongly + * associated with the next pending transaction. + */ + if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { + dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); + return; + } + scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL); } diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 8ea2a7b3d35d2029f9731ef3031d575609093d6e..211e8e0aef2c2b4fade048990249c2444afb946a 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -350,8 +350,8 @@ process_response_opp(struct scmi_opp *opp, unsigned int loop_idx, } static inline void -process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, - unsigned int loop_idx, +process_response_opp_v4(struct device *dev, struct perf_dom_info *dom, + struct scmi_opp *opp, unsigned int loop_idx, const struct scmi_msg_resp_perf_describe_levels_v4 *r) { opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val); @@ -362,10 +362,23 @@ process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, /* Note that PERF v4 reports always five 32-bit words */ opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq); if (dom->level_indexing_mode) { + int ret; + opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index); - xa_store(&dom->opps_by_idx, opp->level_index, opp, GFP_KERNEL); - xa_store(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); + ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp, + GFP_KERNEL); + if (ret) + dev_warn(dev, + "Failed to add opps_by_idx at %d - ret:%d\n", + opp->level_index, ret); + + ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); + if (ret) + dev_warn(dev, + "Failed to add opps_by_lvl at %d - ret:%d\n", + opp->perf, ret); + hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq); } } @@ -382,7 +395,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph, if (PROTOCOL_REV_MAJOR(p->version) <= 0x3) process_response_opp(opp, st->loop_idx, response); else - process_response_opp_v4(p->perf_dom, opp, st->loop_idx, + process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx, response); p->perf_dom->opp_count++; diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c index 0493aa3c12bf5363e02c1ecc9b2520d1bd8b3d67..350573518503355f6abaa4d24cbcac6368e8930c 100644 --- a/drivers/firmware/arm_scmi/raw_mode.c +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -1111,7 +1111,6 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, int i; for (i = 0; i < num_chans; i++) { - void *xret; struct scmi_raw_queue *q; q = scmi_raw_queue_init(raw); @@ -1120,13 +1119,12 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, goto err_xa; } - xret = xa_store(&raw->chans_q, channels[i], q, + ret = xa_insert(&raw->chans_q, channels[i], q, GFP_KERNEL); - if (xa_err(xret)) { + if (ret) { dev_err(dev, "Fail to allocate Raw queue 0x%02X\n", channels[i]); - ret = xa_err(xret); goto err_xa; } } @@ -1322,6 +1320,12 @@ void scmi_raw_message_report(void *r, struct scmi_xfer *xfer, dev = raw->handle->dev; q = scmi_raw_queue_select(raw, idx, SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0); + if (!q) { + dev_warn(dev, + "RAW[%d] - NO queue for chan 0x%X. Dropping report.\n", + idx, chan_id); + return; + } /* * Grab the msg_q_lock upfront to avoid a possible race between diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index 87b4f4d35f06230bc161fc4205c7b199e03c0015..8bf495bcad09b7ba8246c05b4e76086fa1bdaf90 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include "common.h" @@ -122,3 +122,9 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); } + +bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) +{ + return (ioread32(&shmem->channel_status) & + SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); +} diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c index 82fcfd29bc4d29116b051c946edb9b6535fd78ac..a6b48703dc9e9671e8583324f875116094eb7b86 100644 --- a/drivers/firmware/sysfb.c +++ b/drivers/firmware/sysfb.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -69,24 +70,70 @@ void sysfb_disable(void) } EXPORT_SYMBOL_GPL(sysfb_disable); +#if defined(CONFIG_PCI) +static __init bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev) +{ + /* + * TODO: Try to integrate this code into the PCI subsystem + */ + int ret; + u16 command; + + ret = pci_read_config_word(pdev, PCI_COMMAND, &command); + if (ret != PCIBIOS_SUCCESSFUL) + return false; + if (!(command & PCI_COMMAND_MEMORY)) + return false; + return true; +} +#else +static __init bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev) +{ + return false; +} +#endif + +static __init struct device *sysfb_parent_dev(const struct screen_info *si) +{ + struct pci_dev *pdev; + + pdev = screen_info_pci_dev(si); + if (IS_ERR(pdev)) { + return ERR_CAST(pdev); + } else if (pdev) { + if (!sysfb_pci_dev_is_enabled(pdev)) + return ERR_PTR(-ENODEV); + return &pdev->dev; + } + + return NULL; +} + static __init int sysfb_init(void) { struct screen_info *si = &screen_info; + struct device *parent; struct simplefb_platform_data mode; const char *name; bool compatible; int ret = 0; + screen_info_apply_fixups(); + mutex_lock(&disable_lock); if (disabled) goto unlock_mutex; sysfb_apply_efi_quirks(); + parent = sysfb_parent_dev(si); + if (IS_ERR(parent)) + goto unlock_mutex; + /* try to create a simple-framebuffer device */ compatible = sysfb_parse_mode(si, &mode); if (compatible) { - pd = sysfb_create_simplefb(si, &mode); + pd = sysfb_create_simplefb(si, &mode, parent); if (!IS_ERR(pd)) goto unlock_mutex; } @@ -109,6 +156,8 @@ static __init int sysfb_init(void) goto unlock_mutex; } + pd->dev.parent = parent; + sysfb_set_efifb_fwnode(pd); ret = platform_device_add_data(pd, si, sizeof(*si)); @@ -128,4 +177,4 @@ unlock_mutex: } /* must execute after PCI subsystem for EFI quirks */ -subsys_initcall_sync(sysfb_init); +device_initcall(sysfb_init); diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c index 74363ed7501f64ac95382094850756b5b02cda7e..75a186bf8f8ec20ba19e864b05082832aa850d18 100644 --- a/drivers/firmware/sysfb_simplefb.c +++ b/drivers/firmware/sysfb_simplefb.c @@ -91,7 +91,8 @@ __init bool sysfb_parse_mode(const struct screen_info *si, } __init struct platform_device *sysfb_create_simplefb(const struct screen_info *si, - const struct simplefb_platform_data *mode) + const struct simplefb_platform_data *mode, + struct device *parent) { struct platform_device *pd; struct resource res; @@ -143,6 +144,8 @@ __init struct platform_device *sysfb_create_simplefb(const struct screen_info *s if (!pd) return ERR_PTR(-ENOMEM); + pd->dev.parent = parent; + sysfb_set_efifb_fwnode(pd); ret = platform_device_add_resources(pd, &res, 1); diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c index be7f2fa5aa7b600a2605084d832e23f24d501c84..806b88d8dfb7bda7d23cae021eb08c3bbf383ab1 100644 --- a/drivers/gpio/gpio-eic-sprd.c +++ b/drivers/gpio/gpio-eic-sprd.c @@ -330,20 +330,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_LEVEL_HIGH: sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1); + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); break; case IRQ_TYPE_LEVEL_LOW: sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0); + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_BOTH: state = sprd_eic_get(chip, offset); - if (state) + if (state) { sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0); - else + sprd_eic_update(chip, offset, + SPRD_EIC_DBNC_IC, 1); + } else { sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1); + sprd_eic_update(chip, offset, + SPRD_EIC_DBNC_IC, 1); + } break; default: return -ENOTSUPP; @@ -355,20 +362,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_LEVEL_HIGH: sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); break; case IRQ_TYPE_LEVEL_LOW: sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_BOTH: state = sprd_eic_get(chip, offset); - if (state) + if (state) { sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0); - else + sprd_eic_update(chip, offset, + SPRD_EIC_LATCH_INTCLR, 1); + } else { sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1); + sprd_eic_update(chip, offset, + SPRD_EIC_LATCH_INTCLR, 1); + } break; default: return -ENOTSUPP; @@ -382,29 +396,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_EDGE_FALLING: sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_EDGE_BOTH: sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_LEVEL_HIGH: sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_level_irq); break; case IRQ_TYPE_LEVEL_LOW: sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_level_irq); break; default: @@ -417,29 +436,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_EDGE_FALLING: sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_EDGE_BOTH: sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_LEVEL_HIGH: sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_level_irq); break; case IRQ_TYPE_LEVEL_LOW: sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_level_irq); break; default: diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 88066826d8e5b629697136b8bb2431b543544977..cd3e9657cc36df59123a571a0ed2ed5332272a5d 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1651,6 +1651,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_interrupt = "INT33FC:00@3", }, }, + { + /* + * Spurious wakeups from TP_ATTN# pin + * Found in BIOS 0.35 + * https://gitlab.freedesktop.org/drm/amd/-/issues/3073 + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), + DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "PNP0C50:00@8", + }, + }, {} /* Terminating entry */ }; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 2520db0b776e1bccf213fd541baf6275dbb192eb..872edb47bb53236b6296a7f1e02b187a73e30b48 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -19,8 +19,7 @@ menuconfig DRM # gallium uses SYS_kcmp for os_same_file_description() to de-duplicate # device and dmabuf fd. Let's make sure that is available for our userspace. select KCMP - select VIDEO_CMDLINE - select VIDEO_NOMODESET + select VIDEO help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select @@ -42,7 +41,7 @@ config DRM_MIPI_DSI config DRM_DEBUG_MM bool "Insert extra checks and debug info into the DRM range managers" default n - depends on DRM=y + depends on DRM depends on STACKTRACE_SUPPORT select STACKDEPOT help @@ -289,19 +288,7 @@ config DRM_VGEM as used by Mesa's software renderer for enhanced performance. If M is selected the module will be called vgem. -config DRM_VKMS - tristate "Virtual KMS (EXPERIMENTAL)" - depends on DRM && MMU - select DRM_KMS_HELPER - select DRM_GEM_SHMEM_HELPER - select CRC32 - default n - help - Virtual Kernel Mode-Setting (VKMS) is used for testing or for - running GPU in a headless machines. Choose this option to get - a VKMS. - - If M is selected the module will be called vkms. +source "drivers/gpu/drm/vkms/Kconfig" source "drivers/gpu/drm/exynos/Kconfig" diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 260e32ef7bae0ff299bcbeaf9750e15d6cfacaff..4c989da4d2f368f532de504b5cd09cbfa08c3a6e 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -80,7 +80,7 @@ amdgpu-y += amdgpu_device.o amdgpu_doorbell_mgr.o amdgpu_kms.o \ amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \ amdgpu_fw_attestation.o amdgpu_securedisplay.o \ amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o \ - amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o + amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_aca.o amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 3d8a48f46b015613dc44517ebd20d5250df5a3b1..312dfaec7b4a746f5568bc36caf510c6d70ee014 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -107,6 +107,7 @@ #include "amdgpu_smuio.h" #include "amdgpu_fdinfo.h" #include "amdgpu_mca.h" +#include "amdgpu_aca.h" #include "amdgpu_ras.h" #include "amdgpu_xcp.h" #include "amdgpu_seq64.h" @@ -114,14 +115,12 @@ #define MAX_GPU_INSTANCE 64 -struct amdgpu_gpu_instance -{ +struct amdgpu_gpu_instance { struct amdgpu_device *adev; int mgpu_fan_enabled; }; -struct amdgpu_mgpu_info -{ +struct amdgpu_mgpu_info { struct amdgpu_gpu_instance gpu_ins[MAX_GPU_INSTANCE]; struct mutex mutex; uint32_t num_gpu; @@ -140,8 +139,7 @@ enum amdgpu_ss { AMDGPU_SS_DRV_UNLOAD }; -struct amdgpu_watchdog_timer -{ +struct amdgpu_watchdog_timer { bool timeout_fatal_disable; uint32_t period; /* maxCycles = (1 << period), the number of cycles before a timeout */ }; @@ -1045,6 +1043,9 @@ struct amdgpu_device { /* MCA */ struct amdgpu_mca mca; + /* ACA */ + struct amdgpu_aca aca; + struct amdgpu_ip_block ip_blocks[AMDGPU_MAX_IP_NUM]; uint32_t harvest_ip_mask; int num_ip_blocks; @@ -1078,6 +1079,8 @@ struct amdgpu_device { bool in_s3; bool in_s4; bool in_s0ix; + /* indicate amdgpu suspension status */ + bool suspend_complete; enum pp_mp1_state mp1_state; struct amdgpu_doorbell_index doorbell_index; @@ -1329,6 +1332,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev); #define WREG32_FIELD_OFFSET(reg, offset, field, val) \ WREG32(mm##reg + offset, (RREG32(mm##reg + offset) & ~REG_FIELD_MASK(reg, field)) | (val) << REG_FIELD_SHIFT(reg, field)) +#define AMDGPU_GET_REG_FIELD(x, h, l) (((x) & GENMASK_ULL(h, l)) >> (l)) /* * BIOS helpers. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c new file mode 100644 index 0000000000000000000000000000000000000000..493982f94649ee70e75f8b1adca226062b4fa4d4 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c @@ -0,0 +1,879 @@ +/* + * Copyright 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include "amdgpu.h" +#include "amdgpu_aca.h" +#include "amdgpu_ras.h" + +#define ACA_BANK_HWID(type, hwid, mcatype) [ACA_HWIP_TYPE_##type] = {hwid, mcatype} + +typedef int bank_handler_t(struct aca_handle *handle, struct aca_bank *bank, enum aca_error_type type, void *data); + +struct aca_banks { + int nr_banks; + struct list_head list; +}; + +struct aca_hwip { + int hwid; + int mcatype; +}; + +static struct aca_hwip aca_hwid_mcatypes[ACA_HWIP_TYPE_COUNT] = { + ACA_BANK_HWID(SMU, 0x01, 0x01), + ACA_BANK_HWID(PCS_XGMI, 0x50, 0x00), + ACA_BANK_HWID(UMC, 0x96, 0x00), +}; + +static void aca_banks_init(struct aca_banks *banks) +{ + if (!banks) + return; + + memset(banks, 0, sizeof(*banks)); + INIT_LIST_HEAD(&banks->list); +} + +static int aca_banks_add_bank(struct aca_banks *banks, struct aca_bank *bank) +{ + struct aca_bank_node *node; + + if (!bank) + return -EINVAL; + + node = kvzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + memcpy(&node->bank, bank, sizeof(*bank)); + + INIT_LIST_HEAD(&node->node); + list_add_tail(&node->node, &banks->list); + + banks->nr_banks++; + + return 0; +} + +static void aca_banks_release(struct aca_banks *banks) +{ + struct aca_bank_node *node, *tmp; + + list_for_each_entry_safe(node, tmp, &banks->list, node) { + list_del(&node->node); + kvfree(node); + } +} + +static int aca_smu_get_valid_aca_count(struct amdgpu_device *adev, enum aca_error_type type, u32 *count) +{ + struct amdgpu_aca *aca = &adev->aca; + const struct aca_smu_funcs *smu_funcs = aca->smu_funcs; + + if (!count) + return -EINVAL; + + if (!smu_funcs || !smu_funcs->get_valid_aca_count) + return -EOPNOTSUPP; + + return smu_funcs->get_valid_aca_count(adev, type, count); +} + +static struct aca_regs_dump { + const char *name; + int reg_idx; +} aca_regs[] = { + {"CONTROL", ACA_REG_IDX_CTL}, + {"STATUS", ACA_REG_IDX_STATUS}, + {"ADDR", ACA_REG_IDX_ADDR}, + {"MISC", ACA_REG_IDX_MISC0}, + {"CONFIG", ACA_REG_IDX_CONFG}, + {"IPID", ACA_REG_IDX_IPID}, + {"SYND", ACA_REG_IDX_SYND}, + {"DESTAT", ACA_REG_IDX_DESTAT}, + {"DEADDR", ACA_REG_IDX_DEADDR}, + {"CONTROL_MASK", ACA_REG_IDX_CTL_MASK}, +}; + +static void aca_smu_bank_dump(struct amdgpu_device *adev, int idx, int total, struct aca_bank *bank) +{ + int i; + + dev_info(adev->dev, HW_ERR "Accelerator Check Architecture events logged\n"); + /* plus 1 for output format, e.g: ACA[08/08]: xxxx */ + for (i = 0; i < ARRAY_SIZE(aca_regs); i++) + dev_info(adev->dev, HW_ERR "ACA[%02d/%02d].%s=0x%016llx\n", + idx + 1, total, aca_regs[i].name, bank->regs[aca_regs[i].reg_idx]); +} + +static int aca_smu_get_valid_aca_banks(struct amdgpu_device *adev, enum aca_error_type type, + int start, int count, + struct aca_banks *banks) +{ + struct amdgpu_aca *aca = &adev->aca; + const struct aca_smu_funcs *smu_funcs = aca->smu_funcs; + struct aca_bank bank; + int i, max_count, ret; + + if (!count) + return 0; + + if (!smu_funcs || !smu_funcs->get_valid_aca_bank) + return -EOPNOTSUPP; + + switch (type) { + case ACA_ERROR_TYPE_UE: + max_count = smu_funcs->max_ue_bank_count; + break; + case ACA_ERROR_TYPE_CE: + max_count = smu_funcs->max_ce_bank_count; + break; + case ACA_ERROR_TYPE_DEFERRED: + default: + return -EINVAL; + } + + if (start + count >= max_count) + return -EINVAL; + + count = min_t(int, count, max_count); + for (i = 0; i < count; i++) { + memset(&bank, 0, sizeof(bank)); + ret = smu_funcs->get_valid_aca_bank(adev, type, start + i, &bank); + if (ret) + return ret; + + aca_smu_bank_dump(adev, i, count, &bank); + + ret = aca_banks_add_bank(banks, &bank); + if (ret) + return ret; + } + + return 0; +} + +static bool aca_bank_hwip_is_matched(struct aca_bank *bank, enum aca_hwip_type type) +{ + + struct aca_hwip *hwip; + int hwid, mcatype; + u64 ipid; + + if (!bank || type == ACA_HWIP_TYPE_UNKNOW) + return false; + + hwip = &aca_hwid_mcatypes[type]; + if (!hwip->hwid) + return false; + + ipid = bank->regs[ACA_REG_IDX_IPID]; + hwid = ACA_REG__IPID__HARDWAREID(ipid); + mcatype = ACA_REG__IPID__MCATYPE(ipid); + + return hwip->hwid == hwid && hwip->mcatype == mcatype; +} + +static bool aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, enum aca_error_type type) +{ + const struct aca_bank_ops *bank_ops = handle->bank_ops; + + if (!aca_bank_hwip_is_matched(bank, handle->hwip)) + return false; + + if (!bank_ops->aca_bank_is_valid) + return true; + + return bank_ops->aca_bank_is_valid(handle, bank, type, handle->data); +} + +static struct aca_bank_error *new_bank_error(struct aca_error *aerr, struct aca_bank_info *info) +{ + struct aca_bank_error *bank_error; + + bank_error = kvzalloc(sizeof(*bank_error), GFP_KERNEL); + if (!bank_error) + return NULL; + + INIT_LIST_HEAD(&bank_error->node); + memcpy(&bank_error->info, info, sizeof(*info)); + + mutex_lock(&aerr->lock); + list_add_tail(&bank_error->node, &aerr->list); + mutex_unlock(&aerr->lock); + + return bank_error; +} + +static struct aca_bank_error *find_bank_error(struct aca_error *aerr, struct aca_bank_info *info) +{ + struct aca_bank_error *bank_error = NULL; + struct aca_bank_info *tmp_info; + bool found = false; + + mutex_lock(&aerr->lock); + list_for_each_entry(bank_error, &aerr->list, node) { + tmp_info = &bank_error->info; + if (tmp_info->socket_id == info->socket_id && + tmp_info->die_id == info->die_id) { + found = true; + goto out_unlock; + } + } + +out_unlock: + mutex_unlock(&aerr->lock); + + return found ? bank_error : NULL; +} + +static void aca_bank_error_remove(struct aca_error *aerr, struct aca_bank_error *bank_error) +{ + if (!aerr || !bank_error) + return; + + list_del(&bank_error->node); + aerr->nr_errors--; + + kvfree(bank_error); +} + +static struct aca_bank_error *get_bank_error(struct aca_error *aerr, struct aca_bank_info *info) +{ + struct aca_bank_error *bank_error; + + if (!aerr || !info) + return NULL; + + bank_error = find_bank_error(aerr, info); + if (bank_error) + return bank_error; + + return new_bank_error(aerr, info); +} + +static int aca_log_errors(struct aca_handle *handle, enum aca_error_type type, + struct aca_bank_report *report) +{ + struct aca_error_cache *error_cache = &handle->error_cache; + struct aca_bank_error *bank_error; + struct aca_error *aerr; + + if (!handle || !report) + return -EINVAL; + + if (!report->count[type]) + return 0; + + aerr = &error_cache->errors[type]; + bank_error = get_bank_error(aerr, &report->info); + if (!bank_error) + return -ENOMEM; + + bank_error->count[type] += report->count[type]; + + return 0; +} + +static int aca_generate_bank_report(struct aca_handle *handle, struct aca_bank *bank, + enum aca_error_type type, struct aca_bank_report *report) +{ + const struct aca_bank_ops *bank_ops = handle->bank_ops; + + if (!bank || !report) + return -EINVAL; + + if (!bank_ops->aca_bank_generate_report) + return -EOPNOTSUPP; + + memset(report, 0, sizeof(*report)); + return bank_ops->aca_bank_generate_report(handle, bank, type, + report, handle->data); +} + +static int handler_aca_log_bank_error(struct aca_handle *handle, struct aca_bank *bank, + enum aca_error_type type, void *data) +{ + struct aca_bank_report report; + int ret; + + ret = aca_generate_bank_report(handle, bank, type, &report); + if (ret) + return ret; + + if (!report.count[type]) + return 0; + + ret = aca_log_errors(handle, type, &report); + if (ret) + return ret; + + return 0; +} + +static int aca_dispatch_bank(struct aca_handle_manager *mgr, struct aca_bank *bank, + enum aca_error_type type, bank_handler_t handler, void *data) +{ + struct aca_handle *handle; + int ret; + + if (list_empty(&mgr->list)) + return 0; + + list_for_each_entry(handle, &mgr->list, node) { + if (!aca_bank_is_valid(handle, bank, type)) + continue; + + ret = handler(handle, bank, type, data); + if (ret) + return ret; + } + + return 0; +} + +static int aca_dispatch_banks(struct aca_handle_manager *mgr, struct aca_banks *banks, + enum aca_error_type type, bank_handler_t handler, void *data) +{ + struct aca_bank_node *node; + struct aca_bank *bank; + int ret; + + if (!mgr || !banks) + return -EINVAL; + + /* pre check to avoid unnecessary operations */ + if (list_empty(&mgr->list) || list_empty(&banks->list)) + return 0; + + list_for_each_entry(node, &banks->list, node) { + bank = &node->bank; + + ret = aca_dispatch_bank(mgr, bank, type, handler, data); + if (ret) + return ret; + } + + return 0; +} + +static int aca_banks_update(struct amdgpu_device *adev, enum aca_error_type type, + bank_handler_t handler, void *data) +{ + struct amdgpu_aca *aca = &adev->aca; + struct aca_banks banks; + u32 count = 0; + int ret; + + if (list_empty(&aca->mgr.list)) + return 0; + + /* NOTE: pmfw is only support UE and CE */ + if (type == ACA_ERROR_TYPE_DEFERRED) + type = ACA_ERROR_TYPE_CE; + + ret = aca_smu_get_valid_aca_count(adev, type, &count); + if (ret) + return ret; + + if (!count) + return 0; + + aca_banks_init(&banks); + + ret = aca_smu_get_valid_aca_banks(adev, type, 0, count, &banks); + if (ret) + goto err_release_banks; + + if (list_empty(&banks.list)) { + ret = 0; + goto err_release_banks; + } + + ret = aca_dispatch_banks(&aca->mgr, &banks, type, + handler, data); + if (ret) + goto err_release_banks; + +err_release_banks: + aca_banks_release(&banks); + + return ret; +} + +static int aca_log_aca_error_data(struct aca_bank_error *bank_error, enum aca_error_type type, struct ras_err_data *err_data) +{ + struct aca_bank_info *info; + struct amdgpu_smuio_mcm_config_info mcm_info; + u64 count; + + if (type >= ACA_ERROR_TYPE_COUNT) + return -EINVAL; + + count = bank_error->count[type]; + if (!count) + return 0; + + info = &bank_error->info; + mcm_info.die_id = info->die_id; + mcm_info.socket_id = info->socket_id; + + switch (type) { + case ACA_ERROR_TYPE_UE: + amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, NULL, count); + break; + case ACA_ERROR_TYPE_CE: + amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, NULL, count); + break; + case ACA_ERROR_TYPE_DEFERRED: + default: + break; + } + + return 0; +} + +static int aca_log_aca_error(struct aca_handle *handle, enum aca_error_type type, struct ras_err_data *err_data) +{ + struct aca_error_cache *error_cache = &handle->error_cache; + struct aca_error *aerr = &error_cache->errors[type]; + struct aca_bank_error *bank_error, *tmp; + + mutex_lock(&aerr->lock); + + if (list_empty(&aerr->list)) + goto out_unlock; + + list_for_each_entry_safe(bank_error, tmp, &aerr->list, node) { + aca_log_aca_error_data(bank_error, type, err_data); + aca_bank_error_remove(aerr, bank_error); + } + +out_unlock: + mutex_unlock(&aerr->lock); + + return 0; +} + +static int __aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle, enum aca_error_type type, + struct ras_err_data *err_data) +{ + int ret; + + /* udpate aca bank to aca source error_cache first */ + ret = aca_banks_update(adev, type, handler_aca_log_bank_error, NULL); + if (ret) + return ret; + + return aca_log_aca_error(handle, type, err_data); +} + +static bool aca_handle_is_valid(struct aca_handle *handle) +{ + if (!handle->mask || !list_empty(&handle->node)) + return false; + + return true; +} + +int amdgpu_aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle, + enum aca_error_type type, void *data) +{ + struct ras_err_data *err_data = (struct ras_err_data *)data; + + if (!handle || !err_data) + return -EINVAL; + + if (aca_handle_is_valid(handle)) + return -EOPNOTSUPP; + + if (!(BIT(type) & handle->mask)) + return 0; + + return __aca_get_error_data(adev, handle, type, err_data); +} + +static void aca_error_init(struct aca_error *aerr, enum aca_error_type type) +{ + mutex_init(&aerr->lock); + INIT_LIST_HEAD(&aerr->list); + aerr->type = type; + aerr->nr_errors = 0; +} + +static void aca_init_error_cache(struct aca_handle *handle) +{ + struct aca_error_cache *error_cache = &handle->error_cache; + int type; + + for (type = ACA_ERROR_TYPE_UE; type < ACA_ERROR_TYPE_COUNT; type++) + aca_error_init(&error_cache->errors[type], type); +} + +static void aca_error_fini(struct aca_error *aerr) +{ + struct aca_bank_error *bank_error, *tmp; + + mutex_lock(&aerr->lock); + list_for_each_entry_safe(bank_error, tmp, &aerr->list, node) + aca_bank_error_remove(aerr, bank_error); + + mutex_destroy(&aerr->lock); +} + +static void aca_fini_error_cache(struct aca_handle *handle) +{ + struct aca_error_cache *error_cache = &handle->error_cache; + int type; + + for (type = ACA_ERROR_TYPE_UE; type < ACA_ERROR_TYPE_COUNT; type++) + aca_error_fini(&error_cache->errors[type]); +} + +static int add_aca_handle(struct amdgpu_device *adev, struct aca_handle_manager *mgr, struct aca_handle *handle, + const char *name, const struct aca_info *ras_info, void *data) +{ + memset(handle, 0, sizeof(*handle)); + + handle->adev = adev; + handle->mgr = mgr; + handle->name = name; + handle->hwip = ras_info->hwip; + handle->mask = ras_info->mask; + handle->bank_ops = ras_info->bank_ops; + handle->data = data; + aca_init_error_cache(handle); + + INIT_LIST_HEAD(&handle->node); + list_add_tail(&handle->node, &mgr->list); + mgr->nr_handles++; + + return 0; +} + +static ssize_t aca_sysfs_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aca_handle *handle = container_of(attr, struct aca_handle, aca_attr); + + /* NOTE: the aca cache will be auto cleared once read, + * So the driver should unify the query entry point, forward request to ras query interface directly */ + return amdgpu_ras_aca_sysfs_read(dev, attr, handle, buf, handle->data); +} + +static int add_aca_sysfs(struct amdgpu_device *adev, struct aca_handle *handle) +{ + struct device_attribute *aca_attr = &handle->aca_attr; + + snprintf(handle->attr_name, sizeof(handle->attr_name) - 1, "aca_%s", handle->name); + aca_attr->show = aca_sysfs_read; + aca_attr->attr.name = handle->attr_name; + aca_attr->attr.mode = S_IRUGO; + sysfs_attr_init(&aca_attr->attr); + + return sysfs_add_file_to_group(&adev->dev->kobj, + &aca_attr->attr, + "ras"); +} + +int amdgpu_aca_add_handle(struct amdgpu_device *adev, struct aca_handle *handle, + const char *name, const struct aca_info *ras_info, void *data) +{ + struct amdgpu_aca *aca = &adev->aca; + int ret; + + if (!amdgpu_aca_is_enabled(adev)) + return 0; + + ret = add_aca_handle(adev, &aca->mgr, handle, name, ras_info, data); + if (ret) + return ret; + + return add_aca_sysfs(adev, handle); +} + +static void remove_aca_handle(struct aca_handle *handle) +{ + struct aca_handle_manager *mgr = handle->mgr; + + aca_fini_error_cache(handle); + list_del(&handle->node); + mgr->nr_handles--; +} + +static void remove_aca_sysfs(struct aca_handle *handle) +{ + struct amdgpu_device *adev = handle->adev; + struct device_attribute *aca_attr = &handle->aca_attr; + + if (adev->dev->kobj.sd) + sysfs_remove_file_from_group(&adev->dev->kobj, + &aca_attr->attr, + "ras"); +} + +void amdgpu_aca_remove_handle(struct aca_handle *handle) +{ + if (!handle || list_empty(&handle->node)) + return; + + remove_aca_sysfs(handle); + remove_aca_handle(handle); +} + +static int aca_manager_init(struct aca_handle_manager *mgr) +{ + INIT_LIST_HEAD(&mgr->list); + mgr->nr_handles = 0; + + return 0; +} + +static void aca_manager_fini(struct aca_handle_manager *mgr) +{ + struct aca_handle *handle, *tmp; + + list_for_each_entry_safe(handle, tmp, &mgr->list, node) + amdgpu_aca_remove_handle(handle); +} + +bool amdgpu_aca_is_enabled(struct amdgpu_device *adev) +{ + return adev->aca.is_enabled; +} + +int amdgpu_aca_init(struct amdgpu_device *adev) +{ + struct amdgpu_aca *aca = &adev->aca; + int ret; + + ret = aca_manager_init(&aca->mgr); + if (ret) + return ret; + + return 0; +} + +void amdgpu_aca_fini(struct amdgpu_device *adev) +{ + struct amdgpu_aca *aca = &adev->aca; + + aca_manager_fini(&aca->mgr); +} + +int amdgpu_aca_reset(struct amdgpu_device *adev) +{ + amdgpu_aca_fini(adev); + + return amdgpu_aca_init(adev); +} + +void amdgpu_aca_set_smu_funcs(struct amdgpu_device *adev, const struct aca_smu_funcs *smu_funcs) +{ + struct amdgpu_aca *aca = &adev->aca; + + WARN_ON(aca->smu_funcs); + aca->smu_funcs = smu_funcs; +} + +int aca_bank_info_decode(struct aca_bank *bank, struct aca_bank_info *info) +{ + u64 ipid; + u32 instidhi, instidlo; + + if (!bank || !info) + return -EINVAL; + + ipid = bank->regs[ACA_REG_IDX_IPID]; + info->hwid = ACA_REG__IPID__HARDWAREID(ipid); + info->mcatype = ACA_REG__IPID__MCATYPE(ipid); + /* + * Unfied DieID Format: SAASS. A:AID, S:Socket. + * Unfied DieID[4:4] = InstanceId[0:0] + * Unfied DieID[0:3] = InstanceIdHi[0:3] + */ + instidhi = ACA_REG__IPID__INSTANCEIDHI(ipid); + instidlo = ACA_REG__IPID__INSTANCEIDLO(ipid); + info->die_id = ((instidhi >> 2) & 0x03); + info->socket_id = ((instidlo & 0x1) << 2) | (instidhi & 0x03); + + return 0; +} + +static int aca_bank_get_error_code(struct amdgpu_device *adev, struct aca_bank *bank) +{ + int error_code; + + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(13, 0, 6): + if (!(adev->flags & AMD_IS_APU) && adev->pm.fw_version >= 0x00555600) { + error_code = ACA_REG__SYND__ERRORINFORMATION(bank->regs[ACA_REG_IDX_SYND]); + return error_code & 0xff; + } + break; + default: + break; + } + + /* NOTE: the true error code is encoded in status.errorcode[0:7] */ + error_code = ACA_REG__STATUS__ERRORCODE(bank->regs[ACA_REG_IDX_STATUS]); + + return error_code & 0xff; +} + +int aca_bank_check_error_codes(struct amdgpu_device *adev, struct aca_bank *bank, int *err_codes, int size) +{ + int i, error_code; + + if (!bank || !err_codes) + return -EINVAL; + + error_code = aca_bank_get_error_code(adev, bank); + for (i = 0; i < size; i++) { + if (err_codes[i] == error_code) + return 0; + } + + return -EINVAL; +} + +int amdgpu_aca_smu_set_debug_mode(struct amdgpu_device *adev, bool en) +{ + struct amdgpu_aca *aca = &adev->aca; + const struct aca_smu_funcs *smu_funcs = aca->smu_funcs; + + if (!smu_funcs || !smu_funcs->set_debug_mode) + return -EOPNOTSUPP; + + return smu_funcs->set_debug_mode(adev, en); +} + +#if defined(CONFIG_DEBUG_FS) +static int amdgpu_aca_smu_debug_mode_set(void *data, u64 val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + int ret; + + ret = amdgpu_ras_set_aca_debug_mode(adev, val ? true : false); + if (ret) + return ret; + + dev_info(adev->dev, "amdgpu set smu aca debug mode %s success\n", val ? "on" : "off"); + + return 0; +} + +static void aca_dump_entry(struct seq_file *m, struct aca_bank *bank, enum aca_error_type type, int idx) +{ + struct aca_bank_info info; + int i, ret; + + ret = aca_bank_info_decode(bank, &info); + if (ret) + return; + + seq_printf(m, "aca entry[%d].type: %s\n", idx, type == ACA_ERROR_TYPE_UE ? "UE" : "CE"); + seq_printf(m, "aca entry[%d].info: socketid:%d aid:%d hwid:0x%03x mcatype:0x%04x\n", + idx, info.socket_id, info.die_id, info.hwid, info.mcatype); + + for (i = 0; i < ARRAY_SIZE(aca_regs); i++) + seq_printf(m, "aca entry[%d].regs[%d]: 0x%016llx\n", idx, aca_regs[i].reg_idx, bank->regs[aca_regs[i].reg_idx]); +} + +struct aca_dump_context { + struct seq_file *m; + int idx; +}; + +static int handler_aca_bank_dump(struct aca_handle *handle, struct aca_bank *bank, + enum aca_error_type type, void *data) +{ + struct aca_dump_context *ctx = (struct aca_dump_context *)data; + + aca_dump_entry(ctx->m, bank, type, ctx->idx++); + + return handler_aca_log_bank_error(handle, bank, type, NULL); +} + +static int aca_dump_show(struct seq_file *m, enum aca_error_type type) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)m->private; + struct aca_dump_context context = { + .m = m, + .idx = 0, + }; + + return aca_banks_update(adev, type, handler_aca_bank_dump, (void *)&context); +} + +static int aca_dump_ce_show(struct seq_file *m, void *unused) +{ + return aca_dump_show(m, ACA_ERROR_TYPE_CE); +} + +static int aca_dump_ce_open(struct inode *inode, struct file *file) +{ + return single_open(file, aca_dump_ce_show, inode->i_private); +} + +static const struct file_operations aca_ce_dump_debug_fops = { + .owner = THIS_MODULE, + .open = aca_dump_ce_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int aca_dump_ue_show(struct seq_file *m, void *unused) +{ + return aca_dump_show(m, ACA_ERROR_TYPE_UE); +} + +static int aca_dump_ue_open(struct inode *inode, struct file *file) +{ + return single_open(file, aca_dump_ue_show, inode->i_private); +} + +static const struct file_operations aca_ue_dump_debug_fops = { + .owner = THIS_MODULE, + .open = aca_dump_ue_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +DEFINE_DEBUGFS_ATTRIBUTE(aca_debug_mode_fops, NULL, amdgpu_aca_smu_debug_mode_set, "%llu\n"); +#endif + +void amdgpu_aca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root) +{ +#if defined(CONFIG_DEBUG_FS) + if (!root || adev->ip_versions[MP1_HWIP][0] != IP_VERSION(13, 0, 6)) + return; + + debugfs_create_file("aca_debug_mode", 0200, root, adev, &aca_debug_mode_fops); + debugfs_create_file("aca_ue_dump", 0400, root, adev, &aca_ue_dump_debug_fops); + debugfs_create_file("aca_ce_dump", 0400, root, adev, &aca_ce_dump_debug_fops); +#endif +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.h new file mode 100644 index 0000000000000000000000000000000000000000..2da50e0958831e897ca7fb5893810c8328162303 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.h @@ -0,0 +1,202 @@ +/* + * Copyright 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __AMDGPU_ACA_H__ +#define __AMDGPU_ACA_H__ + +#include + +#define ACA_MAX_REGS_COUNT (16) + +#define ACA_REG_FIELD(x, h, l) (((x) & GENMASK_ULL(h, l)) >> l) +#define ACA_REG__STATUS__VAL(x) ACA_REG_FIELD(x, 63, 63) +#define ACA_REG__STATUS__OVERFLOW(x) ACA_REG_FIELD(x, 62, 62) +#define ACA_REG__STATUS__UC(x) ACA_REG_FIELD(x, 61, 61) +#define ACA_REG__STATUS__EN(x) ACA_REG_FIELD(x, 60, 60) +#define ACA_REG__STATUS__MISCV(x) ACA_REG_FIELD(x, 59, 59) +#define ACA_REG__STATUS__ADDRV(x) ACA_REG_FIELD(x, 58, 58) +#define ACA_REG__STATUS__PCC(x) ACA_REG_FIELD(x, 57, 57) +#define ACA_REG__STATUS__ERRCOREIDVAL(x) ACA_REG_FIELD(x, 56, 56) +#define ACA_REG__STATUS__TCC(x) ACA_REG_FIELD(x, 55, 55) +#define ACA_REG__STATUS__SYNDV(x) ACA_REG_FIELD(x, 53, 53) +#define ACA_REG__STATUS__CECC(x) ACA_REG_FIELD(x, 46, 46) +#define ACA_REG__STATUS__UECC(x) ACA_REG_FIELD(x, 45, 45) +#define ACA_REG__STATUS__DEFERRED(x) ACA_REG_FIELD(x, 44, 44) +#define ACA_REG__STATUS__POISON(x) ACA_REG_FIELD(x, 43, 43) +#define ACA_REG__STATUS__SCRUB(x) ACA_REG_FIELD(x, 40, 40) +#define ACA_REG__STATUS__ERRCOREID(x) ACA_REG_FIELD(x, 37, 32) +#define ACA_REG__STATUS__ADDRLSB(x) ACA_REG_FIELD(x, 29, 24) +#define ACA_REG__STATUS__ERRORCODEEXT(x) ACA_REG_FIELD(x, 21, 16) +#define ACA_REG__STATUS__ERRORCODE(x) ACA_REG_FIELD(x, 15, 0) + +#define ACA_REG__IPID__MCATYPE(x) ACA_REG_FIELD(x, 63, 48) +#define ACA_REG__IPID__INSTANCEIDHI(x) ACA_REG_FIELD(x, 47, 44) +#define ACA_REG__IPID__HARDWAREID(x) ACA_REG_FIELD(x, 43, 32) +#define ACA_REG__IPID__INSTANCEIDLO(x) ACA_REG_FIELD(x, 31, 0) + +#define ACA_REG__MISC0__VALID(x) ACA_REG_FIELD(x, 63, 63) +#define ACA_REG__MISC0__OVRFLW(x) ACA_REG_FIELD(x, 48, 48) +#define ACA_REG__MISC0__ERRCNT(x) ACA_REG_FIELD(x, 43, 32) + +#define ACA_REG__SYND__ERRORINFORMATION(x) ACA_REG_FIELD(x, 17, 0) + +/* NOTE: The following codes refers to the smu header file */ +#define ACA_EXTERROR_CODE_CE 0x3a +#define ACA_EXTERROR_CODE_FAULT 0x3b + +#define ACA_ERROR_UE_MASK BIT_MASK(ACA_ERROR_TYPE_UE) +#define ACA_ERROR_CE_MASK BIT_MASK(ACA_ERROR_TYPE_CE) +#define ACA_ERROR_DEFERRED_MASK BIT_MASK(ACA_ERROR_TYPE_DEFERRED) + +enum aca_reg_idx { + ACA_REG_IDX_CTL = 0, + ACA_REG_IDX_STATUS = 1, + ACA_REG_IDX_ADDR = 2, + ACA_REG_IDX_MISC0 = 3, + ACA_REG_IDX_CONFG = 4, + ACA_REG_IDX_IPID = 5, + ACA_REG_IDX_SYND = 6, + ACA_REG_IDX_DESTAT = 8, + ACA_REG_IDX_DEADDR = 9, + ACA_REG_IDX_CTL_MASK = 10, + ACA_REG_IDX_COUNT = 16, +}; + +enum aca_hwip_type { + ACA_HWIP_TYPE_UNKNOW = -1, + ACA_HWIP_TYPE_PSP = 0, + ACA_HWIP_TYPE_UMC, + ACA_HWIP_TYPE_SMU, + ACA_HWIP_TYPE_PCS_XGMI, + ACA_HWIP_TYPE_COUNT, +}; + +enum aca_error_type { + ACA_ERROR_TYPE_INVALID = -1, + ACA_ERROR_TYPE_UE = 0, + ACA_ERROR_TYPE_CE, + ACA_ERROR_TYPE_DEFERRED, + ACA_ERROR_TYPE_COUNT +}; + +struct aca_bank { + u64 regs[ACA_MAX_REGS_COUNT]; +}; + +struct aca_bank_node { + struct aca_bank bank; + struct list_head node; +}; + +struct aca_bank_info { + int die_id; + int socket_id; + int hwid; + int mcatype; +}; + +struct aca_bank_report { + struct aca_bank_info info; + u64 count[ACA_ERROR_TYPE_COUNT]; +}; + +struct aca_bank_error { + struct list_head node; + struct aca_bank_info info; + u64 count[ACA_ERROR_TYPE_COUNT]; +}; + +struct aca_error { + struct list_head list; + struct mutex lock; + enum aca_error_type type; + int nr_errors; +}; + +struct aca_handle_manager { + struct list_head list; + int nr_handles; +}; + +struct aca_error_cache { + struct aca_error errors[ACA_ERROR_TYPE_COUNT]; +}; + +struct aca_handle { + struct list_head node; + enum aca_hwip_type hwip; + struct amdgpu_device *adev; + struct aca_handle_manager *mgr; + struct aca_error_cache error_cache; + const struct aca_bank_ops *bank_ops; + struct device_attribute aca_attr; + char attr_name[64]; + const char *name; + u32 mask; + void *data; +}; + +struct aca_bank_ops { + int (*aca_bank_generate_report)(struct aca_handle *handle, struct aca_bank *bank, enum aca_error_type type, + struct aca_bank_report *report, void *data); + bool (*aca_bank_is_valid)(struct aca_handle *handle, struct aca_bank *bank, enum aca_error_type type, + void *data); +}; + +struct aca_smu_funcs { + int max_ue_bank_count; + int max_ce_bank_count; + int (*set_debug_mode)(struct amdgpu_device *adev, bool enable); + int (*get_valid_aca_count)(struct amdgpu_device *adev, enum aca_error_type type, u32 *count); + int (*get_valid_aca_bank)(struct amdgpu_device *adev, enum aca_error_type type, int idx, struct aca_bank *bank); +}; + +struct amdgpu_aca { + struct aca_handle_manager mgr; + const struct aca_smu_funcs *smu_funcs; + bool is_enabled; +}; + +struct aca_info { + enum aca_hwip_type hwip; + const struct aca_bank_ops *bank_ops; + u32 mask; +}; + +int amdgpu_aca_init(struct amdgpu_device *adev); +void amdgpu_aca_fini(struct amdgpu_device *adev); +int amdgpu_aca_reset(struct amdgpu_device *adev); +void amdgpu_aca_set_smu_funcs(struct amdgpu_device *adev, const struct aca_smu_funcs *smu_funcs); +bool amdgpu_aca_is_enabled(struct amdgpu_device *adev); + +int aca_bank_info_decode(struct aca_bank *bank, struct aca_bank_info *info); +int aca_bank_check_error_codes(struct amdgpu_device *adev, struct aca_bank *bank, int *err_codes, int size); + +int amdgpu_aca_add_handle(struct amdgpu_device *adev, struct aca_handle *handle, + const char *name, const struct aca_info *aca_info, void *data); +void amdgpu_aca_remove_handle(struct aca_handle *handle); +int amdgpu_aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle, + enum aca_error_type type, void *data); +int amdgpu_aca_smu_set_debug_mode(struct amdgpu_device *adev, bool en); +void amdgpu_aca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root); +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 77e2636602887034c188ec695591d20e5b087b60..190039f14c30c676f080e6c55a8c8637901a74fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -141,11 +141,31 @@ static void amdgpu_amdkfd_reset_work(struct work_struct *work) static const struct drm_client_funcs kfd_client_funcs = { .unregister = drm_client_release, }; + +int amdgpu_amdkfd_drm_client_create(struct amdgpu_device *adev) +{ + int ret; + + if (!adev->kfd.init_complete) + return 0; + + ret = drm_client_init(&adev->ddev, &adev->kfd.client, "kfd", + &kfd_client_funcs); + if (ret) { + dev_err(adev->dev, "Failed to init DRM client: %d\n", + ret); + return ret; + } + + drm_client_register(&adev->kfd.client); + + return 0; +} + void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) { int i; int last_valid_bit; - int ret; amdgpu_amdkfd_gpuvm_init_mem_limits(); @@ -164,12 +184,6 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) .enable_mes = adev->enable_mes, }; - ret = drm_client_init(&adev->ddev, &adev->kfd.client, "kfd", &kfd_client_funcs); - if (ret) { - dev_err(adev->dev, "Failed to init DRM client: %d\n", ret); - return; - } - /* this is going to have a few of the MSBs set that we need to * clear */ @@ -208,10 +222,6 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) adev->kfd.init_complete = kgd2kfd_device_init(adev->kfd.dev, &gpu_resources); - if (adev->kfd.init_complete) - drm_client_register(&adev->kfd.client); - else - drm_client_release(&adev->kfd.client); amdgpu_amdkfd_total_mem_size += adev->gmc.real_vram_size; @@ -732,9 +742,10 @@ void amdgpu_amdkfd_debug_mem_fence(struct amdgpu_device *adev) amdgpu_device_flush_hdp(adev, NULL); } -void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, bool reset) +void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, + enum amdgpu_ras_block block, bool reset) { - amdgpu_umc_poison_handler(adev, reset); + amdgpu_umc_poison_handler(adev, block, reset); } int amdgpu_amdkfd_send_close_event_drain_irq(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index f262b9d89541a8a971a394b5f0da0f6a1368ba65..e60f63ccf79a25a3aa01a987509a90988849f542 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -182,6 +182,8 @@ int amdgpu_queue_mask_bit_to_set_resource_bit(struct amdgpu_device *adev, struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, struct mm_struct *mm, struct svm_range_bo *svm_bo); + +int amdgpu_amdkfd_drm_client_create(struct amdgpu_device *adev); #if defined(CONFIG_DEBUG_FS) int kfd_debugfs_kfd_mem_limits(struct seq_file *m, void *data); #endif @@ -191,6 +193,9 @@ struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f); int amdgpu_amdkfd_remove_fence_on_pt_pd_bos(struct amdgpu_bo *bo); int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni, unsigned long cur_seq, struct kgd_mem *mem); +int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, + uint32_t domain, + struct dma_fence *fence); #else static inline bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm) @@ -216,6 +221,13 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni, { return 0; } +static inline +int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, + uint32_t domain, + struct dma_fence *fence) +{ + return 0; +} #endif /* Shared API */ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, @@ -301,7 +313,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv); int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv); -void amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv); +int amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv); int amdgpu_amdkfd_gpuvm_sync_memory( struct amdgpu_device *adev, struct kgd_mem *mem, bool intr); int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem, @@ -324,7 +336,7 @@ void amdgpu_amdkfd_debug_mem_fence(struct amdgpu_device *adev); int amdgpu_amdkfd_get_tile_config(struct amdgpu_device *adev, struct tile_config *config); void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, - bool reset); + enum amdgpu_ras_block block, bool reset); bool amdgpu_amdkfd_bo_mapped_to_dev(struct amdgpu_device *adev, struct kgd_mem *mem); void amdgpu_amdkfd_block_mmu_notifications(void *p); int amdgpu_amdkfd_criu_resume(void *p); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c index 899e31e3a5e81d2be343a668e295a564efee10af..3a3f3ce09f00dbe77f61455f24fed7bd0db0dec5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c @@ -290,7 +290,7 @@ static int suspend_resume_compute_scheduler(struct amdgpu_device *adev, bool sus for (i = 0; i < adev->gfx.num_compute_rings; i++) { struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; - if (!(ring && drm_sched_wqueue_ready(&ring->sched))) + if (!amdgpu_ring_sched_ready(ring)) continue; /* stop secheduler and drain ring. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index f183d7faeeece16cfc7c211f5a6a0232dce37c36..5cd84f72bf26ef5a6896f7ea853c654b55e8569d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -426,9 +426,9 @@ validate_fail: return ret; } -static int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, - uint32_t domain, - struct dma_fence *fence) +int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, + uint32_t domain, + struct dma_fence *fence) { int ret = amdgpu_bo_reserve(bo, false); @@ -464,13 +464,15 @@ static int amdgpu_amdkfd_validate_vm_bo(void *_unused, struct amdgpu_bo *bo) * again. Page directories are only updated after updating page * tables. */ -static int vm_validate_pt_pd_bos(struct amdgpu_vm *vm) +static int vm_validate_pt_pd_bos(struct amdgpu_vm *vm, + struct ww_acquire_ctx *ticket) { struct amdgpu_bo *pd = vm->root.bo; struct amdgpu_device *adev = amdgpu_ttm_adev(pd->tbo.bdev); int ret; - ret = amdgpu_vm_validate_pt_bos(adev, vm, amdgpu_amdkfd_validate_vm_bo, NULL); + ret = amdgpu_vm_validate(adev, vm, ticket, + amdgpu_amdkfd_validate_vm_bo, NULL); if (ret) { pr_err("failed to validate PT BOs\n"); return ret; @@ -1310,14 +1312,15 @@ update_gpuvm_pte_failed: return ret; } -static int process_validate_vms(struct amdkfd_process_info *process_info) +static int process_validate_vms(struct amdkfd_process_info *process_info, + struct ww_acquire_ctx *ticket) { struct amdgpu_vm *peer_vm; int ret; list_for_each_entry(peer_vm, &process_info->vm_list_head, vm_list_node) { - ret = vm_validate_pt_pd_bos(peer_vm); + ret = vm_validate_pt_pd_bos(peer_vm, ticket); if (ret) return ret; } @@ -1402,7 +1405,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info, ret = amdgpu_bo_reserve(vm->root.bo, true); if (ret) goto reserve_pd_fail; - ret = vm_validate_pt_pd_bos(vm); + ret = vm_validate_pt_pd_bos(vm, NULL); if (ret) { pr_err("validate_pt_pd_bos() failed\n"); goto validate_pd_fail; @@ -2043,7 +2046,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu( bo->tbo.resource->mem_type == TTM_PL_SYSTEM) is_invalid_userptr = true; - ret = vm_validate_pt_pd_bos(avm); + ret = vm_validate_pt_pd_bos(avm, NULL); if (unlikely(ret)) goto out_unreserve; @@ -2085,21 +2088,35 @@ out: return ret; } -void amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv) +int amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv) { struct kfd_mem_attachment *entry; struct amdgpu_vm *vm; + int ret; vm = drm_priv_to_vm(drm_priv); mutex_lock(&mem->lock); + ret = amdgpu_bo_reserve(mem->bo, true); + if (ret) + goto out; + list_for_each_entry(entry, &mem->attachments, list) { - if (entry->bo_va->base.vm == vm) - kfd_mem_dmaunmap_attachment(mem, entry); + if (entry->bo_va->base.vm != vm) + continue; + if (entry->bo_va->base.bo->tbo.ttm && + !entry->bo_va->base.bo->tbo.ttm->sg) + continue; + + kfd_mem_dmaunmap_attachment(mem, entry); } + amdgpu_bo_unreserve(mem->bo); +out: mutex_unlock(&mem->lock); + + return ret; } int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( @@ -2122,7 +2139,7 @@ int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( goto unreserve_out; } - ret = vm_validate_pt_pd_bos(avm); + ret = vm_validate_pt_pd_bos(avm, NULL); if (unlikely(ret)) goto unreserve_out; @@ -2620,7 +2637,7 @@ static int validate_invalid_user_pages(struct amdkfd_process_info *process_info) } } - ret = process_validate_vms(process_info); + ret = process_validate_vms(process_info, NULL); if (ret) goto unreserve_out; @@ -2880,11 +2897,6 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu * amdgpu_sync_create(&sync_obj); - /* Validate PDs and PTs */ - ret = process_validate_vms(process_info); - if (ret) - goto validate_map_fail; - /* Validate BOs and map them to GPUVM (update VM page tables). */ list_for_each_entry(mem, &process_info->kfd_bo_list, validate_list) { @@ -2935,6 +2947,13 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu * if (failed_size) pr_debug("0x%lx/0x%lx in system\n", failed_size, total_size); + /* Validate PDs, PTs and evicted DMABuf imports last. Otherwise BO + * validations above would invalidate DMABuf imports again. + */ + ret = process_validate_vms(process_info, &exec.ticket); + if (ret) + goto validate_map_fail; + /* Update mappings not managed by KFD */ list_for_each_entry(peer_vm, &process_info->vm_list_head, vm_list_node) { @@ -3006,7 +3025,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu * &process_info->eviction_fence->base, DMA_RESV_USAGE_BOOKKEEP); } - /* Attach eviction fence to PD / PT BOs */ + /* Attach eviction fence to PD / PT BOs and DMABuf imports */ list_for_each_entry(peer_vm, &process_info->vm_list_head, vm_list_node) { struct amdgpu_bo *bo = peer_vm->root.bo; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index dce9e7d5e4ec672827f574fb64816ca205ef96ee..52b12c1718eb0ecd38d5563306c959ae675f3438 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -1018,7 +1018,8 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, if (clock_type == COMPUTE_ENGINE_PLL_PARAM) { args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock); - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, + sizeof(args)); dividers->post_div = args.v3.ucPostDiv; dividers->enable_post_div = (args.v3.ucCntlFlag & @@ -1038,7 +1039,8 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, if (strobe_mode) args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, + sizeof(args)); dividers->post_div = args.v5.ucPostDiv; dividers->enable_post_div = (args.v5.ucCntlFlag & @@ -1056,7 +1058,8 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, /* fusion */ args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */ - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, + sizeof(args)); dividers->post_divider = dividers->post_div = args.v4.ucPostDiv; dividers->real_clock = le32_to_cpu(args.v4.ulClock); @@ -1067,7 +1070,8 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, args.v6_in.ulClock.ulComputeClockFlag = clock_type; args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */ - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, + sizeof(args)); dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv); dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac); @@ -1109,7 +1113,8 @@ int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev, if (strobe_mode) args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, + sizeof(args)); mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac); mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv); @@ -1151,7 +1156,8 @@ void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev, if (mem_clock) args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK); - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, + sizeof(args)); } void amdgpu_atombios_get_default_voltages(struct amdgpu_device *adev, @@ -1205,7 +1211,8 @@ int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type, args.v2.ucVoltageMode = 0; args.v2.usVoltageLevel = 0; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, + sizeof(args)); *voltage = le16_to_cpu(args.v2.usVoltageLevel); break; @@ -1214,7 +1221,8 @@ int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type, args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL; args.v3.usVoltageLevel = cpu_to_le16(voltage_id); - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, + sizeof(args)); *voltage = le16_to_cpu(args.v3.usVoltageLevel); break; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c index fb2681dd6b338c222eaa0431cce61f940ad239b2..6857c586ded710e62d6b5a15d77966b719c05c6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c @@ -941,5 +941,6 @@ int amdgpu_atomfirmware_asic_init(struct amdgpu_device *adev, bool fb_reset) return -EINVAL; } - return amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, (uint32_t *)&asic_init_ps_v2_1); + return amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, (uint32_t *)&asic_init_ps_v2_1, + sizeof(asic_init_ps_v2_1)); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h index c7eb2caec65a92491b66fe98178199bfe0e7c6f8..649b5530d8ae13905b32937c5a36ce8b5e671d35 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h @@ -36,7 +36,7 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev); int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev); bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev); bool amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device *adev); -bool amdgpu_atomfirmware_ras_rom_addr(struct amdgpu_device *adev, uint8_t* i2c_address); +bool amdgpu_atomfirmware_ras_rom_addr(struct amdgpu_device *adev, uint8_t *i2c_address); bool amdgpu_atomfirmware_mem_training_supported(struct amdgpu_device *adev); bool amdgpu_atomfirmware_dynamic_boot_config_supported(struct amdgpu_device *adev); int amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 6adeddfb3d5643bebe7366094ce8f4ba00dcdfb2..0a4b09709cfb149078c6284f2a0908cbde928430 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -952,10 +952,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, p->bytes_moved = 0; p->bytes_moved_vis = 0; - r = amdgpu_vm_validate_pt_bos(p->adev, &fpriv->vm, - amdgpu_cs_bo_validate, p); + r = amdgpu_vm_validate(p->adev, &fpriv->vm, NULL, + amdgpu_cs_bo_validate, p); if (r) { - DRM_ERROR("amdgpu_vm_validate_pt_bos() failed.\n"); + DRM_ERROR("amdgpu_vm_validate() failed.\n"); goto out_free_user_pages; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c index 796fa6f1420b339c00ee17115765147c6714bbb8..b5ad56690a9d68f63e585ae0bb82522848ac6b9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c @@ -30,7 +30,7 @@ uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev) { uint64_t addr = adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT; - addr -= AMDGPU_VA_RESERVED_SIZE; + addr -= AMDGPU_VA_RESERVED_CSA_SIZE; addr = amdgpu_gmc_sign_extend(addr); return addr; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index e485dd3357c63fd225b3fb7e3847675749f018da..1afbb2e932c6b58a9e26cbabe61370151373a4af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -1678,7 +1678,7 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused) for (i = 0; i < AMDGPU_MAX_RINGS; i++) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring)) continue; drm_sched_wqueue_stop(&ring->sched); } @@ -1694,7 +1694,7 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused) for (i = 0; i < AMDGPU_MAX_RINGS; i++) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring)) continue; drm_sched_wqueue_start(&ring->sched); } @@ -1916,8 +1916,8 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) ring = adev->rings[val]; - if (!ring || !ring->funcs->preempt_ib || - !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring) || + !ring->funcs->preempt_ib) return -EINVAL; /* the last preemption failed */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index b158d27d0a71cbbafb55f0d58657c1ec178fa6c2..d534e192e260d7e5cc92f68e05e70b79e9e7f8ac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -96,6 +96,9 @@ MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); #define AMDGPU_RESUME_MS 2000 #define AMDGPU_MAX_RETRY_LIMIT 2 #define AMDGPU_RETRY_SRIOV_RESET(r) ((r) == -EBUSY || (r) == -ETIMEDOUT || (r) == -EINVAL) +#define AMDGPU_PCIE_INDEX_FALLBACK (0x38 >> 2) +#define AMDGPU_PCIE_INDEX_HI_FALLBACK (0x44 >> 2) +#define AMDGPU_PCIE_DATA_FALLBACK (0x3C >> 2) static const struct drm_driver amdgpu_kms_driver; @@ -781,12 +784,22 @@ u32 amdgpu_device_indirect_rreg_ext(struct amdgpu_device *adev, void __iomem *pcie_index_hi_offset; void __iomem *pcie_data_offset; - pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev); - pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev); - if ((reg_addr >> 32) && (adev->nbio.funcs->get_pcie_index_hi_offset)) - pcie_index_hi = adev->nbio.funcs->get_pcie_index_hi_offset(adev); - else + if (unlikely(!adev->nbio.funcs)) { + pcie_index = AMDGPU_PCIE_INDEX_FALLBACK; + pcie_data = AMDGPU_PCIE_DATA_FALLBACK; + } else { + pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev); + pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev); + } + + if (reg_addr >> 32) { + if (unlikely(!adev->nbio.funcs)) + pcie_index_hi = AMDGPU_PCIE_INDEX_HI_FALLBACK; + else + pcie_index_hi = adev->nbio.funcs->get_pcie_index_hi_offset(adev); + } else { pcie_index_hi = 0; + } spin_lock_irqsave(&adev->pcie_idx_lock, flags); pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4; @@ -1218,8 +1231,6 @@ static int amdgpu_device_asic_init(struct amdgpu_device *adev) amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(11, 0, 0)) { amdgpu_psp_wait_for_bootloader(adev); ret = amdgpu_atomfirmware_asic_init(adev, true); - /* TODO: check the return val and stop device initialization if boot fails */ - amdgpu_psp_query_boot_status(adev); return ret; } else { return amdgpu_atom_asic_init(adev->mode_info.atom_context); @@ -1442,6 +1453,10 @@ int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) return 0; + /* PCI_EXT_CAP_ID_VNDR extended capability is located at 0x100 */ + if (!pci_find_ext_capability(adev->pdev, PCI_EXT_CAP_ID_VNDR)) + DRM_WARN("System can't access extended configuration space,please check!!\n"); + /* skip if the bios has already enabled large BAR */ if (adev->gmc.real_vram_size && (pci_resource_len(adev->pdev, 0) >= adev->gmc.real_vram_size)) @@ -4121,23 +4136,13 @@ int amdgpu_device_init(struct amdgpu_device *adev, } } } else { - switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { - case IP_VERSION(13, 0, 0): - case IP_VERSION(13, 0, 7): - case IP_VERSION(13, 0, 10): - r = psp_gpu_reset(adev); - break; - default: - tmp = amdgpu_reset_method; - /* It should do a default reset when loading or reloading the driver, - * regardless of the module parameter reset_method. - */ - amdgpu_reset_method = AMD_RESET_METHOD_NONE; - r = amdgpu_asic_reset(adev); - amdgpu_reset_method = tmp; - break; - } - + tmp = amdgpu_reset_method; + /* It should do a default reset when loading or reloading the driver, + * regardless of the module parameter reset_method. + */ + amdgpu_reset_method = AMD_RESET_METHOD_NONE; + r = amdgpu_asic_reset(adev); + amdgpu_reset_method = tmp; if (r) { dev_err(adev->dev, "asic reset on init failed\n"); goto failed; @@ -5031,7 +5036,7 @@ bool amdgpu_device_has_job_running(struct amdgpu_device *adev) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring)) continue; spin_lock(&ring->sched.job_list_lock); @@ -5170,7 +5175,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring)) continue; /* Clear job fence from fence drv to avoid force_completion @@ -5637,7 +5642,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = tmp_adev->rings[i]; - if (!ring || !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring)) continue; drm_sched_stop(&ring->sched, job ? &job->base : NULL); @@ -5690,6 +5695,7 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */ /* Aldebaran and gfx_11_0_3 support ras in SRIOV, so need resume ras during reset */ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 2) || + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) || amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 0, 3)) amdgpu_ras_resume(adev); } else { @@ -5706,7 +5712,7 @@ skip_hw_reset: for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = tmp_adev->rings[i]; - if (!ring || !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring)) continue; drm_sched_start(&ring->sched, true); @@ -6061,7 +6067,7 @@ pci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_sta for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring)) continue; drm_sched_stop(&ring->sched, NULL); @@ -6111,6 +6117,20 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev) struct amdgpu_reset_context reset_context; u32 memsize; struct list_head device_list; + struct amdgpu_hive_info *hive; + int hive_ras_recovery = 0; + struct amdgpu_ras *ras; + + /* PCI error slot reset should be skipped During RAS recovery */ + hive = amdgpu_get_xgmi_hive(adev); + if (hive) { + hive_ras_recovery = atomic_read(&hive->ras_recovery); + amdgpu_put_xgmi_hive(hive); + } + ras = amdgpu_ras_get_context(adev); + if ((amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3)) && + ras && (atomic_read(&ras->in_recovery) || hive_ras_recovery)) + return PCI_ERS_RESULT_RECOVERED; DRM_INFO("PCI error: slot reset callback!!\n"); @@ -6189,7 +6209,7 @@ void amdgpu_pci_resume(struct pci_dev *pdev) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !drm_sched_wqueue_ready(&ring->sched)) + if (!amdgpu_ring_sched_ready(ring)) continue; drm_sched_start(&ring->sched, true); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index c7d60dd0fb975d47d749300c79f976da15892736..118288b644870235d66a8ccde39db42e40eda06f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -27,6 +27,7 @@ #include "amdgpu_discovery.h" #include "soc15_hw_ip.h" #include "discovery.h" +#include "amdgpu_ras.h" #include "soc15.h" #include "gfx_v9_0.h" @@ -98,6 +99,7 @@ #define FIRMWARE_IP_DISCOVERY "amdgpu/ip_discovery.bin" MODULE_FIRMWARE(FIRMWARE_IP_DISCOVERY); +#define mmIP_DISCOVERY_VERSION 0x16A00 #define mmRCC_CONFIG_MEMSIZE 0xde3 #define mmMP0_SMN_C2PMSG_33 0x16061 #define mmMM_INDEX 0x0 @@ -518,7 +520,9 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) out: kfree(adev->mman.discovery_bin); adev->mman.discovery_bin = NULL; - + if ((amdgpu_discovery != 2) && + (RREG32(mmIP_DISCOVERY_VERSION) == 4)) + amdgpu_ras_query_boot_status(adev, 4); return r; } @@ -1278,11 +1282,10 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) * 0b10 : encode is disabled * 0b01 : decode is disabled */ - adev->vcn.vcn_config[adev->vcn.num_vcn_inst] = - ip->revision & 0xc0; - ip->revision &= ~0xc0; if (adev->vcn.num_vcn_inst < AMDGPU_MAX_VCN_INSTANCES) { + adev->vcn.vcn_config[adev->vcn.num_vcn_inst] = + ip->revision & 0xc0; adev->vcn.num_vcn_inst++; adev->vcn.inst_mask |= (1U << ip->instance_number); @@ -1293,6 +1296,7 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) adev->vcn.num_vcn_inst + 1, AMDGPU_MAX_VCN_INSTANCES); } + ip->revision &= ~0xc0; } if (le16_to_cpu(ip->hw_id) == SDMA0_HWID || le16_to_cpu(ip->hw_id) == SDMA1_HWID || diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index decbbe3d4f06e9aa67365b68e747feeb5bad6fc1..055ba2ea4c126f621890b56c56ef86672e63b0c3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -377,6 +377,10 @@ amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach) struct amdgpu_vm_bo_base *bo_base; int r; + /* FIXME: This should be after the "if", but needs a fix to make sure + * DMABuf imports are initialized in the right VM list. + */ + amdgpu_vm_bo_invalidate(adev, bo, false); if (!bo->tbo.resource || bo->tbo.resource->mem_type == TTM_PL_SYSTEM) return; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index cc69005f5b46e7b9f06d65db13287a617cc384e2..161ecf9b41747924e42b0e3d2f822f0b2ad42b35 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -366,7 +366,7 @@ module_param_named(aspm, amdgpu_aspm, int, 0444); * Setting the value to 0 disables this functionality. * Setting the value to -2 is auto enabled with power down when displays are attached. */ -MODULE_PARM_DESC(runpm, "PX runtime pm (2 = force enable with BAMACO, 1 = force enable with BACO, 0 = disable, -1 = auto, -2 = autowith displays)"); +MODULE_PARM_DESC(runpm, "PX runtime pm (2 = force enable with BAMACO, 1 = force enable with BACO, 0 = disable, -1 = auto, -2 = auto with displays)"); module_param_named(runpm, amdgpu_runtime_pm, int, 0444); /** @@ -593,7 +593,7 @@ module_param_named(timeout_period, amdgpu_watchdog_timer.period, uint, 0644); #ifdef CONFIG_DRM_AMDGPU_SI #if IS_ENABLED(CONFIG_DRM_RADEON) || IS_ENABLED(CONFIG_DRM_RADEON_MODULE) -int amdgpu_si_support = 0; +int amdgpu_si_support; MODULE_PARM_DESC(si_support, "SI support (1 = enabled, 0 = disabled (default))"); #else int amdgpu_si_support = 1; @@ -612,7 +612,7 @@ module_param_named(si_support, amdgpu_si_support, int, 0444); #ifdef CONFIG_DRM_AMDGPU_CIK #if IS_ENABLED(CONFIG_DRM_RADEON) || IS_ENABLED(CONFIG_DRM_RADEON_MODULE) -int amdgpu_cik_support = 0; +int amdgpu_cik_support; MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled, 0 = disabled (default))"); #else int amdgpu_cik_support = 1; @@ -2255,6 +2255,10 @@ retry_init: if (ret) goto err_pci; + ret = amdgpu_amdkfd_drm_client_create(adev); + if (ret) + goto err_pci; + /* * 1. don't init fbdev on hw without DCE * 2. don't init fbdev if there are no connectors @@ -2472,6 +2476,7 @@ static int amdgpu_pmops_suspend(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(drm_dev); + adev->suspend_complete = false; if (amdgpu_acpi_is_s0ix_active(adev)) adev->in_s0ix = true; else if (amdgpu_acpi_is_s3_active(adev)) @@ -2486,6 +2491,7 @@ static int amdgpu_pmops_suspend_noirq(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(drm_dev); + adev->suspend_complete = true; if (amdgpu_acpi_should_gpu_reset(adev)) return amdgpu_asic_reset(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 73b8cca35bab8780d1938a45d035d19648bdd081..c623e23049d1d4bde50991fcddc8b542df0099b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -121,6 +121,7 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev) struct amdgpu_bo_param bp; dma_addr_t dma_addr; struct page *p; + unsigned long x; int ret; if (adev->gart.bo != NULL) @@ -130,6 +131,10 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev) if (!p) return -ENOMEM; + /* assign pages to this device */ + for (x = 0; x < (1UL << order); x++) + p[x].mapping = adev->mman.bdev.dev_mapping; + /* If the hardware does not support UTCL2 snooping of the CPU caches * then set_memory_wc() could be used as a workaround to mark the pages * as write combine memory. @@ -223,6 +228,7 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev) unsigned int order = get_order(adev->gart.table_size); struct sg_table *sg = adev->gart.bo->tbo.sg; struct page *p; + unsigned long x; int ret; ret = amdgpu_bo_reserve(adev->gart.bo, false); @@ -234,6 +240,8 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev) sg_free_table(sg); kfree(sg); p = virt_to_page(adev->gart.ptr); + for (x = 0; x < (1UL << order); x++) + p[x].mapping = NULL; __free_pages(p, order); adev->gart.ptr = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 49a5f1c73b3ecc98234654dcb452142f3aa7c564..22aeee8adb71bf8d8a076d013db062a287f23674 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -187,7 +187,34 @@ static int amdgpu_gem_object_open(struct drm_gem_object *obj, else ++bo_va->ref_count; amdgpu_bo_unreserve(abo); - return 0; + + /* Validate and add eviction fence to DMABuf imports with dynamic + * attachment in compute VMs. Re-validation will be done by + * amdgpu_vm_validate. Fences are on the reservation shared with the + * export, which is currently required to be validated and fenced + * already by amdgpu_amdkfd_gpuvm_restore_process_bos. + * + * Nested locking below for the case that a GEM object is opened in + * kfd_mem_export_dmabuf. Since the lock below is only taken for imports, + * but not for export, this is a different lock class that cannot lead to + * circular lock dependencies. + */ + if (!vm->is_compute_context || !vm->process_info) + return 0; + if (!obj->import_attach || + !dma_buf_is_dynamic(obj->import_attach->dmabuf)) + return 0; + mutex_lock_nested(&vm->process_info->lock, 1); + if (!WARN_ON(!vm->process_info->eviction_fence)) { + r = amdgpu_amdkfd_bo_validate_and_fence(abo, AMDGPU_GEM_DOMAIN_GTT, + &vm->process_info->eviction_fence->base); + if (r) + dev_warn(adev->dev, "%d: validate_and_fence failed: %d\n", + vm->task_info.pid, r); + } + mutex_unlock(&vm->process_info->lock); + + return r; } static void amdgpu_gem_object_close(struct drm_gem_object *obj, @@ -682,10 +709,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, uint64_t vm_size; int r = 0; - if (args->va_address < AMDGPU_VA_RESERVED_SIZE) { + if (args->va_address < AMDGPU_VA_RESERVED_BOTTOM) { dev_dbg(dev->dev, "va_address 0x%llx is in reserved area 0x%llx\n", - args->va_address, AMDGPU_VA_RESERVED_SIZE); + args->va_address, AMDGPU_VA_RESERVED_BOTTOM); return -EINVAL; } @@ -701,7 +728,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, args->va_address &= AMDGPU_GMC_HOLE_MASK; vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE; - vm_size -= AMDGPU_VA_RESERVED_SIZE; + vm_size -= AMDGPU_VA_RESERVED_TOP; if (args->va_address + args->map_size > vm_size) { dev_dbg(dev->dev, "va_address 0x%llx is in top reserved area 0x%llx\n", diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index b9674c57c4365fb5ebdf9644fc4ac0a31b955da8..78229b61c233f6e98ddf4427e4faa44fcfb9e19f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -329,7 +329,8 @@ int amdgpu_gfx_kiq_init_ring(struct amdgpu_device *adev, ring->eop_gpu_addr = kiq->eop_gpu_addr; ring->no_scheduler = true; - sprintf(ring->name, "kiq_%d.%d.%d.%d", xcc_id, ring->me, ring->pipe, ring->queue); + snprintf(ring->name, sizeof(ring->name), "kiq_%d.%d.%d.%d", + xcc_id, ring->me, ring->pipe, ring->queue); r = amdgpu_ring_init(adev, ring, 1024, irq, AMDGPU_CP_KIQ_IRQ_DRIVER0, AMDGPU_RING_PRIO_DEFAULT, NULL); if (r) @@ -642,8 +643,8 @@ int amdgpu_gfx_enable_kcq(struct amdgpu_device *adev, int xcc_id) kiq->pmf->kiq_set_resources(kiq_ring, queue_mask); for (i = 0; i < adev->gfx.num_compute_rings; i++) { j = i + xcc_id * adev->gfx.num_compute_rings; - kiq->pmf->kiq_map_queues(kiq_ring, - &adev->gfx.compute_ring[j]); + kiq->pmf->kiq_map_queues(kiq_ring, + &adev->gfx.compute_ring[j]); } r = amdgpu_ring_test_helper(kiq_ring); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 55784a9f26c4c83b17008a766130c234df8ecbaf..d4a848c51a83cba5cd37188b41a266af9f6835a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -52,7 +52,7 @@ int amdgpu_gmc_pdb0_alloc(struct amdgpu_device *adev) struct amdgpu_bo_param bp; u64 vram_size = adev->gmc.xgmi.node_segment_size * adev->gmc.xgmi.num_physical_nodes; uint32_t pde0_page_shift = adev->gmc.vmid0_page_table_block_size + 21; - uint32_t npdes = (vram_size + (1ULL << pde0_page_shift) -1) >> pde0_page_shift; + uint32_t npdes = (vram_size + (1ULL << pde0_page_shift) - 1) >> pde0_page_shift; memset(&bp, 0, sizeof(bp)); bp.size = PAGE_ALIGN((npdes + 1) * 8); @@ -746,6 +746,59 @@ error_unlock_reset: return r; } +void amdgpu_gmc_fw_reg_write_reg_wait(struct amdgpu_device *adev, + uint32_t reg0, uint32_t reg1, + uint32_t ref, uint32_t mask, + uint32_t xcc_inst) +{ + struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_inst]; + struct amdgpu_ring *ring = &kiq->ring; + signed long r, cnt = 0; + unsigned long flags; + uint32_t seq; + + if (adev->mes.ring.sched.ready) { + amdgpu_mes_reg_write_reg_wait(adev, reg0, reg1, + ref, mask); + return; + } + + spin_lock_irqsave(&kiq->ring_lock, flags); + amdgpu_ring_alloc(ring, 32); + amdgpu_ring_emit_reg_write_reg_wait(ring, reg0, reg1, + ref, mask); + r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); + if (r) + goto failed_undo; + + amdgpu_ring_commit(ring); + spin_unlock_irqrestore(&kiq->ring_lock, flags); + + r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); + + /* don't wait anymore for IRQ context */ + if (r < 1 && in_interrupt()) + goto failed_kiq; + + might_sleep(); + while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) { + + msleep(MAX_KIQ_REG_BAILOUT_INTERVAL); + r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); + } + + if (cnt > MAX_KIQ_REG_TRY) + goto failed_kiq; + + return; + +failed_undo: + amdgpu_ring_undo(ring); + spin_unlock_irqrestore(&kiq->ring_lock, flags); +failed_kiq: + dev_err(adev->dev, "failed to write reg %x wait reg %x\n", reg0, reg1); +} + /** * amdgpu_gmc_tmz_set -- check and set if a device supports TMZ * @adev: amdgpu_device pointer diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index e699d1ca8debd3e1d49de46a844048e67b55f23a..17f40ea1104b00bcfd1596337a2848b9dc5ef210 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -417,6 +417,10 @@ void amdgpu_gmc_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, int amdgpu_gmc_flush_gpu_tlb_pasid(struct amdgpu_device *adev, uint16_t pasid, uint32_t flush_type, bool all_hub, uint32_t inst); +void amdgpu_gmc_fw_reg_write_reg_wait(struct amdgpu_device *adev, + uint32_t reg0, uint32_t reg1, + uint32_t ref, uint32_t mask, + uint32_t xcc_inst); extern void amdgpu_gmc_tmz_set(struct amdgpu_device *adev); extern void amdgpu_gmc_noretry_set(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index ddd0891da116b9dd9de237643c0707bbf816e751..3d7fcdeaf8cf00c398784bde87a0310fe401aea6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -62,9 +62,8 @@ int amdgpu_pasid_alloc(unsigned int bits) int pasid = -EINVAL; for (bits = min(bits, 31U); bits > 0; bits--) { - pasid = ida_simple_get(&amdgpu_pasid_ida, - 1U << (bits - 1), 1U << bits, - GFP_KERNEL); + pasid = ida_alloc_range(&amdgpu_pasid_ida, 1U << (bits - 1), + (1U << bits) - 1, GFP_KERNEL); if (pasid != -ENOSPC) break; } @@ -82,7 +81,7 @@ int amdgpu_pasid_alloc(unsigned int bits) void amdgpu_pasid_free(u32 pasid) { trace_amdgpu_pasid_freed(pasid); - ida_simple_remove(&amdgpu_pasid_ida, pasid); + ida_free(&amdgpu_pasid_ida, pasid); } static void amdgpu_pasid_free_cb(struct dma_fence *fence, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index bf4f48fe438d1b5936852145c8b4c1059446381c..a2df3025a754b7cc29376b5ff65c3f9c11b8cdb9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -894,14 +894,14 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) dev_info->ids_flags |= AMDGPU_IDS_FLAGS_CONFORMANT_TRUNC_COORD; vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE; - vm_size -= AMDGPU_VA_RESERVED_SIZE; + vm_size -= AMDGPU_VA_RESERVED_TOP; /* Older VCE FW versions are buggy and can handle only 40bits */ if (adev->vce.fw_version && adev->vce.fw_version < AMDGPU_VCE_FW_53_45) vm_size = min(vm_size, 1ULL << 40); - dev_info->virtual_address_offset = AMDGPU_VA_RESERVED_SIZE; + dev_info->virtual_address_offset = AMDGPU_VA_RESERVED_BOTTOM; dev_info->virtual_address_max = min(vm_size, AMDGPU_GMC_HOLE_START); @@ -1114,6 +1114,15 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } ui32 >>= 8; break; + case AMDGPU_INFO_SENSOR_GPU_INPUT_POWER: + /* get input GPU power */ + if (amdgpu_dpm_read_sensor(adev, + AMDGPU_PP_SENSOR_GPU_INPUT_POWER, + (void *)&ui32, &ui32_size)) { + return -EINVAL; + } + ui32 >>= 8; + break; case AMDGPU_INFO_SENSOR_VDDNB: /* get VDDNB in millivolts */ if (amdgpu_dpm_read_sensor(adev, @@ -1370,6 +1379,10 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto error_vm; } + r = amdgpu_seq64_map(adev, &fpriv->vm, &fpriv->seq64_va); + if (r) + goto error_vm; + mutex_init(&fpriv->bo_list_lock); idr_init_base(&fpriv->bo_list_handles, 1); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c index 59fafb8392e0bae775e721e166aac800dfbdc98c..24ad4b97177b5cff7840cb434115f61018f09f74 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c @@ -27,6 +27,16 @@ #include "umc/umc_6_7_0_offset.h" #include "umc/umc_6_7_0_sh_mask.h" +static bool amdgpu_mca_is_deferred_error(struct amdgpu_device *adev, + uint64_t mc_status) +{ + if (adev->umc.ras->check_ecc_err_status) + return adev->umc.ras->check_ecc_err_status(adev, + AMDGPU_MCA_ERROR_TYPE_DE, &mc_status); + + return false; +} + void amdgpu_mca_query_correctable_error_count(struct amdgpu_device *adev, uint64_t mc_status_addr, unsigned long *error_count) @@ -202,16 +212,16 @@ int amdgpu_mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable) static void amdgpu_mca_smu_mca_bank_dump(struct amdgpu_device *adev, int idx, struct mca_bank_entry *entry) { - dev_info(adev->dev, "[Hardware error] Accelerator Check Architecture events logged\n"); - dev_info(adev->dev, "[Hardware error] aca entry[%02d].STATUS=0x%016llx\n", + dev_info(adev->dev, HW_ERR "Accelerator Check Architecture events logged\n"); + dev_info(adev->dev, HW_ERR "aca entry[%02d].STATUS=0x%016llx\n", idx, entry->regs[MCA_REG_IDX_STATUS]); - dev_info(adev->dev, "[Hardware error] aca entry[%02d].ADDR=0x%016llx\n", + dev_info(adev->dev, HW_ERR "aca entry[%02d].ADDR=0x%016llx\n", idx, entry->regs[MCA_REG_IDX_ADDR]); - dev_info(adev->dev, "[Hardware error] aca entry[%02d].MISC0=0x%016llx\n", + dev_info(adev->dev, HW_ERR "aca entry[%02d].MISC0=0x%016llx\n", idx, entry->regs[MCA_REG_IDX_MISC0]); - dev_info(adev->dev, "[Hardware error] aca entry[%02d].IPID=0x%016llx\n", + dev_info(adev->dev, HW_ERR "aca entry[%02d].IPID=0x%016llx\n", idx, entry->regs[MCA_REG_IDX_IPID]); - dev_info(adev->dev, "[Hardware error] aca entry[%02d].SYND=0x%016llx\n", + dev_info(adev->dev, HW_ERR "aca entry[%02d].SYND=0x%016llx\n", idx, entry->regs[MCA_REG_IDX_SYND]); } @@ -256,9 +266,14 @@ int amdgpu_mca_smu_log_ras_error(struct amdgpu_device *adev, enum amdgpu_ras_blo if (type == AMDGPU_MCA_ERROR_TYPE_UE) amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, &err_addr, (uint64_t)count); - else - amdgpu_ras_error_statistic_ce_count(err_data, - &mcm_info, &err_addr, (uint64_t)count); + else { + if (amdgpu_mca_is_deferred_error(adev, entry->regs[MCA_REG_IDX_STATUS])) + amdgpu_ras_error_statistic_de_count(err_data, + &mcm_info, &err_addr, (uint64_t)count); + else + amdgpu_ras_error_statistic_ce_count(err_data, + &mcm_info, &err_addr, (uint64_t)count); + } } out_mca_release: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h index b399f1b62887a98432a5d8a9b9ac34e913384004..b964110ed1e05e4f1a55e2659837fe1c3cb601af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h @@ -65,6 +65,7 @@ enum amdgpu_mca_ip { enum amdgpu_mca_error_type { AMDGPU_MCA_ERROR_TYPE_UE = 0, AMDGPU_MCA_ERROR_TYPE_CE, + AMDGPU_MCA_ERROR_TYPE_DE, }; struct amdgpu_mca_ras_block { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index da48b6da010725a21f9d4261bb59621a50064232..a98e03e0a51f1f741895d253f896e76de29f9aec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -1398,7 +1398,7 @@ int amdgpu_mes_self_test(struct amdgpu_device *adev) goto error_fini; } - ctx_data.meta_data_gpu_addr = AMDGPU_VA_RESERVED_SIZE; + ctx_data.meta_data_gpu_addr = AMDGPU_VA_RESERVED_BOTTOM; r = amdgpu_mes_ctx_map_meta_data(adev, vm, &ctx_data); if (r) { DRM_ERROR("failed to map ctx meta data\n"); @@ -1565,9 +1565,9 @@ void amdgpu_debugfs_mes_event_log_init(struct amdgpu_device *adev) #if defined(CONFIG_DEBUG_FS) struct drm_minor *minor = adev_to_drm(adev)->primary; struct dentry *root = minor->debugfs_root; - - debugfs_create_file("amdgpu_mes_event_log", 0444, root, - adev, &amdgpu_debugfs_mes_event_log_fops); + if (adev->enable_mes) + debugfs_create_file("amdgpu_mes_event_log", 0444, root, + adev, &amdgpu_debugfs_mes_event_log_fops); #endif } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 425cebcc5cbff76d154ccb0d5a571573cbcd4955..b671b06654923d7a1cdfe4d528bc75a91c661240 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -220,9 +220,6 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) placement->num_placement = c; placement->placement = places; - - placement->num_busy_placement = c; - placement->busy_placement = places; } /** @@ -1397,8 +1394,7 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) AMDGPU_GEM_DOMAIN_GTT); /* Avoid costly evictions; only set GTT as a busy placement */ - abo->placement.num_busy_placement = 1; - abo->placement.busy_placement = &abo->placements[1]; + abo->placements[0].flags |= TTM_PL_FLAG_DESIRED; r = ttm_bo_validate(bo, &abo->placement, &ctx); if (unlikely(r == -EBUSY || r == -ERESTARTSYS)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 0328616473f80af861cd4a1176afc0221eee7db9..d9e5eb24341d3857508b05bf0cd92bc539f45b33 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -291,21 +291,22 @@ static int psp_memory_training_init(struct psp_context *psp) struct psp_memory_training_context *ctx = &psp->mem_train_ctx; if (ctx->init != PSP_MEM_TRAIN_RESERVE_SUCCESS) { - DRM_DEBUG("memory training is not supported!\n"); + dev_dbg(psp->adev->dev, "memory training is not supported!\n"); return 0; } ctx->sys_cache = kzalloc(ctx->train_data_size, GFP_KERNEL); if (ctx->sys_cache == NULL) { - DRM_ERROR("alloc mem_train_ctx.sys_cache failed!\n"); + dev_err(psp->adev->dev, "alloc mem_train_ctx.sys_cache failed!\n"); ret = -ENOMEM; goto Err_out; } - DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n", - ctx->train_data_size, - ctx->p2c_train_data_offset, - ctx->c2p_train_data_offset); + dev_dbg(psp->adev->dev, + "train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n", + ctx->train_data_size, + ctx->p2c_train_data_offset, + ctx->c2p_train_data_offset); ctx->init = PSP_MEM_TRAIN_INIT_SUCCESS; return 0; @@ -407,7 +408,7 @@ static int psp_sw_init(void *handle) psp->cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); if (!psp->cmd) { - DRM_ERROR("Failed to allocate memory to command buffer!\n"); + dev_err(adev->dev, "Failed to allocate memory to command buffer!\n"); ret = -ENOMEM; } @@ -454,13 +455,13 @@ static int psp_sw_init(void *handle) if (mem_training_ctx->enable_mem_training) { ret = psp_memory_training_init(psp); if (ret) { - DRM_ERROR("Failed to initialize memory training!\n"); + dev_err(adev->dev, "Failed to initialize memory training!\n"); return ret; } ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT); if (ret) { - DRM_ERROR("Failed to process memory training!\n"); + dev_err(adev->dev, "Failed to process memory training!\n"); return ret; } } @@ -675,9 +676,11 @@ psp_cmd_submit_buf(struct psp_context *psp, */ if (!skip_unsupport && (psp->cmd_buf_mem->resp.status || !timeout) && !ras_intr) { if (ucode) - DRM_WARN("failed to load ucode %s(0x%X) ", - amdgpu_ucode_name(ucode->ucode_id), ucode->ucode_id); - DRM_WARN("psp gfx command %s(0x%X) failed and response status is (0x%X)\n", + dev_warn(psp->adev->dev, + "failed to load ucode %s(0x%X) ", + amdgpu_ucode_name(ucode->ucode_id), ucode->ucode_id); + dev_warn(psp->adev->dev, + "psp gfx command %s(0x%X) failed and response status is (0x%X)\n", psp_gfx_cmd_name(psp->cmd_buf_mem->cmd_id), psp->cmd_buf_mem->cmd_id, psp->cmd_buf_mem->resp.status); /* If any firmware (including CAP) load fails under SRIOV, it should @@ -807,7 +810,7 @@ static int psp_tmr_init(struct psp_context *psp) psp->fw_pri_buf) { ret = psp_load_toc(psp, &tmr_size); if (ret) { - DRM_ERROR("Failed to load toc\n"); + dev_err(psp->adev->dev, "Failed to load toc\n"); return ret; } } @@ -855,7 +858,7 @@ static int psp_tmr_load(struct psp_context *psp) psp_prep_tmr_cmd_buf(psp, cmd, psp->tmr_mc_addr, psp->tmr_bo); if (psp->tmr_bo) - DRM_INFO("reserve 0x%lx from 0x%llx for PSP TMR\n", + dev_info(psp->adev->dev, "reserve 0x%lx from 0x%llx for PSP TMR\n", amdgpu_bo_size(psp->tmr_bo), psp->tmr_mc_addr); ret = psp_cmd_submit_buf(psp, NULL, cmd, @@ -1113,7 +1116,7 @@ int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg, psp_prep_reg_prog_cmd_buf(cmd, reg, value); ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); if (ret) - DRM_ERROR("PSP failed to program reg id %d", reg); + dev_err(psp->adev->dev, "PSP failed to program reg id %d\n", reg); release_psp_cmd_buf(psp); @@ -1526,22 +1529,22 @@ static void psp_ras_ta_check_status(struct psp_context *psp) switch (ras_cmd->ras_status) { case TA_RAS_STATUS__ERROR_UNSUPPORTED_IP: dev_warn(psp->adev->dev, - "RAS WARNING: cmd failed due to unsupported ip\n"); + "RAS WARNING: cmd failed due to unsupported ip\n"); break; case TA_RAS_STATUS__ERROR_UNSUPPORTED_ERROR_INJ: dev_warn(psp->adev->dev, - "RAS WARNING: cmd failed due to unsupported error injection\n"); + "RAS WARNING: cmd failed due to unsupported error injection\n"); break; case TA_RAS_STATUS__SUCCESS: break; case TA_RAS_STATUS__TEE_ERROR_ACCESS_DENIED: if (ras_cmd->cmd_id == TA_RAS_COMMAND__TRIGGER_ERROR) dev_warn(psp->adev->dev, - "RAS WARNING: Inject error to critical region is not allowed\n"); + "RAS WARNING: Inject error to critical region is not allowed\n"); break; default: dev_warn(psp->adev->dev, - "RAS WARNING: ras status = 0x%X\n", ras_cmd->ras_status); + "RAS WARNING: ras status = 0x%X\n", ras_cmd->ras_status); break; } } @@ -1565,7 +1568,7 @@ int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id) return ret; if (ras_cmd->if_version > RAS_TA_HOST_IF_VER) { - DRM_WARN("RAS: Unsupported Interface"); + dev_warn(psp->adev->dev, "RAS: Unsupported Interface\n"); return -EINVAL; } @@ -1715,7 +1718,7 @@ int psp_ras_initialize(struct psp_context *psp) psp->ras_context.context.initialized = true; else { if (ras_cmd->ras_status) - dev_warn(psp->adev->dev, "RAS Init Status: 0x%X\n", ras_cmd->ras_status); + dev_warn(adev->dev, "RAS Init Status: 0x%X\n", ras_cmd->ras_status); /* fail to load RAS TA */ psp->ras_context.context.initialized = false; @@ -1779,6 +1782,31 @@ int psp_ras_trigger_error(struct psp_context *psp, return 0; } + +int psp_ras_query_address(struct psp_context *psp, + struct ta_ras_query_address_input *addr_in, + struct ta_ras_query_address_output *addr_out) +{ + struct ta_ras_shared_memory *ras_cmd; + int ret; + + if (!psp->ras_context.context.initialized) + return -EINVAL; + + ras_cmd = (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf; + memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory)); + + ras_cmd->cmd_id = TA_RAS_COMMAND__QUERY_ADDRESS; + ras_cmd->ras_in_message.address = *addr_in; + + ret = psp_ras_invoke(psp, ras_cmd->cmd_id); + if (ret || ras_cmd->ras_status || psp->cmd_buf_mem->resp.status) + return -EINVAL; + + *addr_out = ras_cmd->ras_out_message.address; + + return 0; +} // ras end // HDCP start @@ -2125,19 +2153,14 @@ int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev) return ret; } -int amdgpu_psp_query_boot_status(struct amdgpu_device *adev) +bool amdgpu_psp_get_ras_capability(struct psp_context *psp) { - struct psp_context *psp = &adev->psp; - int ret = 0; - - if (amdgpu_sriov_vf(adev) || (adev->flags & AMD_IS_APU)) - return 0; - if (psp->funcs && - psp->funcs->query_boot_status) - ret = psp->funcs->query_boot_status(psp); - - return ret; + psp->funcs->get_ras_capability) { + return psp->funcs->get_ras_capability(psp); + } else { + return false; + } } static int psp_hw_start(struct psp_context *psp) @@ -2150,7 +2173,7 @@ static int psp_hw_start(struct psp_context *psp) (psp->funcs->bootloader_load_kdb != NULL)) { ret = psp_bootloader_load_kdb(psp); if (ret) { - DRM_ERROR("PSP load kdb failed!\n"); + dev_err(adev->dev, "PSP load kdb failed!\n"); return ret; } } @@ -2159,7 +2182,7 @@ static int psp_hw_start(struct psp_context *psp) (psp->funcs->bootloader_load_spl != NULL)) { ret = psp_bootloader_load_spl(psp); if (ret) { - DRM_ERROR("PSP load spl failed!\n"); + dev_err(adev->dev, "PSP load spl failed!\n"); return ret; } } @@ -2168,7 +2191,7 @@ static int psp_hw_start(struct psp_context *psp) (psp->funcs->bootloader_load_sysdrv != NULL)) { ret = psp_bootloader_load_sysdrv(psp); if (ret) { - DRM_ERROR("PSP load sys drv failed!\n"); + dev_err(adev->dev, "PSP load sys drv failed!\n"); return ret; } } @@ -2177,7 +2200,7 @@ static int psp_hw_start(struct psp_context *psp) (psp->funcs->bootloader_load_soc_drv != NULL)) { ret = psp_bootloader_load_soc_drv(psp); if (ret) { - DRM_ERROR("PSP load soc drv failed!\n"); + dev_err(adev->dev, "PSP load soc drv failed!\n"); return ret; } } @@ -2186,7 +2209,7 @@ static int psp_hw_start(struct psp_context *psp) (psp->funcs->bootloader_load_intf_drv != NULL)) { ret = psp_bootloader_load_intf_drv(psp); if (ret) { - DRM_ERROR("PSP load intf drv failed!\n"); + dev_err(adev->dev, "PSP load intf drv failed!\n"); return ret; } } @@ -2195,7 +2218,7 @@ static int psp_hw_start(struct psp_context *psp) (psp->funcs->bootloader_load_dbg_drv != NULL)) { ret = psp_bootloader_load_dbg_drv(psp); if (ret) { - DRM_ERROR("PSP load dbg drv failed!\n"); + dev_err(adev->dev, "PSP load dbg drv failed!\n"); return ret; } } @@ -2204,7 +2227,7 @@ static int psp_hw_start(struct psp_context *psp) (psp->funcs->bootloader_load_ras_drv != NULL)) { ret = psp_bootloader_load_ras_drv(psp); if (ret) { - DRM_ERROR("PSP load ras_drv failed!\n"); + dev_err(adev->dev, "PSP load ras_drv failed!\n"); return ret; } } @@ -2213,7 +2236,7 @@ static int psp_hw_start(struct psp_context *psp) (psp->funcs->bootloader_load_sos != NULL)) { ret = psp_bootloader_load_sos(psp); if (ret) { - DRM_ERROR("PSP load sos failed!\n"); + dev_err(adev->dev, "PSP load sos failed!\n"); return ret; } } @@ -2221,7 +2244,7 @@ static int psp_hw_start(struct psp_context *psp) ret = psp_ring_create(psp, PSP_RING_TYPE__KM); if (ret) { - DRM_ERROR("PSP create ring failed!\n"); + dev_err(adev->dev, "PSP create ring failed!\n"); return ret; } @@ -2231,7 +2254,7 @@ static int psp_hw_start(struct psp_context *psp) if (!psp_boottime_tmr(psp)) { ret = psp_tmr_init(psp); if (ret) { - DRM_ERROR("PSP tmr init failed!\n"); + dev_err(adev->dev, "PSP tmr init failed!\n"); return ret; } } @@ -2250,7 +2273,7 @@ skip_pin_bo: ret = psp_tmr_load(psp); if (ret) { - DRM_ERROR("PSP load tmr failed!\n"); + dev_err(adev->dev, "PSP load tmr failed!\n"); return ret; } @@ -2518,7 +2541,8 @@ static void psp_print_fw_hdr(struct psp_context *psp, } } -static int psp_prep_load_ip_fw_cmd_buf(struct amdgpu_firmware_info *ucode, +static int psp_prep_load_ip_fw_cmd_buf(struct psp_context *psp, + struct amdgpu_firmware_info *ucode, struct psp_gfx_cmd_resp *cmd) { int ret; @@ -2531,7 +2555,7 @@ static int psp_prep_load_ip_fw_cmd_buf(struct amdgpu_firmware_info *ucode, ret = psp_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type); if (ret) - DRM_ERROR("Unknown firmware type\n"); + dev_err(psp->adev->dev, "Unknown firmware type\n"); return ret; } @@ -2542,7 +2566,7 @@ int psp_execute_ip_fw_load(struct psp_context *psp, int ret = 0; struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp); - ret = psp_prep_load_ip_fw_cmd_buf(ucode, cmd); + ret = psp_prep_load_ip_fw_cmd_buf(psp, ucode, cmd); if (!ret) { ret = psp_cmd_submit_buf(psp, ucode, cmd, psp->fence_buf_mc_addr); @@ -2601,13 +2625,13 @@ static int psp_load_smu_fw(struct psp_context *psp) amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(11, 0, 2)))) { ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD); if (ret) - DRM_WARN("Failed to set MP1 state prepare for reload\n"); + dev_err(adev->dev, "Failed to set MP1 state prepare for reload\n"); } ret = psp_execute_ip_fw_load(psp, ucode); if (ret) - DRM_ERROR("PSP load smu failed!\n"); + dev_err(adev->dev, "PSP load smu failed!\n"); return ret; } @@ -2712,7 +2736,7 @@ static int psp_load_non_psp_fw(struct psp_context *psp) adev->virt.autoload_ucode_id : AMDGPU_UCODE_ID_RLC_G)) { ret = psp_rlc_autoload_start(psp); if (ret) { - DRM_ERROR("Failed to start rlc autoload\n"); + dev_err(adev->dev, "Failed to start rlc autoload\n"); return ret; } } @@ -2734,7 +2758,7 @@ static int psp_load_fw(struct amdgpu_device *adev) ret = psp_ring_init(psp, PSP_RING_TYPE__KM); if (ret) { - DRM_ERROR("PSP ring init failed!\n"); + dev_err(adev->dev, "PSP ring init failed!\n"); goto failed; } } @@ -2749,13 +2773,13 @@ static int psp_load_fw(struct amdgpu_device *adev) ret = psp_asd_initialize(psp); if (ret) { - DRM_ERROR("PSP load asd failed!\n"); + dev_err(adev->dev, "PSP load asd failed!\n"); goto failed1; } ret = psp_rl_load(adev); if (ret) { - DRM_ERROR("PSP load RL failed!\n"); + dev_err(adev->dev, "PSP load RL failed!\n"); goto failed1; } @@ -2775,7 +2799,7 @@ static int psp_load_fw(struct amdgpu_device *adev) ret = psp_ras_initialize(psp); if (ret) dev_err(psp->adev->dev, - "RAS: Failed to initialize RAS\n"); + "RAS: Failed to initialize RAS\n"); ret = psp_hdcp_initialize(psp); if (ret) @@ -2828,7 +2852,7 @@ static int psp_hw_init(void *handle) ret = psp_load_fw(adev); if (ret) { - DRM_ERROR("PSP firmware loading failed\n"); + dev_err(adev->dev, "PSP firmware loading failed\n"); goto failed; } @@ -2875,7 +2899,7 @@ static int psp_suspend(void *handle) psp->xgmi_context.context.initialized) { ret = psp_xgmi_terminate(psp); if (ret) { - DRM_ERROR("Failed to terminate xgmi ta\n"); + dev_err(adev->dev, "Failed to terminate xgmi ta\n"); goto out; } } @@ -2883,46 +2907,46 @@ static int psp_suspend(void *handle) if (psp->ta_fw) { ret = psp_ras_terminate(psp); if (ret) { - DRM_ERROR("Failed to terminate ras ta\n"); + dev_err(adev->dev, "Failed to terminate ras ta\n"); goto out; } ret = psp_hdcp_terminate(psp); if (ret) { - DRM_ERROR("Failed to terminate hdcp ta\n"); + dev_err(adev->dev, "Failed to terminate hdcp ta\n"); goto out; } ret = psp_dtm_terminate(psp); if (ret) { - DRM_ERROR("Failed to terminate dtm ta\n"); + dev_err(adev->dev, "Failed to terminate dtm ta\n"); goto out; } ret = psp_rap_terminate(psp); if (ret) { - DRM_ERROR("Failed to terminate rap ta\n"); + dev_err(adev->dev, "Failed to terminate rap ta\n"); goto out; } ret = psp_securedisplay_terminate(psp); if (ret) { - DRM_ERROR("Failed to terminate securedisplay ta\n"); + dev_err(adev->dev, "Failed to terminate securedisplay ta\n"); goto out; } } ret = psp_asd_terminate(psp); if (ret) { - DRM_ERROR("Failed to terminate asd\n"); + dev_err(adev->dev, "Failed to terminate asd\n"); goto out; } ret = psp_tmr_terminate(psp); if (ret) { - DRM_ERROR("Failed to terminate tmr\n"); + dev_err(adev->dev, "Failed to terminate tmr\n"); goto out; } ret = psp_ring_stop(psp, PSP_RING_TYPE__KM); if (ret) - DRM_ERROR("PSP ring stop failed\n"); + dev_err(adev->dev, "PSP ring stop failed\n"); out: return ret; @@ -2934,12 +2958,12 @@ static int psp_resume(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct psp_context *psp = &adev->psp; - DRM_INFO("PSP is resuming...\n"); + dev_info(adev->dev, "PSP is resuming...\n"); if (psp->mem_train_ctx.enable_mem_training) { ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME); if (ret) { - DRM_ERROR("Failed to process memory training!\n"); + dev_err(adev->dev, "Failed to process memory training!\n"); return ret; } } @@ -2956,7 +2980,7 @@ static int psp_resume(void *handle) ret = psp_asd_initialize(psp); if (ret) { - DRM_ERROR("PSP load asd failed!\n"); + dev_err(adev->dev, "PSP load asd failed!\n"); goto failed; } @@ -2980,7 +3004,7 @@ static int psp_resume(void *handle) ret = psp_ras_initialize(psp); if (ret) dev_err(psp->adev->dev, - "RAS: Failed to initialize RAS\n"); + "RAS: Failed to initialize RAS\n"); ret = psp_hdcp_initialize(psp); if (ret) @@ -3008,7 +3032,7 @@ static int psp_resume(void *handle) return 0; failed: - DRM_ERROR("PSP resume failed\n"); + dev_err(adev->dev, "PSP resume failed\n"); mutex_unlock(&adev->firmware.mutex); return ret; } @@ -3069,9 +3093,11 @@ int psp_ring_cmd_submit(struct psp_context *psp, write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); /* Check invalid write_frame ptr address */ if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { - DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", - ring_buffer_start, ring_buffer_end, write_frame); - DRM_ERROR("write_frame is pointing to address out of bounds\n"); + dev_err(adev->dev, + "ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", + ring_buffer_start, ring_buffer_end, write_frame); + dev_err(adev->dev, + "write_frame is pointing to address out of bounds\n"); return -EINVAL; } @@ -3597,7 +3623,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev, int ret; if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) { - DRM_INFO("PSP block is not ready yet."); + dev_info(adev->dev, "PSP block is not ready yet\n."); return -EBUSY; } @@ -3606,7 +3632,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev, mutex_unlock(&adev->psp.mutex); if (ret) { - DRM_ERROR("Failed to read USBC PD FW, err = %d", ret); + dev_err(adev->dev, "Failed to read USBC PD FW, err = %d\n", ret); return ret; } @@ -3628,7 +3654,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, void *fw_pri_cpu_addr; if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) { - DRM_INFO("PSP block is not ready yet."); + dev_err(adev->dev, "PSP block is not ready yet."); return -EBUSY; } @@ -3661,7 +3687,7 @@ rel_buf: release_firmware(usbc_pd_fw); fail: if (ret) { - DRM_ERROR("Failed to load USBC PD FW, err = %d", ret); + dev_err(adev->dev, "Failed to load USBC PD FW, err = %d", ret); count = ret; } @@ -3708,7 +3734,7 @@ static ssize_t amdgpu_psp_vbflash_write(struct file *filp, struct kobject *kobj, /* Safeguard against memory drain */ if (adev->psp.vbflash_image_size > AMD_VBIOS_FILE_MAX_SIZE_B) { - dev_err(adev->dev, "File size cannot exceed %u", AMD_VBIOS_FILE_MAX_SIZE_B); + dev_err(adev->dev, "File size cannot exceed %u\n", AMD_VBIOS_FILE_MAX_SIZE_B); kvfree(adev->psp.vbflash_tmp_buf); adev->psp.vbflash_tmp_buf = NULL; adev->psp.vbflash_image_size = 0; @@ -3727,7 +3753,7 @@ static ssize_t amdgpu_psp_vbflash_write(struct file *filp, struct kobject *kobj, adev->psp.vbflash_image_size += count; mutex_unlock(&adev->psp.mutex); - dev_dbg(adev->dev, "IFWI staged for update"); + dev_dbg(adev->dev, "IFWI staged for update\n"); return count; } @@ -3747,7 +3773,7 @@ static ssize_t amdgpu_psp_vbflash_read(struct file *filp, struct kobject *kobj, if (adev->psp.vbflash_image_size == 0) return -EINVAL; - dev_dbg(adev->dev, "PSP IFWI flash process initiated"); + dev_dbg(adev->dev, "PSP IFWI flash process initiated\n"); ret = amdgpu_bo_create_kernel(adev, adev->psp.vbflash_image_size, AMDGPU_GPU_PAGE_SIZE, @@ -3772,11 +3798,11 @@ rel_buf: adev->psp.vbflash_image_size = 0; if (ret) { - dev_err(adev->dev, "Failed to load IFWI, err = %d", ret); + dev_err(adev->dev, "Failed to load IFWI, err = %d\n", ret); return ret; } - dev_dbg(adev->dev, "PSP IFWI flash process done"); + dev_dbg(adev->dev, "PSP IFWI flash process done\n"); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index c4d9cbde55b9bc58799aa1acc9fe4eea29d1a98a..9951bdd022dedd2a57d4d659cd7cef68f69539e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -134,7 +134,7 @@ struct psp_funcs { int (*update_spirom)(struct psp_context *psp, uint64_t fw_pri_mc_addr); int (*vbflash_stat)(struct psp_context *psp); int (*fatal_error_recovery_quirk)(struct psp_context *psp); - int (*query_boot_status)(struct psp_context *psp); + bool (*get_ras_capability)(struct psp_context *psp); }; struct ta_funcs { @@ -502,6 +502,9 @@ int psp_ras_enable_features(struct psp_context *psp, int psp_ras_trigger_error(struct psp_context *psp, struct ta_ras_trigger_error_input *info, uint32_t instance_mask); int psp_ras_terminate(struct psp_context *psp); +int psp_ras_query_address(struct psp_context *psp, + struct ta_ras_query_address_input *addr_in, + struct ta_ras_query_address_output *addr_out); int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id); int psp_dtm_invoke(struct psp_context *psp, uint32_t ta_cmd_id); @@ -538,7 +541,5 @@ int psp_spatial_partition(struct psp_context *psp, int mode); int is_psp_fw_valid(struct psp_bin_desc bin); int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev); - -int amdgpu_psp_query_boot_status(struct amdgpu_device *adev); - +bool amdgpu_psp_get_ras_capability(struct psp_context *psp); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c index 468a67b302d4c140c9d7cf09bc92566404180e75..ca5c86e5f7cd671a651d61357ab52d3c53a1e7f3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c @@ -362,7 +362,7 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size } } - if (copy_to_user((char *)buf, context->mem_context.shared_buf, shared_buf_len)) + if (copy_to_user((char *)&buf[copy_pos], context->mem_context.shared_buf, shared_buf_len)) ret = -EFAULT; err_free_shared_buf: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 31823a30dea217b5af3a8a36624a01fab70b48a5..46f3d1013e8ced2183a5c6ac4c2dc6f8ebef1932 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -39,6 +39,7 @@ #include "nbio_v7_9.h" #include "atom.h" #include "amdgpu_reset.h" +#include "amdgpu_psp.h" #ifdef CONFIG_X86_MCE_AMD #include @@ -73,6 +74,8 @@ const char *ras_block_string[] = { "mca", "vcn", "jpeg", + "ih", + "mpio", }; const char *ras_mca_block_string[] = { @@ -94,7 +97,8 @@ const char *get_ras_block_str(struct ras_common_if *ras_block) if (!ras_block) return "NULL"; - if (ras_block->block >= AMDGPU_RAS_BLOCK_COUNT) + if (ras_block->block >= AMDGPU_RAS_BLOCK_COUNT || + ras_block->block >= ARRAY_SIZE(ras_block_string)) return "OUT OF RANGE"; if (ras_block->block == AMDGPU_RAS_BLOCK__MCA) @@ -116,6 +120,8 @@ const char *get_ras_block_str(struct ras_common_if *ras_block) /* typical ECC bad page rate is 1 bad page per 100MB VRAM */ #define RAS_BAD_PAGE_COVER (100 * 1024 * 1024ULL) +#define MAX_UMC_POISON_POLLING_TIME_ASYNC 100 //ms + enum amdgpu_ras_retire_page_reservation { AMDGPU_RAS_RETIRE_PAGE_RESERVED, AMDGPU_RAS_RETIRE_PAGE_PENDING, @@ -628,8 +634,12 @@ static ssize_t amdgpu_ras_sysfs_read(struct device *dev, dev_warn(obj->adev->dev, "Failed to reset error counter and error status"); } - return sysfs_emit(buf, "%s: %lu\n%s: %lu\n", "ue", info.ue_count, - "ce", info.ce_count); + if (info.head.block == AMDGPU_RAS_BLOCK__UMC) + return sysfs_emit(buf, "%s: %lu\n%s: %lu\n%s: %lu\n", "ue", info.ue_count, + "ce", info.ce_count, "de", info.de_count); + else + return sysfs_emit(buf, "%s: %lu\n%s: %lu\n", "ue", info.ue_count, + "ce", info.ce_count); } /* obj begin */ @@ -1036,7 +1046,8 @@ static void amdgpu_ras_error_print_error_data(struct amdgpu_device *adev, struct ras_manager *ras_mgr, struct ras_err_data *err_data, const char *blk_name, - bool is_ue) + bool is_ue, + bool is_de) { struct amdgpu_smuio_mcm_config_info *mcm_info; struct ras_err_node *err_node; @@ -1065,25 +1076,50 @@ static void amdgpu_ras_error_print_error_data(struct amdgpu_device *adev, } } else { - for_each_ras_error(err_node, err_data) { - err_info = &err_node->err_info; - mcm_info = &err_info->mcm_info; - if (err_info->ce_count) { + if (is_de) { + for_each_ras_error(err_node, err_data) { + err_info = &err_node->err_info; + mcm_info = &err_info->mcm_info; + if (err_info->de_count) { + dev_info(adev->dev, "socket: %d, die: %d, " + "%lld new deferred hardware errors detected in %s block\n", + mcm_info->socket_id, + mcm_info->die_id, + err_info->de_count, + blk_name); + } + } + + for_each_ras_error(err_node, &ras_mgr->err_data) { + err_info = &err_node->err_info; + mcm_info = &err_info->mcm_info; dev_info(adev->dev, "socket: %d, die: %d, " - "%lld new correctable hardware errors detected in %s block\n", - mcm_info->socket_id, - mcm_info->die_id, - err_info->ce_count, - blk_name); + "%lld deferred hardware errors detected in total in %s block\n", + mcm_info->socket_id, mcm_info->die_id, + err_info->de_count, blk_name); + } + } else { + for_each_ras_error(err_node, err_data) { + err_info = &err_node->err_info; + mcm_info = &err_info->mcm_info; + if (err_info->ce_count) { + dev_info(adev->dev, "socket: %d, die: %d, " + "%lld new correctable hardware errors detected in %s block\n", + mcm_info->socket_id, + mcm_info->die_id, + err_info->ce_count, + blk_name); + } } - } - for_each_ras_error(err_node, &ras_mgr->err_data) { - err_info = &err_node->err_info; - mcm_info = &err_info->mcm_info; - dev_info(adev->dev, "socket: %d, die: %d, " - "%lld correctable hardware errors detected in total in %s block\n", - mcm_info->socket_id, mcm_info->die_id, err_info->ce_count, blk_name); + for_each_ras_error(err_node, &ras_mgr->err_data) { + err_info = &err_node->err_info; + mcm_info = &err_info->mcm_info; + dev_info(adev->dev, "socket: %d, die: %d, " + "%lld correctable hardware errors detected in total in %s block\n", + mcm_info->socket_id, mcm_info->die_id, + err_info->ce_count, blk_name); + } } } } @@ -1102,7 +1138,8 @@ static void amdgpu_ras_error_generate_report(struct amdgpu_device *adev, if (err_data->ce_count) { if (err_data_has_source_info(err_data)) { - amdgpu_ras_error_print_error_data(adev, ras_mgr, err_data, blk_name, false); + amdgpu_ras_error_print_error_data(adev, ras_mgr, err_data, + blk_name, false, false); } else if (!adev->aid_mask && adev->smuio.funcs && adev->smuio.funcs->get_socket_id && @@ -1124,7 +1161,8 @@ static void amdgpu_ras_error_generate_report(struct amdgpu_device *adev, if (err_data->ue_count) { if (err_data_has_source_info(err_data)) { - amdgpu_ras_error_print_error_data(adev, ras_mgr, err_data, blk_name, true); + amdgpu_ras_error_print_error_data(adev, ras_mgr, err_data, + blk_name, true, false); } else if (!adev->aid_mask && adev->smuio.funcs && adev->smuio.funcs->get_socket_id && @@ -1144,6 +1182,28 @@ static void amdgpu_ras_error_generate_report(struct amdgpu_device *adev, } } + if (err_data->de_count) { + if (err_data_has_source_info(err_data)) { + amdgpu_ras_error_print_error_data(adev, ras_mgr, err_data, + blk_name, false, true); + } else if (!adev->aid_mask && + adev->smuio.funcs && + adev->smuio.funcs->get_socket_id && + adev->smuio.funcs->get_die_id) { + dev_info(adev->dev, "socket: %d, die: %d " + "%ld deferred hardware errors " + "detected in %s block\n", + adev->smuio.funcs->get_socket_id(adev), + adev->smuio.funcs->get_die_id(adev), + ras_mgr->err_data.de_count, + blk_name); + } else { + dev_info(adev->dev, "%ld deferred hardware errors " + "detected in %s block\n", + ras_mgr->err_data.de_count, + blk_name); + } + } } static void amdgpu_rasmgr_error_data_statistic_update(struct ras_manager *obj, struct ras_err_data *err_data) @@ -1154,7 +1214,8 @@ static void amdgpu_rasmgr_error_data_statistic_update(struct ras_manager *obj, s if (err_data_has_source_info(err_data)) { for_each_ras_error(err_node, err_data) { err_info = &err_node->err_info; - + amdgpu_ras_error_statistic_de_count(&obj->err_data, + &err_info->mcm_info, NULL, err_info->de_count); amdgpu_ras_error_statistic_ce_count(&obj->err_data, &err_info->mcm_info, NULL, err_info->ce_count); amdgpu_ras_error_statistic_ue_count(&obj->err_data, @@ -1164,9 +1225,72 @@ static void amdgpu_rasmgr_error_data_statistic_update(struct ras_manager *obj, s /* for legacy asic path which doesn't has error source info */ obj->err_data.ue_count += err_data->ue_count; obj->err_data.ce_count += err_data->ce_count; + obj->err_data.de_count += err_data->de_count; } } +static struct ras_manager *get_ras_manager(struct amdgpu_device *adev, enum amdgpu_ras_block blk) +{ + struct ras_common_if head; + + memset(&head, 0, sizeof(head)); + head.block = blk; + + return amdgpu_ras_find_obj(adev, &head); +} + +int amdgpu_ras_bind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk, + const struct aca_info *aca_info, void *data) +{ + struct ras_manager *obj; + + obj = get_ras_manager(adev, blk); + if (!obj) + return -EINVAL; + + return amdgpu_aca_add_handle(adev, &obj->aca_handle, ras_block_str(blk), aca_info, data); +} + +int amdgpu_ras_unbind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk) +{ + struct ras_manager *obj; + + obj = get_ras_manager(adev, blk); + if (!obj) + return -EINVAL; + + amdgpu_aca_remove_handle(&obj->aca_handle); + + return 0; +} + +static int amdgpu_aca_log_ras_error_data(struct amdgpu_device *adev, enum amdgpu_ras_block blk, + enum aca_error_type type, struct ras_err_data *err_data) +{ + struct ras_manager *obj; + + obj = get_ras_manager(adev, blk); + if (!obj) + return -EINVAL; + + return amdgpu_aca_get_error_data(adev, &obj->aca_handle, type, err_data); +} + +ssize_t amdgpu_ras_aca_sysfs_read(struct device *dev, struct device_attribute *attr, + struct aca_handle *handle, char *buf, void *data) +{ + struct ras_manager *obj = container_of(handle, struct ras_manager, aca_handle); + struct ras_query_if info = { + .head = obj->head, + }; + + if (amdgpu_ras_query_error_status(obj->adev, &info)) + return -EINVAL; + + return sysfs_emit(buf, "%s: %lu\n%s: %lu\n", "ue", info.ue_count, + "ce", info.ce_count); +} + static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, struct ras_query_if *info, struct ras_err_data *err_data, @@ -1174,6 +1298,7 @@ static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, { enum amdgpu_ras_block blk = info ? info->head.block : AMDGPU_RAS_BLOCK_COUNT; struct amdgpu_ras_block_object *block_obj = NULL; + int ret; if (blk == AMDGPU_RAS_BLOCK_COUNT) return -EINVAL; @@ -1203,9 +1328,19 @@ static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, } } } else { - /* FIXME: add code to check return value later */ - amdgpu_mca_smu_log_ras_error(adev, blk, AMDGPU_MCA_ERROR_TYPE_UE, err_data); - amdgpu_mca_smu_log_ras_error(adev, blk, AMDGPU_MCA_ERROR_TYPE_CE, err_data); + if (amdgpu_aca_is_enabled(adev)) { + ret = amdgpu_aca_log_ras_error_data(adev, blk, ACA_ERROR_TYPE_UE, err_data); + if (ret) + return ret; + + ret = amdgpu_aca_log_ras_error_data(adev, blk, ACA_ERROR_TYPE_CE, err_data); + if (ret) + return ret; + } else { + /* FIXME: add code to check return value later */ + amdgpu_mca_smu_log_ras_error(adev, blk, AMDGPU_MCA_ERROR_TYPE_UE, err_data); + amdgpu_mca_smu_log_ras_error(adev, blk, AMDGPU_MCA_ERROR_TYPE_CE, err_data); + } } return 0; @@ -1239,6 +1374,7 @@ int amdgpu_ras_query_error_status(struct amdgpu_device *adev, struct ras_query_i info->ue_count = obj->err_data.ue_count; info->ce_count = obj->err_data.ce_count; + info->de_count = obj->err_data.de_count; amdgpu_ras_error_generate_report(adev, info, &err_data); @@ -1254,6 +1390,7 @@ int amdgpu_ras_reset_error_count(struct amdgpu_device *adev, struct amdgpu_ras_block_object *block_obj = amdgpu_ras_get_ras_block(adev, block, 0); struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; + const struct aca_smu_funcs *smu_funcs = adev->aca.smu_funcs; struct amdgpu_hive_info *hive; int hive_ras_recovery = 0; @@ -1264,7 +1401,7 @@ int amdgpu_ras_reset_error_count(struct amdgpu_device *adev, } if (!amdgpu_ras_is_supported(adev, block) || - !amdgpu_ras_get_mca_debug_mode(adev)) + !amdgpu_ras_get_aca_debug_mode(adev)) return -EOPNOTSUPP; hive = amdgpu_get_xgmi_hive(adev); @@ -1276,7 +1413,8 @@ int amdgpu_ras_reset_error_count(struct amdgpu_device *adev, /* skip ras error reset in gpu reset */ if ((amdgpu_in_reset(adev) || atomic_read(&ras->in_recovery) || hive_ras_recovery) && - mca_funcs && mca_funcs->mca_set_debug_mode) + ((smu_funcs && smu_funcs->set_debug_mode) || + (mca_funcs && mca_funcs->mca_set_debug_mode))) return -EOPNOTSUPP; if (block_obj->hw_ops->reset_ras_error_count) @@ -1772,7 +1910,10 @@ void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev) } } - amdgpu_mca_smu_debugfs_init(adev, dir); + if (amdgpu_aca_is_enabled(adev)) + amdgpu_aca_smu_debugfs_init(adev, dir); + else + amdgpu_mca_smu_debugfs_init(adev, dir); } /* debugfs end */ @@ -1900,7 +2041,7 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager * } } - amdgpu_umc_poison_handler(adev, false); + amdgpu_umc_poison_handler(adev, obj->head.block, false); if (block_obj->hw_ops && block_obj->hw_ops->handle_poison_consumption) poison_stat = block_obj->hw_ops->handle_poison_consumption(adev); @@ -1951,6 +2092,7 @@ static void amdgpu_ras_interrupt_umc_handler(struct ras_manager *obj, */ obj->err_data.ue_count += err_data.ue_count; obj->err_data.ce_count += err_data.ce_count; + obj->err_data.de_count += err_data.de_count; } amdgpu_ras_error_data_fini(&err_data); @@ -2520,6 +2662,32 @@ static void amdgpu_ras_validate_threshold(struct amdgpu_device *adev, } } +static int amdgpu_ras_page_retirement_thread(void *param) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)param; + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + + while (!kthread_should_stop()) { + + wait_event_interruptible(con->page_retirement_wq, + kthread_should_stop() || + atomic_read(&con->page_retirement_req_cnt)); + + if (kthread_should_stop()) + break; + + dev_info(adev->dev, "Start processing page retirement. request:%d\n", + atomic_read(&con->page_retirement_req_cnt)); + + atomic_dec(&con->page_retirement_req_cnt); + + amdgpu_umc_bad_page_polling_timeout(adev, + false, MAX_UMC_POISON_POLLING_TIME_ASYNC); + } + + return 0; +} + int amdgpu_ras_recovery_init(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); @@ -2583,6 +2751,16 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) } } + mutex_init(&con->page_retirement_lock); + init_waitqueue_head(&con->page_retirement_wq); + atomic_set(&con->page_retirement_req_cnt, 0); + con->page_retirement_thread = + kthread_run(amdgpu_ras_page_retirement_thread, adev, "umc_page_retirement"); + if (IS_ERR(con->page_retirement_thread)) { + con->page_retirement_thread = NULL; + dev_warn(adev->dev, "Failed to create umc_page_retirement thread!!!\n"); + } + #ifdef CONFIG_X86_MCE_AMD if ((adev->asic_type == CHIP_ALDEBARAN) && (adev->gmc.xgmi.connected_to_cpu)) @@ -2618,6 +2796,11 @@ static int amdgpu_ras_recovery_fini(struct amdgpu_device *adev) if (!data) return 0; + if (con->page_retirement_thread) + kthread_stop(con->page_retirement_thread); + + atomic_set(&con->page_retirement_req_cnt, 0); + cancel_work_sync(&con->recovery_work); mutex_lock(&con->recovery_lock); @@ -2679,6 +2862,87 @@ static void amdgpu_ras_get_quirks(struct amdgpu_device *adev) adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__GFX); } +/* Query ras capablity via atomfirmware interface */ +static void amdgpu_ras_query_ras_capablity_from_vbios(struct amdgpu_device *adev) +{ + /* mem_ecc cap */ + if (amdgpu_atomfirmware_mem_ecc_supported(adev)) { + dev_info(adev->dev, "MEM ECC is active.\n"); + adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__UMC | + 1 << AMDGPU_RAS_BLOCK__DF); + } else { + dev_info(adev->dev, "MEM ECC is not presented.\n"); + } + + /* sram_ecc cap */ + if (amdgpu_atomfirmware_sram_ecc_supported(adev)) { + dev_info(adev->dev, "SRAM ECC is active.\n"); + if (!amdgpu_sriov_vf(adev)) + adev->ras_hw_enabled |= ~(1 << AMDGPU_RAS_BLOCK__UMC | + 1 << AMDGPU_RAS_BLOCK__DF); + else + adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__PCIE_BIF | + 1 << AMDGPU_RAS_BLOCK__SDMA | + 1 << AMDGPU_RAS_BLOCK__GFX); + + /* + * VCN/JPEG RAS can be supported on both bare metal and + * SRIOV environment + */ + if (amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(2, 6, 0) || + amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 0) || + amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 3)) + adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN | + 1 << AMDGPU_RAS_BLOCK__JPEG); + else + adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__VCN | + 1 << AMDGPU_RAS_BLOCK__JPEG); + + /* + * XGMI RAS is not supported if xgmi num physical nodes + * is zero + */ + if (!adev->gmc.xgmi.num_physical_nodes) + adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__XGMI_WAFL); + } else { + dev_info(adev->dev, "SRAM ECC is not presented.\n"); + } +} + +/* Query poison mode from umc/df IP callbacks */ +static void amdgpu_ras_query_poison_mode(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + bool df_poison, umc_poison; + + /* poison setting is useless on SRIOV guest */ + if (amdgpu_sriov_vf(adev) || !con) + return; + + /* Init poison supported flag, the default value is false */ + if (adev->gmc.xgmi.connected_to_cpu || + adev->gmc.is_app_apu) { + /* enabled by default when GPU is connected to CPU */ + con->poison_supported = true; + } else if (adev->df.funcs && + adev->df.funcs->query_ras_poison_mode && + adev->umc.ras && + adev->umc.ras->query_ras_poison_mode) { + df_poison = + adev->df.funcs->query_ras_poison_mode(adev); + umc_poison = + adev->umc.ras->query_ras_poison_mode(adev); + + /* Only poison is set in both DF and UMC, we can support it */ + if (df_poison && umc_poison) + con->poison_supported = true; + else if (df_poison != umc_poison) + dev_warn(adev->dev, + "Poison setting is inconsistent in DF/UMC(%d:%d)!\n", + df_poison, umc_poison); + } +} + /* * check hardware's ras ability which will be saved in hw_supported. * if hardware does not support ras, we can skip some ras initializtion and @@ -2695,49 +2959,13 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev) if (!amdgpu_ras_asic_supported(adev)) return; - if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) { - if (amdgpu_atomfirmware_mem_ecc_supported(adev)) { - dev_info(adev->dev, "MEM ECC is active.\n"); - adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__UMC | - 1 << AMDGPU_RAS_BLOCK__DF); - } else { - dev_info(adev->dev, "MEM ECC is not presented.\n"); - } - - if (amdgpu_atomfirmware_sram_ecc_supported(adev)) { - dev_info(adev->dev, "SRAM ECC is active.\n"); - if (!amdgpu_sriov_vf(adev)) - adev->ras_hw_enabled |= ~(1 << AMDGPU_RAS_BLOCK__UMC | - 1 << AMDGPU_RAS_BLOCK__DF); - else - adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__PCIE_BIF | - 1 << AMDGPU_RAS_BLOCK__SDMA | - 1 << AMDGPU_RAS_BLOCK__GFX); - - /* VCN/JPEG RAS can be supported on both bare metal and - * SRIOV environment - */ - if (amdgpu_ip_version(adev, VCN_HWIP, 0) == - IP_VERSION(2, 6, 0) || - amdgpu_ip_version(adev, VCN_HWIP, 0) == - IP_VERSION(4, 0, 0) || - amdgpu_ip_version(adev, VCN_HWIP, 0) == - IP_VERSION(4, 0, 3)) - adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN | - 1 << AMDGPU_RAS_BLOCK__JPEG); - else - adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__VCN | - 1 << AMDGPU_RAS_BLOCK__JPEG); + /* query ras capability from psp */ + if (amdgpu_psp_get_ras_capability(&adev->psp)) + goto init_ras_enabled_flag; - /* - * XGMI RAS is not supported if xgmi num physical nodes - * is zero - */ - if (!adev->gmc.xgmi.num_physical_nodes) - adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__XGMI_WAFL); - } else { - dev_info(adev->dev, "SRAM ECC is not presented.\n"); - } + /* query ras capablity from bios */ + if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) { + amdgpu_ras_query_ras_capablity_from_vbios(adev); } else { /* driver only manages a few IP blocks RAS feature * when GPU is connected cpu through XGMI */ @@ -2746,13 +2974,21 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev) 1 << AMDGPU_RAS_BLOCK__MMHUB); } + /* apply asic specific settings (vega20 only for now) */ amdgpu_ras_get_quirks(adev); + /* query poison mode from umc/df ip callback */ + amdgpu_ras_query_poison_mode(adev); + +init_ras_enabled_flag: /* hw_supported needs to be aligned with RAS block mask. */ adev->ras_hw_enabled &= AMDGPU_RAS_BLOCK_MASK; adev->ras_enabled = amdgpu_ras_enable == 0 ? 0 : adev->ras_hw_enabled & amdgpu_ras_mask; + + /* aca is disabled by default */ + adev->aca.is_enabled = false; } static void amdgpu_ras_counte_dw(struct work_struct *work) @@ -2780,39 +3016,6 @@ Out: pm_runtime_put_autosuspend(dev->dev); } -static void amdgpu_ras_query_poison_mode(struct amdgpu_device *adev) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - bool df_poison, umc_poison; - - /* poison setting is useless on SRIOV guest */ - if (amdgpu_sriov_vf(adev) || !con) - return; - - /* Init poison supported flag, the default value is false */ - if (adev->gmc.xgmi.connected_to_cpu || - adev->gmc.is_app_apu) { - /* enabled by default when GPU is connected to CPU */ - con->poison_supported = true; - } else if (adev->df.funcs && - adev->df.funcs->query_ras_poison_mode && - adev->umc.ras && - adev->umc.ras->query_ras_poison_mode) { - df_poison = - adev->df.funcs->query_ras_poison_mode(adev); - umc_poison = - adev->umc.ras->query_ras_poison_mode(adev); - - /* Only poison is set in both DF and UMC, we can support it */ - if (df_poison && umc_poison) - con->poison_supported = true; - else if (df_poison != umc_poison) - dev_warn(adev->dev, - "Poison setting is inconsistent in DF/UMC(%d:%d)!\n", - df_poison, umc_poison); - } -} - static int amdgpu_get_ras_schema(struct amdgpu_device *adev) { return amdgpu_ras_is_poison_mode_supported(adev) ? AMDGPU_RAS_ERROR__POISON : 0 | @@ -2917,12 +3120,11 @@ int amdgpu_ras_init(struct amdgpu_device *adev) goto release_con; } - amdgpu_ras_query_poison_mode(adev); - /* Packed socket_id to ras feature mask bits[31:29] */ if (adev->smuio.funcs && adev->smuio.funcs->get_socket_id) - con->features |= ((adev->smuio.funcs->get_socket_id(adev)) << 29); + con->features |= ((adev->smuio.funcs->get_socket_id(adev)) << + AMDGPU_RAS_FEATURES_SOCKETID_SHIFT); /* Get RAS schema for particular SOC */ con->schema = amdgpu_get_ras_schema(adev); @@ -3128,7 +3330,7 @@ void amdgpu_ras_suspend(struct amdgpu_device *adev) amdgpu_ras_disable_all_features(adev, 0); /* Make sure all ras objects are disabled. */ - if (con->features) + if (AMDGPU_RAS_GET_FEATURES(con->features)) amdgpu_ras_disable_all_features(adev, 1); } @@ -3142,15 +3344,29 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) return 0; - amdgpu_ras_set_mca_debug_mode(adev, false); + if (amdgpu_aca_is_enabled(adev)) { + if (amdgpu_in_reset(adev)) + r = amdgpu_aca_reset(adev); + else + r = amdgpu_aca_init(adev); + if (r) + return r; + + amdgpu_ras_set_aca_debug_mode(adev, false); + } else { + amdgpu_ras_set_mca_debug_mode(adev, false); + } list_for_each_entry_safe(node, tmp, &adev->ras_list, node) { - if (!node->ras_obj) { + obj = node->ras_obj; + if (!obj) { dev_warn(adev->dev, "Warning: abnormal ras list node.\n"); continue; } - obj = node->ras_obj; + if (!amdgpu_ras_is_supported(adev, obj->ras_comm.block)) + continue; + if (obj->ras_late_init) { r = obj->ras_late_init(adev, &obj->ras_comm); if (r) { @@ -3175,7 +3391,7 @@ int amdgpu_ras_pre_fini(struct amdgpu_device *adev) /* Need disable ras on all IPs here before ip [hw/sw]fini */ - if (con->features) + if (AMDGPU_RAS_GET_FEATURES(con->features)) amdgpu_ras_disable_all_features(adev, 0); amdgpu_ras_recovery_fini(adev); return 0; @@ -3208,10 +3424,13 @@ int amdgpu_ras_fini(struct amdgpu_device *adev) amdgpu_ras_fs_fini(adev); amdgpu_ras_interrupt_remove_all(adev); - WARN(con->features, "Feature mask is not cleared"); + if (amdgpu_aca_is_enabled(adev)) + amdgpu_aca_fini(adev); - if (con->features) - amdgpu_ras_disable_all_features(adev, 1); + WARN(AMDGPU_RAS_GET_FEATURES(con->features), "Feature mask is not cleared"); + + if (AMDGPU_RAS_GET_FEATURES(con->features)) + amdgpu_ras_disable_all_features(adev, 0); cancel_delayed_work_sync(&con->ras_counte_delay_work); @@ -3425,22 +3644,41 @@ int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable) if (con) { ret = amdgpu_mca_smu_set_debug_mode(adev, enable); if (!ret) - con->is_mca_debug_mode = enable; + con->is_aca_debug_mode = enable; + } + + return ret; +} + +int amdgpu_ras_set_aca_debug_mode(struct amdgpu_device *adev, bool enable) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + int ret = 0; + + if (con) { + if (amdgpu_aca_is_enabled(adev)) + ret = amdgpu_aca_smu_set_debug_mode(adev, enable); + else + ret = amdgpu_mca_smu_set_debug_mode(adev, enable); + if (!ret) + con->is_aca_debug_mode = enable; } return ret; } -bool amdgpu_ras_get_mca_debug_mode(struct amdgpu_device *adev) +bool amdgpu_ras_get_aca_debug_mode(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + const struct aca_smu_funcs *smu_funcs = adev->aca.smu_funcs; const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; if (!con) return false; - if (mca_funcs && mca_funcs->mca_set_debug_mode) - return con->is_mca_debug_mode; + if ((amdgpu_aca_is_enabled(adev) && smu_funcs && smu_funcs->set_debug_mode) || + (!amdgpu_aca_is_enabled(adev) && mca_funcs && mca_funcs->mca_set_debug_mode)) + return con->is_aca_debug_mode; else return true; } @@ -3450,15 +3688,16 @@ bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev, { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; + const struct aca_smu_funcs *smu_funcs = adev->aca.smu_funcs; if (!con) { *error_query_mode = AMDGPU_RAS_INVALID_ERROR_QUERY; return false; } - if (mca_funcs && mca_funcs->mca_set_debug_mode) + if ((smu_funcs && smu_funcs->set_debug_mode) || (mca_funcs && mca_funcs->mca_set_debug_mode)) *error_query_mode = - (con->is_mca_debug_mode) ? AMDGPU_RAS_DIRECT_ERROR_QUERY : AMDGPU_RAS_FIRMWARE_ERROR_QUERY; + (con->is_aca_debug_mode) ? AMDGPU_RAS_DIRECT_ERROR_QUERY : AMDGPU_RAS_FIRMWARE_ERROR_QUERY; else *error_query_mode = AMDGPU_RAS_DIRECT_ERROR_QUERY; @@ -3699,8 +3938,7 @@ static int ras_err_info_cmp(void *priv, const struct list_head *a, const struct } static struct ras_err_info *amdgpu_ras_error_get_info(struct ras_err_data *err_data, - struct amdgpu_smuio_mcm_config_info *mcm_info, - struct ras_err_addr *err_addr) + struct amdgpu_smuio_mcm_config_info *mcm_info) { struct ras_err_node *err_node; @@ -3712,10 +3950,9 @@ static struct ras_err_info *amdgpu_ras_error_get_info(struct ras_err_data *err_d if (!err_node) return NULL; - memcpy(&err_node->err_info.mcm_info, mcm_info, sizeof(*mcm_info)); + INIT_LIST_HEAD(&err_node->err_info.err_addr_list); - if (err_addr) - memcpy(&err_node->err_info.err_addr, err_addr, sizeof(*err_addr)); + memcpy(&err_node->err_info.mcm_info, mcm_info, sizeof(*mcm_info)); err_data->err_list_count++; list_add_tail(&err_node->node, &err_data->err_node_list); @@ -3724,6 +3961,29 @@ static struct ras_err_info *amdgpu_ras_error_get_info(struct ras_err_data *err_d return &err_node->err_info; } +void amdgpu_ras_add_mca_err_addr(struct ras_err_info *err_info, struct ras_err_addr *err_addr) +{ + struct ras_err_addr *mca_err_addr; + + mca_err_addr = kzalloc(sizeof(*mca_err_addr), GFP_KERNEL); + if (!mca_err_addr) + return; + + INIT_LIST_HEAD(&mca_err_addr->node); + + mca_err_addr->err_status = err_addr->err_status; + mca_err_addr->err_ipid = err_addr->err_ipid; + mca_err_addr->err_addr = err_addr->err_addr; + + list_add_tail(&mca_err_addr->node, &err_info->err_addr_list); +} + +void amdgpu_ras_del_mca_err_addr(struct ras_err_info *err_info, struct ras_err_addr *mca_err_addr) +{ + list_del(&mca_err_addr->node); + kfree(mca_err_addr); +} + int amdgpu_ras_error_statistic_ue_count(struct ras_err_data *err_data, struct amdgpu_smuio_mcm_config_info *mcm_info, struct ras_err_addr *err_addr, u64 count) @@ -3736,10 +3996,13 @@ int amdgpu_ras_error_statistic_ue_count(struct ras_err_data *err_data, if (!count) return 0; - err_info = amdgpu_ras_error_get_info(err_data, mcm_info, err_addr); + err_info = amdgpu_ras_error_get_info(err_data, mcm_info); if (!err_info) return -EINVAL; + if (err_addr && err_addr->err_status) + amdgpu_ras_add_mca_err_addr(err_info, err_addr); + err_info->ue_count += count; err_data->ue_count += count; @@ -3758,7 +4021,7 @@ int amdgpu_ras_error_statistic_ce_count(struct ras_err_data *err_data, if (!count) return 0; - err_info = amdgpu_ras_error_get_info(err_data, mcm_info, err_addr); + err_info = amdgpu_ras_error_get_info(err_data, mcm_info); if (!err_info) return -EINVAL; @@ -3767,3 +4030,135 @@ int amdgpu_ras_error_statistic_ce_count(struct ras_err_data *err_data, return 0; } + +int amdgpu_ras_error_statistic_de_count(struct ras_err_data *err_data, + struct amdgpu_smuio_mcm_config_info *mcm_info, + struct ras_err_addr *err_addr, u64 count) +{ + struct ras_err_info *err_info; + + if (!err_data || !mcm_info) + return -EINVAL; + + if (!count) + return 0; + + err_info = amdgpu_ras_error_get_info(err_data, mcm_info); + if (!err_info) + return -EINVAL; + + if (err_addr && err_addr->err_status) + amdgpu_ras_add_mca_err_addr(err_info, err_addr); + + err_info->de_count += count; + err_data->de_count += count; + + return 0; +} + +#define mmMP0_SMN_C2PMSG_92 0x1609C +#define mmMP0_SMN_C2PMSG_126 0x160BE +static void amdgpu_ras_boot_time_error_reporting(struct amdgpu_device *adev, + u32 instance, u32 boot_error) +{ + u32 socket_id, aid_id, hbm_id; + u32 reg_data; + u64 reg_addr; + + socket_id = AMDGPU_RAS_GPU_ERR_SOCKET_ID(boot_error); + aid_id = AMDGPU_RAS_GPU_ERR_AID_ID(boot_error); + hbm_id = AMDGPU_RAS_GPU_ERR_HBM_ID(boot_error); + + /* The pattern for smn addressing in other SOC could be different from + * the one for aqua_vanjaram. We should revisit the code if the pattern + * is changed. In such case, replace the aqua_vanjaram implementation + * with more common helper */ + reg_addr = (mmMP0_SMN_C2PMSG_92 << 2) + + aqua_vanjaram_encode_ext_smn_addressing(instance); + + reg_data = amdgpu_device_indirect_rreg_ext(adev, reg_addr); + dev_err(adev->dev, "socket: %d, aid: %d, firmware boot failed, fw status is 0x%x\n", + socket_id, aid_id, reg_data); + + if (AMDGPU_RAS_GPU_ERR_MEM_TRAINING(boot_error)) + dev_info(adev->dev, "socket: %d, aid: %d, hbm: %d, memory training failed\n", + socket_id, aid_id, hbm_id); + + if (AMDGPU_RAS_GPU_ERR_FW_LOAD(boot_error)) + dev_info(adev->dev, "socket: %d, aid: %d, firmware load failed at boot time\n", + socket_id, aid_id); + + if (AMDGPU_RAS_GPU_ERR_WAFL_LINK_TRAINING(boot_error)) + dev_info(adev->dev, "socket: %d, aid: %d, wafl link training failed\n", + socket_id, aid_id); + + if (AMDGPU_RAS_GPU_ERR_XGMI_LINK_TRAINING(boot_error)) + dev_info(adev->dev, "socket: %d, aid: %d, xgmi link training failed\n", + socket_id, aid_id); + + if (AMDGPU_RAS_GPU_ERR_USR_CP_LINK_TRAINING(boot_error)) + dev_info(adev->dev, "socket: %d, aid: %d, usr cp link training failed\n", + socket_id, aid_id); + + if (AMDGPU_RAS_GPU_ERR_USR_DP_LINK_TRAINING(boot_error)) + dev_info(adev->dev, "socket: %d, aid: %d, usr dp link training failed\n", + socket_id, aid_id); + + if (AMDGPU_RAS_GPU_ERR_HBM_MEM_TEST(boot_error)) + dev_info(adev->dev, "socket: %d, aid: %d, hbm: %d, hbm memory test failed\n", + socket_id, aid_id, hbm_id); + + if (AMDGPU_RAS_GPU_ERR_HBM_BIST_TEST(boot_error)) + dev_info(adev->dev, "socket: %d, aid: %d, hbm: %d, hbm bist test failed\n", + socket_id, aid_id, hbm_id); +} + +static int amdgpu_ras_wait_for_boot_complete(struct amdgpu_device *adev, + u32 instance, u32 *boot_error) +{ + u32 reg_addr; + u32 reg_data; + int retry_loop; + + reg_addr = (mmMP0_SMN_C2PMSG_92 << 2) + + aqua_vanjaram_encode_ext_smn_addressing(instance); + + for (retry_loop = 0; retry_loop < AMDGPU_RAS_BOOT_STATUS_POLLING_LIMIT; retry_loop++) { + reg_data = amdgpu_device_indirect_rreg_ext(adev, reg_addr); + if ((reg_data & AMDGPU_RAS_BOOT_STATUS_MASK) == AMDGPU_RAS_BOOT_STEADY_STATUS) { + *boot_error = AMDGPU_RAS_BOOT_SUCEESS; + return 0; + } + msleep(1); + } + + /* The pattern for smn addressing in other SOC could be different from + * the one for aqua_vanjaram. We should revisit the code if the pattern + * is changed. In such case, replace the aqua_vanjaram implementation + * with more common helper */ + reg_addr = (mmMP0_SMN_C2PMSG_126 << 2) + + aqua_vanjaram_encode_ext_smn_addressing(instance); + + for (retry_loop = 0; retry_loop < AMDGPU_RAS_BOOT_STATUS_POLLING_LIMIT; retry_loop++) { + reg_data = amdgpu_device_indirect_rreg_ext(adev, reg_addr); + if (AMDGPU_RAS_GPU_ERR_BOOT_STATUS(reg_data)) { + *boot_error = reg_data; + return 0; + } + msleep(1); + } + + *boot_error = reg_data; + return -ETIME; +} + +void amdgpu_ras_query_boot_status(struct amdgpu_device *adev, u32 num_instances) +{ + u32 boot_error = 0; + u32 i; + + for (i = 0; i < num_instances; i++) { + if (amdgpu_ras_wait_for_boot_complete(adev, i, &boot_error)) + amdgpu_ras_boot_time_error_reporting(adev, i, boot_error); + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index 76fb85628716f6302b3c02beb0965c85f2723a05..d10e5bb0e52f007cdbb380b44ae0b663d89544cd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -29,9 +29,28 @@ #include "ta_ras_if.h" #include "amdgpu_ras_eeprom.h" #include "amdgpu_smuio.h" +#include "amdgpu_aca.h" struct amdgpu_iv_entry; +#define AMDGPU_RAS_GPU_ERR_MEM_TRAINING(x) AMDGPU_GET_REG_FIELD(x, 0, 0) +#define AMDGPU_RAS_GPU_ERR_FW_LOAD(x) AMDGPU_GET_REG_FIELD(x, 1, 1) +#define AMDGPU_RAS_GPU_ERR_WAFL_LINK_TRAINING(x) AMDGPU_GET_REG_FIELD(x, 2, 2) +#define AMDGPU_RAS_GPU_ERR_XGMI_LINK_TRAINING(x) AMDGPU_GET_REG_FIELD(x, 3, 3) +#define AMDGPU_RAS_GPU_ERR_USR_CP_LINK_TRAINING(x) AMDGPU_GET_REG_FIELD(x, 4, 4) +#define AMDGPU_RAS_GPU_ERR_USR_DP_LINK_TRAINING(x) AMDGPU_GET_REG_FIELD(x, 5, 5) +#define AMDGPU_RAS_GPU_ERR_HBM_MEM_TEST(x) AMDGPU_GET_REG_FIELD(x, 6, 6) +#define AMDGPU_RAS_GPU_ERR_HBM_BIST_TEST(x) AMDGPU_GET_REG_FIELD(x, 7, 7) +#define AMDGPU_RAS_GPU_ERR_SOCKET_ID(x) AMDGPU_GET_REG_FIELD(x, 10, 8) +#define AMDGPU_RAS_GPU_ERR_AID_ID(x) AMDGPU_GET_REG_FIELD(x, 12, 11) +#define AMDGPU_RAS_GPU_ERR_HBM_ID(x) AMDGPU_GET_REG_FIELD(x, 13, 13) +#define AMDGPU_RAS_GPU_ERR_BOOT_STATUS(x) AMDGPU_GET_REG_FIELD(x, 31, 31) + +#define AMDGPU_RAS_BOOT_STATUS_POLLING_LIMIT 1000 +#define AMDGPU_RAS_BOOT_STEADY_STATUS 0xBA +#define AMDGPU_RAS_BOOT_STATUS_MASK 0xFF +#define AMDGPU_RAS_BOOT_SUCEESS 0x80000000 + #define AMDGPU_RAS_FLAG_INIT_BY_VBIOS (0x1 << 0) /* position of instance value in sub_block_index of * ta_ras_trigger_error_input, the sub block uses lower 12 bits @@ -39,6 +58,12 @@ struct amdgpu_iv_entry; #define AMDGPU_RAS_INST_MASK 0xfffff000 #define AMDGPU_RAS_INST_SHIFT 0xc +#define AMDGPU_RAS_FEATURES_SOCKETID_SHIFT 29 +#define AMDGPU_RAS_FEATURES_SOCKETID_MASK 0xe0000000 + +/* The high three bits indicates socketid */ +#define AMDGPU_RAS_GET_FEATURES(val) ((val) & ~AMDGPU_RAS_FEATURES_SOCKETID_MASK) + enum amdgpu_ras_block { AMDGPU_RAS_BLOCK__UMC = 0, AMDGPU_RAS_BLOCK__SDMA, @@ -57,6 +82,8 @@ enum amdgpu_ras_block { AMDGPU_RAS_BLOCK__MCA, AMDGPU_RAS_BLOCK__VCN, AMDGPU_RAS_BLOCK__JPEG, + AMDGPU_RAS_BLOCK__IH, + AMDGPU_RAS_BLOCK__MPIO, AMDGPU_RAS_BLOCK__LAST }; @@ -441,10 +468,15 @@ struct amdgpu_ras { /* Indicates smu whether need update bad channel info */ bool update_channel_flag; /* Record status of smu mca debug mode */ - bool is_mca_debug_mode; + bool is_aca_debug_mode; /* Record special requirements of gpu reset caller */ uint32_t gpu_reset_flags; + + struct task_struct *page_retirement_thread; + wait_queue_head_t page_retirement_wq; + struct mutex page_retirement_lock; + atomic_t page_retirement_req_cnt; }; struct ras_fs_data { @@ -453,6 +485,7 @@ struct ras_fs_data { }; struct ras_err_addr { + struct list_head node; uint64_t err_status; uint64_t err_ipid; uint64_t err_addr; @@ -462,7 +495,8 @@ struct ras_err_info { struct amdgpu_smuio_mcm_config_info mcm_info; u64 ce_count; u64 ue_count; - struct ras_err_addr err_addr; + u64 de_count; + struct list_head err_addr_list; }; struct ras_err_node { @@ -473,6 +507,7 @@ struct ras_err_node { struct ras_err_data { unsigned long ue_count; unsigned long ce_count; + unsigned long de_count; unsigned long err_addr_cnt; struct eeprom_table_record *err_addr; u32 err_list_count; @@ -529,6 +564,8 @@ struct ras_manager { struct ras_ih_data ih_data; struct ras_err_data err_data; + + struct aca_handle aca_handle; }; struct ras_badpage { @@ -548,6 +585,7 @@ struct ras_query_if { struct ras_common_if head; unsigned long ue_count; unsigned long ce_count; + unsigned long de_count; }; struct ras_inject_if { @@ -781,7 +819,8 @@ struct amdgpu_ras* amdgpu_ras_get_context(struct amdgpu_device *adev); int amdgpu_ras_set_context(struct amdgpu_device *adev, struct amdgpu_ras *ras_con); int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable); -bool amdgpu_ras_get_mca_debug_mode(struct amdgpu_device *adev); +int amdgpu_ras_set_aca_debug_mode(struct amdgpu_device *adev, bool enable); +bool amdgpu_ras_get_aca_debug_mode(struct amdgpu_device *adev); bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev, unsigned int *mode); @@ -818,5 +857,20 @@ int amdgpu_ras_error_statistic_ce_count(struct ras_err_data *err_data, int amdgpu_ras_error_statistic_ue_count(struct ras_err_data *err_data, struct amdgpu_smuio_mcm_config_info *mcm_info, struct ras_err_addr *err_addr, u64 count); +int amdgpu_ras_error_statistic_de_count(struct ras_err_data *err_data, + struct amdgpu_smuio_mcm_config_info *mcm_info, + struct ras_err_addr *err_addr, u64 count); +void amdgpu_ras_query_boot_status(struct amdgpu_device *adev, u32 num_instances); +int amdgpu_ras_bind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk, + const struct aca_info *aca_info, void *data); +int amdgpu_ras_unbind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk); + +ssize_t amdgpu_ras_aca_sysfs_read(struct device *dev, struct device_attribute *attr, + struct aca_handle *handle, char *buf, void *data); + +void amdgpu_ras_add_mca_err_addr(struct ras_err_info *err_info, + struct ras_err_addr *err_addr); +void amdgpu_ras_del_mca_err_addr(struct ras_err_info *err_info, + struct ras_err_addr *mca_err_addr); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 45424ebf9681430fefc21bdc33d6aa2c6e5f6c91..5505d646f43aa8f963d8d8732846b00fc612a3a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -635,6 +635,7 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring) ring->name); ring->sched.ready = !r; + return r; } @@ -717,3 +718,14 @@ void amdgpu_ring_ib_on_emit_de(struct amdgpu_ring *ring) if (ring->is_sw_ring) amdgpu_sw_ring_ib_mark_offset(ring, AMDGPU_MUX_OFFSET_TYPE_DE); } + +bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring) +{ + if (!ring) + return false; + + if (ring->no_scheduler || !drm_sched_wqueue_ready(&ring->sched)) + return false; + + return true; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index bbb53720a0181d93cf9fdfd6f7721ee006699004..fe1a61eb6e4c0809c1bccd41bc89f32bcd8304f2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -450,5 +450,5 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, int amdgpu_ib_pool_init(struct amdgpu_device *adev); void amdgpu_ib_pool_fini(struct amdgpu_device *adev); int amdgpu_ib_ring_tests(struct amdgpu_device *adev); - +bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c index 2c3675d91614f13b21e35a08d57c5fc7bca32090..db5791e1a7cefbed9ef3ffaf438ba1c952ad3f7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c @@ -241,7 +241,7 @@ void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev) table_size = le32_to_cpu(hdr->jt_size); } - for (i = 0; i < table_size; i ++) { + for (i = 0; i < table_size; i++) { dst_ptr[bo_offset + i] = cpu_to_le32(le32_to_cpu(fw_data[table_offset + i])); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h index b591d33af26452aa58066cd0ea346ef3526305e5..5a17e0ff2ab892957e2cbf8070e25c8e66cf9848 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h @@ -169,7 +169,7 @@ struct amdgpu_rlc_funcs { void (*stop)(struct amdgpu_device *adev); void (*reset)(struct amdgpu_device *adev); void (*start)(struct amdgpu_device *adev); - void (*update_spm_vmid)(struct amdgpu_device *adev, unsigned vmid); + void (*update_spm_vmid)(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned vmid); bool (*is_rlcg_access_range)(struct amdgpu_device *adev, uint32_t reg); }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c index 7a6a67275404c805568f7f7a405cc77af778e5cb..e9081a98cf81ac766b25b7da9334e1a33f0e39a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c @@ -35,14 +35,29 @@ * counters and VM updates. It has maximum count of 32768 64 bit slots. */ +/** + * amdgpu_seq64_get_va_base - Get the seq64 va base address + * + * @adev: amdgpu_device pointer + * + * Returns: + * va base address on success + */ +static inline u64 amdgpu_seq64_get_va_base(struct amdgpu_device *adev) +{ + u64 addr = adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT; + + addr -= AMDGPU_VA_RESERVED_TOP; + + return addr; +} + /** * amdgpu_seq64_map - Map the seq64 memory to VM * * @adev: amdgpu_device pointer * @vm: vm pointer * @bo_va: bo_va pointer - * @seq64_addr: seq64 vaddr start address - * @size: seq64 pool size * * Map the seq64 memory to the given VM. * @@ -50,11 +65,11 @@ * 0 on success or a negative error code on failure */ int amdgpu_seq64_map(struct amdgpu_device *adev, struct amdgpu_vm *vm, - struct amdgpu_bo_va **bo_va, u64 seq64_addr, - uint32_t size) + struct amdgpu_bo_va **bo_va) { struct amdgpu_bo *bo; struct drm_exec exec; + u64 seq64_addr; int r; bo = adev->seq64.sbo; @@ -77,9 +92,9 @@ int amdgpu_seq64_map(struct amdgpu_device *adev, struct amdgpu_vm *vm, goto error; } - r = amdgpu_vm_bo_map(adev, *bo_va, seq64_addr, 0, size, - AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | - AMDGPU_PTE_EXECUTABLE); + seq64_addr = amdgpu_seq64_get_va_base(adev); + r = amdgpu_vm_bo_map(adev, *bo_va, seq64_addr, 0, AMDGPU_VA_RESERVED_SEQ64_SIZE, + AMDGPU_PTE_READABLE); if (r) { DRM_ERROR("failed to do bo_map on userq sem, err=%d\n", r); amdgpu_vm_bo_del(adev, *bo_va); @@ -144,31 +159,25 @@ error: * amdgpu_seq64_alloc - Allocate a 64 bit memory * * @adev: amdgpu_device pointer - * @gpu_addr: allocated gpu VA start address - * @cpu_addr: allocated cpu VA start address + * @va: VA to access the seq in process address space + * @cpu_addr: CPU address to access the seq * * Alloc a 64 bit memory from seq64 pool. * * Returns: * 0 on success or a negative error code on failure */ -int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *gpu_addr, - u64 **cpu_addr) +int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *va, u64 **cpu_addr) { unsigned long bit_pos; - u32 offset; bit_pos = find_first_zero_bit(adev->seq64.used, adev->seq64.num_sem); + if (bit_pos >= adev->seq64.num_sem) + return -ENOSPC; - if (bit_pos < adev->seq64.num_sem) { - __set_bit(bit_pos, adev->seq64.used); - offset = bit_pos << 6; /* convert to qw offset */ - } else { - return -EINVAL; - } - - *gpu_addr = offset + AMDGPU_SEQ64_VADDR_START; - *cpu_addr = offset + adev->seq64.cpu_base_addr; + __set_bit(bit_pos, adev->seq64.used); + *va = bit_pos * sizeof(u64) + amdgpu_seq64_get_va_base(adev); + *cpu_addr = bit_pos + adev->seq64.cpu_base_addr; return 0; } @@ -177,20 +186,17 @@ int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *gpu_addr, * amdgpu_seq64_free - Free the given 64 bit memory * * @adev: amdgpu_device pointer - * @gpu_addr: gpu start address to be freed + * @va: gpu start address to be freed * * Free the given 64 bit memory from seq64 pool. - * */ -void amdgpu_seq64_free(struct amdgpu_device *adev, u64 gpu_addr) +void amdgpu_seq64_free(struct amdgpu_device *adev, u64 va) { - u32 offset; - - offset = gpu_addr - AMDGPU_SEQ64_VADDR_START; + unsigned long bit_pos; - offset >>= 6; - if (offset < adev->seq64.num_sem) - __clear_bit(offset, adev->seq64.used); + bit_pos = (va - amdgpu_seq64_get_va_base(adev)) / sizeof(u64); + if (bit_pos < adev->seq64.num_sem) + __clear_bit(bit_pos, adev->seq64.used); } /** @@ -229,7 +235,7 @@ int amdgpu_seq64_init(struct amdgpu_device *adev) * AMDGPU_MAX_SEQ64_SLOTS * sizeof(u64) * 8 = AMDGPU_MAX_SEQ64_SLOTS * 64bit slots */ - r = amdgpu_bo_create_kernel(adev, AMDGPU_SEQ64_SIZE, + r = amdgpu_bo_create_kernel(adev, AMDGPU_VA_RESERVED_SEQ64_SIZE, PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, &adev->seq64.sbo, NULL, (void **)&adev->seq64.cpu_base_addr); @@ -238,7 +244,7 @@ int amdgpu_seq64_init(struct amdgpu_device *adev) return r; } - memset(adev->seq64.cpu_base_addr, 0, AMDGPU_SEQ64_SIZE); + memset(adev->seq64.cpu_base_addr, 0, AMDGPU_VA_RESERVED_SEQ64_SIZE); adev->seq64.num_sem = AMDGPU_MAX_SEQ64_SLOTS; memset(&adev->seq64.used, 0, sizeof(adev->seq64.used)); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h index 2196e72be508eeada66e2fc2297c98f223af891c..4203b2ab318df64a5b41959007b65e843c5d89ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h @@ -25,10 +25,9 @@ #ifndef __AMDGPU_SEQ64_H__ #define __AMDGPU_SEQ64_H__ -#define AMDGPU_SEQ64_SIZE (2ULL << 20) -#define AMDGPU_MAX_SEQ64_SLOTS (AMDGPU_SEQ64_SIZE / (sizeof(u64) * 8)) -#define AMDGPU_SEQ64_VADDR_OFFSET 0x50000 -#define AMDGPU_SEQ64_VADDR_START (AMDGPU_VA_RESERVED_SIZE + AMDGPU_SEQ64_VADDR_OFFSET) +#include "amdgpu_vm.h" + +#define AMDGPU_MAX_SEQ64_SLOTS (AMDGPU_VA_RESERVED_SEQ64_SIZE / sizeof(u64)) struct amdgpu_seq64 { struct amdgpu_bo *sbo; @@ -42,7 +41,7 @@ int amdgpu_seq64_init(struct amdgpu_device *adev); int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *gpu_addr, u64 **cpu_addr); void amdgpu_seq64_free(struct amdgpu_device *adev, u64 gpu_addr); int amdgpu_seq64_map(struct amdgpu_device *adev, struct amdgpu_vm *vm, - struct amdgpu_bo_va **bo_va, u64 seq64_addr, uint32_t size); + struct amdgpu_bo_va **bo_va); void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 75c9fd2c6c2a1cb4cc39689668f2f65f036e55c5..8722beba494e563fd45c3e2f3cfba05a7f9d38e8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -102,23 +102,19 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, /* Don't handle scatter gather BOs */ if (bo->type == ttm_bo_type_sg) { placement->num_placement = 0; - placement->num_busy_placement = 0; return; } /* Object isn't an AMDGPU object so ignore */ if (!amdgpu_bo_is_amdgpu_bo(bo)) { placement->placement = &placements; - placement->busy_placement = &placements; placement->num_placement = 1; - placement->num_busy_placement = 1; return; } abo = ttm_to_amdgpu_bo(bo); if (abo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) { placement->num_placement = 0; - placement->num_busy_placement = 0; return; } @@ -128,13 +124,13 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, case AMDGPU_PL_OA: case AMDGPU_PL_DOORBELL: placement->num_placement = 0; - placement->num_busy_placement = 0; return; case TTM_PL_VRAM: if (!adev->mman.buffer_funcs_enabled) { /* Move to system memory */ amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); + } else if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) && amdgpu_bo_in_cpu_visible_vram(abo)) { @@ -149,8 +145,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, AMDGPU_GEM_DOMAIN_CPU); abo->placements[0].fpfn = adev->gmc.visible_vram_size >> PAGE_SHIFT; abo->placements[0].lpfn = 0; - abo->placement.busy_placement = &abo->placements[1]; - abo->placement.num_busy_placement = 1; + abo->placements[0].flags |= TTM_PL_FLAG_DESIRED; } else { /* Move to GTT memory */ amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_GTT | @@ -966,8 +961,6 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) /* allocate GART space */ placement.num_placement = 1; placement.placement = &placements; - placement.num_busy_placement = 1; - placement.busy_placement = &placements; placements.fpfn = 0; placements.lpfn = adev->gmc.gart_size >> PAGE_SHIFT; placements.mem_type = TTM_PL_TT; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index d65e21914d8c4a9e8f7d03a59391504e08a46f63..20436f81856ad280f112bf52dd42ea6157443b04 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -23,6 +23,7 @@ #include "amdgpu.h" #include "umc_v6_7.h" +#define MAX_UMC_POISON_POLLING_TIME_SYNC 20 //ms static int amdgpu_umc_convert_error_address(struct amdgpu_device *adev, struct ras_err_data *err_data, uint64_t err_addr, @@ -85,18 +86,21 @@ out_fini_err_data: return ret; } -static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, - void *ras_error_status, - struct amdgpu_iv_entry *entry, - bool reset) +static void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev, + void *ras_error_status) { struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + unsigned int error_query_mode; int ret = 0; + unsigned long err_count; - kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); + amdgpu_ras_get_error_query_mode(adev, &error_query_mode); + + mutex_lock(&con->page_retirement_lock); ret = amdgpu_dpm_get_ecc_info(adev, (void *)&(con->umc_ecc)); - if (ret == -EOPNOTSUPP) { + if (ret == -EOPNOTSUPP && + error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) { if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && adev->umc.ras->ras_block.hw_ops->query_ras_error_count) adev->umc.ras->ras_block.hw_ops->query_ras_error_count(adev, ras_error_status); @@ -120,7 +124,8 @@ static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, */ adev->umc.ras->ras_block.hw_ops->query_ras_error_address(adev, ras_error_status); } - } else if (!ret) { + } else if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY || + (!ret && error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY)) { if (adev->umc.ras && adev->umc.ras->ecc_info_query_ras_error_count) adev->umc.ras->ecc_info_query_ras_error_count(adev, ras_error_status); @@ -147,16 +152,13 @@ static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, } /* only uncorrectable error needs gpu reset */ - if (err_data->ue_count) { - dev_info(adev->dev, "%ld uncorrectable hardware errors " - "detected in UMC block\n", - err_data->ue_count); - + if (err_data->ue_count || err_data->de_count) { + err_count = err_data->ue_count + err_data->de_count; if ((amdgpu_bad_page_threshold != 0) && err_data->err_addr_cnt) { amdgpu_ras_add_bad_pages(adev, err_data->err_addr, err_data->err_addr_cnt); - amdgpu_ras_save_bad_pages(adev, &(err_data->ue_count)); + amdgpu_ras_save_bad_pages(adev, &err_count); amdgpu_dpm_send_hbm_bad_pages_num(adev, con->eeprom_control.ras_num_recs); @@ -165,20 +167,87 @@ static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, con->update_channel_flag = false; } } - - if (reset) { - /* use mode-2 reset for poison consumption */ - if (!entry) - con->gpu_reset_flags |= AMDGPU_RAS_GPU_RESET_MODE2_RESET; - amdgpu_ras_reset_gpu(adev); - } } kfree(err_data->err_addr); + + mutex_unlock(&con->page_retirement_lock); +} + +static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, + void *ras_error_status, + struct amdgpu_iv_entry *entry, + bool reset) +{ + struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + + kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); + amdgpu_umc_handle_bad_pages(adev, ras_error_status); + + if (err_data->ue_count && reset) { + /* use mode-2 reset for poison consumption */ + if (!entry) + con->gpu_reset_flags |= AMDGPU_RAS_GPU_RESET_MODE2_RESET; + amdgpu_ras_reset_gpu(adev); + } + return AMDGPU_RAS_SUCCESS; } -int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset) +int amdgpu_umc_bad_page_polling_timeout(struct amdgpu_device *adev, + bool reset, uint32_t timeout_ms) +{ + struct ras_err_data err_data; + struct ras_common_if head = { + .block = AMDGPU_RAS_BLOCK__UMC, + }; + struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); + uint32_t timeout = timeout_ms; + + memset(&err_data, 0, sizeof(err_data)); + amdgpu_ras_error_data_init(&err_data); + + do { + + amdgpu_umc_handle_bad_pages(adev, &err_data); + + if (timeout && !err_data.de_count) { + msleep(1); + timeout--; + } + + } while (timeout && !err_data.de_count); + + if (!timeout) + dev_warn(adev->dev, "Can't find bad pages\n"); + + if (err_data.de_count) + dev_info(adev->dev, "%ld new deferred hardware errors detected\n", err_data.de_count); + + if (obj) { + obj->err_data.ue_count += err_data.ue_count; + obj->err_data.ce_count += err_data.ce_count; + obj->err_data.de_count += err_data.de_count; + } + + amdgpu_ras_error_data_fini(&err_data); + + kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); + + if (reset) { + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + + /* use mode-2 reset for poison consumption */ + con->gpu_reset_flags |= AMDGPU_RAS_GPU_RESET_MODE2_RESET; + amdgpu_ras_reset_gpu(adev); + } + + return 0; +} + +int amdgpu_umc_poison_handler(struct amdgpu_device *adev, + enum amdgpu_ras_block block, bool reset) { int ret = AMDGPU_RAS_SUCCESS; @@ -195,27 +264,41 @@ int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset) } if (!amdgpu_sriov_vf(adev)) { - struct ras_err_data err_data; - struct ras_common_if head = { - .block = AMDGPU_RAS_BLOCK__UMC, - }; - struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); + if (amdgpu_ip_version(adev, UMC_HWIP, 0) < IP_VERSION(12, 0, 0)) { + struct ras_err_data err_data; + struct ras_common_if head = { + .block = AMDGPU_RAS_BLOCK__UMC, + }; + struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); + + ret = amdgpu_ras_error_data_init(&err_data); + if (ret) + return ret; - ret = amdgpu_ras_error_data_init(&err_data); - if (ret) - return ret; + ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset); - ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset); + if (ret == AMDGPU_RAS_SUCCESS && obj) { + obj->err_data.ue_count += err_data.ue_count; + obj->err_data.ce_count += err_data.ce_count; + obj->err_data.de_count += err_data.de_count; + } - if (ret == AMDGPU_RAS_SUCCESS && obj) { - obj->err_data.ue_count += err_data.ue_count; - obj->err_data.ce_count += err_data.ce_count; - } + amdgpu_ras_error_data_fini(&err_data); + } else { + if (reset) { + amdgpu_umc_bad_page_polling_timeout(adev, + reset, MAX_UMC_POISON_POLLING_TIME_SYNC); + } else { + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - amdgpu_ras_error_data_fini(&err_data); + atomic_inc(&con->page_retirement_req_cnt); + + wake_up(&con->page_retirement_wq); + } + } } else { if (adev->virt.ops && adev->virt.ops->ras_poison_handler) - adev->virt.ops->ras_poison_handler(adev); + adev->virt.ops->ras_poison_handler(adev, block); else dev_warn(adev->dev, "No ras_poison_handler interface in SRIOV!\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index 417a6726c71b479943cf1615040304f6c9f79551..26d2ae498daf22bf2833cfdde9333c5f26523b44 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -21,7 +21,7 @@ #ifndef __AMDGPU_UMC_H__ #define __AMDGPU_UMC_H__ #include "amdgpu_ras.h" - +#include "amdgpu_mca.h" /* * (addr / 256) * 4096, the higher 26 bits in ErrorAddr * is the index of 4KB block @@ -64,6 +64,8 @@ struct amdgpu_umc_ras { void *ras_error_status); void (*ecc_info_query_ras_error_address)(struct amdgpu_device *adev, void *ras_error_status); + bool (*check_ecc_err_status)(struct amdgpu_device *adev, + enum amdgpu_mca_error_type type, void *ras_error_status); /* support different eeprom table version for different asic */ void (*set_eeprom_table_version)(struct amdgpu_ras_eeprom_table_header *hdr); }; @@ -100,7 +102,8 @@ struct amdgpu_umc { int amdgpu_umc_ras_sw_init(struct amdgpu_device *adev); int amdgpu_umc_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block); -int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset); +int amdgpu_umc_poison_handler(struct amdgpu_device *adev, + enum amdgpu_ras_block block, bool reset); int amdgpu_umc_process_ecc_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry); @@ -118,4 +121,7 @@ int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev, int amdgpu_umc_loop_channels(struct amdgpu_device *adev, umc_func func, void *data); + +int amdgpu_umc_bad_page_polling_timeout(struct amdgpu_device *adev, + bool reset, uint32_t timeout_ms); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h index 107f9bb0e24f7f2f8e810084cab0e43e8da9f020..5b27fc41ffbf27396ce1ea3f3827fde1cae70c37 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umr.h @@ -69,12 +69,12 @@ struct amdgpu_debugfs_gprwave_data { }; enum AMDGPU_DEBUGFS_REGS2_CMDS { - AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE=0, + AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE = 0, AMDGPU_DEBUGFS_REGS2_CMD_SET_STATE_V2, }; enum AMDGPU_DEBUGFS_GPRWAVE_CMDS { - AMDGPU_DEBUGFS_GPRWAVE_CMD_SET_STATE=0, + AMDGPU_DEBUGFS_GPRWAVE_CMD_SET_STATE = 0, }; //reg2 interface diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c index bfbf59326ee12d5bc5a7dd3def0a77e74971e008..ab820cf526683b5a15ef94ee28075f20752baeac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c @@ -358,7 +358,7 @@ static int setup_umsch_mm_test(struct amdgpu_device *adev, memset(test->ring_data_cpu_addr, 0, sizeof(struct umsch_mm_test_ring_data)); - test->ring_data_gpu_addr = AMDGPU_VA_RESERVED_SIZE; + test->ring_data_gpu_addr = AMDGPU_VA_RESERVED_BOTTOM; r = map_ring_data(adev, test->vm, test->ring_data_obj, &test->bo_va, test->ring_data_gpu_addr, sizeof(struct umsch_mm_test_ring_data)); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index f4963330c772a9c717dae129e6ccf2ec1c4d3ef0..f300d4a4457d39ed613977ec620866efc10f4972 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -1189,7 +1189,7 @@ int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev, amdgpu_ras_interrupt_dispatch(adev, &ih_data); } else { if (adev->virt.ops && adev->virt.ops->ras_poison_handler) - adev->virt.ops->ras_poison_handler(adev); + adev->virt.ops->ras_poison_handler(adev, ras_if->block); else dev_warn(adev->dev, "No ras_poison_handler interface in SRIOV for VCN!\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 0dcff2889e25d2b8883a39eaf9d09755bb1c2373..6ff7d3fb2008038d7419ce2105759a7a96a24921 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -71,59 +71,6 @@ void amdgpu_virt_init_setting(struct amdgpu_device *adev) amdgpu_num_kcq = 2; } -void amdgpu_virt_kiq_reg_write_reg_wait(struct amdgpu_device *adev, - uint32_t reg0, uint32_t reg1, - uint32_t ref, uint32_t mask, - uint32_t xcc_inst) -{ - struct amdgpu_kiq *kiq = &adev->gfx.kiq[xcc_inst]; - struct amdgpu_ring *ring = &kiq->ring; - signed long r, cnt = 0; - unsigned long flags; - uint32_t seq; - - if (adev->mes.ring.sched.ready) { - amdgpu_mes_reg_write_reg_wait(adev, reg0, reg1, - ref, mask); - return; - } - - spin_lock_irqsave(&kiq->ring_lock, flags); - amdgpu_ring_alloc(ring, 32); - amdgpu_ring_emit_reg_write_reg_wait(ring, reg0, reg1, - ref, mask); - r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); - if (r) - goto failed_undo; - - amdgpu_ring_commit(ring); - spin_unlock_irqrestore(&kiq->ring_lock, flags); - - r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); - - /* don't wait anymore for IRQ context */ - if (r < 1 && in_interrupt()) - goto failed_kiq; - - might_sleep(); - while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) { - - msleep(MAX_KIQ_REG_BAILOUT_INTERVAL); - r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); - } - - if (cnt > MAX_KIQ_REG_TRY) - goto failed_kiq; - - return; - -failed_undo: - amdgpu_ring_undo(ring); - spin_unlock_irqrestore(&kiq->ring_lock, flags); -failed_kiq: - dev_err(adev->dev, "failed to write reg %x wait reg %x\n", reg0, reg1); -} - /** * amdgpu_virt_request_full_gpu() - request full gpu access * @adev: amdgpu device. @@ -303,11 +250,11 @@ static int amdgpu_virt_init_ras_err_handler_data(struct amdgpu_device *adev) if (!*data) goto data_failure; - bps = kmalloc_array(align_space, sizeof((*data)->bps), GFP_KERNEL); + bps = kmalloc_array(align_space, sizeof(*(*data)->bps), GFP_KERNEL); if (!bps) goto bps_failure; - bps_bo = kmalloc_array(align_space, sizeof((*data)->bps_bo), GFP_KERNEL); + bps_bo = kmalloc_array(align_space, sizeof(*(*data)->bps_bo), GFP_KERNEL); if (!bps_bo) goto bps_bo_failure; @@ -340,8 +287,10 @@ static void amdgpu_virt_ras_release_bp(struct amdgpu_device *adev) for (i = data->last_reserved - 1; i >= 0; i--) { bo = data->bps_bo[i]; - amdgpu_bo_free_kernel(&bo, NULL, NULL); - data->bps_bo[i] = bo; + if (bo) { + amdgpu_bo_free_kernel(&bo, NULL, NULL); + data->bps_bo[i] = bo; + } data->last_reserved = i; } } @@ -381,6 +330,8 @@ static void amdgpu_virt_ras_reserve_bps(struct amdgpu_device *adev) { struct amdgpu_virt *virt = &adev->virt; struct amdgpu_virt_ras_err_handler_data *data = virt->virt_eh_data; + struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; + struct ttm_resource_manager *man = &mgr->manager; struct amdgpu_bo *bo = NULL; uint64_t bp; int i; @@ -396,12 +347,18 @@ static void amdgpu_virt_ras_reserve_bps(struct amdgpu_device *adev) * 2) a ras bad page has been reserved (duplicate error injection * for one page); */ - if (amdgpu_bo_create_kernel_at(adev, bp << AMDGPU_GPU_PAGE_SHIFT, - AMDGPU_GPU_PAGE_SIZE, - &bo, NULL)) - DRM_DEBUG("RAS WARN: reserve vram for retired page %llx fail\n", bp); - - data->bps_bo[i] = bo; + if (ttm_resource_manager_used(man)) { + amdgpu_vram_mgr_reserve_range(&adev->mman.vram_mgr, + bp << AMDGPU_GPU_PAGE_SHIFT, + AMDGPU_GPU_PAGE_SIZE); + data->bps_bo[i] = NULL; + } else { + if (amdgpu_bo_create_kernel_at(adev, bp << AMDGPU_GPU_PAGE_SHIFT, + AMDGPU_GPU_PAGE_SIZE, + &bo, NULL)) + DRM_DEBUG("RAS WARN: reserve vram for retired page %llx fail\n", bp); + data->bps_bo[i] = bo; + } data->last_reserved = i + 1; bo = NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index d4207e44141f185bbcd28e28d638b084fda09ec9..fa7be5f277b957b2e8fa9dd9ebef2c543991aa41 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -88,7 +88,8 @@ struct amdgpu_virt_ops { int (*wait_reset)(struct amdgpu_device *adev); void (*trans_msg)(struct amdgpu_device *adev, enum idh_request req, u32 data1, u32 data2, u32 data3); - void (*ras_poison_handler)(struct amdgpu_device *adev); + void (*ras_poison_handler)(struct amdgpu_device *adev, + enum amdgpu_ras_block block); }; /* @@ -332,10 +333,6 @@ static inline bool is_virtual_machine(void) ((adev)->virt.gim_feature & AMDGIM_FEATURE_VCN_RB_DECOUPLE) bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev); void amdgpu_virt_init_setting(struct amdgpu_device *adev); -void amdgpu_virt_kiq_reg_write_reg_wait(struct amdgpu_device *adev, - uint32_t reg0, uint32_t rreg1, - uint32_t ref, uint32_t mask, - uint32_t xcc_inst); int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init); int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init); int amdgpu_virt_reset_gpu(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c index 453a4b786cfcc15c8ac26dd4f9d49a254fbc6228..8baa2e0935cc6e6c3ca6dd0fab54914932514dc9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c @@ -660,8 +660,7 @@ static const struct amd_ip_funcs amdgpu_vkms_ip_funcs = { .set_powergating_state = amdgpu_vkms_set_powergating_state, }; -const struct amdgpu_ip_block_version amdgpu_vkms_ip_block = -{ +const struct amdgpu_ip_block_version amdgpu_vkms_ip_block = { .type = AMD_IP_BLOCK_TYPE_DCE, .major = 1, .minor = 0, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index b8fcb6c55698934549c6696a337e749f0e268217..ed4a8c5d26d7993b6bb342e35501ad450c39b7c7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -233,6 +233,22 @@ static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo) spin_unlock(&vm_bo->vm->status_lock); } +/** + * amdgpu_vm_bo_evicted_user - vm_bo is evicted + * + * @vm_bo: vm_bo which is evicted + * + * State for BOs used by user mode queues which are not at the location they + * should be. + */ +static void amdgpu_vm_bo_evicted_user(struct amdgpu_vm_bo_base *vm_bo) +{ + vm_bo->moved = true; + spin_lock(&vm_bo->vm->status_lock); + list_move(&vm_bo->vm_status, &vm_bo->vm->evicted_user); + spin_unlock(&vm_bo->vm->status_lock); +} + /** * amdgpu_vm_bo_relocated - vm_bo is reloacted * @@ -427,21 +443,25 @@ uint64_t amdgpu_vm_generation(struct amdgpu_device *adev, struct amdgpu_vm *vm) } /** - * amdgpu_vm_validate_pt_bos - validate the page table BOs + * amdgpu_vm_validate - validate evicted BOs tracked in the VM * * @adev: amdgpu device pointer * @vm: vm providing the BOs + * @ticket: optional reservation ticket used to reserve the VM * @validate: callback to do the validation * @param: parameter for the validation callback * - * Validate the page table BOs on command submission if neccessary. + * Validate the page table BOs and per-VM BOs on command submission if + * necessary. If a ticket is given, also try to validate evicted user queue + * BOs. They must already be reserved with the given ticket. * * Returns: * Validation result. */ -int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, - int (*validate)(void *p, struct amdgpu_bo *bo), - void *param) +int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct ww_acquire_ctx *ticket, + int (*validate)(void *p, struct amdgpu_bo *bo), + void *param) { struct amdgpu_vm_bo_base *bo_base; struct amdgpu_bo *shadow; @@ -484,6 +504,28 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, } spin_lock(&vm->status_lock); } + while (ticket && !list_empty(&vm->evicted_user)) { + bo_base = list_first_entry(&vm->evicted_user, + struct amdgpu_vm_bo_base, + vm_status); + spin_unlock(&vm->status_lock); + + bo = bo_base->bo; + + if (dma_resv_locking_ctx(bo->tbo.base.resv) != ticket) { + pr_warn_ratelimited("Evicted user BO is not reserved in pid %d\n", + vm->task_info.pid); + return -EINVAL; + } + + r = validate(param, bo); + if (r) + return r; + + amdgpu_vm_bo_invalidated(bo_base); + + spin_lock(&vm->status_lock); + } spin_unlock(&vm->status_lock); amdgpu_vm_eviction_lock(vm); @@ -651,7 +693,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, amdgpu_gmc_emit_pasid_mapping(ring, job->vmid, job->pasid); if (spm_update_needed && adev->gfx.rlc.funcs->update_spm_vmid) - adev->gfx.rlc.funcs->update_spm_vmid(adev, job->vmid); + adev->gfx.rlc.funcs->update_spm_vmid(adev, ring, job->vmid); if (!ring->is_mes_queue && ring->funcs->emit_gds_switch && gds_switch_needed) { @@ -1426,11 +1468,21 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, } r = amdgpu_vm_bo_update(adev, bo_va, clear); - if (r) - return r; if (unlock) dma_resv_unlock(resv); + if (r) + return r; + + /* Remember evicted DMABuf imports in compute VMs for later + * validation + */ + if (vm->is_compute_context && + bo_va->base.bo->tbo.base.import_attach && + (!bo_va->base.bo->tbo.resource || + bo_va->base.bo->tbo.resource->mem_type == TTM_PL_SYSTEM)) + amdgpu_vm_bo_evicted_user(&bo_va->base); + spin_lock(&vm->status_lock); } spin_unlock(&vm->status_lock); @@ -2196,6 +2248,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, for (i = 0; i < AMDGPU_MAX_VMHUBS; i++) vm->reserved_vmid[i] = NULL; INIT_LIST_HEAD(&vm->evicted); + INIT_LIST_HEAD(&vm->evicted_user); INIT_LIST_HEAD(&vm->relocated); INIT_LIST_HEAD(&vm->moved); INIT_LIST_HEAD(&vm->idle); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 4740dd65b99d6ccc107e5d63aba0f0d67d02d718..666698a571927a1584c6655c8d8d0a12bef94e30 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -136,7 +136,11 @@ struct amdgpu_mem_stats; #define AMDGPU_IS_MMHUB1(x) ((x) >= AMDGPU_MMHUB1_START && (x) < AMDGPU_MAX_VMHUBS) /* Reserve 2MB at top/bottom of address space for kernel use */ -#define AMDGPU_VA_RESERVED_SIZE (2ULL << 20) +#define AMDGPU_VA_RESERVED_CSA_SIZE (2ULL << 20) +#define AMDGPU_VA_RESERVED_SEQ64_SIZE (2ULL << 20) +#define AMDGPU_VA_RESERVED_BOTTOM (2ULL << 20) +#define AMDGPU_VA_RESERVED_TOP (AMDGPU_VA_RESERVED_SEQ64_SIZE + \ + AMDGPU_VA_RESERVED_CSA_SIZE) /* See vm_update_mode */ #define AMDGPU_VM_USE_CPU_FOR_GFX (1 << 0) @@ -288,9 +292,12 @@ struct amdgpu_vm { /* Lock to protect vm_bo add/del/move on all lists of vm */ spinlock_t status_lock; - /* BOs who needs a validation */ + /* Per-VM and PT BOs who needs a validation */ struct list_head evicted; + /* BOs for user mode queues that need a validation */ + struct list_head evicted_user; + /* PT BOs which relocated and their parent need an update */ struct list_head relocated; @@ -434,9 +441,10 @@ int amdgpu_vm_lock_pd(struct amdgpu_vm *vm, struct drm_exec *exec, unsigned int num_fences); bool amdgpu_vm_ready(struct amdgpu_vm *vm); uint64_t amdgpu_vm_generation(struct amdgpu_device *adev, struct amdgpu_vm *vm); -int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, - int (*callback)(void *p, struct amdgpu_bo *bo), - void *param); +int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct ww_acquire_ctx *ticket, + int (*callback)(void *p, struct amdgpu_bo *bo), + void *param); int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_pipe_sync); int amdgpu_vm_update_pdes(struct amdgpu_device *adev, struct amdgpu_vm *vm, bool immediate); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 08916538a615ff3d072eb5241a97495795c7e32a..8db880244324ff1077ff3d87c20b7387ecd8b74b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -221,8 +221,23 @@ static struct attribute *amdgpu_vram_mgr_attributes[] = { NULL }; +static umode_t amdgpu_vram_attrs_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct device *dev = kobj_to_dev(kobj); + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (attr == &dev_attr_mem_info_vram_vendor.attr && + !adev->gmc.vram_vendor) + return 0; + + return attr->mode; +} + const struct attribute_group amdgpu_vram_mgr_attr_group = { - .attrs = amdgpu_vram_mgr_attributes + .attrs = amdgpu_vram_mgr_attributes, + .is_visible = amdgpu_vram_attrs_is_visible }; /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index a6c88f2fe6e5750ea42d153dcfb855046d1a5b25..20d51f6c9bb8ce06be2d79bae3e3959bd9eeb12c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -1035,15 +1035,74 @@ int amdgpu_xgmi_remove_device(struct amdgpu_device *adev) return 0; } +static int xgmi_v6_4_0_aca_bank_generate_report(struct aca_handle *handle, struct aca_bank *bank, enum aca_error_type type, + struct aca_bank_report *report, void *data) +{ + struct amdgpu_device *adev = handle->adev; + const char *error_str; + u64 status; + int ret, ext_error_code; + + ret = aca_bank_info_decode(bank, &report->info); + if (ret) + return ret; + + status = bank->regs[ACA_REG_IDX_STATUS]; + ext_error_code = ACA_REG__STATUS__ERRORCODEEXT(status); + + error_str = ext_error_code < ARRAY_SIZE(xgmi_v6_4_0_ras_error_code_ext) ? + xgmi_v6_4_0_ras_error_code_ext[ext_error_code] : NULL; + if (error_str) + dev_info(adev->dev, "%s detected\n", error_str); + + if ((type == ACA_ERROR_TYPE_UE && ext_error_code == 0) || + (type == ACA_ERROR_TYPE_CE && ext_error_code == 6)) + report->count[type] = ACA_REG__MISC0__ERRCNT(bank->regs[ACA_REG_IDX_MISC0]); + + return 0; +} + +static const struct aca_bank_ops xgmi_v6_4_0_aca_bank_ops = { + .aca_bank_generate_report = xgmi_v6_4_0_aca_bank_generate_report, +}; + +static const struct aca_info xgmi_v6_4_0_aca_info = { + .hwip = ACA_HWIP_TYPE_PCS_XGMI, + .mask = ACA_ERROR_UE_MASK | ACA_ERROR_CE_MASK, + .bank_ops = &xgmi_v6_4_0_aca_bank_ops, +}; + static int amdgpu_xgmi_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) { + int r; + if (!adev->gmc.xgmi.supported || adev->gmc.xgmi.num_physical_nodes == 0) return 0; amdgpu_ras_reset_error_count(adev, AMDGPU_RAS_BLOCK__XGMI_WAFL); - return amdgpu_ras_block_late_init(adev, ras_block); + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) + return r; + + switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) { + case IP_VERSION(6, 4, 0): + r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__XGMI_WAFL, + &xgmi_v6_4_0_aca_info, NULL); + if (r) + goto late_fini; + break; + default: + break; + } + + return 0; + +late_fini: + amdgpu_ras_block_late_fini(adev, ras_block); + + return r; } uint64_t amdgpu_xgmi_get_relative_phy_addr(struct amdgpu_device *adev, @@ -1099,7 +1158,7 @@ static void amdgpu_xgmi_legacy_reset_ras_error_count(struct amdgpu_device *adev) static void __xgmi_v6_4_0_reset_error_count(struct amdgpu_device *adev, int xgmi_inst, u64 mca_base) { - WREG64_MCA(xgmi_inst, mca_base, MCA_REG_IDX_STATUS, 0ULL); + WREG64_MCA(xgmi_inst, mca_base, ACA_REG_IDX_STATUS, 0ULL); } static void xgmi_v6_4_0_reset_error_count(struct amdgpu_device *adev, int xgmi_inst) @@ -1277,12 +1336,12 @@ static void amdgpu_xgmi_legacy_query_ras_error_count(struct amdgpu_device *adev, err_data->ce_count += ce_cnt; } -static enum amdgpu_mca_error_type xgmi_v6_4_0_pcs_mca_get_error_type(struct amdgpu_device *adev, u64 status) +static enum aca_error_type xgmi_v6_4_0_pcs_mca_get_error_type(struct amdgpu_device *adev, u64 status) { const char *error_str; int ext_error_code; - ext_error_code = MCA_REG__STATUS__ERRORCODEEXT(status); + ext_error_code = ACA_REG__STATUS__ERRORCODEEXT(status); error_str = ext_error_code < ARRAY_SIZE(xgmi_v6_4_0_ras_error_code_ext) ? xgmi_v6_4_0_ras_error_code_ext[ext_error_code] : NULL; @@ -1291,9 +1350,9 @@ static enum amdgpu_mca_error_type xgmi_v6_4_0_pcs_mca_get_error_type(struct amdg switch (ext_error_code) { case 0: - return AMDGPU_MCA_ERROR_TYPE_UE; + return ACA_ERROR_TYPE_UE; case 6: - return AMDGPU_MCA_ERROR_TYPE_CE; + return ACA_ERROR_TYPE_CE; default: return -EINVAL; } @@ -1307,22 +1366,22 @@ static void __xgmi_v6_4_0_query_error_count(struct amdgpu_device *adev, struct a int xgmi_inst = mcm_info->die_id; u64 status = 0; - status = RREG64_MCA(xgmi_inst, mca_base, MCA_REG_IDX_STATUS); - if (!MCA_REG__STATUS__VAL(status)) + status = RREG64_MCA(xgmi_inst, mca_base, ACA_REG_IDX_STATUS); + if (!ACA_REG__STATUS__VAL(status)) return; switch (xgmi_v6_4_0_pcs_mca_get_error_type(adev, status)) { - case AMDGPU_MCA_ERROR_TYPE_UE: + case ACA_ERROR_TYPE_UE: amdgpu_ras_error_statistic_ue_count(err_data, mcm_info, NULL, 1ULL); break; - case AMDGPU_MCA_ERROR_TYPE_CE: + case ACA_ERROR_TYPE_CE: amdgpu_ras_error_statistic_ce_count(err_data, mcm_info, NULL, 1ULL); break; default: break; } - WREG64_MCA(xgmi_inst, mca_base, MCA_REG_IDX_STATUS, 0ULL); + WREG64_MCA(xgmi_inst, mca_base, ACA_REG_IDX_STATUS, 0ULL); } static void xgmi_v6_4_0_query_error_count(struct amdgpu_device *adev, int xgmi_inst, struct ras_err_data *err_data) diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index a33e890c70d904a2be4f0f33cf9a194e053b70be..b888613f653f6ce34fb8c36ccc0acbabad06213e 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -62,6 +62,7 @@ typedef struct { struct atom_context *ctx; uint32_t *ps, *ws; + int ps_size, ws_size; int ps_shift; uint16_t start; unsigned last_jump; @@ -70,8 +71,8 @@ typedef struct { } atom_exec_context; int amdgpu_atom_debug; -static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params); -int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params); +static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size); +int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size); static uint32_t atom_arg_mask[8] = { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, @@ -223,7 +224,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, (*ptr)++; /* get_unaligned_le32 avoids unaligned accesses from atombios * tables, noticed on a DEC Alpha. */ - val = get_unaligned_le32((u32 *)&ctx->ps[idx]); + if (idx < ctx->ps_size) + val = get_unaligned_le32((u32 *)&ctx->ps[idx]); + else + pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size); if (print) DEBUG("PS[0x%02X,0x%04X]", idx, val); break; @@ -261,7 +265,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, val = gctx->reg_block; break; default: - val = ctx->ws[idx]; + if (idx < ctx->ws_size) + val = ctx->ws[idx]; + else + pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size); } break; case ATOM_ARG_ID: @@ -495,6 +502,10 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, idx = U8(*ptr); (*ptr)++; DEBUG("PS[0x%02X]", idx); + if (idx >= ctx->ps_size) { + pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size); + return; + } ctx->ps[idx] = cpu_to_le32(val); break; case ATOM_ARG_WS: @@ -527,6 +538,10 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, gctx->reg_block = val; break; default: + if (idx >= ctx->ws_size) { + pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size); + return; + } ctx->ws[idx] = val; } break; @@ -624,7 +639,7 @@ static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) else SDEBUG(" table: %d\n", idx); if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) - r = amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); + r = amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift, ctx->ps_size - ctx->ps_shift); if (r) { ctx->abort = true; } @@ -1203,7 +1218,7 @@ static struct { atom_op_div32, ATOM_ARG_WS}, }; -static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params) +static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size) { int base = CU16(ctx->cmd_table + 4 + 2 * index); int len, ws, ps, ptr; @@ -1225,12 +1240,16 @@ static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, ectx.ps_shift = ps / 4; ectx.start = base; ectx.ps = params; + ectx.ps_size = params_size; ectx.abort = false; ectx.last_jump = 0; - if (ws) + if (ws) { ectx.ws = kcalloc(4, ws, GFP_KERNEL); - else + ectx.ws_size = ws; + } else { ectx.ws = NULL; + ectx.ws_size = 0; + } debug_depth++; while (1) { @@ -1264,7 +1283,7 @@ free: return ret; } -int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params) +int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size) { int r; @@ -1280,7 +1299,7 @@ int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *par /* reset divmul */ ctx->divmul[0] = 0; ctx->divmul[1] = 0; - r = amdgpu_atom_execute_table_locked(ctx, index, params); + r = amdgpu_atom_execute_table_locked(ctx, index, params, params_size); mutex_unlock(&ctx->mutex); return r; } @@ -1552,7 +1571,7 @@ int amdgpu_atom_asic_init(struct atom_context *ctx) if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) return 1; - ret = amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, ps); + ret = amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, ps, 16); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/atom.h b/drivers/gpu/drm/amd/amdgpu/atom.h index c11cf18a0f182fb49203262fe524f8094c5c8efd..b807f6639a4c67c5282e5217472c6c4add7079d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.h +++ b/drivers/gpu/drm/amd/amdgpu/atom.h @@ -156,7 +156,7 @@ struct atom_context { extern int amdgpu_atom_debug; struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios); -int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params); +int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size); int amdgpu_atom_asic_init(struct atom_context *ctx); void amdgpu_atom_destroy(struct atom_context *ctx); bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c index 10098fdd33fc4723efab3448fb4b5044d72c8788..3dfc28840a7d343b865dd3f6fb93947c15cd5e7d 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c @@ -77,7 +77,7 @@ void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc, args.usOverscanTop = cpu_to_le16(amdgpu_crtc->v_border); break; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc) @@ -106,7 +106,7 @@ void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc) args.ucEnable = ATOM_SCALER_DISABLE; break; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock) @@ -123,7 +123,7 @@ void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock) args.ucCRTC = amdgpu_crtc->crtc_id; args.ucEnable = lock; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state) @@ -139,7 +139,7 @@ void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state) args.ucCRTC = amdgpu_crtc->crtc_id; args.ucEnable = state; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state) @@ -155,7 +155,7 @@ void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state) args.ucCRTC = amdgpu_crtc->crtc_id; args.ucBlanking = state; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state) @@ -171,7 +171,7 @@ void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state) args.ucDispPipeId = amdgpu_crtc->crtc_id; args.ucEnable = state; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev) @@ -183,7 +183,7 @@ void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev) args.ucEnable = ATOM_INIT; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc, @@ -228,7 +228,7 @@ void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc, args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = amdgpu_crtc->crtc_id; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } union atom_enable_ss { @@ -293,7 +293,7 @@ static void amdgpu_atombios_crtc_program_ss(struct amdgpu_device *adev, args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); args.v3.ucEnable = enable; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } union adjust_pixel_clock { @@ -395,7 +395,7 @@ static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc, ADJUST_DISPLAY_CONFIG_SS_ENABLE; amdgpu_atom_execute_table(adev->mode_info.atom_context, - index, (uint32_t *)&args); + index, (uint32_t *)&args, sizeof(args)); adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; break; case 3: @@ -428,7 +428,7 @@ static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc, args.v3.sInput.ucExtTransmitterID = 0; amdgpu_atom_execute_table(adev->mode_info.atom_context, - index, (uint32_t *)&args); + index, (uint32_t *)&args, sizeof(args)); adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; if (args.v3.sOutput.ucRefDiv) { amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV; @@ -514,7 +514,7 @@ void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev, DRM_ERROR("Unknown table version %d %d\n", frev, crev); return; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } union set_dce_clock { @@ -544,7 +544,7 @@ u32 amdgpu_atombios_crtc_set_dce_clock(struct amdgpu_device *adev, args.v2_1.asParam.ulDCEClkFreq = cpu_to_le32(freq); /* 10kHz units */ args.v2_1.asParam.ucDCEClkType = clk_type; args.v2_1.asParam.ucDCEClkSrc = clk_src; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); ret_freq = le32_to_cpu(args.v2_1.asParam.ulDCEClkFreq) * 10; break; default: @@ -740,7 +740,7 @@ void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc, return; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index 87c41e0e9b7c24794a4f502ee1a54f7eef324373..622634c08c7b56dce527b37c2d8b479abc58420c 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c @@ -83,7 +83,7 @@ static int amdgpu_atombios_dp_process_aux_ch(struct amdgpu_i2c_chan *chan, args.v2.ucDelay = delay / 10; args.v2.ucHPD_ID = chan->rec.hpd; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); *ack = args.v2.ucReplyStatus; @@ -301,7 +301,7 @@ static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev, args.ucLaneNum = lane_num; args.ucStatus = 0; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); return args.ucStatus; } diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c index 7672abe6c140c03946e5aeda86c70990d6af92d8..25feab188dfe69168f704914589bb65da65445fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c @@ -335,7 +335,7 @@ amdgpu_atombios_encoder_setup_dac(struct drm_encoder *encoder, int action) args.ucDacStandard = ATOM_DAC1_PS2; args.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10); - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } @@ -432,7 +432,7 @@ amdgpu_atombios_encoder_setup_dvo(struct drm_encoder *encoder, int action) break; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } int amdgpu_atombios_encoder_get_encoder_mode(struct drm_encoder *encoder) @@ -732,7 +732,7 @@ amdgpu_atombios_encoder_setup_dig_encoder(struct drm_encoder *encoder, break; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } @@ -1136,7 +1136,7 @@ amdgpu_atombios_encoder_setup_dig_transmitter(struct drm_encoder *encoder, int a break; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } bool @@ -1164,7 +1164,7 @@ amdgpu_atombios_encoder_set_edp_panel_power(struct drm_connector *connector, args.v1.ucAction = action; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); /* wait for the panel to power up */ if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) { @@ -1288,7 +1288,7 @@ amdgpu_atombios_encoder_setup_external_encoder(struct drm_encoder *encoder, DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); return; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } static void @@ -1633,7 +1633,7 @@ amdgpu_atombios_encoder_set_crtc_source(struct drm_encoder *encoder) return; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } /* This only needs to be called once at startup */ @@ -1706,7 +1706,7 @@ amdgpu_atombios_encoder_dac_load_detect(struct drm_encoder *encoder, args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; } - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); return true; } else diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c index af0335535f8277fb9ff1763b8c34a109b6e313bc..a6501114322fd43db12c562526b47a6f6cb23ef8 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c @@ -86,7 +86,7 @@ static int amdgpu_atombios_i2c_process_i2c_ch(struct amdgpu_i2c_chan *chan, args.ucSlaveAddr = slave_addr << 1; args.ucLineNumber = chan->rec.i2c_id; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); /* error */ if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) { @@ -172,5 +172,5 @@ void amdgpu_atombios_i2c_channel_trans(struct amdgpu_device *adev, u8 slave_addr args.ucSlaveAddr = slave_addr; args.ucLineNumber = line_number; - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c index 6f7c031dd197a22e388ddcfaed56ec75e37cafe5..f24e34dc33d1defcd70cab67f1423dffd31e8f08 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c @@ -204,6 +204,12 @@ static u32 cik_ih_get_wptr(struct amdgpu_device *adev, tmp = RREG32(mmIH_RB_CNTL); tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; WREG32(mmIH_RB_CNTL, tmp); + + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; + WREG32(mmIH_RB_CNTL, tmp); } return (wptr & ih->ptr_mask); } diff --git a/drivers/gpu/drm/amd/amdgpu/clearstate_gfx9.h b/drivers/gpu/drm/amd/amdgpu/clearstate_gfx9.h index 567a904804bc694caed08e3072128078fb4cee4f..9c85ca6358c17e44df7b6b69208fc6ff09c8157b 100644 --- a/drivers/gpu/drm/amd/amdgpu/clearstate_gfx9.h +++ b/drivers/gpu/drm/amd/amdgpu/clearstate_gfx9.h @@ -21,8 +21,7 @@ * */ -static const unsigned int gfx9_SECT_CONTEXT_def_1[] = -{ +static const unsigned int gfx9_SECT_CONTEXT_def_1[] = { 0x00000000, // DB_RENDER_CONTROL 0x00000000, // DB_COUNT_CONTROL 0x00000000, // DB_DEPTH_VIEW @@ -236,8 +235,7 @@ static const unsigned int gfx9_SECT_CONTEXT_def_1[] = 0x00000000, // PA_SC_VPORT_ZMIN_15 0x3f800000, // PA_SC_VPORT_ZMAX_15 }; -static const unsigned int gfx9_SECT_CONTEXT_def_2[] = -{ +static const unsigned int gfx9_SECT_CONTEXT_def_2[] = { 0x00000000, // PA_SC_SCREEN_EXTENT_CONTROL 0x00000000, // PA_SC_TILE_STEERING_OVERRIDE 0x00000000, // CP_PERFMON_CNTX_CNTL @@ -521,15 +519,13 @@ static const unsigned int gfx9_SECT_CONTEXT_def_2[] = 0x00000000, // CB_MRT6_EPITCH 0x00000000, // CB_MRT7_EPITCH }; -static const unsigned int gfx9_SECT_CONTEXT_def_3[] = -{ +static const unsigned int gfx9_SECT_CONTEXT_def_3[] = { 0x00000000, // PA_CL_POINT_X_RAD 0x00000000, // PA_CL_POINT_Y_RAD 0x00000000, // PA_CL_POINT_SIZE 0x00000000, // PA_CL_POINT_CULL_RAD }; -static const unsigned int gfx9_SECT_CONTEXT_def_4[] = -{ +static const unsigned int gfx9_SECT_CONTEXT_def_4[] = { 0x00000000, // DB_DEPTH_CONTROL 0x00000000, // DB_EQAA 0x00000000, // CB_COLOR_CONTROL @@ -688,17 +684,14 @@ static const unsigned int gfx9_SECT_CONTEXT_def_4[] = 0x00000000, // VGT_GS_OUT_PRIM_TYPE 0x00000000, // IA_ENHANCE }; -static const unsigned int gfx9_SECT_CONTEXT_def_5[] = -{ +static const unsigned int gfx9_SECT_CONTEXT_def_5[] = { 0x00000000, // WD_ENHANCE 0x00000000, // VGT_PRIMITIVEID_EN }; -static const unsigned int gfx9_SECT_CONTEXT_def_6[] = -{ +static const unsigned int gfx9_SECT_CONTEXT_def_6[] = { 0x00000000, // VGT_PRIMITIVEID_RESET }; -static const unsigned int gfx9_SECT_CONTEXT_def_7[] = -{ +static const unsigned int gfx9_SECT_CONTEXT_def_7[] = { 0x00000000, // VGT_GS_MAX_PRIMS_PER_SUBGROUP 0x00000000, // VGT_DRAW_PAYLOAD_CNTL 0, // HOLE @@ -766,8 +759,7 @@ static const unsigned int gfx9_SECT_CONTEXT_def_7[] = 0x00000000, // VGT_STRMOUT_CONFIG 0x00000000, // VGT_STRMOUT_BUFFER_CONFIG }; -static const unsigned int gfx9_SECT_CONTEXT_def_8[] = -{ +static const unsigned int gfx9_SECT_CONTEXT_def_8[] = { 0x00000000, // PA_SC_CENTROID_PRIORITY_0 0x00000000, // PA_SC_CENTROID_PRIORITY_1 0x00001000, // PA_SC_LINE_CNTL @@ -924,8 +916,7 @@ static const unsigned int gfx9_SECT_CONTEXT_def_8[] = 0x00000000, // CB_COLOR7_DCC_BASE 0x00000000, // CB_COLOR7_DCC_BASE_EXT }; -static const struct cs_extent_def gfx9_SECT_CONTEXT_defs[] = -{ +static const struct cs_extent_def gfx9_SECT_CONTEXT_defs[] = { {gfx9_SECT_CONTEXT_def_1, 0x0000a000, 212 }, {gfx9_SECT_CONTEXT_def_2, 0x0000a0d6, 282 }, {gfx9_SECT_CONTEXT_def_3, 0x0000a1f5, 4 }, diff --git a/drivers/gpu/drm/amd/amdgpu/clearstate_si.h b/drivers/gpu/drm/amd/amdgpu/clearstate_si.h index 66e39cdb5cb0dc5ff1fbac239c6895b825a443ed..5fd96ddd7f0fdd233e3c1db00e5b6724c2d96ab6 100644 --- a/drivers/gpu/drm/amd/amdgpu/clearstate_si.h +++ b/drivers/gpu/drm/amd/amdgpu/clearstate_si.h @@ -21,8 +21,7 @@ * */ -static const u32 si_SECT_CONTEXT_def_1[] = -{ +static const u32 si_SECT_CONTEXT_def_1[] = { 0x00000000, // DB_RENDER_CONTROL 0x00000000, // DB_COUNT_CONTROL 0x00000000, // DB_DEPTH_VIEW @@ -236,8 +235,7 @@ static const u32 si_SECT_CONTEXT_def_1[] = 0x00000000, // PA_SC_VPORT_ZMIN_15 0x3f800000, // PA_SC_VPORT_ZMAX_15 }; -static const u32 si_SECT_CONTEXT_def_2[] = -{ +static const u32 si_SECT_CONTEXT_def_2[] = { 0x00000000, // CP_PERFMON_CNTX_CNTL 0x00000000, // CP_RINGID 0x00000000, // CP_VMID @@ -511,8 +509,7 @@ static const u32 si_SECT_CONTEXT_def_2[] = 0x00000000, // CB_BLEND6_CONTROL 0x00000000, // CB_BLEND7_CONTROL }; -static const u32 si_SECT_CONTEXT_def_3[] = -{ +static const u32 si_SECT_CONTEXT_def_3[] = { 0x00000000, // PA_CL_POINT_X_RAD 0x00000000, // PA_CL_POINT_Y_RAD 0x00000000, // PA_CL_POINT_SIZE @@ -520,8 +517,7 @@ static const u32 si_SECT_CONTEXT_def_3[] = 0x00000000, // VGT_DMA_BASE_HI 0x00000000, // VGT_DMA_BASE }; -static const u32 si_SECT_CONTEXT_def_4[] = -{ +static const u32 si_SECT_CONTEXT_def_4[] = { 0x00000000, // DB_DEPTH_CONTROL 0x00000000, // DB_EQAA 0x00000000, // CB_COLOR_CONTROL @@ -680,16 +676,13 @@ static const u32 si_SECT_CONTEXT_def_4[] = 0x00000000, // VGT_GS_OUT_PRIM_TYPE 0x00000000, // IA_ENHANCE }; -static const u32 si_SECT_CONTEXT_def_5[] = -{ +static const u32 si_SECT_CONTEXT_def_5[] = { 0x00000000, // VGT_PRIMITIVEID_EN }; -static const u32 si_SECT_CONTEXT_def_6[] = -{ +static const u32 si_SECT_CONTEXT_def_6[] = { 0x00000000, // VGT_PRIMITIVEID_RESET }; -static const u32 si_SECT_CONTEXT_def_7[] = -{ +static const u32 si_SECT_CONTEXT_def_7[] = { 0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN 0, // HOLE 0, // HOLE @@ -924,8 +917,7 @@ static const u32 si_SECT_CONTEXT_def_7[] = 0x00000000, // CB_COLOR7_CLEAR_WORD0 0x00000000, // CB_COLOR7_CLEAR_WORD1 }; -static const struct cs_extent_def si_SECT_CONTEXT_defs[] = -{ +static const struct cs_extent_def si_SECT_CONTEXT_defs[] = { {si_SECT_CONTEXT_def_1, 0x0000a000, 212 }, {si_SECT_CONTEXT_def_2, 0x0000a0d8, 272 }, {si_SECT_CONTEXT_def_3, 0x0000a1f5, 6 }, diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c index b8c47e0cf37ad53bcb3f1afe161e6356b91789e3..c19681492efa748bf7b5d92864dbdc61c0351520 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c @@ -216,6 +216,11 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev, tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); WREG32(mmIH_RB_CNTL, tmp); + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + WREG32(mmIH_RB_CNTL, tmp); out: return (wptr & ih->ptr_mask); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 587ee632a3b8fddb2a99cb54d0f246f0e1b1ffd0..221af054d8746994fc823ff2547255133c7d092e 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -52,6 +52,7 @@ static void dce_v10_0_set_display_funcs(struct amdgpu_device *adev); static void dce_v10_0_set_irq_funcs(struct amdgpu_device *adev); +static void dce_v10_0_hpd_int_ack(struct amdgpu_device *adev, int hpd); static const u32 crtc_offsets[] = { CRTC0_REGISTER_OFFSET, @@ -364,6 +365,7 @@ static void dce_v10_0_hpd_init(struct amdgpu_device *adev) AMDGPU_HPD_DISCONNECT_INT_DELAY_IN_MS); WREG32(mmDC_HPD_TOGGLE_FILT_CNTL + hpd_offsets[amdgpu_connector->hpd.hpd], tmp); + dce_v10_0_hpd_int_ack(adev, amdgpu_connector->hpd.hpd); dce_v10_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd); amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index f22ec27365bd251aa448d6b36b199becbe29598f..69e8b0db6cf7023d8ee3a763eda90be938c73ec5 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -52,6 +52,7 @@ static void dce_v11_0_set_display_funcs(struct amdgpu_device *adev); static void dce_v11_0_set_irq_funcs(struct amdgpu_device *adev); +static void dce_v11_0_hpd_int_ack(struct amdgpu_device *adev, int hpd); static const u32 crtc_offsets[] = { @@ -388,6 +389,7 @@ static void dce_v11_0_hpd_init(struct amdgpu_device *adev) AMDGPU_HPD_DISCONNECT_INT_DELAY_IN_MS); WREG32(mmDC_HPD_TOGGLE_FILT_CNTL + hpd_offsets[amdgpu_connector->hpd.hpd], tmp); + dce_v11_0_hpd_int_ack(adev, amdgpu_connector->hpd.hpd); dce_v11_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd); amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd); } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 4dbe9b3259b50dc62bb131442010f235e587759e..60d40201fdd17730f43ce9fe3394958c5a8cac64 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -273,6 +273,21 @@ static void dce_v6_0_hpd_set_polarity(struct amdgpu_device *adev, WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); } +static void dce_v6_0_hpd_int_ack(struct amdgpu_device *adev, + int hpd) +{ + u32 tmp; + + if (hpd >= adev->mode_info.num_hpd) { + DRM_DEBUG("invalid hdp %d\n", hpd); + return; + } + + tmp = RREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd]); + tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; + WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); +} + /** * dce_v6_0_hpd_init - hpd setup callback. * @@ -312,6 +327,7 @@ static void dce_v6_0_hpd_init(struct amdgpu_device *adev) continue; } + dce_v6_0_hpd_int_ack(adev, amdgpu_connector->hpd.hpd); dce_v6_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd); amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd); } @@ -3089,7 +3105,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - uint32_t disp_int, mask, tmp; + uint32_t disp_int, mask; unsigned hpd; if (entry->src_data[0] >= adev->mode_info.num_hpd) { @@ -3102,9 +3118,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev, mask = interrupt_status_offsets[hpd].hpd; if (disp_int & mask) { - tmp = RREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd]); - tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; - WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); + dce_v6_0_hpd_int_ack(adev, hpd); schedule_delayed_work(&adev->hotplug_work, 0); DRM_DEBUG("IH: HPD%d\n", hpd + 1); } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 05bcce23385ec08e2ec8e424e865382794de405b..5a5fcc45e452102bcfa83772b4ab3d85337b5e36 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -265,6 +265,21 @@ static void dce_v8_0_hpd_set_polarity(struct amdgpu_device *adev, WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); } +static void dce_v8_0_hpd_int_ack(struct amdgpu_device *adev, + int hpd) +{ + u32 tmp; + + if (hpd >= adev->mode_info.num_hpd) { + DRM_DEBUG("invalid hdp %d\n", hpd); + return; + } + + tmp = RREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd]); + tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; + WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); +} + /** * dce_v8_0_hpd_init - hpd setup callback. * @@ -304,6 +319,7 @@ static void dce_v8_0_hpd_init(struct amdgpu_device *adev) continue; } + dce_v8_0_hpd_int_ack(adev, amdgpu_connector->hpd.hpd); dce_v8_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd); amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd); } @@ -3177,7 +3193,7 @@ static int dce_v8_0_hpd_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - uint32_t disp_int, mask, tmp; + uint32_t disp_int, mask; unsigned hpd; if (entry->src_data[0] >= adev->mode_info.num_hpd) { @@ -3190,9 +3206,7 @@ static int dce_v8_0_hpd_irq(struct amdgpu_device *adev, mask = interrupt_status_offsets[hpd].hpd; if (disp_int & mask) { - tmp = RREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd]); - tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; - WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); + dce_v8_0_hpd_int_ack(adev, hpd); schedule_delayed_work(&adev->hotplug_work, 0); DRM_DEBUG("IH: HPD%d\n", hpd + 1); } diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index d63cab294883b8b44caa908d5bafaeaf19750ef6..b02d63328f1cd937063cc031f553c4c44e2d4e9c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -4027,8 +4027,6 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) err = 0; adev->gfx.mec2_fw = NULL; } - amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2); - amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT); gfx_v10_0_check_fw_write_wait(adev); out: @@ -6589,7 +6587,7 @@ static int gfx_v10_0_compute_mqd_init(struct amdgpu_device *adev, void *m, #ifdef __BIG_ENDIAN tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, ENDIAN_SWAP, 1); #endif - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, prop->allow_tunneling); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); @@ -7949,7 +7947,7 @@ static void gfx_v10_0_update_spm_vmid_internal(struct amdgpu_device *adev, WREG32_SOC15_NO_KIQ(GC, 0, mmRLC_SPM_MC_CNTL, data); } -static void gfx_v10_0_update_spm_vmid(struct amdgpu_device *adev, unsigned int vmid) +static void gfx_v10_0_update_spm_vmid(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned int vmid) { amdgpu_gfx_off_ctrl(adev, false); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 0ea0866c261f84e24e8494755387b3d22482a0a2..2fb1342d5bd93b3659f31d7ae7207c44d3d76515 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -107,23 +107,6 @@ static const struct soc15_reg_golden golden_settings_gc_11_0_1[] = SOC15_REG_GOLDEN_VALUE(GC, 0, regTCP_CNTL2, 0xfcffffff, 0x0000000a) }; -static const struct soc15_reg_golden golden_settings_gc_11_5_0[] = { - SOC15_REG_GOLDEN_VALUE(GC, 0, regDB_DEBUG5, 0xffffffff, 0x00000800), - SOC15_REG_GOLDEN_VALUE(GC, 0, regGB_ADDR_CONFIG, 0x0c1807ff, 0x00000242), - SOC15_REG_GOLDEN_VALUE(GC, 0, regGCR_GENERAL_CNTL, 0x1ff1ffff, 0x00000500), - SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2A_ADDR_MATCH_MASK, 0xffffffff, 0xfffffff3), - SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_ADDR_MATCH_MASK, 0xffffffff, 0xfffffff3), - SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL, 0xffffffff, 0xf37fff3f), - SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL3, 0xfffffffb, 0x00f40188), - SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL4, 0xf0ffffff, 0x80009007), - SOC15_REG_GOLDEN_VALUE(GC, 0, regPA_CL_ENHANCE, 0xf1ffffff, 0x00880007), - SOC15_REG_GOLDEN_VALUE(GC, 0, regPC_CONFIG_CNTL_1, 0xffffffff, 0x00010000), - SOC15_REG_GOLDEN_VALUE(GC, 0, regTA_CNTL_AUX, 0xf7f7ffff, 0x01030000), - SOC15_REG_GOLDEN_VALUE(GC, 0, regTA_CNTL2, 0x007f0000, 0x00000000), - SOC15_REG_GOLDEN_VALUE(GC, 0, regTCP_CNTL2, 0xffcfffff, 0x0000200a), - SOC15_REG_GOLDEN_VALUE(GC, 0, regUTCL1_CTRL_2, 0xffffffff, 0x0000048f) -}; - #define DEFAULT_SH_MEM_CONFIG \ ((SH_MEM_ADDRESS_MODE_64 << SH_MEM_CONFIG__ADDRESS_MODE__SHIFT) | \ (SH_MEM_ALIGNMENT_MODE_UNALIGNED << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) | \ @@ -304,11 +287,6 @@ static void gfx_v11_0_init_golden_registers(struct amdgpu_device *adev) golden_settings_gc_11_0_1, (const u32)ARRAY_SIZE(golden_settings_gc_11_0_1)); break; - case IP_VERSION(11, 5, 0): - soc15_program_register_sequence(adev, - golden_settings_gc_11_5_0, - (const u32)ARRAY_SIZE(golden_settings_gc_11_5_0)); - break; default: break; } @@ -749,7 +727,7 @@ static int gfx_v11_0_rlc_init(struct amdgpu_device *adev) /* init spm vmid with 0xf */ if (adev->gfx.rlc.funcs->update_spm_vmid) - adev->gfx.rlc.funcs->update_spm_vmid(adev, 0xf); + adev->gfx.rlc.funcs->update_spm_vmid(adev, NULL, 0xf); return 0; } @@ -3846,7 +3824,7 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m, (order_base_2(prop->queue_size / 4) - 1)); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE, (order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1)); - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, prop->allow_tunneling); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); @@ -5049,7 +5027,7 @@ static int gfx_v11_0_update_gfx_clock_gating(struct amdgpu_device *adev, return 0; } -static void gfx_v11_0_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) +static void gfx_v11_0_update_spm_vmid(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned vmid) { u32 data; @@ -5063,6 +5041,14 @@ static void gfx_v11_0_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) WREG32_SOC15_NO_KIQ(GC, 0, regRLC_SPM_MC_CNTL, data); amdgpu_gfx_off_ctrl(adev, true); + + if (ring + && amdgpu_sriov_is_pp_one_vf(adev) + && ((ring->funcs->type == AMDGPU_RING_TYPE_GFX) + || (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE))) { + uint32_t reg = SOC15_REG_OFFSET(GC, 0, regRLC_SPM_MC_CNTL); + amdgpu_ring_emit_wreg(ring, reg, data); + } } static const struct amdgpu_rlc_funcs gfx_v11_0_rlc_funcs = { @@ -6126,7 +6112,8 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = { .get_rptr = gfx_v11_0_ring_get_rptr_gfx, .get_wptr = gfx_v11_0_ring_get_wptr_gfx, .set_wptr = gfx_v11_0_ring_set_wptr_gfx, - .emit_frame_size = /* totally 242 maximum if 16 IBs */ + .emit_frame_size = /* totally 247 maximum if 16 IBs */ + 5 + /* update_spm_vmid */ 5 + /* COND_EXEC */ 9 + /* SET_Q_PREEMPTION_MODE */ 7 + /* PIPELINE_SYNC */ @@ -6176,6 +6163,7 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_compute = { .get_wptr = gfx_v11_0_ring_get_wptr_compute, .set_wptr = gfx_v11_0_ring_set_wptr_compute, .emit_frame_size = + 5 + /* update_spm_vmid */ 20 + /* gfx_v11_0_ring_emit_gds_switch */ 7 + /* gfx_v11_0_ring_emit_hdp_flush */ 5 + /* hdp invalidate */ diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c index 26d6286d86c9991f98c1ace2b9becb54eadeeae3..9e7ce1e6bc0613cda09a142e747344ea96877220 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c @@ -69,7 +69,7 @@ static int gfx_v11_0_3_rlc_gc_fed_irq(struct amdgpu_device *adev, amdgpu_ras_interrupt_dispatch(adev, &ih_data); } else { if (adev->virt.ops && adev->virt.ops->ras_poison_handler) - adev->virt.ops->ras_poison_handler(adev); + adev->virt.ops->ras_poison_handler(adev, ras_if->block); else dev_warn(adev->dev, "No ras_poison_handler interface in SRIOV for %s!\n", ras_if->name); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index c2faf6b4c2fced463cc24598cf10c9775a9663ee..86a4865b1ae54400cb3be21c8e68d84dde618183 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -3274,7 +3274,7 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev) /* init spm vmid with 0xf */ if (adev->gfx.rlc.funcs->update_spm_vmid) - adev->gfx.rlc.funcs->update_spm_vmid(adev, 0xf); + adev->gfx.rlc.funcs->update_spm_vmid(adev, NULL, 0xf); return 0; } @@ -3500,7 +3500,7 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev) return 0; } -static void gfx_v7_0_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) +static void gfx_v7_0_update_spm_vmid(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned vmid) { u32 data; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 1943beb135c4c2923c211c5727afbd16141ac718..ea174b76ee7008439ba3a6f03c5076a1bc2b3a77 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1288,7 +1288,7 @@ static int gfx_v8_0_rlc_init(struct amdgpu_device *adev) /* init spm vmid with 0xf */ if (adev->gfx.rlc.funcs->update_spm_vmid) - adev->gfx.rlc.funcs->update_spm_vmid(adev, 0xf); + adev->gfx.rlc.funcs->update_spm_vmid(adev, NULL, 0xf); return 0; } @@ -5579,7 +5579,7 @@ static void gfx_v8_0_unset_safe_mode(struct amdgpu_device *adev, int xcc_id) } } -static void gfx_v8_0_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) +static void gfx_v8_0_update_spm_vmid(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned vmid) { u32 data; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 69c500910746018281471ad6d27350aaf2461702..169d45268ef6d50bd5b191b91cc4fa4bb086649f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3034,6 +3034,14 @@ static int gfx_v9_0_cp_gfx_start(struct amdgpu_device *adev) gfx_v9_0_cp_gfx_enable(adev, true); + /* Now only limit the quirk on the APU gfx9 series and already + * confirmed that the APU gfx10/gfx11 needn't such update. + */ + if (adev->flags & AMD_IS_APU && + adev->in_s3 && !adev->suspend_complete) { + DRM_INFO(" Will skip the CSB packet resubmit\n"); + return 0; + } r = amdgpu_ring_alloc(ring, gfx_v9_0_get_csb_size(adev) + 4 + 3); if (r) { DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r); @@ -4894,7 +4902,7 @@ static void gfx_v9_0_update_spm_vmid_internal(struct amdgpu_device *adev, WREG32_SOC15(GC, 0, mmRLC_SPM_MC_CNTL, data); } -static void gfx_v9_0_update_spm_vmid(struct amdgpu_device *adev, unsigned int vmid) +static void gfx_v9_0_update_spm_vmid(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned int vmid) { amdgpu_gfx_off_ctrl(adev, false); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c index bc8416afb62c5d5530ebea5b828b06f2974ed47c..f53b379d897141607f34b0ad47351cfda835c9b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c @@ -970,8 +970,9 @@ static void gfx_v9_4_reset_ras_error_count(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, mmATC_L2_CACHE_4K_DSM_INDEX, 255); } -static const struct soc15_reg_entry gfx_v9_4_ea_err_status_regs = - { SOC15_REG_ENTRY(GC, 0, mmGCEA_ERR_STATUS), 0, 1, 32 }; +static const struct soc15_reg_entry gfx_v9_4_ea_err_status_regs = { + SOC15_REG_ENTRY(GC, 0, mmGCEA_ERR_STATUS), 0, 1, 32 +}; static void gfx_v9_4_query_ras_error_status(struct amdgpu_device *adev) { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 131cddbdda0dc11716205307e51d72aa72b271bf..aace4594a603b85450450293036c618f0dc776fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -38,6 +38,7 @@ #include "gfx_v9_4_3.h" #include "amdgpu_xcp.h" +#include "amdgpu_aca.h" MODULE_FIRMWARE("amdgpu/gc_9_4_3_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_9_4_3_rlc.bin"); @@ -48,6 +49,10 @@ MODULE_FIRMWARE("amdgpu/gc_9_4_3_rlc.bin"); #define GOLDEN_GB_ADDR_CONFIG 0x2a114042 #define CP_HQD_PERSISTENT_STATE_DEFAULT 0xbe05301 +#define mmSMNAID_XCD0_MCA_SMU 0x36430400 /* SMN AID XCD0 */ +#define mmSMNAID_XCD1_MCA_SMU 0x38430400 /* SMN AID XCD1 */ +#define mmSMNXCD_XCD0_MCA_SMU 0x40430400 /* SMN XCD XCD0 */ + struct amdgpu_gfx_ras gfx_v9_4_3_ras; static void gfx_v9_4_3_set_ring_funcs(struct amdgpu_device *adev); @@ -675,6 +680,66 @@ static const struct amdgpu_gfx_funcs gfx_v9_4_3_gfx_funcs = { .ih_node_to_logical_xcc = &gfx_v9_4_3_ih_to_xcc_inst, }; +static int gfx_v9_4_3_aca_bank_generate_report(struct aca_handle *handle, + struct aca_bank *bank, enum aca_error_type type, + struct aca_bank_report *report, void *data) +{ + u64 status, misc0; + u32 instlo; + int ret; + + status = bank->regs[ACA_REG_IDX_STATUS]; + if ((type == ACA_ERROR_TYPE_UE && + ACA_REG__STATUS__ERRORCODEEXT(status) == ACA_EXTERROR_CODE_FAULT) || + (type == ACA_ERROR_TYPE_CE && + ACA_REG__STATUS__ERRORCODEEXT(status) == ACA_EXTERROR_CODE_CE)) { + + ret = aca_bank_info_decode(bank, &report->info); + if (ret) + return ret; + + /* NOTE: overwrite info.die_id with xcd id for gfx */ + instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); + instlo &= GENMASK(31, 1); + report->info.die_id = instlo == mmSMNAID_XCD0_MCA_SMU ? 0 : 1; + + misc0 = bank->regs[ACA_REG_IDX_MISC0]; + report->count[type] = ACA_REG__MISC0__ERRCNT(misc0); + } + + return 0; +} + +static bool gfx_v9_4_3_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, + enum aca_error_type type, void *data) +{ + u32 instlo; + + instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); + instlo &= GENMASK(31, 1); + switch (instlo) { + case mmSMNAID_XCD0_MCA_SMU: + case mmSMNAID_XCD1_MCA_SMU: + case mmSMNXCD_XCD0_MCA_SMU: + return true; + default: + break; + } + + return false; +} + +static const struct aca_bank_ops gfx_v9_4_3_aca_bank_ops = { + .aca_bank_generate_report = gfx_v9_4_3_aca_bank_generate_report, + .aca_bank_is_valid = gfx_v9_4_3_aca_bank_is_valid, +}; + +static const struct aca_info gfx_v9_4_3_aca_info = { + .hwip = ACA_HWIP_TYPE_SMU, + .mask = ACA_ERROR_UE_MASK | ACA_ERROR_CE_MASK, + .bank_ops = &gfx_v9_4_3_aca_bank_ops, +}; + static int gfx_v9_4_3_gpu_early_init(struct amdgpu_device *adev) { u32 gb_addr_config; @@ -1109,7 +1174,7 @@ static int gfx_v9_4_3_rlc_init(struct amdgpu_device *adev) { /* init spm vmid with 0xf */ if (adev->gfx.rlc.funcs->update_spm_vmid) - adev->gfx.rlc.funcs->update_spm_vmid(adev, 0xf); + adev->gfx.rlc.funcs->update_spm_vmid(adev, NULL, 0xf); return 0; } @@ -1320,7 +1385,7 @@ static int gfx_v9_4_3_rlc_resume(struct amdgpu_device *adev) return 0; } -static void gfx_v9_4_3_update_spm_vmid(struct amdgpu_device *adev, +static void gfx_v9_4_3_update_spm_vmid(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned vmid) { u32 reg, data; @@ -4242,9 +4307,32 @@ struct amdgpu_ras_block_hw_ops gfx_v9_4_3_ras_ops = { .reset_ras_error_count = &gfx_v9_4_3_reset_ras_error_count, }; +static int gfx_v9_4_3_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) +{ + int r; + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) + return r; + + r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__GFX, + &gfx_v9_4_3_aca_info, + NULL); + if (r) + goto late_fini; + + return 0; + +late_fini: + amdgpu_ras_block_late_fini(adev, ras_block); + + return r; +} + struct amdgpu_gfx_ras gfx_v9_4_3_ras = { .ras_block = { .hw_ops = &gfx_v9_4_3_ras_ops, + .ras_late_init = &gfx_v9_4_3_ras_late_init, }, .enable_watchdog_timer = &gfx_v9_4_3_enable_watchdog_timer, }; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index 6c51856088546faed3c2e3d9376f8c23d54ba554..db89d13bd80db6dbe769b2d59fc736a4b51f63fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -262,16 +262,17 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, /* flush hdp cache */ adev->hdp.funcs->flush_hdp(adev, NULL); - /* For SRIOV run time, driver shouldn't access the register through MMIO - * Directly use kiq to do the vm invalidation instead + /* This is necessary for SRIOV as well as for GFXOFF to function + * properly under bare metal */ if (adev->gfx.kiq[0].ring.sched.ready && !adev->enable_mes && (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev))) { - amdgpu_virt_kiq_reg_write_reg_wait(adev, req, ack, inv_req, - 1 << vmid, GET_INST(GC, 0)); + amdgpu_gmc_fw_reg_write_reg_wait(adev, req, ack, inv_req, + 1 << vmid, GET_INST(GC, 0)); return; } + /* This path is needed before KIQ/MES/GFXOFF are set up */ hub_ip = (vmhub == AMDGPU_GFXHUB(0)) ? GC_HWIP : MMHUB_HWIP; spin_lock(&adev->gmc.invalidate_lock); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index c9c653cfc765b8b88e5ab1f77cefcbbce38ff79c..6c68135cac9f021f522089345043474882b00d1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -223,16 +223,17 @@ static void gmc_v11_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, /* flush hdp cache */ adev->hdp.funcs->flush_hdp(adev, NULL); - /* For SRIOV run time, driver shouldn't access the register through MMIO - * Directly use kiq to do the vm invalidation instead + /* This is necessary for SRIOV as well as for GFXOFF to function + * properly under bare metal */ if ((adev->gfx.kiq[0].ring.sched.ready || adev->mes.ring.sched.ready) && (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev))) { - amdgpu_virt_kiq_reg_write_reg_wait(adev, req, ack, inv_req, - 1 << vmid, GET_INST(GC, 0)); + amdgpu_gmc_fw_reg_write_reg_wait(adev, req, ack, inv_req, + 1 << vmid, GET_INST(GC, 0)); return; } + /* This path is needed before KIQ/MES/GFXOFF are set up */ hub_ip = (vmhub == AMDGPU_GFXHUB(0)) ? GC_HWIP : MMHUB_HWIP; spin_lock(&adev->gmc.invalidate_lock); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 42e103d7077d52d5bbe556f70f2b03bb0d5ae8db..23b478639921a39ecd67fbcdc183fde331585ea5 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -435,9 +435,10 @@ static void gmc_v6_0_set_prt(struct amdgpu_device *adev, bool enable) WREG32(mmVM_PRT_CNTL, tmp); if (enable) { - uint32_t low = AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT; + uint32_t low = AMDGPU_VA_RESERVED_BOTTOM >> + AMDGPU_GPU_PAGE_SHIFT; uint32_t high = adev->vm_manager.max_pfn - - (AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT); + (AMDGPU_VA_RESERVED_TOP >> AMDGPU_GPU_PAGE_SHIFT); WREG32(mmVM_PRT_APERTURE0_LOW_ADDR, low); WREG32(mmVM_PRT_APERTURE1_LOW_ADDR, low); @@ -915,8 +916,8 @@ static int gmc_v6_0_hw_init(void *handle) if (amdgpu_emu_mode == 1) return amdgpu_gmc_vram_checking(adev); - else - return r; + + return 0; } static int gmc_v6_0_hw_fini(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index efc16e580f1e27e384b7c80323c72d0e59fba473..3da7b6a2b00d29113bacf770c9918efa9f2408ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -563,9 +563,10 @@ static void gmc_v7_0_set_prt(struct amdgpu_device *adev, bool enable) WREG32(mmVM_PRT_CNTL, tmp); if (enable) { - uint32_t low = AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT; + uint32_t low = AMDGPU_VA_RESERVED_BOTTOM >> + AMDGPU_GPU_PAGE_SHIFT; uint32_t high = adev->vm_manager.max_pfn - - (AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT); + (AMDGPU_VA_RESERVED_TOP >> AMDGPU_GPU_PAGE_SHIFT); WREG32(mmVM_PRT_APERTURE0_LOW_ADDR, low); WREG32(mmVM_PRT_APERTURE1_LOW_ADDR, low); @@ -1099,8 +1100,8 @@ static int gmc_v7_0_hw_init(void *handle) if (amdgpu_emu_mode == 1) return amdgpu_gmc_vram_checking(adev); - else - return r; + + return 0; } static int gmc_v7_0_hw_fini(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index ff4ae73d27ecd26aaf399bdfe158e22c1de3009f..969a9e8671703f51b8b79b4ea486822822e604fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -777,9 +777,10 @@ static void gmc_v8_0_set_prt(struct amdgpu_device *adev, bool enable) WREG32(mmVM_PRT_CNTL, tmp); if (enable) { - uint32_t low = AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT; + uint32_t low = AMDGPU_VA_RESERVED_BOTTOM >> + AMDGPU_GPU_PAGE_SHIFT; uint32_t high = adev->vm_manager.max_pfn - - (AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT); + (AMDGPU_VA_RESERVED_TOP >> AMDGPU_GPU_PAGE_SHIFT); WREG32(mmVM_PRT_APERTURE0_LOW_ADDR, low); WREG32(mmVM_PRT_APERTURE1_LOW_ADDR, low); @@ -1219,8 +1220,8 @@ static int gmc_v8_0_hw_init(void *handle) if (amdgpu_emu_mode == 1) return amdgpu_gmc_vram_checking(adev); - else - return r; + + return 0; } static int gmc_v8_0_hw_fini(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index f9039d64ff2d72804556daa16b8ed9632b08b307..d442ae85162db5ff8c269969efa4b9c963d33382 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -829,23 +829,25 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, req = hub->vm_inv_eng0_req + hub->eng_distance * eng; ack = hub->vm_inv_eng0_ack + hub->eng_distance * eng; - /* This is necessary for a HW workaround under SRIOV as well - * as GFXOFF under bare metal - */ if (vmhub >= AMDGPU_MMHUB0(0)) inst = GET_INST(GC, 0); else inst = vmhub; + + /* This is necessary for SRIOV as well as for GFXOFF to function + * properly under bare metal + */ if (adev->gfx.kiq[inst].ring.sched.ready && (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev))) { uint32_t req = hub->vm_inv_eng0_req + hub->eng_distance * eng; uint32_t ack = hub->vm_inv_eng0_ack + hub->eng_distance * eng; - amdgpu_virt_kiq_reg_write_reg_wait(adev, req, ack, inv_req, - 1 << vmid, inst); + amdgpu_gmc_fw_reg_write_reg_wait(adev, req, ack, inv_req, + 1 << vmid, inst); return; } + /* This path is needed before KIQ/MES/GFXOFF are set up */ spin_lock(&adev->gmc.invalidate_lock); /* @@ -1947,13 +1949,6 @@ static int gmc_v9_0_init_mem_ranges(struct amdgpu_device *adev) static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev) { - static const u32 regBIF_BIOS_SCRATCH_4 = 0x50; - u32 vram_info; - - if (!amdgpu_sriov_vf(adev)) { - vram_info = RREG32(regBIF_BIOS_SCRATCH_4); - adev->gmc.vram_vendor = vram_info & 0xF; - } adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM; adev->gmc.vram_width = 128 * 64; } @@ -2340,8 +2335,8 @@ static int gmc_v9_0_hw_init(void *handle) if (amdgpu_emu_mode == 1) return amdgpu_gmc_vram_checking(adev); - else - return r; + + return 0; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c index aecad530b10a61289f9e2413612bbf58a33cec22..2c02ae69883d2bb86bec8e1d1fb521f8481d7ebb 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c @@ -215,6 +215,11 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev, tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); WREG32(mmIH_RB_CNTL, tmp); + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + WREG32(mmIH_RB_CNTL, tmp); out: return (wptr & ih->ptr_mask); diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c index d9ed7332d805d3fca1bd0343ebc804e69dc44595..ad4ad39f128f7d7f788a866d36cc7c8175743b5d 100644 --- a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c @@ -418,6 +418,12 @@ static u32 ih_v6_0_get_wptr(struct amdgpu_device *adev, tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); out: return (wptr & ih->ptr_mask); } diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c index 8fb05eae340ad298653afaca4edccfce86741c84..b8da0fc29378c496ba0392e10105d1c58d53bf5a 100644 --- a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c +++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c @@ -418,6 +418,13 @@ static u32 ih_v6_1_get_wptr(struct amdgpu_device *adev, tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + out: return (wptr & ih->ptr_mask); } diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c index e67a337457edad3b12bc1c822f46c00e8fd32c9d..99cd49ee8ef6e48c3488888622af9256a0bd44dc 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c @@ -551,7 +551,7 @@ static int jpeg_v2_5_set_powergating_state(void *handle, struct amdgpu_device *adev = (struct amdgpu_device *)handle; int ret; - if(state == adev->jpeg.cur_state) + if (state == adev->jpeg.cur_state) return 0; if (state == AMD_PG_STATE_GATE) @@ -559,7 +559,7 @@ static int jpeg_v2_5_set_powergating_state(void *handle, else ret = jpeg_v2_5_start(adev); - if(!ret) + if (!ret) adev->jpeg.cur_state = state; return ret; @@ -754,8 +754,7 @@ static void jpeg_v2_5_set_irq_funcs(struct amdgpu_device *adev) } } -const struct amdgpu_ip_block_version jpeg_v2_5_ip_block = -{ +const struct amdgpu_ip_block_version jpeg_v2_5_ip_block = { .type = AMD_IP_BLOCK_TYPE_JPEG, .major = 2, .minor = 5, @@ -763,8 +762,7 @@ const struct amdgpu_ip_block_version jpeg_v2_5_ip_block = .funcs = &jpeg_v2_5_ip_funcs, }; -const struct amdgpu_ip_block_version jpeg_v2_6_ip_block = -{ +const struct amdgpu_ip_block_version jpeg_v2_6_ip_block = { .type = AMD_IP_BLOCK_TYPE_JPEG, .major = 2, .minor = 6, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c index bc38b90f8cf88e8fee393e8e52214ac72f0aa8a6..88ea58d5c4abf5b0f20abff28f9833f402e4b016 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c @@ -674,14 +674,6 @@ static int jpeg_v4_0_set_powergating_state(void *handle, return ret; } -static int jpeg_v4_0_set_interrupt_state(struct amdgpu_device *adev, - struct amdgpu_irq_src *source, - unsigned type, - enum amdgpu_interrupt_state state) -{ - return 0; -} - static int jpeg_v4_0_set_ras_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned int type, @@ -765,7 +757,6 @@ static void jpeg_v4_0_set_dec_ring_funcs(struct amdgpu_device *adev) } static const struct amdgpu_irq_src_funcs jpeg_v4_0_irq_funcs = { - .set = jpeg_v4_0_set_interrupt_state, .process = jpeg_v4_0_process_interrupt, }; diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c index 6ede85b28cc8c0bbfd6a7e94c6a3d1a677e958bf..78b74daf4eebfc30f04ee4aaf6d0ff92891ff30f 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c @@ -181,7 +181,6 @@ static int jpeg_v4_0_5_hw_fini(void *handle) RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS)) jpeg_v4_0_5_set_powergating_state(adev, AMD_PG_STATE_GATE); } - amdgpu_irq_put(adev, &adev->jpeg.inst->irq, 0); return 0; } @@ -516,14 +515,6 @@ static int jpeg_v4_0_5_set_powergating_state(void *handle, return ret; } -static int jpeg_v4_0_5_set_interrupt_state(struct amdgpu_device *adev, - struct amdgpu_irq_src *source, - unsigned type, - enum amdgpu_interrupt_state state) -{ - return 0; -} - static int jpeg_v4_0_5_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -603,7 +594,6 @@ static void jpeg_v4_0_5_set_dec_ring_funcs(struct amdgpu_device *adev) } static const struct amdgpu_irq_src_funcs jpeg_v4_0_5_irq_funcs = { - .set = jpeg_v4_0_5_set_interrupt_state, .process = jpeg_v4_0_5_process_interrupt, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c index fb53aacdcba20f01019a20d63c7bb07d60e1e8d1..c0fc44cdd6581c1d8722007b2ec474aa79c39030 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c @@ -33,6 +33,7 @@ #define regVM_L2_CNTL3_DEFAULT 0x80100007 #define regVM_L2_CNTL4_DEFAULT 0x000000c1 +#define mmSMNAID_AID0_MCA_SMU 0x03b30400 static u64 mmhub_v1_8_get_fb_location(struct amdgpu_device *adev) { @@ -705,8 +706,94 @@ static const struct amdgpu_ras_block_hw_ops mmhub_v1_8_ras_hw_ops = { .reset_ras_error_count = mmhub_v1_8_reset_ras_error_count, }; +static int mmhub_v1_8_aca_bank_generate_report(struct aca_handle *handle, + struct aca_bank *bank, enum aca_error_type type, + struct aca_bank_report *report, void *data) +{ + u64 status, misc0; + int ret; + + status = bank->regs[ACA_REG_IDX_STATUS]; + if ((type == ACA_ERROR_TYPE_UE && + ACA_REG__STATUS__ERRORCODEEXT(status) == ACA_EXTERROR_CODE_FAULT) || + (type == ACA_ERROR_TYPE_CE && + ACA_REG__STATUS__ERRORCODEEXT(status) == ACA_EXTERROR_CODE_CE)) { + + ret = aca_bank_info_decode(bank, &report->info); + if (ret) + return ret; + + misc0 = bank->regs[ACA_REG_IDX_MISC0]; + report->count[type] = ACA_REG__MISC0__ERRCNT(misc0); + } + + return 0; +} + +/* reference to smu driver if header file */ +static int mmhub_v1_8_err_codes[] = { + 0, 1, 2, 3, 4, /* CODE_DAGB0 - 4 */ + 5, 6, 7, 8, 9, /* CODE_EA0 - 4 */ + 10, /* CODE_UTCL2_ROUTER */ + 11, /* CODE_VML2 */ + 12, /* CODE_VML2_WALKER */ + 13, /* CODE_MMCANE */ +}; + +static bool mmhub_v1_8_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, + enum aca_error_type type, void *data) +{ + u32 instlo; + + instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); + instlo &= GENMASK(31, 1); + + if (instlo != mmSMNAID_AID0_MCA_SMU) + return false; + + if (aca_bank_check_error_codes(handle->adev, bank, + mmhub_v1_8_err_codes, + ARRAY_SIZE(mmhub_v1_8_err_codes))) + return false; + + return true; +} + +static const struct aca_bank_ops mmhub_v1_8_aca_bank_ops = { + .aca_bank_generate_report = mmhub_v1_8_aca_bank_generate_report, + .aca_bank_is_valid = mmhub_v1_8_aca_bank_is_valid, +}; + +static const struct aca_info mmhub_v1_8_aca_info = { + .hwip = ACA_HWIP_TYPE_SMU, + .mask = ACA_ERROR_UE_MASK, + .bank_ops = &mmhub_v1_8_aca_bank_ops, +}; + +static int mmhub_v1_8_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) +{ + int r; + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) + return r; + + r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__MMHUB, + &mmhub_v1_8_aca_info, NULL); + if (r) + goto late_fini; + + return 0; + +late_fini: + amdgpu_ras_block_late_fini(adev, ras_block); + + return r; +} + struct amdgpu_mmhub_ras mmhub_v1_8_ras = { .ras_block = { .hw_ops = &mmhub_v1_8_ras_hw_ops, + .ras_late_init = mmhub_v1_8_ras_late_init, }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c index 63725b2ebc03733f607aaf9dd9f8a649f75d2dae..a2bd2c3b1ef9c4a4dfac7ab131a6588429d00856 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c @@ -404,7 +404,8 @@ static int xgpu_ai_request_init_data(struct amdgpu_device *adev) return xgpu_ai_send_access_requests(adev, IDH_REQ_GPU_INIT_DATA); } -static void xgpu_ai_ras_poison_handler(struct amdgpu_device *adev) +static void xgpu_ai_ras_poison_handler(struct amdgpu_device *adev, + enum amdgpu_ras_block block) { xgpu_ai_send_access_requests(adev, IDH_RAS_POISON); } diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c index 6a68ee946f1cc3f58862a8c67fd3c53f4fdb092b..77f5b55decf96032ce1794693a3d51f1481f6009 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c @@ -152,14 +152,14 @@ static void xgpu_nv_mailbox_trans_msg (struct amdgpu_device *adev, xgpu_nv_mailbox_set_valid(adev, false); } -static int xgpu_nv_send_access_requests(struct amdgpu_device *adev, - enum idh_request req) +static int xgpu_nv_send_access_requests_with_param(struct amdgpu_device *adev, + enum idh_request req, u32 data1, u32 data2, u32 data3) { int r, retry = 1; enum idh_event event = -1; send_request: - xgpu_nv_mailbox_trans_msg(adev, req, 0, 0, 0); + xgpu_nv_mailbox_trans_msg(adev, req, data1, data2, data3); switch (req) { case IDH_REQ_GPU_INIT_ACCESS: @@ -170,6 +170,10 @@ send_request: case IDH_REQ_GPU_INIT_DATA: event = IDH_REQ_GPU_INIT_DATA_READY; break; + case IDH_RAS_POISON: + if (data1 != 0) + event = IDH_RAS_POISON_READY; + break; default: break; } @@ -206,6 +210,13 @@ send_request: return 0; } +static int xgpu_nv_send_access_requests(struct amdgpu_device *adev, + enum idh_request req) +{ + return xgpu_nv_send_access_requests_with_param(adev, + req, 0, 0, 0); +} + static int xgpu_nv_request_reset(struct amdgpu_device *adev) { int ret, i = 0; @@ -424,9 +435,17 @@ void xgpu_nv_mailbox_put_irq(struct amdgpu_device *adev) amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0); } -static void xgpu_nv_ras_poison_handler(struct amdgpu_device *adev) +static void xgpu_nv_ras_poison_handler(struct amdgpu_device *adev, + enum amdgpu_ras_block block) { - xgpu_nv_send_access_requests(adev, IDH_RAS_POISON); + if (amdgpu_ip_version(adev, UMC_HWIP, 0) < IP_VERSION(12, 0, 0)) { + xgpu_nv_send_access_requests(adev, IDH_RAS_POISON); + } else { + amdgpu_virt_fini_data_exchange(adev); + xgpu_nv_send_access_requests_with_param(adev, + IDH_RAS_POISON, block, 0, 0); + amdgpu_virt_init_data_exchange(adev); + } } const struct amdgpu_virt_ops xgpu_nv_virt_ops = { diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h index d0221ce087690e9ffaa8c24a0ccfee8226c0b80a..1e8fd90cab434724a04aa2ce45f8b44b0ce37865 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h @@ -51,6 +51,7 @@ enum idh_event { IDH_FAIL, IDH_QUERY_ALIVE, IDH_REQ_GPU_INIT_DATA_READY, + IDH_RAS_POISON_READY, IDH_TEXT_MESSAGE = 255, }; diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c index e64b33115848d204a4d81eb9530df5bf95fdf796..4178f4e5dad7329610958834fb22b8af9d821139 100644 --- a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c @@ -442,6 +442,12 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev, tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); out: return (wptr & ih->ptr_mask); } @@ -722,8 +728,7 @@ static void navi10_ih_set_interrupt_funcs(struct amdgpu_device *adev) adev->irq.ih_funcs = &navi10_ih_funcs; } -const struct amdgpu_ip_block_version navi10_ih_ip_block = -{ +const struct amdgpu_ip_block_version navi10_ih_ip_block = { .type = AMD_IP_BLOCK_TYPE_IH, .major = 5, .minor = 0, diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c index e90f33780803458c32843f2599c07e4f598ca659..b4723d68eab0f939ba057b67cf7712ddb512c8c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c @@ -431,6 +431,12 @@ static void nbio_v7_9_init_registers(struct amdgpu_device *adev) u32 inst_mask; int i; + if (amdgpu_sriov_vf(adev)) + adev->rmmio_remap.reg_offset = + SOC15_REG_OFFSET( + NBIO, 0, + regBIF_BX_DEV0_EPF0_VF0_HDP_MEM_COHERENCY_FLUSH_CNTL) + << 2; WREG32_SOC15(NBIO, 0, regXCC_DOORBELL_FENCE, 0xff & ~(adev->gfx.xcc_mask)); diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c index df1844d0800f2e5d9bcbc9d546ef3e52e060b733..722b6066ce07c5330fa246ec81e56cd41893e064 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c @@ -27,6 +27,7 @@ #include "amdgpu_ucode.h" #include "soc15_common.h" #include "psp_v13_0.h" +#include "amdgpu_ras.h" #include "mp/mp_13_0_2_offset.h" #include "mp/mp_13_0_2_sh_mask.h" @@ -187,11 +188,18 @@ static int psp_v13_0_wait_for_bootloader(struct psp_context *psp) static int psp_v13_0_wait_for_bootloader_steady_state(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; + int ret; if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6)) { - psp_v13_0_wait_for_vmbx_ready(psp); + ret = psp_v13_0_wait_for_vmbx_ready(psp); + if (ret) + amdgpu_ras_query_boot_status(adev, 4); + + ret = psp_v13_0_wait_for_bootloader(psp); + if (ret) + amdgpu_ras_query_boot_status(adev, 4); - return psp_v13_0_wait_for_bootloader(psp); + return ret; } return 0; @@ -763,81 +771,28 @@ static int psp_v13_0_fatal_error_recovery_quirk(struct psp_context *psp) return 0; } - -static void psp_v13_0_boot_error_reporting(struct amdgpu_device *adev, - uint32_t inst, - uint32_t boot_error) -{ - uint32_t socket_id; - uint32_t aid_id; - uint32_t hbm_id; - uint32_t reg_data; - - socket_id = REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, SOCKET_ID); - aid_id = REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, AID_ID); - hbm_id = REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, HBM_ID); - - reg_data = RREG32_SOC15(MP0, inst, regMP0_SMN_C2PMSG_109); - dev_info(adev->dev, "socket: %d, aid: %d, firmware boot failed, fw status is 0x%x\n", - socket_id, aid_id, reg_data); - - if (REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, GPU_ERR_MEM_TRAINING)) - dev_info(adev->dev, "socket: %d, aid: %d, hbm: %d, memory training failed\n", - socket_id, aid_id, hbm_id); - - if (REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, GPU_ERR_FW_LOAD)) - dev_info(adev->dev, "socket: %d, aid: %d, firmware load failed at boot time\n", - socket_id, aid_id); - - if (REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, GPU_ERR_WAFL_LINK_TRAINING)) - dev_info(adev->dev, "socket: %d, aid: %d, wafl link training failed\n", - socket_id, aid_id); - - if (REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, GPU_ERR_XGMI_LINK_TRAINING)) - dev_info(adev->dev, "socket: %d, aid: %d, xgmi link training failed\n", - socket_id, aid_id); - - if (REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, GPU_ERR_USR_CP_LINK_TRAINING)) - dev_info(adev->dev, "socket: %d, aid: %d, usr cp link training failed\n", - socket_id, aid_id); - - if (REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, GPU_ERR_USR_DP_LINK_TRAINING)) - dev_info(adev->dev, "socket: %d, aid: %d, usr dp link training failed\n", - socket_id, aid_id); - - if (REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, GPU_ERR_HBM_MEM_TEST)) - dev_info(adev->dev, "socket: %d, aid: %d, hbm: %d, hbm memory test failed\n", - socket_id, aid_id, hbm_id); - - if (REG_GET_FIELD(boot_error, MP0_SMN_C2PMSG_126, GPU_ERR_HBM_BIST_TEST)) - dev_info(adev->dev, "socket: %d, aid: %d, hbm: %d, hbm bist test failed\n", - socket_id, aid_id, hbm_id); -} - -static int psp_v13_0_query_boot_status(struct psp_context *psp) +static bool psp_v13_0_get_ras_capability(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; - int inst_mask = adev->aid_mask; - uint32_t reg_data; - uint32_t i; - int ret = 0; + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + u32 reg_data; - if (amdgpu_ip_version(adev, MP0_HWIP, 0) != IP_VERSION(13, 0, 6)) - return 0; + /* query ras cap should be done from host side */ + if (amdgpu_sriov_vf(adev)) + return false; - if (RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_59) < 0x00a10109) - return 0; + if (!con) + return false; - for_each_inst(i, inst_mask) { - reg_data = RREG32_SOC15(MP0, i, regMP0_SMN_C2PMSG_126); - if (!REG_GET_FIELD(reg_data, MP0_SMN_C2PMSG_126, BOOT_STATUS)) { - psp_v13_0_boot_error_reporting(adev, i, reg_data); - ret = -EINVAL; - break; - } + if ((amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6)) && + (!(adev->flags & AMD_IS_APU))) { + reg_data = RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_127); + adev->ras_hw_enabled = (reg_data & GENMASK_ULL(23, 0)); + con->poison_supported = ((reg_data & GENMASK_ULL(24, 24)) >> 24) ? true : false; + return true; + } else { + return false; } - - return ret; } static const struct psp_funcs psp_v13_0_funcs = { @@ -862,7 +817,7 @@ static const struct psp_funcs psp_v13_0_funcs = { .update_spirom = psp_v13_0_update_spirom, .vbflash_stat = psp_v13_0_vbflash_status, .fatal_error_recovery_quirk = psp_v13_0_fatal_error_recovery_quirk, - .query_boot_status = psp_v13_0_query_boot_status, + .get_ras_capability = psp_v13_0_get_ras_capability, }; void psp_v13_0_set_psp_funcs(struct psp_context *psp) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 8d5d86675a7fea5e4e5e8bc4e49cdbb580ae17a6..07e19caf2bc10dd30646e5bfd84acd7c722c820c 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -57,22 +57,19 @@ static void sdma_v2_4_set_irq_funcs(struct amdgpu_device *adev); MODULE_FIRMWARE("amdgpu/topaz_sdma.bin"); MODULE_FIRMWARE("amdgpu/topaz_sdma1.bin"); -static const u32 sdma_offsets[SDMA_MAX_INSTANCE] = -{ +static const u32 sdma_offsets[SDMA_MAX_INSTANCE] = { SDMA0_REGISTER_OFFSET, SDMA1_REGISTER_OFFSET }; -static const u32 golden_settings_iceland_a11[] = -{ +static const u32 golden_settings_iceland_a11[] = { mmSDMA0_CHICKEN_BITS, 0xfc910007, 0x00810007, mmSDMA0_CLK_CTRL, 0xff000fff, 0x00000000, mmSDMA1_CHICKEN_BITS, 0xfc910007, 0x00810007, mmSDMA1_CLK_CTRL, 0xff000fff, 0x00000000, }; -static const u32 iceland_mgcg_cgcg_init[] = -{ +static const u32 iceland_mgcg_cgcg_init[] = { mmSDMA0_CLK_CTRL, 0xff000ff0, 0x00000100, mmSDMA1_CLK_CTRL, 0xff000ff0, 0x00000100 }; @@ -142,7 +139,8 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev) case CHIP_TOPAZ: chip_name = "topaz"; break; - default: BUG(); + default: + BUG(); } for (i = 0; i < adev->sdma.num_instances; i++) { @@ -1258,8 +1256,7 @@ static void sdma_v2_4_set_vm_pte_funcs(struct amdgpu_device *adev) adev->vm_manager.vm_pte_num_scheds = adev->sdma.num_instances; } -const struct amdgpu_ip_block_version sdma_v2_4_ip_block = -{ +const struct amdgpu_ip_block_version sdma_v2_4_ip_block = { .type = AMD_IP_BLOCK_TYPE_SDMA, .major = 2, .minor = 4, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c index 2d688dca26bedba5018bd41c76fb09a65a38cd66..fec5a3d1c4bc2035e963e47672df18ee6880462e 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c @@ -45,6 +45,8 @@ MODULE_FIRMWARE("amdgpu/sdma_4_4_2.bin"); +#define mmSMNAID_AID0_MCA_SMU 0x03b30400 + #define WREG32_SDMA(instance, offset, value) \ WREG32(sdma_v4_4_2_get_reg_offset(adev, (instance), (offset)), value) #define RREG32_SDMA(instance, offset) \ @@ -2204,9 +2206,79 @@ static const struct amdgpu_ras_block_hw_ops sdma_v4_4_2_ras_hw_ops = { .reset_ras_error_count = sdma_v4_4_2_reset_ras_error_count, }; +static int sdma_v4_4_2_aca_bank_generate_report(struct aca_handle *handle, + struct aca_bank *bank, enum aca_error_type type, + struct aca_bank_report *report, void *data) +{ + u64 status, misc0; + int ret; + + status = bank->regs[ACA_REG_IDX_STATUS]; + if ((type == ACA_ERROR_TYPE_UE && + ACA_REG__STATUS__ERRORCODEEXT(status) == ACA_EXTERROR_CODE_FAULT) || + (type == ACA_ERROR_TYPE_CE && + ACA_REG__STATUS__ERRORCODEEXT(status) == ACA_EXTERROR_CODE_CE)) { + + ret = aca_bank_info_decode(bank, &report->info); + if (ret) + return ret; + + misc0 = bank->regs[ACA_REG_IDX_MISC0]; + report->count[type] = ACA_REG__MISC0__ERRCNT(misc0); + } + + return 0; +} + +/* CODE_SDMA0 - CODE_SDMA4, reference to smu driver if header file */ +static int sdma_v4_4_2_err_codes[] = { 33, 34, 35, 36 }; + +static bool sdma_v4_4_2_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, + enum aca_error_type type, void *data) +{ + u32 instlo; + + instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); + instlo &= GENMASK(31, 1); + + if (instlo != mmSMNAID_AID0_MCA_SMU) + return false; + + if (aca_bank_check_error_codes(handle->adev, bank, + sdma_v4_4_2_err_codes, + ARRAY_SIZE(sdma_v4_4_2_err_codes))) + return false; + + return true; +} + +static const struct aca_bank_ops sdma_v4_4_2_aca_bank_ops = { + .aca_bank_generate_report = sdma_v4_4_2_aca_bank_generate_report, + .aca_bank_is_valid = sdma_v4_4_2_aca_bank_is_valid, +}; + +static const struct aca_info sdma_v4_4_2_aca_info = { + .hwip = ACA_HWIP_TYPE_SMU, + .mask = ACA_ERROR_UE_MASK, + .bank_ops = &sdma_v4_4_2_aca_bank_ops, +}; + +static int sdma_v4_4_2_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) +{ + int r; + + r = amdgpu_sdma_ras_late_init(adev, ras_block); + if (r) + return r; + + return amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__SDMA, + &sdma_v4_4_2_aca_info, NULL); +} + static struct amdgpu_sdma_ras sdma_v4_4_2_ras = { .ras_block = { .hw_ops = &sdma_v4_4_2_ras_hw_ops, + .ras_late_init = sdma_v4_4_2_ras_late_init, }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c index 9a24f17a57502edaa744451bd312dfcd8b3d678c..cada9f300a7f510a3f025c3ed17c87aedcbbaeb5 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c @@ -119,6 +119,12 @@ static u32 si_ih_get_wptr(struct amdgpu_device *adev, tmp = RREG32(IH_RB_CNTL); tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; WREG32(IH_RB_CNTL, tmp); + + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; + WREG32(IH_RB_CNTL, tmp); } return (wptr & ih->ptr_mask); } diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 15033efec2bac0148e5d9381027a6ee3e70334b7..c64c01e2944a2e4c1f4177355771a1b47cfcc666 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -1298,10 +1298,32 @@ static int soc15_common_suspend(void *handle) return soc15_common_hw_fini(adev); } +static bool soc15_need_reset_on_resume(struct amdgpu_device *adev) +{ + u32 sol_reg; + + sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); + + /* Will reset for the following suspend abort cases. + * 1) Only reset limit on APU side, dGPU hasn't checked yet. + * 2) S3 suspend abort and TOS already launched. + */ + if (adev->flags & AMD_IS_APU && adev->in_s3 && + !adev->suspend_complete && + sol_reg) + return true; + + return false; +} + static int soc15_common_resume(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + if (soc15_need_reset_on_resume(adev)) { + dev_info(adev->dev, "S3 suspend abort case, let's reset ASIC.\n"); + soc15_asic_reset(adev); + } return soc15_common_hw_init(adev); } diff --git a/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h b/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h index 879bb7af297c7bda447b199a2165a03b4c691562..056d4df8fa1ff4a2aa3a2e7ac9733c29b4897ad4 100644 --- a/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h +++ b/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h @@ -36,6 +36,9 @@ enum ras_command { TA_RAS_COMMAND__ENABLE_FEATURES = 0, TA_RAS_COMMAND__DISABLE_FEATURES, TA_RAS_COMMAND__TRIGGER_ERROR, + TA_RAS_COMMAND__QUERY_BLOCK_INFO, + TA_RAS_COMMAND__QUERY_SUB_BLOCK_INFO, + TA_RAS_COMMAND__QUERY_ADDRESS, }; enum ta_ras_status { @@ -105,6 +108,11 @@ enum ta_ras_error_type { TA_RAS_ERROR__POISON = 8, }; +enum ta_ras_address_type { + TA_RAS_MCA_TO_PA, + TA_RAS_PA_TO_MCA, +}; + /* Input/output structures for RAS commands */ /**********************************************************/ @@ -133,12 +141,38 @@ struct ta_ras_init_flags { uint8_t channel_dis_num; }; +struct ta_ras_mca_addr { + uint64_t err_addr; + uint32_t ch_inst; + uint32_t umc_inst; + uint32_t node_inst; +}; + +struct ta_ras_phy_addr { + uint64_t pa; + uint32_t bank; + uint32_t channel_idx; +}; + +struct ta_ras_query_address_input { + enum ta_ras_address_type addr_type; + struct ta_ras_mca_addr ma; + struct ta_ras_phy_addr pa; +}; + struct ta_ras_output_flags { uint8_t ras_init_success_flag; uint8_t err_inject_switch_disable_flag; uint8_t reg_access_failure_flag; }; +struct ta_ras_query_address_output { + /* don't use the flags here */ + struct ta_ras_output_flags flags; + struct ta_ras_mca_addr ma; + struct ta_ras_phy_addr pa; +}; + /* Common input structure for RAS callbacks */ /**********************************************************/ union ta_ras_cmd_input { @@ -146,12 +180,14 @@ union ta_ras_cmd_input { struct ta_ras_enable_features_input enable_features; struct ta_ras_disable_features_input disable_features; struct ta_ras_trigger_error_input trigger_error; + struct ta_ras_query_address_input address; uint32_t reserve_pad[256]; }; union ta_ras_cmd_output { struct ta_ras_output_flags flags; + struct ta_ras_query_address_output address; uint32_t reserve_pad[256]; }; diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c index 917707bba7f3624e37b0525d3ec72bf563c1307a..450b6e8315091448c24e2d90dcd4edccc9d4423c 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c @@ -219,6 +219,12 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev, tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); WREG32(mmIH_RB_CNTL, tmp); + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + WREG32(mmIH_RB_CNTL, tmp); + out: return (wptr & ih->ptr_mask); } diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c index 7458a218e89db1dc98211c83c864e29cd81ab7af..14ef7a24be7b567424c0cfecfdc2bf822923abc6 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c @@ -89,12 +89,28 @@ static void umc_v12_0_reset_error_count(struct amdgpu_device *adev) umc_v12_0_reset_error_count_per_channel, NULL); } +bool umc_v12_0_is_deferred_error(struct amdgpu_device *adev, uint64_t mc_umc_status) +{ + dev_info(adev->dev, + "MCA_UMC_STATUS(0x%llx): Val:%llu, Poison:%llu, Deferred:%llu, PCC:%llu, UC:%llu, TCC:%llu\n", + mc_umc_status, + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val), + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Poison), + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Deferred), + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, PCC), + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UC), + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, TCC) + ); + + return (amdgpu_ras_is_poison_mode_supported(adev) && + (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1) && + (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Deferred) == 1)); +} + bool umc_v12_0_is_uncorrectable_error(struct amdgpu_device *adev, uint64_t mc_umc_status) { - if (amdgpu_ras_is_poison_mode_supported(adev) && - (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1) && - (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Deferred) == 1)) - return true; + if (umc_v12_0_is_deferred_error(adev, mc_umc_status)) + return false; return ((REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1) && (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, PCC) == 1 || @@ -104,9 +120,7 @@ bool umc_v12_0_is_uncorrectable_error(struct amdgpu_device *adev, uint64_t mc_um bool umc_v12_0_is_correctable_error(struct amdgpu_device *adev, uint64_t mc_umc_status) { - if (amdgpu_ras_is_poison_mode_supported(adev) && - (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1) && - (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Deferred) == 1)) + if (umc_v12_0_is_deferred_error(adev, mc_umc_status)) return false; return (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 && @@ -119,9 +133,10 @@ bool umc_v12_0_is_correctable_error(struct amdgpu_device *adev, uint64_t mc_umc_ !(umc_v12_0_is_uncorrectable_error(adev, mc_umc_status))))); } -static void umc_v12_0_query_correctable_error_count(struct amdgpu_device *adev, +static void umc_v12_0_query_error_count_per_type(struct amdgpu_device *adev, uint64_t umc_reg_offset, - unsigned long *error_count) + unsigned long *error_count, + check_error_type_func error_type_func) { uint64_t mc_umc_status; uint64_t mc_umc_status_addr; @@ -129,31 +144,11 @@ static void umc_v12_0_query_correctable_error_count(struct amdgpu_device *adev, mc_umc_status_addr = SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0); - /* Rely on MCUMC_STATUS for correctable error counter - * MCUMC_STATUS is a 64 bit register - */ + /* Check MCUMC_STATUS */ mc_umc_status = RREG64_PCIE_EXT((mc_umc_status_addr + umc_reg_offset) * 4); - if (umc_v12_0_is_correctable_error(adev, mc_umc_status)) - *error_count += 1; -} - -static void umc_v12_0_query_uncorrectable_error_count(struct amdgpu_device *adev, - uint64_t umc_reg_offset, - unsigned long *error_count) -{ - uint64_t mc_umc_status; - uint64_t mc_umc_status_addr; - - mc_umc_status_addr = - SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0); - - /* Check the MCUMC_STATUS. */ - mc_umc_status = - RREG64_PCIE_EXT((mc_umc_status_addr + umc_reg_offset) * 4); - - if (umc_v12_0_is_uncorrectable_error(adev, mc_umc_status)) + if (error_type_func(adev, mc_umc_status)) *error_count += 1; } @@ -162,7 +157,7 @@ static int umc_v12_0_query_error_count(struct amdgpu_device *adev, uint32_t ch_inst, void *data) { struct ras_err_data *err_data = (struct ras_err_data *)data; - unsigned long ue_count = 0, ce_count = 0; + unsigned long ue_count = 0, ce_count = 0, de_count = 0; /* NOTE: node_inst is converted by adev->umc.active_mask and the range is [0-3], * which can be used as die ID directly */ @@ -174,11 +169,16 @@ static int umc_v12_0_query_error_count(struct amdgpu_device *adev, uint64_t umc_reg_offset = get_umc_v12_0_reg_offset(adev, node_inst, umc_inst, ch_inst); - umc_v12_0_query_correctable_error_count(adev, umc_reg_offset, &ce_count); - umc_v12_0_query_uncorrectable_error_count(adev, umc_reg_offset, &ue_count); + umc_v12_0_query_error_count_per_type(adev, umc_reg_offset, + &ce_count, umc_v12_0_is_correctable_error); + umc_v12_0_query_error_count_per_type(adev, umc_reg_offset, + &ue_count, umc_v12_0_is_uncorrectable_error); + umc_v12_0_query_error_count_per_type(adev, umc_reg_offset, + &de_count, umc_v12_0_is_deferred_error); amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, NULL, ue_count); amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, NULL, ce_count); + amdgpu_ras_error_statistic_de_count(err_data, &mcm_info, NULL, de_count); return 0; } @@ -203,14 +203,14 @@ static bool umc_v12_0_bit_wise_xor(uint32_t val) return result; } -static void umc_v12_0_convert_error_address(struct amdgpu_device *adev, - struct ras_err_data *err_data, uint64_t err_addr, - uint32_t ch_inst, uint32_t umc_inst, - uint32_t node_inst) +static void umc_v12_0_mca_addr_to_pa(struct amdgpu_device *adev, + uint64_t err_addr, uint32_t ch_inst, uint32_t umc_inst, + uint32_t node_inst, + struct ta_ras_query_address_output *addr_out) { uint32_t channel_index, i; - uint64_t soc_pa, na, retired_page, column; - uint32_t bank_hash0, bank_hash1, bank_hash2, bank_hash3, col, row, row_xor; + uint64_t na, soc_pa; + uint32_t bank_hash0, bank_hash1, bank_hash2, bank_hash3, col, row; uint32_t bank0, bank1, bank2, bank3, bank; bank_hash0 = (err_addr >> UMC_V12_0_MCA_B0_BIT) & 0x1ULL; @@ -260,12 +260,44 @@ static void umc_v12_0_convert_error_address(struct amdgpu_device *adev, /* the umc channel bits are not original values, they are hashed */ UMC_V12_0_SET_CHANNEL_HASH(channel_index, soc_pa); + addr_out->pa.pa = soc_pa; + addr_out->pa.bank = bank; + addr_out->pa.channel_idx = channel_index; +} + +static void umc_v12_0_convert_error_address(struct amdgpu_device *adev, + struct ras_err_data *err_data, uint64_t err_addr, + uint32_t ch_inst, uint32_t umc_inst, + uint32_t node_inst) +{ + uint32_t col, row, row_xor, bank, channel_index; + uint64_t soc_pa, retired_page, column; + struct ta_ras_query_address_input addr_in; + struct ta_ras_query_address_output addr_out; + + addr_in.addr_type = TA_RAS_MCA_TO_PA; + addr_in.ma.err_addr = err_addr; + addr_in.ma.ch_inst = ch_inst; + addr_in.ma.umc_inst = umc_inst; + addr_in.ma.node_inst = node_inst; + + if (psp_ras_query_address(&adev->psp, &addr_in, &addr_out)) + /* fallback to old path if fail to get pa from psp */ + umc_v12_0_mca_addr_to_pa(adev, err_addr, ch_inst, umc_inst, + node_inst, &addr_out); + + soc_pa = addr_out.pa.pa; + bank = addr_out.pa.bank; + channel_index = addr_out.pa.channel_idx; + + col = (err_addr >> 1) & 0x1fULL; + row = (err_addr >> 10) & 0x3fffULL; + row_xor = row ^ (0x1ULL << 13); /* clear [C3 C2] in soc physical address */ soc_pa &= ~(0x3ULL << UMC_V12_0_PA_C2_BIT); /* clear [C4] in soc physical address */ soc_pa &= ~(0x1ULL << UMC_V12_0_PA_C4_BIT); - row_xor = row ^ (0x1ULL << 13); /* loop for all possibilities of [C4 C3 C2] */ for (column = 0; column < UMC_V12_0_NA_MAP_PA_NUM; column++) { retired_page = soc_pa | ((column & 0x3) << UMC_V12_0_PA_C2_BIT); @@ -316,10 +348,7 @@ static int umc_v12_0_query_error_address(struct amdgpu_device *adev, } /* calculate error address if ue error is detected */ - if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 && - REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, AddrV) == 1 && - REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UC) == 1) { - + if (umc_v12_0_is_uncorrectable_error(adev, mc_umc_status)) { mc_umc_addrt0 = SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_ADDRT0); @@ -385,45 +414,69 @@ static void umc_v12_0_ecc_info_query_ras_error_address(struct amdgpu_device *ade { struct ras_err_node *err_node; uint64_t mc_umc_status; + struct ras_err_info *err_info; + struct ras_err_addr *mca_err_addr, *tmp; struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; for_each_ras_error(err_node, err_data) { - mc_umc_status = err_node->err_info.err_addr.err_status; - if (!mc_umc_status) + err_info = &err_node->err_info; + if (list_empty(&err_info->err_addr_list)) continue; - if (umc_v12_0_is_uncorrectable_error(adev, mc_umc_status)) { - uint64_t mca_addr, err_addr, mca_ipid; - uint32_t InstanceIdLo; - struct amdgpu_smuio_mcm_config_info *mcm_info; - - mcm_info = &err_node->err_info.mcm_info; - mca_addr = err_node->err_info.err_addr.err_addr; - mca_ipid = err_node->err_info.err_addr.err_ipid; - - err_addr = REG_GET_FIELD(mca_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr); - InstanceIdLo = REG_GET_FIELD(mca_ipid, MCMP1_IPIDT0, InstanceIdLo); - - dev_info(adev->dev, "UMC:IPID:0x%llx, aid:%d, inst:%d, ch:%d, err_addr:0x%llx\n", - mca_ipid, - mcm_info->die_id, - MCA_IPID_LO_2_UMC_INST(InstanceIdLo), - MCA_IPID_LO_2_UMC_CH(InstanceIdLo), - err_addr); - - umc_v12_0_convert_error_address(adev, - err_data, err_addr, - MCA_IPID_LO_2_UMC_CH(InstanceIdLo), - MCA_IPID_LO_2_UMC_INST(InstanceIdLo), - mcm_info->die_id); - - /* Clear umc error address content */ - memset(&err_node->err_info.err_addr, - 0, sizeof(err_node->err_info.err_addr)); + list_for_each_entry_safe(mca_err_addr, tmp, &err_info->err_addr_list, node) { + mc_umc_status = mca_err_addr->err_status; + if (mc_umc_status && + (umc_v12_0_is_uncorrectable_error(adev, mc_umc_status) || + umc_v12_0_is_deferred_error(adev, mc_umc_status))) { + uint64_t mca_addr, err_addr, mca_ipid; + uint32_t InstanceIdLo; + + mca_addr = mca_err_addr->err_addr; + mca_ipid = mca_err_addr->err_ipid; + + err_addr = REG_GET_FIELD(mca_addr, + MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr); + InstanceIdLo = REG_GET_FIELD(mca_ipid, MCMP1_IPIDT0, InstanceIdLo); + + dev_info(adev->dev, "UMC:IPID:0x%llx, aid:%d, inst:%d, ch:%d, err_addr:0x%llx\n", + mca_ipid, + err_info->mcm_info.die_id, + MCA_IPID_LO_2_UMC_INST(InstanceIdLo), + MCA_IPID_LO_2_UMC_CH(InstanceIdLo), + err_addr); + + umc_v12_0_convert_error_address(adev, + err_data, err_addr, + MCA_IPID_LO_2_UMC_CH(InstanceIdLo), + MCA_IPID_LO_2_UMC_INST(InstanceIdLo), + err_info->mcm_info.die_id); + } + + /* Delete error address node from list and free memory */ + amdgpu_ras_del_mca_err_addr(err_info, mca_err_addr); } } } +static bool umc_v12_0_check_ecc_err_status(struct amdgpu_device *adev, + enum amdgpu_mca_error_type type, void *ras_error_status) +{ + uint64_t mc_umc_status = *(uint64_t *)ras_error_status; + + switch (type) { + case AMDGPU_MCA_ERROR_TYPE_UE: + return umc_v12_0_is_uncorrectable_error(adev, mc_umc_status); + case AMDGPU_MCA_ERROR_TYPE_CE: + return umc_v12_0_is_correctable_error(adev, mc_umc_status); + case AMDGPU_MCA_ERROR_TYPE_DE: + return umc_v12_0_is_deferred_error(adev, mc_umc_status); + default: + return false; + } + + return false; +} + static void umc_v12_0_err_cnt_init(struct amdgpu_device *adev) { amdgpu_umc_loop_channels(adev, @@ -444,12 +497,71 @@ const struct amdgpu_ras_block_hw_ops umc_v12_0_ras_hw_ops = { .query_ras_error_address = umc_v12_0_query_ras_error_address, }; +static int umc_v12_0_aca_bank_generate_report(struct aca_handle *handle, struct aca_bank *bank, enum aca_error_type type, + struct aca_bank_report *report, void *data) +{ + struct amdgpu_device *adev = handle->adev; + u64 status; + int ret; + + ret = aca_bank_info_decode(bank, &report->info); + if (ret) + return ret; + + status = bank->regs[ACA_REG_IDX_STATUS]; + switch (type) { + case ACA_ERROR_TYPE_UE: + if (umc_v12_0_is_uncorrectable_error(adev, status)) { + report->count[type] = 1; + } + break; + case ACA_ERROR_TYPE_CE: + if (umc_v12_0_is_correctable_error(adev, status)) { + report->count[type] = 1; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct aca_bank_ops umc_v12_0_aca_bank_ops = { + .aca_bank_generate_report = umc_v12_0_aca_bank_generate_report, +}; + +const struct aca_info umc_v12_0_aca_info = { + .hwip = ACA_HWIP_TYPE_UMC, + .mask = ACA_ERROR_UE_MASK | ACA_ERROR_CE_MASK, + .bank_ops = &umc_v12_0_aca_bank_ops, +}; + +static int umc_v12_0_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) +{ + int ret; + + ret = amdgpu_umc_ras_late_init(adev, ras_block); + if (ret) + return ret; + + ret = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__UMC, + &umc_v12_0_aca_info, NULL); + if (ret) + return ret; + + return 0; +} + struct amdgpu_umc_ras umc_v12_0_ras = { .ras_block = { .hw_ops = &umc_v12_0_ras_hw_ops, + .ras_late_init = umc_v12_0_ras_late_init, }, .err_cnt_init = umc_v12_0_err_cnt_init, .query_ras_poison_mode = umc_v12_0_query_ras_poison_mode, .ecc_info_query_ras_error_count = umc_v12_0_ecc_info_query_ras_error_count, .ecc_info_query_ras_error_address = umc_v12_0_ecc_info_query_ras_error_address, + .check_ecc_err_status = umc_v12_0_check_ecc_err_status, }; + diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h index e8de3a92251a2c0070345ce89c317032a386d45b..5973bfb14fceece0ef620d722f97230fe91cfc01 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h +++ b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h @@ -121,9 +121,12 @@ (((_ipid_lo) >> 12) & 0xF)) #define MCA_IPID_LO_2_UMC_INST(_ipid_lo) (((_ipid_lo) >> 21) & 0x7) +bool umc_v12_0_is_deferred_error(struct amdgpu_device *adev, uint64_t mc_umc_status); bool umc_v12_0_is_uncorrectable_error(struct amdgpu_device *adev, uint64_t mc_umc_status); bool umc_v12_0_is_correctable_error(struct amdgpu_device *adev, uint64_t mc_umc_status); +typedef bool (*check_error_type_func)(struct amdgpu_device *adev, uint64_t mc_umc_status); + extern const uint32_t umc_v12_0_channel_idx_tbl[] [UMC_V12_0_UMC_INSTANCE_NUM] diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_0.c index 0d6b50528d7625e3a43ab27a6cd3c94810ba9c9c..97fa88ed770c0f6e27386a48919d860994efbd59 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_0.c @@ -25,7 +25,7 @@ static void umc_v6_0_init_registers(struct amdgpu_device *adev) { - unsigned i,j; + unsigned i, j; for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 169ed400ee7b7413263ab48a2de1e75aa3ed00f7..8ab01ae919d2e36c8ff1c2226227c173223247be 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -2017,22 +2017,6 @@ static int vcn_v4_0_set_powergating_state(void *handle, enum amd_powergating_sta return ret; } -/** - * vcn_v4_0_set_interrupt_state - set VCN block interrupt state - * - * @adev: amdgpu_device pointer - * @source: interrupt sources - * @type: interrupt types - * @state: interrupt states - * - * Set VCN block interrupt state - */ -static int vcn_v4_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, - unsigned type, enum amdgpu_interrupt_state state) -{ - return 0; -} - /** * vcn_v4_0_set_ras_interrupt_state - set VCN block RAS interrupt state * @@ -2097,7 +2081,6 @@ static int vcn_v4_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_ } static const struct amdgpu_irq_src_funcs vcn_v4_0_irq_funcs = { - .set = vcn_v4_0_set_interrupt_state, .process = vcn_v4_0_process_interrupt, }; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c index 2eda30e78f61d928984cf57b94337abc7b9cfc0a..49e4c3c09acab8eab12770325f4cf48c8c491b7c 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c @@ -269,8 +269,6 @@ static int vcn_v4_0_5_hw_fini(void *handle) vcn_v4_0_5_set_powergating_state(adev, AMD_PG_STATE_GATE); } } - - amdgpu_irq_put(adev, &adev->vcn.inst[i].irq, 0); } return 0; @@ -1668,22 +1666,6 @@ static int vcn_v4_0_5_set_powergating_state(void *handle, enum amd_powergating_s return ret; } -/** - * vcn_v4_0_5_set_interrupt_state - set VCN block interrupt state - * - * @adev: amdgpu_device pointer - * @source: interrupt sources - * @type: interrupt types - * @state: interrupt states - * - * Set VCN block interrupt state - */ -static int vcn_v4_0_5_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, - unsigned type, enum amdgpu_interrupt_state state) -{ - return 0; -} - /** * vcn_v4_0_5_process_interrupt - process VCN block interrupt * @@ -1726,7 +1708,6 @@ static int vcn_v4_0_5_process_interrupt(struct amdgpu_device *adev, struct amdgp } static const struct amdgpu_irq_src_funcs vcn_v4_0_5_irq_funcs = { - .set = vcn_v4_0_5_set_interrupt_state, .process = vcn_v4_0_5_process_interrupt, }; diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c index d364c6dd152c33b7fc1fbc614668b2dd4ffe223a..bf68e18e3824b8e492c2451b655bfcf5068910f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c @@ -373,6 +373,12 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev, tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + out: return (wptr & ih->ptr_mask); } diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c index ddfc6941f9d559c916fe2cdb66b4e27394f1d618..db66e6cccaf2aa4e596a8f377eed8030c55159b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c @@ -421,6 +421,12 @@ static u32 vega20_ih_get_wptr(struct amdgpu_device *adev, tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + out: return (wptr & ih->ptr_mask); } diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index df75863393fcb887613fb4dc054977fb46a49b1e..d1caaf0e6a7c4eaed98fc8f390781719bf28b846 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -674,7 +674,7 @@ static const uint32_t cwsr_trap_gfx9_hex[] = { 0x86ea6a6a, 0x8f6e837a, 0xb96ee0c2, 0xbf800002, 0xb97a0002, 0xbf8a0000, - 0xbe801f6c, 0xbf810000, + 0xbe801f6c, 0xbf9b0000, }; static const uint32_t cwsr_trap_nv1x_hex[] = { @@ -1091,7 +1091,7 @@ static const uint32_t cwsr_trap_nv1x_hex[] = { 0xb9eef807, 0x876dff6d, 0x0000ffff, 0x87fe7e7e, 0x87ea6a6a, 0xb9faf802, - 0xbe80226c, 0xbf810000, + 0xbe80226c, 0xbf9b0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0x00000000, @@ -1574,7 +1574,7 @@ static const uint32_t cwsr_trap_arcturus_hex[] = { 0x86ea6a6a, 0x8f6e837a, 0xb96ee0c2, 0xbf800002, 0xb97a0002, 0xbf8a0000, - 0xbe801f6c, 0xbf810000, + 0xbe801f6c, 0xbf9b0000, }; static const uint32_t cwsr_trap_aldebaran_hex[] = { @@ -2065,7 +2065,7 @@ static const uint32_t cwsr_trap_aldebaran_hex[] = { 0x86ea6a6a, 0x8f6e837a, 0xb96ee0c2, 0xbf800002, 0xb97a0002, 0xbf8a0000, - 0xbe801f6c, 0xbf810000, + 0xbe801f6c, 0xbf9b0000, }; static const uint32_t cwsr_trap_gfx10_hex[] = { @@ -2500,7 +2500,7 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0x876dff6d, 0x0000ffff, 0x87fe7e7e, 0x87ea6a6a, 0xb9faf802, 0xbe80226c, - 0xbf810000, 0xbf9f0000, + 0xbf9b0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, }; @@ -2944,7 +2944,7 @@ static const uint32_t cwsr_trap_gfx11_hex[] = { 0xb8eef802, 0xbf0d866e, 0xbfa20002, 0xb97af802, 0xbe80486c, 0xb97af802, - 0xbe804a6c, 0xbfb00000, + 0xbe804a6c, 0xbfb10000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0x00000000, @@ -3436,5 +3436,5 @@ static const uint32_t cwsr_trap_gfx9_4_3_hex[] = { 0x86ea6a6a, 0x8f6e837a, 0xb96ee0c2, 0xbf800002, 0xb97a0002, 0xbf8a0000, - 0xbe801f6c, 0xbf810000, + 0xbe801f6c, 0xbf9b0000, }; diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm index e0140df0b0ec8086433048adb31a06ca6aca740d..71b3dc0c73634aef86846be3669723590ca55db9 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm @@ -1104,7 +1104,7 @@ L_RETURN_WITHOUT_PRIV: s_rfe_b64 s_restore_pc_lo //Return to the main shader program and resume execution L_END_PGM: - s_endpgm + s_endpgm_saved end function write_hwreg_to_mem(s, s_rsrc, s_mem_offset) diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm index e506411ad28ab99f474eca96ff37254fb43078de..bb26338204f4ba84b5ae41a781e1becdf9ad72bb 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm @@ -921,7 +921,7 @@ L_RESTORE: /* the END */ /**************************************************************************/ L_END_PGM: - s_endpgm + s_endpgm_saved end diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index ce4c52ec34d80eabb7f7664051ccebcd2f0ec64e..80e90fdef291d5b8cdcf7d08c6e319150fcf631b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1442,7 +1442,9 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep, kfd_flush_tlb(peer_pdd, TLB_FLUSH_HEAVYWEIGHT); /* Remove dma mapping after tlb flush to avoid IO_PAGE_FAULT */ - amdgpu_amdkfd_gpuvm_dmaunmap_mem(mem, peer_pdd->drm_priv); + err = amdgpu_amdkfd_gpuvm_dmaunmap_mem(mem, peer_pdd->drm_priv); + if (err) + goto sync_memory_failed; } mutex_unlock(&p->mutex); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index cd8e459201f18ca0fd40dfa92c800c5a9271f6e4..002b08fa632f0e119858aca405e1cbea455265a4 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -55,6 +55,7 @@ static struct kfd_gpu_cache_info kaveri_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -64,6 +65,7 @@ static struct kfd_gpu_cache_info kaveri_cache_info[] = { /* Scalar L1 Instruction Cache (in SQC module) per bank */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -73,6 +75,7 @@ static struct kfd_gpu_cache_info kaveri_cache_info[] = { /* Scalar L1 Data Cache (in SQC module) per bank */ .cache_size = 8, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -88,6 +91,7 @@ static struct kfd_gpu_cache_info carrizo_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -95,8 +99,9 @@ static struct kfd_gpu_cache_info carrizo_cache_info[] = { }, { /* Scalar L1 Instruction Cache (in SQC module) per bank */ - .cache_size = 8, + .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -104,8 +109,9 @@ static struct kfd_gpu_cache_info carrizo_cache_info[] = { }, { /* Scalar L1 Data Cache (in SQC module) per bank. */ - .cache_size = 4, + .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -135,6 +141,7 @@ static struct kfd_gpu_cache_info vega10_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -144,6 +151,7 @@ static struct kfd_gpu_cache_info vega10_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -153,6 +161,7 @@ static struct kfd_gpu_cache_info vega10_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -162,6 +171,7 @@ static struct kfd_gpu_cache_info vega10_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 4096, .cache_level = 2, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -174,6 +184,7 @@ static struct kfd_gpu_cache_info raven_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -183,6 +194,7 @@ static struct kfd_gpu_cache_info raven_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -192,6 +204,7 @@ static struct kfd_gpu_cache_info raven_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -201,6 +214,7 @@ static struct kfd_gpu_cache_info raven_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 1024, .cache_level = 2, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -213,6 +227,7 @@ static struct kfd_gpu_cache_info renoir_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -222,6 +237,7 @@ static struct kfd_gpu_cache_info renoir_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -231,6 +247,7 @@ static struct kfd_gpu_cache_info renoir_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -240,6 +257,7 @@ static struct kfd_gpu_cache_info renoir_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 1024, .cache_level = 2, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -252,6 +270,7 @@ static struct kfd_gpu_cache_info vega12_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -261,6 +280,7 @@ static struct kfd_gpu_cache_info vega12_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -270,6 +290,7 @@ static struct kfd_gpu_cache_info vega12_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -279,6 +300,7 @@ static struct kfd_gpu_cache_info vega12_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 2048, .cache_level = 2, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -291,6 +313,7 @@ static struct kfd_gpu_cache_info vega20_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -300,6 +323,7 @@ static struct kfd_gpu_cache_info vega20_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -309,6 +333,7 @@ static struct kfd_gpu_cache_info vega20_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -318,6 +343,7 @@ static struct kfd_gpu_cache_info vega20_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 8192, .cache_level = 2, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -330,6 +356,7 @@ static struct kfd_gpu_cache_info aldebaran_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -339,6 +366,7 @@ static struct kfd_gpu_cache_info aldebaran_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -348,6 +376,7 @@ static struct kfd_gpu_cache_info aldebaran_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -357,6 +386,7 @@ static struct kfd_gpu_cache_info aldebaran_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 8192, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -369,6 +399,7 @@ static struct kfd_gpu_cache_info navi10_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -378,6 +409,7 @@ static struct kfd_gpu_cache_info navi10_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -387,6 +419,7 @@ static struct kfd_gpu_cache_info navi10_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -396,6 +429,7 @@ static struct kfd_gpu_cache_info navi10_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -405,6 +439,7 @@ static struct kfd_gpu_cache_info navi10_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 4096, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -417,6 +452,7 @@ static struct kfd_gpu_cache_info vangogh_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -426,6 +462,7 @@ static struct kfd_gpu_cache_info vangogh_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -435,6 +472,7 @@ static struct kfd_gpu_cache_info vangogh_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -444,6 +482,7 @@ static struct kfd_gpu_cache_info vangogh_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -453,6 +492,7 @@ static struct kfd_gpu_cache_info vangogh_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 1024, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -465,6 +505,7 @@ static struct kfd_gpu_cache_info navi14_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -474,6 +515,7 @@ static struct kfd_gpu_cache_info navi14_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -483,6 +525,7 @@ static struct kfd_gpu_cache_info navi14_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -492,6 +535,7 @@ static struct kfd_gpu_cache_info navi14_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -501,6 +545,7 @@ static struct kfd_gpu_cache_info navi14_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 2048, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -513,6 +558,7 @@ static struct kfd_gpu_cache_info sienna_cichlid_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -522,6 +568,7 @@ static struct kfd_gpu_cache_info sienna_cichlid_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -531,6 +578,7 @@ static struct kfd_gpu_cache_info sienna_cichlid_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -540,6 +588,7 @@ static struct kfd_gpu_cache_info sienna_cichlid_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -549,6 +598,7 @@ static struct kfd_gpu_cache_info sienna_cichlid_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 4096, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -558,6 +608,7 @@ static struct kfd_gpu_cache_info sienna_cichlid_cache_info[] = { /* L3 Data Cache per GPU */ .cache_size = 128*1024, .cache_level = 3, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -570,6 +621,7 @@ static struct kfd_gpu_cache_info navy_flounder_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -579,6 +631,7 @@ static struct kfd_gpu_cache_info navy_flounder_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -588,6 +641,7 @@ static struct kfd_gpu_cache_info navy_flounder_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -597,6 +651,7 @@ static struct kfd_gpu_cache_info navy_flounder_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -606,6 +661,7 @@ static struct kfd_gpu_cache_info navy_flounder_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 3072, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -615,6 +671,7 @@ static struct kfd_gpu_cache_info navy_flounder_cache_info[] = { /* L3 Data Cache per GPU */ .cache_size = 96*1024, .cache_level = 3, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -627,6 +684,7 @@ static struct kfd_gpu_cache_info dimgrey_cavefish_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -636,6 +694,7 @@ static struct kfd_gpu_cache_info dimgrey_cavefish_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -645,6 +704,7 @@ static struct kfd_gpu_cache_info dimgrey_cavefish_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -654,6 +714,7 @@ static struct kfd_gpu_cache_info dimgrey_cavefish_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -663,6 +724,7 @@ static struct kfd_gpu_cache_info dimgrey_cavefish_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 2048, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -672,6 +734,7 @@ static struct kfd_gpu_cache_info dimgrey_cavefish_cache_info[] = { /* L3 Data Cache per GPU */ .cache_size = 32*1024, .cache_level = 3, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -684,6 +747,7 @@ static struct kfd_gpu_cache_info beige_goby_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -693,6 +757,7 @@ static struct kfd_gpu_cache_info beige_goby_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -702,6 +767,7 @@ static struct kfd_gpu_cache_info beige_goby_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -711,6 +777,7 @@ static struct kfd_gpu_cache_info beige_goby_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -720,6 +787,7 @@ static struct kfd_gpu_cache_info beige_goby_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 1024, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -729,6 +797,7 @@ static struct kfd_gpu_cache_info beige_goby_cache_info[] = { /* L3 Data Cache per GPU */ .cache_size = 16*1024, .cache_level = 3, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -741,6 +810,7 @@ static struct kfd_gpu_cache_info yellow_carp_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -750,6 +820,7 @@ static struct kfd_gpu_cache_info yellow_carp_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -759,6 +830,7 @@ static struct kfd_gpu_cache_info yellow_carp_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -768,6 +840,7 @@ static struct kfd_gpu_cache_info yellow_carp_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -777,6 +850,7 @@ static struct kfd_gpu_cache_info yellow_carp_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 2048, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -789,6 +863,7 @@ static struct kfd_gpu_cache_info gfx1037_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -798,6 +873,7 @@ static struct kfd_gpu_cache_info gfx1037_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -807,6 +883,7 @@ static struct kfd_gpu_cache_info gfx1037_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -816,6 +893,7 @@ static struct kfd_gpu_cache_info gfx1037_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -825,6 +903,7 @@ static struct kfd_gpu_cache_info gfx1037_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 256, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -837,6 +916,7 @@ static struct kfd_gpu_cache_info gc_10_3_6_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -846,6 +926,7 @@ static struct kfd_gpu_cache_info gc_10_3_6_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -855,6 +936,7 @@ static struct kfd_gpu_cache_info gc_10_3_6_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -864,6 +946,7 @@ static struct kfd_gpu_cache_info gc_10_3_6_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -873,6 +956,7 @@ static struct kfd_gpu_cache_info gc_10_3_6_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 256, .cache_level = 2, + .cache_line_size = 128, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -885,6 +969,7 @@ static struct kfd_gpu_cache_info dummy_cache_info[] = { /* TCP L1 Cache per CU */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -894,6 +979,7 @@ static struct kfd_gpu_cache_info dummy_cache_info[] = { /* Scalar L1 Instruction Cache per SQC */ .cache_size = 32, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -903,6 +989,7 @@ static struct kfd_gpu_cache_info dummy_cache_info[] = { /* Scalar L1 Data Cache per SQC */ .cache_size = 16, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -912,6 +999,7 @@ static struct kfd_gpu_cache_info dummy_cache_info[] = { /* GL1 Data Cache per SA */ .cache_size = 128, .cache_level = 1, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), @@ -921,6 +1009,7 @@ static struct kfd_gpu_cache_info dummy_cache_info[] = { /* L2 Data Cache per GPU (Total Tex Cache) */ .cache_size = 2048, .cache_level = 2, + .cache_line_size = 64, .flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE), diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h index 74c2d7a0d6285715339482b975f946779def8e58..300634b9f66832dfd4b83e2cf341fcfc75df9a3a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h @@ -303,6 +303,7 @@ struct kfd_node; struct kfd_gpu_cache_info { uint32_t cache_size; uint32_t cache_level; + uint32_t cache_line_size; uint32_t flags; /* Indicates how many Compute Units share this cache * within a SA. Value = 1 indicates the cache is not shared diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c index 9ec750666382fe9bfebbc7708144f67a3fe480e6..d889e3545120a2aa2da5f15feae297c9fab3846e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c @@ -1018,12 +1018,14 @@ int kfd_dbg_trap_device_snapshot(struct kfd_process *target, uint32_t *entry_size) { struct kfd_dbg_device_info_entry device_info; - uint32_t tmp_entry_size = *entry_size, tmp_num_devices; + uint32_t tmp_entry_size, tmp_num_devices; int i, r = 0; if (!(target && user_info && number_of_device_infos && entry_size)) return -EINVAL; + tmp_entry_size = *entry_size; + tmp_num_devices = min_t(size_t, *number_of_device_infos, target->n_pdds); *number_of_device_infos = target->n_pdds; *entry_size = min_t(size_t, *entry_size, sizeof(device_info)); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 739721254a5dfff1b989b228dcb6cbcad3d52dd1..9b33d9d2c9ad533827befe8d5a53a8c62af041cb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -1285,8 +1285,10 @@ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid) uint32_t id = KFD_FIRST_NONSIGNAL_EVENT_ID; int user_gpu_id; - if (!p) + if (!p) { + dev_warn(dev->adev->dev, "Not find process with pasid:%d\n", pasid); return; /* Presumably process exited. */ + } user_gpu_id = kfd_process_get_user_gpu_id(p, dev->id); if (unlikely(user_gpu_id == -EINVAL)) { @@ -1322,6 +1324,8 @@ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid) } } + dev_warn(dev->adev->dev, "Send SIGBUS to process %s(pasid:%d)\n", + p->lead_thread->comm, pasid); rcu_read_unlock(); /* user application will handle SIGBUS signal */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c index a7697ec8188e094a78807e1a6fcada06318af191..9a06c6fb6605851ae9c26ff4a81c66d358b9a69f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c @@ -132,6 +132,7 @@ enum SQ_INTERRUPT_ERROR_TYPE { static void event_interrupt_poison_consumption(struct kfd_node *dev, uint16_t pasid, uint16_t client_id) { + enum amdgpu_ras_block block = 0; int old_poison, ret = -EINVAL; struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); @@ -151,12 +152,14 @@ static void event_interrupt_poison_consumption(struct kfd_node *dev, case SOC15_IH_CLIENTID_SE3SH: case SOC15_IH_CLIENTID_UTCL2: ret = kfd_dqm_evict_pasid(dev->dqm, pasid); + block = AMDGPU_RAS_BLOCK__GFX; break; case SOC15_IH_CLIENTID_SDMA0: case SOC15_IH_CLIENTID_SDMA1: case SOC15_IH_CLIENTID_SDMA2: case SOC15_IH_CLIENTID_SDMA3: case SOC15_IH_CLIENTID_SDMA4: + block = AMDGPU_RAS_BLOCK__SDMA; break; default: break; @@ -171,12 +174,12 @@ static void event_interrupt_poison_consumption(struct kfd_node *dev, dev_warn(dev->adev->dev, "RAS poison consumption, unmap queue flow succeeded: client id %d\n", client_id); - amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, false); + amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, block, false); } else { dev_warn(dev->adev->dev, "RAS poison consumption, fall back to gpu reset flow: client id %d\n", client_id); - amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, true); + amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, block, true); } } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c index 2a65792fd1162ba3f21f1600724897ec78449c2f..7e2859736a558fe899c8d1bb438daa07523f2c59 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c @@ -191,6 +191,7 @@ static void print_sq_intr_info_error(uint32_t context_id0, uint32_t context_id1) static void event_interrupt_poison_consumption_v11(struct kfd_node *dev, uint16_t pasid, uint16_t source_id) { + enum amdgpu_ras_block block = 0; int ret = -EINVAL; struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); @@ -210,9 +211,11 @@ static void event_interrupt_poison_consumption_v11(struct kfd_node *dev, case SOC15_INTSRC_SQ_INTERRUPT_MSG: if (dev->dqm->ops.reset_queues) ret = dev->dqm->ops.reset_queues(dev->dqm, pasid); + block = AMDGPU_RAS_BLOCK__GFX; break; case SOC21_INTSRC_SDMA_ECC: default: + block = AMDGPU_RAS_BLOCK__GFX; break; } @@ -221,9 +224,9 @@ static void event_interrupt_poison_consumption_v11(struct kfd_node *dev, /* resetting queue passes, do page retirement without gpu reset resetting queue fails, fallback to gpu reset solution */ if (!ret) - amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, false); + amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, block, false); else - amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, true); + amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, block, true); } static bool event_interrupt_isr_v11(struct kfd_node *dev, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c index 27cdaea405017aed21ff447eec833068a9f9b101..91dd5e045b511d2aaa42aa4bd9b934e018c407ab 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c @@ -143,6 +143,7 @@ enum SQ_INTERRUPT_ERROR_TYPE { static void event_interrupt_poison_consumption_v9(struct kfd_node *dev, uint16_t pasid, uint16_t client_id) { + enum amdgpu_ras_block block = 0; int old_poison, ret = -EINVAL; struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); @@ -162,12 +163,14 @@ static void event_interrupt_poison_consumption_v9(struct kfd_node *dev, case SOC15_IH_CLIENTID_SE3SH: case SOC15_IH_CLIENTID_UTCL2: ret = kfd_dqm_evict_pasid(dev->dqm, pasid); + block = AMDGPU_RAS_BLOCK__GFX; break; case SOC15_IH_CLIENTID_SDMA0: case SOC15_IH_CLIENTID_SDMA1: case SOC15_IH_CLIENTID_SDMA2: case SOC15_IH_CLIENTID_SDMA3: case SOC15_IH_CLIENTID_SDMA4: + block = AMDGPU_RAS_BLOCK__SDMA; break; default: break; @@ -182,12 +185,12 @@ static void event_interrupt_poison_consumption_v9(struct kfd_node *dev, dev_warn(dev->adev->dev, "RAS poison consumption, unmap queue flow succeeded: client id %d\n", client_id); - amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, false); + amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, block, false); } else { dev_warn(dev->adev->dev, "RAS poison consumption, fall back to gpu reset flow: client id %d\n", client_id); - amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, true); + amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, block, true); } } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index f856901055d34e605cd4ec51fbdfc3be18e2abeb..bdc01ca9609a7e57fac05ee60d6866a5950e2b07 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -574,7 +574,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, pr_debug("svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start, prange->last); - addr = prange->start << PAGE_SHIFT; + addr = migrate->start; src = (uint64_t *)(scratch + npages); dst = scratch; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 8b7fed91352696cf2b5cafab0680ad0737fa95ee..22cbfa1bdaddb9a764053421b16159391c1ba56d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -170,6 +170,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT; m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; + m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index 15277f1d5cf0a9d9eb694ccaeec540e467ab774a..d722cbd317834a8a893a0ed5a847feb3a51d6961 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -224,6 +224,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT; m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; + m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 17fbedbf3651388edfcd0109a22d0fe9dfcd331f..677281c0793e23a694eb5a7bba9b5f9fd48f61d8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -1488,10 +1488,15 @@ void kfd_dec_compute_active(struct kfd_node *dev); /* Cgroup Support */ /* Check with device cgroup if @kfd device is accessible */ -static inline int kfd_devcgroup_check_permission(struct kfd_node *kfd) +static inline int kfd_devcgroup_check_permission(struct kfd_node *node) { #if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF) - struct drm_device *ddev = adev_to_drm(kfd->adev); + struct drm_device *ddev; + + if (node->xcp) + ddev = node->xcp->ddev; + else + ddev = adev_to_drm(node->adev); return devcgroup_check_permission(DEVCG_DEV_CHAR, DRM_MAJOR, ddev->render->index, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index c50a0dc9c9c072f5692d003bce90aaaf13615c5d..f0f7f48af4137acb088e2e903f803c345babc3ec 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1515,9 +1515,9 @@ static int svm_range_reserve_bos(struct svm_validate_context *ctx, bool intr) goto unreserve_out; } - r = amdgpu_vm_validate_pt_bos(pdd->dev->adev, - drm_priv_to_vm(pdd->drm_priv), - svm_range_bo_validate, NULL); + r = amdgpu_vm_validate(pdd->dev->adev, + drm_priv_to_vm(pdd->drm_priv), NULL, + svm_range_bo_validate, NULL); if (r) { pr_debug("failed %d validate pt bos\n", r); goto unreserve_out; @@ -1641,7 +1641,9 @@ static int svm_range_validate_and_map(struct mm_struct *mm, goto free_ctx; } - svm_range_reserve_bos(ctx, intr); + r = svm_range_reserve_bos(ctx, intr); + if (r) + goto free_ctx; p = container_of(prange->svms, struct kfd_process, svms); owner = kfd_svm_page_owner(p, find_first_bit(ctx->bitmap, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index e5f7c92eebcbbfa6a1fda115ca2b599cab48e4e8..0136c27ef49f9a4af27d1da1074851bf0fec25d2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1564,6 +1564,7 @@ static int fill_in_l1_pcache(struct kfd_cache_properties **props_ext, pcache->processor_id_low = cu_processor_id + (first_active_cu - 1); pcache->cache_level = pcache_info[cache_type].cache_level; pcache->cache_size = pcache_info[cache_type].cache_size; + pcache->cacheline_size = pcache_info[cache_type].cache_line_size; if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_DATA_CACHE) pcache->cache_type |= HSA_CACHE_TYPE_DATA; @@ -1632,6 +1633,7 @@ static int fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext, pcache->processor_id_low = cu_processor_id + (first_active_cu - 1); pcache->cache_level = pcache_info[cache_type].cache_level; + pcache->cacheline_size = pcache_info[cache_type].cache_line_size; if (KFD_GC_VERSION(knode) == IP_VERSION(9, 4, 3)) mode = adev->gmc.gmc_funcs->query_mem_partition_mode(adev); @@ -1705,6 +1707,7 @@ static void kfd_fill_cache_non_crat_info(struct kfd_topology_device *dev, struct gpu_processor_id = dev->node_props.simd_id_base; + memset(cache_info, 0, sizeof(cache_info)); pcache_info = cache_info; num_of_cache_types = kfd_get_gpu_cache_info(kdev, &pcache_info); if (!num_of_cache_types) { diff --git a/drivers/gpu/drm/amd/display/TODO b/drivers/gpu/drm/amd/display/TODO deleted file mode 100644 index a8a6c106e8c74ff8ebe7c6faff771ceb69f46036..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/amd/display/TODO +++ /dev/null @@ -1,110 +0,0 @@ -=============================================================================== -TODOs -=============================================================================== - -1. Base this on drm-next - WIP - - -2. Cleanup commit history - - -3. WIP - Drop page flip helper and use DRM's version - - -4. DONE - Flatten all DC objects - * dc_stream/core_stream/stream should just be dc_stream - * Same for other DC objects - - "Is there any major reason to keep all those abstractions? - - Could you collapse everything into struct dc_stream? - - I haven't looked recently but I didn't get the impression there was a - lot of design around what was public/protected, more whatever needed - to be used by someone else was in public." - ~ Dave Airlie - - -5. DONE - Rename DC objects to align more with DRM - * dc_surface -> dc_plane_state - * dc_stream -> dc_stream_state - - -6. DONE - Per-plane and per-stream validation - - -7. WIP - Per-plane and per-stream commit - - -8. WIP - Split pipe_ctx into plane and stream resource structs - - -9. Attach plane and stream reources to state object instead of validate_context - - -10. Remove dc_edid_caps and drm_helpers_parse_edid_caps - * Use drm_display_info instead - * Remove DC's edid quirks and rely on DRM's quirks (add quirks if needed) - - "Making sure you use the sink-specific helper libraries and kernel - subsystems, since there's really no good reason to have 2nd - implementation of those in the kernel. Looks likes that's done for mst - and edid parsing. There's still a bit a midlayer feeling to the edid - parsing side (e.g. dc_edid_caps and dm_helpers_parse_edid_caps, I - think it'd be much better if you convert that over to reading stuff - from drm_display_info and if needed, push stuff into the core). Also, - I can't come up with a good reason why DC needs all this (except to - reimplement half of our edid quirk table, which really isn't a good - idea). Might be good if you put this onto the list of things to fix - long-term, but imo not a blocker. Definitely make sure new stuff - doesn't slip in (i.e. if you start adding edid quirks to DC instead of - the drm core, refactoring to use the core edid stuff was pointless)." - ~ Daniel Vetter - - -11. Remove dc/i2caux. This folder can be somewhat misleading. It's basically an -overy complicated HW programming function for sendind and receiving i2c/aux -commands. We can greatly simplify that and move it into dc/dceXYZ like other -HW blocks. - -12. drm_modeset_lock in MST should no longer be needed in recent kernels - * Adopt appropriate locking scheme - -13. get_modes and best_encoder callbacks look a bit funny. Can probably rip out -a few indirections, and consider removing entirely and using the -drm_atomic_helper_best_encoder default behaviour. - -14. core/dc_debug.c, consider switching to the atomic state debug helpers and -moving all your driver state printing into the various atomic_print_state -callbacks. There's also plans to expose this stuff in a standard way across all -drivers, to make debugging userspace compositors easier across different hw. - -15. Move DP/HDMI dual mode adaptors to drm_dp_dual_mode_helper.c. See -dal_ddc_service_i2c_query_dp_dual_mode_adaptor. - -16. Move to core SCDC helpers (I think those are new since initial DC review). - -17. There's still a pretty massive layer cake around dp aux and DPCD handling, -with like 3 levels of abstraction and using your own structures instead of the -stuff in drm_dp_helper.h. drm_dp_helper.h isn't really great and already has 2 -incompatible styles, just means more reasons not to add a third (or well third -one gets to do the cleanup refactor). - -18. There's a pile of sink handling code, both for DP and HDMI where I didn't -immediately recognize the standard. I think long term it'd be best for the drm -subsystem if we try to move as much of that into helpers/core as possible, and -share it with drivers. But that's a very long term goal, and by far not just an -issue with DC - other drivers, especially around DP sink handling, are equally -guilty. - -19. DONE - The DC logger is still a rather sore thing, but I know that the -DRM_DEBUG stuff just isn't up to the challenges either. We need to figure out -something that integrates better with DRM and linux debug printing, while not -being useless with filtering output. dynamic debug printing might be an option. - -20. Use kernel i2c device to program HDMI retimer. Some boards have an HDMI -retimer that we need to program to pass PHY compliance. Currently that's -bypassing the i2c device and goes directly to HW. This should be changed. - -21. Remove vector.c from dc/basics. It's used in DDC code which can probably -be simplified enough to no longer need a vector implementation. diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index d4f525b66a09055909e163b815beee357f28d19d..467796d97313e215f12cb2640dbdb00731cd2a10 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -67,6 +67,7 @@ #include "amdgpu_dm_debugfs.h" #endif #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" #include "ivsrcid/ivsrcid_vislands30.h" @@ -272,6 +273,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, { u32 v_blank_start, v_blank_end, h_position, v_position; struct amdgpu_crtc *acrtc = NULL; + struct dc *dc = adev->dm.dc; if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc)) return -EINVAL; @@ -284,6 +286,9 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, return 0; } + if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed) + dc_allow_idle_optimizations(dc, false); + /* * TODO rework base driver to use values directly. * for now parse it back into reg-format @@ -1715,7 +1720,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0]; init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0]; - init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL; + if (amdgpu_dc_debug_mask & DC_DISABLE_IPS) + init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL; + + init_data.flags.disable_ips_in_vpb = 1; /* Enable DWB for tested platforms only */ if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0)) @@ -2114,6 +2122,16 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) const struct dmcub_firmware_header_v1_0 *hdr; enum dmub_asic dmub_asic; enum dmub_status status; + static enum dmub_window_memory_type window_memory_type[DMUB_WINDOW_TOTAL] = { + DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_0_INST_CONST + DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_1_STACK + DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_2_BSS_DATA + DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_3_VBIOS + DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_4_MAILBOX + DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_5_TRACEBUFF + DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_6_FW_STATE + DMUB_WINDOW_MEMORY_TYPE_FB //DMUB_WINDOW_7_SCRATCH_MEM + }; int r; switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { @@ -2211,7 +2229,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) adev->dm.dmub_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + PSP_HEADER_BYTES; - region_params.is_mailbox_in_inbox = false; + region_params.window_memory_type = window_memory_type; status = dmub_srv_calc_region_info(dmub_srv, ®ion_params, ®ion_info); @@ -2239,6 +2257,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) memory_params.cpu_fb_addr = adev->dm.dmub_bo_cpu_addr; memory_params.gpu_fb_addr = adev->dm.dmub_bo_gpu_addr; memory_params.region_info = ®ion_info; + memory_params.window_memory_type = window_memory_type; adev->dm.dmub_fb_info = kzalloc(sizeof(*adev->dm.dmub_fb_info), GFP_KERNEL); @@ -4392,6 +4411,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) enum dc_connection_type new_connection_type = dc_connection_none; const struct dc_plane_cap *plane; bool psr_feature_enabled = false; + bool replay_feature_enabled = false; int max_overlay = dm->dc->caps.max_slave_planes; dm->display_indexes_num = dm->dc->caps.max_streams; @@ -4503,6 +4523,23 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } } + /* Determine whether to enable Replay support by default. */ + if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) { + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(3, 1, 4): + case IP_VERSION(3, 1, 5): + case IP_VERSION(3, 1, 6): + case IP_VERSION(3, 2, 0): + case IP_VERSION(3, 2, 1): + case IP_VERSION(3, 5, 0): + replay_feature_enabled = true; + break; + default: + replay_feature_enabled = amdgpu_dc_feature_mask & DC_REPLAY_MASK; + break; + } + } + /* loops over all connectors on the board */ for (i = 0; i < link_cnt; i++) { struct dc_link *link = NULL; @@ -4571,6 +4608,11 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) amdgpu_dm_update_connector_after_detect(aconnector); setup_backlight_device(dm, aconnector); + /* Disable PSR if Replay can be enabled */ + if (replay_feature_enabled) + if (amdgpu_dm_set_replay_caps(link, aconnector)) + psr_feature_enabled = false; + if (psr_feature_enabled) amdgpu_dm_set_psr_caps(link); @@ -6395,10 +6437,81 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, return ret; } +/** + * DOC: panel power savings + * + * The display manager allows you to set your desired **panel power savings** + * level (between 0-4, with 0 representing off), e.g. using the following:: + * + * # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings + * + * Modifying this value can have implications on color accuracy, so tread + * carefully. + */ + +static ssize_t panel_power_savings_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = dev_get_drvdata(device); + struct drm_device *dev = connector->dev; + u8 val; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + val = to_dm_connector_state(connector->state)->abm_level == + ABM_LEVEL_IMMEDIATE_DISABLE ? 0 : + to_dm_connector_state(connector->state)->abm_level; + drm_modeset_unlock(&dev->mode_config.connection_mutex); + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t panel_power_savings_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct drm_connector *connector = dev_get_drvdata(device); + struct drm_device *dev = connector->dev; + long val; + int ret; + + ret = kstrtol(buf, 0, &val); + + if (ret) + return ret; + + if (val < 0 || val > 4) + return -EINVAL; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + to_dm_connector_state(connector->state)->abm_level = val ?: + ABM_LEVEL_IMMEDIATE_DISABLE; + drm_modeset_unlock(&dev->mode_config.connection_mutex); + + drm_kms_helper_hotplug_event(dev); + + return count; +} + +static DEVICE_ATTR_RW(panel_power_savings); + +static struct attribute *amdgpu_attrs[] = { + &dev_attr_panel_power_savings.attr, + NULL +}; + +static const struct attribute_group amdgpu_group = { + .name = "amdgpu", + .attrs = amdgpu_attrs +}; + static void amdgpu_dm_connector_unregister(struct drm_connector *connector) { struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) + sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group); + drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux); } @@ -6500,6 +6613,13 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector) to_amdgpu_dm_connector(connector); int r; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + r = sysfs_create_group(&connector->kdev->kobj, + &amdgpu_group); + if (r) + return r; + } + amdgpu_dm_register_backlight_device(amdgpu_dm_connector); if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || @@ -8519,10 +8639,22 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, dm_update_pflip_irq_state(drm_to_adev(dev), acrtc_attach); - if ((acrtc_state->update_type > UPDATE_TYPE_FAST) && - acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED && - !acrtc_state->stream->link->psr_settings.psr_feature_enabled) - amdgpu_dm_link_setup_psr(acrtc_state->stream); + if (acrtc_state->update_type > UPDATE_TYPE_FAST) { + if (acrtc_state->stream->link->replay_settings.config.replay_supported && + !acrtc_state->stream->link->replay_settings.replay_feature_enabled) { + struct amdgpu_dm_connector *aconn = + (struct amdgpu_dm_connector *)acrtc_state->stream->dm_stream_context; + amdgpu_dm_link_setup_replay(acrtc_state->stream->link, aconn); + } else if (acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED && + !acrtc_state->stream->link->psr_settings.psr_feature_enabled) { + + struct amdgpu_dm_connector *aconn = (struct amdgpu_dm_connector *) + acrtc_state->stream->dm_stream_context; + + if (!aconn->disallow_edp_enter_psr) + amdgpu_dm_link_setup_psr(acrtc_state->stream); + } + } /* Decrement skip count when PSR is enabled and we're doing fast updates. */ if (acrtc_state->update_type == UPDATE_TYPE_FAST && @@ -8549,6 +8681,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) && #endif !acrtc_state->stream->link->psr_settings.psr_allow_active && + !aconn->disallow_edp_enter_psr && (timestamp_ns - acrtc_state->stream->link->psr_settings.psr_dirty_rects_change_timestamp_ns) > 500000000) @@ -8811,11 +8944,12 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, } } /* for_each_crtc_in_state() */ - /* if there mode set or reset, disable eDP PSR */ + /* if there mode set or reset, disable eDP PSR, Replay */ if (mode_set_reset_required) { if (dm->vblank_control_workqueue) flush_workqueue(dm->vblank_control_workqueue); + amdgpu_dm_replay_disable_all(dm); amdgpu_dm_psr_disable_all(dm); } @@ -8976,16 +9110,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) trace_amdgpu_dm_atomic_commit_tail_begin(state); - if (dm->dc->caps.ips_support) { - for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { - if (new_con_state->crtc && - new_con_state->crtc->state->active && - drm_atomic_crtc_needs_modeset(new_con_state->crtc->state)) { - dc_dmub_srv_apply_idle_power_optimizations(dm->dc, false); - break; - } - } - } + if (dm->dc->caps.ips_support && dm->dc->idle_optimizations_allowed) + dc_allow_idle_optimizations(dm->dc, false); drm_atomic_helper_update_legacy_modeset_state(dev, state); drm_dp_mst_atomic_wait_for_dependencies(state); @@ -9188,6 +9314,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) * To fix this, DC should permit updating only stream properties. */ dummy_updates = kzalloc(sizeof(struct dc_surface_update) * MAX_SURFACES, GFP_ATOMIC); + if (!dummy_updates) { + DRM_ERROR("Failed to allocate memory for dummy_updates.\n"); + continue; + } for (j = 0; j < status->plane_count; j++) dummy_updates[j].surface = status->plane_states[0]; @@ -10728,11 +10858,13 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; } - ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); - if (ret) { - DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); - ret = -EINVAL; - goto fail; + if (dc_resource_is_dsc_encoding_supported(dc)) { + ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); + if (ret) { + DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); + ret = -EINVAL; + goto fail; + } } ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context, vars); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 9c1871b866cc973091cd9a7bc5bc604201f6bd16..09519b7abf67ba64f19d78599ae46723ae7004dd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -693,6 +693,7 @@ struct amdgpu_dm_connector { struct drm_display_mode freesync_vid_base; int psr_skip_count; + bool disallow_edp_enter_psr; /* Record progress status of mst*/ uint8_t mst_status; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 6e715ef3a5566edb1f65bab544b2017dc176b7a3..e23a0a276e330d55be75a58f2771e9a335c84261 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -29,6 +29,7 @@ #include "dc.h" #include "amdgpu.h" #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" #include "amdgpu_dm_crtc.h" #include "amdgpu_dm_plane.h" #include "amdgpu_dm_trace.h" @@ -95,6 +96,61 @@ bool amdgpu_dm_crtc_vrr_active(struct dm_crtc_state *dm_state) dm_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED; } +/** + * amdgpu_dm_crtc_set_panel_sr_feature() - Manage panel self-refresh features. + * + * @vblank_work: is a pointer to a struct vblank_control_work object. + * @vblank_enabled: indicates whether the DRM vblank counter is currently + * enabled (true) or disabled (false). + * @allow_sr_entry: represents whether entry into the self-refresh mode is + * allowed (true) or not allowed (false). + * + * The DRM vblank counter enable/disable action is used as the trigger to enable + * or disable various panel self-refresh features: + * + * Panel Replay and PSR SU + * - Enable when: + * - vblank counter is disabled + * - entry is allowed: usermode demonstrates an adequate number of fast + * commits) + * - CRC capture window isn't active + * - Keep enabled even when vblank counter gets enabled + * + * PSR1 + * - Enable condition same as above + * - Disable when vblank counter is enabled + */ +static void amdgpu_dm_crtc_set_panel_sr_feature( + struct vblank_control_work *vblank_work, + bool vblank_enabled, bool allow_sr_entry) +{ + struct dc_link *link = vblank_work->stream->link; + bool is_sr_active = (link->replay_settings.replay_allow_active || + link->psr_settings.psr_allow_active); + bool is_crc_window_active = false; + +#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY + is_crc_window_active = + amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base); +#endif + + if (link->replay_settings.replay_feature_enabled && + allow_sr_entry && !is_sr_active && !is_crc_window_active) { + amdgpu_dm_replay_enable(vblank_work->stream, true); + } else if (vblank_enabled) { + if (link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && is_sr_active) + amdgpu_dm_psr_disable(vblank_work->stream); + } else if (link->psr_settings.psr_feature_enabled && + allow_sr_entry && !is_sr_active && !is_crc_window_active) { + + struct amdgpu_dm_connector *aconn = + (struct amdgpu_dm_connector *) vblank_work->stream->dm_stream_context; + + if (!aconn->disallow_edp_enter_psr) + amdgpu_dm_psr_enable(vblank_work->stream); + } +} + static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) { struct vblank_control_work *vblank_work = @@ -123,18 +179,10 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) * fill_dc_dirty_rects(). */ if (vblank_work->stream && vblank_work->stream->link) { - if (vblank_work->enable) { - if (vblank_work->stream->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && - vblank_work->stream->link->psr_settings.psr_allow_active) - amdgpu_dm_psr_disable(vblank_work->stream); - } else if (vblank_work->stream->link->psr_settings.psr_feature_enabled && - !vblank_work->stream->link->psr_settings.psr_allow_active && -#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY - !amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base) && -#endif - vblank_work->acrtc->dm_irq_params.allow_psr_entry) { - amdgpu_dm_psr_enable(vblank_work->stream); - } + amdgpu_dm_crtc_set_panel_sr_feature( + vblank_work, vblank_work->enable, + vblank_work->acrtc->dm_irq_params.allow_psr_entry || + vblank_work->stream->link->replay_settings.replay_feature_enabled); } mutex_unlock(&dm->dc_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 68a846323912768edea6c6d330a3491c3aff1b27..eee4945653e2d18d09f8bfc8175251499950f53c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -1483,7 +1483,7 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, const uint32_t rd_buf_size = 10; struct pipe_ctx *pipe_ctx; ssize_t result = 0; - int i, r, str_len = 30; + int i, r, str_len = 10; rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); @@ -2971,6 +2971,53 @@ static int allow_edp_hotplug_detection_set(void *data, u64 val) return 0; } +/* check if kernel disallow eDP enter psr state + * cat /sys/kernel/debug/dri/0/eDP-X/disallow_edp_enter_psr + * 0: allow edp enter psr; 1: disallow + */ +static int disallow_edp_enter_psr_get(void *data, u64 *val) +{ + struct amdgpu_dm_connector *aconnector = data; + + *val = (u64) aconnector->disallow_edp_enter_psr; + return 0; +} + +/* set kernel disallow eDP enter psr state + * echo 0x0 /sys/kernel/debug/dri/0/eDP-X/disallow_edp_enter_psr + * 0: allow edp enter psr; 1: disallow + * + * usage: test app read crc from PSR eDP rx. + * + * during kernel boot up, kernel write dpcd 0x170 = 5. + * this notify eDP rx psr enable and let rx check crc. + * rx fw will start checking crc for rx internal logic. + * crc read count within dpcd 0x246 is not updated and + * value is 0. when eDP tx driver wants to read rx crc + * from dpcd 0x246, 0x270, read count 0 lead tx driver + * timeout. + * + * to avoid this, we add this debugfs to let test app to disbable + * rx crc checking for rx internal logic. then test app can read + * non-zero crc read count. + * + * expected app sequence is as below: + * 1. disable eDP PHY and notify eDP rx with dpcd 0x600 = 2. + * 2. echo 0x1 /sys/kernel/debug/dri/0/eDP-X/disallow_edp_enter_psr + * 3. enable eDP PHY and notify eDP rx with dpcd 0x600 = 1 but + * without dpcd 0x170 = 5. + * 4. read crc from rx dpcd 0x270, 0x246, etc. + * 5. echo 0x0 /sys/kernel/debug/dri/0/eDP-X/disallow_edp_enter_psr. + * this will let eDP back to normal with psr setup dpcd 0x170 = 5. + */ +static int disallow_edp_enter_psr_set(void *data, u64 val) +{ + struct amdgpu_dm_connector *aconnector = data; + + aconnector->disallow_edp_enter_psr = val ? true : false; + return 0; +} + static int dmub_trace_mask_set(void *data, u64 val) { struct amdgpu_device *adev = data; @@ -3092,6 +3139,10 @@ DEFINE_DEBUGFS_ATTRIBUTE(allow_edp_hotplug_detection_fops, allow_edp_hotplug_detection_get, allow_edp_hotplug_detection_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(disallow_edp_enter_psr_fops, + disallow_edp_enter_psr_get, + disallow_edp_enter_psr_set, "%llu\n"); + DEFINE_SHOW_ATTRIBUTE(current_backlight); DEFINE_SHOW_ATTRIBUTE(target_backlight); @@ -3265,6 +3316,8 @@ void connector_debugfs_init(struct amdgpu_dm_connector *connector) &edp_ilr_debugfs_fops); debugfs_create_file("allow_edp_hotplug_detection", 0644, dir, connector, &allow_edp_hotplug_detection_fops); + debugfs_create_file("disallow_edp_enter_psr", 0644, dir, connector, + &disallow_edp_enter_psr_fops); } for (i = 0; i < ARRAY_SIZE(connector_debugfs_entries); i++) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index 58b880acb087ae73352e9ac487d5ccd033f03f4d..3390f0d8420a05dc6d9daae1f3d8c4f53de57aed 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -711,7 +711,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev, { bool st; enum dc_irq_source irq_source; - + struct dc *dc = adev->dm.dc; struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc_id]; if (!acrtc) { @@ -729,6 +729,9 @@ static inline int dm_irq_state(struct amdgpu_device *adev, st = (state == AMDGPU_IRQ_STATE_ENABLE); + if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed) + dc_allow_idle_optimizations(dc, false); + dc_interrupt_set(adev->dm.dc, irq_source, st); return 0; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index 5ce542b1f8604202be02ca4cac07b041b809aa4e..738a58eebba780fc7f846b29687a065fbdb80107 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -60,21 +60,26 @@ static bool link_supports_replay(struct dc_link *link, struct amdgpu_dm_connecto if (!as_caps->dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT) return false; + // Sink shall populate line deviation information + if (dpcd_caps->pr_info.pixel_deviation_per_line == 0 || + dpcd_caps->pr_info.max_deviation_line == 0) + return false; + return true; } /* - * amdgpu_dm_setup_replay() - setup replay configuration + * amdgpu_dm_set_replay_caps() - setup Replay capabilities * @link: link * @aconnector: aconnector * */ -bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector) +bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector *aconnector) { - struct replay_config pr_config; + struct replay_config pr_config = { 0 }; union replay_debug_flags *debug_flags = NULL; - // For eDP, if Replay is supported, return true to skip checks + // If Replay is already set to support, return true to skip checks if (link->replay_settings.config.replay_supported) return true; @@ -87,27 +92,50 @@ bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *ac if (!link_supports_replay(link, aconnector)) return false; - // Mark Replay is supported in link and update related attributes + // Mark Replay is supported in pr_config pr_config.replay_supported = true; - pr_config.replay_power_opt_supported = 0; - pr_config.replay_enable_option |= pr_enable_option_static_screen; - pr_config.replay_timing_sync_supported = aconnector->max_vfreq >= 2 * aconnector->min_vfreq; - - if (!pr_config.replay_timing_sync_supported) - pr_config.replay_enable_option &= ~pr_enable_option_general_ui; debug_flags = (union replay_debug_flags *)&pr_config.debug_flags; debug_flags->u32All = 0; debug_flags->bitfields.visual_confirm = link->ctx->dc->debug.visual_confirm == VISUAL_CONFIRM_REPLAY; - link->replay_settings.replay_feature_enabled = true; - init_replay_config(link, &pr_config); return true; } +/* + * amdgpu_dm_link_setup_replay() - configure replay link + * @link: link + * @aconnector: aconnector + * + */ +bool amdgpu_dm_link_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector) +{ + struct replay_config *pr_config; + + if (link == NULL || aconnector == NULL) + return false; + + pr_config = &link->replay_settings.config; + + if (!pr_config->replay_supported) + return false; + + pr_config->replay_power_opt_supported = 0x11; + pr_config->replay_smu_opt_supported = false; + pr_config->replay_enable_option |= pr_enable_option_static_screen; + pr_config->replay_support_fast_resync_in_ultra_sleep_mode = aconnector->max_vfreq >= 2 * aconnector->min_vfreq; + pr_config->replay_timing_sync_supported = false; + + if (!pr_config->replay_timing_sync_supported) + pr_config->replay_enable_option &= ~pr_enable_option_general_ui; + + link->replay_settings.replay_feature_enabled = true; + + return true; +} /* * amdgpu_dm_replay_enable() - enable replay f/w @@ -117,51 +145,23 @@ bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *ac */ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) { - uint64_t state; - unsigned int retry_count; bool replay_active = true; - const unsigned int max_retry = 1000; - bool force_static = true; struct dc_link *link = NULL; - if (stream == NULL) return false; link = stream->link; - if (link == NULL) - return false; - - link->dc->link_srv->edp_setup_replay(link, stream); - - link->dc->link_srv->edp_set_replay_allow_active(link, NULL, false, false, NULL); - - link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, false, true, NULL); - - if (wait == true) { - - for (retry_count = 0; retry_count <= max_retry; retry_count++) { - dc_link_get_replay_state(link, &state); - if (replay_active) { - if (state != REPLAY_STATE_0 && - (!force_static || state == REPLAY_STATE_3)) - break; - } else { - if (state == REPLAY_STATE_0) - break; - } - udelay(500); - } - - /* assert if max retry hit */ - if (retry_count >= max_retry) - ASSERT(0); - } else { - /* To-do: Add trace log */ + if (link) { + link->dc->link_srv->edp_setup_replay(link, stream); + link->dc->link_srv->edp_set_coasting_vtotal(link, stream->timing.v_total); + DRM_DEBUG_DRIVER("Enabling replay...\n"); + link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, wait, false, NULL); + return true; } - return true; + return false; } /* @@ -172,12 +172,31 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) */ bool amdgpu_dm_replay_disable(struct dc_stream_state *stream) { + bool replay_active = false; + struct dc_link *link = NULL; - if (stream->link) { + if (stream == NULL) + return false; + + link = stream->link; + + if (link) { DRM_DEBUG_DRIVER("Disabling replay...\n"); - stream->link->dc->link_srv->edp_set_replay_allow_active(stream->link, NULL, false, false, NULL); + link->dc->link_srv->edp_set_replay_allow_active(stream->link, &replay_active, true, false, NULL); return true; } return false; } + +/* + * amdgpu_dm_replay_disable_all() - disable replay f/w + * if replay is enabled on any stream + * + * Return: true if success + */ +bool amdgpu_dm_replay_disable_all(struct amdgpu_display_manager *dm) +{ + DRM_DEBUG_DRIVER("Disabling replay if replay is enabled on any stream\n"); + return dc_set_replay_allow_active(dm->dc, false); +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h index 01cba3cd62463a2a6ea172383e7fbfebf7d5419a..f0d30eb473126cd0ccf5fa38768c693e70d403b8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.h @@ -40,7 +40,9 @@ enum replay_enable_option { bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool enable); -bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector); +bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector *aconnector); +bool amdgpu_dm_link_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector); bool amdgpu_dm_replay_disable(struct dc_stream_state *stream); +bool amdgpu_dm_replay_disable_all(struct amdgpu_display_manager *dm); #endif /* AMDGPU_DM_AMDGPU_DM_REPLAY_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/basics/conversion.c b/drivers/gpu/drm/amd/display/dc/basics/conversion.c index 1090d235086aca2f99af4c5f7f5483574b7813af..bd1f60ecaba4f83bc3ecc58bb368db52c3cd6ea9 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/conversion.c +++ b/drivers/gpu/drm/amd/display/dc/basics/conversion.c @@ -101,6 +101,40 @@ void convert_float_matrix( } } +static struct fixed31_32 int_frac_to_fixed_point(uint16_t arg, + uint8_t integer_bits, + uint8_t fractional_bits) +{ + struct fixed31_32 result; + uint16_t sign_mask = 1 << (fractional_bits + integer_bits); + uint16_t value_mask = sign_mask - 1; + + result.value = (long long)(arg & value_mask) << + (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits); + + if (arg & sign_mask) + result = dc_fixpt_neg(result); + + return result; +} + +/** + * convert_hw_matrix - converts HW values into fixed31_32 matrix. + * @matrix: fixed point 31.32 matrix + * @reg: array of register values + * @buffer_size: size of the array of register values + * + * Converts HW register spec defined format S2D13 into a fixed-point 31.32 + * matrix. + */ +void convert_hw_matrix(struct fixed31_32 *matrix, + uint16_t *reg, + uint32_t buffer_size) +{ + for (int i = 0; i < buffer_size; ++i) + matrix[i] = int_frac_to_fixed_point(reg[i], 2, 13); +} + static uint32_t find_gcd(uint32_t a, uint32_t b) { uint32_t remainder; diff --git a/drivers/gpu/drm/amd/display/dc/basics/conversion.h b/drivers/gpu/drm/amd/display/dc/basics/conversion.h index 81da4e6f7a1acb074c02d719b068661b1c06db81..a433cef78496f22e8207f283e32f3d46cec8b058 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/conversion.h +++ b/drivers/gpu/drm/amd/display/dc/basics/conversion.h @@ -41,6 +41,10 @@ void convert_float_matrix( void reduce_fraction(uint32_t num, uint32_t den, uint32_t *out_num, uint32_t *out_den); +void convert_hw_matrix(struct fixed31_32 *matrix, + uint16_t *reg, + uint32_t buffer_size); + static inline unsigned int log_2(unsigned int num) { return ilog2(num); diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.c b/drivers/gpu/drm/amd/display/dc/bios/command_table.c index 818a529cacc37382e6598604270cd06051255a93..86f9198e7501185048f582be4962c2597772ded1 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c @@ -37,7 +37,7 @@ #define EXEC_BIOS_CMD_TABLE(command, params)\ (amdgpu_atom_execute_table(((struct amdgpu_device *)bp->base.ctx->driver_context)->mode_info.atom_context, \ GetIndexIntoMasterTable(COMMAND, command), \ - (uint32_t *)¶ms) == 0) + (uint32_t *)¶ms, sizeof(params)) == 0) #define BIOS_CMD_TABLE_REVISION(command, frev, crev)\ amdgpu_atom_parse_cmd_header(((struct amdgpu_device *)bp->base.ctx->driver_context)->mode_info.atom_context, \ diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index 293a919d605d1657d3963ed292cd4c3115d3fb3f..cbae1be7b0093cfa76f4263055f90b4e9b358a64 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -49,7 +49,7 @@ #define EXEC_BIOS_CMD_TABLE(fname, params)\ (amdgpu_atom_execute_table(((struct amdgpu_device *)bp->base.ctx->driver_context)->mode_info.atom_context, \ GET_INDEX_INTO_MASTER_TABLE(command, fname), \ - (uint32_t *)¶ms) == 0) + (uint32_t *)¶ms, sizeof(params)) == 0) #define BIOS_CMD_TABLE_REVISION(fname, frev, crev)\ amdgpu_atom_parse_cmd_header(((struct amdgpu_device *)bp->base.ctx->driver_context)->mode_info.atom_context, \ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c index 0c6a4ab72b1d298e00a856c640e936fac2f89a92..e3e1940198a9c55f6ad036fa411d2cf9226c1173 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c @@ -707,9 +707,7 @@ void rn_clk_mgr_construct( int is_green_sardine = 0; struct clk_log_info log_info = {0}; -#if defined(CONFIG_DRM_AMD_DC_FP) is_green_sardine = ASICREV_IS_GREEN_SARDINE(ctx->asic_id.hw_internal_rev); -#endif clk_mgr->base.ctx = ctx; clk_mgr->base.funcs = &dcn21_funcs; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c index 8c9d45e5b13b8399984cf35c7b22e486d74d4552..d72acbb049b1ba33bd0a3bbdd2d37c4dff12ea52 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c @@ -185,10 +185,6 @@ int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int reque VBIOSSMC_MSG_SetHardMinDcfclkByFreq, khz_to_mhz_ceil(requested_dcfclk_khz)); -#ifdef DBG - smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000); -#endif - return actual_dcfclk_set_mhz * 1000; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c index e4f96b6fd79d0189896d50f94ab5eb70297db7dc..19e5b3be92757ce8a59bfb951341d3b3e607c699 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c @@ -180,10 +180,6 @@ int dcn301_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int request VBIOSSMC_MSG_SetHardMinDcfclkByFreq, khz_to_mhz_ceil(requested_dcfclk_khz)); -#ifdef DBG - smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000); -#endif - return actual_dcfclk_set_mhz * 1000; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c index 32279c5db72483f24106a5b282622903baaaa6ac..6904e95113c12ab243fa878e941e6a1d7c033e4a 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c @@ -202,10 +202,6 @@ int dcn31_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requeste VBIOSSMC_MSG_SetHardMinDcfclkByFreq, khz_to_mhz_ceil(requested_dcfclk_khz)); -#ifdef DBG - smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000); -#endif - return actual_dcfclk_set_mhz * 1000; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c index 07baa10a86473d64ed06efbb5d0b3ecf92af8aa2..c4af406146b7731fd2dda0a2c395ba5f2792d369 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c @@ -220,12 +220,6 @@ int dcn314_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int request VBIOSSMC_MSG_SetHardMinDcfclkByFreq, khz_to_mhz_ceil(requested_dcfclk_khz)); -#ifdef DBG - smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", - actual_dcfclk_set_mhz, - actual_dcfclk_set_mhz * 1000); -#endif - return actual_dcfclk_set_mhz * 1000; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c index 1042cf1a3ab04b9fb5d8e4cbe0283c4a06148a44..879f1494c4cd9d04ea400c6f9bea0104174d7b98 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c @@ -215,10 +215,6 @@ int dcn315_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int request VBIOSSMC_MSG_SetHardMinDcfclkByFreq, khz_to_mhz_ceil(requested_dcfclk_khz)); -#ifdef DBG - smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000); -#endif - return actual_dcfclk_set_mhz * 1000; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.c index 3ed19197a75583cb636ead09425ef2a352f5042c..8b82092b91cd9d42d8d7edeca4ce100d8a1c256e 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.c @@ -189,10 +189,6 @@ int dcn316_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int request VBIOSSMC_MSG_SetHardMinDcfclkByFreq, khz_to_mhz_ceil(requested_dcfclk_khz)); -#ifdef DBG - smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000); -#endif - return actual_dcfclk_set_mhz * 1000; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index aadd07bc68c5dba969fb4f7e158ba1ea990c7b5a..e64e45e4c8338d68ecc672776aca6afc47c1816b 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -387,7 +387,15 @@ static void dcn32_update_clocks_update_dentist( uint32_t temp_dispclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / temp_disp_divider; if (clk_mgr->smu_present) - dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(temp_dispclk_khz)); + /* + * SMU uses discrete dispclk presets. We applied + * the same formula to increase our dppclk_khz + * to the next matching discrete value. By + * contract, we should use the preset dispclk + * floored in Mhz to describe the intended clock. + */ + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, + khz_to_mhz_floor(temp_dispclk_khz)); if (dc->debug.override_dispclk_programming) { REG_GET(DENTIST_DISPCLK_CNTL, @@ -426,7 +434,15 @@ static void dcn32_update_clocks_update_dentist( /* do requested DISPCLK updates*/ if (clk_mgr->smu_present) - dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr->base.clks.dispclk_khz)); + /* + * SMU uses discrete dispclk presets. We applied + * the same formula to increase our dppclk_khz + * to the next matching discrete value. By + * contract, we should use the preset dispclk + * floored in Mhz to describe the intended clock. + */ + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, + khz_to_mhz_floor(clk_mgr->base.clks.dispclk_khz)); if (dc->debug.override_dispclk_programming) { REG_GET(DENTIST_DISPCLK_CNTL, @@ -493,6 +509,8 @@ static void dcn32_auto_dpm_test_log( } } + msleep(5); + mall_ss_size_bytes = context->bw_ctx.bw.dcn.mall_ss_size_bytes; dispclk_khz_reg = REG_READ(CLK1_CLK0_CURRENT_CNT); // DISPCLK @@ -734,7 +752,15 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; if (clk_mgr->smu_present && !dpp_clock_lowered) - dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz)); + /* + * SMU uses discrete dppclk presets. We applied + * the same formula to increase our dppclk_khz + * to the next matching discrete value. By + * contract, we should use the preset dppclk + * floored in Mhz to describe the intended clock. + */ + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, + khz_to_mhz_floor(clk_mgr_base->clks.dppclk_khz)); update_dppclk = true; } @@ -765,7 +791,15 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, dcn32_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); dcn32_update_clocks_update_dentist(clk_mgr, context); if (clk_mgr->smu_present) - dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz)); + /* + * SMU uses discrete dppclk presets. We applied + * the same formula to increase our dppclk_khz + * to the next matching discrete value. By + * contract, we should use the preset dppclk + * floored in Mhz to describe the intended clock. + */ + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, + khz_to_mhz_floor(clk_mgr_base->clks.dppclk_khz)); } else { /* if clock is being raised, increase refclk before lowering DTO */ if (update_dppclk || update_dispclk) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr_smu_msg.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr_smu_msg.h index a34c258c19dc20e492d6579d84e3ab0d04d67ae6..c76352a817de52310fbc4a56c7cfebff37f965f4 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr_smu_msg.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr_smu_msg.h @@ -36,8 +36,7 @@ #define DALSMC_MSG_SetCabForUclkPstate 0x12 #define DALSMC_Result_OK 0x1 -void -dcn32_smu_send_fclk_pstate_message(struct clk_mgr_internal *clk_mgr, bool enable); +void dcn32_smu_send_fclk_pstate_message(struct clk_mgr_internal *clk_mgr, bool enable); void dcn32_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr); void dcn32_smu_set_pme_workaround(struct clk_mgr_internal *clk_mgr); void dcn32_smu_send_cab_for_uclk_message(struct clk_mgr_internal *clk_mgr, unsigned int num_ways); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 9c660d1facc7699d7a1b3f90292ae31d985fd259..06edca50a8fa1cbe7bcbda2cad48bcf2bbb6ea39 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -384,19 +384,6 @@ static void dcn35_enable_pme_wa(struct clk_mgr *clk_mgr_base) dcn35_smu_enable_pme_wa(clk_mgr); } -void dcn35_init_clocks(struct clk_mgr *clk_mgr) -{ - uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz; - - memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); - - // Assumption is that boot state always supports pstate - clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk; // restore ref_dtbclk - clk_mgr->clks.p_state_change_support = true; - clk_mgr->clks.prev_p_state_change_support = true; - clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN; - clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN; -} bool dcn35_are_clock_states_equal(struct dc_clocks *a, struct dc_clocks *b) @@ -422,6 +409,23 @@ static void dcn35_dump_clk_registers(struct clk_state_registers_and_bypass *regs { } +static void init_clk_states(struct clk_mgr *clk_mgr) +{ + uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz; + memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); + + clk_mgr->clks.dtbclk_en = true; + clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk; // restore ref_dtbclk + clk_mgr->clks.p_state_change_support = true; + clk_mgr->clks.prev_p_state_change_support = true; + clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN; + clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN; +} + +void dcn35_init_clocks(struct clk_mgr *clk_mgr) +{ + init_clk_states(clk_mgr); +} static struct clk_bw_params dcn35_bw_params = { .vram_type = Ddr4MemType, .num_channels = 1, @@ -437,32 +441,32 @@ static struct wm_table ddr5_wm_table = { .wm_inst = WM_A, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.72, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .valid = true, }, { .wm_inst = WM_B, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.72, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .valid = true, }, { .wm_inst = WM_C, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.72, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .valid = true, }, { .wm_inst = WM_D, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.72, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .valid = true, }, } @@ -474,32 +478,32 @@ static struct wm_table lpddr5_wm_table = { .wm_inst = WM_A, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .valid = true, }, { .wm_inst = WM_B, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .valid = true, }, { .wm_inst = WM_C, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .valid = true, }, { .wm_inst = WM_D, .wm_type = WM_TYPE_PSTATE_CHG, .pstate_latency_us = 11.65333, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .valid = true, }, } @@ -826,7 +830,7 @@ static void dcn35_set_low_power_state(struct clk_mgr *clk_mgr_base) } } -static void dcn35_set_idle_state(struct clk_mgr *clk_mgr_base, bool allow_idle) +static void dcn35_set_ips_idle_state(struct clk_mgr *clk_mgr_base, bool allow_idle) { struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct dc *dc = clk_mgr_base->ctx->dc; @@ -874,7 +878,7 @@ static bool dcn35_is_ips_supported(struct clk_mgr *clk_mgr_base) return ips_supported; } -static uint32_t dcn35_get_idle_state(struct clk_mgr *clk_mgr_base) +static uint32_t dcn35_get_ips_idle_state(struct clk_mgr *clk_mgr_base) { struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); @@ -883,7 +887,7 @@ static uint32_t dcn35_get_idle_state(struct clk_mgr *clk_mgr_base) static void dcn35_init_clocks_fpga(struct clk_mgr *clk_mgr) { - dcn35_init_clocks(clk_mgr); + init_clk_states(clk_mgr); /* TODO: Implement the functions and remove the ifndef guard */ } @@ -968,8 +972,8 @@ static struct clk_mgr_funcs dcn35_funcs = { .set_low_power_state = dcn35_set_low_power_state, .exit_low_power_state = dcn35_exit_low_power_state, .is_ips_supported = dcn35_is_ips_supported, - .set_idle_state = dcn35_set_idle_state, - .get_idle_state = dcn35_get_idle_state + .set_idle_state = dcn35_set_ips_idle_state, + .get_idle_state = dcn35_get_ips_idle_state }; struct clk_mgr_funcs dcn35_fpga_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c index 6d4a1ffab5ed9d7ed1f82830eee45e818851f6ec..a07f7e685d2890dc7aa50fa0cda8fc6256c156c0 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c @@ -447,6 +447,9 @@ void dcn35_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable) void dcn35_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) { + if (!clk_mgr->smu_present) + return; + dcn35_smu_send_msg_with_param( clk_mgr, VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown, @@ -458,6 +461,9 @@ int dcn35_smu_exit_low_power_state(struct clk_mgr_internal *clk_mgr) { int retv; + if (!clk_mgr->smu_present) + return 0; + retv = dcn35_smu_send_msg_with_param( clk_mgr, VBIOSSMC_MSG_DispPsrExit, @@ -470,6 +476,9 @@ int dcn35_smu_get_ips_supported(struct clk_mgr_internal *clk_mgr) { int retv; + if (!clk_mgr->smu_present) + return 0; + retv = dcn35_smu_send_msg_with_param( clk_mgr, VBIOSSMC_MSG_QueryIPS2Support, @@ -481,6 +490,9 @@ int dcn35_smu_get_ips_supported(struct clk_mgr_internal *clk_mgr) void dcn35_smu_write_ips_scratch(struct clk_mgr_internal *clk_mgr, uint32_t param) { + if (!clk_mgr->smu_present) + return; + REG_WRITE(MP1_SMN_C2PMSG_71, param); //smu_print("%s: write_ips_scratch = %x\n", __func__, param); } @@ -489,6 +501,9 @@ uint32_t dcn35_smu_read_ips_scratch(struct clk_mgr_internal *clk_mgr) { uint32_t retv; + if (!clk_mgr->smu_present) + return 0; + retv = REG_READ(MP1_SMN_C2PMSG_71); //smu_print("%s: dcn35_smu_read_ips_scratch = %x\n", __func__, retv); return retv; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index aa7c02ba948e9ce63aa84eb7518f9c73c80d107a..72512903f88f76c126bc958f9982591255d9952f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -414,6 +414,8 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, if (dc->optimized_required || dc->wm_optimized_required) return false; + dc_exit_ips_for_hw_access(dc); + stream->adjust.v_total_max = adjust->v_total_max; stream->adjust.v_total_mid = adjust->v_total_mid; stream->adjust.v_total_mid_frame_num = adjust->v_total_mid_frame_num; @@ -454,6 +456,8 @@ bool dc_stream_get_last_used_drr_vtotal(struct dc *dc, int i = 0; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; @@ -484,6 +488,8 @@ bool dc_stream_get_crtc_position(struct dc *dc, bool ret = false; struct crtc_position position; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; @@ -603,6 +609,8 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, if (pipe == NULL) return false; + dc_exit_ips_for_hw_access(dc); + /* By default, capture the full frame */ param.windowa_x_start = 0; param.windowa_y_start = 0; @@ -662,6 +670,8 @@ bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, struct pipe_ctx *pipe; struct timing_generator *tg; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { pipe = &dc->current_state->res_ctx.pipe_ctx[i]; if (pipe->stream == stream) @@ -686,6 +696,8 @@ void dc_stream_set_dyn_expansion(struct dc *dc, struct dc_stream_state *stream, int i; struct pipe_ctx *pipe_ctx; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) { @@ -721,6 +733,8 @@ void dc_stream_set_dither_option(struct dc_stream_state *stream, if (option > DITHER_OPTION_MAX) return; + dc_exit_ips_for_hw_access(stream->ctx->dc); + stream->dither_option = option; memset(¶ms, 0, sizeof(params)); @@ -745,6 +759,8 @@ bool dc_stream_set_gamut_remap(struct dc *dc, const struct dc_stream_state *stre bool ret = false; struct pipe_ctx *pipes; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) { pipes = &dc->current_state->res_ctx.pipe_ctx[i]; @@ -762,6 +778,8 @@ bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream) bool ret = false; struct pipe_ctx *pipes; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) { @@ -788,6 +806,8 @@ void dc_stream_set_static_screen_params(struct dc *dc, struct pipe_ctx *pipes_affected[MAX_PIPES]; int num_pipes_affected = 0; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < num_streams; i++) { struct dc_stream_state *stream = streams[i]; @@ -1766,6 +1786,8 @@ void dc_enable_stereo( int i, j; struct pipe_ctx *pipe; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { if (context != NULL) { pipe = &context->res_ctx.pipe_ctx[i]; @@ -1785,6 +1807,8 @@ void dc_enable_stereo( void dc_trigger_sync(struct dc *dc, struct dc_state *context) { if (context->stream_count > 1 && !dc->debug.disable_timing_sync) { + dc_exit_ips_for_hw_access(dc); + enable_timing_multisync(dc, context); program_timing_sync(dc, context); } @@ -2041,6 +2065,8 @@ enum dc_status dc_commit_streams(struct dc *dc, if (!streams_changed(dc, streams, stream_count)) return res; + dc_exit_ips_for_hw_access(dc); + DC_LOG_DC("%s: %d streams\n", __func__, stream_count); for (i = 0; i < stream_count; i++) { @@ -3067,6 +3093,10 @@ static bool update_planes_and_stream_state(struct dc *dc, if (otg_master && otg_master->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) resource_build_test_pattern_params(&context->res_ctx, otg_master); + + if (otg_master && (otg_master->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422 || + otg_master->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)) + resource_build_subsampling_params(&context->res_ctx, otg_master); } } @@ -3376,6 +3406,8 @@ static void commit_planes_for_stream_fast(struct dc *dc, int i, j; struct pipe_ctx *top_pipe_to_program = NULL; struct dc_stream_status *stream_status = NULL; + dc_exit_ips_for_hw_access(dc); + dc_z10_restore(dc); top_pipe_to_program = resource_get_otg_master_for_stream( @@ -3503,10 +3535,23 @@ static void commit_planes_for_stream(struct dc *dc, // dc->current_state anymore, so we have to cache it before we apply // the new SubVP context subvp_prev_use = false; + dc_exit_ips_for_hw_access(dc); + dc_z10_restore(dc); if (update_type == UPDATE_TYPE_FULL) wait_for_outstanding_hw_updates(dc, context); + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->stream && pipe->plane_state) { + set_p_state_switch_method(dc, context, pipe); + + if (dc->debug.visual_confirm) + dc_update_visual_confirm_color(dc, context, pipe); + } + } + if (update_type == UPDATE_TYPE_FULL) { dc_allow_idle_optimizations(dc, false); @@ -3541,17 +3586,6 @@ static void commit_planes_for_stream(struct dc *dc, } } - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - if (pipe->stream && pipe->plane_state) { - set_p_state_switch_method(dc, context, pipe); - - if (dc->debug.visual_confirm) - dc_update_visual_confirm_color(dc, context, pipe); - } - } - if (stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) { struct pipe_ctx *mpcc_pipe; struct pipe_ctx *odm_pipe; @@ -3817,7 +3851,9 @@ static void commit_planes_for_stream(struct dc *dc, * programming has completed (we turn on phantom OTG in order * to complete the plane disable for phantom pipes). */ - dc->hwss.apply_ctx_to_hw(dc, context); + + if (dc->hwss.disable_phantom_streams) + dc->hwss.disable_phantom_streams(dc, context); } if (update_type != UPDATE_TYPE_FAST) @@ -4382,6 +4418,8 @@ bool dc_update_planes_and_stream(struct dc *dc, bool is_plane_addition = 0; bool is_fast_update_only; + dc_exit_ips_for_hw_access(dc); + populate_fast_updates(fast_update, srf_updates, surface_count, stream_update); is_fast_update_only = fast_update_only(dc, fast_update, srf_updates, surface_count, stream_update, stream); @@ -4502,6 +4540,8 @@ void dc_commit_updates_for_stream(struct dc *dc, int i, j; struct dc_fast_update fast_update[MAX_SURFACES] = {0}; + dc_exit_ips_for_hw_access(dc); + populate_fast_updates(fast_update, srf_updates, surface_count, stream_update); stream_status = dc_stream_get_status(stream); context = dc->current_state; @@ -4686,6 +4726,8 @@ void dc_set_power_state( case DC_ACPI_CM_POWER_STATE_D0: dc_state_construct(dc, dc->current_state); + dc_exit_ips_for_hw_access(dc); + dc_z10_restore(dc); dc->hwss.init_hw(dc); @@ -4827,6 +4869,12 @@ void dc_allow_idle_optimizations(struct dc *dc, bool allow) dc->idle_optimizations_allowed = allow; } +void dc_exit_ips_for_hw_access(struct dc *dc) +{ + if (dc->caps.ips_support) + dc_allow_idle_optimizations(dc, false); +} + bool dc_dmub_is_ips_idle_state(struct dc *dc) { uint32_t idle_state = 0; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 9fbdb09697fd5ea16abe86e4f970e80fb764ff7f..96ea283bd16904d955ea55cf4e4992bc1a41b4c5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -822,6 +822,16 @@ static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ct stream->timing.v_border_bottom + stream->timing.v_border_top; + /* Recout for ODM slices after the first slice need one extra left edge pixel + * for 3-tap chroma subsampling. + */ + if (odm_slice_idx > 0 && + (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422 || + pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)) { + odm_rec.x -= 1; + odm_rec.width += 1; + } + return odm_rec; } @@ -1438,6 +1448,7 @@ void resource_build_test_pattern_params(struct resource_context *res_ctx, enum controller_dp_test_pattern controller_test_pattern; enum controller_dp_color_space controller_color_space; enum dc_color_depth color_depth = otg_master->stream->timing.display_color_depth; + enum dc_pixel_encoding pixel_encoding = otg_master->stream->timing.pixel_encoding; int h_active = otg_master->stream->timing.h_addressable + otg_master->stream->timing.h_border_left + otg_master->stream->timing.h_border_right; @@ -1469,10 +1480,36 @@ void resource_build_test_pattern_params(struct resource_context *res_ctx, else params->width = last_odm_slice_width; + /* Extra left edge pixel is required for 3-tap chroma subsampling. */ + if (i != 0 && (pixel_encoding == PIXEL_ENCODING_YCBCR422 || + pixel_encoding == PIXEL_ENCODING_YCBCR420)) { + params->offset -= 1; + params->width += 1; + } + offset += odm_slice_width; } } +void resource_build_subsampling_params(struct resource_context *res_ctx, + struct pipe_ctx *otg_master) +{ + struct pipe_ctx *opp_heads[MAX_PIPES]; + int odm_cnt = 1; + int i; + + odm_cnt = resource_get_opp_heads_for_otg_master(otg_master, res_ctx, opp_heads); + + /* For ODM slices after the first slice, extra left edge pixel is required + * for 3-tap chroma subsampling. + */ + if (otg_master->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422 || + otg_master->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) { + for (i = 0; i < odm_cnt; i++) + opp_heads[i]->stream_res.left_edge_extra_pixel = (i == 0) ? false : true; + } +} + bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) { const struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -1834,23 +1871,6 @@ int resource_find_any_free_pipe(struct resource_context *new_res_ctx, bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type) { -#ifdef DBG - if (pipe_ctx->stream == NULL) { - /* a free pipe with dangling states */ - ASSERT(!pipe_ctx->plane_state); - ASSERT(!pipe_ctx->prev_odm_pipe); - ASSERT(!pipe_ctx->next_odm_pipe); - ASSERT(!pipe_ctx->top_pipe); - ASSERT(!pipe_ctx->bottom_pipe); - } else if (pipe_ctx->top_pipe) { - /* a secondary DPP pipe must be signed to a plane */ - ASSERT(pipe_ctx->plane_state) - } - /* Add more checks here to prevent corrupted pipe ctx. It is very hard - * to debug this issue afterwards because we can't pinpoint the code - * location causing inconsistent pipe context states. - */ -#endif switch (type) { case OTG_MASTER: return !pipe_ctx->prev_odm_pipe && diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c index 88c6436b28b69ca7f4791bdc47404cd5f73a5f83..180ac47868c22a68c1af47096db95ecf6b11994c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c @@ -291,11 +291,14 @@ void dc_state_destruct(struct dc_state *state) dc_stream_release(state->phantom_streams[i]); state->phantom_streams[i] = NULL; } + state->phantom_stream_count = 0; for (i = 0; i < state->phantom_plane_count; i++) { dc_plane_state_release(state->phantom_planes[i]); state->phantom_planes[i] = NULL; } + state->phantom_plane_count = 0; + state->stream_mask = 0; memset(&state->res_ctx, 0, sizeof(state->res_ctx)); memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg)); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 54670e0b15189552dd8ee85a5c1a6f905820be37..51a970fcb5d05d32484726a3993f4886592191a3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -423,6 +423,8 @@ bool dc_stream_add_writeback(struct dc *dc, return false; } + dc_exit_ips_for_hw_access(dc); + wb_info->dwb_params.out_transfer_func = stream->out_transfer_func; dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; @@ -493,6 +495,8 @@ bool dc_stream_fc_disable_writeback(struct dc *dc, return false; } + dc_exit_ips_for_hw_access(dc); + if (dwb->funcs->set_fc_enable) dwb->funcs->set_fc_enable(dwb, DWB_FRAME_CAPTURE_DISABLE); @@ -542,6 +546,8 @@ bool dc_stream_remove_writeback(struct dc *dc, return false; } + dc_exit_ips_for_hw_access(dc); + /* disable writeback */ if (dc->hwss.disable_writeback) { struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst]; @@ -557,6 +563,8 @@ bool dc_stream_warmup_writeback(struct dc *dc, int num_dwb, struct dc_writeback_info *wb_info) { + dc_exit_ips_for_hw_access(dc); + if (dc->hwss.mmhubbub_warmup) return dc->hwss.mmhubbub_warmup(dc, num_dwb, wb_info); else @@ -569,6 +577,8 @@ uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream) struct resource_context *res_ctx = &dc->current_state->res_ctx; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; @@ -597,6 +607,8 @@ bool dc_stream_send_dp_sdp(const struct dc_stream_state *stream, dc = stream->ctx->dc; res_ctx = &dc->current_state->res_ctx; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; @@ -628,6 +640,8 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, struct resource_context *res_ctx = &dc->current_state->res_ctx; + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < MAX_PIPES; i++) { struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; @@ -664,6 +678,8 @@ bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream) if (i == MAX_PIPES) return true; + dc_exit_ips_for_hw_access(dc); + return dc->hwss.dmdata_status_done(pipe); } @@ -698,6 +714,8 @@ bool dc_stream_set_dynamic_metadata(struct dc *dc, pipe_ctx->stream->dmdata_address = attr->address; + dc_exit_ips_for_hw_access(dc); + dc->hwss.program_dmdata_engine(pipe_ctx); if (hubp->funcs->dmdata_set_attributes != NULL && diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index 19a2c7140ae8437c8f01828837a0fc37dd559ecf..19140fb65787c8eccd58b639bc9f1a1c7db1a5cc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -161,6 +161,8 @@ const struct dc_plane_status *dc_plane_get_status( break; } + dc_exit_ips_for_hw_access(dc); + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 5d7aa882416b3435a5dcfbaf502a9f326981bc81..c789cc2e216de7e74b99d08e37417ba347051bd0 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -51,7 +51,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.266" +#define DC_VER "3.2.271" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -429,11 +429,12 @@ struct dc_config { bool force_bios_enable_lttpr; uint8_t force_bios_fixed_vs; int sdpif_request_limit_words_per_umc; - bool use_old_fixed_vs_sequence; bool dc_mode_clk_limit_support; bool EnableMinDispClkODM; bool enable_auto_dpm_test_logs; unsigned int disable_ips; + unsigned int disable_ips_in_vpb; + bool usb4_bw_alloc_support; }; enum visual_confirm { @@ -986,9 +987,11 @@ struct dc_debug_options { bool psp_disabled_wa; unsigned int ips2_eval_delay_us; unsigned int ips2_entry_delay_us; + bool disable_dmub_reallow_idle; bool disable_timeout; bool disable_extblankadj; unsigned int static_screen_wait_frames; + bool force_chroma_subsampling_1tap; }; struct gpu_info_soc_bounding_box_v1_0; @@ -1067,6 +1070,7 @@ struct dc { } scratch; struct dml2_configuration_options dml2_options; + enum dc_acpi_cm_power_state power_state; }; enum frame_buffer_mode { @@ -2218,11 +2222,9 @@ struct dc_sink_dsc_caps { // 'true' if these are virtual DPCD's DSC caps (immediately upstream of sink in MST topology), // 'false' if they are sink's DSC caps bool is_virtual_dpcd_dsc; -#if defined(CONFIG_DRM_AMD_DC_FP) // 'true' if MST topology supports DSC passthrough for sink // 'false' if MST topology does not support DSC passthrough bool is_dsc_passthrough_supported; -#endif struct dsc_dec_dpcd_caps dsc_dec_caps; }; @@ -2324,6 +2326,7 @@ bool dc_is_plane_eligible_for_idle_optimizations(struct dc *dc, struct dc_plane_ struct dc_cursor_attributes *cursor_attr); void dc_allow_idle_optimizations(struct dc *dc, bool allow); +void dc_exit_ips_for_hw_access(struct dc *dc); bool dc_dmub_is_ips_idle_state(struct dc *dc); /* set min and max memory clock to lowest and highest DPM level, respectively */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 2b79a0e5638e1b757ea3d3527add517db139552e..a1477906fe4f8aa6a6624ed6795027e916f0c7a2 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -74,7 +74,10 @@ void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) struct dc_context *dc_ctx = dc_dmub_srv->ctx; enum dmub_status status; - status = dmub_srv_wait_for_idle(dmub, 100000); + do { + status = dmub_srv_wait_for_idle(dmub, 100000); + } while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK); + if (status != DMUB_STATUS_OK) { DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); @@ -145,7 +148,9 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv, if (status == DMUB_STATUS_POWER_STATE_D3) return false; - dmub_srv_wait_for_idle(dmub, 100000); + do { + status = dmub_srv_wait_for_idle(dmub, 100000); + } while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK); /* Requeue the command. */ status = dmub_srv_cmd_queue(dmub, &cmd_list[i]); @@ -186,7 +191,9 @@ bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv, // Wait for DMUB to process command if (wait_type != DM_DMUB_WAIT_TYPE_NO_WAIT) { - status = dmub_srv_wait_for_idle(dmub, 100000); + do { + status = dmub_srv_wait_for_idle(dmub, 100000); + } while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK); if (status != DMUB_STATUS_OK) { DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); @@ -780,21 +787,22 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc, } else if (subvp_pipe->next_odm_pipe) { pipe_data->pipe_config.subvp_data.main_split_pipe_index = subvp_pipe->next_odm_pipe->pipe_idx; } else { - pipe_data->pipe_config.subvp_data.main_split_pipe_index = 0; + pipe_data->pipe_config.subvp_data.main_split_pipe_index = 0xF; } // Find phantom pipe index based on phantom stream for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *phantom_pipe = &context->res_ctx.pipe_ctx[j]; - if (phantom_pipe->stream == dc_state_get_paired_subvp_stream(context, subvp_pipe->stream)) { + if (resource_is_pipe_type(phantom_pipe, OTG_MASTER) && + phantom_pipe->stream == dc_state_get_paired_subvp_stream(context, subvp_pipe->stream)) { pipe_data->pipe_config.subvp_data.phantom_pipe_index = phantom_pipe->stream_res.tg->inst; if (phantom_pipe->bottom_pipe) { pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = phantom_pipe->bottom_pipe->plane_res.hubp->inst; } else if (phantom_pipe->next_odm_pipe) { pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = phantom_pipe->next_odm_pipe->plane_res.hubp->inst; } else { - pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = 0; + pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = 0xF; } break; } @@ -1195,6 +1203,9 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle) if (dc->debug.dmcub_emulation) return; + if (!dc->ctx->dmub_srv || !dc->ctx->dmub_srv->dmub) + return; + memset(&cmd, 0, sizeof(cmd)); cmd.idle_opt_notify_idle.header.type = DMUB_CMD__IDLE_OPT; cmd.idle_opt_notify_idle.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE; @@ -1205,13 +1216,15 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle) cmd.idle_opt_notify_idle.cntl_data.driver_idle = allow_idle; if (allow_idle) { + dc_dmub_srv_wait_idle(dc->ctx->dmub_srv); + if (dc->hwss.set_idle_state) dc->hwss.set_idle_state(dc, true); } /* NOTE: This does not use the "wake" interface since this is part of the wake path. */ /* We also do not perform a wait since DMCUB could enter idle after the notification. */ - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + dm_execute_dmub_cmd(dc->ctx, &cmd, allow_idle ? DM_DMUB_WAIT_TYPE_NO_WAIT : DM_DMUB_WAIT_TYPE_WAIT); } static void dc_dmub_srv_exit_low_power_state(const struct dc *dc) @@ -1361,7 +1374,7 @@ bool dc_wake_and_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned in else result = dm_execute_dmub_cmd(ctx, cmd, wait_type); - if (result && reallow_idle) + if (result && reallow_idle && !ctx->dc->debug.disable_dmub_reallow_idle) dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true); return result; @@ -1410,7 +1423,7 @@ bool dc_wake_and_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_com result = dc_dmub_execute_gpint(ctx, command_code, param, response, wait_type); - if (result && reallow_idle) + if (result && reallow_idle && !ctx->dc->debug.disable_dmub_reallow_idle) dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true); return result; diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 811474f4419bd264a7774676542e09a4f2e1f328..aae2f3a2660d950230f9e714fb98dc1714380d2d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -827,9 +827,7 @@ struct dc_dsc_config { uint32_t version_minor; /* DSC minor version. Full version is formed as 1.version_minor. */ bool ycbcr422_simple; /* Tell DSC engine to convert YCbCr 4:2:2 to 'YCbCr 4:2:2 simple'. */ int32_t rc_buffer_size; /* DSC RC buffer block size in bytes */ -#if defined(CONFIG_DRM_AMD_DC_FP) bool is_frl; /* indicate if DSC is applied based on HDMI FRL sink's capability */ -#endif bool is_dp; /* indicate if DSC is applied based on DP's capability */ uint32_t mst_pbn; /* pbn of display on dsc mst hub */ const struct dc_dsc_rc_params_override *rc_params_ovrd; /* DM owned memory. If not NULL, apply custom dsc rc params */ @@ -942,6 +940,7 @@ struct dc_crtc_timing { uint32_t hdmi_vic; uint32_t rid; uint32_t fr_index; + uint32_t frl_uncompressed_video_bandwidth_in_kbps; enum dc_timing_3d_format timing_3d_format; enum dc_color_depth display_color_depth; enum dc_pixel_encoding pixel_encoding; diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index b08ccb8c68bc366386e82a566c452459da0aabdc..9900dda2eef5cd2e44e6dbd008cd411194d107af 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1034,6 +1034,7 @@ enum replay_FW_Message_type { Replay_Msg_Not_Support = -1, Replay_Set_Timing_Sync_Supported, Replay_Set_Residency_Frameupdate_Timer, + Replay_Set_Pseudo_VTotal, }; union replay_error_status { @@ -1089,6 +1090,10 @@ struct replay_settings { uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM]; /* Maximum link off frame count */ enum replay_link_off_frame_count_level link_off_frame_count_level; + /* Replay pseudo vtotal for abm + ips on full screen video which can improve ips residency */ + uint16_t abm_with_ips_on_full_screen_video_pseudo_vtotal; + /* Replay last pseudo vtotal set to DMUB */ + uint16_t last_pseudo_vtotal; }; /* To split out "global" and "per-panel" config settings. diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index f0458b8f00af842b87ab91feadd71eef4c680e27..12f3c35b3a34cde701346eee73ae87f51076ff81 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -239,27 +239,294 @@ static void check_audio_bandwidth_hdmi( } } } +static struct fixed31_32 get_link_symbol_clk_freq_mhz(enum dc_link_rate link_rate) +{ + switch (link_rate) { + case LINK_RATE_LOW: + return dc_fixpt_from_int(162); /* 162 MHz */ + case LINK_RATE_HIGH: + return dc_fixpt_from_int(270); /* 270 MHz */ + case LINK_RATE_HIGH2: + return dc_fixpt_from_int(540); /* 540 MHz */ + case LINK_RATE_HIGH3: + return dc_fixpt_from_int(810); /* 810 MHz */ + case LINK_RATE_UHBR10: + return dc_fixpt_from_fraction(3125, 10); /* 312.5 MHz */ + case LINK_RATE_UHBR13_5: + return dc_fixpt_from_fraction(421875, 1000); /* 421.875 MHz */ + case LINK_RATE_UHBR20: + return dc_fixpt_from_int(625); /* 625 MHz */ + default: + /* Unexpected case, this requires debug if encountered. */ + ASSERT(0); + return dc_fixpt_from_int(0); + } +} + +struct dp_audio_layout_config { + uint8_t layouts_per_sample_denom; + uint8_t symbols_per_layout; + uint8_t max_layouts_per_audio_sdp; +}; + +static void get_audio_layout_config( + uint32_t channel_count, + enum dp_link_encoding encoding, + struct dp_audio_layout_config *output) +{ + /* Assuming L-PCM audio. Current implementation uses max 1 layout per SDP, + * with each layout being the same size (8ch layout). + */ + if (encoding == DP_8b_10b_ENCODING) { + if (channel_count == 2) { + output->layouts_per_sample_denom = 4; + output->symbols_per_layout = 40; + output->max_layouts_per_audio_sdp = 1; + } else if (channel_count == 8 || channel_count == 6) { + output->layouts_per_sample_denom = 1; + output->symbols_per_layout = 40; + output->max_layouts_per_audio_sdp = 1; + } + } else if (encoding == DP_128b_132b_ENCODING) { + if (channel_count == 2) { + output->layouts_per_sample_denom = 4; + output->symbols_per_layout = 10; + output->max_layouts_per_audio_sdp = 1; + } else if (channel_count == 8 || channel_count == 6) { + output->layouts_per_sample_denom = 1; + output->symbols_per_layout = 10; + output->max_layouts_per_audio_sdp = 1; + } + } +} -/*For DP SST, calculate if specified sample rates can fit into a given timing */ -static void check_audio_bandwidth_dpsst( +static uint32_t get_av_stream_map_lane_count( + enum dp_link_encoding encoding, + enum dc_lane_count lane_count, + bool is_mst) +{ + uint32_t av_stream_map_lane_count = 0; + + if (encoding == DP_8b_10b_ENCODING) { + if (!is_mst) + av_stream_map_lane_count = lane_count; + else + av_stream_map_lane_count = 4; + } else if (encoding == DP_128b_132b_ENCODING) { + av_stream_map_lane_count = 4; + } + + ASSERT(av_stream_map_lane_count != 0); + + return av_stream_map_lane_count; +} + +static uint32_t get_audio_sdp_overhead( + enum dp_link_encoding encoding, + enum dc_lane_count lane_count, + bool is_mst) +{ + uint32_t audio_sdp_overhead = 0; + + if (encoding == DP_8b_10b_ENCODING) { + if (is_mst) + audio_sdp_overhead = 16; /* 4 * 2 + 8 */ + else + audio_sdp_overhead = lane_count * 2 + 8; + } else if (encoding == DP_128b_132b_ENCODING) { + audio_sdp_overhead = 10; /* 4 x 2.5 */ + } + + ASSERT(audio_sdp_overhead != 0); + + return audio_sdp_overhead; +} + +static uint32_t calculate_required_audio_bw_in_symbols( const struct audio_crtc_info *crtc_info, + const struct dp_audio_layout_config *layout_config, uint32_t channel_count, - union audio_sample_rates *sample_rates) + uint32_t sample_rate_hz, + uint32_t av_stream_map_lane_count, + uint32_t audio_sdp_overhead) +{ + /* DP spec recommends between 1.05 to 1.1 safety margin to prevent sample under-run */ + struct fixed31_32 audio_sdp_margin = dc_fixpt_from_fraction(110, 100); + struct fixed31_32 horizontal_line_freq_khz = dc_fixpt_from_fraction( + crtc_info->requested_pixel_clock_100Hz, crtc_info->h_total * 10); + struct fixed31_32 samples_per_line; + struct fixed31_32 layouts_per_line; + struct fixed31_32 symbols_per_sdp_max_layout; + struct fixed31_32 remainder; + uint32_t num_sdp_with_max_layouts; + uint32_t required_symbols_per_hblank; + + samples_per_line = dc_fixpt_from_fraction(sample_rate_hz, 1000); + samples_per_line = dc_fixpt_div(samples_per_line, horizontal_line_freq_khz); + layouts_per_line = dc_fixpt_div_int(samples_per_line, layout_config->layouts_per_sample_denom); + + num_sdp_with_max_layouts = dc_fixpt_floor( + dc_fixpt_div_int(layouts_per_line, layout_config->max_layouts_per_audio_sdp)); + symbols_per_sdp_max_layout = dc_fixpt_from_int( + layout_config->max_layouts_per_audio_sdp * layout_config->symbols_per_layout); + symbols_per_sdp_max_layout = dc_fixpt_add_int(symbols_per_sdp_max_layout, audio_sdp_overhead); + symbols_per_sdp_max_layout = dc_fixpt_mul(symbols_per_sdp_max_layout, audio_sdp_margin); + required_symbols_per_hblank = num_sdp_with_max_layouts; + required_symbols_per_hblank *= ((dc_fixpt_ceil(symbols_per_sdp_max_layout) + av_stream_map_lane_count) / + av_stream_map_lane_count) * av_stream_map_lane_count; + + if (num_sdp_with_max_layouts != dc_fixpt_ceil( + dc_fixpt_div_int(layouts_per_line, layout_config->max_layouts_per_audio_sdp))) { + remainder = dc_fixpt_sub_int(layouts_per_line, + num_sdp_with_max_layouts * layout_config->max_layouts_per_audio_sdp); + remainder = dc_fixpt_mul_int(remainder, layout_config->symbols_per_layout); + remainder = dc_fixpt_add_int(remainder, audio_sdp_overhead); + remainder = dc_fixpt_mul(remainder, audio_sdp_margin); + required_symbols_per_hblank += ((dc_fixpt_ceil(remainder) + av_stream_map_lane_count) / + av_stream_map_lane_count) * av_stream_map_lane_count; + } + + return required_symbols_per_hblank; +} + +/* Current calculation only applicable for 8b/10b MST and 128b/132b SST/MST. + */ +static uint32_t calculate_available_hblank_bw_in_symbols( + const struct audio_crtc_info *crtc_info, + const struct audio_dp_link_info *dp_link_info) { - /* do nothing */ + uint64_t hblank = crtc_info->h_total - crtc_info->h_active; + struct fixed31_32 hblank_time_msec = + dc_fixpt_from_fraction(hblank * 10, crtc_info->requested_pixel_clock_100Hz); + struct fixed31_32 lsclkfreq_mhz = + get_link_symbol_clk_freq_mhz(dp_link_info->link_rate); + struct fixed31_32 average_stream_sym_bw_frac; + struct fixed31_32 peak_stream_bw_kbps; + struct fixed31_32 bits_per_pixel; + struct fixed31_32 link_bw_kbps; + struct fixed31_32 available_stream_sym_count; + uint32_t available_hblank_bw = 0; /* in stream symbols */ + + if (crtc_info->dsc_bits_per_pixel) { + bits_per_pixel = dc_fixpt_from_fraction(crtc_info->dsc_bits_per_pixel, 16); + } else { + switch (crtc_info->color_depth) { + case COLOR_DEPTH_666: + bits_per_pixel = dc_fixpt_from_int(6); + break; + case COLOR_DEPTH_888: + bits_per_pixel = dc_fixpt_from_int(8); + break; + case COLOR_DEPTH_101010: + bits_per_pixel = dc_fixpt_from_int(10); + break; + case COLOR_DEPTH_121212: + bits_per_pixel = dc_fixpt_from_int(12); + break; + default: + /* Default to commonly supported color depth. */ + bits_per_pixel = dc_fixpt_from_int(8); + break; + } + + bits_per_pixel = dc_fixpt_mul_int(bits_per_pixel, 3); + + if (crtc_info->pixel_encoding == PIXEL_ENCODING_YCBCR422) { + bits_per_pixel = dc_fixpt_div_int(bits_per_pixel, 3); + bits_per_pixel = dc_fixpt_mul_int(bits_per_pixel, 2); + } else if (crtc_info->pixel_encoding == PIXEL_ENCODING_YCBCR420) { + bits_per_pixel = dc_fixpt_div_int(bits_per_pixel, 2); + } + } + + /* Use simple stream BW calculation because mainlink overhead is + * accounted for separately in the audio BW calculations. + */ + peak_stream_bw_kbps = dc_fixpt_from_fraction(crtc_info->requested_pixel_clock_100Hz, 10); + peak_stream_bw_kbps = dc_fixpt_mul(peak_stream_bw_kbps, bits_per_pixel); + link_bw_kbps = dc_fixpt_from_int(dp_link_info->link_bandwidth_kbps); + average_stream_sym_bw_frac = dc_fixpt_div(peak_stream_bw_kbps, link_bw_kbps); + + available_stream_sym_count = dc_fixpt_mul_int(hblank_time_msec, 1000); + available_stream_sym_count = dc_fixpt_mul(available_stream_sym_count, lsclkfreq_mhz); + available_stream_sym_count = dc_fixpt_mul(available_stream_sym_count, average_stream_sym_bw_frac); + available_hblank_bw = dc_fixpt_floor(available_stream_sym_count); + available_hblank_bw *= dp_link_info->lane_count; + available_hblank_bw -= crtc_info->dsc_num_slices * 4; /* EOC overhead */ + + if (available_hblank_bw < dp_link_info->hblank_min_symbol_width) + available_hblank_bw = dp_link_info->hblank_min_symbol_width; + + if (available_hblank_bw < 12) + available_hblank_bw = 0; + else + available_hblank_bw -= 12; /* Main link overhead */ + + return available_hblank_bw; } -/*For DP MST, calculate if specified sample rates can fit into a given timing */ -static void check_audio_bandwidth_dpmst( +static void check_audio_bandwidth_dp( const struct audio_crtc_info *crtc_info, + const struct audio_dp_link_info *dp_link_info, uint32_t channel_count, union audio_sample_rates *sample_rates) { - /* do nothing */ + struct dp_audio_layout_config layout_config = {0}; + uint32_t available_hblank_bw; + uint32_t av_stream_map_lane_count; + uint32_t audio_sdp_overhead; + + /* TODO: Add validation for SST 8b/10 case */ + if (!dp_link_info->is_mst && dp_link_info->encoding == DP_8b_10b_ENCODING) + return; + + available_hblank_bw = calculate_available_hblank_bw_in_symbols( + crtc_info, dp_link_info); + av_stream_map_lane_count = get_av_stream_map_lane_count( + dp_link_info->encoding, dp_link_info->lane_count, dp_link_info->is_mst); + audio_sdp_overhead = get_audio_sdp_overhead( + dp_link_info->encoding, dp_link_info->lane_count, dp_link_info->is_mst); + get_audio_layout_config( + channel_count, dp_link_info->encoding, &layout_config); + + if (layout_config.max_layouts_per_audio_sdp == 0 || + layout_config.symbols_per_layout == 0 || + layout_config.layouts_per_sample_denom == 0) { + return; + } + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 192000, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_192 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 176400, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_176_4 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 96000, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_96 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 88200, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_88_2 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 48000, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_48 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 44100, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_44_1 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 32000, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_32 = 0; } static void check_audio_bandwidth( const struct audio_crtc_info *crtc_info, + const struct audio_dp_link_info *dp_link_info, uint32_t channel_count, enum signal_type signal, union audio_sample_rates *sample_rates) @@ -271,12 +538,9 @@ static void check_audio_bandwidth( break; case SIGNAL_TYPE_EDP: case SIGNAL_TYPE_DISPLAY_PORT: - check_audio_bandwidth_dpsst( - crtc_info, channel_count, sample_rates); - break; case SIGNAL_TYPE_DISPLAY_PORT_MST: - check_audio_bandwidth_dpmst( - crtc_info, channel_count, sample_rates); + check_audio_bandwidth_dp( + crtc_info, dp_link_info, channel_count, sample_rates); break; default: break; @@ -394,7 +658,8 @@ void dce_aud_az_configure( struct audio *audio, enum signal_type signal, const struct audio_crtc_info *crtc_info, - const struct audio_info *audio_info) + const struct audio_info *audio_info, + const struct audio_dp_link_info *dp_link_info) { struct dce_audio *aud = DCE_AUD(audio); @@ -529,6 +794,7 @@ void dce_aud_az_configure( check_audio_bandwidth( crtc_info, + dp_link_info, channel_count, signal, &sample_rates); @@ -588,6 +854,7 @@ void dce_aud_az_configure( check_audio_bandwidth( crtc_info, + dp_link_info, 8, signal, &sample_rate); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h index dbd2cfed0603085f25a67ca3700588716afb6cc0..539f881928d1010e2aea7e3ca6383d3263855ad4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h @@ -170,7 +170,8 @@ void dce_aud_az_disable(struct audio *audio); void dce_aud_az_configure(struct audio *audio, enum signal_type signal, const struct audio_crtc_info *crtc_info, - const struct audio_info *audio_info); + const struct audio_info *audio_info, + const struct audio_dp_link_info *dp_link_info); void dce_aud_wall_dto_setup(struct audio *audio, enum signal_type signal, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c index 38e4797e9476ca8de7ba6ad92c6906db5f9823c1..b010814706fec49634b4e76aee6c7c0cfaed4efc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c @@ -258,7 +258,7 @@ static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst, *residency = 0; } -/** +/* * Set REPLAY power optimization flags and coasting vtotal. */ static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dmub, @@ -280,7 +280,7 @@ static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dm dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } -/** +/* * send Replay general cmd to DMUB. */ static void dmub_replay_send_cmd(struct dmub_replay *dmub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index 3538973bd0c6cb7a23a7ffdd2f70883e354ed34f..b7e57aa27361952ddf17985e0e8adfce2bdc4a56 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -62,6 +62,26 @@ void cm_helper_program_color_matrices( } +void cm_helper_read_color_matrices(struct dc_context *ctx, + uint16_t *regval, + const struct color_matrices_reg *reg) +{ + uint32_t cur_csc_reg, regval0, regval1; + unsigned int i = 0; + + for (cur_csc_reg = reg->csc_c11_c12; + cur_csc_reg <= reg->csc_c33_c34; cur_csc_reg++) { + REG_GET_2(cur_csc_reg, + csc_c11, ®val0, + csc_c12, ®val1); + + regval[2 * i] = regval0; + regval[(2 * i) + 1] = regval1; + + i++; + } +} + void cm_helper_program_xfer_func( struct dc_context *ctx, const struct pwl_params *params, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h index 0a68b63d61260b4118ffe11ff48980ef80e5189d..decc50b1ac53c422547ff821b0c3bbe72418154d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h @@ -114,5 +114,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format( const struct dc_transfer_func *output_tf, struct pwl_params *lut_params); - +void cm_helper_read_color_matrices(struct dc_context *ctx, + uint16_t *regval, + const struct color_matrices_reg *reg); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index ef52e6b6eccfbd1ea1a85df0094c2e8363380576..4e391fd1d71caa4cbe6eab34544e5704bff038b7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -543,7 +543,8 @@ static const struct dpp_funcs dcn10_dpp_funcs = { .dpp_set_hdr_multiplier = dpp1_set_hdr_multiplier, .dpp_program_blnd_lut = NULL, .dpp_program_shaper_lut = NULL, - .dpp_program_3dlut = NULL + .dpp_program_3dlut = NULL, + .dpp_get_gamut_remap = dpp1_cm_get_gamut_remap, }; static struct dpp_caps dcn10_dpp_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index c9e045666dcc89854a17492c6df79fe1afc2524c..a039eedc7c24b7258d26cb9e7b2f7061833334a9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -1521,4 +1521,7 @@ void dpp1_construct(struct dcn10_dpp *dpp1, const struct dcn_dpp_registers *tf_regs, const struct dcn_dpp_shift *tf_shift, const struct dcn_dpp_mask *tf_mask); + +void dpp1_cm_get_gamut_remap(struct dpp *dpp_base, + struct dpp_grph_csc_adjustment *adjust); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index 904c2d2789987bce097fa805182a49dc9675a71e..2f994a3a0b9cdb9c13590775abe8dd3a80cf161b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -98,7 +98,7 @@ static void program_gamut_remap( if (regval == NULL || select == GAMUT_REMAP_BYPASS) { REG_SET(CM_GAMUT_REMAP_CONTROL, 0, - CM_GAMUT_REMAP_MODE, 0); + CM_GAMUT_REMAP_MODE, 0); return; } switch (select) { @@ -181,6 +181,74 @@ void dpp1_cm_set_gamut_remap( } } +static void read_gamut_remap(struct dcn10_dpp *dpp, + uint16_t *regval, + enum gamut_remap_select *select) +{ + struct color_matrices_reg gam_regs; + uint32_t selection; + + REG_GET(CM_GAMUT_REMAP_CONTROL, + CM_GAMUT_REMAP_MODE, &selection); + + *select = selection; + + gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_GAMUT_REMAP_C11; + gam_regs.masks.csc_c11 = dpp->tf_mask->CM_GAMUT_REMAP_C11; + gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_GAMUT_REMAP_C12; + gam_regs.masks.csc_c12 = dpp->tf_mask->CM_GAMUT_REMAP_C12; + + if (*select == GAMUT_REMAP_COEFF) { + + gam_regs.csc_c11_c12 = REG(CM_GAMUT_REMAP_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_GAMUT_REMAP_C33_C34); + + cm_helper_read_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + + } else if (*select == GAMUT_REMAP_COMA_COEFF) { + + gam_regs.csc_c11_c12 = REG(CM_COMA_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_COMA_C33_C34); + + cm_helper_read_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + + } else if (*select == GAMUT_REMAP_COMB_COEFF) { + + gam_regs.csc_c11_c12 = REG(CM_COMB_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_COMB_C33_C34); + + cm_helper_read_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + } +} + +void dpp1_cm_get_gamut_remap(struct dpp *dpp_base, + struct dpp_grph_csc_adjustment *adjust) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + uint16_t arr_reg_val[12]; + enum gamut_remap_select select; + + read_gamut_remap(dpp, arr_reg_val, &select); + + if (select == GAMUT_REMAP_BYPASS) { + adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + return; + } + + adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + convert_hw_matrix(adjust->temperature_matrix, + arr_reg_val, ARRAY_SIZE(arr_reg_val)); +} + static void dpp1_cm_program_color_matrix( struct dcn10_dpp *dpp, const uint16_t *regval) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c index 0dec57679269b0da486b00b328ad1377494ca1e5..48a40dcc7050bd597ed7e5b7d645b0764db2c572 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c @@ -23,6 +23,7 @@ * */ +#include "core_types.h" #include "dm_services.h" #include "dcn10_opp.h" #include "reg_helper.h" @@ -160,6 +161,9 @@ static void opp1_set_pixel_encoding( struct dcn10_opp *oppn10, const struct clamping_and_pixel_encoding_params *params) { + bool force_chroma_subsampling_1tap = + oppn10->base.ctx->dc->debug.force_chroma_subsampling_1tap; + switch (params->pixel_encoding) { case PIXEL_ENCODING_RGB: @@ -178,6 +182,9 @@ static void opp1_set_pixel_encoding( default: break; } + + if (force_chroma_subsampling_1tap) + REG_UPDATE(FMT_CONTROL, FMT_SUBSAMPLING_MODE, 0); } /** diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c index eaa7032f0f1a3c11f71e99d5dfc1526f8861eb94..1516c0a4872663655e0ccd60aa543bc4bc97f78e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c @@ -55,21 +55,23 @@ void dpp20_read_state(struct dpp *dpp_base, REG_GET(DPP_CONTROL, DPP_CLOCK_ENABLE, &s->is_enabled); + + // Degamma LUT (RAM) REG_GET(CM_DGAM_CONTROL, - CM_DGAM_LUT_MODE, &s->dgam_lut_mode); - // BGAM has no ROM, and definition is different, can't reuse same dump - //REG_GET(CM_BLNDGAM_CONTROL, - // CM_BLNDGAM_LUT_MODE, &s->rgam_lut_mode); - REG_GET(CM_GAMUT_REMAP_CONTROL, - CM_GAMUT_REMAP_MODE, &s->gamut_remap_mode); - if (s->gamut_remap_mode) { - s->gamut_remap_c11_c12 = REG_READ(CM_GAMUT_REMAP_C11_C12); - s->gamut_remap_c13_c14 = REG_READ(CM_GAMUT_REMAP_C13_C14); - s->gamut_remap_c21_c22 = REG_READ(CM_GAMUT_REMAP_C21_C22); - s->gamut_remap_c23_c24 = REG_READ(CM_GAMUT_REMAP_C23_C24); - s->gamut_remap_c31_c32 = REG_READ(CM_GAMUT_REMAP_C31_C32); - s->gamut_remap_c33_c34 = REG_READ(CM_GAMUT_REMAP_C33_C34); - } + CM_DGAM_LUT_MODE, &s->dgam_lut_mode); + + // Shaper LUT (RAM), 3D LUT (mode, bit-depth, size) + REG_GET(CM_SHAPER_CONTROL, + CM_SHAPER_LUT_MODE, &s->shaper_lut_mode); + REG_GET_2(CM_3DLUT_READ_WRITE_CONTROL, + CM_3DLUT_CONFIG_STATUS, &s->lut3d_mode, + CM_3DLUT_30BIT_EN, &s->lut3d_bit_depth); + REG_GET(CM_3DLUT_MODE, + CM_3DLUT_SIZE, &s->lut3d_size); + + // Blend/Out Gamma (RAM) + REG_GET(CM_BLNDGAM_LUT_WRITE_EN_MASK, + CM_BLNDGAM_CONFIG_STATUS, &s->rgam_lut_mode); } void dpp2_power_on_obuf( @@ -393,6 +395,7 @@ static struct dpp_funcs dcn20_dpp_funcs = { .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp2_set_hdr_multiplier, + .dpp_get_gamut_remap = dpp2_cm_get_gamut_remap, }; static struct dpp_caps dcn20_dpp_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h index e735363d0051bcfd412f870f806472970e002a0c..672cde46c4b9af6bd7df74b01a39287324bfb76c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h @@ -775,4 +775,7 @@ bool dpp2_construct(struct dcn20_dpp *dpp2, void dpp2_power_on_obuf( struct dpp *dpp_base, bool power_on); + +void dpp2_cm_get_gamut_remap(struct dpp *dpp_base, + struct dpp_grph_csc_adjustment *adjust); #endif /* __DC_HWSS_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c index 598caa508d431183b21e96b3ec87254e75b43568..58dc69926e8a81666300a6d51d47fcbf4d26e451 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c @@ -234,6 +234,61 @@ void dpp2_cm_set_gamut_remap( } } +static void read_gamut_remap(struct dcn20_dpp *dpp, + uint16_t *regval, + enum dcn20_gamut_remap_select *select) +{ + struct color_matrices_reg gam_regs; + uint32_t selection; + + IX_REG_GET(CM_TEST_DEBUG_INDEX, CM_TEST_DEBUG_DATA, + CM_TEST_DEBUG_DATA_STATUS_IDX, + CM_TEST_DEBUG_DATA_GAMUT_REMAP_MODE, &selection); + + *select = selection; + + gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_GAMUT_REMAP_C11; + gam_regs.masks.csc_c11 = dpp->tf_mask->CM_GAMUT_REMAP_C11; + gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_GAMUT_REMAP_C12; + gam_regs.masks.csc_c12 = dpp->tf_mask->CM_GAMUT_REMAP_C12; + + if (*select == DCN2_GAMUT_REMAP_COEF_A) { + gam_regs.csc_c11_c12 = REG(CM_GAMUT_REMAP_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_GAMUT_REMAP_C33_C34); + + cm_helper_read_color_matrices(dpp->base.ctx, + regval, + &gam_regs); + + } else if (*select == DCN2_GAMUT_REMAP_COEF_B) { + gam_regs.csc_c11_c12 = REG(CM_GAMUT_REMAP_B_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_GAMUT_REMAP_B_C33_C34); + + cm_helper_read_color_matrices(dpp->base.ctx, + regval, + &gam_regs); + } +} + +void dpp2_cm_get_gamut_remap(struct dpp *dpp_base, + struct dpp_grph_csc_adjustment *adjust) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + uint16_t arr_reg_val[12]; + enum dcn20_gamut_remap_select select; + + read_gamut_remap(dpp, arr_reg_val, &select); + + if (select == DCN2_GAMUT_REMAP_BYPASS) { + adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + return; + } + + adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + convert_hw_matrix(adjust->temperature_matrix, + arr_reg_val, ARRAY_SIZE(arr_reg_val)); +} + void dpp2_program_input_csc( struct dpp *dpp_base, enum dc_color_space color_space, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c index 5da6e44f284a6892ba2a99ddc7f964b50c785b45..16b5ff208d14781617c45f9d4e4628b35e823203 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c @@ -542,8 +542,30 @@ static struct mpcc *mpc2_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id) return NULL; } +static void mpc2_read_mpcc_state( + struct mpc *mpc, + int mpcc_inst, + struct mpcc_state *s) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + REG_GET(MPCC_OPP_ID[mpcc_inst], MPCC_OPP_ID, &s->opp_id); + REG_GET(MPCC_TOP_SEL[mpcc_inst], MPCC_TOP_SEL, &s->dpp_id); + REG_GET(MPCC_BOT_SEL[mpcc_inst], MPCC_BOT_SEL, &s->bot_mpcc_id); + REG_GET_4(MPCC_CONTROL[mpcc_inst], MPCC_MODE, &s->mode, + MPCC_ALPHA_BLND_MODE, &s->alpha_mode, + MPCC_ALPHA_MULTIPLIED_MODE, &s->pre_multiplied_alpha, + MPCC_BLND_ACTIVE_OVERLAP_ONLY, &s->overlap_only); + REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, &s->idle, + MPCC_BUSY, &s->busy); + + /* Gamma block state */ + REG_GET(MPCC_OGAM_LUT_RAM_CONTROL[mpcc_inst], + MPCC_OGAM_CONFIG_STATUS, &s->rgam_mode); +} + static const struct mpc_funcs dcn20_mpc_funcs = { - .read_mpcc_state = mpc1_read_mpcc_state, + .read_mpcc_state = mpc2_read_mpcc_state, .insert_plane = mpc1_insert_plane, .remove_mpcc = mpc1_remove_mpcc, .mpc_init = mpc1_mpc_init, diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c index a7268027a472af981da4109b58c09732d12bd3a7..f809a7d21033320e9b0f47200d5d158e51218b3d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c @@ -275,6 +275,7 @@ static struct dpp_funcs dcn201_dpp_funcs = { .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp2_set_hdr_multiplier, + .dpp_get_gamut_remap = dpp2_cm_get_gamut_remap, }; static struct dpp_caps dcn201_dpp_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c index 11f7746f3a656a2a9ad430cb96ff42534a70f90e..a3a769aad0420100ad0251c4f8f71e714e645b8b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c @@ -44,12 +44,45 @@ void dpp30_read_state(struct dpp *dpp_base, struct dcn_dpp_state *s) { struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); + uint32_t gamcor_lut_mode, rgam_lut_mode; REG_GET(DPP_CONTROL, - DPP_CLOCK_ENABLE, &s->is_enabled); + DPP_CLOCK_ENABLE, &s->is_enabled); + + // Pre-degamma (ROM) + REG_GET_2(PRE_DEGAM, + PRE_DEGAM_MODE, &s->pre_dgam_mode, + PRE_DEGAM_SELECT, &s->pre_dgam_select); + + // Gamma Correction (RAM) + REG_GET(CM_GAMCOR_CONTROL, + CM_GAMCOR_MODE_CURRENT, &s->gamcor_mode); + if (s->gamcor_mode) { + REG_GET(CM_GAMCOR_CONTROL, CM_GAMCOR_SELECT_CURRENT, &gamcor_lut_mode); + if (!gamcor_lut_mode) + s->gamcor_mode = LUT_RAM_A; // Otherwise, LUT_RAM_B + } - // TODO: Implement for DCN3 + // Shaper LUT (RAM), 3D LUT (mode, bit-depth, size) + REG_GET(CM_SHAPER_CONTROL, + CM_SHAPER_LUT_MODE, &s->shaper_lut_mode); + REG_GET(CM_3DLUT_MODE, + CM_3DLUT_MODE_CURRENT, &s->lut3d_mode); + REG_GET(CM_3DLUT_READ_WRITE_CONTROL, + CM_3DLUT_30BIT_EN, &s->lut3d_bit_depth); + REG_GET(CM_3DLUT_MODE, + CM_3DLUT_SIZE, &s->lut3d_size); + + // Blend/Out Gamma (RAM) + REG_GET(CM_BLNDGAM_CONTROL, + CM_BLNDGAM_MODE_CURRENT, &s->rgam_lut_mode); + if (s->rgam_lut_mode){ + REG_GET(CM_BLNDGAM_CONTROL, CM_BLNDGAM_SELECT_CURRENT, &rgam_lut_mode); + if (!rgam_lut_mode) + s->rgam_lut_mode = LUT_RAM_A; // Otherwise, LUT_RAM_B + } } + /*program post scaler scs block in dpp CM*/ void dpp3_program_post_csc( struct dpp *dpp_base, @@ -1462,6 +1495,7 @@ static struct dpp_funcs dcn30_dpp_funcs = { .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp3_set_hdr_multiplier, + .dpp_get_gamut_remap = dpp3_cm_get_gamut_remap, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.h index cea3208e4ab1109719c144bd65df96ca6c81ad57..2ac8045a87a1365e1ebb3ff854c410abfa7da5ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.h @@ -637,4 +637,6 @@ void dpp3_program_cm_dealpha( struct dpp *dpp_base, uint32_t enable, uint32_t additive_blending); +void dpp3_cm_get_gamut_remap(struct dpp *dpp_base, + struct dpp_grph_csc_adjustment *adjust); #endif /* __DC_HWSS_DCN30_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c index e43f77c11c00825aad64ada6ddfb4b0bdce23aff..54ec144f7b812cc9f1aab1458f06405ee1d0a4d6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c @@ -408,3 +408,57 @@ void dpp3_cm_set_gamut_remap( program_gamut_remap(dpp, arr_reg_val, gamut_mode); } } + +static void read_gamut_remap(struct dcn3_dpp *dpp, + uint16_t *regval, + int *select) +{ + struct color_matrices_reg gam_regs; + uint32_t selection; + + //current coefficient set in use + REG_GET(CM_GAMUT_REMAP_CONTROL, CM_GAMUT_REMAP_MODE_CURRENT, &selection); + + *select = selection; + + gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_GAMUT_REMAP_C11; + gam_regs.masks.csc_c11 = dpp->tf_mask->CM_GAMUT_REMAP_C11; + gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_GAMUT_REMAP_C12; + gam_regs.masks.csc_c12 = dpp->tf_mask->CM_GAMUT_REMAP_C12; + + if (*select == GAMUT_REMAP_COEFF) { + gam_regs.csc_c11_c12 = REG(CM_GAMUT_REMAP_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_GAMUT_REMAP_C33_C34); + + cm_helper_read_color_matrices(dpp->base.ctx, + regval, + &gam_regs); + + } else if (*select == GAMUT_REMAP_COMA_COEFF) { + gam_regs.csc_c11_c12 = REG(CM_GAMUT_REMAP_B_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_GAMUT_REMAP_B_C33_C34); + + cm_helper_read_color_matrices(dpp->base.ctx, + regval, + &gam_regs); + } +} + +void dpp3_cm_get_gamut_remap(struct dpp *dpp_base, + struct dpp_grph_csc_adjustment *adjust) +{ + struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base); + uint16_t arr_reg_val[12]; + int select; + + read_gamut_remap(dpp, arr_reg_val, &select); + + if (select == GAMUT_REMAP_BYPASS) { + adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + return; + } + + adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + convert_hw_matrix(adjust->temperature_matrix, + arr_reg_val, ARRAY_SIZE(arr_reg_val)); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c index d1500b2238580b526dfbea2b3ece636295f76c59..bf3386cd444d62c5232909f9b88061e6abf98887 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c @@ -1129,6 +1129,64 @@ void mpc3_set_gamut_remap( } } +static void read_gamut_remap(struct dcn30_mpc *mpc30, + int mpcc_id, + uint16_t *regval, + uint32_t *select) +{ + struct color_matrices_reg gam_regs; + + //current coefficient set in use + REG_GET(MPCC_GAMUT_REMAP_MODE[mpcc_id], MPCC_GAMUT_REMAP_MODE_CURRENT, select); + + gam_regs.shifts.csc_c11 = mpc30->mpc_shift->MPCC_GAMUT_REMAP_C11_A; + gam_regs.masks.csc_c11 = mpc30->mpc_mask->MPCC_GAMUT_REMAP_C11_A; + gam_regs.shifts.csc_c12 = mpc30->mpc_shift->MPCC_GAMUT_REMAP_C12_A; + gam_regs.masks.csc_c12 = mpc30->mpc_mask->MPCC_GAMUT_REMAP_C12_A; + + if (*select == GAMUT_REMAP_COEFF) { + gam_regs.csc_c11_c12 = REG(MPC_GAMUT_REMAP_C11_C12_A[mpcc_id]); + gam_regs.csc_c33_c34 = REG(MPC_GAMUT_REMAP_C33_C34_A[mpcc_id]); + + cm_helper_read_color_matrices( + mpc30->base.ctx, + regval, + &gam_regs); + + } else if (*select == GAMUT_REMAP_COMA_COEFF) { + + gam_regs.csc_c11_c12 = REG(MPC_GAMUT_REMAP_C11_C12_B[mpcc_id]); + gam_regs.csc_c33_c34 = REG(MPC_GAMUT_REMAP_C33_C34_B[mpcc_id]); + + cm_helper_read_color_matrices( + mpc30->base.ctx, + regval, + &gam_regs); + + } + +} + +void mpc3_get_gamut_remap(struct mpc *mpc, + int mpcc_id, + struct mpc_grph_gamut_adjustment *adjust) +{ + struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); + uint16_t arr_reg_val[12]; + int select; + + read_gamut_remap(mpc30, mpcc_id, arr_reg_val, &select); + + if (select == GAMUT_REMAP_BYPASS) { + adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + return; + } + + adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + convert_hw_matrix(adjust->temperature_matrix, + arr_reg_val, ARRAY_SIZE(arr_reg_val)); +} + bool mpc3_program_3dlut( struct mpc *mpc, const struct tetrahedral_params *params, @@ -1382,8 +1440,54 @@ static void mpc3_set_mpc_mem_lp_mode(struct mpc *mpc) } } +static void mpc3_read_mpcc_state( + struct mpc *mpc, + int mpcc_inst, + struct mpcc_state *s) +{ + struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); + uint32_t rmu_status = 0xf; + + REG_GET(MPCC_OPP_ID[mpcc_inst], MPCC_OPP_ID, &s->opp_id); + REG_GET(MPCC_TOP_SEL[mpcc_inst], MPCC_TOP_SEL, &s->dpp_id); + REG_GET(MPCC_BOT_SEL[mpcc_inst], MPCC_BOT_SEL, &s->bot_mpcc_id); + REG_GET_4(MPCC_CONTROL[mpcc_inst], MPCC_MODE, &s->mode, + MPCC_ALPHA_BLND_MODE, &s->alpha_mode, + MPCC_ALPHA_MULTIPLIED_MODE, &s->pre_multiplied_alpha, + MPCC_BLND_ACTIVE_OVERLAP_ONLY, &s->overlap_only); + REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, &s->idle, + MPCC_BUSY, &s->busy); + + /* Color blocks state */ + REG_GET(MPC_RMU_CONTROL, MPC_RMU0_MUX_STATUS, &rmu_status); + + if (rmu_status == mpcc_inst) { + REG_GET(SHAPER_CONTROL[0], + MPC_RMU_SHAPER_LUT_MODE_CURRENT, &s->shaper_lut_mode); + REG_GET(RMU_3DLUT_MODE[0], + MPC_RMU_3DLUT_MODE_CURRENT, &s->lut3d_mode); + REG_GET(RMU_3DLUT_READ_WRITE_CONTROL[0], + MPC_RMU_3DLUT_30BIT_EN, &s->lut3d_bit_depth); + REG_GET(RMU_3DLUT_MODE[0], + MPC_RMU_3DLUT_SIZE, &s->lut3d_size); + } else { + REG_GET(SHAPER_CONTROL[1], + MPC_RMU_SHAPER_LUT_MODE_CURRENT, &s->shaper_lut_mode); + REG_GET(RMU_3DLUT_MODE[1], + MPC_RMU_3DLUT_MODE_CURRENT, &s->lut3d_mode); + REG_GET(RMU_3DLUT_READ_WRITE_CONTROL[1], + MPC_RMU_3DLUT_30BIT_EN, &s->lut3d_bit_depth); + REG_GET(RMU_3DLUT_MODE[1], + MPC_RMU_3DLUT_SIZE, &s->lut3d_size); + } + + REG_GET_2(MPCC_OGAM_CONTROL[mpcc_inst], + MPCC_OGAM_MODE_CURRENT, &s->rgam_mode, + MPCC_OGAM_SELECT_CURRENT, &s->rgam_lut); +} + static const struct mpc_funcs dcn30_mpc_funcs = { - .read_mpcc_state = mpc1_read_mpcc_state, + .read_mpcc_state = mpc3_read_mpcc_state, .insert_plane = mpc1_insert_plane, .remove_mpcc = mpc1_remove_mpcc, .mpc_init = mpc1_mpc_init, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h index 5198f2167c7c8eb7b55d8aa7453010f7460cb726..9cb96ae95a2f753639e3149ee55757dae44bffd3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h @@ -1056,6 +1056,10 @@ void mpc3_set_gamut_remap( int mpcc_id, const struct mpc_grph_gamut_adjustment *adjust); +void mpc3_get_gamut_remap(struct mpc *mpc, + int mpcc_id, + struct mpc_grph_gamut_adjustment *adjust); + void mpc3_set_rmu_mux( struct mpc *mpc, int rmu_idx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c index 501388014855c5a1f830b6a830d9f6eed9bf3224..d761b0df28784afd5d81dfef193dfc11657ddff2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c @@ -203,12 +203,12 @@ void dcn32_link_encoder_construct( enc10->base.hpd_source = init_data->hpd_source; enc10->base.connector = init_data->connector; - if (enc10->base.connector.id == CONNECTOR_ID_USBC) - enc10->base.features.flags.bits.DP_IS_USB_C = 1; enc10->base.preferred_engine = ENGINE_ID_UNKNOWN; enc10->base.features = *enc_features; + if (enc10->base.connector.id == CONNECTOR_ID_USBC) + enc10->base.features.flags.bits.DP_IS_USB_C = 1; enc10->base.transmitter = init_data->transmitter; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dpp.c index dcf12a0b031c78fa658ee1261ae066d037e13636..681e75c6dbaf4389bdbaf4373c8e560bae86da9b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dpp.c @@ -133,6 +133,7 @@ static struct dpp_funcs dcn32_dpp_funcs = { .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp3_set_hdr_multiplier, + .dpp_get_gamut_remap = dpp3_cm_get_gamut_remap, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c index da94e5309fbaf0f8e06a4a1aad4ce431a8d9f2cc..81e349d5835bbed499f03ef6eb33e5210c83d64b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c @@ -184,8 +184,6 @@ void dcn35_link_encoder_construct( enc10->base.hpd_source = init_data->hpd_source; enc10->base.connector = init_data->connector; - if (enc10->base.connector.id == CONNECTOR_ID_USBC) - enc10->base.features.flags.bits.DP_IS_USB_C = 1; enc10->base.preferred_engine = ENGINE_ID_UNKNOWN; @@ -240,6 +238,8 @@ void dcn35_link_encoder_construct( } enc10->base.features.flags.bits.HDMI_6GB_EN = 1; + if (enc10->base.connector.id == CONNECTOR_ID_USBC) + enc10->base.features.flags.bits.DP_IS_USB_C = 1; if (bp_funcs->get_connector_speed_cap_info) result = bp_funcs->get_connector_speed_cap_info(enc10->base.ctx->dc_bios, diff --git a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h index 4229369c57f4b4e8123697ac922ae76e8106ed33..f4d3f04ec85791fa394c50b3e4de167debc70815 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h +++ b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h @@ -26,6 +26,9 @@ #ifndef DM_CP_PSP_IF__H #define DM_CP_PSP_IF__H +/* + * Interface to CPLIB/PSP to enable ASSR + */ struct dc_link; struct cp_psp_stream_config { diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 6042a5a6a44f8c32187b2bea702892572f08ec57..59ade76ffb18d56f26a6b329b850462150214c04 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -72,11 +72,11 @@ CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn10/dcn10_fpu.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/dcn20_fpu.o := $(dml_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags) +CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20.o := $(dml_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) +CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20v2.o := $(dml_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags) +CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_rq_dlg_calc_21.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index 63c48c29ba4910beec4d9e6492b0894f9867d8bb..e7f4a2d491ccf42343afa24ba422e8cb84f57126 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -4273,7 +4273,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l //Calculate Swath, DET Configuration, DCFCLKDeepSleep // - for (i = 0; i < mode_lib->soc.num_states; ++i) { + for (i = start_state; i < mode_lib->soc.num_states; ++i) { for (j = 0; j <= 1; ++j) { for (k = 0; k < v->NumberOfActivePlanes; ++k) { v->RequiredDPPCLKThisState[k] = v->RequiredDPPCLK[i][j][k]; @@ -4576,7 +4576,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l //Calculate Return BW - for (i = 0; i < mode_lib->soc.num_states; ++i) { + for (i = start_state; i < mode_lib->soc.num_states; ++i) { for (j = 0; j <= 1; ++j) { for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { if (v->BlendingAndTiming[k] == k) { @@ -4635,7 +4635,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->UrgentOutOfOrderReturnPerChannelVMDataOnly); v->FinalDRAMClockChangeLatency = (v->DRAMClockChangeLatencyOverride > 0 ? v->DRAMClockChangeLatencyOverride : v->DRAMClockChangeLatency); - for (i = 0; i < mode_lib->soc.num_states; ++i) { + for (i = start_state; i < mode_lib->soc.num_states; ++i) { for (j = 0; j <= 1; ++j) { v->DCFCLKState[i][j] = v->DCFCLKPerState[i]; } @@ -4646,7 +4646,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l if (v->ClampMinDCFCLK) { /* Clamp calculated values to actual minimum */ - for (i = 0; i < mode_lib->soc.num_states; ++i) { + for (i = start_state; i < mode_lib->soc.num_states; ++i) { for (j = 0; j <= 1; ++j) { if (v->DCFCLKState[i][j] < mode_lib->soc.min_dcfclk) { v->DCFCLKState[i][j] = mode_lib->soc.min_dcfclk; @@ -4656,7 +4656,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } } - for (i = 0; i < mode_lib->soc.num_states; ++i) { + for (i = start_state; i < mode_lib->soc.num_states; ++i) { for (j = 0; j <= 1; ++j) { v->IdealSDPPortBandwidthPerState[i][j] = dml_min3( v->ReturnBusWidth * v->DCFCLKState[i][j], @@ -4674,7 +4674,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l //Re-ordering Buffer Support Check - for (i = 0; i < mode_lib->soc.num_states; ++i) { + for (i = start_state; i < mode_lib->soc.num_states; ++i) { for (j = 0; j <= 1; ++j) { if ((v->ROBBufferSizeInKByte - v->PixelChunkSizeInKByte) * 1024 / v->ReturnBWPerState[i][j] > (v->RoundTripPingLatencyCycles + 32) / v->DCFCLKState[i][j] + ReorderingBytes / v->ReturnBWPerState[i][j]) { @@ -4692,7 +4692,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l MaxTotalVActiveRDBandwidth = MaxTotalVActiveRDBandwidth + v->ReadBandwidthLuma[k] + v->ReadBandwidthChroma[k]; } - for (i = 0; i < mode_lib->soc.num_states; ++i) { + for (i = start_state; i < mode_lib->soc.num_states; ++i) { for (j = 0; j <= 1; ++j) { v->MaxTotalVerticalActiveAvailableBandwidth[i][j] = dml_min( v->IdealSDPPortBandwidthPerState[i][j] * v->MaxAveragePercentOfIdealSDPPortBWDisplayCanUseInNormalSystemOperation / 100, @@ -4708,7 +4708,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l //Prefetch Check - for (i = 0; i < mode_lib->soc.num_states; ++i) { + for (i = start_state; i < mode_lib->soc.num_states; ++i) { for (j = 0; j <= 1; ++j) { int NextPrefetchModeState = MinPrefetchMode; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c index 3eb3a021ab7d72f672b0029d333e32f4f58af559..3f02bb806d421a224401aa2bde415e564f453e8b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c @@ -266,6 +266,17 @@ void dcn303_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_p optimal_uclk_for_dcfclk_sta_targets[i] = bw_params->clk_table.entries[j].memclk_mhz * 16; break; + } else { + /* condition where (dcfclk_sta_targets[i] >= optimal_dcfclk_for_uclk[j]): + * This is required for dcn303 because it just so happens that the memory + * bandwidth is low enough such that all the optimal DCFCLK for each UCLK + * is lower than the smallest DCFCLK STA target. In this case we need to + * populate the optimal UCLK for each DCFCLK STA target to be the max UCLK. + */ + if (j == num_uclk_states - 1) { + optimal_uclk_for_dcfclk_sta_targets[i] = + bw_params->clk_table.entries[j].memclk_mhz * 16; + } } } } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 9f37f717a1f86f88c5fa41bc30f477406d70f3b8..ba76dd4a2ce29a68a75883b8e8538395195b4089 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -1112,7 +1112,7 @@ struct pipe_slice_table { struct pipe_ctx *pri_pipe; struct dc_plane_state *plane; int slice_count; - } mpc_combines[MAX_SURFACES]; + } mpc_combines[MAX_PLANES]; int mpc_combine_count; }; @@ -1288,7 +1288,7 @@ static bool update_pipes_with_split_flags(struct dc *dc, struct dc_state *contex return updated; } -static bool should_allow_odm_power_optimization(struct dc *dc, +static bool should_apply_odm_power_optimization(struct dc *dc, struct dc_state *context, struct vba_vars_st *v, int *split, bool *merge) { @@ -1392,9 +1392,12 @@ static void try_odm_power_optimization_and_revalidate( { int i; unsigned int new_vlevel; + unsigned int cur_policy[MAX_PIPES]; - for (i = 0; i < pipe_cnt; i++) + for (i = 0; i < pipe_cnt; i++) { + cur_policy[i] = pipes[i].pipe.dest.odm_combine_policy; pipes[i].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1; + } new_vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); @@ -1403,6 +1406,9 @@ static void try_odm_power_optimization_and_revalidate( memset(merge, 0, MAX_PIPES * sizeof(bool)); *vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, new_vlevel, split, merge); context->bw_ctx.dml.vba.VoltageLevel = *vlevel; + } else { + for (i = 0; i < pipe_cnt; i++) + pipes[i].pipe.dest.odm_combine_policy = cur_policy[i]; } } @@ -1580,7 +1586,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, } } - if (should_allow_odm_power_optimization(dc, context, vba, split, merge)) + if (should_apply_odm_power_optimization(dc, context, vba, split, merge)) try_odm_power_optimization_and_revalidate( dc, context, pipes, split, merge, vlevel, *pipe_cnt); @@ -2209,7 +2215,8 @@ bool dcn32_internal_validate_bw(struct dc *dc, int i; pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); - dcn32_update_dml_pipes_odm_policy_based_on_context(dc, context, pipes); + if (!dc->config.enable_windowed_mpo_odm) + dcn32_update_dml_pipes_odm_policy_based_on_context(dc, context, pipes); /* repopulate_pipes = 1 means the pipes were either split or merged. In this case * we have to re-calculate the DET allocation and run through DML once more to @@ -2753,7 +2760,7 @@ static int build_synthetic_soc_states(bool disable_dc_mode_overwrite, struct clk struct _vcs_dpi_voltage_scaling_st entry = {0}; struct clk_limit_table_entry max_clk_data = {0}; - unsigned int min_dcfclk_mhz = 199, min_fclk_mhz = 299; + unsigned int min_dcfclk_mhz = 399, min_fclk_mhz = 599; static const unsigned int num_dcfclk_stas = 5; unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564}; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c index 475c4ec43c013f481a71ad5668a8aef82ac7ba0a..912256006d7567a712ca191346389cd9f10ac974 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c @@ -164,8 +164,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_5_soc = { }, }, .num_states = 5, - .sr_exit_time_us = 14.0, - .sr_enter_plus_exit_time_us = 16.0, + .sr_exit_time_us = 28.0, + .sr_enter_plus_exit_time_us = 30.0, .sr_exit_z8_time_us = 210.0, .sr_enter_plus_exit_z8_time_us = 320.0, .fclk_change_latency_us = 24.0, @@ -583,9 +583,9 @@ void dcn35_decide_zstate_support(struct dc *dc, struct dc_state *context) plane_count++; } - if (plane_count == 0) { + if (context->stream_count == 0 || plane_count == 0) { support = DCN_ZSTATE_SUPPORT_ALLOW; - } else if (plane_count == 1 && context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) { + } else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) { struct dc_link *link = context->streams[0]->sink->link; bool is_pwrseq0 = link && link->link_index == 0; bool is_psr1 = link && link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr; diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c index 0baf39d64a2d4f33ab30f35e63502fd6ba8c569e..a52c594e1ba4be7551168a01d5f43a0186423e79 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c @@ -141,14 +141,33 @@ static unsigned int find_pipes_assigned_to_plane(struct dml2_context *ctx, { int i; unsigned int num_found = 0; - unsigned int plane_id_assigned_to_pipe; + unsigned int plane_id_assigned_to_pipe = -1; for (i = 0; i < ctx->config.dcn_pipe_count; i++) { - if (state->res_ctx.pipe_ctx[i].plane_state && get_plane_id(ctx, state, state->res_ctx.pipe_ctx[i].plane_state, - state->res_ctx.pipe_ctx[i].stream->stream_id, - ctx->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_index[state->res_ctx.pipe_ctx[i].pipe_idx], &plane_id_assigned_to_pipe)) { - if (plane_id_assigned_to_pipe == plane_id) - pipes[num_found++] = i; + struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; + + if (!pipe->plane_state || !pipe->stream) + continue; + + get_plane_id(ctx, state, pipe->plane_state, pipe->stream->stream_id, + ctx->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_index[pipe->pipe_idx], + &plane_id_assigned_to_pipe); + if (plane_id_assigned_to_pipe == plane_id && !pipe->prev_odm_pipe + && (!pipe->top_pipe || pipe->top_pipe->plane_state != pipe->plane_state)) { + while (pipe) { + struct pipe_ctx *mpc_pipe = pipe; + + while (mpc_pipe) { + pipes[num_found++] = mpc_pipe->pipe_idx; + mpc_pipe = mpc_pipe->bottom_pipe; + if (!mpc_pipe) + break; + if (mpc_pipe->plane_state != pipe->plane_state) + mpc_pipe = NULL; + } + pipe = pipe->next_odm_pipe; + } + break; } } @@ -566,8 +585,14 @@ static unsigned int find_pipes_assigned_to_stream(struct dml2_context *ctx, stru unsigned int num_found = 0; for (i = 0; i < ctx->config.dcn_pipe_count; i++) { - if (state->res_ctx.pipe_ctx[i].stream && state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) { - pipes[num_found++] = i; + struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; + + if (pipe->stream && pipe->stream->stream_id == stream_id && !pipe->top_pipe && !pipe->prev_odm_pipe) { + while (pipe) { + pipes[num_found++] = pipe->pipe_idx; + pipe = pipe->next_odm_pipe; + } + break; } } diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c index 64d01a9cd68c859db9bcffbc478ef09090b07fbf..23a608274096f89002e7e5438be18c85d023e442 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c @@ -341,9 +341,6 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, break; } - if (dml2->config.bbox_overrides.clks_table.num_states) - p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states; - /* Override from passed values, if available */ for (i = 0; i < p->in_states->num_states; i++) { if (dml2->config.bbox_overrides.sr_exit_latency_us) { @@ -400,6 +397,7 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, } /* Copy clocks tables entries, if available */ if (dml2->config.bbox_overrides.clks_table.num_states) { + p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states; for (i = 0; i < dml2->config.bbox_overrides.clks_table.num_entries_per_clk.num_dcfclk_levels; i++) { p->in_states->state_array[i].dcfclk_mhz = dml2->config.bbox_overrides.clks_table.clk_entries[i].dcfclk_mhz; @@ -793,35 +791,28 @@ static void populate_dml_surface_cfg_from_plane_state(enum dml_project_id dml2_p } } -/*TODO no support for mpc combine, need rework - should calculate scaling params based on plane+stream*/ -static struct scaler_data get_scaler_data_for_plane(const struct dc_plane_state *in, const struct dc_state *context) +static struct scaler_data get_scaler_data_for_plane(const struct dc_plane_state *in, struct dc_state *context) { int i; - struct scaler_data data = { 0 }; + struct pipe_ctx *temp_pipe = &context->res_ctx.temp_pipe; + + memset(temp_pipe, 0, sizeof(struct pipe_ctx)); for (i = 0; i < MAX_PIPES; i++) { const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; if (pipe->plane_state == in && !pipe->prev_odm_pipe) { - const struct pipe_ctx *next_pipe = pipe->next_odm_pipe; - - data = context->res_ctx.pipe_ctx[i].plane_res.scl_data; - while (next_pipe) { - data.h_active += next_pipe->plane_res.scl_data.h_active; - data.recout.width += next_pipe->plane_res.scl_data.recout.width; - if (in->rotation == ROTATION_ANGLE_0 || in->rotation == ROTATION_ANGLE_180) { - data.viewport.width += next_pipe->plane_res.scl_data.viewport.width; - } else { - data.viewport.height += next_pipe->plane_res.scl_data.viewport.height; - } - next_pipe = next_pipe->next_odm_pipe; - } + temp_pipe->stream = pipe->stream; + temp_pipe->plane_state = pipe->plane_state; + temp_pipe->plane_res.scl_data.taps = pipe->plane_res.scl_data.taps; + + resource_build_scaling_params(temp_pipe); break; } } ASSERT(i < MAX_PIPES); - return data; + return temp_pipe->plane_res.scl_data; } static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_stream_state *in) @@ -866,7 +857,7 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned out->ScalerEnabled[location] = false; } -static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_plane_state *in, const struct dc_state *context) +static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_plane_state *in, struct dc_state *context) { const struct scaler_data scaler_data = get_scaler_data_for_plane(in, context); diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c index 1068b962d1c12bf5145a7c64ae7ddfa991d0b198..f15d1dbad6a968204be0971776ad46650f2b7d0c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c @@ -234,7 +234,7 @@ static bool get_plane_id(struct dml2_context *dml2, const struct dc_state *state if (state->streams[i]->stream_id == stream_id) { for (j = 0; j < state->stream_status[i].plane_count; j++) { if (state->stream_status[i].plane_states[j] == plane && - (!is_plane_duplicate || (is_plane_duplicate && (j == plane_index)))) { + (!is_plane_duplicate || (j == plane_index))) { *plane_id = (i << 16) | j; return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c index 0df6c55eb32608e95b927a70a4b15ff3fec9e3f3..ac41f9c0a2834189ecfba441cdb463ce1d745bfc 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -137,6 +137,11 @@ uint32_t dc_bandwidth_in_kbps_from_timing( if (link_encoding == DC_LINK_ENCODING_DP_128b_132b) kbps = apply_128b_132b_stream_overhead(timing, kbps); + if (link_encoding == DC_LINK_ENCODING_HDMI_FRL && + timing->vic == 0 && timing->hdmi_vic == 0 && + timing->frl_uncompressed_video_bandwidth_in_kbps != 0) + kbps = timing->frl_uncompressed_video_bandwidth_in_kbps; + return kbps; } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 5660f15da291e9de58637c115e315b07f1cee7a3..9d5df4c0da59796ebd8a16927cba72f17239c4fc 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -1183,9 +1183,9 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx) dto_params.timing = &pipe_ctx->stream->timing; dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; if (dccg) { - dccg->funcs->set_dtbclk_dto(dccg, &dto_params); dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst); dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst); + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); } } else if (dccg && dccg->funcs->disable_symclk_se) { dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst, @@ -1291,6 +1291,46 @@ static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id) } } +static void populate_audio_dp_link_info( + const struct pipe_ctx *pipe_ctx, + struct audio_dp_link_info *dp_link_info) +{ + const struct dc_stream_state *stream = pipe_ctx->stream; + const struct dc_link *link = stream->link; + struct fixed31_32 link_bw_kbps; + + dp_link_info->encoding = link->dc->link_srv->dp_get_encoding_format( + &pipe_ctx->link_config.dp_link_settings); + dp_link_info->is_mst = (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST); + dp_link_info->lane_count = pipe_ctx->link_config.dp_link_settings.lane_count; + dp_link_info->link_rate = pipe_ctx->link_config.dp_link_settings.link_rate; + + link_bw_kbps = dc_fixpt_from_int(dc_link_bandwidth_kbps(link, + &pipe_ctx->link_config.dp_link_settings)); + + /* For audio stream calculations, the video stream should not include FEC or SSC + * in order to get the most pessimistic values. + */ + if (dp_link_info->encoding == DP_8b_10b_ENCODING && + link->dc->link_srv->dp_is_fec_supported(link)) { + link_bw_kbps = dc_fixpt_mul(link_bw_kbps, + dc_fixpt_from_fraction(100, DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100)); + } else if (dp_link_info->encoding == DP_128b_132b_ENCODING) { + link_bw_kbps = dc_fixpt_mul(link_bw_kbps, + dc_fixpt_from_fraction(10000, 9975)); /* 99.75% SSC overhead*/ + } + + dp_link_info->link_bandwidth_kbps = dc_fixpt_floor(link_bw_kbps); + + /* HW minimum for 128b/132b HBlank is 4 frame symbols. + * TODO: Plumb the actual programmed HBlank min symbol width to here. + */ + if (dp_link_info->encoding == DP_128b_132b_ENCODING) + dp_link_info->hblank_min_symbol_width = 4; + else + dp_link_info->hblank_min_symbol_width = 0; +} + static void build_audio_output( struct dc_state *state, const struct pipe_ctx *pipe_ctx, @@ -1338,6 +1378,15 @@ static void build_audio_output( audio_output->crtc_info.calculated_pixel_clock_100Hz = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz; + audio_output->crtc_info.pixel_encoding = + stream->timing.pixel_encoding; + + audio_output->crtc_info.dsc_bits_per_pixel = + stream->timing.dsc_cfg.bits_per_pixel; + + audio_output->crtc_info.dsc_num_slices = + stream->timing.dsc_cfg.num_slices_h; + /*for HDMI, audio ACR is with deep color ratio factor*/ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) && audio_output->crtc_info.requested_pixel_clock_100Hz == @@ -1371,6 +1420,10 @@ static void build_audio_output( audio_output->pll_info.ss_percentage = pipe_ctx->pll_settings.ss_percentage; + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + populate_audio_dp_link_info(pipe_ctx, &audio_output->dp_link_info); + } } static void program_scaler(const struct dc *dc, @@ -1476,7 +1529,7 @@ static enum dc_status dce110_enable_stream_timing( return DC_OK; } -static enum dc_status apply_single_controller_ctx_to_hw( +enum dc_status dce110_apply_single_controller_ctx_to_hw( struct pipe_ctx *pipe_ctx, struct dc_state *context, struct dc *dc) @@ -1507,7 +1560,8 @@ static enum dc_status apply_single_controller_ctx_to_hw( pipe_ctx->stream_res.audio, pipe_ctx->stream->signal, &audio_output.crtc_info, - &pipe_ctx->stream->audio_info); + &pipe_ctx->stream->audio_info, + &audio_output.dp_link_info); } /* make sure no pipes syncd to the pipe being enabled */ @@ -2302,7 +2356,7 @@ enum dc_status dce110_apply_ctx_to_hw( if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe) continue; - status = apply_single_controller_ctx_to_hw( + status = dce110_apply_single_controller_ctx_to_hw( pipe_ctx, context, dc); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h index 08028a1779ae819282ab2394de57c4b8f266a9f3..ed3cc3648e8e23f8d076b92e10a23791253f9662 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h @@ -39,6 +39,10 @@ enum dc_status dce110_apply_ctx_to_hw( struct dc *dc, struct dc_state *context); +enum dc_status dce110_apply_single_controller_ctx_to_hw( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); void dce110_enable_stream(struct pipe_ctx *pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index 6dd479e8a348502c9b285a38f16650fb7cb4f95e..314798400b16e93f60769e0176bba1ab8fbf2b04 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -283,33 +283,33 @@ static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) DTN_INFO("\n"); } -void dcn10_log_hw_state(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx) +static void dcn10_log_color_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx) { struct dc_context *dc_ctx = dc->ctx; struct resource_pool *pool = dc->res_pool; int i; - DTN_INFO_BEGIN(); - - dcn10_log_hubbub_state(dc, log_ctx); - - dcn10_log_hubp_states(dc, log_ctx); - - DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode" - " GAMUT mode C11 C12 C13 C14 C21 C22 C23 C24 " - "C31 C32 C33 C34\n"); + DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode" + " GAMUT adjust " + "C11 C12 C13 C14 " + "C21 C22 C23 C24 " + "C31 C32 C33 C34 \n"); for (i = 0; i < pool->pipe_count; i++) { struct dpp *dpp = pool->dpps[i]; struct dcn_dpp_state s = {0}; dpp->funcs->dpp_read_state(dpp, &s); + dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); if (!s.is_enabled) continue; - DTN_INFO("[%2d]: %11xh %-11s %-11s %-11s" - "%8x %08xh %08xh %08xh %08xh %08xh %08xh", + DTN_INFO("[%2d]: %11xh %11s %9s %9s" + " %12s " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld", dpp->inst, s.igam_input_format, (s.igam_lut_mode == 0) ? "BypassFixed" : @@ -329,16 +329,42 @@ void dcn10_log_hw_state(struct dc *dc, ((s.rgam_lut_mode == 3) ? "RAM" : ((s.rgam_lut_mode == 4) ? "RAM" : "Unknown")))), - s.gamut_remap_mode, - s.gamut_remap_c11_c12, - s.gamut_remap_c13_c14, - s.gamut_remap_c21_c22, - s.gamut_remap_c23_c24, - s.gamut_remap_c31_c32, - s.gamut_remap_c33_c34); + (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : + ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : + "SW"), + s.gamut_remap.temperature_matrix[0].value, + s.gamut_remap.temperature_matrix[1].value, + s.gamut_remap.temperature_matrix[2].value, + s.gamut_remap.temperature_matrix[3].value, + s.gamut_remap.temperature_matrix[4].value, + s.gamut_remap.temperature_matrix[5].value, + s.gamut_remap.temperature_matrix[6].value, + s.gamut_remap.temperature_matrix[7].value, + s.gamut_remap.temperature_matrix[8].value, + s.gamut_remap.temperature_matrix[9].value, + s.gamut_remap.temperature_matrix[10].value, + s.gamut_remap.temperature_matrix[11].value); DTN_INFO("\n"); } DTN_INFO("\n"); + DTN_INFO("DPP Color Caps: input_lut_shared:%d icsc:%d" + " dgam_ram:%d dgam_rom: srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d" + " post_csc:%d gamcor:%d dgam_rom_for_yuv:%d 3d_lut:%d" + " blnd_lut:%d oscs:%d\n\n", + dc->caps.color.dpp.input_lut_shared, + dc->caps.color.dpp.icsc, + dc->caps.color.dpp.dgam_ram, + dc->caps.color.dpp.dgam_rom_caps.srgb, + dc->caps.color.dpp.dgam_rom_caps.bt2020, + dc->caps.color.dpp.dgam_rom_caps.gamma2_2, + dc->caps.color.dpp.dgam_rom_caps.pq, + dc->caps.color.dpp.dgam_rom_caps.hlg, + dc->caps.color.dpp.post_csc, + dc->caps.color.dpp.gamma_corr, + dc->caps.color.dpp.dgam_rom_for_yuv, + dc->caps.color.dpp.hw_3d_lut, + dc->caps.color.dpp.ogam_ram, + dc->caps.color.dpp.ocsc); DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE\n"); for (i = 0; i < pool->pipe_count; i++) { @@ -352,6 +378,30 @@ void dcn10_log_hw_state(struct dc *dc, s.idle); } DTN_INFO("\n"); + DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, ocsc:%d\n\n", + dc->caps.color.mpc.gamut_remap, + dc->caps.color.mpc.num_3dluts, + dc->caps.color.mpc.ogam_ram, + dc->caps.color.mpc.ocsc); +} + +void dcn10_log_hw_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx) +{ + struct dc_context *dc_ctx = dc->ctx; + struct resource_pool *pool = dc->res_pool; + int i; + + DTN_INFO_BEGIN(); + + dcn10_log_hubbub_state(dc, log_ctx); + + dcn10_log_hubp_states(dc, log_ctx); + + if (dc->hwss.log_color_state) + dc->hwss.log_color_state(dc, log_ctx); + else + dcn10_log_color_state(dc, log_ctx); DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel h_bs h_be h_ss h_se hpol htot vtot underflow blank_en\n"); @@ -1840,6 +1890,9 @@ bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, { struct dpp *dpp = pipe_ctx->plane_res.dpp; + if (!stream) + return false; + if (dpp == NULL) return false; @@ -1862,8 +1915,8 @@ bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, } else dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); - if (stream != NULL && stream->ctx != NULL && - stream->out_transfer_func != NULL) { + if (stream->ctx && + stream->out_transfer_func) { log_tf(stream->ctx, stream->out_transfer_func, dpp->regamma_params.hw_points_num); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index e931342fcf4cf1d4f4b0cf41628cd9f855fa6dac..bc0a21957e33f97930df9b16582c8bb500026fde 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -71,6 +71,112 @@ #define FN(reg_name, field_name) \ hws->shifts->field_name, hws->masks->field_name +void dcn20_log_color_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx) +{ + struct dc_context *dc_ctx = dc->ctx; + struct resource_pool *pool = dc->res_pool; + int i; + + DTN_INFO("DPP: DGAM mode SHAPER mode 3DLUT mode 3DLUT bit depth" + " 3DLUT size RGAM mode GAMUT adjust " + "C11 C12 C13 C14 " + "C21 C22 C23 C24 " + "C31 C32 C33 C34 \n"); + + for (i = 0; i < pool->pipe_count; i++) { + struct dpp *dpp = pool->dpps[i]; + struct dcn_dpp_state s = {0}; + + dpp->funcs->dpp_read_state(dpp, &s); + dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); + + if (!s.is_enabled) + continue; + + DTN_INFO("[%2d]: %8s %11s %10s %15s %10s %9s %12s " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld", + dpp->inst, + (s.dgam_lut_mode == 0) ? "Bypass" : + ((s.dgam_lut_mode == 1) ? "sRGB" : + ((s.dgam_lut_mode == 2) ? "Ycc" : + ((s.dgam_lut_mode == 3) ? "RAM" : + ((s.dgam_lut_mode == 4) ? "RAM" : + "Unknown")))), + (s.shaper_lut_mode == 1) ? "RAM A" : + ((s.shaper_lut_mode == 2) ? "RAM B" : + "Bypass"), + (s.lut3d_mode == 1) ? "RAM A" : + ((s.lut3d_mode == 2) ? "RAM B" : + "Bypass"), + (s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit", + (s.lut3d_size == 0) ? "17x17x17" : "9x9x9", + (s.rgam_lut_mode == 1) ? "RAM A" : + ((s.rgam_lut_mode == 1) ? "RAM B" : "Bypass"), + (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : + ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : + "SW"), + s.gamut_remap.temperature_matrix[0].value, + s.gamut_remap.temperature_matrix[1].value, + s.gamut_remap.temperature_matrix[2].value, + s.gamut_remap.temperature_matrix[3].value, + s.gamut_remap.temperature_matrix[4].value, + s.gamut_remap.temperature_matrix[5].value, + s.gamut_remap.temperature_matrix[6].value, + s.gamut_remap.temperature_matrix[7].value, + s.gamut_remap.temperature_matrix[8].value, + s.gamut_remap.temperature_matrix[9].value, + s.gamut_remap.temperature_matrix[10].value, + s.gamut_remap.temperature_matrix[11].value); + DTN_INFO("\n"); + } + DTN_INFO("\n"); + DTN_INFO("DPP Color Caps: input_lut_shared:%d icsc:%d" + " dgam_ram:%d dgam_rom: srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d" + " post_csc:%d gamcor:%d dgam_rom_for_yuv:%d 3d_lut:%d" + " blnd_lut:%d oscs:%d\n\n", + dc->caps.color.dpp.input_lut_shared, + dc->caps.color.dpp.icsc, + dc->caps.color.dpp.dgam_ram, + dc->caps.color.dpp.dgam_rom_caps.srgb, + dc->caps.color.dpp.dgam_rom_caps.bt2020, + dc->caps.color.dpp.dgam_rom_caps.gamma2_2, + dc->caps.color.dpp.dgam_rom_caps.pq, + dc->caps.color.dpp.dgam_rom_caps.hlg, + dc->caps.color.dpp.post_csc, + dc->caps.color.dpp.gamma_corr, + dc->caps.color.dpp.dgam_rom_for_yuv, + dc->caps.color.dpp.hw_3d_lut, + dc->caps.color.dpp.ogam_ram, + dc->caps.color.dpp.ocsc); + + DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE" + " OGAM mode\n"); + + for (i = 0; i < pool->pipe_count; i++) { + struct mpcc_state s = {0}; + + pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); + if (s.opp_id != 0xf) + DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d %9s\n", + i, s.opp_id, s.dpp_id, s.bot_mpcc_id, + s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only, + s.idle, + (s.rgam_mode == 1) ? "RAM A" : + ((s.rgam_mode == 2) ? "RAM B" : + "Bypass")); + } + DTN_INFO("\n"); + DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, ocsc:%d\n\n", + dc->caps.color.mpc.gamut_remap, + dc->caps.color.mpc.num_3dluts, + dc->caps.color.mpc.ogam_ram, + dc->caps.color.mpc.ocsc); +} + + static int find_free_gsl_group(const struct dc *dc) { if (dc->res_pool->gsl_groups.gsl_0 == 0) @@ -1467,7 +1573,8 @@ static void dcn20_detect_pipe_changes(struct dc_state *old_state, * makes this assumption at the moment with how hubp reset is matched to * same index mpcc reset. */ - if (old_pipe->stream_res.opp != new_pipe->stream_res.opp) + if (old_pipe->stream_res.opp != new_pipe->stream_res.opp || + old_pipe->stream_res.left_edge_extra_pixel != new_pipe->stream_res.left_edge_extra_pixel) new_pipe->update_flags.bits.opp_changed = 1; if (old_pipe->stream_res.tg != new_pipe->stream_res.tg) new_pipe->update_flags.bits.tg_changed = 1; @@ -1853,6 +1960,10 @@ static void dcn20_program_pipe( pipe_ctx->stream_res.opp, &pipe_ctx->stream->bit_depth_params, &pipe_ctx->stream->clamping); + + pipe_ctx->stream_res.opp->funcs->opp_program_left_edge_extra_pixel( + pipe_ctx->stream_res.opp, + pipe_ctx->stream_res.left_edge_extra_pixel); } /* Set ABM pipe after other pipe configurations done */ @@ -1958,7 +2069,6 @@ void dcn20_program_front_end_for_ctx( && context->res_ctx.pipe_ctx[i].stream) hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true); - /* Disconnect mpcc */ for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable @@ -2561,7 +2671,7 @@ void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) tg->funcs->setup_vertical_interrupt2(tg, start_line); } -static void dcn20_reset_back_end_for_pipe( +void dcn20_reset_back_end_for_pipe( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) @@ -2790,18 +2900,17 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) } if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; - dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst); - - phyd32clk = get_phyd32clk_src(link); - dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); - dto_params.otg_inst = tg->inst; dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx); dto_params.timing = &pipe_ctx->stream->timing; dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; + dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst); + + phyd32clk = get_phyd32clk_src(link); + dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); } else { if (dccg->funcs->enable_symclk_se) dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h index b94c85340abff7c02f3ec59025b04c8417d77bd6..5c874f7b0683ed4c208565f63d0cc49fdf63249d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h @@ -28,6 +28,8 @@ #include "hw_sequencer_private.h" +void dcn20_log_color_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx); bool dcn20_set_blend_lut( struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); bool dcn20_set_shaper_3dlut( @@ -84,6 +86,10 @@ enum dc_status dcn20_enable_stream_timing( void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context); void dcn20_init_blank( struct dc *dc, struct timing_generator *tg); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c index 8e88dcaf88f5b2b709a95abf9e0673390e27daa5..5c7f380a84f91ecb1a668e4798be6aaf9347a46f 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c @@ -206,28 +206,32 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) { struct abm *abm = pipe_ctx->stream_res.abm; - uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; + struct timing_generator *tg = pipe_ctx->stream_res.tg; struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; + uint32_t otg_inst; + + if (!abm && !tg && !panel_cntl) + return; + + otg_inst = tg->inst; if (dmcu) { dce110_set_pipe(pipe_ctx); return; } - if (abm && panel_cntl) { - if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, + if (abm->funcs && abm->funcs->set_pipe_ex) { + abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst, panel_cntl->pwrseq_inst); - } else { - dmub_abm_set_pipe(abm, otg_inst, - SET_ABM_PIPE_NORMAL, - panel_cntl->inst, - panel_cntl->pwrseq_inst); - } + } else { + dmub_abm_set_pipe(abm, otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } } @@ -237,34 +241,35 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, { struct dc_context *dc = pipe_ctx->stream->ctx; struct abm *abm = pipe_ctx->stream_res.abm; + struct timing_generator *tg = pipe_ctx->stream_res.tg; struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; + uint32_t otg_inst; + + if (!abm && !tg && !panel_cntl) + return false; + + otg_inst = tg->inst; if (dc->dc->res_pool->dmcu) { dce110_set_backlight_level(pipe_ctx, backlight_pwm_u16_16, frame_ramp); return true; } - if (abm != NULL) { - uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; - - if (abm && panel_cntl) { - if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, - otg_inst, - SET_ABM_PIPE_NORMAL, - panel_cntl->inst, - panel_cntl->pwrseq_inst); - } else { - dmub_abm_set_pipe(abm, - otg_inst, - SET_ABM_PIPE_NORMAL, - panel_cntl->inst, - panel_cntl->pwrseq_inst); - } - } + if (abm->funcs && abm->funcs->set_pipe_ex) { + abm->funcs->set_pipe_ex(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); + } else { + dmub_abm_set_pipe(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } - if (abm && abm->funcs && abm->funcs->set_backlight_level_pwm) + if (abm->funcs && abm->funcs->set_backlight_level_pwm) abm->funcs->set_backlight_level_pwm(abm, backlight_pwm_u16_16, frame_ramp, 0, panel_cntl->inst); else diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index c34c13e1e0a4ea918de9a9e36dbe305ce5224485..7e6b7f2a6dc9ea799c3a4b0a23b5d3e4c6d26b17 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -69,6 +69,155 @@ #define FN(reg_name, field_name) \ hws->shifts->field_name, hws->masks->field_name +void dcn30_log_color_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx) +{ + struct dc_context *dc_ctx = dc->ctx; + struct resource_pool *pool = dc->res_pool; + int i; + + DTN_INFO("DPP: DGAM ROM DGAM ROM type DGAM LUT SHAPER mode" + " 3DLUT mode 3DLUT bit depth 3DLUT size RGAM mode" + " GAMUT adjust " + "C11 C12 C13 C14 " + "C21 C22 C23 C24 " + "C31 C32 C33 C34 \n"); + + for (i = 0; i < pool->pipe_count; i++) { + struct dpp *dpp = pool->dpps[i]; + struct dcn_dpp_state s = {0}; + + dpp->funcs->dpp_read_state(dpp, &s); + dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap); + + if (!s.is_enabled) + continue; + + DTN_INFO("[%2d]: %7x %13s %8s %11s %10s %15s %10s %9s" + " %12s " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld", + dpp->inst, + s.pre_dgam_mode, + (s.pre_dgam_select == 0) ? "sRGB" : + ((s.pre_dgam_select == 1) ? "Gamma 2.2" : + ((s.pre_dgam_select == 2) ? "Gamma 2.4" : + ((s.pre_dgam_select == 3) ? "Gamma 2.6" : + ((s.pre_dgam_select == 4) ? "BT.709" : + ((s.pre_dgam_select == 5) ? "PQ" : + ((s.pre_dgam_select == 6) ? "HLG" : + "Unknown")))))), + (s.gamcor_mode == 0) ? "Bypass" : + ((s.gamcor_mode == 1) ? "RAM A" : + "RAM B"), + (s.shaper_lut_mode == 1) ? "RAM A" : + ((s.shaper_lut_mode == 2) ? "RAM B" : + "Bypass"), + (s.lut3d_mode == 1) ? "RAM A" : + ((s.lut3d_mode == 2) ? "RAM B" : + "Bypass"), + (s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit", + (s.lut3d_size == 0) ? "17x17x17" : "9x9x9", + (s.rgam_lut_mode == 0) ? "Bypass" : + ((s.rgam_lut_mode == 1) ? "RAM A" : + "RAM B"), + (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : + ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : + "SW"), + s.gamut_remap.temperature_matrix[0].value, + s.gamut_remap.temperature_matrix[1].value, + s.gamut_remap.temperature_matrix[2].value, + s.gamut_remap.temperature_matrix[3].value, + s.gamut_remap.temperature_matrix[4].value, + s.gamut_remap.temperature_matrix[5].value, + s.gamut_remap.temperature_matrix[6].value, + s.gamut_remap.temperature_matrix[7].value, + s.gamut_remap.temperature_matrix[8].value, + s.gamut_remap.temperature_matrix[9].value, + s.gamut_remap.temperature_matrix[10].value, + s.gamut_remap.temperature_matrix[11].value); + DTN_INFO("\n"); + } + DTN_INFO("\n"); + DTN_INFO("DPP Color Caps: input_lut_shared:%d icsc:%d" + " dgam_ram:%d dgam_rom: srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d" + " post_csc:%d gamcor:%d dgam_rom_for_yuv:%d 3d_lut:%d" + " blnd_lut:%d oscs:%d\n\n", + dc->caps.color.dpp.input_lut_shared, + dc->caps.color.dpp.icsc, + dc->caps.color.dpp.dgam_ram, + dc->caps.color.dpp.dgam_rom_caps.srgb, + dc->caps.color.dpp.dgam_rom_caps.bt2020, + dc->caps.color.dpp.dgam_rom_caps.gamma2_2, + dc->caps.color.dpp.dgam_rom_caps.pq, + dc->caps.color.dpp.dgam_rom_caps.hlg, + dc->caps.color.dpp.post_csc, + dc->caps.color.dpp.gamma_corr, + dc->caps.color.dpp.dgam_rom_for_yuv, + dc->caps.color.dpp.hw_3d_lut, + dc->caps.color.dpp.ogam_ram, + dc->caps.color.dpp.ocsc); + + DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE" + " SHAPER mode 3DLUT mode 3DLUT bit-depth 3DLUT size OGAM mode OGAM LUT" + " GAMUT adjust " + "C11 C12 C13 C14 " + "C21 C22 C23 C24 " + "C31 C32 C33 C34 \n"); + + for (i = 0; i < pool->pipe_count; i++) { + struct mpcc_state s = {0}; + + pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); + mpc3_get_gamut_remap(pool->mpc, i, &s.gamut_remap); + + if (s.opp_id != 0xf) + DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d %11s %11s %16s %11s %10s %9s" + " %-12s " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld " + "%010lld %010lld %010lld %010lld\n", + i, s.opp_id, s.dpp_id, s.bot_mpcc_id, + s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only, + s.idle, + (s.shaper_lut_mode == 1) ? "RAM A" : + ((s.shaper_lut_mode == 2) ? "RAM B" : + "Bypass"), + (s.lut3d_mode == 1) ? "RAM A" : + ((s.lut3d_mode == 2) ? "RAM B" : + "Bypass"), + (s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit", + (s.lut3d_size == 0) ? "17x17x17" : "9x9x9", + (s.rgam_mode == 0) ? "Bypass" : + ((s.rgam_mode == 2) ? "RAM" : + "Unknown"), + (s.rgam_mode == 1) ? "B" : "A", + (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" : + ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" : + "SW"), + s.gamut_remap.temperature_matrix[0].value, + s.gamut_remap.temperature_matrix[1].value, + s.gamut_remap.temperature_matrix[2].value, + s.gamut_remap.temperature_matrix[3].value, + s.gamut_remap.temperature_matrix[4].value, + s.gamut_remap.temperature_matrix[5].value, + s.gamut_remap.temperature_matrix[6].value, + s.gamut_remap.temperature_matrix[7].value, + s.gamut_remap.temperature_matrix[8].value, + s.gamut_remap.temperature_matrix[9].value, + s.gamut_remap.temperature_matrix[10].value, + s.gamut_remap.temperature_matrix[11].value); + + } + DTN_INFO("\n"); + DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, ocsc:%d\n\n", + dc->caps.color.mpc.gamut_remap, + dc->caps.color.mpc.num_3dluts, + dc->caps.color.mpc.ogam_ram, + dc->caps.color.mpc.ocsc); +} + bool dcn30_set_blend_lut( struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) { @@ -1015,21 +1164,3 @@ void dcn30_prepare_bandwidth(struct dc *dc, if (!dc->clk_mgr->clks.fw_based_mclk_switching) dc_dmub_srv_p_state_delegate(dc, false, context); } - -void dcn30_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params) -{ - unsigned int i; - unsigned int triggers = 0; - - if (params->triggers.surface_update) - triggers |= 0x100; - if (params->triggers.cursor_update) - triggers |= 0x8; - if (params->triggers.force_trigger) - triggers |= 0x1; - - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(pipe_ctx[i]->stream_res.tg, - triggers, params->num_frames); -} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h index e557e2b9861870bb17ed1ac70f73e636888528d1..638f018a3cb57d17a935c37f27e228dd54a3d07e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h @@ -52,6 +52,9 @@ bool dcn30_mmhubbub_warmup( unsigned int num_dwb, struct dc_writeback_info *wb_info); +void dcn30_log_color_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx); + bool dcn30_set_blend_lut(struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); @@ -90,7 +93,4 @@ void dcn30_set_hubp_blank(const struct dc *dc, void dcn30_prepare_bandwidth(struct dc *dc, struct dc_state *context); -void dcn30_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params); - #endif /* __DC_HWSS_DCN30_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c index 9894caedffed7393e04639ad3adda8c3defe0f6d..ef913445a79573cee099460a1d44a4c27092d945 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c @@ -64,7 +64,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = { .update_bandwidth = dcn20_update_bandwidth, .set_drr = dcn10_set_drr, .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, + .set_static_screen_control = dcn10_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dcn30_set_avmute, .log_hw_state = dcn10_log_hw_state, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c index 7423880fabb6e3b0d1a1003bab1fa8ff4898a936..a760f0c6fe98f22536abe25ebcdde5445fa8399f 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -98,10 +98,8 @@ static void enable_memory_low_power(struct dc *dc) for (i = 0; i < dc->res_pool->stream_enc_count; i++) if (dc->res_pool->stream_enc[i]->vpg) dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); -#if defined(CONFIG_DRM_AMD_DC_FP) for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg); -#endif } } @@ -617,3 +615,21 @@ void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable) if (hws->ctx->dc->debug.hpo_optimization) REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable); } + +void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params) +{ + unsigned int i; + unsigned int triggers = 0; + + if (params->triggers.surface_update) + triggers |= 0x100; + if (params->triggers.cursor_update) + triggers |= 0x8; + if (params->triggers.force_trigger) + triggers |= 0x1; + + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(pipe_ctx[i]->stream_res.tg, + triggers, params->num_frames); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h index edfc01d6ad7378be5873ec2f6b72a63c2991320f..b8bc939da1554fcb9d36bd9ae0ae110523761440 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h @@ -56,4 +56,8 @@ bool dcn31_is_abm_supported(struct dc *dc, void dcn31_init_pipes(struct dc *dc, struct dc_state *context); void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); +void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params); + + #endif /* __DC_HWSS_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c index 669f524bd064d50cc24f87d0b0585d215ce99639..c06cc2c5da920f457c1ba422a7ffa8f59db9d6c0 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c @@ -67,7 +67,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = { .update_bandwidth = dcn20_update_bandwidth, .set_drr = dcn10_set_drr, .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, + .set_static_screen_control = dcn31_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dcn30_set_avmute, .log_hw_state = dcn10_log_hw_state, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c index ccb7e317e86af1b2ea8c0a5669a05a18612c2aee..542ce3b7f9e4d12d4bf7c6fcab2b4ce05c01f4f5 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c @@ -69,7 +69,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = { .update_bandwidth = dcn20_update_bandwidth, .set_drr = dcn10_set_drr, .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, + .set_static_screen_control = dcn31_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dcn30_set_avmute, .log_hw_state = dcn10_log_hw_state, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index 6c9299c7683df19b3c444b865d297182d91ae7b3..aa36d7a56ca8c3b6f3cd47e67455ba67549bf73b 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -1474,9 +1474,44 @@ void dcn32_update_dsc_pg(struct dc *dc, } } +void dcn32_disable_phantom_streams(struct dc *dc, struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + int i; + + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx_old->stream) + continue; + + if (dc_state_get_pipe_subvp_type(dc->current_state, pipe_ctx_old) != SUBVP_PHANTOM) + continue; + + if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) + continue; + + if (!pipe_ctx->stream || pipe_need_reprogram(pipe_ctx_old, pipe_ctx) || + (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + if (hws->funcs.reset_back_end_for_pipe) + hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx_old); + if (old_clk) + old_clk->funcs->cs_power_down(old_clk); + } + } +} + void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context) { unsigned int i; + enum dc_status status = DC_OK; + struct dce_hwseq *hws = dc->hwseq; for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; @@ -1497,16 +1532,39 @@ void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context) } } for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; - - if (new_pipe->stream && dc_state_get_pipe_subvp_type(context, new_pipe) == SUBVP_PHANTOM) { - // If old context or new context has phantom pipes, apply - // the phantom timings now. We can't change the phantom - // pipe configuration safely without driver acquiring - // the DMCUB lock first. - dc->hwss.apply_ctx_to_hw(dc, context); - break; + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == NULL) + continue; + + if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) + continue; + + if (pipe_ctx->stream == pipe_ctx_old->stream && + pipe_ctx->stream->link->link_state_valid) { + continue; } + + if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) + continue; + + if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe) + continue; + + if (hws->funcs.apply_single_controller_ctx_to_hw) + status = hws->funcs.apply_single_controller_ctx_to_hw( + pipe_ctx, + context, + dc); + + ASSERT(status == DC_OK); + +#ifdef CONFIG_DRM_AMD_DC_FP + if (hws->funcs.resync_fifo_dccg_dio) + hws->funcs.resync_fifo_dccg_dio(hws, dc, context); +#endif } } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h index cecf7f0f567190b257cf81e5f756b5a916eba09c..069e20bc87c0a75af028168253219fc9343b1af3 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h @@ -111,6 +111,8 @@ void dcn32_update_dsc_pg(struct dc *dc, void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context); +void dcn32_disable_phantom_streams(struct dc *dc, struct dc_state *context); + void dcn32_init_blank( struct dc *dc, struct timing_generator *tg); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c index 427cfc8c24a4b7ed4cee1f0b6955cbe371797219..2b073123d3ede2eb16ae766af9a285511fc6e8ea 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c @@ -65,7 +65,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = { .update_bandwidth = dcn20_update_bandwidth, .set_drr = dcn10_set_drr, .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, + .set_static_screen_control = dcn31_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dcn30_set_avmute, .log_hw_state = dcn10_log_hw_state, @@ -109,6 +109,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = { .get_dcc_en_bits = dcn10_get_dcc_en_bits, .commit_subvp_config = dcn32_commit_subvp_config, .enable_phantom_streams = dcn32_enable_phantom_streams, + .disable_phantom_streams = dcn32_disable_phantom_streams, .subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock, .update_visual_confirm_color = dcn10_update_visual_confirm_color, .subvp_pipe_control_lock_fast = dcn32_subvp_pipe_control_lock_fast, @@ -159,6 +160,8 @@ static const struct hwseq_private_funcs dcn32_private_funcs = { .set_pixels_per_cycle = dcn32_set_pixels_per_cycle, .resync_fifo_dccg_dio = dcn32_resync_fifo_dccg_dio, .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy, + .apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw, + .reset_back_end_for_pipe = dcn20_reset_back_end_for_pipe, }; void dcn32_hw_sequencer_init_functions(struct dc *dc) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index 9c806385ecbdcce6c0d14f949ea41879758969f7..4b92df23ff0db90498e722c0df0d8bbb149e76e2 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -680,7 +680,7 @@ void dcn35_power_down_on_boot(struct dc *dc) bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) { struct dc_link *edp_links[MAX_NUM_EDP]; - int edp_num; + int i, edp_num; if (dc->debug.dmcub_emulation) return true; @@ -688,6 +688,13 @@ bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) dc_get_edp_links(dc, edp_links, &edp_num); if (edp_num == 0 || edp_num > 1) return false; + + for (i = 0; i < dc->current_state->stream_count; ++i) { + struct dc_stream_state *stream = dc->current_state->streams[i]; + + if (!stream->dpms_off && !dc_is_embedded_signal(stream->signal)) + return false; + } } // TODO: review other cases when idle optimization is allowed @@ -1335,8 +1342,8 @@ void dcn35_set_drr(struct pipe_ctx **pipe_ctx, { int i = 0; struct drr_params params = {0}; - // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow - unsigned int event_triggers = 0x800; + // DRR set trigger event mapped to OTG_TRIG_A + unsigned int event_triggers = 0x2;//Bit[1]: OTG_TRIG_A // Note DRR trigger events are generated regardless of whether num frames met. unsigned int num_frames = 2; @@ -1370,3 +1377,20 @@ void dcn35_set_drr(struct pipe_ctx **pipe_ctx, } } } +void dcn35_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params) +{ + unsigned int i; + unsigned int triggers = 0; + + if (params->triggers.surface_update) + triggers |= 0x200;/*bit 9 : 10 0000 0000*/ + if (params->triggers.cursor_update) + triggers |= 0x8;/*bit3*/ + if (params->triggers.force_trigger) + triggers |= 0x1; + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs-> + set_static_screen_control(pipe_ctx[i]->stream_res.tg, + triggers, params->num_frames); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h index fd66316e33de367da8c90e3520087fce385ebb5b..c354efa6c1b2f8f6e69754553f8ac905ffab8936 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h @@ -90,4 +90,7 @@ uint32_t dcn35_get_idle_state(const struct dc *dc); void dcn35_set_drr(struct pipe_ctx **pipe_ctx, int num_pipes, struct dc_crtc_timing_adjust adjust); +void dcn35_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params); + #endif /* __DC_HWSS_DCN35_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c index a630aa77dcec036c791c3ae4a75a2e3bedafe2f8..a93073055e7bfc976f6c9c4a2885a773a26ccf24 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c @@ -70,7 +70,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = { .update_bandwidth = dcn20_update_bandwidth, .set_drr = dcn35_set_drr, .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, + .set_static_screen_control = dcn35_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dcn30_set_avmute, .log_hw_state = dcn10_log_hw_state, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c index 143d3fc0221cf88b44de1965587fc5578c66ea07..ab17fa1c64e8c5b405ae2f24a93c1ee54abefe10 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c @@ -69,7 +69,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = { .update_bandwidth = dcn20_update_bandwidth, .set_drr = dcn10_set_drr, .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, + .set_static_screen_control = dcn35_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dcn30_set_avmute, .log_hw_state = dcn10_log_hw_state, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index a54399383318145b8bc72fc85e646bf546588609..f89f205e42a1a8ce0da54a83cdb3a3d2033aa3a6 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -339,6 +339,8 @@ struct hw_sequencer_funcs { /* HW State Logging Related */ void (*log_hw_state)(struct dc *dc, struct dc_log_buffer_ctx *log_ctx); + void (*log_color_state)(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx); void (*get_hw_state)(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask); void (*clear_status_bits)(struct dc *dc, unsigned int mask); @@ -379,6 +381,7 @@ struct hw_sequencer_funcs { struct dc_cursor_attributes *cursor_attr); void (*commit_subvp_config)(struct dc *dc, struct dc_state *context); void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context); + void (*disable_phantom_streams)(struct dc *dc, struct dc_state *context); void (*subvp_pipe_control_lock)(struct dc *dc, struct dc_state *context, bool lock, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h index 6137cf09aa54d25750246e86583c5938e557501b..554cfab5ab24a5be6b98b41acf19ffe3c023b620 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -155,7 +155,6 @@ struct hwseq_private_funcs { void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable); void (*enable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context); -#ifdef CONFIG_DRM_AMD_DC_FP void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context); void (*update_force_pstate)(struct dc *dc, struct dc_state *context); void (*update_mall_sel)(struct dc *dc, struct dc_state *context); @@ -165,8 +164,14 @@ struct hwseq_private_funcs { void (*set_pixels_per_cycle)(struct pipe_ctx *pipe_ctx); void (*resync_fifo_dccg_dio)(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context); + enum dc_status (*apply_single_controller_ctx_to_hw)( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); bool (*is_dp_dig_pixel_rate_div_policy)(struct pipe_ctx *pipe_ctx); -#endif + void (*reset_back_end_for_pipe)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context); }; struct dce_hwseq { diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index f74ae0d41d3c49cf215d615f336339b773cbbcbc..ebb659c327e06f7a3baf6e975b7f745536441920 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -333,6 +333,8 @@ struct stream_resource { uint8_t gsl_group; struct test_pattern_params test_pattern_params; + + bool left_edge_extra_pixel; }; struct plane_resource { @@ -469,6 +471,8 @@ struct resource_context { unsigned int hpo_dp_link_enc_to_link_idx[MAX_HPO_DP2_LINK_ENCODERS]; int hpo_dp_link_enc_ref_cnts[MAX_HPO_DP2_LINK_ENCODERS]; bool is_mpc_3dlut_acquired[MAX_PIPES]; + /* solely used for build scalar data in dml2 */ + struct pipe_ctx temp_pipe; }; struct dce_bw_output { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/audio.h b/drivers/gpu/drm/amd/display/dc/inc/hw/audio.h index 6ed1fb8c930009a95842355af2181e8413999e6e..b6203253111cab1b573300f42ede8788e63ef658 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/audio.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/audio.h @@ -43,7 +43,8 @@ struct audio_funcs { void (*az_configure)(struct audio *audio, enum signal_type signal, const struct audio_crtc_info *crtc_info, - const struct audio_info *audio_info); + const struct audio_info *audio_info, + const struct audio_dp_link_info *dp_link_info); void (*wall_dto_setup)(struct audio *audio, enum signal_type signal, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h index 6f4c97543c145fd75c9fbdccbd681dd4c14ad727..f4d4a68c91dc7d8bff2db9aff6c6429691081e2b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h @@ -356,6 +356,7 @@ struct clk_mgr_internal { long long wm_range_table_addr; bool dpm_present; + bool pme_trigger_pending; }; struct clk_mgr_internal_funcs { @@ -393,6 +394,11 @@ static inline int khz_to_mhz_ceil(int khz) return (khz + 999) / 1000; } +static inline int khz_to_mhz_floor(int khz) +{ + return khz / 1000; +} + int clk_mgr_helper_get_active_display_cnt( struct dc *dc, struct dc_state *context); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index 901891316dfbf16fc3b1b598ad906e9ad8465c5f..2ae7484d18afb0f6f705015f2b81dc7c6b67d256 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -26,6 +26,12 @@ #ifndef __DAL_DCHUBBUB_H__ #define __DAL_DCHUBBUB_H__ +/** + * DOC: overview + * + * There is only one common DCHUBBUB. It contains the common request and return + * blocks for the Data Fabric Interface that are not clock/power gated. + */ enum dcc_control { dcc_control__256_256_xxx, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index f4aa76e02518549bafbf9965164c13aab32d0618..0f24afbf43883b39ff9aad7a1f273b6381a3971c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -27,6 +27,31 @@ #ifndef __DAL_DPP_H__ #define __DAL_DPP_H__ +/** + * DOC: overview + * + * The DPP (Display Pipe and Plane) block is the unified display data + * processing engine in DCN for processing graphic or video data on per DPP + * rectangle base. This rectangle can be a part of SLS (Single Large Surface), + * or a layer to be blended with other DPP, or a rectangle associated with a + * display tile. + * + * It provides various functions including: + * - graphic color keyer + * - graphic cursor compositing + * - graphic or video image source to destination scaling + * - image sharping + * - video format conversion from 4:2:0 or 4:2:2 to 4:4:4 + * - Color Space Conversion + * - Host LUT gamma adjustment + * - Color Gamut Remap + * - brightness and contrast adjustment. + * + * DPP pipe consists of Converter and Cursor (CNVC), Scaler (DSCL), Color + * Management (CM), Output Buffer (OBUF) and Digital Bypass (DPB) module + * connected in a video/graphics pipeline. + */ + #include "transform.h" #include "cursor_reg_cache.h" @@ -141,6 +166,7 @@ struct dcn_dpp_state { uint32_t igam_input_format; uint32_t dgam_lut_mode; uint32_t rgam_lut_mode; + // gamut_remap data for dcn10_get_cm_states() uint32_t gamut_remap_mode; uint32_t gamut_remap_c11_c12; uint32_t gamut_remap_c13_c14; @@ -148,6 +174,16 @@ struct dcn_dpp_state { uint32_t gamut_remap_c23_c24; uint32_t gamut_remap_c31_c32; uint32_t gamut_remap_c33_c34; + // gamut_remap data for dcn*_log_color_state() + struct dpp_grph_csc_adjustment gamut_remap; + uint32_t shaper_lut_mode; + uint32_t lut3d_mode; + uint32_t lut3d_bit_depth; + uint32_t lut3d_size; + uint32_t blnd_lut_mode; + uint32_t pre_dgam_mode; + uint32_t pre_dgam_select; + uint32_t gamcor_mode; }; struct CM_bias_params { @@ -290,6 +326,9 @@ struct dpp_funcs { void (*dpp_cnv_set_alpha_keyer)( struct dpp *dpp_base, struct cnv_color_keyer_params *color_keyer); + + void (*dpp_get_gamut_remap)(struct dpp *dpp_base, + struct dpp_grph_csc_adjustment *adjust); }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index 7f3f9b69e903a186fcc864963ece237403d3e88a..72610cd7eae0befbd83a05e385e4a9e5fcb32ef4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -26,13 +26,24 @@ #ifndef __DAL_HUBP_H__ #define __DAL_HUBP_H__ +/** + * DOC: overview + * + * Display Controller Hub (DCHUB) is the gateway between the Scalable Data Port + * (SDP) and DCN. This component has multiple features, such as memory + * arbitration, rotation, and cursor manipulation. + * + * There is one HUBP allocated per pipe, which fetches data and converts + * different pixel formats (i.e. ARGB8888, NV12, etc) into linear, interleaved + * and fixed-depth streams of pixel data. + */ + #include "mem_input.h" #include "cursor_reg_cache.h" #define OPP_ID_INVALID 0xf #define MAX_TTU 0xffffff - enum cursor_pitch { CURSOR_PITCH_64_PIXELS = 0, CURSOR_PITCH_128_PIXELS, @@ -146,9 +157,7 @@ struct hubp_funcs { void (*set_blank)(struct hubp *hubp, bool blank); void (*set_blank_regs)(struct hubp *hubp, bool blank); -#ifdef CONFIG_DRM_AMD_DC_FP void (*phantom_hubp_post_enable)(struct hubp *hubp); -#endif void (*set_hubp_blank_en)(struct hubp *hubp, bool blank); void (*set_cursor_attributes)( diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h index 61a2406dcc53937ff38ce7996c761a1c82cb9deb..ba9b942ce09f9ade4e705a86631159b2190f4413 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h @@ -23,13 +23,28 @@ */ /** - * DOC: mpc-overview + * DOC: overview * - * Multiple Pipe/Plane Combined (MPC) is a component in the hardware pipeline + * Multiple Pipe/Plane Combiner (MPC) is a component in the hardware pipeline * that performs blending of multiple planes, using global and per-pixel alpha. * It also performs post-blending color correction operations according to the * hardware capabilities, such as color transformation matrix and gamma 1D and * 3D LUT. + * + * MPC receives output from all DPP pipes and combines them to multiple outputs + * supporting "M MPC inputs -> N MPC outputs" flexible composition + * architecture. It features: + * + * - Programmable blending structure to allow software controlled blending and + * cascading; + * - Programmable window location of each DPP in active region of display; + * - Combining multiple DPP pipes in one active region when a single DPP pipe + * cannot process very large surface; + * - Combining multiple DPP from different SLS with blending; + * - Stereo formats from single DPP in top-bottom or side-by-side modes; + * - Stereo formats from 2 DPPs; + * - Alpha blending of multiple layers from different DPP pipes; + * - Programmable background color; */ #ifndef __DC_MPCC_H__ @@ -83,34 +98,66 @@ enum mpcc_alpha_blend_mode { /** * struct mpcc_blnd_cfg - MPCC blending configuration - * - * @black_color: background color - * @alpha_mode: alpha blend mode (MPCC_ALPHA_BLND_MODE) - * @pre_multiplied_alpha: whether pixel color values were pre-multiplied by the - * alpha channel (MPCC_ALPHA_MULTIPLIED_MODE) - * @global_gain: used when blend mode considers both pixel alpha and plane - * alpha value and assumes the global alpha value. - * @global_alpha: plane alpha value - * @overlap_only: whether overlapping of different planes is allowed - * @bottom_gain_mode: blend mode for bottom gain setting - * @background_color_bpc: background color for bpc - * @top_gain: top gain setting - * @bottom_inside_gain: blend mode for bottom inside - * @bottom_outside_gain: blend mode for bottom outside */ struct mpcc_blnd_cfg { - struct tg_color black_color; /* background color */ - enum mpcc_alpha_blend_mode alpha_mode; /* alpha blend mode */ - bool pre_multiplied_alpha; /* alpha pre-multiplied mode flag */ + /** + * @black_color: background color. + */ + struct tg_color black_color; + + /** + * @alpha_mode: alpha blend mode (MPCC_ALPHA_BLND_MODE). + */ + enum mpcc_alpha_blend_mode alpha_mode; + + /*** + * @@pre_multiplied_alpha: + * + * Whether pixel color values were pre-multiplied by the alpha channel + * (MPCC_ALPHA_MULTIPLIED_MODE). + */ + bool pre_multiplied_alpha; + + /** + * @global_gain: Used when blend mode considers both pixel alpha and plane. + */ int global_gain; + + /** + * @global_alpha: Plane alpha value. + */ int global_alpha; + + /** + * @@overlap_only: Whether overlapping of different planes is allowed. + */ bool overlap_only; /* MPCC top/bottom gain settings */ + + /** + * @bottom_gain_mode: Blend mode for bottom gain setting. + */ int bottom_gain_mode; + + /** + * @background_color_bpc: Background color for bpc. + */ int background_color_bpc; + + /** + * @top_gain: Top gain setting. + */ int top_gain; + + /** + * @bottom_inside_gain: Blend mode for bottom inside. + */ int bottom_inside_gain; + + /** + * @bottom_outside_gain: Blend mode for bottom outside. + */ int bottom_outside_gain; }; @@ -150,34 +197,58 @@ struct mpc_dwb_flow_control { /** * struct mpcc - MPCC connection and blending configuration for a single MPCC instance. - * @mpcc_id: MPCC physical instance - * @dpp_id: DPP input to this MPCC - * @mpcc_bot: pointer to bottom layer MPCC. NULL when not connected. - * @blnd_cfg: the blending configuration for this MPCC - * @sm_cfg: stereo mix setting for this MPCC - * @shared_bottom: if MPCC output to both OPP and DWB endpoints, true. Otherwise, false. * * This struct is used as a node in an MPC tree. */ struct mpcc { - int mpcc_id; /* MPCC physical instance */ - int dpp_id; /* DPP input to this MPCC */ - struct mpcc *mpcc_bot; /* pointer to bottom layer MPCC. NULL when not connected */ - struct mpcc_blnd_cfg blnd_cfg; /* The blending configuration for this MPCC */ - struct mpcc_sm_cfg sm_cfg; /* stereo mix setting for this MPCC */ - bool shared_bottom; /* TRUE if MPCC output to both OPP and DWB endpoints, else FALSE */ + /** + * @mpcc_id: MPCC physical instance. + */ + int mpcc_id; + + /** + * @dpp_id: DPP input to this MPCC + */ + int dpp_id; + + /** + * @mpcc_bot: Pointer to bottom layer MPCC. NULL when not connected. + */ + struct mpcc *mpcc_bot; + + /** + * @blnd_cfg: The blending configuration for this MPCC. + */ + struct mpcc_blnd_cfg blnd_cfg; + + /** + * @sm_cfg: stereo mix setting for this MPCC + */ + struct mpcc_sm_cfg sm_cfg; + + /** + * @shared_bottom: + * + * If MPCC output to both OPP and DWB endpoints, true. Otherwise, false. + */ + bool shared_bottom; }; /** * struct mpc_tree - MPC tree represents all MPCC connections for a pipe. * - * @opp_id: the OPP instance that owns this MPC tree - * @opp_list: the top MPCC layer of the MPC tree that outputs to OPP endpoint * */ struct mpc_tree { - int opp_id; /* The OPP instance that owns this MPC tree */ - struct mpcc *opp_list; /* The top MPCC layer of the MPC tree that outputs to OPP endpoint */ + /** + * @opp_id: The OPP instance that owns this MPC tree. + */ + int opp_id; + + /** + * @opp_list: the top MPCC layer of the MPC tree that outputs to OPP endpoint + */ + struct mpcc *opp_list; }; struct mpc { @@ -199,6 +270,13 @@ struct mpcc_state { uint32_t overlap_only; uint32_t idle; uint32_t busy; + uint32_t shaper_lut_mode; + uint32_t lut3d_mode; + uint32_t lut3d_bit_depth; + uint32_t lut3d_size; + uint32_t rgam_mode; + uint32_t rgam_lut; + struct mpc_grph_gamut_adjustment gamut_remap; }; /** @@ -217,16 +295,20 @@ struct mpc_funcs { * Only used for planes that are part of blending chain for OPP output * * Parameters: - * [in/out] mpc - MPC context. - * [in/out] tree - MPC tree structure that plane will be added to. - * [in] blnd_cfg - MPCC blending configuration for the new blending layer. - * [in] sm_cfg - MPCC stereo mix configuration for the new blending layer. - * stereo mix must disable for the very bottom layer of the tree config. - * [in] insert_above_mpcc - Insert new plane above this MPCC. If NULL, insert as bottom plane. - * [in] dpp_id - DPP instance for the plane to be added. - * [in] mpcc_id - The MPCC physical instance to use for blending. - * - * Return: struct mpcc* - MPCC that was added. + * + * - [in/out] mpc - MPC context. + * - [in/out] tree - MPC tree structure that plane will be added to. + * - [in] blnd_cfg - MPCC blending configuration for the new blending layer. + * - [in] sm_cfg - MPCC stereo mix configuration for the new blending layer. + * stereo mix must disable for the very bottom layer of the tree config. + * - [in] insert_above_mpcc - Insert new plane above this MPCC. + * If NULL, insert as bottom plane. + * - [in] dpp_id - DPP instance for the plane to be added. + * - [in] mpcc_id - The MPCC physical instance to use for blending. + * + * Return: + * + * struct mpcc* - MPCC that was added. */ struct mpcc* (*insert_plane)( struct mpc *mpc, @@ -243,11 +325,14 @@ struct mpc_funcs { * Remove a specified MPCC from the MPC tree. * * Parameters: - * [in/out] mpc - MPC context. - * [in/out] tree - MPC tree structure that plane will be removed from. - * [in/out] mpcc - MPCC to be removed from tree. * - * Return: void + * - [in/out] mpc - MPC context. + * - [in/out] tree - MPC tree structure that plane will be removed from. + * - [in/out] mpcc - MPCC to be removed from tree. + * + * Return: + * + * void */ void (*remove_mpcc)( struct mpc *mpc, @@ -260,9 +345,12 @@ struct mpc_funcs { * Reset the MPCC HW status by disconnecting all muxes. * * Parameters: - * [in/out] mpc - MPC context. * - * Return: void + * - [in/out] mpc - MPC context. + * + * Return: + * + * void */ void (*mpc_init)(struct mpc *mpc); void (*mpc_init_single_inst)( @@ -275,11 +363,14 @@ struct mpc_funcs { * Update the blending configuration for a specified MPCC. * * Parameters: - * [in/out] mpc - MPC context. - * [in] blnd_cfg - MPCC blending configuration. - * [in] mpcc_id - The MPCC physical instance. * - * Return: void + * - [in/out] mpc - MPC context. + * - [in] blnd_cfg - MPCC blending configuration. + * - [in] mpcc_id - The MPCC physical instance. + * + * Return: + * + * void */ void (*update_blending)( struct mpc *mpc, @@ -289,15 +380,18 @@ struct mpc_funcs { /** * @cursor_lock: * - * Lock cursor updates for the specified OPP. - * OPP defines the set of MPCC that are locked together for cursor. + * Lock cursor updates for the specified OPP. OPP defines the set of + * MPCC that are locked together for cursor. * * Parameters: - * [in] mpc - MPC context. - * [in] opp_id - The OPP to lock cursor updates on - * [in] lock - lock/unlock the OPP * - * Return: void + * - [in] mpc - MPC context. + * - [in] opp_id - The OPP to lock cursor updates on + * - [in] lock - lock/unlock the OPP + * + * Return: + * + * void */ void (*cursor_lock)( struct mpc *mpc, @@ -307,20 +401,25 @@ struct mpc_funcs { /** * @insert_plane_to_secondary: * - * Add DPP into secondary MPC tree based on specified blending position. - * Only used for planes that are part of blending chain for DWB output + * Add DPP into secondary MPC tree based on specified blending + * position. Only used for planes that are part of blending chain for + * DWB output * * Parameters: - * [in/out] mpc - MPC context. - * [in/out] tree - MPC tree structure that plane will be added to. - * [in] blnd_cfg - MPCC blending configuration for the new blending layer. - * [in] sm_cfg - MPCC stereo mix configuration for the new blending layer. - * stereo mix must disable for the very bottom layer of the tree config. - * [in] insert_above_mpcc - Insert new plane above this MPCC. If NULL, insert as bottom plane. - * [in] dpp_id - DPP instance for the plane to be added. - * [in] mpcc_id - The MPCC physical instance to use for blending. - * - * Return: struct mpcc* - MPCC that was added. + * + * - [in/out] mpc - MPC context. + * - [in/out] tree - MPC tree structure that plane will be added to. + * - [in] blnd_cfg - MPCC blending configuration for the new blending layer. + * - [in] sm_cfg - MPCC stereo mix configuration for the new blending layer. + * stereo mix must disable for the very bottom layer of the tree config. + * - [in] insert_above_mpcc - Insert new plane above this MPCC. If + * NULL, insert as bottom plane. + * - [in] dpp_id - DPP instance for the plane to be added. + * - [in] mpcc_id - The MPCC physical instance to use for blending. + * + * Return: + * + * struct mpcc* - MPCC that was added. */ struct mpcc* (*insert_plane_to_secondary)( struct mpc *mpc, @@ -337,10 +436,14 @@ struct mpc_funcs { * Remove a specified DPP from the 'secondary' MPC tree. * * Parameters: - * [in/out] mpc - MPC context. - * [in/out] tree - MPC tree structure that plane will be removed from. - * [in] mpcc - MPCC to be removed from tree. - * Return: void + * + * - [in/out] mpc - MPC context. + * - [in/out] tree - MPC tree structure that plane will be removed from. + * - [in] mpcc - MPCC to be removed from tree. + * + * Return: + * + * void */ void (*remove_mpcc_from_secondary)( struct mpc *mpc, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h index 7617fabbd16ee64a82a26e1a1664b1f428f0bbdb..aee5372e292c5a691c9b6f2d8a45ef31e823889d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h @@ -23,6 +23,22 @@ * */ +/** + * DOC: overview + * + * The Output Plane Processor (OPP) block groups have functions that format + * pixel streams such that they are suitable for display at the display device. + * The key functions contained in the OPP are: + * + * - Adaptive Backlight Modulation (ABM) + * - Formatter (FMT) which provide pixel-by-pixel operations for format the + * incoming pixel stream. + * - Output Buffer that provide pixel replication, and overlapping. + * - Interface between MPC and OPTC. + * - Clock and reset generation. + * - CRC generation. + */ + #ifndef __DAL_OPP_H__ #define __DAL_OPP_H__ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 9a00a99317b298c0b7e148acebb032c518c6f310..d98d72f35be5bd3eb28f8db759c6f8848bf5fa85 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -182,9 +182,7 @@ struct timing_generator_funcs { bool (*enable_crtc)(struct timing_generator *tg); bool (*disable_crtc)(struct timing_generator *tg); -#ifdef CONFIG_DRM_AMD_DC_FP void (*phantom_crtc_post_enable)(struct timing_generator *tg); -#endif void (*disable_phantom_crtc)(struct timing_generator *tg); bool (*immediate_disable_crtc)(struct timing_generator *tg); bool (*is_counter_moving)(struct timing_generator *tg); diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index c958ef37b78a667b1bb9bfb26827ae3e45053715..b14d52e52fa2f43c2f7fa46891513de0675c8180 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -107,6 +107,10 @@ void resource_build_test_pattern_params( struct resource_context *res_ctx, struct pipe_ctx *pipe_ctx); +void resource_build_subsampling_params( + struct resource_context *res_ctx, + struct pipe_ctx *pipe_ctx); + bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx); enum dc_status resource_build_scaling_params_for_context( @@ -427,22 +431,18 @@ struct pipe_ctx *resource_get_primary_dpp_pipe(const struct pipe_ctx *dpp_pipe); int resource_get_mpc_slice_index(const struct pipe_ctx *dpp_pipe); /* - * Get number of MPC "cuts" of the plane associated with the pipe. MPC slice - * count is equal to MPC splits + 1. For example if a plane is cut 3 times, it - * will have 4 pieces of slice. - * return - 0 if pipe is not used for a plane with MPCC combine. otherwise - * the number of MPC "cuts" for the plane. + * Get the number of MPC slices associated with the pipe. + * The function returns 0 if the pipe is not associated with an MPC combine + * pipe topology. */ -int resource_get_mpc_slice_count(const struct pipe_ctx *opp_head); +int resource_get_mpc_slice_count(const struct pipe_ctx *pipe); /* - * Get number of ODM "cuts" of the timing associated with the pipe. ODM slice - * count is equal to ODM splits + 1. For example if a timing is cut 3 times, it - * will have 4 pieces of slice. - * return - 0 if pipe is not used for ODM combine. otherwise - * the number of ODM "cuts" for the timing. + * Get the number of ODM slices associated with the pipe. + * The function returns 0 if the pipe is not associated with an ODM combine + * pipe topology. */ -int resource_get_odm_slice_count(const struct pipe_ctx *otg_master); +int resource_get_odm_slice_count(const struct pipe_ctx *pipe); /* Get the ODM slice index counting from 0 from left most slice */ int resource_get_odm_slice_index(const struct pipe_ctx *opp_head); diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h index f4633d3cf9b98ecf77e4572be64b397d6c311881..a1f72fe378ee4824dd940f2c88565eda1330237f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h +++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h @@ -22,6 +22,16 @@ * Authors: AMD * */ + +/** + * DOC: overview + * + * Display Input Output (DIO), is the display input and output unit in DCN. It + * includes output encoders to support different display output, like + * DisplayPort, HDMI, DVI interface, and others. It also includes the control + * and status channels for these interfaces. + */ + #ifndef __LINK_HWSS_DIO_H__ #define __LINK_HWSS_DIO_H__ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index 24153b0df503dd77a672526ac911947ac272e789..b8c4a04dd175789e92a4076ba5eb82a6aae573c4 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -41,6 +41,7 @@ #include "protocols/link_dp_dpia.h" #include "protocols/link_dp_phy.h" #include "protocols/link_dp_training.h" +#include "protocols/link_dp_dpia_bw.h" #include "accessories/link_dp_trace.h" #include "link_enc_cfg.h" @@ -991,6 +992,23 @@ static bool detect_link_and_local_sink(struct dc_link *link, if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->reported_link_cap.link_rate > LINK_RATE_HIGH3) link->reported_link_cap.link_rate = LINK_RATE_HIGH3; + + /* + * If this is DP over USB4 link then we need to: + * - Enable BW ALLOC support on DPtx if applicable + */ + if (dc->config.usb4_bw_alloc_support) { + if (link_dp_dpia_set_dptx_usb4_bw_alloc_support(link)) { + /* update with non reduced link cap if bw allocation mode is supported */ + if (link->dpia_bw_alloc_config.nrd_max_link_rate && + link->dpia_bw_alloc_config.nrd_max_lane_count) { + link->reported_link_cap.link_rate = + link->dpia_bw_alloc_config.nrd_max_link_rate; + link->reported_link_cap.lane_count = + link->dpia_bw_alloc_config.nrd_max_lane_count; + } + } + } break; } diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 3cbfbf8d107e9b62c639ef1618041b8fc09dd9b5..a72de44a5747a446e655536747c40135df2a686a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -2197,6 +2197,64 @@ static enum dc_status enable_link( static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, int bw) { + struct dc_link *link = stream->sink->link; + int req_bw = bw; + + DC_LOGGER_INIT(link->ctx->logger); + + if (!link->dpia_bw_alloc_config.bw_alloc_enabled) + return false; + + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + int sink_index = 0; + int i = 0; + + for (i = 0; i < link->sink_count; i++) { + if (link->remote_sinks[i] == NULL) + continue; + + if (stream->sink->sink_id != link->remote_sinks[i]->sink_id) + req_bw += link->dpia_bw_alloc_config.remote_sink_req_bw[i]; + else + sink_index = i; + } + + link->dpia_bw_alloc_config.remote_sink_req_bw[sink_index] = bw; + } + + /* get dp overhead for dp tunneling */ + link->dpia_bw_alloc_config.dp_overhead = link_dp_dpia_get_dp_overhead_in_dp_tunneling(link); + req_bw += link->dpia_bw_alloc_config.dp_overhead; + + if (link_dp_dpia_allocate_usb4_bandwidth_for_stream(link, req_bw)) { + if (req_bw <= link->dpia_bw_alloc_config.allocated_bw) { + DC_LOG_DEBUG("%s, Success in allocate bw for link(%d), allocated_bw(%d), dp_overhead(%d)\n", + __func__, link->link_index, link->dpia_bw_alloc_config.allocated_bw, + link->dpia_bw_alloc_config.dp_overhead); + } else { + // Cannot get the required bandwidth. + DC_LOG_ERROR("%s, Failed to allocate bw for link(%d), allocated_bw(%d), dp_overhead(%d)\n", + __func__, link->link_index, link->dpia_bw_alloc_config.allocated_bw, + link->dpia_bw_alloc_config.dp_overhead); + return false; + } + } else { + DC_LOG_DEBUG("%s, usb4 request bw timeout\n", __func__); + return false; + } + + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + int i = 0; + + for (i = 0; i < link->sink_count; i++) { + if (link->remote_sinks[i] == NULL) + continue; + DC_LOG_DEBUG("%s, remote_sink=%s, request_bw=%d\n", __func__, + (const char *)(&link->remote_sinks[i]->edid_caps.display_name[0]), + link->dpia_bw_alloc_config.remote_sink_req_bw[i]); + } + } + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c b/drivers/gpu/drm/amd/display/dc/link/link_validation.c index 8fe66c3678508d9aee6779fa25cd6128e1f30832..1c038e2a527b36e9a0f00bdb703290eae431753a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_validation.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c @@ -125,11 +125,9 @@ static bool dp_active_dongle_validate_timing( if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter struct dc_crtc_timing outputTiming = *timing; -#if defined(CONFIG_DRM_AMD_DC_FP) if (timing->flags.DSC && !timing->dsc_cfg.is_frl) /* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */ outputTiming.flags.DSC = 0; -#endif if (dc_bandwidth_in_kbps_from_timing(&outputTiming, DC_LINK_ENCODING_HDMI_FRL) > dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps) return false; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c index dd0d2b206462c927c5f68b355498e71250c154b9..5491b707cec881b9854ab96834503c1e88053380 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c @@ -196,7 +196,7 @@ static int get_host_router_total_dp_tunnel_bw(const struct dc *dc, uint8_t hr_in struct dc_link *link_dpia_primary, *link_dpia_secondary; int total_bw = 0; - for (uint8_t i = 0; i < MAX_PIPES * 2; ++i) { + for (uint8_t i = 0; i < (MAX_PIPES * 2) - 1; ++i) { if (!dc->links[i] || dc->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) continue; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c index 5a0b0451895690d184ec00c56873f0d1acad6864..e06d3c2d891023f323b4136306bf0d8c0ee4f76f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c @@ -1505,10 +1505,7 @@ enum link_training_result dp_perform_link_training( * Non-LT AUX transactions inside training mode. */ if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING) - if (link->dc->config.use_old_fixed_vs_sequence) - status = dp_perform_fixed_vs_pe_training_sequence_legacy(link, link_res, <_settings); - else - status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); + status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); else if (encoding == DP_8b_10b_ENCODING) status = dp_perform_8b_10b_link_training(link, link_res, <_settings); else if (encoding == DP_128b_132b_ENCODING) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c index 7087cdc9e9775c4ad953d3db6eafba6ea12e72b0..b5cf75975fffd64774aa9ee8ed64ba44e50deb6e 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c @@ -186,356 +186,6 @@ static enum link_training_result perform_fixed_vs_pe_nontransparent_training_seq return status; } - -enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings) -{ - const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; - const uint8_t offset = dp_parse_lttpr_repeater_count( - link->dpcd_caps.lttpr_caps.phy_repeater_cnt); - const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; - const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68}; - uint32_t pre_disable_intercept_delay_ms = 0; - uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; - uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; - const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19}; - const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01}; - const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18}; - const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03}; - const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06}; - const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87}; - enum link_training_result status = LINK_TRAINING_SUCCESS; - uint8_t lane = 0; - union down_spread_ctrl downspread = {0}; - union lane_count_set lane_count_set = {0}; - uint8_t toggle_rate; - uint8_t rate; - - /* Only 8b/10b is supported */ - ASSERT(link_dp_get_encoding_format(<_settings->link_settings) == - DP_8b_10b_ENCODING); - - if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { - status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); - return status; - } - - if (offset != 0xFF) { - if (offset == 2) { - pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; - - /* Certain display and cable configuration require extra delay */ - } else if (offset > 2) { - pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; - } - } - - /* Vendor specific: Reset lane settings */ - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset)); - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); - - /* Vendor specific: Enable intercept */ - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en)); - - - /* 1. set link rate, lane count and spread. */ - - downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); - - lane_count_set.bits.LANE_COUNT_SET = - lt_settings->link_settings.lane_count; - - lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; - lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; - - - if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { - lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = - link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; - } - - core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, - &downspread.raw, sizeof(downspread)); - - core_link_write_dpcd(link, DP_LANE_COUNT_SET, - &lane_count_set.raw, 1); - - rate = get_dpcd_link_rate(<_settings->link_settings); - - /* Vendor specific: Toggle link rate */ - toggle_rate = (rate == 0x6) ? 0xA : 0x6; - - if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { - core_link_write_dpcd( - link, - DP_LINK_BW_SET, - &toggle_rate, - 1); - } - - link->vendor_specific_lttpr_link_rate_wa = rate; - - core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); - - DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", - __func__, - DP_LINK_BW_SET, - lt_settings->link_settings.link_rate, - DP_LANE_COUNT_SET, - lt_settings->link_settings.lane_count, - lt_settings->enhanced_framing, - DP_DOWNSPREAD_CTRL, - lt_settings->link_settings.link_spread); - - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_dpmf[0], - sizeof(vendor_lttpr_write_data_dpmf)); - - if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) { - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1)); - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2)); - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3)); - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4)); - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5)); - } - - /* 2. Perform link training */ - - /* Perform Clock Recovery Sequence */ - if (status == LINK_TRAINING_SUCCESS) { - const uint8_t max_vendor_dpcd_retries = 10; - uint32_t retries_cr; - uint32_t retry_count; - uint32_t wait_time_microsec; - enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; - union lane_align_status_updated dpcd_lane_status_updated; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - uint8_t i = 0; - - retries_cr = 0; - retry_count = 0; - - memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); - memset(&dpcd_lane_status_updated, '\0', - sizeof(dpcd_lane_status_updated)); - - while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && - (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { - - - /* 1. call HWSS to set lane settings */ - dp_set_hw_lane_settings( - link, - link_res, - lt_settings, - 0); - - /* 2. update DPCD of the receiver */ - if (!retry_count) { - /* EPR #361076 - write as a 5-byte burst, - * but only for the 1-st iteration. - */ - dpcd_set_lt_pattern_and_lane_settings( - link, - lt_settings, - lt_settings->pattern_for_cr, - 0); - /* Vendor specific: Disable intercept */ - for (i = 0; i < max_vendor_dpcd_retries; i++) { - if (pre_disable_intercept_delay_ms != 0) - msleep(pre_disable_intercept_delay_ms); - if (link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_intercept_dis[0], - sizeof(vendor_lttpr_write_data_intercept_dis))) - break; - - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_intercept_en[0], - sizeof(vendor_lttpr_write_data_intercept_en)); - } - } else { - vendor_lttpr_write_data_vs[3] = 0; - vendor_lttpr_write_data_pe[3] = 0; - - for (lane = 0; lane < lane_count; lane++) { - vendor_lttpr_write_data_vs[3] |= - lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); - vendor_lttpr_write_data_pe[3] |= - lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); - } - - /* Vendor specific: Update VS and PE to DPRX requested value */ - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); - - dpcd_set_lane_settings( - link, - lt_settings, - 0); - } - - /* 3. wait receiver to lock-on*/ - wait_time_microsec = lt_settings->cr_pattern_time; - - dp_wait_for_training_aux_rd_interval( - link, - wait_time_microsec); - - /* 4. Read lane status and requested drive - * settings as set by the sink - */ - dp_get_lane_status_and_lane_adjust( - link, - lt_settings, - dpcd_lane_status, - &dpcd_lane_status_updated, - dpcd_lane_adjust, - 0); - - /* 5. check CR done*/ - if (dp_is_cr_done(lane_count, dpcd_lane_status)) { - status = LINK_TRAINING_SUCCESS; - break; - } - - /* 6. max VS reached*/ - if (dp_is_max_vs_reached(lt_settings)) - break; - - /* 7. same lane settings */ - /* Note: settings are the same for all lanes, - * so comparing first lane is sufficient - */ - if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == - dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) - retries_cr++; - else - retries_cr = 0; - - /* 8. update VS/PE/PC2 in lt_settings*/ - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - retry_count++; - } - - if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { - ASSERT(0); - DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", - __func__, - LINK_TRAINING_MAX_CR_RETRY); - - } - - status = dp_get_cr_failure(lane_count, dpcd_lane_status); - } - - /* Perform Channel EQ Sequence */ - if (status == LINK_TRAINING_SUCCESS) { - enum dc_dp_training_pattern tr_pattern; - uint32_t retries_ch_eq; - uint32_t wait_time_microsec; - enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; - union lane_align_status_updated dpcd_lane_status_updated = {0}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; - - /* Note: also check that TPS4 is a supported feature*/ - tr_pattern = lt_settings->pattern_for_eq; - - dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); - - status = LINK_TRAINING_EQ_FAIL_EQ; - - for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; - retries_ch_eq++) { - - dp_set_hw_lane_settings(link, link_res, lt_settings, 0); - - vendor_lttpr_write_data_vs[3] = 0; - vendor_lttpr_write_data_pe[3] = 0; - - for (lane = 0; lane < lane_count; lane++) { - vendor_lttpr_write_data_vs[3] |= - lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); - vendor_lttpr_write_data_pe[3] |= - lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); - } - - /* Vendor specific: Update VS and PE to DPRX requested value */ - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs)); - link_configure_fixed_vs_pe_retimer(link->ddc, - &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe)); - - /* 2. update DPCD*/ - if (!retries_ch_eq) - /* EPR #361076 - write as a 5-byte burst, - * but only for the 1-st iteration - */ - - dpcd_set_lt_pattern_and_lane_settings( - link, - lt_settings, - tr_pattern, 0); - else - dpcd_set_lane_settings(link, lt_settings, 0); - - /* 3. wait for receiver to lock-on*/ - wait_time_microsec = lt_settings->eq_pattern_time; - - dp_wait_for_training_aux_rd_interval( - link, - wait_time_microsec); - - /* 4. Read lane status and requested - * drive settings as set by the sink - */ - dp_get_lane_status_and_lane_adjust( - link, - lt_settings, - dpcd_lane_status, - &dpcd_lane_status_updated, - dpcd_lane_adjust, - 0); - - /* 5. check CR done*/ - if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { - status = LINK_TRAINING_EQ_FAIL_CR; - break; - } - - /* 6. check CHEQ done*/ - if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && - dp_is_symbol_locked(lane_count, dpcd_lane_status) && - dp_is_interlane_aligned(dpcd_lane_status_updated)) { - status = LINK_TRAINING_SUCCESS; - break; - } - - /* 7. update VS/PE/PC2 in lt_settings*/ - dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, - lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - } - } - - return status; -} - enum link_training_result dp_perform_fixed_vs_pe_training_sequence( struct dc_link *link, const struct link_resource *link_res, @@ -620,18 +270,20 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( rate = get_dpcd_link_rate(<_settings->link_settings); - /* Vendor specific: Toggle link rate */ - toggle_rate = (rate == 0x6) ? 0xA : 0x6; + if (!link->dpcd_caps.lttpr_caps.main_link_channel_coding.bits.DP_128b_132b_SUPPORTED) { + /* Vendor specific: Toggle link rate */ + toggle_rate = (rate == 0x6) ? 0xA : 0x6; - if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { - core_link_write_dpcd( - link, - DP_LINK_BW_SET, - &toggle_rate, - 1); - } + if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { + core_link_write_dpcd( + link, + DP_LINK_BW_SET, + &toggle_rate, + 1); + } - link->vendor_specific_lttpr_link_rate_wa = rate; + link->vendor_specific_lttpr_link_rate_wa = rate; + } core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h index c0d6ea329504ffeea503cf5a72193b05375040bc..e61970e27661d97c8dcec49c41e3d1e5d2a13223 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h @@ -28,11 +28,6 @@ #define __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ #include "link_dp_training.h" -enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( - struct dc_link *link, - const struct link_resource *link_res, - struct link_training_settings *lt_settings); - enum link_training_result dp_perform_fixed_vs_pe_training_sequence( struct dc_link *link, const struct link_resource *link_res, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c index 5c9a30211c109f749ab7e1cceb402bd7a0dcb786..fc50931c2aecbb53d74a2d48913e608134510940 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c @@ -205,7 +205,7 @@ enum dc_status core_link_read_dpcd( uint32_t extended_size; /* size of the remaining partitioned address space */ uint32_t size_left_to_read; - enum dc_status status; + enum dc_status status = DC_ERROR_UNEXPECTED; /* size of the next partition to be read from */ uint32_t partition_size; uint32_t data_index = 0; @@ -234,7 +234,7 @@ enum dc_status core_link_write_dpcd( { uint32_t partition_size; uint32_t data_index = 0; - enum dc_status status; + enum dc_status status = DC_ERROR_UNEXPECTED; while (size) { partition_size = dpcd_get_next_partition_size(address, size); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index 046d3e205415311cd63a98aa3c0e59c8aaea2e89..443215b963089be5cbadd361599d1f8090aa192b 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -287,7 +287,7 @@ bool set_default_brightness_aux(struct dc_link *link) if (link && link->dpcd_sink_ext_caps.bits.oled == 1) { if (!read_default_bl_aux(link, &default_backlight)) default_backlight = 150000; - // if < 1 nits or > 5000, it might be wrong readback + // if > 5000, it might be wrong readback. 0 nits is a valid default value for OLED panel. if (default_backlight < 1000 || default_backlight > 5000000) default_backlight = 150000; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c index 37a64186f3241a456c4eeea6038cc311fca0de43..ecc477ef8e3b78e1705b8546ac17e1d8490982f7 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -2169,6 +2169,17 @@ void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params optimal_uclk_for_dcfclk_sta_targets[i] = bw_params->clk_table.entries[j].memclk_mhz * 16; break; + } else { + /* condition where (dcfclk_sta_targets[i] >= optimal_dcfclk_for_uclk[j]): + * If it just so happens that the memory bandwidth is low enough such that + * all the optimal DCFCLK for each UCLK is lower than the smallest DCFCLK STA + * target, we need to populate the optimal UCLK for each DCFCLK STA target to + * be the max UCLK. + */ + if (j == num_uclk_states - 1) { + optimal_uclk_for_dcfclk_sta_targets[i] = + bw_params->clk_table.entries[j].memclk_mhz * 16; + } } } } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c index 511ff6b5b9856776ea834393e4a7bfcaa90ca49f..7538b548c5725177b12e2d169acc681c31174797 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c @@ -999,7 +999,7 @@ static struct stream_encoder *dcn301_stream_encoder_create(enum engine_id eng_id vpg = dcn301_vpg_create(ctx, vpg_inst); afmt = dcn301_afmt_create(ctx, afmt_inst); - if (!enc1 || !vpg || !afmt) { + if (!enc1 || !vpg || !afmt || eng_id >= ARRAY_SIZE(stream_enc_regs)) { kfree(enc1); kfree(vpg); kfree(afmt); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index 31035fc3d8686359e00c694519429c000165e844..04d142f974745e3e4dc327eb0b7f8c7875839501 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -1941,8 +1941,6 @@ static bool dcn31_resource_construct( dc->caps.color.mpc.ogam_rom_caps.hlg = 0; dc->caps.color.mpc.ocsc = 1; - dc->config.use_old_fixed_vs_sequence = true; - /* Use pipe context based otg sync logic */ dc->config.use_pipe_ctx_sync_logic = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c index c4d71e7f18af47ba47dbc89e1a9098a0a4eade04..6f10052caeef02c3448307c4c81aef805e68e95b 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -1829,7 +1829,21 @@ int dcn32_populate_dml_pipes_from_context( dcn32_zero_pipe_dcc_fraction(pipes, pipe_cnt); DC_FP_END(); pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; - pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; + if (dc->config.enable_windowed_mpo_odm && + dc->debug.enable_single_display_2to1_odm_policy) { + switch (resource_get_odm_slice_count(pipe)) { + case 2: + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1; + break; + case 4: + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_4to1; + break; + default: + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; + } + } else { + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; + } pipes[pipe_cnt].pipe.src.gpuvm_min_page_size_kbytes = 256; // according to spreadsheet pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_19; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c index 74412e5f03fefbaa9350982ac92bc528cc8e80e8..6f832bf278cff540d548d17bb674a62614421361 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -1760,6 +1760,7 @@ static bool dcn321_resource_construct( dc->caps.color.mpc.ocsc = 1; dc->config.dc_mode_clk_limit_support = true; + dc->config.enable_windowed_mpo_odm = false; /* read VBIOS LTTPR caps */ { if (ctx->dc_bios->funcs->get_lttpr_caps) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 761ec989187568730fdd8cd51cd1802fa657be9c..e534e87cc85b5e20290e6d14d337872c22062224 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -701,7 +701,7 @@ static const struct dc_plane_cap plane_cap = { // 6:1 downscaling ratio: 1000/6 = 166.666 .max_downscale_factor = { - .argb8888 = 167, + .argb8888 = 250, .nv12 = 167, .fp16 = 167 }, @@ -764,6 +764,7 @@ static const struct dc_debug_options debug_defaults_drv = { }, .seamless_boot_odm_combine = DML_FAIL_SOURCE_PIXEL_FORMAT, .enable_z9_disable_interface = true, /* Allow support for the PMFW interface for disable Z9*/ + .minimum_z8_residency_time = 2100, .using_dml2 = true, .support_eDP1_5 = true, .enable_hpo_pg_support = false, @@ -780,8 +781,9 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = false, .ignore_pg = true, .psp_disabled_wa = true, - .ips2_eval_delay_us = 200, - .ips2_entry_delay_us = 400, + .ips2_eval_delay_us = 1650, + .ips2_entry_delay_us = 800, + .disable_dmub_reallow_idle = true, .static_screen_wait_frames = 2, }; @@ -2130,6 +2132,7 @@ static bool dcn35_resource_construct( dc->dml2_options.dcn_pipe_count = pool->base.pipe_count; dc->dml2_options.use_native_pstate_optimization = true; dc->dml2_options.use_native_soc_bb_construction = true; + dc->dml2_options.minimize_dispclk_using_odm = false; if (dc->config.EnableMinDispClkODM) dc->dml2_options.minimize_dispclk_using_odm = true; dc->dml2_options.enable_windowed_mpo_odm = dc->config.enable_windowed_mpo_odm; diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index c78c9224ab6060493a454683423c9d2a3b27e9a1..ae30fe2b6d0d90a6bcbb5bcea0d1f71d1aa8517a 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -78,6 +78,12 @@ struct dmub_srv_dcn31_regs; struct dmcub_trace_buf_entry; +/* enum dmub_window_memory_type - memory location type specification for windows */ +enum dmub_window_memory_type { + DMUB_WINDOW_MEMORY_TYPE_FB = 0, + DMUB_WINDOW_MEMORY_TYPE_GART +}; + /* enum dmub_status - return code for dmcub functions */ enum dmub_status { DMUB_STATUS_OK = 0, @@ -203,7 +209,7 @@ struct dmub_srv_region_params { uint32_t vbios_size; const uint8_t *fw_inst_const; const uint8_t *fw_bss_data; - bool is_mailbox_in_inbox; + const enum dmub_window_memory_type *window_memory_type; }; /** @@ -223,7 +229,7 @@ struct dmub_srv_region_params { */ struct dmub_srv_region_info { uint32_t fb_size; - uint32_t inbox_size; + uint32_t gart_size; uint8_t num_regions; struct dmub_region regions[DMUB_WINDOW_TOTAL]; }; @@ -239,9 +245,10 @@ struct dmub_srv_region_info { struct dmub_srv_memory_params { const struct dmub_srv_region_info *region_info; void *cpu_fb_addr; - void *cpu_inbox_addr; + void *cpu_gart_addr; uint64_t gpu_fb_addr; - uint64_t gpu_inbox_addr; + uint64_t gpu_gart_addr; + const enum dmub_window_memory_type *window_memory_type; }; /** @@ -443,7 +450,6 @@ struct dmub_srv_create_params { struct dmub_srv_base_funcs funcs; struct dmub_srv_hw_funcs *hw_funcs; void *user_ctx; - struct dc_context *dc_ctx; enum dmub_asic asic; uint32_t fw_version; bool is_virtual; diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index c64b6c848ef7219e3ddc44da8d4e56763a9bf7f4..59b96136871e5a97f0eefe16ef3f6e66d99e4fa4 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -26,15 +26,6 @@ #ifndef DMUB_CMD_H #define DMUB_CMD_H -#if defined(_TEST_HARNESS) || defined(FPGA_USB4) -#include "dmub_fw_types.h" -#include "include_legacy/atomfirmware.h" - -#if defined(_TEST_HARNESS) -#include -#endif -#else - #include #include #include @@ -42,8 +33,6 @@ #include "atomfirmware.h" -#endif // defined(_TEST_HARNESS) || defined(FPGA_USB4) - //================================================================== /* Basic type definitions. */ @@ -403,15 +392,16 @@ union replay_debug_flags { /** * 0x400 (bit 10) - * @force_disable_ips1: Force disable IPS1 state + * @enable_ips_visual_confirm: Enable IPS visual confirm when entering IPS + * If we enter IPS2, the Visual confirm bar will change to yellow */ - uint32_t force_disable_ips1 : 1; + uint32_t enable_ips_visual_confirm : 1; /** * 0x800 (bit 11) - * @force_disable_ips2: Force disable IPS2 state + * @enable_ips_residency_profiling: Enable IPS residency profiling */ - uint32_t force_disable_ips2 : 1; + uint32_t enable_ips_residency_profiling : 1; uint32_t reserved : 20; } bitfields; @@ -1270,11 +1260,11 @@ struct dmub_cmd_PLAT_54186_wa { uint32_t DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C; /**< reg value */ uint32_t DCSURF_PRIMARY_SURFACE_ADDRESS_C; /**< reg value */ struct { - uint8_t hubp_inst : 4; /**< HUBP instance */ - uint8_t tmz_surface : 1; /**< TMZ enable or disable */ - uint8_t immediate :1; /**< Immediate flip */ - uint8_t vmid : 4; /**< VMID */ - uint8_t grph_stereo : 1; /**< 1 if stereo */ + uint32_t hubp_inst : 4; /**< HUBP instance */ + uint32_t tmz_surface : 1; /**< TMZ enable or disable */ + uint32_t immediate :1; /**< Immediate flip */ + uint32_t vmid : 4; /**< VMID */ + uint32_t grph_stereo : 1; /**< 1 if stereo */ uint32_t reserved : 21; /**< Reserved */ } flip_params; /**< Pageflip parameters */ uint32_t reserved[9]; /**< Reserved bits */ @@ -2832,6 +2822,7 @@ struct dmub_rb_cmd_psr_set_power_opt { #define REPLAY_RESIDENCY_MODE_MASK (0x1 << REPLAY_RESIDENCY_MODE_SHIFT) # define REPLAY_RESIDENCY_MODE_PHY (0x0 << REPLAY_RESIDENCY_MODE_SHIFT) # define REPLAY_RESIDENCY_MODE_ALPM (0x1 << REPLAY_RESIDENCY_MODE_SHIFT) +# define REPLAY_RESIDENCY_MODE_IPS 0x10 #define REPLAY_RESIDENCY_ENABLE_MASK (0x1 << REPLAY_RESIDENCY_ENABLE_SHIFT) # define REPLAY_RESIDENCY_DISABLE (0x0 << REPLAY_RESIDENCY_ENABLE_SHIFT) @@ -2894,6 +2885,10 @@ enum dmub_cmd_replay_type { * Set Residency Frameupdate Timer. */ DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER = 6, + /** + * Set pseudo vtotal + */ + DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL = 7, }; /** @@ -3076,6 +3071,26 @@ struct dmub_cmd_replay_set_timing_sync_data { uint8_t pad[2]; }; +/** + * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. + */ +struct dmub_cmd_replay_set_pseudo_vtotal { + /** + * Panel Instance. + * Panel isntance to identify which replay_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Source Vtotal that Replay + IPS + ABM full screen video src vtotal + */ + uint16_t vtotal; + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad; +}; + /** * Definition of a DMUB_CMD__SET_REPLAY_POWER_OPT command. */ @@ -3156,6 +3171,20 @@ struct dmub_rb_cmd_replay_set_timing_sync { struct dmub_cmd_replay_set_timing_sync_data replay_set_timing_sync_data; }; +/** + * Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. + */ +struct dmub_rb_cmd_replay_set_pseudo_vtotal { + /** + * Command header. + */ + struct dmub_cmd_header header; + /** + * Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. + */ + struct dmub_cmd_replay_set_pseudo_vtotal data; +}; + /** * Data passed from driver to FW in DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command. */ @@ -3207,6 +3236,10 @@ union dmub_replay_cmd_set { * Definition of DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command data. */ struct dmub_cmd_replay_frameupdate_timer_data timer_data; + /** + * Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command data. + */ + struct dmub_cmd_replay_set_pseudo_vtotal pseudo_vtotal_data; }; /** @@ -4358,6 +4391,10 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command. */ struct dmub_rb_cmd_replay_set_frameupdate_timer replay_set_frameupdate_timer; + /** + * Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. + */ + struct dmub_rb_cmd_replay_set_pseudo_vtotal replay_set_pseudo_vtotal; }; /** diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c index 2daa1e0c806165a382717705cf08c3ad99d5e8ba..305463b8f110be1742476528bf2ee64439c02a58 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c @@ -32,8 +32,6 @@ #include "dcn/dcn_3_2_0_offset.h" #include "dcn/dcn_3_2_0_sh_mask.h" -#define DCN_BASE__INST0_SEG2 0x000034C0 - #define BASE_INNER(seg) ctx->dcn_reg_offsets[seg] #define CTX dmub #define REGS dmub->regs_dcn32 diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index 9ad738805320deeba210f6c103459617e553768f..569c2a27a042b1a983bbae2513ebd65d312e114c 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -417,58 +417,44 @@ void dmub_srv_destroy(struct dmub_srv *dmub) dmub_memset(dmub, 0, sizeof(*dmub)); } +static uint32_t dmub_srv_calc_regions_for_memory_type(const struct dmub_srv_region_params *params, + struct dmub_srv_region_info *out, + const uint32_t *window_sizes, + enum dmub_window_memory_type memory_type) +{ + uint32_t i, top = 0; + + for (i = 0; i < DMUB_WINDOW_TOTAL; ++i) { + if (params->window_memory_type[i] == memory_type) { + struct dmub_region *region = &out->regions[i]; + + region->base = dmub_align(top, 256); + region->top = region->base + dmub_align(window_sizes[i], 64); + top = region->top; + } + } + + return dmub_align(top, 4096); +} + enum dmub_status -dmub_srv_calc_region_info(struct dmub_srv *dmub, - const struct dmub_srv_region_params *params, - struct dmub_srv_region_info *out) + dmub_srv_calc_region_info(struct dmub_srv *dmub, + const struct dmub_srv_region_params *params, + struct dmub_srv_region_info *out) { - struct dmub_region *inst = &out->regions[DMUB_WINDOW_0_INST_CONST]; - struct dmub_region *stack = &out->regions[DMUB_WINDOW_1_STACK]; - struct dmub_region *data = &out->regions[DMUB_WINDOW_2_BSS_DATA]; - struct dmub_region *bios = &out->regions[DMUB_WINDOW_3_VBIOS]; - struct dmub_region *mail = &out->regions[DMUB_WINDOW_4_MAILBOX]; - struct dmub_region *trace_buff = &out->regions[DMUB_WINDOW_5_TRACEBUFF]; - struct dmub_region *fw_state = &out->regions[DMUB_WINDOW_6_FW_STATE]; - struct dmub_region *scratch_mem = &out->regions[DMUB_WINDOW_7_SCRATCH_MEM]; const struct dmub_fw_meta_info *fw_info; uint32_t fw_state_size = DMUB_FW_STATE_SIZE; uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE; - uint32_t scratch_mem_size = DMUB_SCRATCH_MEM_SIZE; - uint32_t previous_top = 0; + uint32_t window_sizes[DMUB_WINDOW_TOTAL] = { 0 }; + if (!dmub->sw_init) return DMUB_STATUS_INVALID; memset(out, 0, sizeof(*out)); + memset(window_sizes, 0, sizeof(window_sizes)); out->num_regions = DMUB_NUM_WINDOWS; - inst->base = 0x0; - inst->top = inst->base + params->inst_const_size; - - data->base = dmub_align(inst->top, 256); - data->top = data->base + params->bss_data_size; - - /* - * All cache windows below should be aligned to the size - * of the DMCUB cache line, 64 bytes. - */ - - stack->base = dmub_align(data->top, 256); - stack->top = stack->base + DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE; - - bios->base = dmub_align(stack->top, 256); - bios->top = bios->base + params->vbios_size; - - if (params->is_mailbox_in_inbox) { - mail->base = 0; - mail->top = mail->base + DMUB_MAILBOX_SIZE; - previous_top = bios->top; - } else { - mail->base = dmub_align(bios->top, 256); - mail->top = mail->base + DMUB_MAILBOX_SIZE; - previous_top = mail->top; - } - fw_info = dmub_get_fw_meta_info(params); if (fw_info) { @@ -486,19 +472,20 @@ dmub_srv_calc_region_info(struct dmub_srv *dmub, dmub->fw_version = fw_info->fw_version; } - trace_buff->base = dmub_align(previous_top, 256); - trace_buff->top = trace_buff->base + dmub_align(trace_buffer_size, 64); - - fw_state->base = dmub_align(trace_buff->top, 256); - fw_state->top = fw_state->base + dmub_align(fw_state_size, 64); + window_sizes[DMUB_WINDOW_0_INST_CONST] = params->inst_const_size; + window_sizes[DMUB_WINDOW_1_STACK] = DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE; + window_sizes[DMUB_WINDOW_2_BSS_DATA] = params->bss_data_size; + window_sizes[DMUB_WINDOW_3_VBIOS] = params->vbios_size; + window_sizes[DMUB_WINDOW_4_MAILBOX] = DMUB_MAILBOX_SIZE; + window_sizes[DMUB_WINDOW_5_TRACEBUFF] = trace_buffer_size; + window_sizes[DMUB_WINDOW_6_FW_STATE] = fw_state_size; + window_sizes[DMUB_WINDOW_7_SCRATCH_MEM] = DMUB_SCRATCH_MEM_SIZE; - scratch_mem->base = dmub_align(fw_state->top, 256); - scratch_mem->top = scratch_mem->base + dmub_align(scratch_mem_size, 64); + out->fb_size = + dmub_srv_calc_regions_for_memory_type(params, out, window_sizes, DMUB_WINDOW_MEMORY_TYPE_FB); - out->fb_size = dmub_align(scratch_mem->top, 4096); - - if (params->is_mailbox_in_inbox) - out->inbox_size = dmub_align(mail->top, 4096); + out->gart_size = + dmub_srv_calc_regions_for_memory_type(params, out, window_sizes, DMUB_WINDOW_MEMORY_TYPE_GART); return DMUB_STATUS_OK; } @@ -507,8 +494,6 @@ enum dmub_status dmub_srv_calc_mem_info(struct dmub_srv *dmub, const struct dmub_srv_memory_params *params, struct dmub_srv_fb_info *out) { - uint8_t *cpu_base; - uint64_t gpu_base; uint32_t i; if (!dmub->sw_init) @@ -519,19 +504,16 @@ enum dmub_status dmub_srv_calc_mem_info(struct dmub_srv *dmub, if (params->region_info->num_regions != DMUB_NUM_WINDOWS) return DMUB_STATUS_INVALID; - cpu_base = (uint8_t *)params->cpu_fb_addr; - gpu_base = params->gpu_fb_addr; - for (i = 0; i < DMUB_NUM_WINDOWS; ++i) { const struct dmub_region *reg = ¶ms->region_info->regions[i]; - out->fb[i].cpu_addr = cpu_base + reg->base; - out->fb[i].gpu_addr = gpu_base + reg->base; - - if (i == DMUB_WINDOW_4_MAILBOX && params->cpu_inbox_addr != 0) { - out->fb[i].cpu_addr = (uint8_t *)params->cpu_inbox_addr + reg->base; - out->fb[i].gpu_addr = params->gpu_inbox_addr + reg->base; + if (params->window_memory_type[i] == DMUB_WINDOW_MEMORY_TYPE_GART) { + out->fb[i].cpu_addr = (uint8_t *)params->cpu_gart_addr + reg->base; + out->fb[i].gpu_addr = params->gpu_gart_addr + reg->base; + } else { + out->fb[i].cpu_addr = (uint8_t *)params->cpu_fb_addr + reg->base; + out->fb[i].gpu_addr = params->gpu_fb_addr + reg->base; } out->fb[i].size = reg->top - reg->base; @@ -809,11 +791,20 @@ enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub) bool dmub_srv_is_hw_pwr_up(struct dmub_srv *dmub) { + union dmub_fw_boot_status status; + if (!dmub->hw_funcs.is_hw_powered_up) return true; - return dmub->hw_funcs.is_hw_powered_up(dmub) && - dmub->hw_funcs.is_hw_init(dmub); + if (!dmub->hw_funcs.is_hw_powered_up(dmub)) + return false; + + if (!dmub->hw_funcs.is_hw_init(dmub)) + return false; + + status = dmub->hw_funcs.get_fw_status(dmub); + + return status.bits.dal_fw && status.bits.mailbox_rdy; } enum dmub_status dmub_srv_wait_for_hw_pwr_up(struct dmub_srv *dmub, diff --git a/drivers/gpu/drm/amd/display/include/audio_types.h b/drivers/gpu/drm/amd/display/include/audio_types.h index 915a031a43cb286fdb03f2fb2788d0fa9e539b59..e4a26143f14c940f73bb0975bfd6b97d1c3f2d73 100644 --- a/drivers/gpu/drm/amd/display/include/audio_types.h +++ b/drivers/gpu/drm/amd/display/include/audio_types.h @@ -27,11 +27,21 @@ #define __AUDIO_TYPES_H__ #include "signal_types.h" +#include "fixed31_32.h" +#include "dc_dp_types.h" #define AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS 20 #define MAX_HW_AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS 18 #define MULTI_CHANNEL_SPLIT_NO_ASSO_INFO 0xFFFFFFFF +struct audio_dp_link_info { + uint32_t link_bandwidth_kbps; + uint32_t hblank_min_symbol_width; + enum dp_link_encoding encoding; + enum dc_link_rate link_rate; + enum dc_lane_count lane_count; + bool is_mst; +}; struct audio_crtc_info { uint32_t h_total; @@ -42,7 +52,10 @@ struct audio_crtc_info { uint32_t calculated_pixel_clock_100Hz; /* in 100Hz */ uint32_t refresh_rate; enum dc_color_depth color_depth; + enum dc_pixel_encoding pixel_encoding; bool interlaced; + uint32_t dsc_bits_per_pixel; + uint32_t dsc_num_slices; }; struct azalia_clock_info { uint32_t pixel_clock_in_10khz; @@ -95,6 +108,8 @@ struct audio_output { enum signal_type signal; /* video timing */ struct audio_crtc_info crtc_info; + /* DP link info */ + struct audio_dp_link_info dp_link_info; /* PLL for audio */ struct audio_pll_info pll_info; }; diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index ad98e504c00de5908ca94a38392ef818e91b2152..e304e8435fb8f1c5e29428f72c20a6097fb57697 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -980,6 +980,11 @@ void set_replay_coasting_vtotal(struct dc_link *link, link->replay_settings.coasting_vtotal_table[type] = vtotal; } +void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal) +{ + link->replay_settings.abm_with_ips_on_full_screen_video_pseudo_vtotal = vtotal; +} + void calculate_replay_link_off_frame_count(struct dc_link *link, uint16_t vtotal, uint16_t htotal) { diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h index c17bbc6fb38cafb518777b16c96a99b2116c36eb..bef4815e1703d78cdebc6f49bc160932d08c5272 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h @@ -57,6 +57,7 @@ void init_replay_config(struct dc_link *link, struct replay_config *pr_config); void set_replay_coasting_vtotal(struct dc_link *link, enum replay_coasting_vtotal_type type, uint16_t vtotal); +void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal); void calculate_replay_link_off_frame_count(struct dc_link *link, uint16_t vtotal, uint16_t htotal); diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 1dc5dd9b7bf70b10641a76e4c731e3e735aeaeef..a89d93154ddbf67d4700cd4a8d3fe8b846155e06 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -244,6 +244,7 @@ enum DC_FEATURE_MASK { DC_DISABLE_LTTPR_DP2_0 = (1 << 6), //0x40, disabled by default DC_PSR_ALLOW_SMU_OPT = (1 << 7), //0x80, disabled by default DC_PSR_ALLOW_MULTI_DISP_OPT = (1 << 8), //0x100, disabled by default + DC_REPLAY_MASK = (1 << 9), //0x200, disabled by default for dcn < 3.1.4 }; enum DC_DEBUG_MASK { @@ -258,6 +259,7 @@ enum DC_DEBUG_MASK { DC_ENABLE_DML2 = 0x100, DC_DISABLE_PSR_SU = 0x200, DC_DISABLE_REPLAY = 0x400, + DC_DISABLE_IPS = 0x800, }; enum amd_dpm_forced_level; diff --git a/drivers/gpu/drm/amd/include/amdgpu_reg_state.h b/drivers/gpu/drm/amd/include/amdgpu_reg_state.h index be519c8edf496fda93f393a077f174454e635a05..335980e2afbfb8e6eae89e7f28fdcc3391d39cde 100644 --- a/drivers/gpu/drm/amd/include/amdgpu_reg_state.h +++ b/drivers/gpu/drm/amd/include/amdgpu_reg_state.h @@ -138,7 +138,7 @@ static inline size_t amdgpu_reginst_size(uint16_t num_inst, size_t inst_size, } #define amdgpu_asic_get_reg_state_supported(adev) \ - ((adev)->asic_funcs->get_reg_state ? 1 : 0) + (((adev)->asic_funcs && (adev)->asic_funcs->get_reg_state) ? 1 : 0) #define amdgpu_asic_get_reg_state(adev, state, buf, size) \ ((adev)->asic_funcs->get_reg_state ? \ diff --git a/drivers/gpu/drm/amd/include/arct_ip_offset.h b/drivers/gpu/drm/amd/include/arct_ip_offset.h index af1c46991429be573c68a5ebe76cda97a26ec94a..7dd876f7df74c5369f5e26c24a32c283dd2aa89d 100644 --- a/drivers/gpu/drm/amd/include/arct_ip_offset.h +++ b/drivers/gpu/drm/amd/include/arct_ip_offset.h @@ -25,13 +25,11 @@ #define MAX_SEGMENT 6 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; } __maybe_unused; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_6_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_6_offset.h index 222fa8d1326966cefaa04e78274edd0d7332d7ea..a05bf8e4f58d9630fc100d03bb330f23f3b410b3 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_6_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_6_offset.h @@ -626,6 +626,8 @@ #define regDTBCLK_DTO2_MODULO_BASE_IDX 2 #define regDTBCLK_DTO3_MODULO 0x0022 #define regDTBCLK_DTO3_MODULO_BASE_IDX 2 +#define regHDMICHARCLK0_CLOCK_CNTL 0x004a +#define regHDMICHARCLK0_CLOCK_CNTL_BASE_IDX 2 #define regPHYASYMCLK_CLOCK_CNTL 0x0052 #define regPHYASYMCLK_CLOCK_CNTL_BASE_IDX 2 #define regPHYBSYMCLK_CLOCK_CNTL 0x0053 @@ -638,6 +640,8 @@ #define regPHYESYMCLK_CLOCK_CNTL_BASE_IDX 2 #define regPHYFSYMCLK_CLOCK_CNTL 0x0057 #define regPHYFSYMCLK_CLOCK_CNTL_BASE_IDX 2 +#define regHDMISTREAMCLK_CNTL 0x0059 +#define regHDMISTREAMCLK_CNTL_BASE_IDX 2 #define regDCCG_GATE_DISABLE_CNTL3 0x005a #define regDCCG_GATE_DISABLE_CNTL3_BASE_IDX 2 #define regHDMISTREAMCLK0_DTO_PARAM 0x005b diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_6_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_6_sh_mask.h index 8ddb03a1dc394d4f92ea00d5a82ea24788d9be5b..df84941bbe5be562d0d536fdecf7b111dd2d9d7f 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_6_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_1_6_sh_mask.h @@ -1933,6 +1933,11 @@ //DTBCLK_DTO3_MODULO #define DTBCLK_DTO3_MODULO__DTBCLK_DTO3_MODULO__SHIFT 0x0 #define DTBCLK_DTO3_MODULO__DTBCLK_DTO3_MODULO_MASK 0xFFFFFFFFL +//HDMICHARCLK0_CLOCK_CNTL +#define HDMICHARCLK0_CLOCK_CNTL__HDMICHARCLK0_EN__SHIFT 0x0 +#define HDMICHARCLK0_CLOCK_CNTL__HDMICHARCLK0_SRC_SEL__SHIFT 0x4 +#define HDMICHARCLK0_CLOCK_CNTL__HDMICHARCLK0_EN_MASK 0x00000001L +#define HDMICHARCLK0_CLOCK_CNTL__HDMICHARCLK0_SRC_SEL_MASK 0x00000070L //PHYASYMCLK_CLOCK_CNTL #define PHYASYMCLK_CLOCK_CNTL__PHYASYMCLK_FORCE_EN__SHIFT 0x0 #define PHYASYMCLK_CLOCK_CNTL__PHYASYMCLK_FORCE_SRC_SEL__SHIFT 0x4 @@ -1967,6 +1972,11 @@ #define PHYFSYMCLK_CLOCK_CNTL__PHYFSYMCLK_FORCE_SRC_SEL__SHIFT 0x4 #define PHYFSYMCLK_CLOCK_CNTL__PHYFSYMCLK_FORCE_EN_MASK 0x00000001L #define PHYFSYMCLK_CLOCK_CNTL__PHYFSYMCLK_FORCE_SRC_SEL_MASK 0x00000030L +//HDMISTREAMCLK_CNTL +#define HDMISTREAMCLK_CNTL__HDMISTREAMCLK0_SRC_SEL__SHIFT 0x0 +#define HDMISTREAMCLK_CNTL__HDMISTREAMCLK0_DTO_FORCE_DIS__SHIFT 0x10 +#define HDMISTREAMCLK_CNTL__HDMISTREAMCLK0_SRC_SEL_MASK 0x00000003L +#define HDMISTREAMCLK_CNTL__HDMISTREAMCLK0_DTO_FORCE_DIS_MASK 0x00010000L //DCCG_GATE_DISABLE_CNTL3 #define DCCG_GATE_DISABLE_CNTL3__HDMISTREAMCLK0_GATE_DISABLE__SHIFT 0x0 #define DCCG_GATE_DISABLE_CNTL3__HDMISTREAMCLK1_GATE_DISABLE__SHIFT 0x1 diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_offset.h index 7cf0a625277b1ee6e6e692f799091b3fa7185e29..33b5d9be06b185f51d0a3d7cf720fcaccff64f6e 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_offset.h @@ -4802,6 +4802,10 @@ #define regCM0_CM_DEALPHA_BASE_IDX 2 #define regCM0_CM_COEF_FORMAT 0x0d8c #define regCM0_CM_COEF_FORMAT_BASE_IDX 2 +#define regCM0_CM_TEST_DEBUG_INDEX 0x0d8d +#define regCM0_CM_TEST_DEBUG_INDEX_BASE_IDX 2 +#define regCM0_CM_TEST_DEBUG_DATA 0x0d8e +#define regCM0_CM_TEST_DEBUG_DATA_BASE_IDX 2 // addressBlock: dce_dc_dpp0_dispdec_dpp_dcperfmon_dc_perfmon_dispdec @@ -5210,6 +5214,10 @@ #define regCM1_CM_DEALPHA_BASE_IDX 2 #define regCM1_CM_COEF_FORMAT 0x0ef7 #define regCM1_CM_COEF_FORMAT_BASE_IDX 2 +#define regCM1_CM_TEST_DEBUG_INDEX 0x0ef8 +#define regCM1_CM_TEST_DEBUG_INDEX_BASE_IDX 2 +#define regCM1_CM_TEST_DEBUG_DATA 0x0ef9 +#define regCM1_CM_TEST_DEBUG_DATA_BASE_IDX 2 // addressBlock: dce_dc_dpp1_dispdec_dpp_dcperfmon_dc_perfmon_dispdec @@ -5618,6 +5626,10 @@ #define regCM2_CM_DEALPHA_BASE_IDX 2 #define regCM2_CM_COEF_FORMAT 0x1062 #define regCM2_CM_COEF_FORMAT_BASE_IDX 2 +#define regCM2_CM_TEST_DEBUG_INDEX 0x1063 +#define regCM2_CM_TEST_DEBUG_INDEX_BASE_IDX 2 +#define regCM2_CM_TEST_DEBUG_DATA 0x1064 +#define regCM2_CM_TEST_DEBUG_DATA_BASE_IDX 2 // addressBlock: dce_dc_dpp2_dispdec_dpp_dcperfmon_dc_perfmon_dispdec @@ -6026,6 +6038,10 @@ #define regCM3_CM_DEALPHA_BASE_IDX 2 #define regCM3_CM_COEF_FORMAT 0x11cd #define regCM3_CM_COEF_FORMAT_BASE_IDX 2 +#define regCM3_CM_TEST_DEBUG_INDEX 0x11ce +#define regCM3_CM_TEST_DEBUG_INDEX_BASE_IDX 2 +#define regCM3_CM_TEST_DEBUG_DATA 0x11cf +#define regCM3_CM_TEST_DEBUG_DATA_BASE_IDX 2 // addressBlock: dce_dc_dpp3_dispdec_dpp_dcperfmon_dc_perfmon_dispdec @@ -10568,6 +10584,8 @@ #define regDSCC0_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL_BASE_IDX 2 #define regDSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL 0x3035 #define regDSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL_BASE_IDX 2 +#define regDSCC0_DSCC_TEST_DEBUG_BUS_ROTATE 0x303a +#define regDSCC0_DSCC_TEST_DEBUG_BUS_ROTATE_BASE_IDX 2 // addressBlock: dce_dc_dsc0_dispdec_dsc_dcperfmon_dc_perfmon_dispdec @@ -10697,6 +10715,8 @@ #define regDSCC1_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL_BASE_IDX 2 #define regDSCC1_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL 0x3091 #define regDSCC1_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL_BASE_IDX 2 +#define regDSCC1_DSCC_TEST_DEBUG_BUS_ROTATE 0x3096 +#define regDSCC1_DSCC_TEST_DEBUG_BUS_ROTATE_BASE_IDX 2 // addressBlock: dce_dc_dsc1_dispdec_dsc_dcperfmon_dc_perfmon_dispdec @@ -10827,6 +10847,8 @@ #define regDSCC2_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL_BASE_IDX 2 #define regDSCC2_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL 0x30ed #define regDSCC2_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL_BASE_IDX 2 +#define regDSCC2_DSCC_TEST_DEBUG_BUS_ROTATE 0x30f2 +#define regDSCC2_DSCC_TEST_DEBUG_BUS_ROTATE_BASE_IDX 2 // addressBlock: dce_dc_dsc2_dispdec_dsc_dcperfmon_dc_perfmon_dispdec @@ -10957,6 +10979,8 @@ #define regDSCC3_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL_BASE_IDX 2 #define regDSCC3_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL 0x3149 #define regDSCC3_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL_BASE_IDX 2 +#define regDSCC3_DSCC_TEST_DEBUG_BUS_ROTATE 0x314e +#define regDSCC3_DSCC_TEST_DEBUG_BUS_ROTATE_BASE_IDX 2 // addressBlock: dce_dc_dsc3_dispdec_dsc_dcperfmon_dc_perfmon_dispdec diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h index fca72e2ec92947d8f792c0e51974723c762fbae6..ff77b71167eb71a0495af2e288acd30af86ce4c2 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h @@ -16556,6 +16556,13 @@ #define CM0_CM_COEF_FORMAT__CM_BIAS_FORMAT_MASK 0x00000001L #define CM0_CM_COEF_FORMAT__CM_POST_CSC_COEF_FORMAT_MASK 0x00000010L #define CM0_CM_COEF_FORMAT__CM_GAMUT_REMAP_COEF_FORMAT_MASK 0x00000100L + +//CM0_CM_TEST_DEBUG_INDEX +#define CM0_CM_TEST_DEBUG_INDEX__CM_TEST_DEBUG_INDEX__SHIFT 0x0 +#define CM0_CM_TEST_DEBUG_INDEX__CM_TEST_DEBUG_WRITE_EN__SHIFT 0x8 +#define CM0_CM_TEST_DEBUG_INDEX__CM_TEST_DEBUG_INDEX_MASK 0x000000FFL +#define CM0_CM_TEST_DEBUG_INDEX__CM_TEST_DEBUG_WRITE_EN_MASK 0x00000100L + #define DC_PERFMON10_PERFCOUNTER_CNTL__PERFCOUNTER_EVENT_SEL__SHIFT 0x0 #define DC_PERFMON10_PERFCOUNTER_CNTL__PERFCOUNTER_CVALUE_SEL__SHIFT 0x9 #define DC_PERFMON10_PERFCOUNTER_CNTL__PERFCOUNTER_INC_MODE__SHIFT 0xc @@ -27176,6 +27183,23 @@ #define DIG0_AFMT_CNTL__AFMT_AUDIO_CLOCK_ON__SHIFT 0x8 #define DIG0_AFMT_CNTL__AFMT_AUDIO_CLOCK_EN_MASK 0x00000001L #define DIG0_AFMT_CNTL__AFMT_AUDIO_CLOCK_ON_MASK 0x00000100L + +//DIG0_DIG_BE_CLK_CNTL +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_MODE__SHIFT 0x0 +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_CLK_EN__SHIFT 0x4 +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_SOFT_RESET__SHIFT 0x5 +#define DIG0_DIG_BE_CLK_CNTL__HDCP_SOFT_RESET__SHIFT 0x6 +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_SYMCLK_G_CLOCK_ON__SHIFT 0xb +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_SYMCLK_G_HDCP_CLOCK_ON__SHIFT 0xc +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_SYMCLK_G_TMDS_CLOCK_ON__SHIFT 0xd +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_MODE_MASK 0x00000007L +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_CLK_EN_MASK 0x00000010L +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_SOFT_RESET_MASK 0x00000020L +#define DIG0_DIG_BE_CLK_CNTL__HDCP_SOFT_RESET_MASK 0x00000040L +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_SYMCLK_G_CLOCK_ON_MASK 0x00000800L +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_SYMCLK_G_HDCP_CLOCK_ON_MASK 0x00001000L +#define DIG0_DIG_BE_CLK_CNTL__DIG_BE_SYMCLK_G_TMDS_CLOCK_ON_MASK 0x00002000L + #define DIG0_DIG_BE_CNTL__DIG_DUAL_LINK_ENABLE__SHIFT 0x0 #define DIG0_DIG_BE_CNTL__DIG_SWAP__SHIFT 0x1 #define DIG0_DIG_BE_CNTL__DIG_RB_SWITCH_EN__SHIFT 0x2 @@ -36716,6 +36740,17 @@ #define DSCC0_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL__DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL_MASK 0x0003FFFFL #define DSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL__DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL__SHIFT 0x0 #define DSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL__DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL_MASK 0x0003FFFFL + +//DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE +#define DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE__DSCC_TEST_DEBUG_BUS0_ROTATE__SHIFT 0x0 +#define DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE__DSCC_TEST_DEBUG_BUS1_ROTATE__SHIFT 0x8 +#define DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE__DSCC_TEST_DEBUG_BUS2_ROTATE__SHIFT 0x10 +#define DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE__DSCC_TEST_DEBUG_BUS3_ROTATE__SHIFT 0x18 +#define DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE__DSCC_TEST_DEBUG_BUS0_ROTATE_MASK 0x0000001FL +#define DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE__DSCC_TEST_DEBUG_BUS1_ROTATE_MASK 0x00001F00L +#define DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE__DSCC_TEST_DEBUG_BUS2_ROTATE_MASK 0x001F0000L +#define DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE__DSCC_TEST_DEBUG_BUS3_ROTATE_MASK 0x1F000000L + #define DC_PERFMON17_PERFCOUNTER_CNTL__PERFCOUNTER_EVENT_SEL__SHIFT 0x0 #define DC_PERFMON17_PERFCOUNTER_CNTL__PERFCOUNTER_CVALUE_SEL__SHIFT 0x9 #define DC_PERFMON17_PERFCOUNTER_CNTL__PERFCOUNTER_INC_MODE__SHIFT 0xc @@ -38488,6 +38523,18 @@ #define DWB_OGAM_LUT_INDEX__DWB_OGAM_LUT_INDEX_MASK 0x000001FFL #define DWB_OGAM_LUT_DATA__DWB_OGAM_LUT_DATA__SHIFT 0x0 #define DWB_OGAM_LUT_DATA__DWB_OGAM_LUT_DATA_MASK 0x0003FFFFL +//DWB_OGAM_LUT_CONTROL +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_WRITE_COLOR_MASK__SHIFT 0x0 +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_READ_COLOR_SEL__SHIFT 0x4 +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_READ_DBG__SHIFT 0x8 +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_HOST_SEL__SHIFT 0xc +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_CONFIG_MODE__SHIFT 0x10 +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_WRITE_COLOR_MASK_MASK 0x00000007L +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_READ_COLOR_SEL_MASK 0x00000030L +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_READ_DBG_MASK 0x00000100L +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_HOST_SEL_MASK 0x00001000L +#define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_CONFIG_MODE_MASK 0x00010000L + #define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_WRITE_COLOR_MASK__SHIFT 0x0 #define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_READ_COLOR_SEL__SHIFT 0x4 #define DWB_OGAM_LUT_CONTROL__DWB_OGAM_LUT_HOST_SEL__SHIFT 0xc @@ -52008,6 +52055,14 @@ #define DIO_CLK_CNTL__SYMCLK_R_GATE_DIS__SHIFT 0x10 #define DIO_CLK_CNTL__SYMCLK_G_GATE_DIS__SHIFT 0x11 #define DIO_CLK_CNTL__DIO_FGCG_REP_DIS__SHIFT 0x14 +#define DIO_CLK_CNTL__DISPCLK_G_HDCP_GATE_DIS__SHIFT 0x15 +#define DIO_CLK_CNTL__SYMCLKA_G_HDCP_GATE_DIS__SHIFT 0x16 +#define DIO_CLK_CNTL__SYMCLKB_G_HDCP_GATE_DIS__SHIFT 0x17 +#define DIO_CLK_CNTL__SYMCLKC_G_HDCP_GATE_DIS__SHIFT 0x18 +#define DIO_CLK_CNTL__SYMCLKD_G_HDCP_GATE_DIS__SHIFT 0x19 +#define DIO_CLK_CNTL__SYMCLKE_G_HDCP_GATE_DIS__SHIFT 0x1a +#define DIO_CLK_CNTL__SYMCLKF_G_HDCP_GATE_DIS__SHIFT 0x1b +#define DIO_CLK_CNTL__SYMCLKG_G_HDCP_GATE_DIS__SHIFT 0x1c #define DIO_CLK_CNTL__DIO_TEST_CLK_SEL_MASK 0x0000007FL #define DIO_CLK_CNTL__DISPCLK_R_GATE_DIS_MASK 0x00000200L #define DIO_CLK_CNTL__DISPCLK_G_GATE_DIS_MASK 0x00000400L @@ -52019,6 +52074,16 @@ #define DIO_CLK_CNTL__SYMCLK_R_GATE_DIS_MASK 0x00010000L #define DIO_CLK_CNTL__SYMCLK_G_GATE_DIS_MASK 0x00020000L #define DIO_CLK_CNTL__DIO_FGCG_REP_DIS_MASK 0x00100000L + +#define DIO_CLK_CNTL__DISPCLK_G_HDCP_GATE_DIS_MASK 0x00200000L +#define DIO_CLK_CNTL__SYMCLKA_G_HDCP_GATE_DIS_MASK 0x00400000L +#define DIO_CLK_CNTL__SYMCLKB_G_HDCP_GATE_DIS_MASK 0x00800000L +#define DIO_CLK_CNTL__SYMCLKC_G_HDCP_GATE_DIS_MASK 0x01000000L +#define DIO_CLK_CNTL__SYMCLKD_G_HDCP_GATE_DIS_MASK 0x02000000L +#define DIO_CLK_CNTL__SYMCLKE_G_HDCP_GATE_DIS_MASK 0x04000000L +#define DIO_CLK_CNTL__SYMCLKF_G_HDCP_GATE_DIS_MASK 0x08000000L +#define DIO_CLK_CNTL__SYMCLKG_G_HDCP_GATE_DIS_MASK 0x10000000L + #define DIO_PSP_INTERRUPT_STATUS__DIO_PSP_INTERRUPT_STATUS__SHIFT 0x0 #define DIO_PSP_INTERRUPT_STATUS__DIO_PSP_INTERRUPT_MESSAGE__SHIFT 0x1 #define DIO_PSP_INTERRUPT_STATUS__DIO_PSP_INTERRUPT_STATUS_MASK 0x00000001L diff --git a/drivers/gpu/drm/amd/include/atom-bits.h b/drivers/gpu/drm/amd/include/atom-bits.h index e8fae5c77514a257a9b04483e1af2a354a923e57..2bfd6d0ff050033cb972309cba15189268a43c94 100644 --- a/drivers/gpu/drm/amd/include/atom-bits.h +++ b/drivers/gpu/drm/amd/include/atom-bits.h @@ -33,7 +33,7 @@ static inline uint8_t get_u8(void *bios, int ptr) #define CU8(ptr) get_u8(ctx->bios, (ptr)) static inline uint16_t get_u16(void *bios, int ptr) { - return get_u8(bios ,ptr)|(((uint16_t)get_u8(bios, ptr+1))<<8); + return get_u8(bios, ptr)|(((uint16_t)get_u8(bios, ptr+1))<<8); } #define U16(ptr) get_u16(ctx->ctx->bios, (ptr)) #define CU16(ptr) get_u16(ctx->bios, (ptr)) diff --git a/drivers/gpu/drm/amd/include/beige_goby_ip_offset.h b/drivers/gpu/drm/amd/include/beige_goby_ip_offset.h index 26044cb285d29523d1eabcf377040b2fcd2521f7..48542ea6882a168dfb2223e43e4f33de853cb40a 100644 --- a/drivers/gpu/drm/amd/include/beige_goby_ip_offset.h +++ b/drivers/gpu/drm/amd/include/beige_goby_ip_offset.h @@ -26,13 +26,11 @@ #define MAX_SEGMENT 6 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; }; diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h index 60a6536ff656d70a4ade58c3a84c57798157415c..f40b6a03fe63455c22625fb365450e9928de61db 100644 --- a/drivers/gpu/drm/amd/include/cgs_common.h +++ b/drivers/gpu/drm/amd/include/cgs_common.h @@ -149,27 +149,26 @@ struct cgs_ops { struct cgs_os_ops; /* To be define in OS-specific CGS header */ -struct cgs_device -{ +struct cgs_device { const struct cgs_ops *ops; /* to be embedded at the start of driver private structure */ }; /* Convenience macros that make CGS indirect function calls look like * normal function calls */ -#define CGS_CALL(func,dev,...) \ +#define CGS_CALL(func, dev, ...) \ (((struct cgs_device *)dev)->ops->func(dev, ##__VA_ARGS__)) -#define CGS_OS_CALL(func,dev,...) \ +#define CGS_OS_CALL(func, dev, ...) \ (((struct cgs_device *)dev)->os_ops->func(dev, ##__VA_ARGS__)) -#define cgs_read_register(dev,offset) \ - CGS_CALL(read_register,dev,offset) -#define cgs_write_register(dev,offset,value) \ - CGS_CALL(write_register,dev,offset,value) -#define cgs_read_ind_register(dev,space,index) \ - CGS_CALL(read_ind_register,dev,space,index) -#define cgs_write_ind_register(dev,space,index,value) \ - CGS_CALL(write_ind_register,dev,space,index,value) +#define cgs_read_register(dev, offset) \ + CGS_CALL(read_register, dev, offset) +#define cgs_write_register(dev, offset, value) \ + CGS_CALL(write_register, dev, offset, value) +#define cgs_read_ind_register(dev, space, index) \ + CGS_CALL(read_ind_register, dev, space, index) +#define cgs_write_ind_register(dev, space, index, value) \ + CGS_CALL(write_ind_register, dev, space, index, value) #define cgs_get_firmware_info(dev, type, info) \ CGS_CALL(get_firmware_info, dev, type, info) diff --git a/drivers/gpu/drm/amd/include/cyan_skillfish_ip_offset.h b/drivers/gpu/drm/amd/include/cyan_skillfish_ip_offset.h index ce79e5de8ce3dc320e653b0db9870ac374f1940b..1a73296a9a74a41957514e444747a39c1bc34dec 100644 --- a/drivers/gpu/drm/amd/include/cyan_skillfish_ip_offset.h +++ b/drivers/gpu/drm/amd/include/cyan_skillfish_ip_offset.h @@ -25,13 +25,11 @@ #define MAX_SEGMENT 5 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; } __maybe_unused; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; diff --git a/drivers/gpu/drm/amd/include/dimgrey_cavefish_ip_offset.h b/drivers/gpu/drm/amd/include/dimgrey_cavefish_ip_offset.h index f84996a73de94dd2f052acbb4428d17b17a975ce..53cb4296df88a32f5cdbb01ffd7fd4f594429894 100644 --- a/drivers/gpu/drm/amd/include/dimgrey_cavefish_ip_offset.h +++ b/drivers/gpu/drm/amd/include/dimgrey_cavefish_ip_offset.h @@ -25,13 +25,11 @@ #define MAX_SEGMENT 6 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; diff --git a/drivers/gpu/drm/amd/include/dm_pp_interface.h b/drivers/gpu/drm/amd/include/dm_pp_interface.h index 1d93a0c574c9e9d3194c5a2a5b4431c90a47aa76..acd1cef61b7c53013672d242d197d77b0a5bfde1 100644 --- a/drivers/gpu/drm/amd/include/dm_pp_interface.h +++ b/drivers/gpu/drm/amd/include/dm_pp_interface.h @@ -27,7 +27,7 @@ #define PP_MAX_CLOCK_LEVELS 16 -enum amd_pp_display_config_type{ +enum amd_pp_display_config_type { AMD_PP_DisplayConfigType_None = 0, AMD_PP_DisplayConfigType_DP54 , AMD_PP_DisplayConfigType_DP432 , @@ -36,8 +36,8 @@ enum amd_pp_display_config_type{ AMD_PP_DisplayConfigType_DP243, AMD_PP_DisplayConfigType_DP216, AMD_PP_DisplayConfigType_DP162, - AMD_PP_DisplayConfigType_HDMI6G , - AMD_PP_DisplayConfigType_HDMI297 , + AMD_PP_DisplayConfigType_HDMI6G, + AMD_PP_DisplayConfigType_HDMI297, AMD_PP_DisplayConfigType_HDMI162, AMD_PP_DisplayConfigType_LVDS, AMD_PP_DisplayConfigType_DVI, @@ -45,8 +45,7 @@ enum amd_pp_display_config_type{ AMD_PP_DisplayConfigType_VGA }; -struct single_display_configuration -{ +struct single_display_configuration { uint32_t controller_index; uint32_t controller_id; uint32_t signal_type; diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index edcb85560cede5b42989eb7337e04c9df1fb7233..32054ecf0b87e342453485d86d0329565cddb4c5 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -244,8 +244,7 @@ enum pp_df_cstate { * @PP_PWR_LIMIT_DEFAULT: Default Power Limit * @PP_PWR_LIMIT_MAX: Maximum Power Limit */ -enum pp_power_limit_level -{ +enum pp_power_limit_level { PP_PWR_LIMIT_MIN = -1, PP_PWR_LIMIT_CURRENT, PP_PWR_LIMIT_DEFAULT, @@ -260,8 +259,7 @@ enum pp_power_limit_level * @PP_PWR_TYPE_FAST: manages the ~10 ms moving average of APU power, * where supported. */ -enum pp_power_type -{ +enum pp_power_type { PP_PWR_TYPE_SUSTAINED, PP_PWR_TYPE_FAST, }; diff --git a/drivers/gpu/drm/amd/include/navi12_ip_offset.h b/drivers/gpu/drm/amd/include/navi12_ip_offset.h index d8fc00478b6a07555490a380f607064577304f60..e94d80ec8d92e8d45e2316cc9d624f7ffa8c967b 100644 --- a/drivers/gpu/drm/amd/include/navi12_ip_offset.h +++ b/drivers/gpu/drm/amd/include/navi12_ip_offset.h @@ -25,13 +25,11 @@ #define MAX_SEGMENT 5 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; diff --git a/drivers/gpu/drm/amd/include/navi14_ip_offset.h b/drivers/gpu/drm/amd/include/navi14_ip_offset.h index c39ef651adc6f738d0cc08e97038b267445a5a45..508011288dea0aafc7159bd199d269b2635f66ed 100644 --- a/drivers/gpu/drm/amd/include/navi14_ip_offset.h +++ b/drivers/gpu/drm/amd/include/navi14_ip_offset.h @@ -25,13 +25,11 @@ #define MAX_SEGMENT 5 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; diff --git a/drivers/gpu/drm/amd/include/pptable.h b/drivers/gpu/drm/amd/include/pptable.h index 5aac8d545bdc6d45ef4719011307c308579f730e..2e8e6c9875f6c619db989b918811d1c21a8a5b7d 100644 --- a/drivers/gpu/drm/amd/include/pptable.h +++ b/drivers/gpu/drm/amd/include/pptable.h @@ -491,7 +491,7 @@ typedef struct _ClockInfoArray{ //sizeof(ATOM_PPLIB_CLOCK_INFO) UCHAR ucEntrySize; - UCHAR clockInfo[1]; + UCHAR clockInfo[]; }ClockInfoArray; typedef struct _NonClockInfoArray{ @@ -501,7 +501,7 @@ typedef struct _NonClockInfoArray{ //sizeof(ATOM_PPLIB_NONCLOCK_INFO) UCHAR ucEntrySize; - ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[1]; + ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[]; }NonClockInfoArray; typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Record @@ -658,7 +658,7 @@ typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Record typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Table{ UCHAR numEntries; - ATOM_PPLIB_SAMClk_Voltage_Limit_Record entries[1]; + ATOM_PPLIB_SAMClk_Voltage_Limit_Record entries[]; }ATOM_PPLIB_SAMClk_Voltage_Limit_Table; typedef struct _ATOM_PPLIB_SAMU_Table diff --git a/drivers/gpu/drm/amd/include/renoir_ip_offset.h b/drivers/gpu/drm/amd/include/renoir_ip_offset.h index 7dff85c81e5a7ea09cf0ed9905bfb101690f45b3..fa023cfdf72d0af952120cf6dad482d0da5002ef 100644 --- a/drivers/gpu/drm/amd/include/renoir_ip_offset.h +++ b/drivers/gpu/drm/amd/include/renoir_ip_offset.h @@ -25,13 +25,11 @@ #define MAX_SEGMENT 5 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; diff --git a/drivers/gpu/drm/amd/include/sienna_cichlid_ip_offset.h b/drivers/gpu/drm/amd/include/sienna_cichlid_ip_offset.h index b07bc2dd895dc7d916f6f14efdfbc5f16f25a134..054790470800373613dccfbd2c0cfd7a11e98c64 100644 --- a/drivers/gpu/drm/amd/include/sienna_cichlid_ip_offset.h +++ b/drivers/gpu/drm/amd/include/sienna_cichlid_ip_offset.h @@ -25,13 +25,11 @@ #define MAX_SEGMENT 5 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; diff --git a/drivers/gpu/drm/amd/include/v10_structs.h b/drivers/gpu/drm/amd/include/v10_structs.h index c0e98a98a641510a9284046aabc505ea11b098c4..58002a83d1dfd3426e76936cd1f3526b082bf563 100644 --- a/drivers/gpu/drm/amd/include/v10_structs.h +++ b/drivers/gpu/drm/amd/include/v10_structs.h @@ -24,8 +24,7 @@ #ifndef V10_STRUCTS_H_ #define V10_STRUCTS_H_ -struct v10_gfx_mqd -{ +struct v10_gfx_mqd { uint32_t reserved_0; // offset: 0 (0x0) uint32_t reserved_1; // offset: 1 (0x1) uint32_t reserved_2; // offset: 2 (0x2) diff --git a/drivers/gpu/drm/amd/include/vangogh_ip_offset.h b/drivers/gpu/drm/amd/include/vangogh_ip_offset.h index 691073ed780ecd713c100f76824a126b5c783240..695d7d04dfa60e795e29d9641f1655eb8c7f2b64 100644 --- a/drivers/gpu/drm/amd/include/vangogh_ip_offset.h +++ b/drivers/gpu/drm/amd/include/vangogh_ip_offset.h @@ -28,13 +28,11 @@ #define MAX_SEGMENT 6 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; diff --git a/drivers/gpu/drm/amd/include/vega10_ip_offset.h b/drivers/gpu/drm/amd/include/vega10_ip_offset.h index 3a22a5d169193fadf712ba39e4af419a14f1aea9..1e1ca69f21f78a9ea8760ce759fbdb6980df3076 100644 --- a/drivers/gpu/drm/amd/include/vega10_ip_offset.h +++ b/drivers/gpu/drm/amd/include/vega10_ip_offset.h @@ -24,13 +24,11 @@ #define MAX_INSTANCE 5 #define MAX_SEGMENT 5 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; }; diff --git a/drivers/gpu/drm/amd/include/vega20_ip_offset.h b/drivers/gpu/drm/amd/include/vega20_ip_offset.h index 1deb68f3d3341a91ebdaafda1bb6985657cadc1d..92cf2d9e767f8b5659804f3d60d10a63f81eac5f 100644 --- a/drivers/gpu/drm/amd/include/vega20_ip_offset.h +++ b/drivers/gpu/drm/amd/include/vega20_ip_offset.h @@ -25,139 +25,137 @@ #define MAX_SEGMENT 6 -struct IP_BASE_INSTANCE -{ +struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; }; -struct IP_BASE -{ +struct IP_BASE { struct IP_BASE_INSTANCE instance[MAX_INSTANCE]; } __maybe_unused; -static const struct IP_BASE ATHUB_BASE ={ { { { 0x00000C20, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE ATHUB_BASE = { { { { 0x00000C20, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } } } }; +static const struct IP_BASE CLK_BASE = { { { { 0x00016C00, 0x00016E00, 0x00017000, 0x00017200, 0x0001B000, 0x0001B200 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE CLK_BASE ={ { { { 0x00016C00, 0x00016E00, 0x00017000, 0x00017200, 0x0001B000, 0x0001B200 } }, +static const struct IP_BASE DCE_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } } } }; +static const struct IP_BASE DF_BASE = { { { { 0x00007000, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, 0, 0, 0 } } } }; +static const struct IP_BASE FUSE_BASE = { { { { 0x00017400, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE DCE_BASE ={ { { { 0x00000012, 0x000000C0, 0x000034C0, 0, 0, 0 } }, +static const struct IP_BASE GC_BASE = { { { { 0x00002000, 0x0000A000, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE DF_BASE ={ { { { 0x00007000, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE HDP_BASE = { { { { 0x00000F20, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE FUSE_BASE ={ { { { 0x00017400, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE MMHUB_BASE = { { { { 0x0001A000, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE GC_BASE ={ { { { 0x00002000, 0x0000A000, 0, 0, 0, 0 } }, +static const struct IP_BASE MP0_BASE = { { { { 0x00016000, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE HDP_BASE ={ { { { 0x00000F20, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE MP1_BASE = { { { { 0x00016000, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE MMHUB_BASE ={ { { { 0x0001A000, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE NBIO_BASE = { { { { 0x00000000, 0x00000014, 0x00000D20, 0x00010400, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE MP0_BASE ={ { { { 0x00016000, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE OSSSYS_BASE = { { { { 0x000010A0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE MP1_BASE ={ { { { 0x00016000, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE SDMA0_BASE = { { { { 0x00001260, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE NBIO_BASE ={ { { { 0x00000000, 0x00000014, 0x00000D20, 0x00010400, 0, 0 } }, +static const struct IP_BASE SDMA1_BASE = { { { { 0x00001860, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE OSSSYS_BASE ={ { { { 0x000010A0, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE SMUIO_BASE = { { { { 0x00016800, 0x00016A00, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE SDMA0_BASE ={ { { { 0x00001260, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE THM_BASE = { { { { 0x00016600, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE SDMA1_BASE ={ { { { 0x00001860, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE UMC_BASE = { { { { 0x00014000, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE SMUIO_BASE ={ { { { 0x00016800, 0x00016A00, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE THM_BASE ={ { { { 0x00016600, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE UMC_BASE ={ { { { 0x00014000, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } }, - { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE UVD_BASE ={ { { { 0x00007800, 0x00007E00, 0, 0, 0, 0 } }, +static const struct IP_BASE UVD_BASE = { { { { 0x00007800, 0x00007E00, 0, 0, 0, 0 } }, { { 0, 0x00009000, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; /* Adjust VCE_BASE to make vce_4_1 use vce_4_0 offset header files*/ -static const struct IP_BASE VCE_BASE ={ { { { 0x00007E00/* 0x00008800 */, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE VCE_BASE = { { { { 0x00007E00/* 0x00008800 */, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE XDMA_BASE ={ { { { 0x00003400, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE XDMA_BASE = { { { { 0x00003400, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } } } }; -static const struct IP_BASE RSMU_BASE ={ { { { 0x00012000, 0, 0, 0, 0, 0 } }, +static const struct IP_BASE RSMU_BASE = { { { { 0x00012000, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, { { 0, 0, 0, 0, 0, 0 } }, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c index f503e61faa6008f588c9bc243599238cb3cb7269..b1b4c09c34671e9e284345fdf3316fb4384e1d07 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c @@ -226,7 +226,7 @@ int atomctrl_set_engine_dram_timings_rv770( return amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings), - (uint32_t *)&engine_clock_parameters); + (uint32_t *)&engine_clock_parameters, sizeof(engine_clock_parameters)); } /* @@ -297,7 +297,7 @@ int atomctrl_get_memory_pll_dividers_si( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam), - (uint32_t *)&mpll_parameters); + (uint32_t *)&mpll_parameters, sizeof(mpll_parameters)); if (0 == result) { mpll_param->mpll_fb_divider.clk_frac = @@ -345,7 +345,7 @@ int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr, result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam), - (uint32_t *)&mpll_parameters); + (uint32_t *)&mpll_parameters, sizeof(mpll_parameters)); if (!result) mpll_param->mpll_post_divider = @@ -366,7 +366,7 @@ int atomctrl_get_memory_pll_dividers_ai(struct pp_hwmgr *hwmgr, result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam), - (uint32_t *)&mpll_parameters); + (uint32_t *)&mpll_parameters, sizeof(mpll_parameters)); /* VEGAM's mpll takes sometime to finish computing */ udelay(10); @@ -396,7 +396,7 @@ int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr, result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL), - (uint32_t *)&pll_parameters); + (uint32_t *)&pll_parameters, sizeof(pll_parameters)); if (0 == result) { dividers->pll_post_divider = pll_parameters.ucPostDiv; @@ -420,7 +420,7 @@ int atomctrl_get_engine_pll_dividers_vi( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL), - (uint32_t *)&pll_patameters); + (uint32_t *)&pll_patameters, sizeof(pll_patameters)); if (0 == result) { dividers->pll_post_divider = @@ -457,7 +457,7 @@ int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr *hwmgr, result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL), - (uint32_t *)&pll_patameters); + (uint32_t *)&pll_patameters, sizeof(pll_patameters)); if (0 == result) { dividers->usSclk_fcw_frac = le16_to_cpu(pll_patameters.usSclk_fcw_frac); @@ -490,7 +490,7 @@ int atomctrl_get_dfs_pll_dividers_vi( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL), - (uint32_t *)&pll_patameters); + (uint32_t *)&pll_patameters, sizeof(pll_patameters)); if (0 == result) { dividers->pll_post_divider = @@ -773,7 +773,7 @@ int atomctrl_calculate_voltage_evv_on_sclk( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues); + (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); if (result) return result; @@ -794,7 +794,7 @@ int atomctrl_calculate_voltage_evv_on_sclk( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues); + (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); if (result) return result; @@ -814,7 +814,7 @@ int atomctrl_calculate_voltage_evv_on_sclk( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues); + (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); if (result) return result; @@ -835,7 +835,7 @@ int atomctrl_calculate_voltage_evv_on_sclk( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues); + (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); if (result) return result; @@ -857,7 +857,7 @@ int atomctrl_calculate_voltage_evv_on_sclk( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues); + (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); if (result) return result; @@ -878,7 +878,7 @@ int atomctrl_calculate_voltage_evv_on_sclk( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues); + (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); if (result) return result; @@ -909,7 +909,7 @@ int atomctrl_calculate_voltage_evv_on_sclk( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues); + (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); if (result) return result; @@ -1134,7 +1134,7 @@ int atomctrl_get_voltage_evv_on_sclk( result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, GetVoltageInfo), - (uint32_t *)&get_voltage_info_param_space); + (uint32_t *)&get_voltage_info_param_space, sizeof(get_voltage_info_param_space)); *voltage = result ? 0 : le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *) @@ -1179,7 +1179,7 @@ int atomctrl_get_voltage_evv(struct pp_hwmgr *hwmgr, result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, GetVoltageInfo), - (uint32_t *)&get_voltage_info_param_space); + (uint32_t *)&get_voltage_info_param_space, sizeof(get_voltage_info_param_space)); if (0 != result) return result; @@ -1359,7 +1359,7 @@ int atomctrl_read_efuse(struct pp_hwmgr *hwmgr, uint16_t start_index, result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&efuse_param); + (uint32_t *)&efuse_param, sizeof(efuse_param)); *efuse = result ? 0 : le32_to_cpu(efuse_param.ulEfuseValue) & mask; return result; @@ -1380,7 +1380,7 @@ int atomctrl_set_ac_timing_ai(struct pp_hwmgr *hwmgr, uint32_t memory_clock, result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings), - (uint32_t *)&memory_clock_parameters); + (uint32_t *)&memory_clock_parameters, sizeof(memory_clock_parameters)); return result; } @@ -1399,7 +1399,7 @@ int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr *hwmgr, uint8_t voltage_ result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, GetVoltageInfo), - (uint32_t *)&get_voltage_info_param_space); + (uint32_t *)&get_voltage_info_param_space, sizeof(get_voltage_info_param_space)); *voltage = result ? 0 : le32_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3 *)(&get_voltage_info_param_space))->ulVoltageLevel); @@ -1526,7 +1526,7 @@ int atomctrl_get_leakage_id_from_efuse(struct pp_hwmgr *hwmgr, uint16_t *virtual result = amdgpu_atom_execute_table(adev->mode_info.atom_context, GetIndexIntoMasterTable(COMMAND, SetVoltage), - (uint32_t *)voltage_parameters); + (uint32_t *)voltage_parameters, sizeof(*voltage_parameters)); *virtual_voltage_id = voltage_parameters->usVoltageLevel; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c index a47a47238e2b9b01a9a423978ff8d2b70918a9d4..82d540334318d29111ec27fa7dedba47f0f36a13 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c @@ -258,7 +258,7 @@ int pp_atomfwctrl_get_gpu_pll_dividers_vega10(struct pp_hwmgr *hwmgr, idx = GetIndexIntoMasterCmdTable(computegpuclockparam); if (amdgpu_atom_execute_table( - adev->mode_info.atom_context, idx, (uint32_t *)&pll_parameters)) + adev->mode_info.atom_context, idx, (uint32_t *)&pll_parameters, sizeof(pll_parameters))) return -EINVAL; pll_output = (struct compute_gpu_clock_output_parameter_v1_8 *) @@ -505,7 +505,7 @@ int pp_atomfwctrl_get_clk_information_by_clkid(struct pp_hwmgr *hwmgr, ix = GetIndexIntoMasterCmdTable(getsmuclockinfo); if (amdgpu_atom_execute_table( - adev->mode_info.atom_context, ix, (uint32_t *)¶meters)) + adev->mode_info.atom_context, ix, (uint32_t *)¶meters, sizeof(parameters))) return -EINVAL; output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)¶meters; diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index c16703868e5ca2a3f0a7f6c7e3757b8e6ba036d0..0ad947df777ab2665a8f0de986a5d39737dd9ded 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "amdgpu.h" @@ -733,7 +734,7 @@ static int smu_early_init(void *handle) smu->adev = adev; smu->pm_enabled = !!amdgpu_dpm; smu->is_apu = false; - smu->smu_baco.state = SMU_BACO_STATE_NONE; + smu->smu_baco.state = SMU_BACO_STATE_EXIT; smu->smu_baco.platform_support = false; smu->user_dpm_profile.fan_mode = -1; @@ -817,16 +818,8 @@ static int smu_late_init(void *handle) * handle the switch automatically. Driver involvement * is unnecessary. */ - if (!smu->dc_controlled_by_gpio) { - ret = smu_set_power_source(smu, - adev->pm.ac_power ? SMU_POWER_SOURCE_AC : - SMU_POWER_SOURCE_DC); - if (ret) { - dev_err(adev->dev, "Failed to switch to %s mode!\n", - adev->pm.ac_power ? "AC" : "DC"); - return ret; - } - } + adev->pm.ac_power = power_supply_is_system_supplied() > 0; + smu_set_ac_dc(smu); if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 1)) || (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 3))) @@ -1961,31 +1954,10 @@ static int smu_smc_hw_cleanup(struct smu_context *smu) return 0; } -static int smu_reset_mp1_state(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - int ret = 0; - - if ((!adev->in_runpm) && (!adev->in_suspend) && - (!amdgpu_in_reset(adev))) - switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { - case IP_VERSION(13, 0, 0): - case IP_VERSION(13, 0, 7): - case IP_VERSION(13, 0, 10): - ret = smu_set_mp1_state(smu, PP_MP1_STATE_UNLOAD); - break; - default: - break; - } - - return ret; -} - static int smu_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct smu_context *smu = adev->powerplay.pp_handle; - int ret; if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) return 0; @@ -2003,15 +1975,7 @@ static int smu_hw_fini(void *handle) adev->pm.dpm_enabled = false; - ret = smu_smc_hw_cleanup(smu); - if (ret) - return ret; - - ret = smu_reset_mp1_state(smu); - if (ret) - return ret; - - return 0; + return smu_smc_hw_cleanup(smu); } static void smu_late_fini(void *handle) @@ -2710,6 +2674,7 @@ int smu_get_power_limit(void *handle, case SMU_PPT_LIMIT_CURRENT: switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(13, 0, 2): + case IP_VERSION(13, 0, 6): case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 0, 12): diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 2aa4fea873147516c23fb2fc568a94d907ee1c8a..66e84defd0b6ec2521c230262c34215a14251dfb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -424,7 +424,6 @@ enum smu_reset_mode { enum smu_baco_state { SMU_BACO_STATE_ENTER = 0, SMU_BACO_STATE_EXIT, - SMU_BACO_STATE_NONE, }; struct smu_baco_context { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 5a314d0316c1c8410d1f44281e5cc487e4947e81..f6545093bfc14a349138dc43960f21dbc90625ff 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -514,7 +514,7 @@ static int smu_v11_0_atom_get_smu_clockinfo(struct amdgpu_device *adev, getsmuclockinfo); ret = amdgpu_atom_execute_table(adev->mode_info.atom_context, index, - (uint32_t *)&input); + (uint32_t *)&input, sizeof(input)); if (ret) return -EINVAL; @@ -1432,22 +1432,24 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU HW CTF!\n"); orderly_poweroff(true); } else if (client_id == SOC15_IH_CLIENTID_MP1) { - if (src_id == 0xfe) { + if (src_id == SMU_IH_INTERRUPT_ID_TO_DRIVER) { /* ACK SMUToHost interrupt */ data = RREG32_SOC15(MP1, 0, mmMP1_SMN_IH_SW_INT_CTRL); data = REG_SET_FIELD(data, MP1_SMN_IH_SW_INT_CTRL, INT_ACK, 1); WREG32_SOC15(MP1, 0, mmMP1_SMN_IH_SW_INT_CTRL, data); switch (ctxid) { - case 0x3: + case SMU_IH_INTERRUPT_CONTEXT_ID_AC: dev_dbg(adev->dev, "Switched to AC mode!\n"); schedule_work(&smu->interrupt_work); + adev->pm.ac_power = true; break; - case 0x4: + case SMU_IH_INTERRUPT_CONTEXT_ID_DC: dev_dbg(adev->dev, "Switched to DC mode!\n"); schedule_work(&smu->interrupt_work); + adev->pm.ac_power = false; break; - case 0x7: + case SMU_IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING: /* * Increment the throttle interrupt counter */ @@ -1460,6 +1462,10 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, schedule_work(&smu->throttling_logging_work); break; + default: + dev_dbg(adev->dev, "Unhandled context id %d from client:%d!\n", + ctxid, client_id); + break; } } } @@ -1502,7 +1508,7 @@ int smu_v11_0_register_irq_handler(struct smu_context *smu) return ret; ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_MP1, - 0xfe, + SMU_IH_INTERRUPT_ID_TO_DRIVER, irq_src); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index 5e408a1958604aaa3f590a6e4615bd9c6c346d5f..ed15f5a0fd119f7f821d8411fde458ddf6771c8f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -301,7 +301,7 @@ static int smu_v12_0_atom_get_smu_clockinfo(struct amdgpu_device *adev, getsmuclockinfo); ret = amdgpu_atom_execute_table(adev->mode_info.atom_context, index, - (uint32_t *)&input); + (uint32_t *)&input, sizeof(input)); if (ret) return -EINVAL; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 771a3d457c335e2cc08582a3e4e3a3ba853d2928..48170bb5112ea05ef12c09b66f0ac07c950abc72 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -1369,22 +1369,24 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev, dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU HW CTF!\n"); orderly_poweroff(true); } else if (client_id == SOC15_IH_CLIENTID_MP1) { - if (src_id == 0xfe) { + if (src_id == SMU_IH_INTERRUPT_ID_TO_DRIVER) { /* ACK SMUToHost interrupt */ data = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); data = REG_SET_FIELD(data, MP1_SMN_IH_SW_INT_CTRL, INT_ACK, 1); WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, data); switch (ctxid) { - case 0x3: + case SMU_IH_INTERRUPT_CONTEXT_ID_AC: dev_dbg(adev->dev, "Switched to AC mode!\n"); smu_v13_0_ack_ac_dc_interrupt(smu); + adev->pm.ac_power = true; break; - case 0x4: + case SMU_IH_INTERRUPT_CONTEXT_ID_DC: dev_dbg(adev->dev, "Switched to DC mode!\n"); smu_v13_0_ack_ac_dc_interrupt(smu); + adev->pm.ac_power = false; break; - case 0x7: + case SMU_IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING: /* * Increment the throttle interrupt counter */ @@ -1397,7 +1399,7 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev, schedule_work(&smu->throttling_logging_work); break; - case 0x8: + case SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL: high = smu->thermal_range.software_shutdown_temp + smu->thermal_range.software_shutdown_temp_offset; high = min_t(typeof(high), @@ -1414,7 +1416,7 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev, data = data & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK); WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, data); break; - case 0x9: + case SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY: high = min_t(typeof(high), SMU_THERMAL_MAXIMUM_ALERT_TEMP, smu->thermal_range.software_shutdown_temp); @@ -1427,6 +1429,10 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev, data = data & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK); WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, data); break; + default: + dev_dbg(adev->dev, "Unhandled context id %d from client:%d!\n", + ctxid, client_id); + break; } } } @@ -1471,7 +1477,7 @@ int smu_v13_0_register_irq_handler(struct smu_context *smu) return ret; ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_MP1, - 0xfe, + SMU_IH_INTERRUPT_ID_TO_DRIVER, irq_src); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index a9b25faa63e468d0069ea08acfd7b90b1b36f056..a9954ffc02c562b91bf1166bb4bf87208152b36a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -2357,6 +2357,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, PPTable_t *pptable = table_context->driver_pptable; SkuTable_t *skutable = &pptable->SkuTable; uint32_t power_limit, od_percent_upper, od_percent_lower; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; if (smu_v13_0_get_current_power_limit(smu, &power_limit)) power_limit = smu->adev->pm.ac_power ? @@ -2380,7 +2381,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, od_percent_upper, od_percent_lower, power_limit); if (max_power_limit) { - *max_power_limit = power_limit * (100 + od_percent_upper); + *max_power_limit = msg_limit * (100 + od_percent_upper); *max_power_limit /= 100; } @@ -2747,13 +2748,7 @@ static int smu_v13_0_0_set_mp1_state(struct smu_context *smu, switch (mp1_state) { case PP_MP1_STATE_UNLOAD: - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_PrepareMp1ForUnload, - 0x55, NULL); - - if (!ret && smu->smu_baco.state == SMU_BACO_STATE_EXIT) - ret = smu_v13_0_disable_pmfw_state(smu); - + ret = smu_cmn_set_mp1_state(smu, mp1_state); break; default: /* Ignore others */ @@ -2949,7 +2944,7 @@ static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - switch (adev->ip_versions[MP1_HWIP][0]) { + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(13, 0, 0): return smu->smc_fw_version >= 0x004e6300; case IP_VERSION(13, 0, 10): @@ -2959,6 +2954,55 @@ static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu) } } +static int smu_v13_0_0_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + SkuTable_t *skutable = &pptable->SkuTable; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + struct smu_table_context *table_context = &smu->smu_table; + OverDriveTableExternal_t *od_table = + (OverDriveTableExternal_t *)table_context->overdrive_table; + int ret = 0; + + if (limit_type != SMU_DEFAULT_PPT_LIMIT) + return -EINVAL; + + if (limit <= msg_limit) { + if (smu->current_power_limit > msg_limit) { + od_table->OverDriveTable.Ppt = 0; + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; + + ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + return ret; + } + } + return smu_v13_0_set_power_limit(smu, limit_type, limit); + } else if (smu->od_enabled) { + ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit); + if (ret) + return ret; + + od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; + + ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + return ret; + } + + smu->current_power_limit = limit; + } else { + return -EINVAL; + } + + return 0; +} + static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask, .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table, @@ -3013,7 +3057,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .set_fan_control_mode = smu_v13_0_set_fan_control_mode, .enable_mgpu_fan_boost = smu_v13_0_0_enable_mgpu_fan_boost, .get_power_limit = smu_v13_0_0_get_power_limit, - .set_power_limit = smu_v13_0_set_power_limit, + .set_power_limit = smu_v13_0_0_set_power_limit, .set_power_source = smu_v13_0_set_power_source, .get_power_profile_mode = smu_v13_0_0_get_power_profile_mode, .set_power_profile_mode = smu_v13_0_0_set_power_profile_mode, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 3c98a8a0386a2612d0470dd6dbd767a6ecc308b0..1b96158b63bf468e0394cf364650f549598c3725 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -45,6 +45,7 @@ #include #include "amdgpu_ras.h" #include "amdgpu_mca.h" +#include "amdgpu_aca.h" #include "smu_cmn.h" #include "mp/mp_13_0_6_offset.h" #include "mp/mp_13_0_6_sh_mask.h" @@ -160,8 +161,8 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0), MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxDpmFreq, 1), MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxDpmFreq, 1), - MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 0), - MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 0), + MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1), + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0), MSG_MAP(GetCTFLimit, PPSMC_MSG_GetCTFLimit, 0), MSG_MAP(GetThermalLimit, PPSMC_MSG_ReadThrottlerLimit, 0), @@ -1438,7 +1439,10 @@ static int smu_v13_0_6_irq_process(struct amdgpu_device *adev, entry->src_data[1]); schedule_work(&smu->throttling_logging_work); } - + break; + default: + dev_dbg(adev->dev, "Unhandled context id %d from client:%d!\n", + ctxid, client_id); break; } } @@ -2547,18 +2551,22 @@ static int mca_umc_mca_get_err_count(const struct mca_ras_info *mca_ras, struct enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count) { uint64_t status0; + uint32_t ext_error_code; + uint32_t odecc_err_cnt; status0 = entry->regs[MCA_REG_IDX_STATUS]; + ext_error_code = MCA_REG__STATUS__ERRORCODEEXT(status0); + odecc_err_cnt = MCA_REG__MISC0__ERRCNT(entry->regs[MCA_REG_IDX_MISC0]); if (!REG_GET_FIELD(status0, MCMP1_STATUST0, Val)) { *count = 0; return 0; } - if (type == AMDGPU_MCA_ERROR_TYPE_UE && umc_v12_0_is_uncorrectable_error(adev, status0)) - *count = 1; - else if (type == AMDGPU_MCA_ERROR_TYPE_CE && umc_v12_0_is_correctable_error(adev, status0)) - *count = 1; + if (umc_v12_0_is_deferred_error(adev, status0) || + umc_v12_0_is_uncorrectable_error(adev, status0) || + umc_v12_0_is_correctable_error(adev, status0)) + *count = (ext_error_code == 0) ? odecc_err_cnt : 1; return 0; } @@ -2857,6 +2865,143 @@ static const struct amdgpu_mca_smu_funcs smu_v13_0_6_mca_smu_funcs = { .mca_get_valid_mca_count = mca_smu_get_valid_mca_count, }; +static int aca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu_v13_0_6_mca_set_debug_mode(smu, enable); +} + +static int smu_v13_0_6_get_valid_aca_count(struct smu_context *smu, enum aca_error_type type, u32 *count) +{ + uint32_t msg; + int ret; + + if (!count) + return -EINVAL; + + switch (type) { + case ACA_ERROR_TYPE_UE: + msg = SMU_MSG_QueryValidMcaCount; + break; + case ACA_ERROR_TYPE_CE: + msg = SMU_MSG_QueryValidMcaCeCount; + break; + default: + return -EINVAL; + } + + ret = smu_cmn_send_smc_msg(smu, msg, count); + if (ret) { + *count = 0; + return ret; + } + + return 0; +} + +static int aca_smu_get_valid_aca_count(struct amdgpu_device *adev, + enum aca_error_type type, u32 *count) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + int ret; + + switch (type) { + case ACA_ERROR_TYPE_UE: + case ACA_ERROR_TYPE_CE: + ret = smu_v13_0_6_get_valid_aca_count(smu, type, count); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int __smu_v13_0_6_aca_bank_dump(struct smu_context *smu, enum aca_error_type type, + int idx, int offset, u32 *val) +{ + uint32_t msg, param; + + switch (type) { + case ACA_ERROR_TYPE_UE: + msg = SMU_MSG_McaBankDumpDW; + break; + case ACA_ERROR_TYPE_CE: + msg = SMU_MSG_McaBankCeDumpDW; + break; + default: + return -EINVAL; + } + + param = ((idx & 0xffff) << 16) | (offset & 0xfffc); + + return smu_cmn_send_smc_msg_with_param(smu, msg, param, (uint32_t *)val); +} + +static int smu_v13_0_6_aca_bank_dump(struct smu_context *smu, enum aca_error_type type, + int idx, int offset, u32 *val, int count) +{ + int ret, i; + + if (!val) + return -EINVAL; + + for (i = 0; i < count; i++) { + ret = __smu_v13_0_6_aca_bank_dump(smu, type, idx, offset + (i << 2), &val[i]); + if (ret) + return ret; + } + + return 0; +} + +static int aca_bank_read_reg(struct amdgpu_device *adev, enum aca_error_type type, + int idx, int reg_idx, u64 *val) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + u32 data[2] = {0, 0}; + int ret; + + if (!val || reg_idx >= ACA_REG_IDX_COUNT) + return -EINVAL; + + ret = smu_v13_0_6_aca_bank_dump(smu, type, idx, reg_idx * 8, data, ARRAY_SIZE(data)); + if (ret) + return ret; + + *val = (u64)data[1] << 32 | data[0]; + + dev_dbg(adev->dev, "mca read bank reg: type:%s, index: %d, reg_idx: %d, val: 0x%016llx\n", + type == ACA_ERROR_TYPE_UE ? "UE" : "CE", idx, reg_idx, *val); + + return 0; +} + +static int aca_smu_get_valid_aca_bank(struct amdgpu_device *adev, + enum aca_error_type type, int idx, struct aca_bank *bank) +{ + int i, ret, count; + + count = min_t(int, 16, ARRAY_SIZE(bank->regs)); + for (i = 0; i < count; i++) { + ret = aca_bank_read_reg(adev, type, idx, i, &bank->regs[i]); + if (ret) + return ret; + } + + return 0; +} + +static const struct aca_smu_funcs smu_v13_0_6_aca_smu_funcs = { + .max_ue_bank_count = 12, + .max_ce_bank_count = 12, + .set_debug_mode = aca_smu_set_debug_mode, + .get_valid_aca_count = aca_smu_get_valid_aca_count, + .get_valid_aca_bank = aca_smu_get_valid_aca_bank, +}; + static int smu_v13_0_6_select_xgmi_plpd_policy(struct smu_context *smu, enum pp_xgmi_plpd_mode mode) { @@ -2895,13 +3040,6 @@ static int smu_v13_0_6_select_xgmi_plpd_policy(struct smu_context *smu, return ret; } -static ssize_t smu_v13_0_6_get_ecc_info(struct smu_context *smu, - void *table) -{ - /* Support ecc info by default */ - return 0; -} - static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { /* init dpm */ .get_allowed_feature_mask = smu_v13_0_6_get_allowed_feature_mask, @@ -2956,7 +3094,6 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .i2c_init = smu_v13_0_6_i2c_control_init, .i2c_fini = smu_v13_0_6_i2c_control_fini, .send_hbm_bad_pages_num = smu_v13_0_6_smu_send_hbm_bad_page_num, - .get_ecc_info = smu_v13_0_6_get_ecc_info, }; void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) @@ -2969,4 +3106,5 @@ void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) smu->smc_driver_if_version = SMU13_0_6_DRIVER_IF_VERSION; smu_v13_0_set_smu_mailbox_registers(smu); amdgpu_mca_smu_init_funcs(smu->adev, &smu_v13_0_6_mca_smu_funcs); + amdgpu_aca_set_smu_funcs(smu->adev, &smu_v13_0_6_aca_smu_funcs); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 59606a19e3d2b4494885b72f36f6524ec25b5139..0ffdb58af74e654af7ca73acf078415663f41dfe 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -2321,6 +2321,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, PPTable_t *pptable = table_context->driver_pptable; SkuTable_t *skutable = &pptable->SkuTable; uint32_t power_limit, od_percent_upper, od_percent_lower; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; if (smu_v13_0_get_current_power_limit(smu, &power_limit)) power_limit = smu->adev->pm.ac_power ? @@ -2344,7 +2345,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, od_percent_upper, od_percent_lower, power_limit); if (max_power_limit) { - *max_power_limit = power_limit * (100 + od_percent_upper); + *max_power_limit = msg_limit * (100 + od_percent_upper); *max_power_limit /= 100; } @@ -2504,13 +2505,7 @@ static int smu_v13_0_7_set_mp1_state(struct smu_context *smu, switch (mp1_state) { case PP_MP1_STATE_UNLOAD: - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_PrepareMp1ForUnload, - 0x55, NULL); - - if (!ret && smu->smu_baco.state == SMU_BACO_STATE_EXIT) - ret = smu_v13_0_disable_pmfw_state(smu); - + ret = smu_cmn_set_mp1_state(smu, mp1_state); break; default: /* Ignore others */ @@ -2545,6 +2540,55 @@ static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu) return smu->smc_fw_version > 0x00524600; } +static int smu_v13_0_7_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + SkuTable_t *skutable = &pptable->SkuTable; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + struct smu_table_context *table_context = &smu->smu_table; + OverDriveTableExternal_t *od_table = + (OverDriveTableExternal_t *)table_context->overdrive_table; + int ret = 0; + + if (limit_type != SMU_DEFAULT_PPT_LIMIT) + return -EINVAL; + + if (limit <= msg_limit) { + if (smu->current_power_limit > msg_limit) { + od_table->OverDriveTable.Ppt = 0; + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; + + ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + return ret; + } + } + return smu_v13_0_set_power_limit(smu, limit_type, limit); + } else if (smu->od_enabled) { + ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit); + if (ret) + return ret; + + od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; + + ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + return ret; + } + + smu->current_power_limit = limit; + } else { + return -EINVAL; + } + + return 0; +} + static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask, .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table, @@ -2596,7 +2640,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .set_fan_control_mode = smu_v13_0_set_fan_control_mode, .enable_mgpu_fan_boost = smu_v13_0_7_enable_mgpu_fan_boost, .get_power_limit = smu_v13_0_7_get_power_limit, - .set_power_limit = smu_v13_0_set_power_limit, + .set_power_limit = smu_v13_0_7_set_power_limit, .set_power_source = smu_v13_0_set_power_source, .get_power_profile_mode = smu_v13_0_7_get_power_profile_mode, .set_power_profile_mode = smu_v13_0_7_set_power_profile_mode, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index 4894f7ee737b41dd0e81503b5cb7f3fc1182a6e6..2aa7e9945a0bcfd4c32edeb9ce5f652c42ae8232 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -892,7 +892,7 @@ int smu_v14_0_register_irq_handler(struct smu_context *smu) // TODO: THM related ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_MP1, - 0xfe, + SMU_IH_INTERRUPT_ID_TO_DRIVER, irq_src); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 00cd615bbcdc0bf1b88dbb67e94c86b86173777a..b8dbd4e2534881e3cba8013d25998e40e1396a1a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -378,8 +378,15 @@ int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, res = __smu_cmn_reg2errno(smu, reg); if (res != 0) __smu_cmn_reg_print_error(smu, reg, index, param, msg); - if (read_arg) + if (read_arg) { smu_cmn_read_arg(smu, read_arg); + dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x,\ + readval: 0x%08x\n", + smu_get_message_name(smu, msg), index, param, reg, *read_arg); + } else { + dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x\n", + smu_get_message_name(smu, msg), index, param, reg); + } Out: if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && res) { amdgpu_device_halt(adev); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index cc590e27d88ac903d6b24dcdef5725f8cf2de76e..81bfce1406e52e4bcaf03e470ba13ebfbc541864 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -30,6 +30,16 @@ #define FDO_PWM_MODE_STATIC 1 #define FDO_PWM_MODE_STATIC_RPM 5 +#define SMU_IH_INTERRUPT_ID_TO_DRIVER 0xFE +#define SMU_IH_INTERRUPT_CONTEXT_ID_BACO 0x2 +#define SMU_IH_INTERRUPT_CONTEXT_ID_AC 0x3 +#define SMU_IH_INTERRUPT_CONTEXT_ID_DC 0x4 +#define SMU_IH_INTERRUPT_CONTEXT_ID_AUDIO_D0 0x5 +#define SMU_IH_INTERRUPT_CONTEXT_ID_AUDIO_D3 0x6 +#define SMU_IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING 0x7 +#define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8 +#define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9 + extern const int link_speed[]; /* Helper to Convert from PCIE Gen 1/2/3/4/5/6 to 0.1 GT/s speed units */ diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 8be235144f6d948cfe5de21e2ccdc198021a09bb..1e40d451ce8c275b345a72092a9658a6130ca34a 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -604,10 +604,10 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, * ADV75xx helpers */ -static struct edid *adv7511_get_edid(struct adv7511 *adv7511, - struct drm_connector *connector) +static const struct drm_edid *adv7511_edid_read(struct adv7511 *adv7511, + struct drm_connector *connector) { - struct edid *edid; + const struct drm_edid *drm_edid; /* Reading the EDID only works if the device is powered */ if (!adv7511->powered) { @@ -621,31 +621,44 @@ static struct edid *adv7511_get_edid(struct adv7511 *adv7511, edid_i2c_addr); } - edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); + drm_edid = drm_edid_read_custom(connector, adv7511_get_edid_block, adv7511); if (!adv7511->powered) __adv7511_power_off(adv7511); - adv7511_set_config_csc(adv7511, connector, adv7511->rgb, - drm_detect_hdmi_monitor(edid)); + if (drm_edid) { + /* + * FIXME: The CEC physical address should be set using + * cec_s_phys_addr(adap, + * connector->display_info.source_physical_address, false) from + * a path that has read the EDID and called + * drm_edid_connector_update(). + */ + const struct edid *edid = drm_edid_raw(drm_edid); + + adv7511_set_config_csc(adv7511, connector, adv7511->rgb, + drm_detect_hdmi_monitor(edid)); - cec_s_phys_addr_from_edid(adv7511->cec_adap, edid); + cec_s_phys_addr_from_edid(adv7511->cec_adap, edid); + } else { + cec_s_phys_addr_from_edid(adv7511->cec_adap, NULL); + } - return edid; + return drm_edid; } static int adv7511_get_modes(struct adv7511 *adv7511, struct drm_connector *connector) { - struct edid *edid; + const struct drm_edid *drm_edid; unsigned int count; - edid = adv7511_get_edid(adv7511, connector); + drm_edid = adv7511_edid_read(adv7511, connector); - drm_connector_update_edid_property(connector, edid); - count = drm_add_edid_modes(connector, edid); + drm_edid_connector_update(connector, drm_edid); + count = drm_edid_connector_add_modes(connector); - kfree(edid); + drm_edid_free(drm_edid); return count; } @@ -953,12 +966,12 @@ static enum drm_connector_status adv7511_bridge_detect(struct drm_bridge *bridge return adv7511_detect(adv, NULL); } -static struct edid *adv7511_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *adv7511_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct adv7511 *adv = bridge_to_adv7511(bridge); - return adv7511_get_edid(adv, connector); + return adv7511_edid_read(adv, connector); } static void adv7511_bridge_hpd_notify(struct drm_bridge *bridge, @@ -977,7 +990,7 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = { .mode_valid = adv7511_bridge_mode_valid, .attach = adv7511_bridge_attach, .detect = adv7511_bridge_detect, - .get_edid = adv7511_bridge_get_edid, + .edid_read = adv7511_bridge_edid_read, .hpd_notify = adv7511_bridge_hpd_notify, }; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index ef31033439bc15a896ed8748b7a62a8b46336c13..9d96d28d6fe8e1a32d26881c13c54d450754c30c 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1762,6 +1762,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, u8 request = msg->request & ~DP_AUX_I2C_MOT; int ret = 0; + mutex_lock(&ctx->aux_lock); pm_runtime_get_sync(dev); msg->reply = 0; switch (request) { @@ -1778,28 +1779,19 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, msg->size, msg->buffer); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + mutex_unlock(&ctx->aux_lock); return ret; } -static struct edid *anx7625_get_edid(struct anx7625_data *ctx) +static const struct drm_edid *anx7625_edid_read(struct anx7625_data *ctx) { struct device *dev = ctx->dev; struct s_edid_data *p_edid = &ctx->slimport_edid_p; int edid_num; - u8 *edid; - edid = kmalloc(FOUR_BLOCK_SIZE, GFP_KERNEL); - if (!edid) { - DRM_DEV_ERROR(dev, "Fail to allocate buffer\n"); - return NULL; - } - - if (ctx->slimport_edid_p.edid_block_num > 0) { - memcpy(edid, ctx->slimport_edid_p.edid_raw_data, - FOUR_BLOCK_SIZE); - return (struct edid *)edid; - } + if (ctx->slimport_edid_p.edid_block_num > 0) + goto out; pm_runtime_get_sync(dev); _anx7625_hpd_polling(ctx, 5000 * 100); @@ -1808,14 +1800,14 @@ static struct edid *anx7625_get_edid(struct anx7625_data *ctx) if (edid_num < 1) { DRM_DEV_ERROR(dev, "Fail to read EDID: %d\n", edid_num); - kfree(edid); return NULL; } p_edid->edid_block_num = edid_num; - memcpy(edid, ctx->slimport_edid_p.edid_raw_data, FOUR_BLOCK_SIZE); - return (struct edid *)edid; +out: + return drm_edid_alloc(ctx->slimport_edid_p.edid_raw_data, + FOUR_BLOCK_SIZE); } static enum drm_connector_status anx7625_sink_detect(struct anx7625_data *ctx) @@ -2474,7 +2466,9 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, ctx->connector = NULL; anx7625_dp_stop(ctx); - pm_runtime_put_sync(dev); + mutex_lock(&ctx->aux_lock); + pm_runtime_put_sync_suspend(dev); + mutex_unlock(&ctx->aux_lock); } static enum drm_connector_status @@ -2488,15 +2482,15 @@ anx7625_bridge_detect(struct drm_bridge *bridge) return anx7625_sink_detect(ctx); } -static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *anx7625_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct anx7625_data *ctx = bridge_to_anx7625(bridge); struct device *dev = ctx->dev; DRM_DEV_DEBUG_DRIVER(dev, "drm bridge get edid\n"); - return anx7625_get_edid(ctx); + return anx7625_edid_read(ctx); } static const struct drm_bridge_funcs anx7625_bridge_funcs = { @@ -2511,7 +2505,7 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = { .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, .detect = anx7625_bridge_detect, - .get_edid = anx7625_bridge_get_edid, + .edid_read = anx7625_bridge_edid_read, }; static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, @@ -2668,6 +2662,7 @@ static int anx7625_i2c_probe(struct i2c_client *client) mutex_init(&platform->lock); mutex_init(&platform->hdcp_wq_lock); + mutex_init(&platform->aux_lock); INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func); platform->hdcp_workqueue = create_workqueue("hdcp workqueue"); diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 66ebee7f3d832534ec64b780bdfa985bbfcfc896..39ed35d338363390d2fe37b765d4e0e48dc0118e 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -475,6 +475,8 @@ struct anx7625_data { struct workqueue_struct *hdcp_workqueue; /* Lock for hdcp work queue */ struct mutex hdcp_wq_lock; + /* Lock for aux transfer and disable */ + struct mutex aux_lock; char edid_block; struct display_timing dt; u8 display_timing_valid; diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 7d470527455b102d286cf4af1d3a0b7c388a251f..e226acc5c15e1fbed2282b04ef0d39e27a5dc4ae 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -1505,33 +1505,35 @@ static void cdns_mhdp_link_down(struct cdns_mhdp_device *mhdp) mhdp->link_up = false; } -static struct edid *cdns_mhdp_get_edid(struct cdns_mhdp_device *mhdp, - struct drm_connector *connector) +static const struct drm_edid *cdns_mhdp_edid_read(struct cdns_mhdp_device *mhdp, + struct drm_connector *connector) { if (!mhdp->plugged) return NULL; - return drm_do_get_edid(connector, cdns_mhdp_get_edid_block, mhdp); + return drm_edid_read_custom(connector, cdns_mhdp_get_edid_block, mhdp); } static int cdns_mhdp_get_modes(struct drm_connector *connector) { struct cdns_mhdp_device *mhdp = connector_to_mhdp(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int num_modes; if (!mhdp->plugged) return 0; - edid = cdns_mhdp_get_edid(mhdp, connector); - if (!edid) { + drm_edid = cdns_mhdp_edid_read(mhdp, connector); + + drm_edid_connector_update(connector, drm_edid); + + if (!drm_edid) { dev_err(mhdp->dev, "Failed to read EDID\n"); return 0; } - drm_connector_update_edid_property(connector, edid); - num_modes = drm_add_edid_modes(connector, edid); - kfree(edid); + num_modes = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); /* * HACK: Warn about unsupported display formats until we deal @@ -2220,12 +2222,12 @@ static enum drm_connector_status cdns_mhdp_bridge_detect(struct drm_bridge *brid return cdns_mhdp_detect(mhdp); } -static struct edid *cdns_mhdp_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *cdns_mhdp_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); - return cdns_mhdp_get_edid(mhdp, connector); + return cdns_mhdp_edid_read(mhdp, connector); } static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { @@ -2239,7 +2241,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { .atomic_reset = cdns_mhdp_bridge_atomic_reset, .atomic_get_input_bus_fmts = cdns_mhdp_get_input_bus_fmts, .detect = cdns_mhdp_bridge_detect, - .get_edid = cdns_mhdp_bridge_get_edid, + .edid_read = cdns_mhdp_bridge_edid_read, .hpd_enable = cdns_mhdp_bridge_hpd_enable, .hpd_disable = cdns_mhdp_bridge_hpd_disable, }; diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index 483c28c7fc99b4520bf33277c6632af0df0aeede..c83486cf6b15f105f28c27cc4fca4d24817ea335 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -230,14 +230,14 @@ static const struct drm_connector_funcs ch7033_connector_funcs = { static int ch7033_connector_get_modes(struct drm_connector *connector) { struct ch7033_priv *priv = conn_to_ch7033_priv(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int ret; - edid = drm_bridge_get_edid(priv->next_bridge, connector); - drm_connector_update_edid_property(connector, edid); - if (edid) { - ret = drm_add_edid_modes(connector, edid); - kfree(edid); + drm_edid = drm_bridge_edid_read(priv->next_bridge, connector); + drm_edid_connector_update(connector, drm_edid); + if (drm_edid) { + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); } else { ret = drm_add_modes_noedid(connector, 1920, 1080); drm_set_preferred_mode(connector, 1024, 768); diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index 08bd5695ddae0f59bdb104b588876a41110e7ff4..ab8e00baf3f163fb64baa21aba90098e24635fb5 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -81,12 +81,12 @@ display_connector_detect(struct drm_bridge *bridge) } } -static struct edid *display_connector_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *display_connector_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct display_connector *conn = to_display_connector(bridge); - return drm_get_edid(connector, conn->bridge.ddc); + return drm_edid_read_ddc(connector, conn->bridge.ddc); } /* @@ -172,7 +172,7 @@ static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge, static const struct drm_bridge_funcs display_connector_bridge_funcs = { .attach = display_connector_attach, .detect = display_connector_detect, - .get_edid = display_connector_get_edid, + .edid_read = display_connector_edid_read, .atomic_get_output_bus_fmts = display_connector_get_output_bus_fmts, .atomic_get_input_bus_fmts = display_connector_get_input_bus_fmts, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig index 5a4f3d58501e235dfa86465824e854a803fae107..5965e8027529a19cb36c58d6c0335ce0db613b21 100644 --- a/drivers/gpu/drm/bridge/imx/Kconfig +++ b/drivers/gpu/drm/bridge/imx/Kconfig @@ -3,6 +3,24 @@ if ARCH_MXC || COMPILE_TEST config DRM_IMX_LDB_HELPER tristate +config DRM_IMX8MP_DW_HDMI_BRIDGE + tristate "Freescale i.MX8MP HDMI-TX bridge support" + depends on OF + depends on COMMON_CLK + select DRM_DW_HDMI + select DRM_IMX8MP_HDMI_PVI + select PHY_FSL_SAMSUNG_HDMI_PHY + help + Choose this to enable support for the internal HDMI encoder found + on the i.MX8MP SoC. + +config DRM_IMX8MP_HDMI_PVI + tristate "Freescale i.MX8MP HDMI PVI bridge support" + depends on OF + help + Choose this to enable support for the internal HDMI TX Parallel + Video Interface found on the Freescale i.MX8MP SoC. + config DRM_IMX8QM_LDB tristate "Freescale i.MX8QM LVDS display bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile index 2b0c2e44aa1b880f57a06fb043448d5ed537e2b8..edb0a7b71b30a361898e5c08f995299c3210634b 100644 --- a/drivers/gpu/drm/bridge/imx/Makefile +++ b/drivers/gpu/drm/bridge/imx/Makefile @@ -1,4 +1,6 @@ obj-$(CONFIG_DRM_IMX_LDB_HELPER) += imx-ldb-helper.o +obj-$(CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE) += imx8mp-hdmi-tx.o +obj-$(CONFIG_DRM_IMX8MP_HDMI_PVI) += imx8mp-hdmi-pvi.o obj-$(CONFIG_DRM_IMX8QM_LDB) += imx8qm-ldb.o obj-$(CONFIG_DRM_IMX8QXP_LDB) += imx8qxp-ldb.o obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o diff --git a/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c new file mode 100644 index 0000000000000000000000000000000000000000..f2a09c879e3d4b4a1ef6aa2ebc235527597f69ec --- /dev/null +++ b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Copyright (C) 2022 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HTX_PVI_CTRL 0x0 +#define PVI_CTRL_OP_VSYNC_POL BIT(18) +#define PVI_CTRL_OP_HSYNC_POL BIT(17) +#define PVI_CTRL_OP_DE_POL BIT(16) +#define PVI_CTRL_INP_VSYNC_POL BIT(14) +#define PVI_CTRL_INP_HSYNC_POL BIT(13) +#define PVI_CTRL_INP_DE_POL BIT(12) +#define PVI_CTRL_MODE_MASK GENMASK(2, 1) +#define PVI_CTRL_MODE_LCDIF 2 +#define PVI_CTRL_EN BIT(0) + +struct imx8mp_hdmi_pvi { + struct drm_bridge bridge; + struct device *dev; + struct drm_bridge *next_bridge; + void __iomem *regs; +}; + +static inline struct imx8mp_hdmi_pvi * +to_imx8mp_hdmi_pvi(struct drm_bridge *bridge) +{ + return container_of(bridge, struct imx8mp_hdmi_pvi, bridge); +} + +static int imx8mp_hdmi_pvi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge); + + return drm_bridge_attach(bridge->encoder, pvi->next_bridge, + bridge, flags); +} + +static void imx8mp_hdmi_pvi_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct drm_atomic_state *state = bridge_state->base.state; + struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge); + struct drm_connector_state *conn_state; + const struct drm_display_mode *mode; + struct drm_crtc_state *crtc_state; + struct drm_connector *connector; + u32 bus_flags = 0, val; + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + conn_state = drm_atomic_get_new_connector_state(state, connector); + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + + if (WARN_ON(pm_runtime_resume_and_get(pvi->dev))) + return; + + mode = &crtc_state->adjusted_mode; + + val = FIELD_PREP(PVI_CTRL_MODE_MASK, PVI_CTRL_MODE_LCDIF) | PVI_CTRL_EN; + + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + val |= PVI_CTRL_OP_VSYNC_POL | PVI_CTRL_INP_VSYNC_POL; + + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + val |= PVI_CTRL_OP_HSYNC_POL | PVI_CTRL_INP_HSYNC_POL; + + if (pvi->next_bridge->timings) + bus_flags = pvi->next_bridge->timings->input_bus_flags; + else if (bridge_state) + bus_flags = bridge_state->input_bus_cfg.flags; + + if (bus_flags & DRM_BUS_FLAG_DE_HIGH) + val |= PVI_CTRL_OP_DE_POL | PVI_CTRL_INP_DE_POL; + + writel(val, pvi->regs + HTX_PVI_CTRL); +} + +static void imx8mp_hdmi_pvi_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge); + + writel(0x0, pvi->regs + HTX_PVI_CTRL); + + pm_runtime_put(pvi->dev); +} + +static u32 * +imx8mp_hdmi_pvi_bridge_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge); + struct drm_bridge *next_bridge = pvi->next_bridge; + struct drm_bridge_state *next_state; + + if (!next_bridge->funcs->atomic_get_input_bus_fmts) + return NULL; + + next_state = drm_atomic_get_new_bridge_state(crtc_state->state, + next_bridge); + + return next_bridge->funcs->atomic_get_input_bus_fmts(next_bridge, + next_state, + crtc_state, + conn_state, + output_fmt, + num_input_fmts); +} + +static const struct drm_bridge_funcs imx_hdmi_pvi_bridge_funcs = { + .attach = imx8mp_hdmi_pvi_bridge_attach, + .atomic_enable = imx8mp_hdmi_pvi_bridge_enable, + .atomic_disable = imx8mp_hdmi_pvi_bridge_disable, + .atomic_get_input_bus_fmts = imx8mp_hdmi_pvi_bridge_get_input_bus_fmts, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, +}; + +static int imx8mp_hdmi_pvi_probe(struct platform_device *pdev) +{ + struct device_node *remote; + struct imx8mp_hdmi_pvi *pvi; + + pvi = devm_kzalloc(&pdev->dev, sizeof(*pvi), GFP_KERNEL); + if (!pvi) + return -ENOMEM; + + platform_set_drvdata(pdev, pvi); + pvi->dev = &pdev->dev; + + pvi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pvi->regs)) + return PTR_ERR(pvi->regs); + + /* Get the next bridge in the pipeline. */ + remote = of_graph_get_remote_node(pdev->dev.of_node, 1, -1); + if (!remote) + return -EINVAL; + + pvi->next_bridge = of_drm_find_bridge(remote); + of_node_put(remote); + + if (!pvi->next_bridge) + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, + "could not find next bridge\n"); + + pm_runtime_enable(&pdev->dev); + + /* Register the bridge. */ + pvi->bridge.funcs = &imx_hdmi_pvi_bridge_funcs; + pvi->bridge.of_node = pdev->dev.of_node; + pvi->bridge.timings = pvi->next_bridge->timings; + + drm_bridge_add(&pvi->bridge); + + return 0; +} + +static int imx8mp_hdmi_pvi_remove(struct platform_device *pdev) +{ + struct imx8mp_hdmi_pvi *pvi = platform_get_drvdata(pdev); + + drm_bridge_remove(&pvi->bridge); + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id imx8mp_hdmi_pvi_match[] = { + { + .compatible = "fsl,imx8mp-hdmi-pvi", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, imx8mp_hdmi_pvi_match); + +static struct platform_driver imx8mp_hdmi_pvi_driver = { + .probe = imx8mp_hdmi_pvi_probe, + .remove = imx8mp_hdmi_pvi_remove, + .driver = { + .name = "imx-hdmi-pvi", + .of_match_table = imx8mp_hdmi_pvi_match, + }, +}; +module_platform_driver(imx8mp_hdmi_pvi_driver); + +MODULE_DESCRIPTION("i.MX8MP HDMI TX Parallel Video Interface bridge driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c new file mode 100644 index 0000000000000000000000000000000000000000..89fc432ac611421468579726d54953e30221fa22 --- /dev/null +++ b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Copyright (C) 2022 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include + +struct imx8mp_hdmi { + struct dw_hdmi_plat_data plat_data; + struct dw_hdmi *dw_hdmi; + struct clk *pixclk; +}; + +static enum drm_mode_status +imx8mp_hdmi_mode_valid(struct dw_hdmi *dw_hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct imx8mp_hdmi *hdmi = (struct imx8mp_hdmi *)data; + + if (mode->clock < 13500) + return MODE_CLOCK_LOW; + + if (mode->clock > 297000) + return MODE_CLOCK_HIGH; + + if (clk_round_rate(hdmi->pixclk, mode->clock * 1000) != + mode->clock * 1000) + return MODE_CLOCK_RANGE; + + /* We don't support double-clocked and Interlaced modes */ + if ((mode->flags & DRM_MODE_FLAG_DBLCLK) || + (mode->flags & DRM_MODE_FLAG_INTERLACE)) + return MODE_BAD; + + return MODE_OK; +} + +static int imx8mp_hdmi_phy_init(struct dw_hdmi *dw_hdmi, void *data, + const struct drm_display_info *display, + const struct drm_display_mode *mode) +{ + return 0; +} + +static void imx8mp_hdmi_phy_disable(struct dw_hdmi *dw_hdmi, void *data) +{ +} + +static void im8mp_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data) +{ + /* + * Just release PHY core from reset, all other power management is done + * by the PHY driver. + */ + dw_hdmi_phy_gen1_reset(hdmi); + + dw_hdmi_phy_setup_hpd(hdmi, data); +} + +static const struct dw_hdmi_phy_ops imx8mp_hdmi_phy_ops = { + .init = imx8mp_hdmi_phy_init, + .disable = imx8mp_hdmi_phy_disable, + .setup_hpd = im8mp_hdmi_phy_setup_hpd, + .read_hpd = dw_hdmi_phy_read_hpd, + .update_hpd = dw_hdmi_phy_update_hpd, +}; + +static int imx8mp_dw_hdmi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dw_hdmi_plat_data *plat_data; + struct imx8mp_hdmi *hdmi; + + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + plat_data = &hdmi->plat_data; + + hdmi->pixclk = devm_clk_get(dev, "pix"); + if (IS_ERR(hdmi->pixclk)) + return dev_err_probe(dev, PTR_ERR(hdmi->pixclk), + "Unable to get pixel clock\n"); + + plat_data->mode_valid = imx8mp_hdmi_mode_valid; + plat_data->phy_ops = &imx8mp_hdmi_phy_ops; + plat_data->phy_name = "SAMSUNG HDMI TX PHY"; + plat_data->priv_data = hdmi; + plat_data->phy_force_vendor = true; + + hdmi->dw_hdmi = dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi->dw_hdmi)) + return PTR_ERR(hdmi->dw_hdmi); + + platform_set_drvdata(pdev, hdmi); + + return 0; +} + +static int imx8mp_dw_hdmi_remove(struct platform_device *pdev) +{ + struct imx8mp_hdmi *hdmi = platform_get_drvdata(pdev); + + dw_hdmi_remove(hdmi->dw_hdmi); + + return 0; +} + +static int __maybe_unused imx8mp_dw_hdmi_pm_suspend(struct device *dev) +{ + return 0; +} + +static int __maybe_unused imx8mp_dw_hdmi_pm_resume(struct device *dev) +{ + struct imx8mp_hdmi *hdmi = dev_get_drvdata(dev); + + dw_hdmi_resume(hdmi->dw_hdmi); + + return 0; +} + +static const struct dev_pm_ops imx8mp_dw_hdmi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(imx8mp_dw_hdmi_pm_suspend, + imx8mp_dw_hdmi_pm_resume) +}; + +static const struct of_device_id imx8mp_dw_hdmi_of_table[] = { + { .compatible = "fsl,imx8mp-hdmi-tx" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx8mp_dw_hdmi_of_table); + +static struct platform_driver imx8mp_dw_hdmi_platform_driver = { + .probe = imx8mp_dw_hdmi_probe, + .remove = imx8mp_dw_hdmi_remove, + .driver = { + .name = "imx8mp-dw-hdmi-tx", + .of_match_table = imx8mp_dw_hdmi_of_table, + .pm = &imx8mp_dw_hdmi_pm_ops, + }, +}; + +module_platform_driver(imx8mp_dw_hdmi_platform_driver); + +MODULE_DESCRIPTION("i.MX8MP HDMI encoder driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 2f300f5ca051cc17426aa7d6ad63420d787007ca..27334173e911c1c35468dff9155e693c1f79d4b1 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -458,7 +458,7 @@ struct it6505 { /* it6505 driver hold option */ bool enable_drv_hold; - struct edid *cached_edid; + const struct drm_edid *cached_edid; }; struct it6505_step_train_para { @@ -2240,11 +2240,13 @@ static void it6505_link_training_work(struct work_struct *work) ret = it6505_link_start_auto_train(it6505); DRM_DEV_DEBUG_DRIVER(dev, "auto train %s, auto_train_retry: %d", ret ? "pass" : "failed", it6505->auto_train_retry); - it6505->auto_train_retry--; if (ret) { + it6505->auto_train_retry = AUTO_TRAIN_RETRY; it6505_link_train_ok(it6505); return; + } else { + it6505->auto_train_retry--; } it6505_dump(it6505); @@ -2261,7 +2263,7 @@ static void it6505_plugged_status_to_codec(struct it6505 *it6505) static void it6505_remove_edid(struct it6505 *it6505) { - kfree(it6505->cached_edid); + drm_edid_free(it6505->cached_edid); it6505->cached_edid = NULL; } @@ -3032,15 +3034,16 @@ it6505_bridge_detect(struct drm_bridge *bridge) return it6505_detect(it6505); } -static struct edid *it6505_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *it6505_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct it6505 *it6505 = bridge_to_it6505(bridge); struct device *dev = it6505->dev; if (!it6505->cached_edid) { - it6505->cached_edid = drm_do_get_edid(connector, it6505_get_edid_block, - it6505); + it6505->cached_edid = drm_edid_read_custom(connector, + it6505_get_edid_block, + it6505); if (!it6505->cached_edid) { DRM_DEV_DEBUG_DRIVER(dev, "failed to get edid!"); @@ -3048,7 +3051,7 @@ static struct edid *it6505_bridge_get_edid(struct drm_bridge *bridge, } } - return drm_edid_duplicate(it6505->cached_edid); + return drm_edid_dup(it6505->cached_edid); } static const struct drm_bridge_funcs it6505_bridge_funcs = { @@ -3063,7 +3066,7 @@ static const struct drm_bridge_funcs it6505_bridge_funcs = { .atomic_pre_enable = it6505_bridge_atomic_pre_enable, .atomic_post_disable = it6505_bridge_atomic_post_disable, .detect = it6505_bridge_detect, - .get_edid = it6505_bridge_get_edid, + .edid_read = it6505_bridge_edid_read, }; static __maybe_unused int it6505_bridge_resume(struct device *dev) diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c index 1cf3fb1f13dcc1d905c5ac312b91732d8018f377..1c3433b5e3664e86cc1a861929c44eb0fd5cb7c3 100644 --- a/drivers/gpu/drm/bridge/ite-it66121.c +++ b/drivers/gpu/drm/bridge/ite-it66121.c @@ -874,33 +874,33 @@ static void it66121_bridge_hpd_disable(struct drm_bridge *bridge) dev_err(ctx->dev, "failed to disable HPD IRQ\n"); } -static struct edid *it66121_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *it66121_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge); - struct edid *edid; + const struct drm_edid *drm_edid; int ret; mutex_lock(&ctx->lock); ret = it66121_preamble_ddc(ctx); if (ret) { - edid = NULL; + drm_edid = NULL; goto out_unlock; } ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG, IT66121_DDC_HEADER_EDID); if (ret) { - edid = NULL; + drm_edid = NULL; goto out_unlock; } - edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx); + drm_edid = drm_edid_read_custom(connector, it66121_get_edid_block, ctx); out_unlock: mutex_unlock(&ctx->lock); - return edid; + return drm_edid; } static const struct drm_bridge_funcs it66121_bridge_funcs = { @@ -916,7 +916,7 @@ static const struct drm_bridge_funcs it66121_bridge_funcs = { .mode_set = it66121_bridge_mode_set, .mode_valid = it66121_bridge_mode_valid, .detect = it66121_bridge_detect, - .get_edid = it66121_bridge_get_edid, + .edid_read = it66121_bridge_edid_read, .hpd_enable = it66121_bridge_hpd_enable, .hpd_disable = it66121_bridge_hpd_disable, }; diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 273157428c8270741d5cafcac33d44695eb774a4..e7c4bef74aa46a37d0e1b4e87a78eee6f1c94b42 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -440,16 +440,16 @@ lt8912_connector_mode_valid(struct drm_connector *connector, static int lt8912_connector_get_modes(struct drm_connector *connector) { - struct edid *edid; + const struct drm_edid *drm_edid; int ret = -1; int num = 0; struct lt8912 *lt = connector_to_lt8912(connector); u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; - edid = drm_bridge_get_edid(lt->hdmi_port, connector); - if (edid) { - drm_connector_update_edid_property(connector, edid); - num = drm_add_edid_modes(connector, edid); + drm_edid = drm_bridge_edid_read(lt->hdmi_port, connector); + drm_edid_connector_update(connector, drm_edid); + if (drm_edid) { + num = drm_edid_connector_add_modes(connector); } else { return ret; } @@ -459,7 +459,7 @@ static int lt8912_connector_get_modes(struct drm_connector *connector) if (ret) num = ret; - kfree(edid); + drm_edid_free(drm_edid); return num; } @@ -620,8 +620,8 @@ lt8912_bridge_detect(struct drm_bridge *bridge) return lt8912_check_cable_status(lt); } -static struct edid *lt8912_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *lt8912_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct lt8912 *lt = bridge_to_lt8912(bridge); @@ -630,7 +630,7 @@ static struct edid *lt8912_bridge_get_edid(struct drm_bridge *bridge, * given to the hdmi connector node. */ if (lt->hdmi_port->ops & DRM_BRIDGE_OP_EDID) - return drm_bridge_get_edid(lt->hdmi_port, connector); + return drm_bridge_edid_read(lt->hdmi_port, connector); dev_warn(lt->dev, "The connected bridge does not supports DRM_BRIDGE_OP_EDID\n"); return NULL; @@ -642,7 +642,7 @@ static const struct drm_bridge_funcs lt8912_bridge_funcs = { .mode_set = lt8912_bridge_mode_set, .enable = lt8912_bridge_enable, .detect = lt8912_bridge_detect, - .get_edid = lt8912_bridge_get_edid, + .edid_read = lt8912_bridge_edid_read, }; static int lt8912_bridge_resume(struct device *dev) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 9663601ce0981803e0a4e0d3cecba8261097b663..a9c7e2b07ea10d15b06e682ac1a63c9d995e7137 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -846,13 +847,13 @@ lt9611_bridge_atomic_post_disable(struct drm_bridge *bridge, lt9611_sleep_setup(lt9611); } -static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *lt9611_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct lt9611 *lt9611 = bridge_to_lt9611(bridge); lt9611_power_on(lt9611); - return drm_do_get_edid(connector, lt9611_get_edid_block, lt9611); + return drm_edid_read_custom(connector, lt9611_get_edid_block, lt9611); } static void lt9611_bridge_hpd_enable(struct drm_bridge *bridge) @@ -892,7 +893,7 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = { .attach = lt9611_bridge_attach, .mode_valid = lt9611_bridge_mode_valid, .detect = lt9611_bridge_detect, - .get_edid = lt9611_bridge_get_edid, + .edid_read = lt9611_bridge_edid_read, .hpd_enable = lt9611_bridge_hpd_enable, .atomic_pre_enable = lt9611_bridge_atomic_pre_enable, diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index e971b75e90ad01d2097773226e24a15d09245750..bcf8bccd86d6cc0a90f8bbba7a9cc76a64b3803b 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -294,12 +295,12 @@ static int lt9611uxc_connector_get_modes(struct drm_connector *connector) { struct lt9611uxc *lt9611uxc = connector_to_lt9611uxc(connector); unsigned int count; - struct edid *edid; + const struct drm_edid *drm_edid; - edid = drm_bridge_get_edid(<9611uxc->bridge, connector); - drm_connector_update_edid_property(connector, edid); - count = drm_add_edid_modes(connector, edid); - kfree(edid); + drm_edid = drm_bridge_edid_read(<9611uxc->bridge, connector); + drm_edid_connector_update(connector, drm_edid); + count = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return count; } @@ -494,8 +495,8 @@ static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, siz return 0; }; -static struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge); int ret; @@ -509,7 +510,7 @@ static struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge, return NULL; } - return drm_do_get_edid(connector, lt9611uxc_get_edid_block, lt9611uxc); + return drm_edid_read_custom(connector, lt9611uxc_get_edid_block, lt9611uxc); } static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = { @@ -517,7 +518,7 @@ static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = { .mode_valid = lt9611uxc_bridge_mode_valid, .mode_set = lt9611uxc_bridge_mode_set, .detect = lt9611uxc_bridge_detect, - .get_edid = lt9611uxc_bridge_get_edid, + .edid_read = lt9611uxc_bridge_edid_read, }; static int lt9611uxc_parse_dt(struct device *dev, diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index e93083bbec9d1c6d561b884cd12f2ea3d4dcbd10..4480523244e4e29806469a84a485668d54b969a3 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -91,26 +91,26 @@ static int stdp2690_read_block(void *context, u8 *buf, unsigned int block, size_ return 0; } -static struct edid *ge_b850v3_lvds_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *ge_b850v3_lvds_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct i2c_client *client; client = ge_b850v3_lvds_ptr->stdp2690_i2c; - return drm_do_get_edid(connector, stdp2690_read_block, client); + return drm_edid_read_custom(connector, stdp2690_read_block, client); } static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) { - struct edid *edid; + const struct drm_edid *drm_edid; int num_modes; - edid = ge_b850v3_lvds_get_edid(&ge_b850v3_lvds_ptr->bridge, connector); + drm_edid = ge_b850v3_lvds_edid_read(&ge_b850v3_lvds_ptr->bridge, connector); - drm_connector_update_edid_property(connector, edid); - num_modes = drm_add_edid_modes(connector, edid); - kfree(edid); + drm_edid_connector_update(connector, drm_edid); + num_modes = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return num_modes; } @@ -226,7 +226,7 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = { .attach = ge_b850v3_lvds_attach, .detect = ge_b850v3_lvds_bridge_detect, - .get_edid = ge_b850v3_lvds_get_edid, + .edid_read = ge_b850v3_lvds_edid_read, }; static int ge_b850v3_lvds_init(struct device *dev) diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 7c0076e499533abf041a2235a62083f0489bbf76..ed93fd4c326572621e670408befb022da8cc9257 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -154,10 +154,11 @@ static void ptn3460_disable(struct drm_bridge *bridge) } -static struct edid *ptn3460_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *ptn3460_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); + const struct drm_edid *drm_edid = NULL; bool power_off; u8 *edid; int ret; @@ -175,27 +176,28 @@ static struct edid *ptn3460_get_edid(struct drm_bridge *bridge, EDID_LENGTH); if (ret) { kfree(edid); - edid = NULL; goto out; } + drm_edid = drm_edid_alloc(edid, EDID_LENGTH); + out: if (power_off) ptn3460_disable(&ptn_bridge->bridge); - return (struct edid *)edid; + return drm_edid; } static int ptn3460_connector_get_modes(struct drm_connector *connector) { struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int num_modes; - edid = ptn3460_get_edid(&ptn_bridge->bridge, connector); - drm_connector_update_edid_property(connector, edid); - num_modes = drm_add_edid_modes(connector, edid); - kfree(edid); + drm_edid = ptn3460_edid_read(&ptn_bridge->bridge, connector); + drm_edid_connector_update(connector, drm_edid); + num_modes = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return num_modes; } @@ -254,7 +256,7 @@ static const struct drm_bridge_funcs ptn3460_bridge_funcs = { .pre_enable = ptn3460_pre_enable, .disable = ptn3460_disable, .attach = ptn3460_bridge_attach, - .get_edid = ptn3460_get_edid, + .edid_read = ptn3460_edid_read, }; static int ptn3460_probe(struct i2c_client *client) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 541e4f5afc4c86a4e87b74a016885d6231afb892..14d4dcf239da835955f1d594579dd165288bd63f 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -107,6 +107,7 @@ struct ps8640 { struct device_link *link; bool pre_enabled; bool need_post_hpd_delay; + struct mutex aux_lock; }; static const struct regmap_config ps8640_regmap_config[] = { @@ -345,11 +346,20 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux, struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev; int ret; + mutex_lock(&ps_bridge->aux_lock); pm_runtime_get_sync(dev); + ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000); + if (ret) { + pm_runtime_put_sync_suspend(dev); + goto exit; + } ret = ps8640_aux_transfer_msg(aux, msg); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); +exit: + mutex_unlock(&ps_bridge->aux_lock); + return ret; } @@ -470,7 +480,18 @@ static void ps8640_atomic_post_disable(struct drm_bridge *bridge, ps_bridge->pre_enabled = false; ps8640_bridge_vdo_control(ps_bridge, DISABLE); + + /* + * The bridge seems to expect everything to be power cycled at the + * disable process, so grab a lock here to make sure + * ps8640_aux_transfer() is not holding a runtime PM reference and + * preventing the bridge from suspend. + */ + mutex_lock(&ps_bridge->aux_lock); + pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev); + + mutex_unlock(&ps_bridge->aux_lock); } static int ps8640_bridge_attach(struct drm_bridge *bridge, @@ -619,6 +640,8 @@ static int ps8640_probe(struct i2c_client *client) if (!ps_bridge) return -ENOMEM; + mutex_init(&ps_bridge->aux_lock); + ps_bridge->supplies[0].supply = "vdd12"; ps_bridge->supplies[1].supply = "vdd33"; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies), diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index be5914caa17d546601d11719976161624c1a420f..95fedc68b0ae55c94acfc64706ace51783e58e26 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -96,6 +96,7 @@ #define DSIM_MFLUSH_VS BIT(29) /* This flag is valid only for exynos3250/3472/5260/5430 */ #define DSIM_CLKLANE_STOP BIT(30) +#define DSIM_NON_CONTINUOUS_CLKLANE BIT(31) /* DSIM_ESCMODE */ #define DSIM_TX_TRIGGER_RST BIT(4) @@ -945,8 +946,12 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) * power consumption. */ if (driver_data->has_clklane_stop && - dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) + dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) { + if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) + reg |= DSIM_NON_CONTINUOUS_CLKLANE; + reg |= DSIM_CLKLANE_STOP; + } samsung_dsim_write(dsi, DSIM_CONFIG_REG, reg); lanes_mask = BIT(dsi->lanes) - 1; @@ -969,10 +974,6 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); reg &= ~DSIM_STOP_STATE_CNT_MASK; reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]); - - if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) - reg |= DSIM_FORCE_STOP_STATE; - samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); @@ -1431,18 +1432,6 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi) disable_irq(dsi->irq); } -static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable) -{ - u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); - - if (enable) - reg |= DSIM_FORCE_STOP_STATE; - else - reg &= ~DSIM_FORCE_STOP_STATE; - - samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); -} - static int samsung_dsim_init(struct samsung_dsim *dsi) { const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; @@ -1492,9 +1481,6 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge, ret = samsung_dsim_init(dsi); if (ret) return; - - samsung_dsim_set_display_mode(dsi); - samsung_dsim_set_display_enable(dsi, true); } } @@ -1503,12 +1489,8 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge, { struct samsung_dsim *dsi = bridge_to_dsi(bridge); - if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) { - samsung_dsim_set_display_mode(dsi); - samsung_dsim_set_display_enable(dsi, true); - } else { - samsung_dsim_set_stop_state(dsi, false); - } + samsung_dsim_set_display_mode(dsi); + samsung_dsim_set_display_enable(dsi, true); dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1521,9 +1503,7 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge, if (!(dsi->state & DSIM_STATE_ENABLED)) return; - if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) - samsung_dsim_set_stop_state(dsi, true); - + samsung_dsim_set_display_enable(dsi, false); dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1532,8 +1512,6 @@ static void samsung_dsim_atomic_post_disable(struct drm_bridge *bridge, { struct samsung_dsim *dsi = bridge_to_dsi(bridge); - samsung_dsim_set_display_enable(dsi, false); - dsi->state &= ~DSIM_STATE_ENABLED; pm_runtime_put_sync(dsi->dev); } @@ -1828,8 +1806,6 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host, if (ret) return ret; - samsung_dsim_set_stop_state(dsi, false); - ret = mipi_dsi_create_packet(&xfer.packet, msg); if (ret < 0) return ret; @@ -2020,11 +1996,11 @@ int samsung_dsim_probe(struct platform_device *pdev) else dsi->bridge.timings = &samsung_dsim_bridge_timings_de_high; - if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host) + if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host) { ret = dsi->plat_data->host_ops->register_host(dsi); - - if (ret) - goto err_disable_runtime; + if (ret) + goto err_disable_runtime; + } return 0; diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 2bdc5b439bebd56407af3b5b04892b3ac90678d4..8f84e98249c74e9402b4ee6ca1459ee8e5f07be1 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -278,39 +278,35 @@ static const struct drm_connector_funcs sii902x_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static struct edid *sii902x_get_edid(struct sii902x *sii902x, - struct drm_connector *connector) +static const struct drm_edid *sii902x_edid_read(struct sii902x *sii902x, + struct drm_connector *connector) { - struct edid *edid; + const struct drm_edid *drm_edid; mutex_lock(&sii902x->mutex); - edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); - if (edid) { - if (drm_detect_hdmi_monitor(edid)) - sii902x->sink_is_hdmi = true; - else - sii902x->sink_is_hdmi = false; - } + drm_edid = drm_edid_read_ddc(connector, sii902x->i2cmux->adapter[0]); mutex_unlock(&sii902x->mutex); - return edid; + return drm_edid; } static int sii902x_get_modes(struct drm_connector *connector) { struct sii902x *sii902x = connector_to_sii902x(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int num = 0; - edid = sii902x_get_edid(sii902x, connector); - drm_connector_update_edid_property(connector, edid); - if (edid) { - num = drm_add_edid_modes(connector, edid); - kfree(edid); + drm_edid = sii902x_edid_read(sii902x, connector); + drm_edid_connector_update(connector, drm_edid); + if (drm_edid) { + num = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); } + sii902x->sink_is_hdmi = connector->display_info.is_hdmi; + return num; } @@ -465,12 +461,12 @@ static enum drm_connector_status sii902x_bridge_detect(struct drm_bridge *bridge return sii902x_detect(sii902x); } -static struct edid *sii902x_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *sii902x_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct sii902x *sii902x = bridge_to_sii902x(bridge); - return sii902x_get_edid(sii902x, connector); + return sii902x_edid_read(sii902x, connector); } static u32 *sii902x_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, @@ -514,7 +510,7 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = { .disable = sii902x_bridge_disable, .enable = sii902x_bridge_enable, .detect = sii902x_bridge_detect, - .get_edid = sii902x_bridge_get_edid, + .edid_read = sii902x_bridge_edid_read, .atomic_reset = drm_atomic_helper_bridge_reset, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, @@ -1080,6 +1076,26 @@ static int sii902x_init(struct sii902x *sii902x) return ret; } + ret = sii902x_audio_codec_init(sii902x, dev); + if (ret) + return ret; + + i2c_set_clientdata(sii902x->i2c, sii902x); + + sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev, + 1, 0, I2C_MUX_GATE, + sii902x_i2c_bypass_select, + sii902x_i2c_bypass_deselect); + if (!sii902x->i2cmux) { + ret = -ENOMEM; + goto err_unreg_audio; + } + + sii902x->i2cmux->priv = sii902x; + ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); + if (ret) + goto err_unreg_audio; + sii902x->bridge.funcs = &sii902x_bridge_funcs; sii902x->bridge.of_node = dev->of_node; sii902x->bridge.timings = &default_sii902x_timings; @@ -1090,19 +1106,13 @@ static int sii902x_init(struct sii902x *sii902x) drm_bridge_add(&sii902x->bridge); - sii902x_audio_codec_init(sii902x, dev); + return 0; - i2c_set_clientdata(sii902x->i2c, sii902x); +err_unreg_audio: + if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev)) + platform_device_unregister(sii902x->audio.pdev); - sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev, - 1, 0, I2C_MUX_GATE, - sii902x_i2c_bypass_select, - sii902x_i2c_bypass_deselect); - if (!sii902x->i2cmux) - return -ENOMEM; - - sii902x->i2cmux->priv = sii902x; - return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); + return ret; } static int sii902x_probe(struct i2c_client *client) @@ -1170,12 +1180,14 @@ static int sii902x_probe(struct i2c_client *client) } static void sii902x_remove(struct i2c_client *client) - { struct sii902x *sii902x = i2c_get_clientdata(client); - i2c_mux_del_adapters(sii902x->i2cmux); drm_bridge_remove(&sii902x->bridge); + i2c_mux_del_adapters(sii902x->i2cmux); + + if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev)) + platform_device_unregister(sii902x->audio.pdev); } static const struct of_device_id sii902x_dt_ids[] = { diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index cbe8e778d7c7a9552d03677c117636ffb7774b1e..5813a2c4fc5eee930a97c81556811d960a109a7c 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -51,18 +51,20 @@ drm_connector_to_simple_bridge(struct drm_connector *connector) static int simple_bridge_get_modes(struct drm_connector *connector) { struct simple_bridge *sbridge = drm_connector_to_simple_bridge(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int ret; if (sbridge->next_bridge->ops & DRM_BRIDGE_OP_EDID) { - edid = drm_bridge_get_edid(sbridge->next_bridge, connector); - if (!edid) + drm_edid = drm_bridge_edid_read(sbridge->next_bridge, connector); + if (!drm_edid) DRM_INFO("EDID read failed. Fallback to standard modes\n"); } else { - edid = NULL; + drm_edid = NULL; } - if (!edid) { + drm_edid_connector_update(connector, drm_edid); + + if (!drm_edid) { /* * In case we cannot retrieve the EDIDs (missing or broken DDC * bus from the next bridge), fallback on the XGA standards and @@ -73,9 +75,8 @@ static int simple_bridge_get_modes(struct drm_connector *connector) return ret; } - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return ret; } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index aca5bb0866f886c05f5914ec647242ee1326509a..0e59b30d5227ddfbcb909acdd7b7079e45d0593f 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -2453,27 +2454,35 @@ static enum drm_connector_status dw_hdmi_detect(struct dw_hdmi *hdmi) return result; } -static struct edid *dw_hdmi_get_edid(struct dw_hdmi *hdmi, - struct drm_connector *connector) +static const struct drm_edid *dw_hdmi_edid_read(struct dw_hdmi *hdmi, + struct drm_connector *connector) { - struct edid *edid; + const struct drm_edid *drm_edid; + const struct edid *edid; if (!hdmi->ddc) return NULL; - edid = drm_get_edid(connector, hdmi->ddc); - if (!edid) { + drm_edid = drm_edid_read_ddc(connector, hdmi->ddc); + if (!drm_edid) { dev_dbg(hdmi->dev, "failed to get edid\n"); return NULL; } + /* + * FIXME: This should use connector->display_info.is_hdmi and + * connector->display_info.has_audio from a path that has read the EDID + * and called drm_edid_connector_update(). + */ + edid = drm_edid_raw(drm_edid); + dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", edid->width_cm, edid->height_cm); hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); hdmi->sink_has_audio = drm_detect_monitor_audio(edid); - return edid; + return drm_edid; } /* ----------------------------------------------------------------------------- @@ -2492,17 +2501,16 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) { struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector); - struct edid *edid; + const struct drm_edid *drm_edid; int ret; - edid = dw_hdmi_get_edid(hdmi, connector); - if (!edid) - return 0; + drm_edid = dw_hdmi_edid_read(hdmi, connector); - drm_connector_update_edid_property(connector, edid); - cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); + drm_edid_connector_update(connector, drm_edid); + cec_notifier_set_phys_addr(hdmi->cec_notifier, + connector->display_info.source_physical_address); + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return ret; } @@ -2979,12 +2987,12 @@ static enum drm_connector_status dw_hdmi_bridge_detect(struct drm_bridge *bridge return dw_hdmi_detect(hdmi); } -static struct edid *dw_hdmi_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *dw_hdmi_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct dw_hdmi *hdmi = bridge->driver_private; - return dw_hdmi_get_edid(hdmi, connector); + return dw_hdmi_edid_read(hdmi, connector); } static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { @@ -3001,7 +3009,7 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { .mode_set = dw_hdmi_bridge_mode_set, .mode_valid = dw_hdmi_bridge_mode_valid, .detect = dw_hdmi_bridge_detect, - .get_edid = dw_hdmi_bridge_get_edid, + .edid_read = dw_hdmi_bridge_edid_read, }; /* ----------------------------------------------------------------------------- diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 615cc8f950d7b3e11d174f61559a13088af91179..166f9a3e9622db9b45ede7631b675884d6e034d5 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -41,8 +41,24 @@ /* Registers */ +/* DSI D-PHY Layer registers */ +#define D0W_DPHYCONTTX 0x0004 +#define CLW_DPHYCONTTX 0x0020 +#define D0W_DPHYCONTRX 0x0024 +#define D1W_DPHYCONTRX 0x0028 +#define D2W_DPHYCONTRX 0x002c +#define D3W_DPHYCONTRX 0x0030 +#define COM_DPHYCONTRX 0x0038 +#define CLW_CNTRL 0x0040 +#define D0W_CNTRL 0x0044 +#define D1W_CNTRL 0x0048 +#define D2W_CNTRL 0x004c +#define D3W_CNTRL 0x0050 +#define TESTMODE_CNTRL 0x0054 + /* PPI layer registers */ #define PPI_STARTPPI 0x0104 /* START control bit */ +#define PPI_BUSYPPI 0x0108 /* PPI busy status */ #define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */ #define LPX_PERIOD 3 #define PPI_LANEENABLE 0x0134 @@ -59,6 +75,7 @@ /* DSI layer registers */ #define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */ +#define DSI_BUSYDSI 0x0208 /* DSI busy status */ #define DSI_LANEENABLE 0x0210 /* Enables each lane */ #define DSI_RX_START BIT(0) @@ -69,6 +86,20 @@ #define LANEENABLE_L2EN BIT(1) #define LANEENABLE_L3EN BIT(2) +#define DSI_LANESTATUS0 0x0214 /* DSI lane status 0 */ +#define DSI_LANESTATUS1 0x0218 /* DSI lane status 1 */ +#define DSI_INTSTATUS 0x0220 /* Interrupt Status */ +#define DSI_INTMASK 0x0224 /* Interrupt Mask */ +#define DSI_INTCLR 0x0228 /* Interrupt Clear */ +#define DSI_LPTXTO 0x0230 /* LPTX Time Out Counter */ + +/* DSI General Registers */ +#define DSIERRCNT 0x0300 /* DSI Error Count Register */ + +/* DSI Application Layer Registers */ +#define APLCTRL 0x0400 /* Application layer Control Register */ +#define RDPKTLN 0x0404 /* DSI Read packet Length Register */ + /* Display Parallel Input Interface */ #define DPIPXLFMT 0x0440 #define VS_POL_ACTIVE_LOW (1 << 10) @@ -114,35 +145,39 @@ #define VFUEN BIT(0) /* Video Frame Timing Upload */ /* System */ -#define TC_IDREG 0x0500 -#define SYSSTAT 0x0508 -#define SYSCTRL 0x0510 -#define DP0_AUDSRC_NO_INPUT (0 << 3) -#define DP0_AUDSRC_I2S_RX (1 << 3) -#define DP0_VIDSRC_NO_INPUT (0 << 0) -#define DP0_VIDSRC_DSI_RX (1 << 0) -#define DP0_VIDSRC_DPI_RX (2 << 0) -#define DP0_VIDSRC_COLOR_BAR (3 << 0) -#define SYSRSTENB 0x050c +#define TC_IDREG 0x0500 /* Chip ID and Revision ID */ +#define SYSBOOT 0x0504 /* System BootStrap Status Register */ +#define SYSSTAT 0x0508 /* System Status Register */ +#define SYSRSTENB 0x050c /* System Reset/Enable Register */ #define ENBI2C (1 << 0) #define ENBLCD0 (1 << 2) #define ENBBM (1 << 3) #define ENBDSIRX (1 << 4) #define ENBREG (1 << 5) #define ENBHDCP (1 << 8) -#define GPIOM 0x0540 -#define GPIOC 0x0544 -#define GPIOO 0x0548 -#define GPIOI 0x054c -#define INTCTL_G 0x0560 -#define INTSTS_G 0x0564 +#define SYSCTRL 0x0510 /* System Control Register */ +#define DP0_AUDSRC_NO_INPUT (0 << 3) +#define DP0_AUDSRC_I2S_RX (1 << 3) +#define DP0_VIDSRC_NO_INPUT (0 << 0) +#define DP0_VIDSRC_DSI_RX (1 << 0) +#define DP0_VIDSRC_DPI_RX (2 << 0) +#define DP0_VIDSRC_COLOR_BAR (3 << 0) +#define GPIOM 0x0540 /* GPIO Mode Control Register */ +#define GPIOC 0x0544 /* GPIO Direction Control Register */ +#define GPIOO 0x0548 /* GPIO Output Register */ +#define GPIOI 0x054c /* GPIO Input Register */ +#define INTCTL_G 0x0560 /* General Interrupts Control Register */ +#define INTSTS_G 0x0564 /* General Interrupts Status Register */ #define INT_SYSERR BIT(16) #define INT_GPIO_H(x) (1 << (x == 0 ? 2 : 10)) #define INT_GPIO_LC(x) (1 << (x == 0 ? 3 : 11)) -#define INT_GP0_LCNT 0x0584 -#define INT_GP1_LCNT 0x0588 +#define TEST_INT_C 0x0570 /* Test Interrupts Control Register */ +#define TEST_INT_S 0x0574 /* Test Interrupts Status Register */ + +#define INT_GP0_LCNT 0x0584 /* Interrupt GPIO0 Low Count Value Register */ +#define INT_GP1_LCNT 0x0588 /* Interrupt GPIO1 Low Count Value Register */ /* Control */ #define DP0CTL 0x0600 @@ -152,9 +187,12 @@ #define DP_EN BIT(0) /* Enable DPTX function */ /* Clocks */ -#define DP0_VIDMNGEN0 0x0610 -#define DP0_VIDMNGEN1 0x0614 -#define DP0_VMNGENSTATUS 0x0618 +#define DP0_VIDMNGEN0 0x0610 /* DP0 Video Force M Value Register */ +#define DP0_VIDMNGEN1 0x0614 /* DP0 Video Force N Value Register */ +#define DP0_VMNGENSTATUS 0x0618 /* DP0 Video Current M Value Register */ +#define DP0_AUDMNGEN0 0x0628 /* DP0 Audio Force M Value Register */ +#define DP0_AUDMNGEN1 0x062c /* DP0 Audio Force N Value Register */ +#define DP0_AMNGENSTATUS 0x0630 /* DP0 Audio Current M Value Register */ /* Main Channel */ #define DP0_SECSAMPLE 0x0640 @@ -224,8 +262,22 @@ #define DP0_SNKLTCHGREQ 0x06d4 #define DP0_LTLOOPCTRL 0x06d8 #define DP0_SNKLTCTRL 0x06e4 - -#define DP1_SRCCTRL 0x07a0 +#define DP0_TPATDAT0 0x06e8 /* DP0 Test Pattern bits 29 to 0 */ +#define DP0_TPATDAT1 0x06ec /* DP0 Test Pattern bits 59 to 30 */ +#define DP0_TPATDAT2 0x06f0 /* DP0 Test Pattern bits 89 to 60 */ +#define DP0_TPATDAT3 0x06f4 /* DP0 Test Pattern bits 119 to 90 */ + +#define AUDCFG0 0x0700 /* DP0 Audio Config0 Register */ +#define AUDCFG1 0x0704 /* DP0 Audio Config1 Register */ +#define AUDIFDATA0 0x0708 /* DP0 Audio Info Frame Bytes 3 to 0 */ +#define AUDIFDATA1 0x070c /* DP0 Audio Info Frame Bytes 7 to 4 */ +#define AUDIFDATA2 0x0710 /* DP0 Audio Info Frame Bytes 11 to 8 */ +#define AUDIFDATA3 0x0714 /* DP0 Audio Info Frame Bytes 15 to 12 */ +#define AUDIFDATA4 0x0718 /* DP0 Audio Info Frame Bytes 19 to 16 */ +#define AUDIFDATA5 0x071c /* DP0 Audio Info Frame Bytes 23 to 20 */ +#define AUDIFDATA6 0x0720 /* DP0 Audio Info Frame Bytes 27 to 24 */ + +#define DP1_SRCCTRL 0x07a0 /* DP1 Control Register */ /* PHY */ #define DP_PHY_CTRL 0x0800 @@ -238,6 +290,25 @@ #define PHY_2LANE BIT(2) /* PHY Enable 2 lanes */ #define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */ #define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */ +#define DP_PHY_CFG_WR 0x0810 /* DP PHY Configuration Test Write Register */ +#define DP_PHY_CFG_RD 0x0814 /* DP PHY Configuration Test Read Register */ +#define DP0_AUX_PHY_CTRL 0x0820 /* DP0 AUX PHY Control Register */ +#define DP0_MAIN_PHY_DBG 0x0840 /* DP0 Main PHY Test Debug Register */ + +/* I2S */ +#define I2SCFG 0x0880 /* I2S Audio Config 0 Register */ +#define I2SCH0STAT0 0x0888 /* I2S Audio Channel 0 Status Bytes 3 to 0 */ +#define I2SCH0STAT1 0x088c /* I2S Audio Channel 0 Status Bytes 7 to 4 */ +#define I2SCH0STAT2 0x0890 /* I2S Audio Channel 0 Status Bytes 11 to 8 */ +#define I2SCH0STAT3 0x0894 /* I2S Audio Channel 0 Status Bytes 15 to 12 */ +#define I2SCH0STAT4 0x0898 /* I2S Audio Channel 0 Status Bytes 19 to 16 */ +#define I2SCH0STAT5 0x089c /* I2S Audio Channel 0 Status Bytes 23 to 20 */ +#define I2SCH1STAT0 0x08a0 /* I2S Audio Channel 1 Status Bytes 3 to 0 */ +#define I2SCH1STAT1 0x08a4 /* I2S Audio Channel 1 Status Bytes 7 to 4 */ +#define I2SCH1STAT2 0x08a8 /* I2S Audio Channel 1 Status Bytes 11 to 8 */ +#define I2SCH1STAT3 0x08ac /* I2S Audio Channel 1 Status Bytes 15 to 12 */ +#define I2SCH1STAT4 0x08b0 /* I2S Audio Channel 1 Status Bytes 19 to 16 */ +#define I2SCH1STAT5 0x08b4 /* I2S Audio Channel 1 Status Bytes 23 to 20 */ /* PLL */ #define DP0_PLLCTRL 0x0900 @@ -546,9 +617,14 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock) continue; for (i_post = 0; i_post < ARRAY_SIZE(ext_div); i_post++) { for (div = 1; div <= 16; div++) { - u32 clk; + u32 clk, iclk; u64 tmp; + /* PCLK PLL input unit clock ... 6..40 MHz */ + iclk = refclk / (div * ext_div[i_pre]); + if (iclk < 6000000 || iclk > 40000000) + continue; + tmp = pixelclock * ext_div[i_pre] * ext_div[i_post] * div; do_div(tmp, refclk); @@ -1575,19 +1651,19 @@ static void tc_bridge_mode_set(struct drm_bridge *bridge, drm_mode_copy(&tc->mode, mode); } -static struct edid *tc_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *tc_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct tc_data *tc = bridge_to_tc(bridge); - return drm_get_edid(connector, &tc->aux.ddc); + return drm_edid_read_ddc(connector, &tc->aux.ddc); } static int tc_connector_get_modes(struct drm_connector *connector) { struct tc_data *tc = connector_to_tc(connector); int num_modes; - struct edid *edid; + const struct drm_edid *drm_edid; int ret; ret = tc_get_display_props(tc); @@ -1602,9 +1678,10 @@ static int tc_connector_get_modes(struct drm_connector *connector) return num_modes; } - edid = tc_get_edid(&tc->bridge, connector); - num_modes = drm_add_edid_modes(connector, edid); - kfree(edid); + drm_edid = tc_edid_read(&tc->bridge, connector); + drm_edid_connector_update(connector, drm_edid); + num_modes = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return num_modes; } @@ -1773,7 +1850,7 @@ static const struct drm_bridge_funcs tc_edp_bridge_funcs = { .atomic_enable = tc_edp_bridge_atomic_enable, .atomic_disable = tc_edp_bridge_atomic_disable, .detect = tc_bridge_detect, - .get_edid = tc_get_edid, + .edid_read = tc_edid_read, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, @@ -1833,16 +1910,16 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg) case 0x1f4: /* DSI Protocol Layer */ case DSI_STARTDSI: - case 0x208: + case DSI_BUSYDSI: case DSI_LANEENABLE: - case 0x214: - case 0x218: - case 0x220: + case DSI_LANESTATUS0: + case DSI_LANESTATUS1: + case DSI_INTSTATUS: case 0x224: case 0x228: case 0x230: /* DSI General */ - case 0x300: + case DSIERRCNT: /* DSI Application Layer */ case 0x400: case 0x404: @@ -1978,13 +2055,20 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg) } static const struct regmap_range tc_volatile_ranges[] = { + regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI), + regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI), + regmap_reg_range(DSI_LANESTATUS0, DSI_INTSTATUS), + regmap_reg_range(DSIERRCNT, DSIERRCNT), + regmap_reg_range(VFUEN0, VFUEN0), + regmap_reg_range(SYSSTAT, SYSSTAT), + regmap_reg_range(GPIOI, GPIOI), + regmap_reg_range(INTSTS_G, INTSTS_G), + regmap_reg_range(DP0_VMNGENSTATUS, DP0_VMNGENSTATUS), + regmap_reg_range(DP0_AMNGENSTATUS, DP0_AMNGENSTATUS), regmap_reg_range(DP0_AUXWDATA(0), DP0_AUXSTATUS), regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), regmap_reg_range(DP_PHY_CTRL, DP_PHY_CTRL), regmap_reg_range(DP0_PLLCTRL, PXL_PLLCTRL), - regmap_reg_range(VFUEN0, VFUEN0), - regmap_reg_range(INTSTS_G, INTSTS_G), - regmap_reg_range(GPIOI, GPIOI), }; static const struct regmap_access_table tc_volatile_table = { @@ -1992,12 +2076,28 @@ static const struct regmap_access_table tc_volatile_table = { .n_yes_ranges = ARRAY_SIZE(tc_volatile_ranges), }; -static bool tc_writeable_reg(struct device *dev, unsigned int reg) -{ - return (reg != TC_IDREG) && - (reg != DP0_LTSTAT) && - (reg != DP0_SNKLTCHGREQ); -} +static const struct regmap_range tc_precious_ranges[] = { + regmap_reg_range(SYSSTAT, SYSSTAT), +}; + +static const struct regmap_access_table tc_precious_table = { + .yes_ranges = tc_precious_ranges, + .n_yes_ranges = ARRAY_SIZE(tc_precious_ranges), +}; + +static const struct regmap_range tc_non_writeable_ranges[] = { + regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI), + regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI), + regmap_reg_range(DSI_LANESTATUS0, DSI_INTSTATUS), + regmap_reg_range(TC_IDREG, SYSSTAT), + regmap_reg_range(GPIOI, GPIOI), + regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), +}; + +static const struct regmap_access_table tc_writeable_table = { + .no_ranges = tc_non_writeable_ranges, + .n_no_ranges = ARRAY_SIZE(tc_non_writeable_ranges), +}; static const struct regmap_config tc_regmap_config = { .name = "tc358767", @@ -2008,7 +2108,8 @@ static const struct regmap_config tc_regmap_config = { .cache_type = REGCACHE_MAPLE, .readable_reg = tc_readable_reg, .volatile_table = &tc_volatile_table, - .writeable_reg = tc_writeable_reg, + .precious_table = &tc_precious_table, + .wr_table = &tc_writeable_table, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_LITTLE, }; diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 62cc3893dca5d3eefbe853e95e863c7b0a0cdfdb..61dc6f063fb45aea7cd3d4b3fa20bb5f6379b35e 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1207,19 +1207,19 @@ static enum drm_connector_status ti_sn_bridge_detect(struct drm_bridge *bridge) : connector_status_disconnected; } -static struct edid *ti_sn_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *ti_sn_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); - return drm_get_edid(connector, &pdata->aux.ddc); + return drm_edid_read_ddc(connector, &pdata->aux.ddc); } static const struct drm_bridge_funcs ti_sn_bridge_funcs = { .attach = ti_sn_bridge_attach, .detach = ti_sn_bridge_detach, .mode_valid = ti_sn_bridge_mode_valid, - .get_edid = ti_sn_bridge_get_edid, + .edid_read = ti_sn_bridge_edid_read, .detect = ti_sn_bridge_detect, .atomic_pre_enable = ti_sn_bridge_atomic_pre_enable, .atomic_enable = ti_sn_bridge_atomic_enable, diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 28848a8eb42e847676e66eb2c3d51f004d5ee900..c7bef5c2392710dbe842778641aec7825f1b77ad 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -50,18 +50,20 @@ drm_connector_to_tfp410(struct drm_connector *connector) static int tfp410_get_modes(struct drm_connector *connector) { struct tfp410 *dvi = drm_connector_to_tfp410(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int ret; if (dvi->next_bridge->ops & DRM_BRIDGE_OP_EDID) { - edid = drm_bridge_get_edid(dvi->next_bridge, connector); - if (!edid) + drm_edid = drm_bridge_edid_read(dvi->next_bridge, connector); + if (!drm_edid) DRM_INFO("EDID read failed. Fallback to standard modes\n"); } else { - edid = NULL; + drm_edid = NULL; } - if (!edid) { + drm_edid_connector_update(connector, drm_edid); + + if (!drm_edid) { /* * No EDID, fallback on the XGA standard modes and prefer a mode * pretty much anything can handle. @@ -71,11 +73,9 @@ static int tfp410_get_modes(struct drm_connector *connector) return ret; } - drm_connector_update_edid_property(connector, edid); - - ret = drm_add_edid_modes(connector, edid); + ret = drm_edid_connector_add_modes(connector); - kfree(edid); + drm_edid_free(drm_edid); return ret; } diff --git a/drivers/gpu/drm/ci/build.sh b/drivers/gpu/drm/ci/build.sh index f73f3471e94e82e184004cc38c5318bd402dc7c6..106f2d40d222fe2d3af7d22186e6aaff35e3c5e1 100644 --- a/drivers/gpu/drm/ci/build.sh +++ b/drivers/gpu/drm/ci/build.sh @@ -26,6 +26,7 @@ if [[ "$KERNEL_ARCH" = "arm64" ]]; then DEVICE_TREES+=" arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper-sku16.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-limozeen-nots-r5.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtb" elif [[ "$KERNEL_ARCH" = "arm" ]]; then GCC_ARCH="arm-linux-gnueabihf" DEBIAN_ARCH="armhf" diff --git a/drivers/gpu/drm/ci/gitlab-ci.yml b/drivers/gpu/drm/ci/gitlab-ci.yml index dac92cc2777cc3a91a5e8e5a2aa073faeb71f360..084e3ff8e3f42df368537358e984f22c9ec5f0e0 100644 --- a/drivers/gpu/drm/ci/gitlab-ci.yml +++ b/drivers/gpu/drm/ci/gitlab-ci.yml @@ -1,6 +1,6 @@ variables: DRM_CI_PROJECT_PATH: &drm-ci-project-path mesa/mesa - DRM_CI_COMMIT_SHA: &drm-ci-commit-sha edfbf74df1d4d6ce54ffe24566108be0e1a98c3d + DRM_CI_COMMIT_SHA: &drm-ci-commit-sha 9d162de9a05155e1c4041857a5848842749164cf UPSTREAM_REPO: git://anongit.freedesktop.org/drm/drm TARGET_BRANCH: drm-next @@ -25,7 +25,9 @@ variables: # per-job artifact storage on MinIO JOB_ARTIFACTS_BASE: ${PIPELINE_ARTIFACTS_BASE}/${CI_JOB_ID} # default kernel for rootfs before injecting the current kernel tree - KERNEL_IMAGE_BASE: https://${S3_HOST}/mesa-lava/gfx-ci/linux/v6.4.12-for-mesa-ci-f6b4ad45f48d + KERNEL_REPO: "gfx-ci/linux" + KERNEL_TAG: "v6.6.4-for-mesa-ci-e4f4c500f7fb" + KERNEL_IMAGE_BASE: https://${S3_HOST}/mesa-lava/${KERNEL_REPO}/${KERNEL_TAG} LAVA_TAGS: subset-1-gfx LAVA_JOB_PRIORITY: 30 @@ -133,6 +135,11 @@ stages: - if: &is-pre-merge-for-marge '$GITLAB_USER_LOGIN == "marge-bot" && $CI_PIPELINE_SOURCE == "merge_request_event"' when: on_success +.never-post-merge-rules: + rules: + - if: *is-post-merge + when: never + # Rule to filter for only scheduled pipelines. .scheduled_pipeline-rules: rules: @@ -150,6 +157,7 @@ stages: .build-rules: rules: - !reference [.no_scheduled_pipelines-rules, rules] + - !reference [.never-post-merge-rules, rules] # Run automatically once all dependency jobs have passed - when: on_success @@ -157,6 +165,7 @@ stages: .container+build-rules: rules: - !reference [.no_scheduled_pipelines-rules, rules] + - !reference [.never-post-merge-rules, rules] - when: manual .ci-deqp-artifacts: @@ -175,6 +184,7 @@ stages: .container-rules: rules: - !reference [.no_scheduled_pipelines-rules, rules] + - !reference [.never-post-merge-rules, rules] # Run pipeline by default in the main project if any CI pipeline # configuration files were changed, to ensure docker images are up to date - if: *is-post-merge diff --git a/drivers/gpu/drm/ci/test.yml b/drivers/gpu/drm/ci/test.yml index 2c9a1838e7284c93c43296f52a6c9157c749a840..0857773e5c5fdfc039c78b28bf6915af1dd4b9dd 100644 --- a/drivers/gpu/drm/ci/test.yml +++ b/drivers/gpu/drm/ci/test.yml @@ -82,20 +82,35 @@ tags: - $RUNNER_TAG -msm:sc7180: +.msm-sc7180: extends: - .lava-igt:arm64 stage: msm - parallel: 4 variables: DRIVER_NAME: msm - DEVICE_TYPE: sc7180-trogdor-lazor-limozeen - DTB: sc7180-trogdor-lazor-limozeen-nots-r5 BOOT_METHOD: depthcharge KERNEL_IMAGE_TYPE: "" - GPU_VERSION: sc7180 + +msm:sc7180-trogdor-lazor-limozeen: + extends: + - .msm-sc7180 + parallel: 4 + variables: + DEVICE_TYPE: sc7180-trogdor-lazor-limozeen + DTB: sc7180-trogdor-lazor-limozeen-nots-r5 + GPU_VERSION: ${DEVICE_TYPE} RUNNER_TAG: mesa-ci-x86-64-lava-sc7180-trogdor-lazor-limozeen +msm:sc7180-trogdor-kingoftown: + extends: + - .msm-sc7180 + parallel: 6 + variables: + DEVICE_TYPE: sc7180-trogdor-kingoftown + DTB: sc7180-trogdor-kingoftown + GPU_VERSION: ${DEVICE_TYPE} + RUNNER_TAG: mesa-ci-x86-64-lava-sc7180-trogdor-kingoftown + msm:apq8016: extends: - .baremetal-igt-arm64 @@ -104,7 +119,10 @@ msm:apq8016: DRIVER_NAME: msm BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/apq8016-sbc-usb-host.dtb GPU_VERSION: apq8016 - BM_CMDLINE: "ip=dhcp console=ttyMSM0,115200n8 $BM_KERNEL_EXTRA_ARGS root=/dev/nfs rw nfsrootdebug nfsroot=,tcp,nfsvers=4.2 init=/init $BM_KERNELARGS" + # disabling unused clocks congests with the MDSS runtime PM trying to + # disable those clocks and causes boot to fail. + # Reproducer: DRM_MSM=y, DRM_I2C_ADV7511=m + BM_KERNEL_EXTRA_ARGS: clk_ignore_unused RUNNER_TAG: google-freedreno-db410c script: - ./install/bare-metal/fastboot.sh @@ -324,6 +342,7 @@ virtio_gpu:none: GPU_VERSION: none extends: - .test-gl + - .test-rules tags: - kvm script: diff --git a/drivers/gpu/drm/ci/testlist.txt b/drivers/gpu/drm/ci/testlist.txt index f82cd90372f4a4e6f82bd18f5e64a42e4585bad4..eaeb751bb0ad61da172ca4e4601cbfd0027d1340 100644 --- a/drivers/gpu/drm/ci/testlist.txt +++ b/drivers/gpu/drm/ci/testlist.txt @@ -2910,3 +2910,52 @@ kms_writeback@writeback-invalid-parameters kms_writeback@writeback-fb-id kms_writeback@writeback-check-output prime_mmap_kms@buffer-sharing +msm_shrink@copy-gpu-sanitycheck-8 +msm_shrink@copy-gpu-sanitycheck-32 +msm_shrink@copy-gpu-8 +msm_shrink@copy-gpu-32 +msm_shrink@copy-gpu-madvise-8 +msm_shrink@copy-gpu-madvise-32 +msm_shrink@copy-gpu-oom-8 +msm_shrink@copy-gpu-oom-32 +msm_shrink@copy-mmap-sanitycheck-8 +msm_shrink@copy-mmap-sanitycheck-32 +msm_shrink@copy-mmap-8 +msm_shrink@copy-mmap-32 +msm_shrink@copy-mmap-madvise-8 +msm_shrink@copy-mmap-madvise-32 +msm_shrink@copy-mmap-oom-8 +msm_shrink@copy-mmap-oom-32 +msm_shrink@copy-mmap-dmabuf-sanitycheck-8 +msm_shrink@copy-mmap-dmabuf-sanitycheck-32 +msm_shrink@copy-mmap-dmabuf-8 +msm_shrink@copy-mmap-dmabuf-32 +msm_shrink@copy-mmap-dmabuf-madvise-8 +msm_shrink@copy-mmap-dmabuf-madvise-32 +msm_shrink@copy-mmap-dmabuf-oom-8 +msm_shrink@copy-mmap-dmabuf-oom-32 +msm_mapping@ring +msm_mapping@sqefw +msm_mapping@shadow +msm_submitoverhead@submitbench-10-bos +msm_submitoverhead@submitbench-10-bos-no-implicit-sync +msm_submitoverhead@submitbench-100-bos +msm_submitoverhead@submitbench-100-bos-no-implicit-sync +msm_submitoverhead@submitbench-250-bos +msm_submitoverhead@submitbench-250-bos-no-implicit-sync +msm_submitoverhead@submitbench-500-bos +msm_submitoverhead@submitbench-500-bos-no-implicit-sync +msm_submitoverhead@submitbench-1000-bos +msm_submitoverhead@submitbench-1000-bos-no-implicit-sync +msm_recovery@hangcheck +msm_recovery@gpu-fault +msm_recovery@gpu-fault-parallel +msm_recovery@iova-fault +msm_submit@empty-submit +msm_submit@invalid-queue-submit +msm_submit@invalid-flags-submit +msm_submit@invalid-in-fence-submit +msm_submit@invalid-duplicate-bo-submit +msm_submit@invalid-cmd-idx-submit +msm_submit@invalid-cmd-type-submit +msm_submit@valid-submit diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt index d39d254c935e9ac56f69de73b03d6259908d84cb..44a5c62dedad98c12cf8d2a194eeba811af4bb7e 100644 --- a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt +++ b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt @@ -6,8 +6,6 @@ kms_cursor_legacy@all-pipes-single-bo,Fail kms_cursor_legacy@all-pipes-single-move,Fail kms_cursor_legacy@all-pipes-torture-bo,Fail kms_cursor_legacy@all-pipes-torture-move,Fail -kms_cursor_legacy@forked-bo,Fail -kms_cursor_legacy@forked-move,Fail kms_cursor_legacy@pipe-A-forked-bo,Fail kms_cursor_legacy@pipe-A-forked-move,Fail kms_cursor_legacy@pipe-A-single-bo,Fail @@ -18,3 +16,4 @@ kms_force_connector_basic@force-edid,Fail kms_hdmi_inject@inject-4k,Fail kms_selftest@drm_format,Timeout kms_selftest@drm_format_helper,Timeout +msm_mapping@ring,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-fails.txt deleted file mode 100644 index f71166a577316f76a7b78e92f759d5c157ca42c3..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/ci/xfails/msm-sc7180-fails.txt +++ /dev/null @@ -1,30 +0,0 @@ -kms_color@ctm-0-25,Fail -kms_color@ctm-0-50,Fail -kms_color@ctm-0-75,Fail -kms_color@ctm-blue-to-red,Fail -kms_color@ctm-green-to-red,Fail -kms_color@ctm-negative,Fail -kms_color@ctm-red-to-blue,Fail -kms_color@ctm-signed,Fail -kms_cursor_legacy@cursor-vs-flip-toggle,Fail -kms_cursor_legacy@cursor-vs-flip-varying-size,Fail -kms_cursor_legacy@cursorA-vs-flipA-atomic-transitions,Crash -kms_flip@flip-vs-modeset-vs-hang,Fail -kms_flip@flip-vs-panning-vs-hang,Fail -kms_pipe_crc_basic@compare-crc-sanitycheck-nv12,Fail -kms_plane_alpha_blend@alpha-7efc,Fail -kms_plane_alpha_blend@coverage-7efc,Fail -kms_plane_alpha_blend@coverage-vs-premult-vs-constant,Fail -kms_plane_alpha_blend@pipe-A-alpha-7efc,Fail -kms_plane_alpha_blend@pipe-A-coverage-7efc,Fail -kms_plane_alpha_blend@pipe-A-coverage-vs-premult-vs-constant,Fail -kms_plane_alpha_blend@pipe-B-alpha-7efc,Fail -kms_plane_alpha_blend@pipe-B-alpha-basic,Fail -kms_plane_alpha_blend@pipe-B-alpha-opaque-fb,Fail -kms_plane_alpha_blend@pipe-B-constant-alpha-max,Fail -kms_plane_alpha_blend@pipe-B-constant-alpha-mid,Fail -kms_plane_alpha_blend@pipe-B-coverage-7efc,Fail -kms_plane_alpha_blend@pipe-B-coverage-vs-premult-vs-constant,Fail -kms_rmfb@close-fd,Fail -kms_universal_plane@disable-primary-vs-flip-pipe-b,Fail -kms_universal_plane@universal-plane-pipe-B-sanity,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-flakes.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-flakes.txt deleted file mode 100644 index 04730044ed12489e6a647f0874687aad7ebc5a4d..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/ci/xfails/msm-sc7180-flakes.txt +++ /dev/null @@ -1,17 +0,0 @@ -kms_color@ctm-0-25 -kms_color@ctm-0-50 -kms_color@ctm-0-75 -kms_color@ctm-blue-to-red -kms_color@ctm-green-to-red -kms_color@ctm-negative -kms_color@ctm-red-to-blue -kms_color@ctm-signed -kms_flip@flip-vs-modeset-vs-hang -kms_flip@flip-vs-panning-vs-hang -kms_plane@pixel-format -kms_plane@pixel-format-source-clamping -kms_plane@plane-position-covered -kms_plane@plane-position-hole -kms_plane@plane-position-hole-dpms -kms_writeback@writeback-fb-id -kms_writeback@writeback-invalid-parameters diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-skips.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-skips.txt deleted file mode 100644 index e59a2fddfde04160c4209cb641b764939de381fd..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/ci/xfails/msm-sc7180-skips.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Suspend to RAM seems to be broken on this machine -.*suspend.* - -# Test incorrectly assumes that CTM support implies gamma/degamma -# LUT support. None of the subtests handle the case of only having -# CTM support -#kms_color.* diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-kingoftown-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-kingoftown-fails.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e4d8744fcc6cc84dc0fb76d6a35e2e9b4a15ee4 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-kingoftown-fails.txt @@ -0,0 +1,17 @@ +kms_color@ctm-0-25,Fail +kms_color@ctm-0-50,Fail +kms_color@ctm-0-75,Fail +kms_color@ctm-blue-to-red,Fail +kms_color@ctm-green-to-red,Fail +kms_color@ctm-negative,Fail +kms_color@ctm-red-to-blue,Fail +kms_color@ctm-signed,Fail +kms_cursor_legacy@cursor-vs-flip-toggle,Fail +kms_cursor_legacy@cursor-vs-flip-varying-size,Fail +kms_flip@flip-vs-modeset-vs-hang,Fail +kms_flip@flip-vs-panning-vs-hang,Fail +kms_pipe_crc_basic@compare-crc-sanitycheck-nv12,Fail +kms_plane_alpha_blend@alpha-7efc,Fail +kms_plane_alpha_blend@coverage-7efc,Fail +kms_plane_alpha_blend@coverage-vs-premult-vs-constant,Fail +kms_rmfb@close-fd,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-lazor-limozeen-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-lazor-limozeen-fails.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e4d8744fcc6cc84dc0fb76d6a35e2e9b4a15ee4 --- /dev/null +++ b/drivers/gpu/drm/ci/xfails/msm-sc7180-trogdor-lazor-limozeen-fails.txt @@ -0,0 +1,17 @@ +kms_color@ctm-0-25,Fail +kms_color@ctm-0-50,Fail +kms_color@ctm-0-75,Fail +kms_color@ctm-blue-to-red,Fail +kms_color@ctm-green-to-red,Fail +kms_color@ctm-negative,Fail +kms_color@ctm-red-to-blue,Fail +kms_color@ctm-signed,Fail +kms_cursor_legacy@cursor-vs-flip-toggle,Fail +kms_cursor_legacy@cursor-vs-flip-varying-size,Fail +kms_flip@flip-vs-modeset-vs-hang,Fail +kms_flip@flip-vs-panning-vs-hang,Fail +kms_pipe_crc_basic@compare-crc-sanitycheck-nv12,Fail +kms_plane_alpha_blend@alpha-7efc,Fail +kms_plane_alpha_blend@coverage-7efc,Fail +kms_plane_alpha_blend@coverage-vs-premult-vs-constant,Fail +kms_rmfb@close-fd,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sdm845-fails.txt b/drivers/gpu/drm/ci/xfails/msm-sdm845-fails.txt index c55baa2d18c1b1a4bf4e2c0b860519921320c30f..e9043a00383efc03ce23bd485bda744681edf046 100644 --- a/drivers/gpu/drm/ci/xfails/msm-sdm845-fails.txt +++ b/drivers/gpu/drm/ci/xfails/msm-sdm845-fails.txt @@ -15,7 +15,7 @@ kms_color@pipe-A-ctm-max,Fail kms_color@pipe-A-ctm-negative,Fail kms_color@pipe-A-ctm-red-to-blue,Fail kms_color@pipe-A-legacy-gamma,Fail -kms_cursor_legacy@basic-flip-after-cursor-legacy,Fail +kms_cursor_legacy@basic-flip-after-cursor-atomic,Fail kms_cursor_legacy@basic-flip-after-cursor-varying-size,Fail kms_cursor_legacy@basic-flip-before-cursor-atomic,Fail kms_cursor_legacy@basic-flip-before-cursor-legacy,Fail @@ -29,9 +29,6 @@ kms_cursor_legacy@flip-vs-cursor-atomic,Fail kms_cursor_legacy@flip-vs-cursor-crc-atomic,Fail kms_cursor_legacy@flip-vs-cursor-crc-legacy,Fail kms_cursor_legacy@flip-vs-cursor-legacy,Fail -kms_cursor_legacy@short-flip-after-cursor-atomic-transitions,Fail -kms_cursor_legacy@short-flip-after-cursor-atomic-transitions-varying-size,Fail -kms_cursor_legacy@short-flip-after-cursor-toggle,Fail kms_flip@flip-vs-modeset-vs-hang,Fail kms_flip@flip-vs-panning-vs-hang,Fail kms_pipe_crc_basic@compare-crc-sanitycheck-nv12,Fail diff --git a/drivers/gpu/drm/ci/xfails/msm-sdm845-flakes.txt b/drivers/gpu/drm/ci/xfails/msm-sdm845-flakes.txt index 16d205c04cbbf186e8be3aef10c1edccb1a5bb80..8a492f01eaa4ac3189aaaeaa620203a796557583 100644 --- a/drivers/gpu/drm/ci/xfails/msm-sdm845-flakes.txt +++ b/drivers/gpu/drm/ci/xfails/msm-sdm845-flakes.txt @@ -1,12 +1,22 @@ -kms_cursor_legacy@basic-flip-after-cursor-atomic -kms_cursor_legacy@basic-flip-before-cursor-varying-size -kms_cursor_legacy@cursorA-vs-flipA-toggle -kms_cursor_legacy@flip-vs-cursor-atomic-transitions +# Board Name: msm:sdm845 +# Bug Report: https://lore.kernel.org/dri-devel/46287831-edfa-78e8-6055-d7a08831c445@collabora.com/T/#u +# Failure Rate: 50 +# IGT Version: 1.28-gd2af13d9f +# Linux Version: 6.7.0-rc3 + +# Reported by deqp-runner +kms_cursor_legacy@basic-flip-after-cursor-legacy kms_cursor_legacy@flip-vs-cursor-toggle kms_cursor_legacy@flip-vs-cursor-varying-size +kms_cursor_legacy@short-flip-after-cursor-toggle kms_cursor_legacy@short-flip-before-cursor-atomic-transitions -kms_cursor_legacy@short-flip-before-cursor-toggle -kms_flip@flip-vs-modeset-vs-hang -kms_flip@flip-vs-panning-vs-hang -kms_plane@pixel-format -kms_plane@pixel-format-source-clamping +kms_cursor_legacy@short-flip-before-cursor-atomic-transitions-varying-size +msm_shrink@copy-gpu-32 +msm_shrink@copy-gpu-oom-32 + +# The below test shows inconsistency across multiple runs, giving +# results of Pass and Fail alternately. +kms_cursor_legacy@basic-flip-before-cursor-varying-size +kms_cursor_legacy@flip-vs-cursor-atomic-transitions +kms_cursor_legacy@short-flip-after-cursor-atomic-transitions +kms_cursor_legacy@short-flip-after-cursor-atomic-transitions-varying-size diff --git a/drivers/gpu/drm/ci/xfails/msm-sdm845-skips.txt b/drivers/gpu/drm/ci/xfails/msm-sdm845-skips.txt index 42675f1c6d762c819390744c9c0dfec92cb3e203..618e3a3a7277721d91abbfbf9ef30092fbb7e6c4 100644 --- a/drivers/gpu/drm/ci/xfails/msm-sdm845-skips.txt +++ b/drivers/gpu/drm/ci/xfails/msm-sdm845-skips.txt @@ -1,2 +1,7 @@ # Hangs machine -kms_bw.* \ No newline at end of file +kms_bw.* + +# Failing due to a bootloader/fw issue. The workaround in mesa CI involves these two patches +# https://gitlab.freedesktop.org/gfx-ci/linux/-/commit/4b49f902ec6f2bb382cbbf489870573f4b43371e +# https://gitlab.freedesktop.org/gfx-ci/linux/-/commit/38cdf4c5559771e2474ae0fecef8469f65147bc1 +msm_mapping@* diff --git a/drivers/gpu/drm/display/drm_dp_aux_bus.c b/drivers/gpu/drm/display/drm_dp_aux_bus.c index 8a165be1a82144fc0c766286eec12cda3d38e794..5afc26be9d2a958fee70876795be27e71595bf22 100644 --- a/drivers/gpu/drm/display/drm_dp_aux_bus.c +++ b/drivers/gpu/drm/display/drm_dp_aux_bus.c @@ -127,7 +127,7 @@ static void dp_aux_ep_shutdown(struct device *dev) aux_ep_drv->shutdown(to_dp_aux_ep_dev(dev)); } -static struct bus_type dp_aux_bus_type = { +static const struct bus_type dp_aux_bus_type = { .name = "dp-aux", .match = dp_aux_ep_match, .probe = dp_aux_ep_probe, diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index b1ca3a1100dabbbad98279a65654a85266953e30..8d6ce46471ae6161c601ae0488fb65dda48f396b 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2897,22 +2897,19 @@ static const char *dp_content_type_get_name(enum dp_content_type content_type) } } -void drm_dp_vsc_sdp_log(const char *level, struct device *dev, - const struct drm_dp_vsc_sdp *vsc) +void drm_dp_vsc_sdp_log(struct drm_printer *p, const struct drm_dp_vsc_sdp *vsc) { -#define DP_SDP_LOG(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__) - DP_SDP_LOG("DP SDP: %s, revision %u, length %u\n", "VSC", + drm_printf(p, "DP SDP: VSC, revision %u, length %u\n", vsc->revision, vsc->length); - DP_SDP_LOG(" pixelformat: %s\n", + drm_printf(p, " pixelformat: %s\n", dp_pixelformat_get_name(vsc->pixelformat)); - DP_SDP_LOG(" colorimetry: %s\n", + drm_printf(p, " colorimetry: %s\n", dp_colorimetry_get_name(vsc->pixelformat, vsc->colorimetry)); - DP_SDP_LOG(" bpc: %u\n", vsc->bpc); - DP_SDP_LOG(" dynamic range: %s\n", + drm_printf(p, " bpc: %u\n", vsc->bpc); + drm_printf(p, " dynamic range: %s\n", dp_dynamic_range_get_name(vsc->dynamic_range)); - DP_SDP_LOG(" content type: %s\n", + drm_printf(p, " content type: %s\n", dp_content_type_get_name(vsc->content_type)); -#undef DP_SDP_LOG } EXPORT_SYMBOL(drm_dp_vsc_sdp_log); diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index bd6c24d4213cdf2f6bcb132848330f43e4546efd..03d528209426214530bc81c752a7d6319f01168b 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -1306,7 +1306,8 @@ static int drm_dp_mst_wait_tx_reply(struct drm_dp_mst_branch *mstb, } out: if (unlikely(ret == -EIO) && drm_debug_enabled(DRM_UT_DP)) { - struct drm_printer p = drm_debug_printer(DBG_PREFIX); + struct drm_printer p = drm_dbg_printer(mgr->dev, DRM_UT_DP, + DBG_PREFIX); drm_dp_mst_dump_sideband_msg_tx(&p, txmsg); } @@ -1593,10 +1594,11 @@ topology_ref_type_to_str(enum drm_dp_mst_topology_ref_type type) } static void -__dump_topology_ref_history(struct drm_dp_mst_topology_ref_history *history, +__dump_topology_ref_history(struct drm_device *drm, + struct drm_dp_mst_topology_ref_history *history, void *ptr, const char *type_str) { - struct drm_printer p = drm_debug_printer(DBG_PREFIX); + struct drm_printer p = drm_dbg_printer(drm, DRM_UT_DP, DBG_PREFIX); char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); int i; @@ -1638,15 +1640,15 @@ out: static __always_inline void drm_dp_mst_dump_mstb_topology_history(struct drm_dp_mst_branch *mstb) { - __dump_topology_ref_history(&mstb->topology_ref_history, mstb, - "MSTB"); + __dump_topology_ref_history(mstb->mgr->dev, &mstb->topology_ref_history, + mstb, "MSTB"); } static __always_inline void drm_dp_mst_dump_port_topology_history(struct drm_dp_mst_port *port) { - __dump_topology_ref_history(&port->topology_ref_history, port, - "Port"); + __dump_topology_ref_history(port->mgr->dev, &port->topology_ref_history, + port, "Port"); } static __always_inline void @@ -2824,7 +2826,9 @@ static int process_single_tx_qlock(struct drm_dp_mst_topology_mgr *mgr, ret = drm_dp_send_sideband_msg(mgr, up, chunk, idx); if (ret) { if (drm_debug_enabled(DRM_UT_DP)) { - struct drm_printer p = drm_debug_printer(DBG_PREFIX); + struct drm_printer p = drm_dbg_printer(mgr->dev, + DRM_UT_DP, + DBG_PREFIX); drm_printf(&p, "sideband msg failed to send\n"); drm_dp_mst_dump_sideband_msg_tx(&p, txmsg); @@ -2869,7 +2873,8 @@ static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr, list_add_tail(&txmsg->next, &mgr->tx_msg_downq); if (drm_debug_enabled(DRM_UT_DP)) { - struct drm_printer p = drm_debug_printer(DBG_PREFIX); + struct drm_printer p = drm_dbg_printer(mgr->dev, DRM_UT_DP, + DBG_PREFIX); drm_dp_mst_dump_sideband_msg_tx(&p, txmsg); } @@ -5491,6 +5496,7 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); * - 0 if the new state is valid * - %-ENOSPC, if the new state is invalid, because of BW limitation * @failing_port is set to: + * * - The non-root port where a BW limit check failed * with all the ports downstream of @failing_port passing * the BW limit check. @@ -5499,6 +5505,7 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); * - %NULL if the BW limit check failed at the root port * with all the ports downstream of the root port passing * the BW limit check. + * * - %-EINVAL, if the new state is invalid, because the root port has * too many payloads. */ diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index cee3188adf3d54bca2b6cb22e51329295d980589..521a71c61b16453a3651ecb2aa73f11344b85f89 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -27,8 +27,9 @@ #include #include -#include #include +#include +#include #include #include #include @@ -1207,26 +1208,26 @@ int drm_bridge_get_modes(struct drm_bridge *bridge, EXPORT_SYMBOL_GPL(drm_bridge_get_modes); /** - * drm_bridge_get_edid - get the EDID data of the connected display + * drm_bridge_edid_read - read the EDID data of the connected display * @bridge: bridge control structure * @connector: the connector to read EDID for * * If the bridge supports output EDID retrieval, as reported by the - * DRM_BRIDGE_OP_EDID bridge ops flag, call &drm_bridge_funcs.get_edid to - * get the EDID and return it. Otherwise return NULL. + * DRM_BRIDGE_OP_EDID bridge ops flag, call &drm_bridge_funcs.edid_read to get + * the EDID and return it. Otherwise return NULL. * * RETURNS: * The retrieved EDID on success, or NULL otherwise. */ -struct edid *drm_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +const struct drm_edid *drm_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { if (!(bridge->ops & DRM_BRIDGE_OP_EDID)) return NULL; - return bridge->funcs->get_edid(bridge, connector); + return bridge->funcs->edid_read(bridge, connector); } -EXPORT_SYMBOL_GPL(drm_bridge_get_edid); +EXPORT_SYMBOL_GPL(drm_bridge_edid_read); /** * drm_bridge_hpd_enable - enable hot plug detection for the bridge diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 3acd67021ec62fbb4699cd7b05e97c3632d36511..982552c9f92c935666593b5dea050579ef4bb708 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -239,27 +239,27 @@ static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector, struct drm_bridge *bridge) { enum drm_connector_status status; - struct edid *edid; + const struct drm_edid *drm_edid; int n; status = drm_bridge_connector_detect(connector, false); if (status != connector_status_connected) goto no_edid; - edid = drm_bridge_get_edid(bridge, connector); - if (!drm_edid_is_valid(edid)) { - kfree(edid); + drm_edid = drm_bridge_edid_read(bridge, connector); + if (!drm_edid_valid(drm_edid)) { + drm_edid_free(drm_edid); goto no_edid; } - drm_connector_update_edid_property(connector, edid); - n = drm_add_edid_modes(connector, edid); + drm_edid_connector_update(connector, drm_edid); + n = drm_edid_connector_add_modes(connector); - kfree(edid); + drm_edid_free(drm_edid); return n; no_edid: - drm_connector_update_edid_property(connector, NULL); + drm_edid_connector_update(connector, NULL); return 0; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index cb90e70d85e862a495f2e8691813161a93b7a030..a4d25b0e5c9171b8bfaf3ce2547ec7fb5eb7f008 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -61,13 +61,13 @@ * to one or more &drm_encoder, which are then each connected to one * &drm_connector. * - * To create a CRTC, a KMS drivers allocates and zeroes an instances of + * To create a CRTC, a KMS driver allocates and zeroes an instance of * &struct drm_crtc (possibly as part of a larger structure) and registers it * with a call to drm_crtc_init_with_planes(). * - * The CRTC is also the entry point for legacy modeset operations, see - * &drm_crtc_funcs.set_config, legacy plane operations, see - * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy + * The CRTC is also the entry point for legacy modeset operations (see + * &drm_crtc_funcs.set_config), legacy plane operations (see + * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2), and other legacy * operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these * features are controlled through &drm_property and * &drm_mode_config_funcs.atomic_check. diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index f4715a67e340d3f5fdd9ee8f8801af677040d25c..08fcefd804bc09a730e760f9074efffba8685e13 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -45,8 +45,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#if defined(CONFIG_DEBUG_FS) - /*************************************************** * Initialization, etc. **************************************************/ @@ -647,5 +645,3 @@ void drm_debugfs_encoder_remove(struct drm_encoder *encoder) debugfs_remove_recursive(encoder->debugfs_entry); encoder->debugfs_entry = NULL; } - -#endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 69c68804023ff9a959e482d8c7ac5176f1ab34e1..923c4423151c1eb2c8ce635940898fc01db63825 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3611,7 +3611,8 @@ static bool mode_in_range(const struct drm_display_mode *mode, if (!mode_in_vsync_range(mode, edid, t)) return false; - if ((max_clock = range_pixel_clock(edid, t))) + max_clock = range_pixel_clock(edid, t); + if (max_clock) if (mode->clock > max_clock) return false; @@ -6990,28 +6991,6 @@ int drm_add_modes_noedid(struct drm_connector *connector, } EXPORT_SYMBOL(drm_add_modes_noedid); -/** - * drm_set_preferred_mode - Sets the preferred mode of a connector - * @connector: connector whose mode list should be processed - * @hpref: horizontal resolution of preferred mode - * @vpref: vertical resolution of preferred mode - * - * Marks a mode as preferred if it matches the resolution specified by @hpref - * and @vpref. - */ -void drm_set_preferred_mode(struct drm_connector *connector, - int hpref, int vpref) -{ - struct drm_display_mode *mode; - - list_for_each_entry(mode, &connector->probed_modes, head) { - if (mode->hdisplay == hpref && - mode->vdisplay == vpref) - mode->type |= DRM_MODE_TYPE_PREFERRED; - } -} -EXPORT_SYMBOL(drm_set_preferred_mode); - static bool is_hdmi2_sink(const struct drm_connector *connector) { /* diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index 48ee851b61d904b7661095f8e0393e4fc0973035..2da094bdf8a4d282742943500ab84b785fa8e334 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -76,7 +76,7 @@ static void drm_exec_unlock_all(struct drm_exec *exec) * If nr is non-zero then it is used as the initial objects table size. * In either case, the table will grow (be re-allocated) on demand. */ -void drm_exec_init(struct drm_exec *exec, uint32_t flags, unsigned nr) +void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr) { if (!nr) nr = PAGE_SIZE / sizeof(void *); diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index b67eafa557159eb59d0142d7ef3062cff3488a98..75f2eaf0d5b610c2f9eb0b85b911676ba7e47b63 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -147,7 +147,6 @@ static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo, invariant_flags = TTM_PL_FLAG_TOPDOWN; gbo->placement.placement = gbo->placements; - gbo->placement.busy_placement = gbo->placements; if (pl_flag & DRM_GEM_VRAM_PL_FLAG_VRAM) { gbo->placements[c].mem_type = TTM_PL_VRAM; @@ -160,7 +159,6 @@ static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo, } gbo->placement.num_placement = c; - gbo->placement.num_busy_placement = c; for (i = 0; i < c; ++i) { gbo->placements[i].fpfn = 0; diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 129e2b91dbfe7f785a821c165db0c0b88ff4b1c9..e6b5b06de1487be0f9b0a08892e341a49750534b 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -229,7 +229,7 @@ typedef struct drm_update_draw32 { unsigned int num; /* 64-bit version has a 32-bit pad here */ u64 data; /**< Pointer */ -} __attribute__((packed)) drm_update_draw32_t; +} __packed drm_update_draw32_t; static int compat_drm_update_draw(struct file *file, unsigned int cmd, unsigned long arg) @@ -296,7 +296,7 @@ typedef struct drm_mode_fb_cmd232 { u32 pitches[4]; u32 offsets[4]; u64 modifier[4]; -} __attribute__((packed)) drm_mode_fb_cmd232_t; +} __packed drm_mode_fb_cmd232_t; static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd, unsigned long arg) diff --git a/drivers/gpu/drm/drm_managed.c b/drivers/gpu/drm/drm_managed.c index bcd111404b128aacb5081cfb4a489dab636923e2..7646f67bda4e47bf9f1a233e107d080f3e25770f 100644 --- a/drivers/gpu/drm/drm_managed.c +++ b/drivers/gpu/drm/drm_managed.c @@ -176,6 +176,45 @@ int __drmm_add_action_or_reset(struct drm_device *dev, } EXPORT_SYMBOL(__drmm_add_action_or_reset); +/** + * drmm_release_action - release a managed action from a &drm_device + * @dev: DRM device + * @action: function which would be called when @dev is released + * @data: opaque pointer, passed to @action + * + * This function calls the @action previously added by drmm_add_action() + * immediately. + * The @action is removed from the list of cleanup actions for @dev, + * which means that it won't be called in the final drm_dev_put(). + */ +void drmm_release_action(struct drm_device *dev, + drmres_release_t action, + void *data) +{ + struct drmres *dr_match = NULL, *dr; + unsigned long flags; + + spin_lock_irqsave(&dev->managed.lock, flags); + list_for_each_entry_reverse(dr, &dev->managed.resources, node.entry) { + if (dr->node.release == action) { + if (!data || (data && *(void **)dr->data == data)) { + dr_match = dr; + del_dr(dev, dr_match); + break; + } + } + } + spin_unlock_irqrestore(&dev->managed.lock, flags); + + if (WARN_ON(!dr_match)) + return; + + action(dev, data); + + free_dr(dr_match); +} +EXPORT_SYMBOL(drmm_release_action); + /** * drmm_kmalloc - &drm_device managed kmalloc() * @dev: DRM device diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 843a6dbda93a07724ce3271584746c34ffd29747..ef6e416522f8a96f3216546541fc4e2b7fbbb0d2 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -89,7 +89,7 @@ static const struct dev_pm_ops mipi_dsi_device_pm_ops = { .restore = pm_generic_restore, }; -static struct bus_type mipi_dsi_bus_type = { +static const struct bus_type mipi_dsi_bus_type = { .name = "mipi-dsi", .match = mipi_dsi_device_match, .uevent = mipi_dsi_uevent, diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 8525ef8515406ba956bed80d8e365cce82dd686d..48fd2d67f352f4ed3788ecb69d0e6249bde8b702 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -544,7 +544,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) */ WARN_ON(!list_empty(&dev->mode_config.fb_list)); list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { - struct drm_printer p = drm_debug_printer("[leaked fb]"); + struct drm_printer p = drm_dbg_printer(dev, DRM_UT_KMS, "[leaked fb]"); drm_printf(&p, "framebuffer[%u]:\n", fb->base.id); drm_framebuffer_print_info(&p, 1, fb); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 893f52ee492610e11ebb5ded63d1cc7683e81b31..c4f88c3a93b7a98baac9b7deed397b08a8f6dfca 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2752,3 +2752,25 @@ bool drm_mode_is_420(const struct drm_display_info *display, drm_mode_is_420_also(display, mode); } EXPORT_SYMBOL(drm_mode_is_420); + +/** + * drm_set_preferred_mode - Sets the preferred mode of a connector + * @connector: connector whose mode list should be processed + * @hpref: horizontal resolution of preferred mode + * @vpref: vertical resolution of preferred mode + * + * Marks a mode as preferred if it matches the resolution specified by @hpref + * and @vpref. + */ +void drm_set_preferred_mode(struct drm_connector *connector, + int hpref, int vpref) +{ + struct drm_display_mode *mode; + + list_for_each_entry(mode, &connector->probed_modes, head) { + if (mode->hdisplay == hpref && + mode->vdisplay == vpref) + mode->type |= DRM_MODE_TYPE_PREFERRED; + } +} +EXPORT_SYMBOL(drm_set_preferred_mode); diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 918065982db4614d7d3b62f9356804053e5ae60c..7694b85e75e3ebd6b2bb081ccd5bc00ee48122b3 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -91,7 +91,7 @@ static noinline depot_stack_handle_t __drm_stack_depot_save(void) static void __drm_stack_depot_print(depot_stack_handle_t stack_depot) { - struct drm_printer p = drm_debug_printer("drm_modeset_lock"); + struct drm_printer p = drm_dbg_printer(NULL, DRM_UT_KMS, "drm_modeset_lock"); unsigned long *entries; unsigned int nr_entries; char *buf; diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index 3d92f66e550c3885d1639c9450487228758afd76..aa93129c3397e40c67027d2098d8e6dd1a875932 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -117,6 +117,12 @@ static const struct drm_dmi_panel_orientation_data lcd1080x1920_leftside_up = { .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, }; +static const struct drm_dmi_panel_orientation_data lcd1080x1920_rightside_up = { + .width = 1080, + .height = 1920, + .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, +}; + static const struct drm_dmi_panel_orientation_data lcd1200x1920_rightside_up = { .width = 1200, .height = 1920, @@ -279,6 +285,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1618-03") }, .driver_data = (void *)&lcd720x1280_rightside_up, + }, { /* GPD Win Mini */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1617-01") + }, + .driver_data = (void *)&lcd1080x1920_rightside_up, }, { /* I.T.Works TW891 */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 5b93c11895bb1e6336c016b1cf27919e5cbae62f..699b7dbffd7ba124da8179309e98c08f21a9ec16 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -182,16 +182,35 @@ void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf) } EXPORT_SYMBOL(__drm_printfn_info); -void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf) +void __drm_printfn_dbg(struct drm_printer *p, struct va_format *vaf) { - /* pr_debug callsite decorations are unhelpful here */ - printk(KERN_DEBUG "%s %pV", p->prefix, vaf); + const struct drm_device *drm = p->arg; + const struct device *dev = drm ? drm->dev : NULL; + enum drm_debug_category category = p->category; + const char *prefix = p->prefix ?: ""; + const char *prefix_pad = p->prefix ? " " : ""; + + if (!__drm_debug_enabled(category)) + return; + + /* Note: __builtin_return_address(0) is useless here. */ + if (dev) + dev_printk(KERN_DEBUG, dev, "[" DRM_NAME "]%s%s %pV", + prefix_pad, prefix, vaf); + else + printk(KERN_DEBUG "[" DRM_NAME "]%s%s %pV", + prefix_pad, prefix, vaf); } -EXPORT_SYMBOL(__drm_printfn_debug); +EXPORT_SYMBOL(__drm_printfn_dbg); void __drm_printfn_err(struct drm_printer *p, struct va_format *vaf) { - pr_err("*ERROR* %s %pV", p->prefix, vaf); + struct drm_device *drm = p->arg; + + if (p->prefix) + drm_err(drm, "%s %pV", p->prefix, vaf); + else + drm_err(drm, "%pV", vaf); } EXPORT_SYMBOL(__drm_printfn_err); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 3f479483d7d80f21febcda087570bcc6af2fd34c..d1e1ade66f81cb3bd90e91a3dbcd8d0d9acd60de 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -1100,42 +1100,6 @@ enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc, } EXPORT_SYMBOL(drm_crtc_helper_mode_valid_fixed); -/** - * drm_connector_helper_get_modes_from_ddc - Updates the connector's EDID - * property from the connector's - * DDC channel - * @connector: The connector - * - * Returns: - * The number of detected display modes. - * - * Uses a connector's DDC channel to retrieve EDID data and update the - * connector's EDID property and display modes. Drivers can use this - * function to implement struct &drm_connector_helper_funcs.get_modes - * for connectors with a DDC channel. - */ -int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector) -{ - struct edid *edid; - int count = 0; - - if (!connector->ddc) - return 0; - - edid = drm_get_edid(connector, connector->ddc); - - // clears property if EDID is NULL - drm_connector_update_edid_property(connector, edid); - - if (edid) { - count = drm_add_edid_modes(connector, edid); - kfree(edid); - } - - return count; -} -EXPORT_SYMBOL(drm_connector_helper_get_modes_from_ddc); - /** * drm_connector_helper_get_modes_fixed - Duplicates a display mode for a connector * @connector: the connector diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 776f2f0b602debb88a6c820add8d737332f2938e..0ef7bc8848b0798b125f7a65ff04cf4586f13d71 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -319,9 +319,9 @@ static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win, static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, struct drm_framebuffer *fb) { - struct exynos_drm_plane plane = ctx->planes[win]; + struct exynos_drm_plane *plane = &ctx->planes[win]; struct exynos_drm_plane_state *state = - to_exynos_plane_state(plane.base.state); + to_exynos_plane_state(plane->base.state); unsigned int alpha = state->base.alpha; unsigned int pixel_alpha; unsigned long val; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index a9f1c5c058940178c8318484fcea422f1428de69..f2145227a1e0ce889d2ce0a3926a79e64c832fc9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -480,7 +480,7 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) struct fimd_context *ctx = crtc->ctx; struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; const struct fimd_driver_data *driver_data = ctx->driver_data; - void *timing_base = ctx->regs + driver_data->timing_base; + void __iomem *timing_base = ctx->regs + driver_data->timing_base; u32 val; if (ctx->suspended) @@ -661,9 +661,9 @@ static void fimd_win_set_bldmod(struct fimd_context *ctx, unsigned int win, static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win, struct drm_framebuffer *fb, int width) { - struct exynos_drm_plane plane = ctx->planes[win]; + struct exynos_drm_plane *plane = &ctx->planes[win]; struct exynos_drm_plane_state *state = - to_exynos_plane_state(plane.base.state); + to_exynos_plane_state(plane->base.state); uint32_t pixel_format = fb->format->format; unsigned int alpha = state->base.alpha; u32 val = WINCONx_ENWIN; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index e9a769590415dcd0d7899df16254d7c20cdea8b1..180507a477009d6e424cc5aede8e18255127b3f1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -1341,7 +1341,7 @@ static int __maybe_unused gsc_runtime_resume(struct device *dev) for (i = 0; i < ctx->num_clocks; i++) { ret = clk_prepare_enable(ctx->clocks[i]); if (ret) { - while (--i > 0) + while (--i >= 0) clk_disable_unprepare(ctx->clocks[i]); return ret; } diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index f957552c6c50785734521a38a79c95858fb0ef3f..207aa3f660b030870b722317fe24f575493c2cc7 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -18,7 +18,6 @@ #include #include -#include #include struct hibmc_connector { diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index 8c6d2ea2a4729f4c36ffcb34f073b6c03d260901..94e2c573a7aff35f3f19597d92c26e23d43ae631 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e777686190ca241f0ed288b2ad32645d41f1a288..c13f14edb50889baa604b044d2324a371e444ed5 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -17,7 +17,6 @@ subdir-ccflags-y += $(call cc-option, -Wunused-const-variable) subdir-ccflags-y += $(call cc-option, -Wpacked-not-aligned) subdir-ccflags-y += $(call cc-option, -Wformat-overflow) subdir-ccflags-y += $(call cc-option, -Wformat-truncation) -subdir-ccflags-y += $(call cc-option, -Wstringop-overflow) subdir-ccflags-y += $(call cc-option, -Wstringop-truncation) # The following turn off the warnings enabled by -Wextra ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),) diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index 91f2bc405cbaf0aef44288969c939bd3aeee96fd..0279c8aabdd1f768d81abb01e2edae5b74679e44 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -1060,3 +1060,33 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, plane_config->fb = intel_fb; } + +bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc, + const struct intel_initial_plane_config *plane_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + const struct intel_plane_state *plane_state = + to_intel_plane_state(plane->base.state); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + u32 base; + + if (!plane_state->uapi.visible) + return false; + + base = intel_plane_ggtt_offset(plane_state); + + /* + * We may have moved the surface to a different + * part of ggtt, make the plane aware of that. + */ + if (plane_config->base == base) + return false; + + if (DISPLAY_VER(dev_priv) >= 4) + intel_de_write(dev_priv, DSPSURF(i9xx_plane), base); + else + intel_de_write(dev_priv, DSPADDR(i9xx_plane), base); + + return true; +} diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.h b/drivers/gpu/drm/i915/display/i9xx_plane.h index b3d724a144cb9d2a624500a549b5f5f400c7117f..0ca12d1e683936d1075dc1a6c27180b73729989c 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.h +++ b/drivers/gpu/drm/i915/display/i9xx_plane.h @@ -26,6 +26,8 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe); void i9xx_get_initial_plane_config(struct intel_crtc *crtc, struct intel_initial_plane_config *plane_config); +bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc, + const struct intel_initial_plane_config *plane_config); #else static inline unsigned int i965_plane_max_stride(struct intel_plane *plane, u32 pixel_format, u64 modifier, @@ -46,6 +48,11 @@ static inline void i9xx_get_initial_plane_config(struct intel_crtc *crtc, struct intel_initial_plane_config *plane_config) { } +static inline bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc, + const struct intel_initial_plane_config *plane_config) +{ + return false; +} #endif #endif diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index ac456a2275dbad62cb9a4ac7f706333c73dd03aa..eda4a8b885904de71bb6e3bb1998fa1242a1b9a7 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1155,6 +1155,7 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) } intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); /* ensure all panel commands dispatched before enabling transcoder */ wait_for_cmds_dispatched_to_panel(encoder); @@ -1255,8 +1256,6 @@ static void gen11_dsi_enable(struct intel_atomic_state *state, /* step6d: enable dsi transcoder */ gen11_dsi_enable_transcoder(encoder); - intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); - /* step7: enable backlight */ intel_backlight_enable(crtc_state, conn_state); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON); diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 06c2455bdd788f999725d4697859e2445bbe60b6..76d77d5a0409f8259f6a9a3d62fc5e466cfd22eb 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -217,6 +217,9 @@ intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, int width, height; unsigned int rel_data_rate; + if (plane->id == PLANE_CURSOR) + return 0; + if (!plane_state->uapi.visible) return 0; @@ -244,9 +247,6 @@ intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, rel_data_rate = width * height * fb->format->cpp[color_plane]; - if (plane->id == PLANE_CURSOR) - return rel_data_rate; - return intel_adjusted_rate(&plane_state->uapi.src, &plane_state->uapi.dst, rel_data_rate); diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 3f3cd944a1c5bfcc1a94cfa02ae180496140f408..1946d7fb3c2e512b50e7715c9d50e7109b9e190e 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -1465,7 +1465,7 @@ static bool cnp_backlight_controller_is_valid(struct drm_i915_private *i915, int if (controller == 1 && INTEL_PCH_TYPE(i915) >= PCH_ICP && - INTEL_PCH_TYPE(i915) < PCH_MTP) + INTEL_PCH_TYPE(i915) <= PCH_ADP) return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT; return true; diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index aa169b0055e97da3738f6d4bc5b4481ab2e38696..5f04e495fd27563342808951dabd72089b37313e 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2204,8 +2204,7 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) if (IS_DGFX(i915)) return vbt_pin; - if (INTEL_PCH_TYPE(i915) >= PCH_LNL || HAS_PCH_MTP(i915) || - IS_ALDERLAKE_P(i915)) { + if (INTEL_PCH_TYPE(i915) >= PCH_MTL || IS_ALDERLAKE_P(i915)) { ddc_pin_map = adlp_ddc_pin_map; n_entries = ARRAY_SIZE(adlp_ddc_pin_map); } else if (IS_ALDERLAKE_S(i915)) { @@ -3074,7 +3073,7 @@ err_unmap_oprom: */ void intel_bios_init(struct drm_i915_private *i915) { - const struct vbt_header *vbt = i915->display.opregion.vbt; + const struct vbt_header *vbt; struct vbt_header *oprom_vbt = NULL; const struct bdb_header *bdb; @@ -3089,6 +3088,8 @@ void intel_bios_init(struct drm_i915_private *i915) init_vbt_defaults(i915); + vbt = intel_opregion_get_vbt(i915, NULL); + /* * If the OpRegion does not have VBT, look in SPI flash through MMIO or * PCI mapping @@ -3306,7 +3307,7 @@ bool intel_bios_is_lvds_present(struct drm_i915_private *i915, u8 *i2c_pin) * additional data. Trust that if the VBT was written into * the OpRegion then they have validated the LVDS's existence. */ - if (i915->display.opregion.vbt) + if (intel_opregion_get_vbt(i915, NULL)) return true; } @@ -3657,3 +3658,30 @@ void intel_bios_for_each_encoder(struct drm_i915_private *i915, list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) func(i915, devdata); } + +static int intel_bios_vbt_show(struct seq_file *m, void *unused) +{ + struct drm_i915_private *i915 = m->private; + const void *vbt; + size_t vbt_size; + + /* + * FIXME: VBT might originate from other places than opregion, and then + * this would be incorrect. + */ + vbt = intel_opregion_get_vbt(i915, &vbt_size); + if (vbt) + seq_write(m, vbt, vbt_size); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(intel_bios_vbt); + +void intel_bios_debugfs_register(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + + debugfs_create_file("i915_vbt", 0444, minor->debugfs_root, + i915, &intel_bios_vbt_fops); +} diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h index 49e24b7cf6753ad2dc409ab83fc6567743170832..41bfb009d4b047069b869d595a1ec9468a0210c9 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.h +++ b/drivers/gpu/drm/i915/display/intel_bios.h @@ -246,13 +246,10 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t size); bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv); bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin); bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port); -bool intel_bios_is_port_edp(struct drm_i915_private *dev_priv, enum port port); bool intel_bios_is_dsi_present(struct drm_i915_private *dev_priv, enum port *port); bool intel_bios_get_dsc_params(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, int dsc_max_bpc); -bool intel_bios_port_supports_typec_usb(struct drm_i915_private *i915, enum port port); -bool intel_bios_port_supports_tbt(struct drm_i915_private *i915, enum port port); const struct intel_bios_encoder_data * intel_bios_encoder_data_lookup(struct drm_i915_private *i915, enum port port); @@ -283,4 +280,6 @@ void intel_bios_for_each_encoder(struct drm_i915_private *i915, void (*func)(struct drm_i915_private *i915, const struct intel_bios_encoder_data *devdata)); +void intel_bios_debugfs_register(struct drm_i915_private *i915); + #endif /* _INTEL_BIOS_H_ */ diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index c985ebb6831a3755d14548d9925839cb426bb52d..26200ee3e23f9fed708b5764b4f06a4aa4a7037a 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1227,183 +1227,182 @@ struct intel_cdclk_vals { u32 cdclk; u16 refclk; u16 waveform; - u8 divider; /* CD2X divider * 2 */ u8 ratio; }; static const struct intel_cdclk_vals bxt_cdclk_table[] = { - { .refclk = 19200, .cdclk = 144000, .divider = 8, .ratio = 60 }, - { .refclk = 19200, .cdclk = 288000, .divider = 4, .ratio = 60 }, - { .refclk = 19200, .cdclk = 384000, .divider = 3, .ratio = 60 }, - { .refclk = 19200, .cdclk = 576000, .divider = 2, .ratio = 60 }, - { .refclk = 19200, .cdclk = 624000, .divider = 2, .ratio = 65 }, + { .refclk = 19200, .cdclk = 144000, .ratio = 60 }, + { .refclk = 19200, .cdclk = 288000, .ratio = 60 }, + { .refclk = 19200, .cdclk = 384000, .ratio = 60 }, + { .refclk = 19200, .cdclk = 576000, .ratio = 60 }, + { .refclk = 19200, .cdclk = 624000, .ratio = 65 }, {} }; static const struct intel_cdclk_vals glk_cdclk_table[] = { - { .refclk = 19200, .cdclk = 79200, .divider = 8, .ratio = 33 }, - { .refclk = 19200, .cdclk = 158400, .divider = 4, .ratio = 33 }, - { .refclk = 19200, .cdclk = 316800, .divider = 2, .ratio = 33 }, + { .refclk = 19200, .cdclk = 79200, .ratio = 33 }, + { .refclk = 19200, .cdclk = 158400, .ratio = 33 }, + { .refclk = 19200, .cdclk = 316800, .ratio = 33 }, {} }; static const struct intel_cdclk_vals icl_cdclk_table[] = { - { .refclk = 19200, .cdclk = 172800, .divider = 2, .ratio = 18 }, - { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 }, - { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, - { .refclk = 19200, .cdclk = 326400, .divider = 4, .ratio = 68 }, - { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, - { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, - - { .refclk = 24000, .cdclk = 180000, .divider = 2, .ratio = 15 }, - { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, - { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, - { .refclk = 24000, .cdclk = 324000, .divider = 4, .ratio = 54 }, - { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 }, - - { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 9 }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, - { .refclk = 38400, .cdclk = 326400, .divider = 4, .ratio = 34 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + { .refclk = 19200, .cdclk = 172800, .ratio = 18 }, + { .refclk = 19200, .cdclk = 192000, .ratio = 20 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 32 }, + { .refclk = 19200, .cdclk = 326400, .ratio = 68 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 68 }, + + { .refclk = 24000, .cdclk = 180000, .ratio = 15 }, + { .refclk = 24000, .cdclk = 192000, .ratio = 16 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 26 }, + { .refclk = 24000, .cdclk = 324000, .ratio = 54 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 46 }, + { .refclk = 24000, .cdclk = 648000, .ratio = 54 }, + + { .refclk = 38400, .cdclk = 172800, .ratio = 9 }, + { .refclk = 38400, .cdclk = 192000, .ratio = 10 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16 }, + { .refclk = 38400, .cdclk = 326400, .ratio = 34 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34 }, {} }; static const struct intel_cdclk_vals rkl_cdclk_table[] = { - { .refclk = 19200, .cdclk = 172800, .divider = 4, .ratio = 36 }, - { .refclk = 19200, .cdclk = 192000, .divider = 4, .ratio = 40 }, - { .refclk = 19200, .cdclk = 307200, .divider = 4, .ratio = 64 }, - { .refclk = 19200, .cdclk = 326400, .divider = 8, .ratio = 136 }, - { .refclk = 19200, .cdclk = 556800, .divider = 4, .ratio = 116 }, - { .refclk = 19200, .cdclk = 652800, .divider = 4, .ratio = 136 }, - - { .refclk = 24000, .cdclk = 180000, .divider = 4, .ratio = 30 }, - { .refclk = 24000, .cdclk = 192000, .divider = 4, .ratio = 32 }, - { .refclk = 24000, .cdclk = 312000, .divider = 4, .ratio = 52 }, - { .refclk = 24000, .cdclk = 324000, .divider = 8, .ratio = 108 }, - { .refclk = 24000, .cdclk = 552000, .divider = 4, .ratio = 92 }, - { .refclk = 24000, .cdclk = 648000, .divider = 4, .ratio = 108 }, - - { .refclk = 38400, .cdclk = 172800, .divider = 4, .ratio = 18 }, - { .refclk = 38400, .cdclk = 192000, .divider = 4, .ratio = 20 }, - { .refclk = 38400, .cdclk = 307200, .divider = 4, .ratio = 32 }, - { .refclk = 38400, .cdclk = 326400, .divider = 8, .ratio = 68 }, - { .refclk = 38400, .cdclk = 556800, .divider = 4, .ratio = 58 }, - { .refclk = 38400, .cdclk = 652800, .divider = 4, .ratio = 68 }, + { .refclk = 19200, .cdclk = 172800, .ratio = 36 }, + { .refclk = 19200, .cdclk = 192000, .ratio = 40 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 64 }, + { .refclk = 19200, .cdclk = 326400, .ratio = 136 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 116 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 136 }, + + { .refclk = 24000, .cdclk = 180000, .ratio = 30 }, + { .refclk = 24000, .cdclk = 192000, .ratio = 32 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 52 }, + { .refclk = 24000, .cdclk = 324000, .ratio = 108 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 92 }, + { .refclk = 24000, .cdclk = 648000, .ratio = 108 }, + + { .refclk = 38400, .cdclk = 172800, .ratio = 18 }, + { .refclk = 38400, .cdclk = 192000, .ratio = 20 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 32 }, + { .refclk = 38400, .cdclk = 326400, .ratio = 68 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 58 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 68 }, {} }; static const struct intel_cdclk_vals adlp_a_step_cdclk_table[] = { - { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, - { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, - { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 32 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 68 }, - { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, - { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 26 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 46 }, + { .refclk = 24400, .cdclk = 648000, .ratio = 54 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34 }, {} }; static const struct intel_cdclk_vals adlp_cdclk_table[] = { - { .refclk = 19200, .cdclk = 172800, .divider = 3, .ratio = 27 }, - { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 }, - { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, - { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, - { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, - - { .refclk = 24000, .cdclk = 176000, .divider = 3, .ratio = 22 }, - { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, - { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, - { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 }, - - { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + { .refclk = 19200, .cdclk = 172800, .ratio = 27 }, + { .refclk = 19200, .cdclk = 192000, .ratio = 20 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 32 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 68 }, + + { .refclk = 24000, .cdclk = 176000, .ratio = 22 }, + { .refclk = 24000, .cdclk = 192000, .ratio = 16 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 26 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 46 }, + { .refclk = 24000, .cdclk = 648000, .ratio = 54 }, + + { .refclk = 38400, .cdclk = 179200, .ratio = 14 }, + { .refclk = 38400, .cdclk = 192000, .ratio = 10 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34 }, {} }; static const struct intel_cdclk_vals rplu_cdclk_table[] = { - { .refclk = 19200, .cdclk = 172800, .divider = 3, .ratio = 27 }, - { .refclk = 19200, .cdclk = 192000, .divider = 2, .ratio = 20 }, - { .refclk = 19200, .cdclk = 307200, .divider = 2, .ratio = 32 }, - { .refclk = 19200, .cdclk = 480000, .divider = 2, .ratio = 50 }, - { .refclk = 19200, .cdclk = 556800, .divider = 2, .ratio = 58 }, - { .refclk = 19200, .cdclk = 652800, .divider = 2, .ratio = 68 }, - - { .refclk = 24000, .cdclk = 176000, .divider = 3, .ratio = 22 }, - { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, - { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, - { .refclk = 24000, .cdclk = 480000, .divider = 2, .ratio = 40 }, - { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, - { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 }, - - { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16 }, - { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34 }, + { .refclk = 19200, .cdclk = 172800, .ratio = 27 }, + { .refclk = 19200, .cdclk = 192000, .ratio = 20 }, + { .refclk = 19200, .cdclk = 307200, .ratio = 32 }, + { .refclk = 19200, .cdclk = 480000, .ratio = 50 }, + { .refclk = 19200, .cdclk = 556800, .ratio = 58 }, + { .refclk = 19200, .cdclk = 652800, .ratio = 68 }, + + { .refclk = 24000, .cdclk = 176000, .ratio = 22 }, + { .refclk = 24000, .cdclk = 192000, .ratio = 16 }, + { .refclk = 24000, .cdclk = 312000, .ratio = 26 }, + { .refclk = 24000, .cdclk = 480000, .ratio = 40 }, + { .refclk = 24000, .cdclk = 552000, .ratio = 46 }, + { .refclk = 24000, .cdclk = 648000, .ratio = 54 }, + + { .refclk = 38400, .cdclk = 179200, .ratio = 14 }, + { .refclk = 38400, .cdclk = 192000, .ratio = 10 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16 }, + { .refclk = 38400, .cdclk = 480000, .ratio = 25 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34 }, {} }; static const struct intel_cdclk_vals dg2_cdclk_table[] = { - { .refclk = 38400, .cdclk = 163200, .divider = 2, .ratio = 34, .waveform = 0x8888 }, - { .refclk = 38400, .cdclk = 204000, .divider = 2, .ratio = 34, .waveform = 0x9248 }, - { .refclk = 38400, .cdclk = 244800, .divider = 2, .ratio = 34, .waveform = 0xa4a4 }, - { .refclk = 38400, .cdclk = 285600, .divider = 2, .ratio = 34, .waveform = 0xa54a }, - { .refclk = 38400, .cdclk = 326400, .divider = 2, .ratio = 34, .waveform = 0xaaaa }, - { .refclk = 38400, .cdclk = 367200, .divider = 2, .ratio = 34, .waveform = 0xad5a }, - { .refclk = 38400, .cdclk = 408000, .divider = 2, .ratio = 34, .waveform = 0xb6b6 }, - { .refclk = 38400, .cdclk = 448800, .divider = 2, .ratio = 34, .waveform = 0xdbb6 }, - { .refclk = 38400, .cdclk = 489600, .divider = 2, .ratio = 34, .waveform = 0xeeee }, - { .refclk = 38400, .cdclk = 530400, .divider = 2, .ratio = 34, .waveform = 0xf7de }, - { .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 163200, .ratio = 34, .waveform = 0x8888 }, + { .refclk = 38400, .cdclk = 204000, .ratio = 34, .waveform = 0x9248 }, + { .refclk = 38400, .cdclk = 244800, .ratio = 34, .waveform = 0xa4a4 }, + { .refclk = 38400, .cdclk = 285600, .ratio = 34, .waveform = 0xa54a }, + { .refclk = 38400, .cdclk = 326400, .ratio = 34, .waveform = 0xaaaa }, + { .refclk = 38400, .cdclk = 367200, .ratio = 34, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 408000, .ratio = 34, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 448800, .ratio = 34, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 489600, .ratio = 34, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 530400, .ratio = 34, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 571200, .ratio = 34, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 612000, .ratio = 34, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff }, {} }; static const struct intel_cdclk_vals mtl_cdclk_table[] = { - { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0x0000 }, - { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0x0000 }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0x0000 }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0x0000 }, + { .refclk = 38400, .cdclk = 172800, .ratio = 16, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 192000, .ratio = 16, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16, .waveform = 0x0000 }, + { .refclk = 38400, .cdclk = 480000, .ratio = 25, .waveform = 0x0000 }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29, .waveform = 0x0000 }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0x0000 }, {} }; static const struct intel_cdclk_vals lnl_cdclk_table[] = { - { .refclk = 38400, .cdclk = 153600, .divider = 2, .ratio = 16, .waveform = 0xaaaa }, - { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a }, - { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 }, - { .refclk = 38400, .cdclk = 211200, .divider = 2, .ratio = 16, .waveform = 0xdbb6 }, - { .refclk = 38400, .cdclk = 230400, .divider = 2, .ratio = 16, .waveform = 0xeeee }, - { .refclk = 38400, .cdclk = 249600, .divider = 2, .ratio = 16, .waveform = 0xf7de }, - { .refclk = 38400, .cdclk = 268800, .divider = 2, .ratio = 16, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 288000, .divider = 2, .ratio = 16, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0xffff }, - { .refclk = 38400, .cdclk = 330000, .divider = 2, .ratio = 25, .waveform = 0xdbb6 }, - { .refclk = 38400, .cdclk = 360000, .divider = 2, .ratio = 25, .waveform = 0xeeee }, - { .refclk = 38400, .cdclk = 390000, .divider = 2, .ratio = 25, .waveform = 0xf7de }, - { .refclk = 38400, .cdclk = 420000, .divider = 2, .ratio = 25, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 450000, .divider = 2, .ratio = 25, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0xffff }, - { .refclk = 38400, .cdclk = 487200, .divider = 2, .ratio = 29, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 522000, .divider = 2, .ratio = 29, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0xffff }, - { .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe }, - { .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe }, - { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 153600, .ratio = 16, .waveform = 0xaaaa }, + { .refclk = 38400, .cdclk = 172800, .ratio = 16, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 192000, .ratio = 16, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 211200, .ratio = 16, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 230400, .ratio = 16, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 249600, .ratio = 16, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 268800, .ratio = 16, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 288000, .ratio = 16, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 330000, .ratio = 25, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 360000, .ratio = 25, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 390000, .ratio = 25, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 420000, .ratio = 25, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 450000, .ratio = 25, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 480000, .ratio = 25, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 487200, .ratio = 29, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 522000, .ratio = 29, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 571200, .ratio = 34, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 612000, .ratio = 34, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff }, {} }; @@ -1901,15 +1900,47 @@ static bool pll_enable_wa_needed(struct drm_i915_private *dev_priv) dev_priv->display.cdclk.hw.vco > 0; } +static u32 bxt_cdclk_ctl(struct drm_i915_private *i915, + const struct intel_cdclk_config *cdclk_config, + enum pipe pipe) +{ + int cdclk = cdclk_config->cdclk; + int vco = cdclk_config->vco; + int unsquashed_cdclk; + u16 waveform; + u32 val; + + waveform = cdclk_squash_waveform(i915, cdclk); + + unsquashed_cdclk = DIV_ROUND_CLOSEST(cdclk * cdclk_squash_len, + cdclk_squash_divider(waveform)); + + val = bxt_cdclk_cd2x_div_sel(i915, unsquashed_cdclk, vco) | + bxt_cdclk_cd2x_pipe(i915, pipe); + + /* + * Disable SSA Precharge when CD clock frequency < 500 MHz, + * enable otherwise. + */ + if ((IS_GEMINILAKE(i915) || IS_BROXTON(i915)) && + cdclk >= 500000) + val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; + + if (DISPLAY_VER(i915) >= 20) + val |= MDCLK_SOURCE_SEL_CDCLK_PLL; + else + val |= skl_cdclk_decimal(cdclk); + + return val; +} + static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { int cdclk = cdclk_config->cdclk; int vco = cdclk_config->vco; - int unsquashed_cdclk; u16 waveform; - u32 val; if (HAS_CDCLK_CRAWL(dev_priv) && dev_priv->display.cdclk.hw.vco > 0 && vco > 0 && !cdclk_pll_is_unknown(dev_priv->display.cdclk.hw.vco)) { @@ -1926,29 +1957,10 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, waveform = cdclk_squash_waveform(dev_priv, cdclk); - unsquashed_cdclk = DIV_ROUND_CLOSEST(cdclk * cdclk_squash_len, - cdclk_squash_divider(waveform)); - if (HAS_CDCLK_SQUASH(dev_priv)) dg2_cdclk_squash_program(dev_priv, waveform); - val = bxt_cdclk_cd2x_div_sel(dev_priv, unsquashed_cdclk, vco) | - bxt_cdclk_cd2x_pipe(dev_priv, pipe); - - /* - * Disable SSA Precharge when CD clock frequency < 500 MHz, - * enable otherwise. - */ - if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && - cdclk >= 500000) - val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; - - if (DISPLAY_VER(dev_priv) >= 20) - val |= MDCLK_SOURCE_SEL_CDCLK_PLL; - else - val |= skl_cdclk_decimal(cdclk); - - intel_de_write(dev_priv, CDCLK_CTL, val); + intel_de_write(dev_priv, CDCLK_CTL, bxt_cdclk_ctl(dev_priv, cdclk_config, pipe)); if (pipe != INVALID_PIPE) intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(dev_priv, pipe)); @@ -2039,7 +2051,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) { u32 cdctl, expected; - int cdclk, clock, vco; + int cdclk, vco; intel_update_cdclk(dev_priv); intel_cdclk_dump_config(dev_priv, &dev_priv->display.cdclk.hw, "Current CDCLK"); @@ -2048,20 +2060,6 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) dev_priv->display.cdclk.hw.cdclk == dev_priv->display.cdclk.hw.bypass) goto sanitize; - /* DPLL okay; verify the cdclock - * - * Some BIOS versions leave an incorrect decimal frequency value and - * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4, - * so sanitize this register. - */ - cdctl = intel_de_read(dev_priv, CDCLK_CTL); - /* - * Let's ignore the pipe field, since BIOS could have configured the - * dividers both synching to an active pipe, or asynchronously - * (PIPE_NONE). - */ - cdctl &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE); - /* Make sure this is a legal cdclk value for the platform */ cdclk = bxt_calc_cdclk(dev_priv, dev_priv->display.cdclk.hw.cdclk); if (cdclk != dev_priv->display.cdclk.hw.cdclk) @@ -2072,24 +2070,21 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) if (vco != dev_priv->display.cdclk.hw.vco) goto sanitize; - expected = skl_cdclk_decimal(cdclk); - - /* Figure out what CD2X divider we should be using for this cdclk */ - if (HAS_CDCLK_SQUASH(dev_priv)) - clock = dev_priv->display.cdclk.hw.vco / 2; - else - clock = dev_priv->display.cdclk.hw.cdclk; - - expected |= bxt_cdclk_cd2x_div_sel(dev_priv, clock, - dev_priv->display.cdclk.hw.vco); + /* + * Some BIOS versions leave an incorrect decimal frequency value and + * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4, + * so sanitize this register. + */ + cdctl = intel_de_read(dev_priv, CDCLK_CTL); + expected = bxt_cdclk_ctl(dev_priv, &dev_priv->display.cdclk.hw, INVALID_PIPE); /* - * Disable SSA Precharge when CD clock frequency < 500 MHz, - * enable otherwise. + * Let's ignore the pipe field, since BIOS could have configured the + * dividers both synching to an active pipe, or asynchronously + * (PIPE_NONE). */ - if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && - dev_priv->display.cdclk.hw.cdclk >= 500000) - expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; + cdctl &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE); + expected &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE); if (cdctl == expected) /* All well; nothing to sanitize */ @@ -3467,15 +3462,15 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) { u32 freq; - if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) - freq = dg1_rawclk(dev_priv); - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP) + if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTL) /* * MTL always uses a 38.4 MHz rawclk. The bspec tells us * "RAWCLK_FREQ defaults to the values for 38.4 and does * not need to be programmed." */ freq = 38400; + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) + freq = dg1_rawclk(dev_priv); else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) freq = cnp_rawclk(dev_priv); else if (HAS_PCH_SPLIT(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index abaacea5c2cc455fa2f7286fbfe8e580686609b6..b9733a73e21d4357e5716ccc06522fb7ce84eebd 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -42,6 +42,7 @@ #include "intel_ddi.h" #include "intel_ddi_buf_trans.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" @@ -846,6 +847,9 @@ intel_crt_detect(struct drm_connector *connector, if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; + if (!intel_display_driver_check_access(dev_priv)) + return connector->status; + if (dev_priv->display.params.load_detect_test) { wakeref = intel_display_power_get(dev_priv, intel_encoder->power_domain); @@ -1069,6 +1073,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv) } else { intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; } + intel_connector->base.polled = intel_connector->polled; if (HAS_DDI(dev_priv)) { assert_port_valid(dev_priv, PORT_E); diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 8a84a31c7b48a24ceb8c9e61116410854c38dc39..25593f6aae7de0200fa349ac9a9825b5b80938d9 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -461,70 +461,6 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, 1000 * adjusted_mode->crtc_htotal); } -static int intel_mode_vblank_start(const struct drm_display_mode *mode) -{ - int vblank_start = mode->crtc_vblank_start; - - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - vblank_start = DIV_ROUND_UP(vblank_start, 2); - - return vblank_start; -} - -static void intel_crtc_vblank_evade_scanlines(struct intel_atomic_state *state, - struct intel_crtc *crtc, - int *min, int *max, int *vblank_start) -{ - const struct intel_crtc_state *old_crtc_state = - intel_atomic_get_old_crtc_state(state, crtc); - const struct intel_crtc_state *new_crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); - const struct intel_crtc_state *crtc_state; - const struct drm_display_mode *adjusted_mode; - - /* - * During fastsets/etc. the transcoder is still - * running with the old timings at this point. - * - * TODO: maybe just use the active timings here? - */ - if (intel_crtc_needs_modeset(new_crtc_state)) - crtc_state = new_crtc_state; - else - crtc_state = old_crtc_state; - - adjusted_mode = &crtc_state->hw.adjusted_mode; - - if (crtc->mode_flags & I915_MODE_FLAG_VRR) { - /* timing changes should happen with VRR disabled */ - drm_WARN_ON(state->base.dev, intel_crtc_needs_modeset(new_crtc_state) || - new_crtc_state->update_m_n || new_crtc_state->update_lrr); - - if (intel_vrr_is_push_sent(crtc_state)) - *vblank_start = intel_vrr_vmin_vblank_start(crtc_state); - else - *vblank_start = intel_vrr_vmax_vblank_start(crtc_state); - } else { - *vblank_start = intel_mode_vblank_start(adjusted_mode); - } - - /* FIXME needs to be calibrated sensibly */ - *min = *vblank_start - intel_usecs_to_scanlines(adjusted_mode, - VBLANK_EVASION_TIME_US); - *max = *vblank_start - 1; - - /* - * M/N and TRANS_VTOTAL are double buffered on the transcoder's - * undelayed vblank, so with seamless M/N and LRR we must evade - * both vblanks. - * - * DSB execution waits for the transcoder's undelayed vblank, - * hence we must kick off the commit before that. - */ - if (new_crtc_state->dsb || new_crtc_state->update_m_n || new_crtc_state->update_lrr) - *min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; -} - /** * intel_pipe_update_start() - start update of a set of display registers * @state: the atomic state @@ -542,14 +478,12 @@ void intel_pipe_update_start(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - long timeout = msecs_to_jiffies_timeout(1); - int scanline, min, max, vblank_start; - wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); - bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && - intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); - DEFINE_WAIT(wait); + struct intel_vblank_evade_ctx evade; + int scanline; intel_psr_lock(new_crtc_state); @@ -566,9 +500,7 @@ void intel_pipe_update_start(struct intel_atomic_state *state, if (intel_crtc_needs_vblank_work(new_crtc_state)) intel_crtc_vblank_work_init(new_crtc_state); - intel_crtc_vblank_evade_scanlines(state, crtc, &min, &max, &vblank_start); - if (min <= 0 || max <= 0) - goto irq_disable; + intel_vblank_evade_init(old_crtc_state, new_crtc_state, &evade); if (drm_WARN_ON(&dev_priv->drm, drm_crtc_vblank_get(&crtc->base))) goto irq_disable; @@ -582,58 +514,14 @@ void intel_pipe_update_start(struct intel_atomic_state *state, local_irq_disable(); - crtc->debug.min_vbl = min; - crtc->debug.max_vbl = max; + crtc->debug.min_vbl = evade.min; + crtc->debug.max_vbl = evade.max; trace_intel_pipe_update_start(crtc); - for (;;) { - /* - * prepare_to_wait() has a memory barrier, which guarantees - * other CPUs can see the task state update by the time we - * read the scanline. - */ - prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); - - scanline = intel_get_crtc_scanline(crtc); - if (scanline < min || scanline > max) - break; - - if (!timeout) { - drm_err(&dev_priv->drm, - "Potential atomic update failure on pipe %c\n", - pipe_name(crtc->pipe)); - break; - } - - local_irq_enable(); - - timeout = schedule_timeout(timeout); - - local_irq_disable(); - } - - finish_wait(wq, &wait); + scanline = intel_vblank_evade(&evade); drm_crtc_vblank_put(&crtc->base); - /* - * On VLV/CHV DSI the scanline counter would appear to - * increment approx. 1/3 of a scanline before start of vblank. - * The registers still get latched at start of vblank however. - * This means we must not write any registers on the first - * line of vblank (since not the whole line is actually in - * vblank). And unfortunately we can't use the interrupt to - * wait here since it will fire too soon. We could use the - * frame start interrupt instead since it will fire after the - * critical scanline, but that would require more changes - * in the interrupt code. So for now we'll just do the nasty - * thing and poll for the bad scanline to pass us by. - * - * FIXME figure out if BXT+ DSI suffers from this as well - */ - while (need_vlv_dsi_wa && scanline == vblank_start) - scanline = intel_get_crtc_scanline(crtc); - crtc->debug.scanline_start = scanline; crtc->debug.start_vbl_time = ktime_get(); crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 49fd100ec98a021012cab38c8adda4e6efb5804b..4bcf446c75f49a5cd8115313fd0f1a152c798fd5 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -55,10 +55,9 @@ static void intel_dump_dp_vsc_sdp(struct drm_i915_private *i915, const struct drm_dp_vsc_sdp *vsc) { - if (!drm_debug_enabled(DRM_UT_KMS)) - return; + struct drm_printer p = drm_dbg_printer(&i915->drm, DRM_UT_KMS, NULL); - drm_dp_vsc_sdp_log(KERN_DEBUG, i915->drm.dev, vsc); + drm_dp_vsc_sdp_log(&p, vsc); } static void diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 926e2de00eb5820a1ca1e31d538f90b9eaa1bf62..f8b33999d43fccdba84fd2f26f650356423d2bc3 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -22,6 +22,7 @@ #include "intel_frontbuffer.h" #include "intel_psr.h" #include "intel_psr_regs.h" +#include "intel_vblank.h" #include "skl_watermark.h" #include "gem/i915_gem_object.h" @@ -47,12 +48,23 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state) return base + plane_state->view.color_plane[0].offset; } -static u32 intel_cursor_position(const struct intel_plane_state *plane_state) +static u32 intel_cursor_position(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + bool early_tpt) { int x = plane_state->uapi.dst.x1; int y = plane_state->uapi.dst.y1; u32 pos = 0; + /* + * Formula from Bspec: + * MAX(-1 * + 1, CUR_POS Y Position - Update region Y position + */ + if (early_tpt) + y = max(-1 * drm_rect_height(&plane_state->uapi.dst) + 1, + y - crtc_state->psr2_su_area.y1); + if (x < 0) { pos |= CURSOR_POS_X_SIGN; x = -x; @@ -274,7 +286,7 @@ static void i845_cursor_update_arm(struct intel_plane *plane, size = CURSOR_HEIGHT(height) | CURSOR_WIDTH(width); base = intel_cursor_base(plane_state); - pos = intel_cursor_position(plane_state); + pos = intel_cursor_position(crtc_state, plane_state, false); } /* On these chipsets we can only modify the base/size/stride @@ -503,17 +515,24 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum pipe pipe = plane->pipe; if (!crtc_state->enable_psr2_sel_fetch) return; - if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), + if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) { + if (crtc_state->enable_psr2_su_region_et) { + u32 val = intel_cursor_position(crtc_state, plane_state, + true); + intel_de_write_fw(dev_priv, CURPOS_ERLY_TPT(pipe), val); + } + + intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), plane_state->ctl); - else + } else { i9xx_cursor_disable_sel_fetch_arm(plane, crtc_state); + } } /* TODO: split into noarm+arm pair */ @@ -536,7 +555,7 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane, fbc_ctl = CUR_FBC_EN | CUR_FBC_HEIGHT(height - 1); base = intel_cursor_base(plane_state); - pos = intel_cursor_position(plane_state); + pos = intel_cursor_position(crtc_state, plane_state, false); } /* @@ -647,12 +666,14 @@ intel_legacy_cursor_update(struct drm_plane *_plane, { struct intel_plane *plane = to_intel_plane(_plane); struct intel_crtc *crtc = to_intel_crtc(_crtc); + struct drm_i915_private *i915 = to_i915(plane->base.dev); struct intel_plane_state *old_plane_state = to_intel_plane_state(plane->base.state); struct intel_plane_state *new_plane_state; struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); struct intel_crtc_state *new_crtc_state; + struct intel_vblank_evade_ctx evade; int ret; /* @@ -745,13 +766,25 @@ intel_legacy_cursor_update(struct drm_plane *_plane, */ crtc_state->active_planes = new_crtc_state->active_planes; - /* - * Technically we should do a vblank evasion here to make - * sure all the cursor registers update on the same frame. - * For now just make sure the register writes happen as - * quickly as possible to minimize the race window. - */ - local_irq_disable(); + intel_vblank_evade_init(crtc_state, crtc_state, &evade); + + intel_psr_lock(crtc_state); + + if (!drm_WARN_ON(&i915->drm, drm_crtc_vblank_get(&crtc->base))) { + /* + * TODO: maybe check if we're still in PSR + * and skip the vblank evasion entirely? + */ + intel_psr_wait_for_idle_locked(crtc_state); + + local_irq_disable(); + + intel_vblank_evade(&evade); + + drm_crtc_vblank_put(&crtc->base); + } else { + local_irq_disable(); + } if (new_plane_state->uapi.visible) { intel_plane_update_noarm(plane, crtc_state, new_plane_state); @@ -762,6 +795,8 @@ intel_legacy_cursor_update(struct drm_plane *_plane, local_irq_enable(); + intel_psr_unlock(crtc_state); + intel_plane_unpin_fb(old_plane_state); out_free: diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 6b25e195232f13376f9b435f04fa48c50c01abdd..288a00e083c87596f46e1fe435b7f5644fc58c13 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -78,7 +78,7 @@ static void intel_cx0_program_msgbus_timer(struct intel_encoder *encoder) for_each_cx0_lane_in_mask(INTEL_CX0_BOTH_LANES, lane) intel_de_rmw(i915, - XELPDP_PORT_MSGBUS_TIMER(encoder->port, lane), + XELPDP_PORT_MSGBUS_TIMER(i915, encoder->port, lane), XELPDP_PORT_MSGBUS_TIMER_VAL_MASK, XELPDP_PORT_MSGBUS_TIMER_VAL); } @@ -117,7 +117,7 @@ static void intel_cx0_phy_transaction_end(struct intel_encoder *encoder, intel_w static void intel_clear_response_ready_flag(struct drm_i915_private *i915, enum port port, int lane) { - intel_de_rmw(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane), + intel_de_rmw(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(i915, port, lane), 0, XELPDP_PORT_P2M_RESPONSE_READY | XELPDP_PORT_P2M_ERROR_SET); } @@ -125,10 +125,10 @@ static void intel_cx0_bus_reset(struct drm_i915_private *i915, enum port port, i { enum phy phy = intel_port_to_phy(i915, port); - intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane), + intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane), XELPDP_PORT_M2P_TRANSACTION_RESET); - if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane), + if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane), XELPDP_PORT_M2P_TRANSACTION_RESET, XELPDP_MSGBUS_TIMEOUT_SLOW)) { drm_err_once(&i915->drm, "Failed to bring PHY %c to idle.\n", phy_name(phy)); @@ -144,7 +144,7 @@ static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port, enum phy phy = intel_port_to_phy(i915, port); if (__intel_de_wait_for_register(i915, - XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane), + XELPDP_PORT_P2M_MSGBUS_STATUS(i915, port, lane), XELPDP_PORT_P2M_RESPONSE_READY, XELPDP_PORT_P2M_RESPONSE_READY, XELPDP_MSGBUS_TIMEOUT_FAST_US, @@ -152,7 +152,7 @@ static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port, drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for message ACK. Status: 0x%x\n", phy_name(phy), *val); - if (!(intel_de_read(i915, XELPDP_PORT_MSGBUS_TIMER(port, lane)) & + if (!(intel_de_read(i915, XELPDP_PORT_MSGBUS_TIMER(i915, port, lane)) & XELPDP_PORT_MSGBUS_TIMER_TIMED_OUT)) drm_dbg_kms(&i915->drm, "PHY %c Hardware did not detect a timeout\n", @@ -186,7 +186,7 @@ static int __intel_cx0_read_once(struct drm_i915_private *i915, enum port port, int ack; u32 val; - if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane), + if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING, XELPDP_MSGBUS_TIMEOUT_SLOW)) { drm_dbg_kms(&i915->drm, @@ -195,7 +195,7 @@ static int __intel_cx0_read_once(struct drm_i915_private *i915, enum port port, return -ETIMEDOUT; } - intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane), + intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING | XELPDP_PORT_M2P_COMMAND_READ | XELPDP_PORT_M2P_ADDRESS(addr)); @@ -253,7 +253,7 @@ static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port, int ack; u32 val; - if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane), + if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING, XELPDP_MSGBUS_TIMEOUT_SLOW)) { drm_dbg_kms(&i915->drm, @@ -262,14 +262,14 @@ static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port, return -ETIMEDOUT; } - intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane), + intel_de_write(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING | (committed ? XELPDP_PORT_M2P_COMMAND_WRITE_COMMITTED : XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED) | XELPDP_PORT_M2P_DATA(data) | XELPDP_PORT_M2P_ADDRESS(addr)); - if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane), + if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING, XELPDP_MSGBUS_TIMEOUT_SLOW)) { drm_dbg_kms(&i915->drm, @@ -282,7 +282,7 @@ static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port, ack = intel_cx0_wait_for_ack(i915, port, XELPDP_PORT_P2M_COMMAND_WRITE_ACK, lane, &val); if (ack < 0) return ack; - } else if ((intel_de_read(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane)) & + } else if ((intel_de_read(i915, XELPDP_PORT_P2M_MSGBUS_STATUS(i915, port, lane)) & XELPDP_PORT_P2M_ERROR_SET)) { drm_dbg_kms(&i915->drm, "PHY %c Error occurred during write command.\n", phy_name(phy)); @@ -2096,13 +2096,54 @@ int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, return intel_c20pll_calc_state(crtc_state, encoder); } -static bool intel_c20_use_mplla(u32 clock) +static bool intel_c20phy_use_mpllb(const struct intel_c20pll_state *state) { - /* 10G and 20G rates use MPLLA */ - if (clock == 1000000 || clock == 2000000) - return true; + return state->tx[0] & C20_PHY_USE_MPLLB; +} - return false; +static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c20pll_state *pll_state) +{ + unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; + unsigned int multiplier, refclk = 38400; + unsigned int tx_clk_div; + unsigned int ref_clk_mpllb_div; + unsigned int fb_clk_div4_en; + unsigned int ref, vco; + unsigned int tx_rate_mult; + unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]); + + if (intel_c20phy_use_mpllb(pll_state)) { + tx_rate_mult = 1; + frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]); + frac_quot = pll_state->mpllb[8]; + frac_rem = pll_state->mpllb[9]; + frac_den = pll_state->mpllb[7]; + multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]); + tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]); + ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mpllb[6]); + fb_clk_div4_en = 0; + } else { + tx_rate_mult = 2; + frac_en = REG_FIELD_GET(C20_MPLLA_FRACEN, pll_state->mplla[6]); + frac_quot = pll_state->mplla[8]; + frac_rem = pll_state->mplla[9]; + frac_den = pll_state->mplla[7]; + multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]); + tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]); + ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mplla[6]); + fb_clk_div4_en = REG_FIELD_GET(C20_FB_CLK_DIV4_EN, pll_state->mplla[0]); + } + + if (frac_en) + frac = frac_quot + DIV_ROUND_CLOSEST(frac_rem, frac_den); + else + frac = 0; + + ref = DIV_ROUND_CLOSEST(refclk * (1 << (1 + fb_clk_div4_en)), 1 << ref_clk_mpllb_div); + vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(ref, (multiplier << (17 - 2)) + frac) >> 17, 10); + + return vco << tx_rate_mult >> tx_clk_div >> tx_rate; } static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, @@ -2138,7 +2179,7 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, PHY_C20_A_CMN_CNTX_CFG(i)); } - if (pll_state->tx[0] & C20_PHY_USE_MPLLB) { + if (intel_c20phy_use_mpllb(pll_state)) { /* MPLLB configuration */ for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) { if (cntx) @@ -2160,6 +2201,8 @@ static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, } } + pll_state->clock = intel_c20pll_calc_port_clock(encoder, pll_state); + intel_cx0_phy_transaction_end(encoder, wakeref); } @@ -2174,12 +2217,12 @@ void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, drm_dbg_kms(&i915->drm, "cmn[0] = 0x%.4x, cmn[1] = 0x%.4x, cmn[2] = 0x%.4x, cmn[3] = 0x%.4x\n", hw_state->cmn[0], hw_state->cmn[1], hw_state->cmn[2], hw_state->cmn[3]); - if (intel_c20_use_mplla(hw_state->clock)) { - for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++) - drm_dbg_kms(&i915->drm, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]); - } else { + if (intel_c20phy_use_mpllb(hw_state)) { for (i = 0; i < ARRAY_SIZE(hw_state->mpllb); i++) drm_dbg_kms(&i915->drm, "mpllb[%d] = 0x%.4x\n", i, hw_state->mpllb[i]); + } else { + for (i = 0; i < ARRAY_SIZE(hw_state->mplla); i++) + drm_dbg_kms(&i915->drm, "mplla[%d] = 0x%.4x\n", i, hw_state->mplla[i]); } } @@ -2326,27 +2369,27 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, } /* 3.3 mpllb or mplla configuration */ - if (intel_c20_use_mplla(clock)) { - for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) { + if (intel_c20phy_use_mpllb(pll_state)) { + for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) { if (cntx) intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, - PHY_C20_A_MPLLA_CNTX_CFG(i), - pll_state->mplla[i]); + PHY_C20_A_MPLLB_CNTX_CFG(i), + pll_state->mpllb[i]); else intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, - PHY_C20_B_MPLLA_CNTX_CFG(i), - pll_state->mplla[i]); + PHY_C20_B_MPLLB_CNTX_CFG(i), + pll_state->mpllb[i]); } } else { - for (i = 0; i < ARRAY_SIZE(pll_state->mpllb); i++) { + for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) { if (cntx) intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, - PHY_C20_A_MPLLB_CNTX_CFG(i), - pll_state->mpllb[i]); + PHY_C20_A_MPLLA_CNTX_CFG(i), + pll_state->mplla[i]); else intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, - PHY_C20_B_MPLLB_CNTX_CFG(i), - pll_state->mpllb[i]); + PHY_C20_B_MPLLA_CNTX_CFG(i), + pll_state->mplla[i]); } } @@ -2408,51 +2451,6 @@ static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, return tmpclk; } -static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c20pll_state *pll_state) -{ - unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; - unsigned int multiplier, refclk = 38400; - unsigned int tx_clk_div; - unsigned int ref_clk_mpllb_div; - unsigned int fb_clk_div4_en; - unsigned int ref, vco; - unsigned int tx_rate_mult; - unsigned int tx_rate = REG_FIELD_GET(C20_PHY_TX_RATE, pll_state->tx[0]); - - if (pll_state->tx[0] & C20_PHY_USE_MPLLB) { - tx_rate_mult = 1; - frac_en = REG_FIELD_GET(C20_MPLLB_FRACEN, pll_state->mpllb[6]); - frac_quot = pll_state->mpllb[8]; - frac_rem = pll_state->mpllb[9]; - frac_den = pll_state->mpllb[7]; - multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mpllb[0]); - tx_clk_div = REG_FIELD_GET(C20_MPLLB_TX_CLK_DIV_MASK, pll_state->mpllb[0]); - ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mpllb[6]); - fb_clk_div4_en = 0; - } else { - tx_rate_mult = 2; - frac_en = REG_FIELD_GET(C20_MPLLA_FRACEN, pll_state->mplla[6]); - frac_quot = pll_state->mplla[8]; - frac_rem = pll_state->mplla[9]; - frac_den = pll_state->mplla[7]; - multiplier = REG_FIELD_GET(C20_MULTIPLIER_MASK, pll_state->mplla[0]); - tx_clk_div = REG_FIELD_GET(C20_MPLLA_TX_CLK_DIV_MASK, pll_state->mplla[1]); - ref_clk_mpllb_div = REG_FIELD_GET(C20_REF_CLK_MPLLB_DIV_MASK, pll_state->mplla[6]); - fb_clk_div4_en = REG_FIELD_GET(C20_FB_CLK_DIV4_EN, pll_state->mplla[0]); - } - - if (frac_en) - frac = frac_quot + DIV_ROUND_CLOSEST(frac_rem, frac_den); - else - frac = 0; - - ref = DIV_ROUND_CLOSEST(refclk * (1 << (1 + fb_clk_div4_en)), 1 << ref_clk_mpllb_div); - vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(ref, (multiplier << (17 - 2)) + frac) >> 17, 10); - - return vco << tx_rate_mult >> tx_clk_div >> tx_rate; -} - static void intel_program_port_clock_ctl(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, bool lane_reversal) @@ -2460,7 +2458,8 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); u32 val = 0; - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(encoder->port), XELPDP_PORT_REVERSAL, + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(i915, encoder->port), + XELPDP_PORT_REVERSAL, lane_reversal ? XELPDP_PORT_REVERSAL : 0); if (lane_reversal) @@ -2481,7 +2480,7 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder, else val |= crtc_state->cx0pll_state.ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), XELPDP_LANE1_PHY_CLOCK_SELECT | XELPDP_FORWARD_CLOCK_UNGATE | XELPDP_DDI_CLOCK_SELECT_MASK | XELPDP_SSC_ENABLE_PLLA | XELPDP_SSC_ENABLE_PLLB, val); @@ -2514,15 +2513,16 @@ static void intel_cx0_powerdown_change_sequence(struct drm_i915_private *i915, u8 lane_mask, u8 state) { enum phy phy = intel_port_to_phy(i915, port); + i915_reg_t buf_ctl2_reg = XELPDP_PORT_BUF_CTL2(i915, port); int lane; - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), + intel_de_rmw(i915, buf_ctl2_reg, intel_cx0_get_powerdown_state(INTEL_CX0_BOTH_LANES, XELPDP_LANE_POWERDOWN_NEW_STATE_MASK), intel_cx0_get_powerdown_state(lane_mask, state)); /* Wait for pending transactions.*/ for_each_cx0_lane_in_mask(lane_mask, lane) - if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(port, lane), + if (intel_de_wait_for_clear(i915, XELPDP_PORT_M2P_MSGBUS_CTL(i915, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING, XELPDP_MSGBUS_TIMEOUT_SLOW)) { drm_dbg_kms(&i915->drm, @@ -2531,12 +2531,12 @@ static void intel_cx0_powerdown_change_sequence(struct drm_i915_private *i915, intel_cx0_bus_reset(i915, port, lane); } - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), + intel_de_rmw(i915, buf_ctl2_reg, intel_cx0_get_powerdown_update(INTEL_CX0_BOTH_LANES), intel_cx0_get_powerdown_update(lane_mask)); /* Update Timeout Value */ - if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL2(port), + if (__intel_de_wait_for_register(i915, buf_ctl2_reg, intel_cx0_get_powerdown_update(lane_mask), 0, XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_US, 0, NULL)) drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dus.\n", @@ -2545,10 +2545,10 @@ static void intel_cx0_powerdown_change_sequence(struct drm_i915_private *i915, static void intel_cx0_setup_powerdown(struct drm_i915_private *i915, enum port port) { - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(i915, port), XELPDP_POWER_STATE_READY_MASK, XELPDP_POWER_STATE_READY(CX0_P2_STATE_READY)); - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL3(port), + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL3(i915, port), XELPDP_POWER_STATE_ACTIVE_MASK | XELPDP_PLL_LANE_STAGGERING_DELAY_MASK, XELPDP_POWER_STATE_ACTIVE(CX0_P0_STATE_ACTIVE) | @@ -2593,27 +2593,27 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915, XELPDP_LANE_PHY_CURRENT_STATUS(1)) : XELPDP_LANE_PHY_CURRENT_STATUS(0); - if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL1(port), + if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL1(i915, port), XELPDP_PORT_BUF_SOC_PHY_READY, XELPDP_PORT_BUF_SOC_PHY_READY, XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US, 0, NULL)) drm_warn(&i915->drm, "PHY %c failed to bring out of SOC reset after %dus.\n", phy_name(phy), XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US); - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), lane_pipe_reset, + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(i915, port), lane_pipe_reset, lane_pipe_reset); - if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL2(port), + if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL2(i915, port), lane_phy_current_status, lane_phy_current_status, XELPDP_PORT_RESET_START_TIMEOUT_US, 0, NULL)) drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dus.\n", phy_name(phy), XELPDP_PORT_RESET_START_TIMEOUT_US); - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, port), intel_cx0_get_pclk_refclk_request(owned_lane_mask), intel_cx0_get_pclk_refclk_request(lane_mask)); - if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(port), + if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, port), intel_cx0_get_pclk_refclk_ack(owned_lane_mask), intel_cx0_get_pclk_refclk_ack(lane_mask), XELPDP_REFCLK_ENABLE_TIMEOUT_US, 0, NULL)) @@ -2624,9 +2624,10 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915, CX0_P2_STATE_RESET); intel_cx0_setup_powerdown(i915, port); - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(port), lane_pipe_reset, 0); + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL2(i915, port), lane_pipe_reset, 0); - if (intel_de_wait_for_clear(i915, XELPDP_PORT_BUF_CTL2(port), lane_phy_current_status, + if (intel_de_wait_for_clear(i915, XELPDP_PORT_BUF_CTL2(i915, port), + lane_phy_current_status, XELPDP_PORT_RESET_END_TIMEOUT)) drm_warn(&i915->drm, "PHY %c failed to bring out of Lane reset after %dms.\n", phy_name(phy), XELPDP_PORT_RESET_END_TIMEOUT); @@ -2761,12 +2762,12 @@ static void intel_cx0pll_enable(struct intel_encoder *encoder, * 9. Set PORT_CLOCK_CTL register PCLK PLL Request * LN to "1" to enable PLL. */ - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES), intel_cx0_get_pclk_pll_request(maxpclk_lane)); /* 10. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN == "1". */ - if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES), intel_cx0_get_pclk_pll_ack(maxpclk_lane), XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US, 0, NULL)) @@ -2786,7 +2787,7 @@ int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); u32 clock; - u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(encoder->port)); + u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port)); clock = REG_FIELD_GET(XELPDP_DDI_CLOCK_SELECT_MASK, val); @@ -2839,11 +2840,11 @@ static void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder, */ val |= XELPDP_DDI_CLOCK_SELECT(intel_mtl_tbt_clock_select(i915, crtc_state->port_clock)); val |= XELPDP_FORWARD_CLOCK_UNGATE; - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), XELPDP_DDI_CLOCK_SELECT_MASK | XELPDP_FORWARD_CLOCK_UNGATE, val); /* 2. Read back PORT_CLOCK_CTL REGISTER */ - val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(encoder->port)); + val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port)); /* * 3. Follow the Display Voltage Frequency Switching - Sequence @@ -2854,10 +2855,10 @@ static void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder, * 4. Set PORT_CLOCK_CTL register TBT CLOCK Request to "1" to enable PLL. */ val |= XELPDP_TBT_CLOCK_REQUEST; - intel_de_write(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), val); + intel_de_write(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), val); /* 5. Poll on PORT_CLOCK_CTL TBT CLOCK Ack == "1". */ - if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), XELPDP_TBT_CLOCK_ACK, XELPDP_TBT_CLOCK_ACK, 100, 0, NULL)) @@ -2909,7 +2910,7 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder) * 3. Set PORT_CLOCK_CTL register PCLK PLL Request LN * to "0" to disable PLL. */ - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES) | intel_cx0_get_pclk_refclk_request(INTEL_CX0_BOTH_LANES), 0); @@ -2919,7 +2920,7 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder) /* * 5. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN == "0". */ - if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES) | intel_cx0_get_pclk_refclk_ack(INTEL_CX0_BOTH_LANES), 0, XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US, 0, NULL)) @@ -2932,9 +2933,9 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder) */ /* 7. Program PORT_CLOCK_CTL register to disable and gate clocks. */ - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), XELPDP_DDI_CLOCK_SELECT_MASK, 0); - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), XELPDP_FORWARD_CLOCK_UNGATE, 0); intel_cx0_phy_transaction_end(encoder, wakeref); @@ -2953,11 +2954,11 @@ static void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder) /* * 2. Set PORT_CLOCK_CTL register TBT CLOCK Request to "0" to disable PLL. */ - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), XELPDP_TBT_CLOCK_REQUEST, 0); /* 3. Poll on PORT_CLOCK_CTL TBT CLOCK Ack == "0". */ - if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), XELPDP_TBT_CLOCK_ACK, 0, 10, 0, NULL)) drm_warn(&i915->drm, "[ENCODER:%d:%s][%c] PHY PLL not unlocked after 10us.\n", encoder->base.base.id, encoder->base.name, phy_name(phy)); @@ -2970,7 +2971,7 @@ static void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder) /* * 5. Program PORT CLOCK CTRL register to disable and gate clocks */ - intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port), XELPDP_DDI_CLOCK_SELECT_MASK | XELPDP_FORWARD_CLOCK_UNGATE, 0); @@ -2997,7 +2998,7 @@ intel_mtl_port_pll_type(struct intel_encoder *encoder, * TODO: Determine the PLL type from the SW state, once MTL PLL * handling is done via the standard shared DPLL framework. */ - u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(encoder->port)); + u32 val = intel_de_read(i915, XELPDP_PORT_CLOCK_CTL(i915, encoder->port)); u32 clock = REG_FIELD_GET(XELPDP_DDI_CLOCK_SELECT_MASK, val); if (clock == XELPDP_DDI_CLOCK_SELECT_MAXPCLK || @@ -3016,6 +3017,9 @@ static void intel_c10pll_state_verify(const struct intel_crtc_state *state, const struct intel_c10pll_state *mpllb_sw_state = &state->cx0pll_state.c10; int i; + if (intel_crtc_needs_fastset(state)) + return; + for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) { u8 expected = mpllb_sw_state->pll[i]; @@ -3067,10 +3071,15 @@ static void intel_c20pll_state_verify(const struct intel_crtc_state *state, { struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct intel_c20pll_state *mpll_sw_state = &state->cx0pll_state.c20; - bool sw_use_mpllb = mpll_sw_state->tx[0] & C20_PHY_USE_MPLLB; - bool hw_use_mpllb = mpll_hw_state->tx[0] & C20_PHY_USE_MPLLB; + bool sw_use_mpllb = intel_c20phy_use_mpllb(mpll_sw_state); + bool hw_use_mpllb = intel_c20phy_use_mpllb(mpll_hw_state); int i; + I915_STATE_WARN(i915, mpll_hw_state->clock != mpll_sw_state->clock, + "[CRTC:%d:%s] mismatch in C20: Register CLOCK (expected %d, found %d)", + crtc->base.base.id, crtc->base.name, + mpll_sw_state->clock, mpll_hw_state->clock); + I915_STATE_WARN(i915, sw_use_mpllb != hw_use_mpllb, "[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)", crtc->base.base.id, crtc->base.name, diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index adf8f4ce0d493119caf2ee0025b9e91c6c146d7e..bdd0c8c4ef9743d558f295faf81ea6b2dbaef61c 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -7,16 +7,39 @@ #define __INTEL_CX0_PHY_REGS_H__ #include "i915_reg_defs.h" +#include "intel_display_limits.h" + +/* + * Wrapper macro to convert from port number to the index used in some of the + * registers. For Display version 20 and above it converts the port number to a + * single range, starting with the TC offsets. When used together with + * _PICK_EVEN_2RANGES(idx, PORT_TC1, ...), this single range will be the second + * range. Example: + * + * PORT_TC1 -> PORT_TC1 + * PORT_TC2 -> PORT_TC2 + * PORT_TC3 -> PORT_TC3 + * PORT_TC4 -> PORT_TC4 + * PORT_A -> PORT_TC4 + 1 + * PORT_B -> PORT_TC4 + 2 + * ... + */ +#define __xe2lpd_port_idx(port) \ + (port >= PORT_TC1 ? port : PORT_TC4 + 1 + port - PORT_A) #define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A 0x64040 #define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B 0x64140 #define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1 0x16F240 #define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2 0x16F440 -#define XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ +#define _XELPDP_PORT_M2P_MSGBUS_CTL(idx, lane) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \ _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A, \ _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B, \ _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1, \ _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2) + (lane) * 4) +#define XELPDP_PORT_M2P_MSGBUS_CTL(i915__, port, lane) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_PORT_M2P_MSGBUS_CTL(__xe2lpd_port_idx(port), lane) : \ + _XELPDP_PORT_M2P_MSGBUS_CTL(port, lane)) #define XELPDP_PORT_M2P_TRANSACTION_PENDING REG_BIT(31) #define XELPDP_PORT_M2P_COMMAND_TYPE_MASK REG_GENMASK(30, 27) #define XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x1) @@ -27,11 +50,16 @@ #define XELPDP_PORT_M2P_TRANSACTION_RESET REG_BIT(15) #define XELPDP_PORT_M2P_ADDRESS_MASK REG_GENMASK(11, 0) #define XELPDP_PORT_M2P_ADDRESS(val) REG_FIELD_PREP(XELPDP_PORT_M2P_ADDRESS_MASK, val) -#define XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ + +#define _XELPDP_PORT_P2M_MSGBUS_STATUS(idx, lane) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \ _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A, \ _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B, \ _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1, \ _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2) + (lane) * 4 + 8) +#define XELPDP_PORT_P2M_MSGBUS_STATUS(i915__, port, lane) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_PORT_P2M_MSGBUS_STATUS(__xe2lpd_port_idx(port), lane) : \ + _XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane)) #define XELPDP_PORT_P2M_RESPONSE_READY REG_BIT(31) #define XELPDP_PORT_P2M_COMMAND_TYPE_MASK REG_GENMASK(30, 27) #define XELPDP_PORT_P2M_COMMAND_READ_ACK 0x4 @@ -54,11 +82,15 @@ #define _XELPDP_PORT_BUF_CTL1_LN0_B 0x64104 #define _XELPDP_PORT_BUF_CTL1_LN0_USBC1 0x16F200 #define _XELPDP_PORT_BUF_CTL1_LN0_USBC2 0x16F400 -#define XELPDP_PORT_BUF_CTL1(port) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ +#define _XELPDP_PORT_BUF_CTL1(idx) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \ _XELPDP_PORT_BUF_CTL1_LN0_A, \ _XELPDP_PORT_BUF_CTL1_LN0_B, \ _XELPDP_PORT_BUF_CTL1_LN0_USBC1, \ _XELPDP_PORT_BUF_CTL1_LN0_USBC2)) +#define XELPDP_PORT_BUF_CTL1(i915__, port) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_PORT_BUF_CTL1(__xe2lpd_port_idx(port)) : \ + _XELPDP_PORT_BUF_CTL1(port)) #define XELPDP_PORT_BUF_D2D_LINK_ENABLE REG_BIT(29) #define XELPDP_PORT_BUF_D2D_LINK_STATE REG_BIT(28) #define XELPDP_PORT_BUF_SOC_PHY_READY REG_BIT(24) @@ -75,12 +107,15 @@ #define XELPDP_PORT_WIDTH_MASK REG_GENMASK(3, 1) #define XELPDP_PORT_WIDTH(val) REG_FIELD_PREP(XELPDP_PORT_WIDTH_MASK, val) -#define XELPDP_PORT_BUF_CTL2(port) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ +#define _XELPDP_PORT_BUF_CTL2(idx) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \ _XELPDP_PORT_BUF_CTL1_LN0_A, \ _XELPDP_PORT_BUF_CTL1_LN0_B, \ _XELPDP_PORT_BUF_CTL1_LN0_USBC1, \ _XELPDP_PORT_BUF_CTL1_LN0_USBC2) + 4) - +#define XELPDP_PORT_BUF_CTL2(i915__, port) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_PORT_BUF_CTL2(__xe2lpd_port_idx(port)) : \ + _XELPDP_PORT_BUF_CTL2(port)) #define XELPDP_LANE_PIPE_RESET(lane) _PICK(lane, REG_BIT(31), REG_BIT(30)) #define XELPDP_LANE_PHY_CURRENT_STATUS(lane) _PICK(lane, REG_BIT(29), REG_BIT(28)) #define XELPDP_LANE_POWERDOWN_UPDATE(lane) _PICK(lane, REG_BIT(25), REG_BIT(24)) @@ -95,11 +130,15 @@ #define XELPDP_POWER_STATE_READY_MASK REG_GENMASK(7, 4) #define XELPDP_POWER_STATE_READY(val) REG_FIELD_PREP(XELPDP_POWER_STATE_READY_MASK, val) -#define XELPDP_PORT_BUF_CTL3(port) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ +#define _XELPDP_PORT_BUF_CTL3(idx) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \ _XELPDP_PORT_BUF_CTL1_LN0_A, \ _XELPDP_PORT_BUF_CTL1_LN0_B, \ _XELPDP_PORT_BUF_CTL1_LN0_USBC1, \ _XELPDP_PORT_BUF_CTL1_LN0_USBC2) + 8) +#define XELPDP_PORT_BUF_CTL3(i915__, port) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_PORT_BUF_CTL3(__xe2lpd_port_idx(port)) : \ + _XELPDP_PORT_BUF_CTL3(port)) #define XELPDP_PLL_LANE_STAGGERING_DELAY_MASK REG_GENMASK(15, 8) #define XELPDP_PLL_LANE_STAGGERING_DELAY(val) REG_FIELD_PREP(XELPDP_PLL_LANE_STAGGERING_DELAY_MASK, val) #define XELPDP_POWER_STATE_ACTIVE_MASK REG_GENMASK(3, 0) @@ -114,11 +153,15 @@ #define _XELPDP_PORT_MSGBUS_TIMER_LN0_B 0x641d8 #define _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC1 0x16f258 #define _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC2 0x16f458 -#define XELPDP_PORT_MSGBUS_TIMER(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ +#define _XELPDP_PORT_MSGBUS_TIMER(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ _XELPDP_PORT_MSGBUS_TIMER_LN0_A, \ _XELPDP_PORT_MSGBUS_TIMER_LN0_B, \ _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC1, \ _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC2) + (lane) * 4) +#define XELPDP_PORT_MSGBUS_TIMER(i915__, port, lane) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_PORT_MSGBUS_TIMER(__xe2lpd_port_idx(port), lane) : \ + _XELPDP_PORT_MSGBUS_TIMER(port, lane)) #define XELPDP_PORT_MSGBUS_TIMER_TIMED_OUT REG_BIT(31) #define XELPDP_PORT_MSGBUS_TIMER_VAL_MASK REG_GENMASK(23, 0) #define XELPDP_PORT_MSGBUS_TIMER_VAL REG_FIELD_PREP(XELPDP_PORT_MSGBUS_TIMER_VAL_MASK, 0xa000) @@ -127,11 +170,15 @@ #define _XELPDP_PORT_CLOCK_CTL_B 0x641E0 #define _XELPDP_PORT_CLOCK_CTL_USBC1 0x16F260 #define _XELPDP_PORT_CLOCK_CTL_USBC2 0x16F460 -#define XELPDP_PORT_CLOCK_CTL(port) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ +#define _XELPDP_PORT_CLOCK_CTL(idx) _MMIO(_PICK_EVEN_2RANGES(idx, PORT_TC1, \ _XELPDP_PORT_CLOCK_CTL_A, \ _XELPDP_PORT_CLOCK_CTL_B, \ _XELPDP_PORT_CLOCK_CTL_USBC1, \ _XELPDP_PORT_CLOCK_CTL_USBC2)) +#define XELPDP_PORT_CLOCK_CTL(i915__, port) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_PORT_CLOCK_CTL(__xe2lpd_port_idx(port)) : \ + _XELPDP_PORT_CLOCK_CTL(port)) #define XELPDP_LANE_PCLK_PLL_REQUEST(lane) REG_BIT(31 - ((lane) * 4)) #define XELPDP_LANE_PCLK_PLL_ACK(lane) REG_BIT(30 - ((lane) * 4)) #define XELPDP_LANE_PCLK_REFCLK_REQUEST(lane) REG_BIT(29 - ((lane) * 4)) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 12a29363e5dfe493a724afddba08f38228fc09fb..bea441590204485c5043987275eafb118cf7ea3f 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -178,7 +178,7 @@ static void mtl_wait_ddi_buf_idle(struct drm_i915_private *i915, enum port port) int ret; /* FIXME: find out why Bspec's 100us timeout is too short */ - ret = wait_for_us((intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)) & + ret = wait_for_us((intel_de_read(i915, XELPDP_PORT_BUF_CTL1(i915, port)) & XELPDP_PORT_BUF_PHY_IDLE), 10000); if (ret) drm_err(&i915->drm, "Timeout waiting for DDI BUF %c to get idle\n", @@ -226,7 +226,9 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv, } if (DISPLAY_VER(dev_priv) >= 14) - ret = _wait_for(!(intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) & XELPDP_PORT_BUF_PHY_IDLE), + ret = _wait_for(!(intel_de_read(dev_priv, + XELPDP_PORT_BUF_CTL1(dev_priv, port)) & + XELPDP_PORT_BUF_PHY_IDLE), timeout_us, 10, 10); else ret = _wait_for(!(intel_de_read(dev_priv, DDI_BUF_CTL(port)) & DDI_BUF_IS_IDLE), @@ -2429,13 +2431,22 @@ mtl_ddi_enable_d2d(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; + i915_reg_t reg; + u32 set_bits, wait_bits; - intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(port), 0, - XELPDP_PORT_BUF_D2D_LINK_ENABLE); + if (DISPLAY_VER(dev_priv) >= 20) { + reg = DDI_BUF_CTL(port); + set_bits = XE2LPD_DDI_BUF_D2D_LINK_ENABLE; + wait_bits = XE2LPD_DDI_BUF_D2D_LINK_STATE; + } else { + reg = XELPDP_PORT_BUF_CTL1(dev_priv, port); + set_bits = XELPDP_PORT_BUF_D2D_LINK_ENABLE; + wait_bits = XELPDP_PORT_BUF_D2D_LINK_STATE; + } - if (wait_for_us((intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) & - XELPDP_PORT_BUF_D2D_LINK_STATE), 100)) { - drm_err(&dev_priv->drm, "Timeout waiting for D2D Link enable for PORT_BUF_CTL %c\n", + intel_de_rmw(dev_priv, reg, 0, set_bits); + if (wait_for_us(intel_de_read(dev_priv, reg) & wait_bits, 100)) { + drm_err(&dev_priv->drm, "Timeout waiting for D2D Link enable for DDI/PORT_BUF_CTL %c\n", port_name(port)); } } @@ -2448,7 +2459,7 @@ static void mtl_port_buf_ctl_program(struct intel_encoder *encoder, enum port port = encoder->port; u32 val; - val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)); + val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(i915, port)); val &= ~XELPDP_PORT_WIDTH_MASK; val |= XELPDP_PORT_WIDTH(mtl_get_port_width(crtc_state->lane_count)); @@ -2461,7 +2472,7 @@ static void mtl_port_buf_ctl_program(struct intel_encoder *encoder, if (dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL) val |= XELPDP_PORT_REVERSAL; - intel_de_write(i915, XELPDP_PORT_BUF_CTL1(port), val); + intel_de_write(i915, XELPDP_PORT_BUF_CTL1(i915, port), val); } static void mtl_port_buf_ctl_io_selection(struct intel_encoder *encoder) @@ -2472,7 +2483,7 @@ static void mtl_port_buf_ctl_io_selection(struct intel_encoder *encoder) val = intel_tc_port_in_tbt_alt_mode(dig_port) ? XELPDP_PORT_BUF_IO_SELECT_TBT : 0; - intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(encoder->port), + intel_de_rmw(i915, XELPDP_PORT_BUF_CTL1(i915, encoder->port), XELPDP_PORT_BUF_IO_SELECT_TBT, val); } @@ -2898,13 +2909,22 @@ mtl_ddi_disable_d2d_link(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; + i915_reg_t reg; + u32 clr_bits, wait_bits; - intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(port), - XELPDP_PORT_BUF_D2D_LINK_ENABLE, 0); + if (DISPLAY_VER(dev_priv) >= 20) { + reg = DDI_BUF_CTL(port); + clr_bits = XE2LPD_DDI_BUF_D2D_LINK_ENABLE; + wait_bits = XE2LPD_DDI_BUF_D2D_LINK_STATE; + } else { + reg = XELPDP_PORT_BUF_CTL1(dev_priv, port); + clr_bits = XELPDP_PORT_BUF_D2D_LINK_ENABLE; + wait_bits = XELPDP_PORT_BUF_D2D_LINK_STATE; + } - if (wait_for_us(!(intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)) & - XELPDP_PORT_BUF_D2D_LINK_STATE), 100)) - drm_err(&dev_priv->drm, "Timeout waiting for D2D Link disable for PORT_BUF_CTL %c\n", + intel_de_rmw(dev_priv, reg, clr_bits, 0); + if (wait_for_us(!(intel_de_read(dev_priv, reg) & wait_bits), 100)) + drm_err(&dev_priv->drm, "Timeout waiting for D2D Link disable for DDI/PORT_BUF_CTL %c\n", port_name(port)); } @@ -3038,7 +3058,7 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, /* De-select Thunderbolt */ if (DISPLAY_VER(dev_priv) >= 14) - intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(encoder->port), + intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(dev_priv, encoder->port), XELPDP_PORT_BUF_IO_SELECT_TBT, 0); } @@ -3319,10 +3339,13 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, if (dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL) port_buf |= XELPDP_PORT_REVERSAL; - intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(port), + intel_de_rmw(dev_priv, XELPDP_PORT_BUF_CTL1(dev_priv, port), XELPDP_PORT_WIDTH_MASK | XELPDP_PORT_REVERSAL, port_buf); buf_ctl |= DDI_PORT_WIDTH(lane_count); + + if (DISPLAY_VER(dev_priv) >= 20) + buf_ctl |= XE2LPD_DDI_BUF_D2D_LINK_ENABLE; } else if (IS_ALDERLAKE_P(dev_priv) && intel_phy_is_tc(dev_priv, phy)) { drm_WARN_ON(&dev_priv->drm, !intel_tc_port_in_legacy_mode(dig_port)); buf_ctl |= DDI_BUF_CTL_TC_PHY_OWNERSHIP; @@ -3543,6 +3566,9 @@ static void mtl_ddi_prepare_link_retrain(struct intel_dp *intel_dp, /* 6.i Configure and enable DDI_CTL_DE to start sending valid data to port slice */ intel_dp->DP |= DDI_BUF_CTL_ENABLE; + if (DISPLAY_VER(dev_priv) >= 20) + intel_dp->DP |= XE2LPD_DDI_BUF_D2D_LINK_ENABLE; + intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP); intel_de_posting_read(dev_priv, DDI_BUF_CTL(port)); @@ -3941,11 +3967,11 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, if (DISPLAY_VER(dev_priv) >= 8) bdw_get_trans_port_sync_config(pipe_config); + intel_psr_get_config(encoder, pipe_config); + intel_read_dp_sdp(encoder, pipe_config, HDMI_PACKET_TYPE_GAMUT_METADATA); intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC); - intel_psr_get_config(encoder, pipe_config); - intel_audio_codec_get_config(encoder, pipe_config); } @@ -5117,6 +5143,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, encoder->suspend_complete = intel_ddi_tc_encoder_suspend_complete; encoder->shutdown_complete = intel_ddi_tc_encoder_shutdown_complete; + dig_port->lock = intel_tc_port_lock; + dig_port->unlock = intel_tc_port_unlock; + if (intel_tc_port_init(dig_port, is_legacy) < 0) goto err; } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b10aad15a63d913cbef5f813fd3b1805027e601d..7db0655d8c9e020d678909696bf6bcfca4bb8d9e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -104,6 +104,7 @@ #include "intel_pmdemand.h" #include "intel_pps.h" #include "intel_psr.h" +#include "intel_psr_regs.h" #include "intel_sdvo.h" #include "intel_snps_phy.h" #include "intel_tc.h" @@ -2706,6 +2707,15 @@ static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state) */ intel_de_write(dev_priv, PIPESRC(pipe), PIPESRC_WIDTH(width - 1) | PIPESRC_HEIGHT(height - 1)); + + if (!crtc_state->enable_psr2_su_region_et) + return; + + width = drm_rect_width(&crtc_state->psr2_su_area); + height = drm_rect_height(&crtc_state->psr2_su_area); + + intel_de_write(dev_priv, PIPE_SRCSZ_ERLY_TPT(pipe), + PIPESRC_WIDTH(width - 1) | PIPESRC_HEIGHT(height - 1)); } static bool intel_pipe_is_interlaced(const struct intel_crtc_state *crtc_state) @@ -4764,7 +4774,11 @@ static bool intel_compare_dp_vsc_sdp(const struct drm_dp_vsc_sdp *a, const struct drm_dp_vsc_sdp *b) { - return memcmp(a, b, sizeof(*a)) == 0; + return a->pixelformat == b->pixelformat && + a->colorimetry == b->colorimetry && + a->bpc == b->bpc && + a->dynamic_range == b->dynamic_range && + a->content_type == b->content_type; } static bool @@ -4799,28 +4813,27 @@ pipe_config_infoframe_mismatch(struct drm_i915_private *dev_priv, } static void -pipe_config_dp_vsc_sdp_mismatch(struct drm_i915_private *dev_priv, +pipe_config_dp_vsc_sdp_mismatch(struct drm_i915_private *i915, bool fastset, const char *name, const struct drm_dp_vsc_sdp *a, const struct drm_dp_vsc_sdp *b) { + struct drm_printer p; + if (fastset) { - if (!drm_debug_enabled(DRM_UT_KMS)) - return; + p = drm_dbg_printer(&i915->drm, DRM_UT_KMS, NULL); - drm_dbg_kms(&dev_priv->drm, - "fastset requirement not met in %s dp sdp\n", name); - drm_dbg_kms(&dev_priv->drm, "expected:\n"); - drm_dp_vsc_sdp_log(KERN_DEBUG, dev_priv->drm.dev, a); - drm_dbg_kms(&dev_priv->drm, "found:\n"); - drm_dp_vsc_sdp_log(KERN_DEBUG, dev_priv->drm.dev, b); + drm_printf(&p, "fastset requirement not met in %s dp sdp\n", name); } else { - drm_err(&dev_priv->drm, "mismatch in %s dp sdp\n", name); - drm_err(&dev_priv->drm, "expected:\n"); - drm_dp_vsc_sdp_log(KERN_ERR, dev_priv->drm.dev, a); - drm_err(&dev_priv->drm, "found:\n"); - drm_dp_vsc_sdp_log(KERN_ERR, dev_priv->drm.dev, b); + p = drm_err_printer(&i915->drm, NULL); + + drm_printf(&p, "mismatch in %s dp sdp\n", name); } + + drm_printf(&p, "expected:\n"); + drm_dp_vsc_sdp_log(&p, a); + drm_printf(&p, "found:\n"); + drm_dp_vsc_sdp_log(&p, b); } /* Returns the length up to and including the last differing byte */ @@ -5045,8 +5058,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, } while (0) #define PIPE_CONF_CHECK_DP_VSC_SDP(name) do { \ - if (!current_config->has_psr && !pipe_config->has_psr && \ - !intel_compare_dp_vsc_sdp(¤t_config->infoframes.name, \ + if (!intel_compare_dp_vsc_sdp(¤t_config->infoframes.name, \ &pipe_config->infoframes.name)) { \ pipe_config_dp_vsc_sdp_mismatch(dev_priv, fastset, __stringify(name), \ ¤t_config->infoframes.name, \ @@ -5199,13 +5211,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_CSC(csc); PIPE_CONF_CHECK_CSC(output_csc); - - if (current_config->active_planes) { - PIPE_CONF_CHECK_BOOL(has_psr); - PIPE_CONF_CHECK_BOOL(has_psr2); - PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch); - PIPE_CONF_CHECK_I(dc3co_exitline); - } } PIPE_CONF_CHECK_BOOL(double_wide); @@ -6307,6 +6312,9 @@ int intel_atomic_check(struct drm_device *dev, int ret, i; bool any_ms = false; + if (!intel_display_driver_check_access(dev_priv)) + return -ENODEV; + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { /* @@ -7068,6 +7076,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) drm_atomic_helper_wait_for_dependencies(&state->base); drm_dp_mst_atomic_wait_for_dependencies(&state->base); + intel_atomic_global_state_wait_for_dependencies(state); /* * During full modesets we write a lot of registers, wait @@ -7244,6 +7253,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_pmdemand_post_plane_update(state); drm_atomic_helper_commit_hw_done(&state->base); + intel_atomic_global_state_commit_done(state); if (state->modeset) { /* As one of the primary mmio accessors, KMS has a high @@ -7294,6 +7304,38 @@ static void intel_atomic_track_fbs(struct intel_atomic_state *state) plane->frontbuffer_bit); } +static int intel_atomic_setup_commit(struct intel_atomic_state *state, bool nonblock) +{ + int ret; + + ret = drm_atomic_helper_setup_commit(&state->base, nonblock); + if (ret) + return ret; + + ret = intel_atomic_global_state_setup_commit(state); + if (ret) + return ret; + + return 0; +} + +static int intel_atomic_swap_state(struct intel_atomic_state *state) +{ + int ret; + + ret = drm_atomic_helper_swap_state(&state->base, true); + if (ret) + return ret; + + intel_atomic_swap_global_state(state); + + intel_shared_dpll_swap_state(state); + + intel_atomic_track_fbs(state); + + return 0; +} + int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, bool nonblock) { @@ -7339,11 +7381,9 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, return ret; } - ret = drm_atomic_helper_setup_commit(&state->base, nonblock); + ret = intel_atomic_setup_commit(state, nonblock); if (!ret) - ret = drm_atomic_helper_swap_state(&state->base, true); - if (!ret) - intel_atomic_swap_global_state(state); + ret = intel_atomic_swap_state(state); if (ret) { struct intel_crtc_state *new_crtc_state; @@ -7357,8 +7397,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref); return ret; } - intel_shared_dpll_swap_state(state); - intel_atomic_track_fbs(state); drm_atomic_state_get(&state->base); INIT_WORK(&state->base.commit_work, intel_atomic_commit_work); @@ -7811,6 +7849,7 @@ static const struct intel_display_funcs skl_display_funcs = { .crtc_disable = hsw_crtc_disable, .commit_modeset_enables = skl_commit_modeset_enables, .get_initial_plane_config = skl_get_initial_plane_config, + .fixup_initial_plane_config = skl_fixup_initial_plane_config, }; static const struct intel_display_funcs ddi_display_funcs = { @@ -7819,6 +7858,7 @@ static const struct intel_display_funcs ddi_display_funcs = { .crtc_disable = hsw_crtc_disable, .commit_modeset_enables = intel_commit_modeset_enables, .get_initial_plane_config = i9xx_get_initial_plane_config, + .fixup_initial_plane_config = i9xx_fixup_initial_plane_config, }; static const struct intel_display_funcs pch_split_display_funcs = { @@ -7827,6 +7867,7 @@ static const struct intel_display_funcs pch_split_display_funcs = { .crtc_disable = ilk_crtc_disable, .commit_modeset_enables = intel_commit_modeset_enables, .get_initial_plane_config = i9xx_get_initial_plane_config, + .fixup_initial_plane_config = i9xx_fixup_initial_plane_config, }; static const struct intel_display_funcs vlv_display_funcs = { @@ -7835,6 +7876,7 @@ static const struct intel_display_funcs vlv_display_funcs = { .crtc_disable = i9xx_crtc_disable, .commit_modeset_enables = intel_commit_modeset_enables, .get_initial_plane_config = i9xx_get_initial_plane_config, + .fixup_initial_plane_config = i9xx_fixup_initial_plane_config, }; static const struct intel_display_funcs i9xx_display_funcs = { @@ -7843,6 +7885,7 @@ static const struct intel_display_funcs i9xx_display_funcs = { .crtc_disable = i9xx_crtc_disable, .commit_modeset_enables = intel_commit_modeset_enables, .get_initial_plane_config = i9xx_get_initial_plane_config, + .fixup_initial_plane_config = i9xx_fixup_initial_plane_config, }; /** diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 47297ed85822371b2329ad0740dfe7caaffc884f..fdeaac994e17bbf18fa1e303c12c5f68fdf5e72e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -28,6 +28,8 @@ #include "intel_opregion.h" #include "intel_wm_types.h" +struct task_struct; + struct drm_i915_private; struct drm_property; struct drm_property_blob; @@ -47,6 +49,7 @@ struct intel_fbdev; struct intel_fdi_funcs; struct intel_hotplug_funcs; struct intel_initial_plane_config; +struct intel_opregion; struct intel_overlay; /* Amount of SAGV/QGV points, BSpec precisely defines this */ @@ -64,6 +67,8 @@ struct intel_display_funcs { struct intel_crtc_state *); void (*get_initial_plane_config)(struct intel_crtc *, struct intel_initial_plane_config *); + bool (*fixup_initial_plane_config)(struct intel_crtc *crtc, + const struct intel_initial_plane_config *plane_config); void (*crtc_enable)(struct intel_atomic_state *state, struct intel_crtc *crtc); void (*crtc_disable)(struct intel_atomic_state *state, @@ -172,6 +177,12 @@ struct intel_hotplug { struct work_struct poll_init_work; bool poll_enabled; + /* + * Queuing of hotplug_work, reenable_work and poll_init_work is + * enabled. Protected by drm_i915_private::irq_lock. + */ + bool detection_work_enabled; + unsigned int hpd_storm_threshold; /* Whether or not to count short HPD IRQs in HPD storms */ u8 hpd_short_storm_enabled; @@ -298,6 +309,11 @@ struct intel_display { const struct intel_audio_funcs *audio; } funcs; + struct { + bool any_task_allowed; + struct task_struct *allowed_task; + } access; + struct { /* backlight registers and fields in struct intel_panel */ struct mutex lock; @@ -513,7 +529,7 @@ struct intel_display { struct intel_fbc *fbc[I915_MAX_FBCS]; struct intel_frontbuffer_tracking fb_tracking; struct intel_hotplug hotplug; - struct intel_opregion opregion; + struct intel_opregion *opregion; struct intel_overlay *overlay; struct intel_display_params params; struct intel_vbt_data vbt; diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index d951edb3668714480b56eae2314c2a91b00e7301..6f2d13c8ccf776e265fa39ae23b7a4138a069c89 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -86,28 +86,6 @@ static int i915_sr_status(struct seq_file *m, void *unused) return 0; } -static int i915_opregion(struct seq_file *m, void *unused) -{ - struct drm_i915_private *i915 = node_to_i915(m->private); - struct intel_opregion *opregion = &i915->display.opregion; - - if (opregion->header) - seq_write(m, opregion->header, OPREGION_SIZE); - - return 0; -} - -static int i915_vbt(struct seq_file *m, void *unused) -{ - struct drm_i915_private *i915 = node_to_i915(m->private); - struct intel_opregion *opregion = &i915->display.opregion; - - if (opregion->vbt) - seq_write(m, opregion->vbt, opregion->vbt_size); - - return 0; -} - static int i915_gem_framebuffer_info(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = node_to_i915(m->private); @@ -1066,8 +1044,6 @@ static const struct file_operations i915_fifo_underrun_reset_ops = { static const struct drm_info_list intel_display_debugfs_list[] = { {"i915_frontbuffer_tracking", i915_frontbuffer_tracking, 0}, {"i915_sr_status", i915_sr_status, 0}, - {"i915_opregion", i915_opregion, 0}, - {"i915_vbt", i915_vbt, 0}, {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, {"i915_display_info", i915_display_info, 0}, @@ -1105,10 +1081,12 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) ARRAY_SIZE(intel_display_debugfs_list), minor->debugfs_root, minor); + intel_bios_debugfs_register(i915); intel_cdclk_debugfs_register(i915); intel_dmc_debugfs_register(i915); intel_fbc_debugfs_register(i915); intel_hpd_debugfs_register(i915); + intel_opregion_debugfs_register(i915); intel_psr_debugfs_register(i915); intel_wm_debugfs_register(i915); intel_display_debugfs_params(i915); diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c index b7e68eb62452258ff7fbd1b3543a0f46b4fefe42..f3571874855551e7bafce48fd5e5a50b6fd6da56 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c @@ -3,6 +3,7 @@ * Copyright © 2023 Intel Corporation */ +#include #include #include diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 0b522c6a8d6f5fa1c6a8ba1a58fcb5bd33e3ef3f..c02d79b50006ca74fd75b53be75db137bca662f4 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1012,7 +1012,7 @@ static void __intel_display_device_info_runtime_init(struct drm_i915_private *i9 goto display_fused_off; } - if (IS_GRAPHICS_VER(i915, 7, 8) && HAS_PCH_SPLIT(i915)) { + if (IS_DISPLAY_VER(i915, 7, 8) && HAS_PCH_SPLIT(i915)) { u32 fuse_strap = intel_de_read(i915, FUSE_STRAP); u32 sfuse_strap = intel_de_read(i915, SFUSE_STRAP); diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 9df9097a0255afda44013c13e2357357769005be..4f7ba7eb03d273ed4c36a067393b30de0c77f173 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -45,6 +45,7 @@ #include "intel_hdcp.h" #include "intel_hotplug.h" #include "intel_hti.h" +#include "intel_modeset_lock.h" #include "intel_modeset_setup.h" #include "intel_opregion.h" #include "intel_overlay.h" @@ -276,12 +277,144 @@ cleanup_bios: return ret; } +static void set_display_access(struct drm_i915_private *i915, + bool any_task_allowed, + struct task_struct *allowed_task) +{ + struct drm_modeset_acquire_ctx ctx; + int err; + + intel_modeset_lock_ctx_retry(&ctx, NULL, 0, err) { + err = drm_modeset_lock_all_ctx(&i915->drm, &ctx); + if (err) + continue; + + i915->display.access.any_task_allowed = any_task_allowed; + i915->display.access.allowed_task = allowed_task; + } + + drm_WARN_ON(&i915->drm, err); +} + +/** + * intel_display_driver_enable_user_access - Enable display HW access for all threads + * @i915: i915 device instance + * + * Enable the display HW access for all threads. Examples for such accesses + * are modeset commits and connector probing. + * + * This function should be called during driver loading and system resume once + * all the HW initialization steps are done. + */ +void intel_display_driver_enable_user_access(struct drm_i915_private *i915) +{ + set_display_access(i915, true, NULL); + + intel_hpd_enable_detection_work(i915); +} + +/** + * intel_display_driver_disable_user_access - Disable display HW access for user threads + * @i915: i915 device instance + * + * Disable the display HW access for user threads. Examples for such accesses + * are modeset commits and connector probing. For the current thread the + * access is still enabled, which should only perform HW init/deinit + * programming (as the initial modeset during driver loading or the disabling + * modeset during driver unloading and system suspend/shutdown). This function + * should be followed by calling either intel_display_driver_enable_user_access() + * after completing the HW init programming or + * intel_display_driver_suspend_access() after completing the HW deinit + * programming. + * + * This function should be called during driver loading/unloading and system + * suspend/shutdown before starting the HW init/deinit programming. + */ +void intel_display_driver_disable_user_access(struct drm_i915_private *i915) +{ + intel_hpd_disable_detection_work(i915); + + set_display_access(i915, false, current); +} + +/** + * intel_display_driver_suspend_access - Suspend display HW access for all threads + * @i915: i915 device instance + * + * Disable the display HW access for all threads. Examples for such accesses + * are modeset commits and connector probing. This call should be either + * followed by calling intel_display_driver_resume_access(), or the driver + * should be unloaded/shutdown. + * + * This function should be called during driver unloading and system + * suspend/shutdown after completing the HW deinit programming. + */ +void intel_display_driver_suspend_access(struct drm_i915_private *i915) +{ + set_display_access(i915, false, NULL); +} + +/** + * intel_display_driver_resume_access - Resume display HW access for the resume thread + * @i915: i915 device instance + * + * Enable the display HW access for the current resume thread, keeping the + * access disabled for all other (user) threads. Examples for such accesses + * are modeset commits and connector probing. The resume thread should only + * perform HW init programming (as the restoring modeset). This function + * should be followed by calling intel_display_driver_enable_user_access(), + * after completing the HW init programming steps. + * + * This function should be called during system resume before starting the HW + * init steps. + */ +void intel_display_driver_resume_access(struct drm_i915_private *i915) +{ + set_display_access(i915, false, current); +} + +/** + * intel_display_driver_check_access - Check if the current thread has disaplay HW access + * @i915: i915 device instance + * + * Check whether the current thread has display HW access, print a debug + * message if it doesn't. Such accesses are modeset commits and connector + * probing. If the function returns %false any HW access should be prevented. + * + * Returns %true if the current thread has display HW access, %false + * otherwise. + */ +bool intel_display_driver_check_access(struct drm_i915_private *i915) +{ + char comm[TASK_COMM_LEN]; + char current_task[TASK_COMM_LEN + 16]; + char allowed_task[TASK_COMM_LEN + 16] = "none"; + + if (i915->display.access.any_task_allowed || + i915->display.access.allowed_task == current) + return true; + + snprintf(current_task, sizeof(current_task), "%s[%d]", + get_task_comm(comm, current), + task_pid_vnr(current)); + + if (i915->display.access.allowed_task) + snprintf(allowed_task, sizeof(allowed_task), "%s[%d]", + get_task_comm(comm, i915->display.access.allowed_task), + task_pid_vnr(i915->display.access.allowed_task)); + + drm_dbg_kms(&i915->drm, + "Reject display access from task %s (allowed to %s)\n", + current_task, allowed_task); + + return false; +} + /* part #2: call after irq install, but before gem init */ int intel_display_driver_probe_nogem(struct drm_i915_private *i915) { struct drm_device *dev = &i915->drm; enum pipe pipe; - struct intel_crtc *crtc; int ret; if (!HAS_DISPLAY(i915)) @@ -315,8 +448,6 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915) intel_display_driver_init_hw(i915); intel_dpll_update_ref_clks(i915); - intel_hdcp_component_init(i915); - if (i915->display.cdclk.max_cdclk_freq == 0) intel_update_max_cdclk(i915); @@ -326,16 +457,14 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915) intel_vga_disable(i915); intel_setup_outputs(i915); + intel_display_driver_disable_user_access(i915); + drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(i915, dev->mode_config.acquire_ctx); intel_acpi_assign_connector_fwnodes(i915); drm_modeset_unlock_all(dev); - for_each_intel_crtc(dev, crtc) { - if (!to_intel_crtc_state(crtc->base.state)->uapi.active) - continue; - intel_crtc_initial_plane_config(crtc); - } + intel_initial_plane_config(i915); /* * Make sure hardware watermarks really match the state we read out. @@ -356,6 +485,13 @@ int intel_display_driver_probe(struct drm_i915_private *i915) if (!HAS_DISPLAY(i915)) return 0; + /* + * This will bind stuff into ggtt, so it needs to be done after + * the BIOS fb takeover and whatever else magic ggtt reservations + * happen during gem/ggtt init. + */ + intel_hdcp_component_init(i915); + /* * Force all active planes to recompute their states. So that on * mode_setcrtc after probe, all the intel_plane_state variables @@ -374,7 +510,6 @@ int intel_display_driver_probe(struct drm_i915_private *i915) /* Only enable hotplug handling once the fbdev is fully set up. */ intel_hpd_init(i915); - intel_hpd_poll_disable(i915); skl_watermark_ipc_init(i915); @@ -383,7 +518,8 @@ int intel_display_driver_probe(struct drm_i915_private *i915) void intel_display_driver_register(struct drm_i915_private *i915) { - struct drm_printer p = drm_debug_printer("i915 display info:"); + struct drm_printer p = drm_dbg_printer(&i915->drm, DRM_UT_KMS, + "i915 display info:"); if (!HAS_DISPLAY(i915)) return; @@ -394,6 +530,8 @@ void intel_display_driver_register(struct drm_i915_private *i915) intel_audio_init(i915); + intel_display_driver_enable_user_access(i915); + intel_display_debugfs_register(i915); /* @@ -412,6 +550,7 @@ void intel_display_driver_register(struct drm_i915_private *i915) * fbdev->async_cookie. */ drm_kms_helper_poll_init(&i915->drm); + intel_hpd_poll_disable(i915); intel_display_device_info_print(DISPLAY_INFO(i915), DISPLAY_RUNTIME_INFO(i915), &p); @@ -440,6 +579,8 @@ void intel_display_driver_remove_noirq(struct drm_i915_private *i915) if (!HAS_DISPLAY(i915)) return; + intel_display_driver_suspend_access(i915); + /* * Due to the hpd irq storm handling the hotplug work can re-arm the * poll handlers. Hence disable polling after hpd handling is shut down. @@ -486,14 +627,17 @@ void intel_display_driver_unregister(struct drm_i915_private *i915) return; intel_fbdev_unregister(i915); - intel_audio_deinit(i915); - /* * After flushing the fbdev (incl. a late async config which * will have delayed queuing of a hotplug event), then flush * the hotplug events. */ drm_kms_helper_poll_fini(&i915->drm); + + intel_display_driver_disable_user_access(i915); + + intel_audio_deinit(i915); + drm_atomic_helper_shutdown(&i915->drm); acpi_video_unregister(); diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.h b/drivers/gpu/drm/i915/display/intel_display_driver.h index c276a58ee3293f8f0e1761154a28d0ce46e046ba..42cc4af6d3fd5bc60628ecbeb0741c20accdbdbf 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.h +++ b/drivers/gpu/drm/i915/display/intel_display_driver.h @@ -32,5 +32,11 @@ int __intel_display_driver_resume(struct drm_i915_private *i915, struct drm_atomic_state *state, struct drm_modeset_acquire_ctx *ctx); +void intel_display_driver_enable_user_access(struct drm_i915_private *i915); +void intel_display_driver_disable_user_access(struct drm_i915_private *i915); +void intel_display_driver_suspend_access(struct drm_i915_private *i915); +void intel_display_driver_resume_access(struct drm_i915_private *i915); +bool intel_display_driver_check_access(struct drm_i915_private *i915); + #endif /* __INTEL_DISPLAY_DRIVER_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index a7d8f3fc98de91ec31436a4a2b2a78606e6d2466..f846c5b108b50518c38e6bac506528222b45e5e1 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -266,12 +266,12 @@ void i915_disable_pipestat(struct drm_i915_private *dev_priv, intel_uncore_posting_read(&dev_priv->uncore, reg); } -static bool i915_has_asle(struct drm_i915_private *dev_priv) +static bool i915_has_asle(struct drm_i915_private *i915) { - if (!dev_priv->display.opregion.asle) + if (!IS_PINEVIEW(i915) && !IS_MOBILE(i915)) return false; - return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv); + return intel_opregion_asle_present(i915); } /** @@ -986,7 +986,7 @@ static void gen8_read_and_ack_pch_irqs(struct drm_i915_private *i915, u32 *pch_i * their flags both in the PICA and SDE IIR. */ if (*pch_iir & SDE_PICAINTERRUPT) { - drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTP); + drm_WARN_ON(&i915->drm, INTEL_PCH_TYPE(i915) < PCH_MTL); pica_ier = intel_de_rmw(i915, PICAINTERRUPT_IER, ~0, 0); *pica_iir = intel_de_read(i915, PICAINTERRUPT_IIR); @@ -1587,7 +1587,7 @@ void ilk_de_irq_postinstall(struct drm_i915_private *i915) struct intel_uncore *uncore = &i915->uncore; u32 display_mask, extra_mask; - if (GRAPHICS_VER(i915) >= 7) { + if (DISPLAY_VER(i915) >= 7) { display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | DE_AUX_CHANNEL_A_IVB); extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB | diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 3fdd8a5179831288f1e10bc8d9161d8d23a7ba6a..01eb6e4e604914db8c780dccae513dda94f8e778 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -780,6 +780,8 @@ struct intel_plane_state { struct intel_initial_plane_config { struct intel_framebuffer *fb; + struct intel_memory_region *mem; + resource_size_t phys_base; struct i915_vma *vma; unsigned int tiling; int size; @@ -1213,12 +1215,12 @@ struct intel_crtc_state { bool has_psr; bool has_psr2; bool enable_psr2_sel_fetch; + bool enable_psr2_su_region_et; bool req_psr2_sdp_prior_scanline; bool has_panel_replay; bool wm_level_disabled; u32 dc3co_exitline; u16 su_y_granularity; - struct drm_dp_vsc_sdp psr_vsc; /* * Frequence the dpll for the port should run at. Differs from the @@ -1402,6 +1404,8 @@ struct intel_crtc_state { u32 psr2_man_track_ctl; + struct drm_rect psr2_su_area; + /* Variable Refresh Rate state */ struct { bool enable, in_range; @@ -1682,13 +1686,14 @@ struct intel_psr { /* Mutex for PSR state of the transcoder */ struct mutex lock; -#define I915_PSR_DEBUG_MODE_MASK 0x0f -#define I915_PSR_DEBUG_DEFAULT 0x00 -#define I915_PSR_DEBUG_DISABLE 0x01 -#define I915_PSR_DEBUG_ENABLE 0x02 -#define I915_PSR_DEBUG_FORCE_PSR1 0x03 -#define I915_PSR_DEBUG_ENABLE_SEL_FETCH 0x4 -#define I915_PSR_DEBUG_IRQ 0x10 +#define I915_PSR_DEBUG_MODE_MASK 0x0f +#define I915_PSR_DEBUG_DEFAULT 0x00 +#define I915_PSR_DEBUG_DISABLE 0x01 +#define I915_PSR_DEBUG_ENABLE 0x02 +#define I915_PSR_DEBUG_FORCE_PSR1 0x03 +#define I915_PSR_DEBUG_ENABLE_SEL_FETCH 0x4 +#define I915_PSR_DEBUG_IRQ 0x10 +#define I915_PSR_DEBUG_SU_REGION_ET_DISABLE 0x20 u32 debug; bool sink_support; @@ -1702,14 +1707,20 @@ struct intel_psr { unsigned int busy_frontbuffer_bits; bool sink_psr2_support; bool link_standby; - bool colorimetry_support; bool psr2_enabled; bool psr2_sel_fetch_enabled; bool psr2_sel_fetch_cff_enabled; bool req_psr2_sdp_prior_scanline; u8 sink_sync_latency; - u8 io_wake_lines; - u8 fast_wake_lines; + + struct { + u8 io_wake_lines; + u8 fast_wake_lines; + + /* LNL and beyond */ + u8 check_entry_lines; + } alpm_parameters; + ktime_t last_entry_attempt; ktime_t last_exit; bool sink_not_reliable; @@ -1833,6 +1844,8 @@ struct intel_dp { /* When we last wrote the OUI for eDP */ unsigned long last_oui_write; + + bool colorimetry_support; }; enum lspcon_vendor { @@ -1890,6 +1903,9 @@ struct intel_digital_port { u32 (*infoframes_enabled)(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config); bool (*connected)(struct intel_encoder *encoder); + + void (*lock)(struct intel_digital_port *dig_port); + void (*unlock)(struct intel_digital_port *dig_port); }; struct intel_dp_mst_encoder { diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index b70502586ab985426928bbbdb863194f6e4a93fa..835781624482918bd5a044b2666f01287f6356e7 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -1158,7 +1158,7 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) str_yes_no(intel_dmc_has_payload(i915))); seq_printf(m, "path: %s\n", dmc ? dmc->fw_path : "N/A"); seq_printf(m, "Pipe A fw needed: %s\n", - str_yes_no(GRAPHICS_VER(i915) >= 12)); + str_yes_no(DISPLAY_VER(i915) >= 12)); seq_printf(m, "Pipe A fw loaded: %s\n", str_yes_no(has_dmc_id_fw(i915, DMC_FW_PIPEA))); seq_printf(m, "Pipe B fw needed: %s\n", diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f5ef95da55346ff14cc6b102c27e78e8960cec65..ab415f41924d7d1a615ae19d19c11c750f94e27b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -56,6 +56,7 @@ #include "intel_cx0_phy.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_aux.h" @@ -2616,58 +2617,38 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct drm_dp_vsc_sdp *vsc = &crtc_state->infoframes.vsc; + struct drm_dp_vsc_sdp *vsc; - /* When a crtc state has PSR, VSC SDP will be handled by PSR routine */ - if (crtc_state->has_psr) + if ((!intel_dp->colorimetry_support || + !intel_dp_needs_vsc_sdp(crtc_state, conn_state)) && + !crtc_state->has_psr) return; - if (!intel_dp_needs_vsc_sdp(crtc_state, conn_state)) - return; + vsc = &crtc_state->infoframes.vsc; crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); vsc->sdp_type = DP_SDP_VSC; - intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, - &crtc_state->infoframes.vsc); -} -void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, - struct drm_dp_vsc_sdp *vsc) -{ - vsc->sdp_type = DP_SDP_VSC; - - if (crtc_state->has_psr2) { - if (intel_dp->psr.colorimetry_support && - intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { - /* [PSR2, +Colorimetry] */ - intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, - vsc); - } else { - /* - * [PSR2, -Colorimetry] - * Prepare VSC Header for SU as per eDP 1.4 spec, Table 6-11 - * 3D stereo + PSR/PSR2 + Y-coordinate. - */ - vsc->revision = 0x4; - vsc->length = 0xe; - } + /* Needs colorimetry */ + if (intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { + intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, + vsc); + } else if (crtc_state->has_psr2) { + /* + * [PSR2 without colorimetry] + * Prepare VSC Header for SU as per eDP 1.4 spec, Table 6-11 + * 3D stereo + PSR/PSR2 + Y-coordinate. + */ + vsc->revision = 0x4; + vsc->length = 0xe; } else if (crtc_state->has_panel_replay) { - if (intel_dp->psr.colorimetry_support && - intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { - /* [Panel Replay with colorimetry info] */ - intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, - vsc); - } else { - /* - * [Panel Replay without colorimetry info] - * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223 - * VSC SDP supporting 3D stereo + Panel Replay. - */ - vsc->revision = 0x6; - vsc->length = 0x10; - } + /* + * [Panel Replay without colorimetry info] + * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223 + * VSC SDP supporting 3D stereo + Panel Replay. + */ + vsc->revision = 0x6; + vsc->length = 0x10; } else { /* * [PSR1] @@ -3345,13 +3326,6 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, fastset = false; } - if (CAN_PSR(intel_dp)) { - drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset to compute PSR state\n", - encoder->base.base.id, encoder->base.name); - crtc_state->uapi.mode_changed = true; - fastset = false; - } - return fastset; } @@ -4288,24 +4262,6 @@ static void intel_write_dp_sdp(struct intel_encoder *encoder, dig_port->write_infoframe(encoder, crtc_state, type, &sdp, len); } -void intel_write_dp_vsc_sdp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - const struct drm_dp_vsc_sdp *vsc) -{ - struct intel_digital_port *dig_port = enc_to_dig_port(encoder); - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct dp_sdp sdp = {}; - ssize_t len; - - len = intel_dp_vsc_sdp_pack(vsc, &sdp, sizeof(sdp)); - - if (drm_WARN_ON(&dev_priv->drm, len < 0)) - return; - - dig_port->write_infoframe(encoder, crtc_state, DP_SDP_VSC, - &sdp, len); -} - void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable, const struct intel_crtc_state *crtc_state, @@ -4332,9 +4288,7 @@ void intel_dp_set_infoframes(struct intel_encoder *encoder, if (!enable) return; - /* When PSR is enabled, VSC SDP is handled by PSR routine */ - if (!crtc_state->has_psr) - intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC); + intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC); intel_write_dp_sdp(encoder, crtc_state, HDMI_PACKET_TYPE_GAMUT_METADATA); } @@ -4465,10 +4419,6 @@ static void intel_read_dp_vsc_sdp(struct intel_encoder *encoder, struct dp_sdp sdp = {}; int ret; - /* When PSR is enabled, VSC SDP is handled by PSR routine */ - if (crtc_state->has_psr) - return; - if ((crtc_state->infoframes.enable & intel_hdmi_infoframe_enable(type)) == 0) return; @@ -4679,31 +4629,36 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, struct drm_dp_phy_test_params *data = &intel_dp->compliance.test_data.phytest; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; enum pipe pipe = crtc->pipe; u32 pattern_val; switch (data->phy_pattern) { - case DP_PHY_TEST_PATTERN_NONE: + case DP_LINK_QUAL_PATTERN_DISABLE: drm_dbg_kms(&dev_priv->drm, "Disable Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0); + if (DISPLAY_VER(dev_priv) >= 10) + intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), + DP_TP_CTL_TRAIN_PAT4_SEL_MASK | DP_TP_CTL_LINK_TRAIN_MASK, + DP_TP_CTL_LINK_TRAIN_NORMAL); break; - case DP_PHY_TEST_PATTERN_D10_2: + case DP_LINK_QUAL_PATTERN_D10_2: drm_dbg_kms(&dev_priv->drm, "Set D10.2 Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_D10_2); break; - case DP_PHY_TEST_PATTERN_ERROR_COUNT: + case DP_LINK_QUAL_PATTERN_ERROR_RATE: drm_dbg_kms(&dev_priv->drm, "Set Error Count Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_SCRAMBLED_0); break; - case DP_PHY_TEST_PATTERN_PRBS7: + case DP_LINK_QUAL_PATTERN_PRBS7: drm_dbg_kms(&dev_priv->drm, "Set PRBS7 Phy Test Pattern\n"); intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_PRBS7); break; - case DP_PHY_TEST_PATTERN_80BIT_CUSTOM: + case DP_LINK_QUAL_PATTERN_80BIT_CUSTOM: /* * FIXME: Ideally pattern should come from DPCD 0x250. As * current firmware of DPR-100 could not set it, so hardcoding @@ -4721,7 +4676,7 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_CUSTOM80); break; - case DP_PHY_TEST_PATTERN_CP2520: + case DP_LINK_QUAL_PATTERN_CP2520_PAT_1: /* * FIXME: Ideally pattern should come from DPCD 0x24A. As * current firmware of DPR-100 could not set it, so hardcoding @@ -4733,8 +4688,19 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_HBR2 | pattern_val); break; + case DP_LINK_QUAL_PATTERN_CP2520_PAT_3: + if (DISPLAY_VER(dev_priv) < 10) { + drm_warn(&dev_priv->drm, "Platform does not support TPS4\n"); + break; + } + drm_dbg_kms(&dev_priv->drm, "Set TPS4 compliance Phy Test Pattern\n"); + intel_de_write(dev_priv, DDI_DP_COMP_CTL(pipe), 0x0); + intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), + DP_TP_CTL_TRAIN_PAT4_SEL_MASK | DP_TP_CTL_LINK_TRAIN_MASK, + DP_TP_CTL_TRAIN_PAT4_SEL_TP4A | DP_TP_CTL_LINK_TRAIN_PAT4); + break; default: - WARN(1, "Invalid Phy Test Pattern\n"); + drm_warn(&dev_priv->drm, "Invalid Phy Test Pattern\n"); } } @@ -5453,8 +5419,24 @@ edp_detect(struct intel_dp *intel_dp) return connector_status_connected; } +void intel_digital_port_lock(struct intel_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (dig_port->lock) + dig_port->lock(dig_port); +} + +void intel_digital_port_unlock(struct intel_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (dig_port->unlock) + dig_port->unlock(dig_port); +} + /* - * intel_digital_port_connected - is the specified port connected? + * intel_digital_port_connected_locked - is the specified port connected? * @encoder: intel_encoder * * In cases where there's a connector physically connected but it can't be used @@ -5462,21 +5444,44 @@ edp_detect(struct intel_dp *intel_dp) * pretty much treat the port as disconnected. This is relevant for type-C * (starting on ICL) where there's ownership involved. * + * The caller must hold the lock acquired by calling intel_digital_port_lock() + * when calling this function. + * * Return %true if port is connected, %false otherwise. */ -bool intel_digital_port_connected(struct intel_encoder *encoder) +bool intel_digital_port_connected_locked(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + bool is_glitch_free = intel_tc_port_handles_hpd_glitches(dig_port); bool is_connected = false; intel_wakeref_t wakeref; - with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) - is_connected = dig_port->connected(encoder); + with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) { + unsigned long wait_expires = jiffies + msecs_to_jiffies_timeout(4); + + do { + is_connected = dig_port->connected(encoder); + if (is_connected || is_glitch_free) + break; + usleep_range(10, 30); + } while (time_before(jiffies, wait_expires)); + } return is_connected; } +bool intel_digital_port_connected(struct intel_encoder *encoder) +{ + bool ret; + + intel_digital_port_lock(encoder); + ret = intel_digital_port_connected_locked(encoder); + intel_digital_port_unlock(encoder); + + return ret; +} + static const struct drm_edid * intel_dp_get_edid(struct intel_dp *intel_dp) { @@ -5670,6 +5675,9 @@ intel_dp_detect(struct drm_connector *connector, if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; + if (!intel_display_driver_check_access(dev_priv)) + return connector->status; + /* Can't disconnect eDP */ if (intel_dp_is_edp(intel_dp)) status = edp_detect(intel_dp); @@ -5770,6 +5778,10 @@ intel_dp_force(struct drm_connector *connector) drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); + + if (!intel_display_driver_check_access(dev_priv)) + return; + intel_dp_unset_edid(intel_dp); if (connector->status != connector_status_connected) @@ -6054,7 +6066,7 @@ static void intel_dp_oob_hotplug_event(struct drm_connector *connector, spin_unlock_irq(&i915->irq_lock); if (need_work) - queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0); + intel_hpd_schedule_detection(i915); } static const struct drm_connector_funcs intel_dp_connector_funcs = { @@ -6497,6 +6509,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, connector->interlace_allowed = true; intel_connector->polled = DRM_CONNECTOR_POLL_HPD; + intel_connector->base.polled = intel_connector->polled; intel_connector_attach_encoder(intel_connector, intel_encoder); @@ -6527,6 +6540,9 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, "HDCP init failed, skipping.\n"); } + intel_dp->colorimetry_support = + intel_dp_get_colorimetry_status(intel_dp); + intel_dp->frl.is_trained = false; intel_dp->frl.trained_rate_gbps = 0; diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 05db46b111f216e150760e0dff76581cc18bbcca..530cc97bc42f43cc9707f410248ecb19c7bbf9b9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -109,20 +109,16 @@ int intel_dp_max_data_rate(int max_link_rate, int max_lanes); bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp); bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); -void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state, - struct drm_dp_vsc_sdp *vsc); -void intel_write_dp_vsc_sdp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - const struct drm_dp_vsc_sdp *vsc); void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); void intel_read_dp_sdp(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, unsigned int type); +void intel_digital_port_lock(struct intel_encoder *encoder); +void intel_digital_port_unlock(struct intel_encoder *encoder); bool intel_digital_port_connected(struct intel_encoder *encoder); +bool intel_digital_port_connected_locked(struct intel_encoder *encoder); int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector, u8 dsc_max_bpc); u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915, diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 2e2af71bcd5a824c48710c0e5c4cd772d3055cb1..4f4a0e3b31140d97822493c4533ccfbf5500534f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -9,6 +9,7 @@ #include "intel_bios.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dp.h" #include "intel_dp_aux.h" #include "intel_dp_aux_regs.h" #include "intel_pps.h" @@ -228,9 +229,8 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, u32 aux_send_ctl_flags) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *encoder = &dig_port->base; struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - enum phy phy = intel_port_to_phy(i915, dig_port->base.port); - bool is_tc_port = intel_phy_is_tc(i915, phy); i915_reg_t ch_ctl, ch_data[5]; u32 aux_clock_divider; enum intel_display_power_domain aux_domain; @@ -245,18 +245,16 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, for (i = 0; i < ARRAY_SIZE(ch_data); i++) ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i); - if (is_tc_port) { - intel_tc_port_lock(dig_port); - /* - * Abort transfers on a disconnected port as required by - * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX - * timeouts that would otherwise happen. - * TODO: abort the transfer on non-TC ports as well. - */ - if (!intel_tc_port_connected_locked(&dig_port->base)) { - ret = -ENXIO; - goto out_unlock; - } + intel_digital_port_lock(encoder); + /* + * Abort transfers on a disconnected port as required by + * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX + * timeouts that would otherwise happen. + */ + if (!intel_dp_is_edp(intel_dp) && + !intel_digital_port_connected_locked(&dig_port->base)) { + ret = -ENXIO; + goto out_unlock; } aux_domain = intel_aux_power_domain(dig_port); @@ -423,8 +421,7 @@ out: intel_pps_unlock(intel_dp, pps_wakeref); intel_display_power_put_async(i915, aux_domain, aux_wakeref); out_unlock: - if (is_tc_port) - intel_tc_port_unlock(dig_port); + intel_digital_port_unlock(encoder); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 8a9432335030346ecf3b7501a4cfb19cd59d5259..5fa25a5a36b5532282f9e42037c089a2dd4ebeb6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -37,6 +37,7 @@ #include "intel_crtc.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_hdcp.h" @@ -1410,6 +1411,9 @@ intel_dp_mst_detect(struct drm_connector *connector, if (drm_connector_is_unregistered(connector)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->status; + return drm_dp_mst_detect_port(connector, ctx, &intel_dp->mst_mgr, intel_connector->port); } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index ef57dad1a9cb7912cf98c4d344b35d29757c8f06..e7e0a4cf9f93ee830606704ea3441d99594fec19 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -1263,11 +1263,11 @@ static const struct dpll_info hsw_plls[] = { { .name = "WRPLL 2", .funcs = &hsw_ddi_wrpll_funcs, .id = DPLL_ID_WRPLL2, }, { .name = "SPLL", .funcs = &hsw_ddi_spll_funcs, .id = DPLL_ID_SPLL, }, { .name = "LCPLL 810", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_810, - .flags = INTEL_DPLL_ALWAYS_ON, }, + .always_on = true, }, { .name = "LCPLL 1350", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_1350, - .flags = INTEL_DPLL_ALWAYS_ON, }, + .always_on = true, }, { .name = "LCPLL 2700", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_2700, - .flags = INTEL_DPLL_ALWAYS_ON, }, + .always_on = true, }, {} }; @@ -1945,7 +1945,7 @@ static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = { static const struct dpll_info skl_plls[] = { { .name = "DPLL 0", .funcs = &skl_ddi_dpll0_funcs, .id = DPLL_ID_SKL_DPLL0, - .flags = INTEL_DPLL_ALWAYS_ON, }, + .always_on = true, }, { .name = "DPLL 1", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL1, }, { .name = "DPLL 2", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL2, }, { .name = "DPLL 3", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL3, }, @@ -3308,6 +3308,8 @@ static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state, struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_DEFAULT]; struct skl_wrpll_params pll_params = {}; @@ -3326,7 +3328,11 @@ static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state, return ret; /* this is mainly for the fastset check */ - icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_MG_PHY); + if (old_crtc_state->shared_dpll && + old_crtc_state->shared_dpll->info->id == DPLL_ID_ICL_TBTPLL) + icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT); + else + icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_MG_PHY); crtc_state->port_clock = icl_ddi_mg_pll_get_freq(i915, NULL, &port_dpll->hw_state); @@ -4023,7 +4029,8 @@ static const struct intel_shared_dpll_funcs mg_pll_funcs = { static const struct dpll_info icl_plls[] = { { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, - { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, + .is_alt_port_dpll = true, }, { .name = "MG PLL 1", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, { .name = "MG PLL 2", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, { .name = "MG PLL 3", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, @@ -4068,7 +4075,8 @@ static const struct intel_shared_dpll_funcs dkl_pll_funcs = { static const struct dpll_info tgl_plls[] = { { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, - { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, + .is_alt_port_dpll = true, }, { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, { .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, @@ -4141,7 +4149,8 @@ static const struct intel_dpll_mgr adls_pll_mgr = { static const struct dpll_info adlp_plls[] = { { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, - { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, + .is_alt_port_dpll = true, }, { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, { .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, @@ -4465,31 +4474,29 @@ verify_single_dpll_state(struct drm_i915_private *i915, struct intel_crtc *crtc, const struct intel_crtc_state *new_crtc_state) { - struct intel_dpll_hw_state dpll_hw_state; + struct intel_dpll_hw_state dpll_hw_state = {}; u8 pipe_mask; bool active; - memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); - - drm_dbg_kms(&i915->drm, "%s\n", pll->info->name); - active = intel_dpll_get_hw_state(i915, pll, &dpll_hw_state); - if (!(pll->info->flags & INTEL_DPLL_ALWAYS_ON)) { + if (!pll->info->always_on) { I915_STATE_WARN(i915, !pll->on && pll->active_mask, - "pll in active use but not on in sw tracking\n"); + "%s: pll in active use but not on in sw tracking\n", + pll->info->name); I915_STATE_WARN(i915, pll->on && !pll->active_mask, - "pll is on but not used by any active pipe\n"); + "%s: pll is on but not used by any active pipe\n", + pll->info->name); I915_STATE_WARN(i915, pll->on != active, - "pll on state mismatch (expected %i, found %i)\n", - pll->on, active); + "%s: pll on state mismatch (expected %i, found %i)\n", + pll->info->name, pll->on, active); } if (!crtc) { I915_STATE_WARN(i915, pll->active_mask & ~pll->state.pipe_mask, - "more active pll users than references: 0x%x vs 0x%x\n", - pll->active_mask, pll->state.pipe_mask); + "%s: more active pll users than references: 0x%x vs 0x%x\n", + pll->info->name, pll->active_mask, pll->state.pipe_mask); return; } @@ -4498,21 +4505,29 @@ verify_single_dpll_state(struct drm_i915_private *i915, if (new_crtc_state->hw.active) I915_STATE_WARN(i915, !(pll->active_mask & pipe_mask), - "pll active mismatch (expected pipe %c in active mask 0x%x)\n", - pipe_name(crtc->pipe), pll->active_mask); + "%s: pll active mismatch (expected pipe %c in active mask 0x%x)\n", + pll->info->name, pipe_name(crtc->pipe), pll->active_mask); else I915_STATE_WARN(i915, pll->active_mask & pipe_mask, - "pll active mismatch (didn't expect pipe %c in active mask 0x%x)\n", - pipe_name(crtc->pipe), pll->active_mask); + "%s: pll active mismatch (didn't expect pipe %c in active mask 0x%x)\n", + pll->info->name, pipe_name(crtc->pipe), pll->active_mask); I915_STATE_WARN(i915, !(pll->state.pipe_mask & pipe_mask), - "pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n", - pipe_mask, pll->state.pipe_mask); + "%s: pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n", + pll->info->name, pipe_mask, pll->state.pipe_mask); I915_STATE_WARN(i915, pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state, sizeof(dpll_hw_state)), - "pll hw state mismatch\n"); + "%s: pll hw state mismatch\n", + pll->info->name); +} + +static bool has_alt_port_dpll(const struct intel_shared_dpll *old_pll, + const struct intel_shared_dpll *new_pll) +{ + return old_pll && new_pll && old_pll != new_pll && + (old_pll->info->is_alt_port_dpll || new_pll->info->is_alt_port_dpll); } void intel_shared_dpll_state_verify(struct intel_atomic_state *state, @@ -4534,11 +4549,15 @@ void intel_shared_dpll_state_verify(struct intel_atomic_state *state, struct intel_shared_dpll *pll = old_crtc_state->shared_dpll; I915_STATE_WARN(i915, pll->active_mask & pipe_mask, - "pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n", - pipe_name(crtc->pipe), pll->active_mask); - I915_STATE_WARN(i915, pll->state.pipe_mask & pipe_mask, - "pll enabled crtcs mismatch (found pipe %c in enabled mask (0x%x))\n", - pipe_name(crtc->pipe), pll->state.pipe_mask); + "%s: pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n", + pll->info->name, pipe_name(crtc->pipe), pll->active_mask); + + /* TC ports have both MG/TC and TBT PLL referenced simultaneously */ + I915_STATE_WARN(i915, !has_alt_port_dpll(old_crtc_state->shared_dpll, + new_crtc_state->shared_dpll) && + pll->state.pipe_mask & pipe_mask, + "%s: pll enabled crtcs mismatch (found pipe %c in enabled mask (0x%x))\n", + pll->info->name, pipe_name(crtc->pipe), pll->state.pipe_mask); } } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index 2e7ea0d8d3ffb3628f4b65ec657e3df63eada52a..616afe861b4670fbe0818e6ffb2423fd8e07e3a2 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -276,15 +276,21 @@ struct dpll_info { */ enum intel_display_power_domain power_domain; -#define INTEL_DPLL_ALWAYS_ON (1 << 0) /** - * @flags: + * @always_on: * - * INTEL_DPLL_ALWAYS_ON - * Inform the state checker that the DPLL is kept enabled even if - * not in use by any CRTC. + * Inform the state checker that the DPLL is kept enabled even if + * not in use by any CRTC. */ - u32 flags; + bool always_on; + + /** + * @is_alt_port_dpll: + * + * Inform the state checker that the DPLL can be used as a fallback + * (for TC->TBT fallback). + */ + bool is_alt_port_dpll; }; /** diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 482c28b5c2de5428f0e2a123ccbd5dc541842c7f..a6c7122fd671df14400e891366806d9bd8c317d3 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -453,6 +453,10 @@ struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, if (!HAS_DSB(i915)) return NULL; + /* TODO: DSB is broken in Xe KMD, so disabling it until fixed */ + if (!IS_ENABLED(I915)) + return NULL; + dsb = kzalloc(sizeof(*dsb), GFP_KERNEL); if (!dsb) goto out; diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 9111e9d46486d8920077eb2cbd3b01c09f911a16..8ca9ae4798a8940f8f79473b3030bcb345e716e9 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -35,6 +35,7 @@ #include "i915_reg.h" #include "intel_connector.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dvo.h" #include "intel_dvo_dev.h" @@ -328,6 +329,9 @@ intel_dvo_detect(struct drm_connector *_connector, bool force) if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->base.status; + return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); } @@ -536,6 +540,7 @@ void intel_dvo_init(struct drm_i915_private *i915) if (intel_dvo->dev.type == INTEL_DVO_CHIP_TMDS) connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + connector->base.polled = connector->polled; drm_connector_init_with_ddc(&i915->drm, &connector->base, &intel_dvo_connector_funcs, diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index f17a1afb4929ec35d6e446a1b04f74fffe54b4a5..b453fcbd67dadd16714f294c93b7053fc39a870b 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1087,18 +1087,7 @@ static bool i8xx_fbc_tiling_valid(const struct intel_plane_state *plane_state) static bool skl_fbc_tiling_valid(const struct intel_plane_state *plane_state) { - const struct drm_framebuffer *fb = plane_state->hw.fb; - - switch (fb->modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Yf_TILED: - case I915_FORMAT_MOD_4_TILED: - case I915_FORMAT_MOD_X_TILED: - return true; - default: - return false; - } + return true; } static bool tiling_is_valid(const struct intel_plane_state *plane_state) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c index 717c3a3237c4818fb49ee355b564e9562d10fbcc..0665f943f65f28fab51c3764862be40273ef3e2f 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -78,8 +78,9 @@ int intel_fbdev_fb_fill_info(struct drm_i915_private *i915, struct fb_info *info /* Use fbdev's framebuffer from lmem for discrete */ info->fix.smem_start = - (unsigned long)(mem->io_start + - i915_gem_object_get_dma_address(obj, 0)); + (unsigned long)(mem->io.start + + i915_gem_object_get_dma_address(obj, 0) - + mem->region.start); info->fix.smem_len = obj->base.size; } else { struct i915_ggtt *ggtt = to_gt(i915)->ggtt; diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c index e8e8be54143b431393bfedcac3b399429defd3ce..cbcd1e91b7bee2877fff15ff6562d20d1e7e8b7f 100644 --- a/drivers/gpu/drm/i915/display/intel_global_state.c +++ b/drivers/gpu/drm/i915/display/intel_global_state.c @@ -10,12 +10,55 @@ #include "intel_display_types.h" #include "intel_global_state.h" +struct intel_global_commit { + struct kref ref; + struct completion done; +}; + +static struct intel_global_commit *commit_new(void) +{ + struct intel_global_commit *commit; + + commit = kzalloc(sizeof(*commit), GFP_KERNEL); + if (!commit) + return NULL; + + init_completion(&commit->done); + kref_init(&commit->ref); + + return commit; +} + +static void __commit_free(struct kref *kref) +{ + struct intel_global_commit *commit = + container_of(kref, typeof(*commit), ref); + + kfree(commit); +} + +static struct intel_global_commit *commit_get(struct intel_global_commit *commit) +{ + if (commit) + kref_get(&commit->ref); + + return commit; +} + +static void commit_put(struct intel_global_commit *commit) +{ + if (commit) + kref_put(&commit->ref, __commit_free); +} + static void __intel_atomic_global_state_free(struct kref *kref) { struct intel_global_state *obj_state = container_of(kref, struct intel_global_state, ref); struct intel_global_obj *obj = obj_state->obj; + commit_put(obj_state->commit); + obj->funcs->atomic_destroy_state(obj, obj_state); } @@ -127,6 +170,8 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state, obj_state->obj = obj; obj_state->changed = false; + obj_state->serialized = false; + obj_state->commit = NULL; kref_init(&obj_state->ref); @@ -239,19 +284,13 @@ int intel_atomic_lock_global_state(struct intel_global_state *obj_state) int intel_atomic_serialize_global_state(struct intel_global_state *obj_state) { - struct intel_atomic_state *state = obj_state->state; - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - struct intel_crtc *crtc; + int ret; - for_each_intel_crtc(&dev_priv->drm, crtc) { - struct intel_crtc_state *crtc_state; + ret = intel_atomic_lock_global_state(obj_state); + if (ret) + return ret; - crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - } - - obj_state->changed = true; + obj_state->serialized = true; return 0; } @@ -267,3 +306,79 @@ intel_atomic_global_state_is_serialized(struct intel_atomic_state *state) return false; return true; } + +int +intel_atomic_global_state_setup_commit(struct intel_atomic_state *state) +{ + const struct intel_global_state *old_obj_state; + struct intel_global_state *new_obj_state; + struct intel_global_obj *obj; + int i; + + for_each_oldnew_global_obj_in_state(state, obj, old_obj_state, + new_obj_state, i) { + struct intel_global_commit *commit = NULL; + + if (new_obj_state->serialized) { + /* + * New commit which is going to be completed + * after the hardware reprogramming is done. + */ + commit = commit_new(); + if (!commit) + return -ENOMEM; + } else if (new_obj_state->changed) { + /* + * We're going to swap to this state, so carry the + * previous commit along, in case it's not yet done. + */ + commit = commit_get(old_obj_state->commit); + } + + new_obj_state->commit = commit; + } + + return 0; +} + +int +intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_global_state *old_obj_state; + struct intel_global_obj *obj; + int i; + + for_each_old_global_obj_in_state(state, obj, old_obj_state, i) { + struct intel_global_commit *commit = old_obj_state->commit; + long ret; + + if (!commit) + continue; + + ret = wait_for_completion_timeout(&commit->done, 10 * HZ); + if (ret == 0) { + drm_err(&i915->drm, "global state timed out\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +void +intel_atomic_global_state_commit_done(struct intel_atomic_state *state) +{ + const struct intel_global_state *new_obj_state; + struct intel_global_obj *obj; + int i; + + for_each_new_global_obj_in_state(state, obj, new_obj_state, i) { + struct intel_global_commit *commit = new_obj_state->commit; + + if (!new_obj_state->serialized) + continue; + + complete_all(&commit->done); + } +} diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h index 5477de8f0b30ce4ec0edfc9337814365810cd5eb..5c8545d7a76a7736a7e3e782187c75adfe606d39 100644 --- a/drivers/gpu/drm/i915/display/intel_global_state.h +++ b/drivers/gpu/drm/i915/display/intel_global_state.h @@ -54,11 +54,14 @@ struct intel_global_obj { (__i)++) \ for_each_if(obj) +struct intel_global_commit; + struct intel_global_state { struct intel_global_obj *obj; struct intel_atomic_state *state; + struct intel_global_commit *commit; struct kref ref; - bool changed; + bool changed, serialized; }; struct __intel_global_objs_state { @@ -87,6 +90,10 @@ void intel_atomic_clear_global_state(struct intel_atomic_state *state); int intel_atomic_lock_global_state(struct intel_global_state *obj_state); int intel_atomic_serialize_global_state(struct intel_global_state *obj_state); +int intel_atomic_global_state_setup_commit(struct intel_atomic_state *state); +void intel_atomic_global_state_commit_done(struct intel_atomic_state *state); +int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state); + bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state); #endif diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index e9e4dcf345f95722b6c67cb4db802a193c84b0dd..d3e03ed5b79c56438a2d48b22602f44ce70824bb 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -155,7 +155,7 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915, const struct gmbus_pin *pins; size_t size; - if (INTEL_PCH_TYPE(i915) >= PCH_LNL) { + if (INTEL_PCH_TYPE(i915) >= PCH_MTL) { pins = gmbus_pins_mtp; size = ARRAY_SIZE(gmbus_pins_mtp); } else if (INTEL_PCH_TYPE(i915) >= PCH_DG2) { @@ -164,9 +164,6 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915, } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) { pins = gmbus_pins_dg1; size = ARRAY_SIZE(gmbus_pins_dg1); - } else if (INTEL_PCH_TYPE(i915) >= PCH_MTP) { - pins = gmbus_pins_mtp; - size = ARRAY_SIZE(gmbus_pins_mtp); } else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) { pins = gmbus_pins_icp; size = ARRAY_SIZE(gmbus_pins_icp); diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 39b3f7c0c77c99068deb40567060c588e398d408..c3e692e7f790db2a3999822b315132fb9973052a 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -347,7 +347,7 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *i915, default: drm_err(&i915->drm, "Unknown transcoder %d\n", cpu_transcoder); - return -EINVAL; + return 0; } } @@ -364,7 +364,7 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *i915, return HDCP_DDIE_REP_PRESENT | HDCP_DDIE_SHA1_M0; default: drm_err(&i915->drm, "Unknown port %d\n", port); - return -EINVAL; + return 0; } } @@ -853,8 +853,8 @@ static int intel_hdcp_auth(struct intel_connector *connector) if (shim->stream_encryption) { ret = shim->stream_encryption(connector, true); if (ret) { - drm_err(&i915->drm, "[%s:%d] Failed to enable HDCP 1.4 stream enc\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to enable HDCP 1.4 stream enc\n", + connector->base.base.id, connector->base.name); return ret; } drm_dbg_kms(&i915->drm, "HDCP 1.4 transcoder: %s stream encrypted\n", @@ -878,14 +878,14 @@ static int _intel_hdcp_disable(struct intel_connector *connector) u32 repeater_ctl; int ret; - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP is being disabled...\n", - connector->base.name, connector->base.base.id); + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP is being disabled...\n", + connector->base.base.id, connector->base.name); if (hdcp->shim->stream_encryption) { ret = hdcp->shim->stream_encryption(connector, false); if (ret) { - drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4 stream enc\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to disable HDCP 1.4 stream enc\n", + connector->base.base.id, connector->base.name); return ret; } drm_dbg_kms(&i915->drm, "HDCP 1.4 transcoder: %s stream encryption disabled\n", @@ -929,8 +929,8 @@ static int intel_hdcp1_enable(struct intel_connector *connector) struct intel_hdcp *hdcp = &connector->hdcp; int i, ret, tries = 3; - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP is being enabled...\n", - connector->base.name, connector->base.base.id); + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP is being enabled...\n", + connector->base.base.id, connector->base.name); if (!hdcp_key_loadable(i915)) { drm_err(&i915->drm, "HDCP key Load is not possible\n"); @@ -1027,8 +1027,8 @@ static int intel_hdcp_check_link(struct intel_connector *connector) if (drm_WARN_ON(&i915->drm, !intel_hdcp_in_use(i915, cpu_transcoder, port))) { drm_err(&i915->drm, - "%s:%d HDCP link stopped encryption,%x\n", - connector->base.name, connector->base.base.id, + "[CONNECTOR:%d:%s] HDCP link stopped encryption,%x\n", + connector->base.base.id, connector->base.name, intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder, port))); ret = -ENXIO; intel_hdcp_update_value(connector, @@ -1046,8 +1046,8 @@ static int intel_hdcp_check_link(struct intel_connector *connector) } drm_dbg_kms(&i915->drm, - "[%s:%d] HDCP link failed, retrying authentication\n", - connector->base.name, connector->base.base.id); + "[CONNECTOR:%d:%s] HDCP link failed, retrying authentication\n", + connector->base.base.id, connector->base.name); ret = _intel_hdcp_disable(connector); if (ret) { @@ -1633,6 +1633,12 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) !HDCP_2_2_HDCP1_DEVICE_CONNECTED(rx_info[1]) && !HDCP_2_2_HDCP_2_0_REP_CONNECTED(rx_info[1]); + if (!dig_port->hdcp_mst_type1_capable && hdcp->content_type) { + drm_dbg_kms(&i915->drm, + "HDCP1.x or 2.0 Legacy Device Downstream\n"); + return -EINVAL; + } + /* Converting and Storing the seq_num_v to local variable as DWORD */ seq_num_v = drm_hdcp_be24_to_cpu((const u8 *)msgs.recvid_list.seq_num_v); @@ -1731,8 +1737,8 @@ static int hdcp2_enable_stream_encryption(struct intel_connector *connector) if (!(intel_de_read(i915, HDCP2_STATUS(i915, cpu_transcoder, port)) & LINK_ENCRYPTION_STATUS)) { - drm_err(&i915->drm, "[%s:%d] HDCP 2.2 Link is not encrypted\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] HDCP 2.2 Link is not encrypted\n", + connector->base.base.id, connector->base.name); ret = -EPERM; goto link_recover; } @@ -1740,8 +1746,8 @@ static int hdcp2_enable_stream_encryption(struct intel_connector *connector) if (hdcp->shim->stream_2_2_encryption) { ret = hdcp->shim->stream_2_2_encryption(connector, true); if (ret) { - drm_err(&i915->drm, "[%s:%d] Failed to enable HDCP 2.2 stream enc\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to enable HDCP 2.2 stream enc\n", + connector->base.base.id, connector->base.name); return ret; } drm_dbg_kms(&i915->drm, "HDCP 2.2 transcoder: %s stream encrypted\n", @@ -1925,8 +1931,8 @@ static int _intel_hdcp2_enable(struct intel_connector *connector) struct intel_hdcp *hdcp = &connector->hdcp; int ret; - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is being enabled. Type: %d\n", - connector->base.name, connector->base.base.id, + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is being enabled. Type: %d\n", + connector->base.base.id, connector->base.name, hdcp->content_type); ret = hdcp2_authenticate_and_encrypt(connector); @@ -1936,8 +1942,8 @@ static int _intel_hdcp2_enable(struct intel_connector *connector) return ret; } - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is enabled. Type %d\n", - connector->base.name, connector->base.base.id, + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is enabled. Type %d\n", + connector->base.base.id, connector->base.name, hdcp->content_type); hdcp->hdcp2_encrypted = true; @@ -1953,14 +1959,14 @@ _intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recovery struct intel_hdcp *hdcp = &connector->hdcp; int ret; - drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is being Disabled\n", - connector->base.name, connector->base.base.id); + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] HDCP2.2 is being Disabled\n", + connector->base.base.id, connector->base.name); if (hdcp->shim->stream_2_2_encryption) { ret = hdcp->shim->stream_2_2_encryption(connector, false); if (ret) { - drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 2.2 stream enc\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to disable HDCP 2.2 stream enc\n", + connector->base.base.id, connector->base.name); return ret; } drm_dbg_kms(&i915->drm, "HDCP 2.2 transcoder: %s stream encryption disabled\n", @@ -2040,20 +2046,20 @@ static int intel_hdcp2_check_link(struct intel_connector *connector) goto out; } drm_dbg_kms(&i915->drm, - "[%s:%d] Repeater topology auth failed.(%d)\n", - connector->base.name, connector->base.base.id, + "[CONNECTOR:%d:%s] Repeater topology auth failed.(%d)\n", + connector->base.base.id, connector->base.name, ret); } else { drm_dbg_kms(&i915->drm, - "[%s:%d] HDCP2.2 link failed, retrying auth\n", - connector->base.name, connector->base.base.id); + "[CONNECTOR:%d:%s] HDCP2.2 link failed, retrying auth\n", + connector->base.base.id, connector->base.name); } ret = _intel_hdcp2_disable(connector, true); if (ret) { drm_err(&i915->drm, - "[%s:%d] Failed to disable hdcp2.2 (%d)\n", - connector->base.name, connector->base.base.id, ret); + "[CONNECTOR:%d:%s] Failed to disable hdcp2.2 (%d)\n", + connector->base.base.id, connector->base.name, ret); intel_hdcp_update_value(connector, DRM_MODE_CONTENT_PROTECTION_DESIRED, true); goto out; @@ -2062,8 +2068,8 @@ static int intel_hdcp2_check_link(struct intel_connector *connector) ret = _intel_hdcp2_enable(connector); if (ret) { drm_dbg_kms(&i915->drm, - "[%s:%d] Failed to enable hdcp2.2 (%d)\n", - connector->base.name, connector->base.base.id, + "[CONNECTOR:%d:%s] Failed to enable hdcp2.2 (%d)\n", + connector->base.base.id, connector->base.name, ret); intel_hdcp_update_value(connector, DRM_MODE_CONTENT_PROTECTION_DESIRED, @@ -2341,8 +2347,8 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state, return -ENOENT; if (!connector->encoder) { - drm_err(&i915->drm, "[%s:%d] encoder is not initialized\n", - connector->base.name, connector->base.base.id); + drm_err(&i915->drm, "[CONNECTOR:%d:%s] encoder is not initialized\n", + connector->base.base.id, connector->base.name); return -ENODEV; } diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c index 18117b789b1689866ab35a16be159ddbf2b58bbf..302bff75b06c56f6d973df7364cb62cf8a388ce4 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c @@ -65,7 +65,7 @@ static int intel_hdcp_gsc_initialize_message(struct drm_i915_private *i915, goto out_unmap; } - err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL); + err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH); if (err) goto out_unmap; diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h index 8023c85c7fa0ea141a8de0e852d4ad44ded45cd0..a568a457e53268011a6c932efc7f3dc1b7cb9fb0 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h +++ b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h @@ -8,6 +8,8 @@ #include "intel_display_reg_defs.h" +#define TRANS_HDCP(__i915) (DISPLAY_VER(__i915) >= 12) + /* HDCP Key Registers */ #define HDCP_KEY_CONF _MMIO(0x66c00) #define HDCP_AKSV_SEND_TRIGGER REG_BIT(31) @@ -82,7 +84,7 @@ #define TRANS_HDCP_CONF(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_CONF, \ _TRANSB_HDCP_CONF) #define HDCP_CONF(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_CONF(trans) : \ PORT_HDCP_CONF(port)) @@ -95,7 +97,7 @@ _TRANSA_HDCP_ANINIT, \ _TRANSB_HDCP_ANINIT) #define HDCP_ANINIT(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_ANINIT(trans) : \ PORT_HDCP_ANINIT(port)) @@ -105,7 +107,7 @@ #define TRANS_HDCP_ANLO(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_ANLO, \ _TRANSB_HDCP_ANLO) #define HDCP_ANLO(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_ANLO(trans) : \ PORT_HDCP_ANLO(port)) @@ -115,7 +117,7 @@ #define TRANS_HDCP_ANHI(trans) _MMIO_TRANS(trans, _TRANSA_HDCP_ANHI, \ _TRANSB_HDCP_ANHI) #define HDCP_ANHI(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_ANHI(trans) : \ PORT_HDCP_ANHI(port)) @@ -126,7 +128,7 @@ _TRANSA_HDCP_BKSVLO, \ _TRANSB_HDCP_BKSVLO) #define HDCP_BKSVLO(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_BKSVLO(trans) : \ PORT_HDCP_BKSVLO(port)) @@ -137,7 +139,7 @@ _TRANSA_HDCP_BKSVHI, \ _TRANSB_HDCP_BKSVHI) #define HDCP_BKSVHI(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_BKSVHI(trans) : \ PORT_HDCP_BKSVHI(port)) @@ -148,7 +150,7 @@ _TRANSA_HDCP_RPRIME, \ _TRANSB_HDCP_RPRIME) #define HDCP_RPRIME(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_RPRIME(trans) : \ PORT_HDCP_RPRIME(port)) @@ -159,7 +161,7 @@ _TRANSA_HDCP_STATUS, \ _TRANSB_HDCP_STATUS) #define HDCP_STATUS(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP_STATUS(trans) : \ PORT_HDCP_STATUS(port)) @@ -200,7 +202,7 @@ #define AUTH_FORCE_CLR_INPUTCTR REG_BIT(19) #define AUTH_CLR_KEYS REG_BIT(18) #define HDCP2_AUTH(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_AUTH(trans) : \ PORT_HDCP2_AUTH(port)) @@ -211,7 +213,7 @@ _TRANSB_HDCP2_CTL) #define CTL_LINK_ENCRYPTION_REQ REG_BIT(31) #define HDCP2_CTL(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_CTL(trans) : \ PORT_HDCP2_CTL(port)) @@ -225,7 +227,7 @@ #define LINK_AUTH_STATUS REG_BIT(21) #define LINK_ENCRYPTION_STATUS REG_BIT(20) #define HDCP2_STATUS(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_STATUS(trans) : \ PORT_HDCP2_STATUS(port)) @@ -247,7 +249,7 @@ #define STREAM_ENCRYPTION_STATUS REG_BIT(31) #define STREAM_TYPE_STATUS REG_BIT(30) #define HDCP2_STREAM_STATUS(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_STREAM_STATUS(trans) : \ PIPE_HDCP2_STREAM_STATUS(pipe)) @@ -263,7 +265,7 @@ _TRANSB_HDCP2_AUTH_STREAM) #define AUTH_STREAM_TYPE REG_BIT(31) #define HDCP2_AUTH_STREAM(dev_priv, trans, port) \ - (GRAPHICS_VER(dev_priv) >= 12 ? \ + (TRANS_HDCP(dev_priv) ? \ TRANS_HDCP2_AUTH_STREAM(trans) : \ PORT_HDCP2_AUTH_STREAM(port)) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 39e4f5f7c81715666fee6f4451e22b62aef4879d..7020e58061092bd919af3b53486181b3300afb9a 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -49,6 +49,7 @@ #include "intel_cx0_phy.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_gmbus.h" @@ -523,10 +524,12 @@ void hsw_write_infoframe(struct intel_encoder *encoder, 0); /* Wa_14013475917 */ - if (IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC) - return; + if (!(IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC)) + val |= hsw_infoframe_enable(type); + + if (type == DP_SDP_VSC) + val |= VSC_DIP_HW_DATA_SW_HEA; - val |= hsw_infoframe_enable(type); intel_de_write(dev_priv, ctl_reg, val); intel_de_posting_read(dev_priv, ctl_reg); } @@ -2503,6 +2506,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; + if (!intel_display_driver_check_access(dev_priv)) + return connector->status; + wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); if (DISPLAY_VER(dev_priv) >= 11 && @@ -2531,6 +2537,9 @@ intel_hdmi_force(struct drm_connector *connector) drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); + if (!intel_display_driver_check_access(i915)) + return; + intel_hdmi_unset_edid(connector); if (connector->status != connector_status_connected) @@ -3015,6 +3024,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, connector->ycbcr_420_allowed = true; intel_connector->polled = DRM_CONNECTOR_POLL_HPD; + intel_connector->base.polled = intel_connector->polled; if (HAS_DDI(dev_priv)) intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 0c0700c6ec66d5448c4ee3489285f75f1026ca69..d9ec349f3c8c3f4a051271f9a99463e9a75d4653 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -177,6 +177,46 @@ static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, return storm; } +static bool detection_work_enabled(struct drm_i915_private *i915) +{ + lockdep_assert_held(&i915->irq_lock); + + return i915->display.hotplug.detection_work_enabled; +} + +static bool +mod_delayed_detection_work(struct drm_i915_private *i915, struct delayed_work *work, int delay) +{ + lockdep_assert_held(&i915->irq_lock); + + if (!detection_work_enabled(i915)) + return false; + + return mod_delayed_work(i915->unordered_wq, work, delay); +} + +static bool +queue_delayed_detection_work(struct drm_i915_private *i915, struct delayed_work *work, int delay) +{ + lockdep_assert_held(&i915->irq_lock); + + if (!detection_work_enabled(i915)) + return false; + + return queue_delayed_work(i915->unordered_wq, work, delay); +} + +static bool +queue_detection_work(struct drm_i915_private *i915, struct work_struct *work) +{ + lockdep_assert_held(&i915->irq_lock); + + if (!detection_work_enabled(i915)) + return false; + + return queue_work(i915->unordered_wq, work); +} + static void intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) { @@ -213,9 +253,9 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) /* Enable polling and queue hotplug re-enabling. */ if (hpd_disabled) { drm_kms_helper_poll_reschedule(&dev_priv->drm); - mod_delayed_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.reenable_work, - msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); + mod_delayed_detection_work(dev_priv, + &dev_priv->display.hotplug.reenable_work, + msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); } } @@ -348,9 +388,9 @@ static void i915_digport_work_func(struct work_struct *work) if (old_bits) { spin_lock_irq(&dev_priv->irq_lock); dev_priv->display.hotplug.event_bits |= old_bits; + queue_delayed_detection_work(dev_priv, + &dev_priv->display.hotplug.hotplug_work, 0); spin_unlock_irq(&dev_priv->irq_lock); - queue_delayed_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.hotplug_work, 0); } } @@ -467,11 +507,11 @@ static void i915_hotplug_work_func(struct work_struct *work) if (retry) { spin_lock_irq(&dev_priv->irq_lock); dev_priv->display.hotplug.retry_bits |= retry; - spin_unlock_irq(&dev_priv->irq_lock); - mod_delayed_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.hotplug_work, - msecs_to_jiffies(HPD_RETRY_DELAY)); + mod_delayed_detection_work(dev_priv, + &dev_priv->display.hotplug.hotplug_work, + msecs_to_jiffies(HPD_RETRY_DELAY)); + spin_unlock_irq(&dev_priv->irq_lock); } } @@ -590,7 +630,6 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, */ if (storm_detected) intel_hpd_irq_setup(dev_priv); - spin_unlock(&dev_priv->irq_lock); /* * Our hotplug handler can grab modeset locks (by calling down into the @@ -601,8 +640,10 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, if (queue_dig) queue_work(dev_priv->display.hotplug.dp_wq, &dev_priv->display.hotplug.dig_port_work); if (queue_hp) - queue_delayed_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.hotplug_work, 0); + queue_delayed_detection_work(dev_priv, + &dev_priv->display.hotplug.hotplug_work, 0); + + spin_unlock(&dev_priv->irq_lock); } /** @@ -710,6 +751,8 @@ static void i915_hpd_poll_init_work(struct work_struct *work) cancel_work(&dev_priv->display.hotplug.poll_init_work); } + spin_lock_irq(&dev_priv->irq_lock); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { enum hpd_pin pin; @@ -718,6 +761,9 @@ static void i915_hpd_poll_init_work(struct work_struct *work) if (pin == HPD_NONE) continue; + if (dev_priv->display.hotplug.stats[pin].state == HPD_DISABLED) + continue; + connector->base.polled = connector->polled; if (enabled && connector->base.polled == DRM_CONNECTOR_POLL_HPD) @@ -726,6 +772,8 @@ static void i915_hpd_poll_init_work(struct work_struct *work) } drm_connector_list_iter_end(&conn_iter); + spin_unlock_irq(&dev_priv->irq_lock); + if (enabled) drm_kms_helper_poll_reschedule(&dev_priv->drm); @@ -774,8 +822,10 @@ void intel_hpd_poll_enable(struct drm_i915_private *dev_priv) * As well, there's no issue if we race here since we always reschedule * this worker anyway */ - queue_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.poll_init_work); + spin_lock_irq(&dev_priv->irq_lock); + queue_detection_work(dev_priv, + &dev_priv->display.hotplug.poll_init_work); + spin_unlock_irq(&dev_priv->irq_lock); } /** @@ -803,8 +853,11 @@ void intel_hpd_poll_disable(struct drm_i915_private *dev_priv) return; WRITE_ONCE(dev_priv->display.hotplug.poll_enabled, false); - queue_work(dev_priv->unordered_wq, - &dev_priv->display.hotplug.poll_init_work); + + spin_lock_irq(&dev_priv->irq_lock); + queue_detection_work(dev_priv, + &dev_priv->display.hotplug.poll_init_work); + spin_unlock_irq(&dev_priv->irq_lock); } void intel_hpd_init_early(struct drm_i915_private *i915) @@ -826,6 +879,20 @@ void intel_hpd_init_early(struct drm_i915_private *i915) i915->display.hotplug.hpd_short_storm_enabled = !HAS_DP_MST(i915); } +static bool cancel_all_detection_work(struct drm_i915_private *i915) +{ + bool was_pending = false; + + if (cancel_delayed_work_sync(&i915->display.hotplug.hotplug_work)) + was_pending = true; + if (cancel_work_sync(&i915->display.hotplug.poll_init_work)) + was_pending = true; + if (cancel_delayed_work_sync(&i915->display.hotplug.reenable_work)) + was_pending = true; + + return was_pending; +} + void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) { if (!HAS_DISPLAY(dev_priv)) @@ -841,9 +908,13 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); cancel_work_sync(&dev_priv->display.hotplug.dig_port_work); - cancel_delayed_work_sync(&dev_priv->display.hotplug.hotplug_work); - cancel_work_sync(&dev_priv->display.hotplug.poll_init_work); - cancel_delayed_work_sync(&dev_priv->display.hotplug.reenable_work); + + /* + * All other work triggered by hotplug events should be canceled by + * now. + */ + if (cancel_all_detection_work(dev_priv)) + drm_dbg_kms(&dev_priv->drm, "Hotplug detection work still active\n"); } bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin) @@ -873,6 +944,62 @@ void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin) spin_unlock_irq(&dev_priv->irq_lock); } +static void queue_work_for_missed_irqs(struct drm_i915_private *i915) +{ + bool queue_work = false; + enum hpd_pin pin; + + lockdep_assert_held(&i915->irq_lock); + + if (i915->display.hotplug.event_bits || + i915->display.hotplug.retry_bits) + queue_work = true; + + for_each_hpd_pin(pin) { + switch (i915->display.hotplug.stats[pin].state) { + case HPD_MARK_DISABLED: + queue_work = true; + break; + case HPD_ENABLED: + break; + default: + MISSING_CASE(i915->display.hotplug.stats[pin].state); + } + } + + if (queue_work) + queue_delayed_detection_work(i915, &i915->display.hotplug.hotplug_work, 0); +} + +void intel_hpd_enable_detection_work(struct drm_i915_private *i915) +{ + spin_lock_irq(&i915->irq_lock); + i915->display.hotplug.detection_work_enabled = true; + queue_work_for_missed_irqs(i915); + spin_unlock_irq(&i915->irq_lock); +} + +void intel_hpd_disable_detection_work(struct drm_i915_private *i915) +{ + spin_lock_irq(&i915->irq_lock); + i915->display.hotplug.detection_work_enabled = false; + spin_unlock_irq(&i915->irq_lock); + + cancel_all_detection_work(i915); +} + +bool intel_hpd_schedule_detection(struct drm_i915_private *i915) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&i915->irq_lock, flags); + ret = queue_delayed_detection_work(i915, &i915->display.hotplug.hotplug_work, 0); + spin_unlock_irqrestore(&i915->irq_lock, flags); + + return ret; +} + static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = m->private; diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h index 424ae5dbf5a0eee4ec976ffbc0e5f75953a641b6..a17253ddec83a3aa898d123203d6dbb01e6b9169 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.h +++ b/drivers/gpu/drm/i915/display/intel_hotplug.h @@ -30,4 +30,8 @@ bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin); void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin); void intel_hpd_debugfs_register(struct drm_i915_private *i915); +void intel_hpd_enable_detection_work(struct drm_i915_private *i915); +void intel_hpd_disable_detection_work(struct drm_i915_private *i915); +bool intel_hpd_schedule_detection(struct drm_i915_private *i915); + #endif /* __INTEL_HOTPLUG_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index 04f62f27ad74b12666d5f167c17db40c514ec063..76076509f7717f86657f9b975fe1f1c0b7bf875b 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -163,12 +163,10 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))) return; - if (INTEL_PCH_TYPE(dev_priv) >= PCH_LNL) + if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTL) hpd->pch_hpd = hpd_mtp; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) hpd->pch_hpd = hpd_sde_dg1; - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP) - hpd->pch_hpd = hpd_mtp; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) hpd->pch_hpd = hpd_icp; else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv)) @@ -1139,7 +1137,7 @@ static void xelpdp_hpd_irq_setup(struct drm_i915_private *i915) if (INTEL_PCH_TYPE(i915) >= PCH_LNL) xe2lpd_sde_hpd_irq_setup(i915); - else if (INTEL_PCH_TYPE(i915) >= PCH_MTP) + else if (INTEL_PCH_TYPE(i915) >= PCH_MTL) mtp_hpd_irq_setup(i915); } diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index 1ce785db6a5e199a6044ff766cdc541628c4a32b..f242bb320610a623cdeb54cd1c09e05756307d7b 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -250,11 +250,36 @@ struct opregion_asle_ext { #define MAX_DSLP 1500 +#define OPREGION_SIZE (8 * 1024) + +struct intel_opregion { + struct drm_i915_private *i915; + + struct opregion_header *header; + struct opregion_acpi *acpi; + struct opregion_swsci *swsci; + u32 swsci_gbda_sub_functions; + u32 swsci_sbcb_sub_functions; + struct opregion_asle *asle; + struct opregion_asle_ext *asle_ext; + void *rvda; + void *vbt_firmware; + const void *vbt; + u32 vbt_size; + struct work_struct asle_work; + struct notifier_block acpi_notifier; +}; + static int check_swsci_function(struct drm_i915_private *i915, u32 function) { - struct opregion_swsci *swsci = i915->display.opregion.swsci; + struct intel_opregion *opregion = i915->display.opregion; + struct opregion_swsci *swsci; u32 main_function, sub_function; + if (!opregion) + return -ENODEV; + + swsci = opregion->swsci; if (!swsci) return -ENODEV; @@ -265,11 +290,11 @@ static int check_swsci_function(struct drm_i915_private *i915, u32 function) /* Check if we can call the function. See swsci_setup for details. */ if (main_function == SWSCI_SBCB) { - if ((i915->display.opregion.swsci_sbcb_sub_functions & + if ((opregion->swsci_sbcb_sub_functions & (1 << sub_function)) == 0) return -EINVAL; } else if (main_function == SWSCI_GBDA) { - if ((i915->display.opregion.swsci_gbda_sub_functions & + if ((opregion->swsci_gbda_sub_functions & (1 << sub_function)) == 0) return -EINVAL; } @@ -280,7 +305,7 @@ static int check_swsci_function(struct drm_i915_private *i915, u32 function) static int swsci(struct drm_i915_private *dev_priv, u32 function, u32 parm, u32 *parm_out) { - struct opregion_swsci *swsci = dev_priv->display.opregion.swsci; + struct opregion_swsci *swsci; struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u32 scic, dslp; u16 swsci_val; @@ -290,6 +315,8 @@ static int swsci(struct drm_i915_private *dev_priv, if (ret) return ret; + swsci = dev_priv->display.opregion->swsci; + /* Driver sleep timeout in ms. */ dslp = swsci->dslp; if (!dslp) { @@ -462,7 +489,7 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp) { struct intel_connector *connector; struct drm_connector_list_iter conn_iter; - struct opregion_asle *asle = dev_priv->display.opregion.asle; + struct opregion_asle *asle = dev_priv->display.opregion->asle; drm_dbg(&dev_priv->drm, "bclp = 0x%08x\n", bclp); @@ -584,9 +611,8 @@ static void asle_work(struct work_struct *work) { struct intel_opregion *opregion = container_of(work, struct intel_opregion, asle_work); - struct drm_i915_private *dev_priv = - container_of(opregion, struct drm_i915_private, display.opregion); - struct opregion_asle *asle = dev_priv->display.opregion.asle; + struct drm_i915_private *dev_priv = opregion->i915; + struct opregion_asle *asle = opregion->asle; u32 aslc_stat = 0; u32 aslc_req; @@ -632,11 +658,17 @@ static void asle_work(struct work_struct *work) asle->aslc = aslc_stat; } -void intel_opregion_asle_intr(struct drm_i915_private *dev_priv) +bool intel_opregion_asle_present(struct drm_i915_private *i915) +{ + return i915->display.opregion && i915->display.opregion->asle; +} + +void intel_opregion_asle_intr(struct drm_i915_private *i915) { - if (dev_priv->display.opregion.asle) - queue_work(dev_priv->unordered_wq, - &dev_priv->display.opregion.asle_work); + struct intel_opregion *opregion = i915->display.opregion; + + if (opregion && opregion->asle) + queue_work(i915->unordered_wq, &opregion->asle_work); } #define ACPI_EV_DISPLAY_SWITCH (1<<0) @@ -692,7 +724,7 @@ static void set_did(struct intel_opregion *opregion, int i, u32 val) static void intel_didl_outputs(struct drm_i915_private *dev_priv) { - struct intel_opregion *opregion = &dev_priv->display.opregion; + struct intel_opregion *opregion = dev_priv->display.opregion; struct intel_connector *connector; struct drm_connector_list_iter conn_iter; int i = 0, max_outputs; @@ -731,7 +763,7 @@ static void intel_didl_outputs(struct drm_i915_private *dev_priv) static void intel_setup_cadls(struct drm_i915_private *dev_priv) { - struct intel_opregion *opregion = &dev_priv->display.opregion; + struct intel_opregion *opregion = dev_priv->display.opregion; struct intel_connector *connector; struct drm_connector_list_iter conn_iter; int i = 0; @@ -761,7 +793,7 @@ static void intel_setup_cadls(struct drm_i915_private *dev_priv) static void swsci_setup(struct drm_i915_private *dev_priv) { - struct intel_opregion *opregion = &dev_priv->display.opregion; + struct intel_opregion *opregion = dev_priv->display.opregion; bool requested_callbacks = false; u32 tmp; @@ -839,7 +871,7 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = { static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv) { - struct intel_opregion *opregion = &dev_priv->display.opregion; + struct intel_opregion *opregion = dev_priv->display.opregion; const struct firmware *fw = NULL; const char *name = dev_priv->display.params.vbt_firmware; int ret; @@ -879,7 +911,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv) int intel_opregion_setup(struct drm_i915_private *dev_priv) { - struct intel_opregion *opregion = &dev_priv->display.opregion; + struct intel_opregion *opregion; struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u32 asls, mboxes; char buf[sizeof(OPREGION_SIGNATURE)]; @@ -902,11 +934,20 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) return -ENOTSUPP; } + opregion = kzalloc(sizeof(*opregion), GFP_KERNEL); + if (!opregion) + return -ENOMEM; + + opregion->i915 = dev_priv; + dev_priv->display.opregion = opregion; + INIT_WORK(&opregion->asle_work, asle_work); base = memremap(asls, OPREGION_SIZE, MEMREMAP_WB); - if (!base) - return -ENOMEM; + if (!base) { + err = -ENOMEM; + goto err_memremap; + } memcpy(buf, base, sizeof(buf)); @@ -916,7 +957,6 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) goto err_out; } opregion->header = base; - opregion->lid_state = base + ACPI_CLID; drm_dbg(&dev_priv->drm, "ACPI OpRegion version %u.%u.%u\n", opregion->header->over.major, @@ -1034,6 +1074,10 @@ out: err_out: memunmap(base); +err_memremap: + kfree(opregion); + dev_priv->display.opregion = NULL; + return err; } @@ -1106,12 +1150,12 @@ const struct drm_edid *intel_opregion_get_edid(struct intel_connector *intel_con { struct drm_connector *connector = &intel_connector->base; struct drm_i915_private *i915 = to_i915(connector->dev); - struct intel_opregion *opregion = &i915->display.opregion; + struct intel_opregion *opregion = i915->display.opregion; const struct drm_edid *drm_edid; const void *edid; int len; - if (!opregion->asle_ext) + if (!opregion || !opregion->asle_ext) return NULL; edid = opregion->asle_ext->bddc; @@ -1132,10 +1176,28 @@ const struct drm_edid *intel_opregion_get_edid(struct intel_connector *intel_con return drm_edid; } +const void *intel_opregion_get_vbt(struct drm_i915_private *i915, size_t *size) +{ + struct intel_opregion *opregion = i915->display.opregion; + + if (!opregion || !opregion->vbt) + return NULL; + + if (size) + *size = opregion->vbt_size; + + return opregion->vbt; +} + bool intel_opregion_headless_sku(struct drm_i915_private *i915) { - struct intel_opregion *opregion = &i915->display.opregion; - struct opregion_header *header = opregion->header; + struct intel_opregion *opregion = i915->display.opregion; + struct opregion_header *header; + + if (!opregion) + return false; + + header = opregion->header; if (!header || header->over.major < 2 || (header->over.major == 2 && header->over.minor < 3)) @@ -1146,9 +1208,9 @@ bool intel_opregion_headless_sku(struct drm_i915_private *i915) void intel_opregion_register(struct drm_i915_private *i915) { - struct intel_opregion *opregion = &i915->display.opregion; + struct intel_opregion *opregion = i915->display.opregion; - if (!opregion->header) + if (!opregion) return; if (opregion->acpi) { @@ -1162,7 +1224,7 @@ void intel_opregion_register(struct drm_i915_private *i915) static void intel_opregion_resume_display(struct drm_i915_private *i915) { - struct intel_opregion *opregion = &i915->display.opregion; + struct intel_opregion *opregion = i915->display.opregion; if (opregion->acpi) { intel_didl_outputs(i915); @@ -1188,9 +1250,9 @@ static void intel_opregion_resume_display(struct drm_i915_private *i915) void intel_opregion_resume(struct drm_i915_private *i915) { - struct intel_opregion *opregion = &i915->display.opregion; + struct intel_opregion *opregion = i915->display.opregion; - if (!opregion->header) + if (!opregion) return; if (HAS_DISPLAY(i915)) @@ -1201,12 +1263,12 @@ void intel_opregion_resume(struct drm_i915_private *i915) static void intel_opregion_suspend_display(struct drm_i915_private *i915) { - struct intel_opregion *opregion = &i915->display.opregion; + struct intel_opregion *opregion = i915->display.opregion; if (opregion->asle) opregion->asle->ardy = ASLE_ARDY_NOT_READY; - cancel_work_sync(&i915->display.opregion.asle_work); + cancel_work_sync(&opregion->asle_work); if (opregion->acpi) opregion->acpi->drdy = 0; @@ -1214,9 +1276,9 @@ static void intel_opregion_suspend_display(struct drm_i915_private *i915) void intel_opregion_suspend(struct drm_i915_private *i915, pci_power_t state) { - struct intel_opregion *opregion = &i915->display.opregion; + struct intel_opregion *opregion = i915->display.opregion; - if (!opregion->header) + if (!opregion) return; intel_opregion_notify_adapter(i915, state); @@ -1227,11 +1289,11 @@ void intel_opregion_suspend(struct drm_i915_private *i915, pci_power_t state) void intel_opregion_unregister(struct drm_i915_private *i915) { - struct intel_opregion *opregion = &i915->display.opregion; + struct intel_opregion *opregion = i915->display.opregion; intel_opregion_suspend(i915, PCI_D1); - if (!opregion->header) + if (!opregion) return; if (opregion->acpi_notifier.notifier_call) { @@ -1242,26 +1304,36 @@ void intel_opregion_unregister(struct drm_i915_private *i915) void intel_opregion_cleanup(struct drm_i915_private *i915) { - struct intel_opregion *opregion = &i915->display.opregion; + struct intel_opregion *opregion = i915->display.opregion; - if (!opregion->header) + if (!opregion) return; - /* just clear all opregion memory pointers now */ memunmap(opregion->header); - if (opregion->rvda) { + if (opregion->rvda) memunmap(opregion->rvda); - opregion->rvda = NULL; - } - if (opregion->vbt_firmware) { - kfree(opregion->vbt_firmware); - opregion->vbt_firmware = NULL; - } - opregion->header = NULL; - opregion->acpi = NULL; - opregion->swsci = NULL; - opregion->asle = NULL; - opregion->asle_ext = NULL; - opregion->vbt = NULL; - opregion->lid_state = NULL; + kfree(opregion->vbt_firmware); + kfree(opregion); + i915->display.opregion = NULL; +} + +static int intel_opregion_show(struct seq_file *m, void *unused) +{ + struct drm_i915_private *i915 = m->private; + struct intel_opregion *opregion = i915->display.opregion; + + if (opregion) + seq_write(m, opregion->header, OPREGION_SIZE); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(intel_opregion); + +void intel_opregion_debugfs_register(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + + debugfs_create_file("i915_opregion", 0444, minor->debugfs_root, + i915, &intel_opregion_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_opregion.h b/drivers/gpu/drm/i915/display/intel_opregion.h index fd2ea8ef0fa2093e9cfc7578f830f4c89eb8bd16..0bec224f711fc48ce995b2c255b6389eb0df7d62 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.h +++ b/drivers/gpu/drm/i915/display/intel_opregion.h @@ -25,38 +25,13 @@ #ifndef _INTEL_OPREGION_H_ #define _INTEL_OPREGION_H_ -#include #include +#include struct drm_i915_private; struct intel_connector; struct intel_encoder; -struct opregion_header; -struct opregion_acpi; -struct opregion_swsci; -struct opregion_asle; -struct opregion_asle_ext; - -struct intel_opregion { - struct opregion_header *header; - struct opregion_acpi *acpi; - struct opregion_swsci *swsci; - u32 swsci_gbda_sub_functions; - u32 swsci_sbcb_sub_functions; - struct opregion_asle *asle; - struct opregion_asle_ext *asle_ext; - void *rvda; - void *vbt_firmware; - const void *vbt; - u32 vbt_size; - u32 *lid_state; - struct work_struct asle_work; - struct notifier_block acpi_notifier; -}; - -#define OPREGION_SIZE (8 * 1024) - #ifdef CONFIG_ACPI int intel_opregion_setup(struct drm_i915_private *dev_priv); @@ -69,6 +44,7 @@ void intel_opregion_resume(struct drm_i915_private *dev_priv); void intel_opregion_suspend(struct drm_i915_private *dev_priv, pci_power_t state); +bool intel_opregion_asle_present(struct drm_i915_private *i915); void intel_opregion_asle_intr(struct drm_i915_private *dev_priv); int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, bool enable); @@ -77,8 +53,12 @@ int intel_opregion_notify_adapter(struct drm_i915_private *dev_priv, int intel_opregion_get_panel_type(struct drm_i915_private *dev_priv); const struct drm_edid *intel_opregion_get_edid(struct intel_connector *connector); +const void *intel_opregion_get_vbt(struct drm_i915_private *i915, size_t *size); + bool intel_opregion_headless_sku(struct drm_i915_private *i915); +void intel_opregion_debugfs_register(struct drm_i915_private *i915); + #else /* CONFIG_ACPI*/ static inline int intel_opregion_setup(struct drm_i915_private *dev_priv) @@ -107,6 +87,11 @@ static inline void intel_opregion_suspend(struct drm_i915_private *dev_priv, { } +static inline bool intel_opregion_asle_present(struct drm_i915_private *i915) +{ + return false; +} + static inline void intel_opregion_asle_intr(struct drm_i915_private *dev_priv) { } @@ -134,11 +119,21 @@ intel_opregion_get_edid(struct intel_connector *connector) return NULL; } +static inline const void * +intel_opregion_get_vbt(struct drm_i915_private *i915, size_t *size) +{ + return NULL; +} + static inline bool intel_opregion_headless_sku(struct drm_i915_private *i915) { return false; } +static inline void intel_opregion_debugfs_register(struct drm_i915_private *i915) +{ +} + #endif /* CONFIG_ACPI */ #endif diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 0d8e5320a4f88e2526b832b3c9d2659956136832..073ea3166c360f4a8f63dc6175095093d576b7ab 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -37,6 +37,7 @@ #include "intel_backlight.h" #include "intel_connector.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_drrs.h" #include "intel_lvds_regs.h" @@ -683,6 +684,9 @@ intel_panel_detect(struct drm_connector *connector, bool force) if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->status; + return connector_status_connected; } diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index a55c09cbd0e484ee7af1316a52d9d0eacb887514..ada1792df5b3e9731f2c6a7460f8b9210e5e9ff0 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -3,9 +3,11 @@ * Copyright © 2021 Intel Corporation */ +#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" #include "i915_drv.h" #include "intel_atomic_plane.h" +#include "intel_crtc.h" #include "intel_display.h" #include "intel_display_types.h" #include "intel_fb.h" @@ -13,20 +15,21 @@ #include "intel_plane_initial.h" static bool -intel_reuse_initial_plane_obj(struct drm_i915_private *i915, - const struct intel_initial_plane_config *plane_config, +intel_reuse_initial_plane_obj(struct intel_crtc *this, + const struct intel_initial_plane_config plane_configs[], struct drm_framebuffer **fb, struct i915_vma **vma) { + struct drm_i915_private *i915 = to_i915(this->base.dev); struct intel_crtc *crtc; for_each_intel_crtc(&i915->drm, crtc) { - struct intel_crtc_state *crtc_state = - to_intel_crtc_state(crtc->base.state); struct intel_plane *plane = to_intel_plane(crtc->base.primary); - struct intel_plane_state *plane_state = + const struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state); + const struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); if (!crtc_state->uapi.active) continue; @@ -34,7 +37,7 @@ intel_reuse_initial_plane_obj(struct drm_i915_private *i915, if (!plane_state->ggtt_vma) continue; - if (intel_plane_ggtt_offset(plane_state) == plane_config->base) { + if (plane_configs[this->pipe].base == plane_configs[crtc->pipe].base) { *fb = plane_state->hw.fb; *vma = plane_state->ggtt_vma; return true; @@ -44,12 +47,100 @@ intel_reuse_initial_plane_obj(struct drm_i915_private *i915, return false; } +static bool +initial_plane_phys_lmem(struct drm_i915_private *i915, + struct intel_initial_plane_config *plane_config) +{ + gen8_pte_t __iomem *gte = to_gt(i915)->ggtt->gsm; + struct intel_memory_region *mem; + dma_addr_t dma_addr; + gen8_pte_t pte; + u32 base; + + base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); + + gte += base / I915_GTT_PAGE_SIZE; + + pte = ioread64(gte); + if (!(pte & GEN12_GGTT_PTE_LM)) { + drm_err(&i915->drm, + "Initial plane programming missing PTE_LM bit\n"); + return false; + } + + dma_addr = pte & GEN12_GGTT_PTE_ADDR_MASK; + + if (IS_DGFX(i915)) + mem = i915->mm.regions[INTEL_REGION_LMEM_0]; + else + mem = i915->mm.stolen_region; + if (!mem) { + drm_dbg_kms(&i915->drm, + "Initial plane memory region not initialized\n"); + return false; + } + + /* + * On lmem we don't currently expect this to + * ever be placed in the stolen portion. + */ + if (dma_addr < mem->region.start || dma_addr > mem->region.end) { + drm_err(&i915->drm, + "Initial plane programming using invalid range, dma_addr=%pa (%s [%pa-%pa])\n", + &dma_addr, mem->region.name, &mem->region.start, &mem->region.end); + return false; + } + + drm_dbg(&i915->drm, + "Using dma_addr=%pa, based on initial plane programming\n", + &dma_addr); + + plane_config->phys_base = dma_addr - mem->region.start; + plane_config->mem = mem; + + return true; +} + +static bool +initial_plane_phys_smem(struct drm_i915_private *i915, + struct intel_initial_plane_config *plane_config) +{ + struct intel_memory_region *mem; + u32 base; + + base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); + + mem = i915->mm.stolen_region; + if (!mem) { + drm_dbg_kms(&i915->drm, + "Initial plane memory region not initialized\n"); + return false; + } + + /* FIXME get and validate the dma_addr from the PTE */ + plane_config->phys_base = base; + plane_config->mem = mem; + + return true; +} + +static bool +initial_plane_phys(struct drm_i915_private *i915, + struct intel_initial_plane_config *plane_config) +{ + if (IS_DGFX(i915) || HAS_LMEMBAR_SMEM_STOLEN(i915)) + return initial_plane_phys_lmem(i915, plane_config); + else + return initial_plane_phys_smem(i915, plane_config); +} + static struct i915_vma * initial_plane_vma(struct drm_i915_private *i915, struct intel_initial_plane_config *plane_config) { struct intel_memory_region *mem; struct drm_i915_gem_object *obj; + struct drm_mm_node orig_mm = {}; struct i915_vma *vma; resource_size_t phys_base; u32 base, size; @@ -58,45 +149,13 @@ initial_plane_vma(struct drm_i915_private *i915, if (plane_config->size == 0) return NULL; - base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); - if (IS_DGFX(i915)) { - gen8_pte_t __iomem *gte = to_gt(i915)->ggtt->gsm; - gen8_pte_t pte; - - gte += base / I915_GTT_PAGE_SIZE; - - pte = ioread64(gte); - if (!(pte & GEN12_GGTT_PTE_LM)) { - drm_err(&i915->drm, - "Initial plane programming missing PTE_LM bit\n"); - return NULL; - } - - phys_base = pte & I915_GTT_PAGE_MASK; - mem = i915->mm.regions[INTEL_REGION_LMEM_0]; - - /* - * We don't currently expect this to ever be placed in the - * stolen portion. - */ - if (phys_base >= resource_size(&mem->region)) { - drm_err(&i915->drm, - "Initial plane programming using invalid range, phys_base=%pa\n", - &phys_base); - return NULL; - } - - drm_dbg(&i915->drm, - "Using phys_base=%pa, based on initial plane programming\n", - &phys_base); - } else { - phys_base = base; - mem = i915->mm.stolen_region; - } - - if (!mem) + if (!initial_plane_phys(i915, plane_config)) return NULL; + phys_base = plane_config->phys_base; + mem = plane_config->mem; + + base = round_down(plane_config->base, I915_GTT_MIN_ALIGNMENT); size = round_up(plane_config->base + plane_config->size, mem->min_page_size); size -= base; @@ -108,14 +167,19 @@ initial_plane_vma(struct drm_i915_private *i915, */ if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) && mem == i915->mm.stolen_region && - size * 2 > i915->dsm.usable_size) + size * 2 > i915->dsm.usable_size) { + drm_dbg_kms(&i915->drm, "Initial FB size exceeds half of stolen, discarding\n"); return NULL; + } obj = i915_gem_object_create_region_at(mem, phys_base, size, I915_BO_ALLOC_USER | I915_BO_PREALLOC); - if (IS_ERR(obj)) + if (IS_ERR(obj)) { + drm_dbg_kms(&i915->drm, "Failed to preallocate initial FB in %s\n", + mem->region.name); return NULL; + } /* * Mark it WT ahead of time to avoid changing the @@ -139,23 +203,66 @@ initial_plane_vma(struct drm_i915_private *i915, goto err_obj; } + /* + * MTL GOP likes to place the framebuffer high up in ggtt, + * which can cause problems for ggtt_reserve_guc_top(). + * Try to pin it to a low ggtt address instead to avoid that. + */ + base = 0; + + if (base != plane_config->base) { + struct i915_ggtt *ggtt = to_gt(i915)->ggtt; + int ret; + + /* + * Make sure the original and new locations + * can't overlap. That would corrupt the original + * PTEs which are still being used for scanout. + */ + ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &orig_mm, + size, plane_config->base, + I915_COLOR_UNEVICTABLE, PIN_NOEVICT); + if (ret) + goto err_obj; + } + vma = i915_vma_instance(obj, &to_gt(i915)->ggtt->vm, NULL); if (IS_ERR(vma)) goto err_obj; +retry: pinctl = PIN_GLOBAL | PIN_OFFSET_FIXED | base; - if (HAS_GMCH(i915)) + if (!i915_gem_object_is_lmem(obj)) pinctl |= PIN_MAPPABLE; - if (i915_vma_pin(vma, 0, 0, pinctl)) + if (i915_vma_pin(vma, 0, 0, pinctl)) { + if (drm_mm_node_allocated(&orig_mm)) { + drm_mm_remove_node(&orig_mm); + /* + * Try again, but this time pin + * it to its original location. + */ + base = plane_config->base; + goto retry; + } goto err_obj; + } if (i915_gem_object_is_tiled(obj) && !i915_vma_is_map_and_fenceable(vma)) goto err_obj; + if (drm_mm_node_allocated(&orig_mm)) + drm_mm_remove_node(&orig_mm); + + drm_dbg_kms(&i915->drm, + "Initial plane fb bound to 0x%x in the ggtt (original 0x%x)\n", + i915_ggtt_offset(vma), plane_config->base); + return vma; err_obj: + if (drm_mm_node_allocated(&orig_mm)) + drm_mm_remove_node(&orig_mm); i915_gem_object_put(obj); return NULL; } @@ -210,10 +317,11 @@ err_vma: static void intel_find_initial_plane_obj(struct intel_crtc *crtc, - struct intel_initial_plane_config *plane_config) + struct intel_initial_plane_config plane_configs[]) { - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_initial_plane_config *plane_config = + &plane_configs[crtc->pipe]; struct intel_plane *plane = to_intel_plane(crtc->base.primary); struct intel_plane_state *plane_state = @@ -239,7 +347,7 @@ intel_find_initial_plane_obj(struct intel_crtc *crtc, * Failed to alloc the obj, check to see if we should share * an fb with another CRTC instead */ - if (intel_reuse_initial_plane_obj(dev_priv, plane_config, &fb, &vma)) + if (intel_reuse_initial_plane_obj(crtc, plane_configs, &fb, &vma)) goto valid_fb; /* @@ -302,25 +410,36 @@ static void plane_config_fini(struct intel_initial_plane_config *plane_config) i915_vma_put(plane_config->vma); } -void intel_crtc_initial_plane_config(struct intel_crtc *crtc) +void intel_initial_plane_config(struct drm_i915_private *i915) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_initial_plane_config plane_config = {}; + struct intel_initial_plane_config plane_configs[I915_MAX_PIPES] = {}; + struct intel_crtc *crtc; - /* - * Note that reserving the BIOS fb up front prevents us - * from stuffing other stolen allocations like the ring - * on top. This prevents some ugliness at boot time, and - * can even allow for smooth boot transitions if the BIOS - * fb is large enough for the active pipe configuration. - */ - dev_priv->display.funcs.display->get_initial_plane_config(crtc, &plane_config); + for_each_intel_crtc(&i915->drm, crtc) { + struct intel_initial_plane_config *plane_config = + &plane_configs[crtc->pipe]; - /* - * If the fb is shared between multiple heads, we'll - * just get the first one. - */ - intel_find_initial_plane_obj(crtc, &plane_config); + if (!to_intel_crtc_state(crtc->base.state)->uapi.active) + continue; + + /* + * Note that reserving the BIOS fb up front prevents us + * from stuffing other stolen allocations like the ring + * on top. This prevents some ugliness at boot time, and + * can even allow for smooth boot transitions if the BIOS + * fb is large enough for the active pipe configuration. + */ + i915->display.funcs.display->get_initial_plane_config(crtc, plane_config); - plane_config_fini(&plane_config); + /* + * If the fb is shared between multiple heads, we'll + * just get the first one. + */ + intel_find_initial_plane_obj(crtc, plane_configs); + + if (i915->display.funcs.display->fixup_initial_plane_config(crtc, plane_config)) + intel_crtc_wait_for_next_vblank(crtc); + + plane_config_fini(plane_config); + } } diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.h b/drivers/gpu/drm/i915/display/intel_plane_initial.h index c7e35ab3182b65f2ceb69b3572410699edf68e96..64ab95239cd451c0e60cc3faa8ac46f6ffa345a5 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.h +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.h @@ -6,8 +6,8 @@ #ifndef __INTEL_PLANE_INITIAL_H__ #define __INTEL_PLANE_INITIAL_H__ -struct intel_crtc; +struct drm_i915_private; -void intel_crtc_initial_plane_config(struct intel_crtc *crtc); +void intel_initial_plane_config(struct drm_i915_private *i915); #endif diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index a8fa3a20990e76d4571e40e42f8b775094cba918..2d65a538f83e4e9422f3e4e4419c9f95235d0831 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -366,7 +366,7 @@ static bool intel_pps_is_valid(struct intel_dp *intel_dp) if (intel_dp->pps.pps_idx == 1 && INTEL_PCH_TYPE(i915) >= PCH_ICP && - INTEL_PCH_TYPE(i915) < PCH_MTP) + INTEL_PCH_TYPE(i915) <= PCH_ADP) return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT; return true; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 8f702c3fc62d483e6ba92d4d02537576975441ae..72cadad09db5f1ecacf87976a7ba6e0e6e18590f 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -173,6 +173,12 @@ * irrelevant for normal operation. */ +#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \ + (intel_dp)->psr.source_support) + +#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)->psr.sink_panel_replay_support && \ + (intel_dp)->psr.source_panel_replay_support) + bool intel_encoder_can_psr(struct intel_encoder *encoder) { if (intel_encoder_is_dp(encoder) || encoder->type == INTEL_OUTPUT_DP_MST) @@ -528,7 +534,7 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp) intel_dp_get_sink_sync_latency(intel_dp); if (DISPLAY_VER(i915) >= 9 && - intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) { + intel_dp->psr_dpcd[0] >= DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) { bool y_req = intel_dp->psr_dpcd[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED; bool alpm = intel_dp_get_alpm_status(intel_dp); @@ -560,11 +566,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) if (intel_dp->psr_dpcd[0]) _psr_init_dpcd(intel_dp); - if (intel_dp->psr.sink_psr2_support) { - intel_dp->psr.colorimetry_support = - intel_dp_get_colorimetry_status(intel_dp); + if (intel_dp->psr.sink_psr2_support) intel_dp_get_su_granularity(intel_dp); - } } static void hsw_psr_setup_aux(struct intel_dp *intel_dp) @@ -604,6 +607,18 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) aux_ctl); } +static bool psr2_su_region_et_valid(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + if (DISPLAY_VER(i915) >= 20 && + intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_ET_SUPPORTED && + !(intel_dp->psr.debug & I915_PSR_DEBUG_SU_REGION_ET_DISABLE)) + return true; + + return false; +} + static void intel_psr_enable_sink(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -619,6 +634,8 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE); dpcd_val |= DP_PSR_ENABLE_PSR2 | DP_PSR_IRQ_HPD_WITH_CRC_ERRORS; + if (psr2_su_region_et_valid(intel_dp)) + dpcd_val |= DP_PSR_ENABLE_SU_REGION_ET; } else { if (intel_dp->psr.link_standby) dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE; @@ -762,8 +779,8 @@ static u32 intel_psr2_get_tp_time(struct intel_dp *intel_dp) static int psr2_block_count_lines(struct intel_dp *intel_dp) { - return intel_dp->psr.io_wake_lines < 9 && - intel_dp->psr.fast_wake_lines < 9 ? 8 : 12; + return intel_dp->psr.alpm_parameters.io_wake_lines < 9 && + intel_dp->psr.alpm_parameters.fast_wake_lines < 9 ? 8 : 12; } static int psr2_block_count(struct intel_dp *intel_dp) @@ -800,6 +817,7 @@ static void dg2_activate_panel_replay(struct intel_dp *intel_dp) static void hsw_activate_psr2(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_psr *psr = &intel_dp->psr; enum transcoder cpu_transcoder = intel_dp->psr.transcoder; u32 val = EDP_PSR2_ENABLE; u32 psr_val = 0; @@ -841,17 +859,18 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) */ int tmp; - tmp = map[intel_dp->psr.io_wake_lines - TGL_EDP_PSR2_IO_BUFFER_WAKE_MIN_LINES]; + tmp = map[psr->alpm_parameters.io_wake_lines - + TGL_EDP_PSR2_IO_BUFFER_WAKE_MIN_LINES]; val |= TGL_EDP_PSR2_IO_BUFFER_WAKE(tmp + TGL_EDP_PSR2_IO_BUFFER_WAKE_MIN_LINES); - tmp = map[intel_dp->psr.fast_wake_lines - TGL_EDP_PSR2_FAST_WAKE_MIN_LINES]; + tmp = map[psr->alpm_parameters.fast_wake_lines - TGL_EDP_PSR2_FAST_WAKE_MIN_LINES]; val |= TGL_EDP_PSR2_FAST_WAKE(tmp + TGL_EDP_PSR2_FAST_WAKE_MIN_LINES); } else if (DISPLAY_VER(dev_priv) >= 12) { - val |= TGL_EDP_PSR2_IO_BUFFER_WAKE(intel_dp->psr.io_wake_lines); - val |= TGL_EDP_PSR2_FAST_WAKE(intel_dp->psr.fast_wake_lines); + val |= TGL_EDP_PSR2_IO_BUFFER_WAKE(psr->alpm_parameters.io_wake_lines); + val |= TGL_EDP_PSR2_FAST_WAKE(psr->alpm_parameters.fast_wake_lines); } else if (DISPLAY_VER(dev_priv) >= 9) { - val |= EDP_PSR2_IO_BUFFER_WAKE(intel_dp->psr.io_wake_lines); - val |= EDP_PSR2_FAST_WAKE(intel_dp->psr.fast_wake_lines); + val |= EDP_PSR2_IO_BUFFER_WAKE(psr->alpm_parameters.io_wake_lines); + val |= EDP_PSR2_FAST_WAKE(psr->alpm_parameters.fast_wake_lines); } if (intel_dp->psr.req_psr2_sdp_prior_scanline) @@ -869,6 +888,9 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(cpu_transcoder), 0); } + if (psr2_su_region_et_valid(intel_dp)) + val |= LNL_EDP_PSR2_SU_REGION_ET_ENABLE; + /* * PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is * recommending keep this bit unset while PSR2 is enabled. @@ -1031,6 +1053,9 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, return false; } + if (psr2_su_region_et_valid(intel_dp)) + crtc_state->enable_psr2_su_region_et = true; + return crtc_state->enable_psr2_sel_fetch = true; } @@ -1101,8 +1126,32 @@ static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_dp *intel_d return true; } -static bool _compute_psr2_wake_times(struct intel_dp *intel_dp, +static bool _lnl_compute_alpm_params(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int check_entry_lines; + + if (DISPLAY_VER(i915) < 20) + return true; + + /* ALPM Entry Check = 2 + CEILING( 5us /tline ) */ + check_entry_lines = 2 + + intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode, 5); + + if (check_entry_lines > 15) + return false; + + if (i915->display.params.psr_safest_params) + check_entry_lines = 15; + + intel_dp->psr.alpm_parameters.check_entry_lines = check_entry_lines; + + return true; +} + +static bool _compute_alpm_params(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); int io_wake_lines, io_wake_time, fast_wake_lines, fast_wake_time; @@ -1115,6 +1164,8 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp, * it is not enough -> use 45 us. */ fast_wake_time = 45; + + /* TODO: Check how we can use ALPM_CTL fast wake extended field */ max_wake_lines = 12; } else { io_wake_time = 50; @@ -1131,12 +1182,15 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp, fast_wake_lines > max_wake_lines) return false; + if (!_lnl_compute_alpm_params(intel_dp, crtc_state)) + return false; + if (i915->display.params.psr_safest_params) io_wake_lines = fast_wake_lines = max_wake_lines; /* According to Bspec lower limit should be set as 7 lines. */ - intel_dp->psr.io_wake_lines = max(io_wake_lines, 7); - intel_dp->psr.fast_wake_lines = max(fast_wake_lines, 7); + intel_dp->psr.alpm_parameters.io_wake_lines = max(io_wake_lines, 7); + intel_dp->psr.alpm_parameters.fast_wake_lines = max(fast_wake_lines, 7); return true; } @@ -1268,7 +1322,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } - if (!_compute_psr2_wake_times(intel_dp, crtc_state)) { + if (!_compute_alpm_params(intel_dp, crtc_state)) { drm_dbg_kms(&dev_priv->drm, "PSR2 not enabled, Unable to use long enough wake times\n"); return false; @@ -1377,10 +1431,6 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, return; crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); - - crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); - intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state, - &crtc_state->psr_vsc); } void intel_psr_get_config(struct intel_encoder *encoder, @@ -1504,6 +1554,21 @@ static void wm_optimization_wa(struct intel_dp *intel_dp, wa_16013835468_bit_get(intel_dp), 0); } +static void lnl_alpm_configure(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + enum transcoder cpu_transcoder = intel_dp->psr.transcoder; + struct intel_psr *psr = &intel_dp->psr; + + if (DISPLAY_VER(dev_priv) < 20) + return; + + intel_de_write(dev_priv, ALPM_CTL(cpu_transcoder), + ALPM_CTL_EXTENDED_FAST_WAKE_ENABLE | + ALPM_CTL_ALPM_ENTRY_CHECK(psr->alpm_parameters.check_entry_lines) | + ALPM_CTL_EXTENDED_FAST_WAKE_TIME(psr->alpm_parameters.fast_wake_lines)); +} + static void intel_psr_enable_source(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { @@ -1525,8 +1590,18 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, * can rely on frontbuffer tracking. */ mask = EDP_PSR_DEBUG_MASK_MEMUP | - EDP_PSR_DEBUG_MASK_HPD | - EDP_PSR_DEBUG_MASK_LPSP; + EDP_PSR_DEBUG_MASK_HPD; + + /* + * For some unknown reason on HSW non-ULT (or at least on + * Dell Latitude E6540) external displays start to flicker + * when PSR is enabled on the eDP. SR/PC6 residency is much + * higher than should be possible with an external display. + * As a workaround leave LPSP unmasked to prevent PSR entry + * when external displays are active. + */ + if (DISPLAY_VER(dev_priv) >= 8 || IS_HASWELL_ULT(dev_priv)) + mask |= EDP_PSR_DEBUG_MASK_LPSP; if (DISPLAY_VER(dev_priv) < 20) mask |= EDP_PSR_DEBUG_MASK_MAX_SLEEP; @@ -1559,6 +1634,8 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, intel_dp->psr.psr2_sel_fetch_enabled ? IGNORE_PSR2_HW_TRACKING : 0); + lnl_alpm_configure(intel_dp); + /* * Wa_16013835468 * Wa_14015648006 @@ -1624,7 +1701,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port); - struct intel_encoder *encoder = &dig_port->base; u32 val; drm_WARN_ON(&dev_priv->drm, intel_dp->psr.enabled); @@ -1652,7 +1728,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", intel_dp->psr.psr2_enabled ? "2" : "1"); - intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc); intel_snps_phy_update_psr_power_state(dev_priv, phy, true); intel_psr_enable_sink(intel_dp); intel_psr_enable_source(intel_dp, crtc_state); @@ -1941,7 +2016,7 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st } static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, - struct drm_rect *clip, bool full_update) + bool full_update) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -1956,17 +2031,21 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, goto exit; } - if (clip->y1 == -1) + if (crtc_state->psr2_su_area.y1 == -1) goto exit; if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14) { - val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1); - val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 - 1); + val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(crtc_state->psr2_su_area.y1); + val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(crtc_state->psr2_su_area.y2 - 1); } else { - drm_WARN_ON(crtc_state->uapi.crtc->dev, clip->y1 % 4 || clip->y2 % 4); + drm_WARN_ON(crtc_state->uapi.crtc->dev, + crtc_state->psr2_su_area.y1 % 4 || + crtc_state->psr2_su_area.y2 % 4); - val |= PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1 / 4 + 1); - val |= PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 / 4 + 1); + val |= PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR( + crtc_state->psr2_su_area.y1 / 4 + 1); + val |= PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR( + crtc_state->psr2_su_area.y2 / 4 + 1); } exit: crtc_state->psr2_man_track_ctl = val; @@ -1992,8 +2071,7 @@ static void clip_area_update(struct drm_rect *overlap_damage_area, overlap_damage_area->y2 = damage_area->y2; } -static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *crtc_state, - struct drm_rect *pipe_clip) +static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; @@ -2006,9 +2084,32 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c else y_alignment = crtc_state->su_y_granularity; - pipe_clip->y1 -= pipe_clip->y1 % y_alignment; - if (pipe_clip->y2 % y_alignment) - pipe_clip->y2 = ((pipe_clip->y2 / y_alignment) + 1) * y_alignment; + crtc_state->psr2_su_area.y1 -= crtc_state->psr2_su_area.y1 % y_alignment; + if (crtc_state->psr2_su_area.y2 % y_alignment) + crtc_state->psr2_su_area.y2 = ((crtc_state->psr2_su_area.y2 / + y_alignment) + 1) * y_alignment; +} + +/* + * When early transport is in use we need to extend SU area to cover + * cursor fully when cursor is in SU area. + */ +static void +intel_psr2_sel_fetch_et_alignment(struct intel_crtc_state *crtc_state, + struct intel_plane_state *cursor_state) +{ + struct drm_rect inter; + + if (!crtc_state->enable_psr2_su_region_et || + !cursor_state->uapi.visible) + return; + + inter = crtc_state->psr2_su_area; + if (!drm_rect_intersect(&inter, &cursor_state->uapi.dst)) + return; + + clip_area_update(&crtc_state->psr2_su_area, &cursor_state->uapi.dst, + &crtc_state->pipe_src); } /* @@ -2051,8 +2152,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, { struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct drm_rect pipe_clip = { .x1 = 0, .y1 = -1, .x2 = INT_MAX, .y2 = -1 }; - struct intel_plane_state *new_plane_state, *old_plane_state; + struct intel_plane_state *new_plane_state, *old_plane_state, + *cursor_plane_state = NULL; struct intel_plane *plane; bool full_update = false; int i, ret; @@ -2065,6 +2166,11 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, goto skip_sel_fetch_set_loop; } + crtc_state->psr2_su_area.x1 = 0; + crtc_state->psr2_su_area.y1 = -1; + crtc_state->psr2_su_area.x2 = INT_MAX; + crtc_state->psr2_su_area.y2 = -1; + /* * Calculate minimal selective fetch area of each plane and calculate * the pipe damaged area. @@ -2099,14 +2205,14 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if (old_plane_state->uapi.visible) { damaged_area.y1 = old_plane_state->uapi.dst.y1; damaged_area.y2 = old_plane_state->uapi.dst.y2; - clip_area_update(&pipe_clip, &damaged_area, + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); } if (new_plane_state->uapi.visible) { damaged_area.y1 = new_plane_state->uapi.dst.y1; damaged_area.y2 = new_plane_state->uapi.dst.y2; - clip_area_update(&pipe_clip, &damaged_area, + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); } continue; @@ -2114,7 +2220,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, /* If alpha changed mark the whole plane area as damaged */ damaged_area.y1 = new_plane_state->uapi.dst.y1; damaged_area.y2 = new_plane_state->uapi.dst.y2; - clip_area_update(&pipe_clip, &damaged_area, + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); continue; } @@ -2131,7 +2237,14 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, damaged_area.x1 += new_plane_state->uapi.dst.x1 - src.x1; damaged_area.x2 += new_plane_state->uapi.dst.x1 - src.x1; - clip_area_update(&pipe_clip, &damaged_area, &crtc_state->pipe_src); + clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src); + + /* + * Cursor plane new state is stored to adjust su area to cover + * cursor are fully. + */ + if (plane->id == PLANE_CURSOR) + cursor_plane_state = new_plane_state; } /* @@ -2140,7 +2253,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, * should identify cases where this happens and fix the area * calculation for those. */ - if (pipe_clip.y1 == -1) { + if (crtc_state->psr2_su_area.y1 == -1) { drm_info_once(&dev_priv->drm, "Selective fetch area calculation failed in pipe %c\n", pipe_name(crtc->pipe)); @@ -2154,13 +2267,17 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, if ((IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0) || IS_ALDERLAKE_P(dev_priv) || IS_TIGERLAKE(dev_priv)) && crtc_state->splitter.enable) - pipe_clip.y1 = 0; + crtc_state->psr2_su_area.y1 = 0; ret = drm_atomic_add_affected_planes(&state->base, &crtc->base); if (ret) return ret; - intel_psr2_sel_fetch_pipe_alignment(crtc_state, &pipe_clip); + /* Adjust su area to cover cursor fully as necessary */ + if (cursor_plane_state) + intel_psr2_sel_fetch_et_alignment(crtc_state, cursor_plane_state); + + intel_psr2_sel_fetch_pipe_alignment(crtc_state); /* * Now that we have the pipe damaged area check if it intersect with @@ -2175,7 +2292,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, !new_plane_state->uapi.visible) continue; - inter = pipe_clip; + inter = crtc_state->psr2_su_area; sel_fetch_area = &new_plane_state->psr2_sel_fetch_area; if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) { sel_fetch_area->y1 = -1; @@ -2220,7 +2337,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, } skip_sel_fetch_set_loop: - psr2_man_trk_ctl_calc(crtc_state, &pipe_clip, full_update); + psr2_man_trk_ctl_calc(crtc_state, full_update); return 0; } @@ -2789,6 +2906,9 @@ void intel_psr_init(struct intel_dp *intel_dp) else intel_dp->psr.source_support = true; + /* Disable early transport for now */ + intel_dp->psr.debug |= I915_PSR_DEBUG_SU_REGION_ET_DISABLE; + /* Set link_standby x link_off defaults */ if (DISPLAY_VER(dev_priv) < 12) /* For new platforms up to TGL let's respect VBT back again */ diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 143e0595c09773bf67f66c95582a6c896625fb98..cde781df84d5ec207a038bde72103df0426d2dd4 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -21,12 +21,6 @@ struct intel_encoder; struct intel_plane; struct intel_plane_state; -#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \ - (intel_dp)->psr.source_support) - -#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)->psr.sink_panel_replay_support && \ - (intel_dp)->psr.source_panel_replay_support) - bool intel_encoder_can_psr(struct intel_encoder *encoder); void intel_psr_init_dpcd(struct intel_dp *intel_dp); void intel_psr_pre_plane_update(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h index efe4306b37e0c254368348d4e455571602c0281a..8427a736f639960a9d384ab204de1284e0ec1b86 100644 --- a/drivers/gpu/drm/i915/display/intel_psr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h @@ -159,6 +159,7 @@ #define TGL_EDP_PSR2_BLOCK_COUNT_MASK REG_BIT(28) #define TGL_EDP_PSR2_BLOCK_COUNT_NUM_2 REG_FIELD_PREP(TGL_EDP_PSR2_BLOCK_COUNT_MASK, 0) #define TGL_EDP_PSR2_BLOCK_COUNT_NUM_3 REG_FIELD_PREP(TGL_EDP_PSR2_BLOCK_COUNT_MASK, 1) +#define LNL_EDP_PSR2_SU_REGION_ET_ENABLE REG_BIT(27) #define EDP_Y_COORDINATE_ENABLE REG_BIT(25) /* display 10, 11 and 12 */ #define EDP_PSR2_SU_SDP_SCANLINE REG_BIT(25) /* display 13+ */ #define EDP_MAX_SU_DISABLE_TIME_MASK REG_GENMASK(24, 20) @@ -245,6 +246,11 @@ #define ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME REG_BIT(14) #define ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME REG_BIT(13) +/* PSR2 Early transport */ +#define _PIPE_SRCSZ_ERLY_TPT_A 0x70074 + +#define PIPE_SRCSZ_ERLY_TPT(trans) _MMIO_TRANS2(trans, _PIPE_SRCSZ_ERLY_TPT_A) + #define _SEL_FETCH_PLANE_BASE_1_A 0x70890 #define _SEL_FETCH_PLANE_BASE_2_A 0x708B0 #define _SEL_FETCH_PLANE_BASE_3_A 0x708D0 @@ -290,4 +296,61 @@ _SEL_FETCH_PLANE_OFFSET_1_A - \ _SEL_FETCH_PLANE_BASE_1_A) +#define _ALPM_CTL_A 0x60950 +#define ALPM_CTL(tran) _MMIO_TRANS2(tran, _ALPM_CTL_A) +#define ALPM_CTL_ALPM_ENABLE REG_BIT(31) +#define ALPM_CTL_ALPM_AUX_LESS_ENABLE REG_BIT(30) +#define ALPM_CTL_LOBF_ENABLE REG_BIT(29) +#define ALPM_CTL_EXTENDED_FAST_WAKE_ENABLE REG_BIT(28) +#define ALPM_CTL_KEEP_FEC_ENABLE_FOR_AUX_WAKE_SLEEP REG_BIT(27) +#define ALPM_CTL_RESTORE_OCCURED REG_BIT(26) +#define ALPM_CTL_RESTORE_TO_SLEEP REG_BIT(25) +#define ALPM_CTL_RESTORE_TO_DEEP_SLEEP REG_BIT(24) +#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK REG_GENMASK(23, 21) +#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_50_SYMBOLS REG_FIELD_PREP(ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK, 0) +#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_128_SYMBOLS REG_FIELD_PREP(ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK, 1) +#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_256_SYMBOLS REG_FIELD_PREP(ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK, 2) +#define ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_512_SYMBOLS REG_FIELD_PREP(ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_MASK, 3) +#define ALPM_CTL_AUX_WAKE_SLEEP_HOLD_ENABLE REG_BIT(20) +#define ALPM_CTL_ALPM_ENTRY_CHECK_MASK REG_GENMASK(19, 16) +#define ALPM_CTL_ALPM_ENTRY_CHECK(val) REG_FIELD_PREP(ALPM_CTL_ALPM_ENTRY_CHECK_MASK, val) +#define ALPM_CTL_EXTENDED_FAST_WAKE_TIME_MASK REG_GENMASK(13, 8) +#define ALPM_CTL_EXTENDED_FAST_WAKE_MIN_LINES 5 +#define ALPM_CTL_EXTENDED_FAST_WAKE_TIME(lines) REG_FIELD_PREP(ALPM_CTL_EXTENDED_FAST_WAKE_TIME_MASK, (lines) - ALPM_CTL_EXTENDED_FAST_WAKE_MIN_LINES) +#define ALPM_CTL_AUX_LESS_WAKE_TIME_MASK REG_GENMASK(5, 0) +#define ALPM_CTL_AUX_LESS_WAKE_TIME(val) REG_FIELD_PREP(ALPM_CTL_AUX_LESS_WAKE_TIME_MASK, val) + +#define _ALPM_CTL2_A 0x60954 +#define ALPM_CTL2(tran) _MMIO_TRANS2(tran, _ALPM_CTL2_A) +#define ALPM_CTL2_SWITCH_TO_ACTIVE_LATENCY_MASK REG_GENMASK(28, 24) +#define ALPM_CTL2_SWITCH_TO_ACTIVE_LATENCY(val) REG_FIELD_PREP(ALPM_CTL2_SWITCH_TO_ACTIVE_LATENCY_MASK, val) +#define ALPM_CTL2_AUX_LESS_WAKE_TIME_EXTENSION_MASK REG_GENMASK(19, 16) +#define ALPM_CTL2_AUX_LESS_WAKE_TIME_EXTENSION(val) REG_FIELD_PREP(ALPM_CTL2_AUX_LESS_WAKE_TIME_EXTENSION_MASK, val) +#define ALPM_CTL2_NUMBER_OF_LTTPR_MASK REG_GENMASK(15, 12) +#define ALPM_CTL2_NUMBER_OF_LTTPR(val) REG_FIELD_PREP(ALPM_CTL2_NUMBER_OF_LTTPR_MASK, val) +#define ALPM_CTL2_LTTPR_AUX_LESS_SLEEP_HOLD_TIME_MASK REG_GENMASK(10, 8) +#define ALPM_CTL2_LTTPR_AUX_LESS_SLEEP_HOLD_TIME(val) REG_FIELD_PREP(ALPM_CTL2_LTTPR_AUX_LESS_SLEEP_HOLD_TIME_MASK, val) +#define ALPM_CTL2_FEC_DECODE_EN_POSITION_AFTER_WAKE_SR REG_BIT(4) +#define ALPM_CTL2_NUMBER_AUX_LESS_ML_PHY_SLEEP_SEQUENCES_MASK REG_GENMASK(2, 0) +#define ALPM_CTL2_NUMBER_AUX_LESS_ML_PHY_SLEEP_SEQUENCES(val) REG_FIELD_PREP(ALPM_CTL2_NUMBER_AUX_LESS_ML_PHY_SLEEP_SEQUENCES_MASK, val) + +#define _PORT_ALPM_CTL_A 0x16fa2c +#define PORT_ALPM_CTL(tran) _MMIO_TRANS2(tran, _PORT_ALPM_CTL_A) +#define PORT_ALPM_CTL_ALPM_AUX_LESS_ENABLE REG_BIT(31) +#define PORT_ALPM_CTL_MAX_PHY_SWING_SETUP_MASK REG_GENMASK(23, 20) +#define PORT_ALPM_CTL_MAX_PHY_SWING_SETUP(val) REG_FIELD_PREP(PORT_ALPM_CTL_MAX_PHY_SWING_SETUP_MASK, val) +#define PORT_ALPM_CTL_MAX_PHY_SWING_HOLD_MASK REG_GENMASK(19, 16) +#define PORT_ALPM_CTL_MAX_PHY_SWING_HOLD(val) REG_FIELD_PREP(PORT_ALPM_CTL_MAX_PHY_SWING_HOLD_MASK, val) +#define PORT_ALPM_CTL_SILENCE_PERIOD_MASK REG_GENMASK(7, 0) +#define PORT_ALPM_CTL_SILENCE_PERIOD(val) REG_FIELD_PREP(PORT_ALPM_CTL_SILENCE_PERIOD_MASK, val) + +#define _PORT_ALPM_LFPS_CTL_A 0x16fa30 +#define PORT_ALPM_LFPS_CTL(tran) _MMIO_TRANS2(tran, _PORT_ALPM_LFPS_CTL_A) +#define PORT_ALPM_LFPS_CTL_LFPS_START_POLARITY REG_BIT(31) +#define PORT_ALPM_LFPS_CTL_LFPS_CYCLE_COUNT_MASK REG_GENMASK(27, 24) +#define ALPM_CTL_EXTENDED_FAST_WAKE_MIN_LINES 5 +#define ALPM_CTL_EXTENDED_FAST_WAKE_TIME(lines) REG_FIELD_PREP(ALPM_CTL_EXTENDED_FAST_WAKE_TIME_MASK, (lines) - ALPM_CTL_EXTENDED_FAST_WAKE_MIN_LINES) +#define ALPM_CTL_AUX_LESS_WAKE_TIME_MASK REG_GENMASK(5, 0) +#define ALPM_CTL_AUX_LESS_WAKE_TIME(val) REG_FIELD_PREP(ALPM_CTL_AUX_LESS_WAKE_TIME_MASK, val) + #endif /* __INTEL_PSR_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index acc6b6804105102389dc26c3fefce80444d0adad..2571ef5a1b211221f7a21afc442a0c9b96dbdc7f 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -44,6 +44,7 @@ #include "intel_connector.h" #include "intel_crtc.h" #include "intel_de.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fifo_underrun.h" @@ -2140,6 +2141,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->status; + if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo_connector->output_flag)) return connector_status_unknown; @@ -2805,6 +2809,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type) } else { intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; } + intel_connector->base.polled = intel_connector->polled; encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; @@ -2880,6 +2885,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type) intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->base.polled = intel_connector->polled; encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index dcf05e00e5052420821d939aa0c8835cb84a76b2..6b374d481cd9e7259294202e28b377d1ba76a054 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -122,6 +122,15 @@ bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port) return intel_tc_port_in_mode(dig_port, TC_PORT_LEGACY); } +bool intel_tc_port_handles_hpd_glitches(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); + struct intel_tc_port *tc = to_tc_port(dig_port); + + return intel_phy_is_tc(i915, phy) && !tc->legacy_port; +} + /* * The display power domains used for TC ports depending on the * platform and TC mode (legacy, DP-alt, TBT): @@ -986,10 +995,11 @@ xelpdp_tc_phy_tcss_power_is_enabled(struct intel_tc_port *tc) { struct drm_i915_private *i915 = tc_to_i915(tc); enum port port = tc->dig_port->base.port; + i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port); assert_tc_cold_blocked(tc); - return intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)) & XELPDP_TCSS_POWER_STATE; + return intel_de_read(i915, reg) & XELPDP_TCSS_POWER_STATE; } static bool @@ -1012,16 +1022,17 @@ static void __xelpdp_tc_phy_enable_tcss_power(struct intel_tc_port *tc, bool ena { struct drm_i915_private *i915 = tc_to_i915(tc); enum port port = tc->dig_port->base.port; + i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port); u32 val; assert_tc_cold_blocked(tc); - val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)); + val = intel_de_read(i915, reg); if (enable) val |= XELPDP_TCSS_POWER_REQUEST; else val &= ~XELPDP_TCSS_POWER_REQUEST; - intel_de_write(i915, XELPDP_PORT_BUF_CTL1(port), val); + intel_de_write(i915, reg, val); } static bool xelpdp_tc_phy_enable_tcss_power(struct intel_tc_port *tc, bool enable) @@ -1055,26 +1066,28 @@ static void xelpdp_tc_phy_take_ownership(struct intel_tc_port *tc, bool take) { struct drm_i915_private *i915 = tc_to_i915(tc); enum port port = tc->dig_port->base.port; + i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port); u32 val; assert_tc_cold_blocked(tc); - val = intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)); + val = intel_de_read(i915, reg); if (take) val |= XELPDP_TC_PHY_OWNERSHIP; else val &= ~XELPDP_TC_PHY_OWNERSHIP; - intel_de_write(i915, XELPDP_PORT_BUF_CTL1(port), val); + intel_de_write(i915, reg, val); } static bool xelpdp_tc_phy_is_owned(struct intel_tc_port *tc) { struct drm_i915_private *i915 = tc_to_i915(tc); enum port port = tc->dig_port->base.port; + i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port); assert_tc_cold_blocked(tc); - return intel_de_read(i915, XELPDP_PORT_BUF_CTL1(port)) & XELPDP_TC_PHY_OWNERSHIP; + return intel_de_read(i915, reg) & XELPDP_TC_PHY_OWNERSHIP; } static void xelpdp_tc_phy_get_hw_state(struct intel_tc_port *tc) @@ -1590,7 +1603,7 @@ void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port, * connected ports are usable, and avoids exposing to the users objects they * can't really use. */ -bool intel_tc_port_connected_locked(struct intel_encoder *encoder) +bool intel_tc_port_connected(struct intel_encoder *encoder) { struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); @@ -1605,19 +1618,6 @@ bool intel_tc_port_connected_locked(struct intel_encoder *encoder) return tc_phy_hpd_live_status(tc) & mask; } -bool intel_tc_port_connected(struct intel_encoder *encoder) -{ - struct intel_digital_port *dig_port = enc_to_dig_port(encoder); - struct intel_tc_port *tc = to_tc_port(dig_port); - bool is_connected; - - mutex_lock(&tc->lock); - is_connected = intel_tc_port_connected_locked(encoder); - mutex_unlock(&tc->lock); - - return is_connected; -} - static bool __intel_tc_port_link_needs_reset(struct intel_tc_port *tc) { bool ret; diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 80a61e52850ee1b7dea26852a19e34b4fb0a61f5..26c4265368c1a5e95739274a33e42663823028bf 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -15,9 +15,9 @@ struct intel_encoder; bool intel_tc_port_in_tbt_alt_mode(struct intel_digital_port *dig_port); bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port); bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port); +bool intel_tc_port_handles_hpd_glitches(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_encoder *encoder); -bool intel_tc_port_connected_locked(struct intel_encoder *encoder); u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port); int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port); diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index d4386cb3569e0991bc3c0c78a4415d77a7bc1998..a96bcfcf90a3d3191297740e9c98981eb180574a 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -40,6 +40,7 @@ #include "intel_crtc.h" #include "intel_de.h" #include "intel_display_irq.h" +#include "intel_display_driver.h" #include "intel_display_types.h" #include "intel_dpll.h" #include "intel_hotplug.h" @@ -1327,7 +1328,7 @@ intel_tv_compute_config(struct intel_encoder *encoder, * the active portion. Hence following this formula seems * more trouble that it's worth. * - * if (GRAPHICS_VER(dev_priv) == 4) { + * if (DISPLAY_VER(dev_priv) == 4) { * num = cdclk * (tv_mode->oversample >> !tv_mode->progressive); * den = tv_mode->clock; * } else { @@ -1723,6 +1724,9 @@ intel_tv_detect(struct drm_connector *connector, if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_display_driver_check_access(i915)) + return connector->status; + if (force) { struct drm_atomic_state *state; @@ -1990,6 +1994,7 @@ intel_tv_init(struct drm_i915_private *dev_priv) * More recent chipsets favour HDMI rather than integrated S-Video. */ intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->base.polled = intel_connector->polled; drm_connector_init(&dev_priv->drm, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index fe256bf7b485b99ab4228effe330d2d12729a9d1..baf7354cb6e2c472d89180e0ad3e9f2539904699 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -5,6 +5,7 @@ #include "i915_drv.h" #include "i915_reg.h" +#include "intel_crtc.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_vblank.h" @@ -581,3 +582,132 @@ void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state, intel_vblank_section_exit(i915); spin_unlock_irqrestore(&i915->drm.vblank_time_lock, irqflags); } + +static int intel_mode_vblank_start(const struct drm_display_mode *mode) +{ + int vblank_start = mode->crtc_vblank_start; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vblank_start = DIV_ROUND_UP(vblank_start, 2); + + return vblank_start; +} + +void intel_vblank_evade_init(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state, + struct intel_vblank_evade_ctx *evade) +{ + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + const struct intel_crtc_state *crtc_state; + const struct drm_display_mode *adjusted_mode; + + evade->crtc = crtc; + + evade->need_vlv_dsi_wa = (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) && + intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); + + /* + * During fastsets/etc. the transcoder is still + * running with the old timings at this point. + * + * TODO: maybe just use the active timings here? + */ + if (intel_crtc_needs_modeset(new_crtc_state)) + crtc_state = new_crtc_state; + else + crtc_state = old_crtc_state; + + adjusted_mode = &crtc_state->hw.adjusted_mode; + + if (crtc->mode_flags & I915_MODE_FLAG_VRR) { + /* timing changes should happen with VRR disabled */ + drm_WARN_ON(crtc->base.dev, intel_crtc_needs_modeset(new_crtc_state) || + new_crtc_state->update_m_n || new_crtc_state->update_lrr); + + if (intel_vrr_is_push_sent(crtc_state)) + evade->vblank_start = intel_vrr_vmin_vblank_start(crtc_state); + else + evade->vblank_start = intel_vrr_vmax_vblank_start(crtc_state); + } else { + evade->vblank_start = intel_mode_vblank_start(adjusted_mode); + } + + /* FIXME needs to be calibrated sensibly */ + evade->min = evade->vblank_start - intel_usecs_to_scanlines(adjusted_mode, + VBLANK_EVASION_TIME_US); + evade->max = evade->vblank_start - 1; + + /* + * M/N and TRANS_VTOTAL are double buffered on the transcoder's + * undelayed vblank, so with seamless M/N and LRR we must evade + * both vblanks. + * + * DSB execution waits for the transcoder's undelayed vblank, + * hence we must kick off the commit before that. + */ + if (new_crtc_state->dsb || new_crtc_state->update_m_n || new_crtc_state->update_lrr) + evade->min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; +} + +/* must be called with vblank interrupt already enabled! */ +int intel_vblank_evade(struct intel_vblank_evade_ctx *evade) +{ + struct intel_crtc *crtc = evade->crtc; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + long timeout = msecs_to_jiffies_timeout(1); + wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); + DEFINE_WAIT(wait); + int scanline; + + if (evade->min <= 0 || evade->max <= 0) + return 0; + + for (;;) { + /* + * prepare_to_wait() has a memory barrier, which guarantees + * other CPUs can see the task state update by the time we + * read the scanline. + */ + prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); + + scanline = intel_get_crtc_scanline(crtc); + if (scanline < evade->min || scanline > evade->max) + break; + + if (!timeout) { + drm_err(&i915->drm, + "Potential atomic update failure on pipe %c\n", + pipe_name(crtc->pipe)); + break; + } + + local_irq_enable(); + + timeout = schedule_timeout(timeout); + + local_irq_disable(); + } + + finish_wait(wq, &wait); + + /* + * On VLV/CHV DSI the scanline counter would appear to + * increment approx. 1/3 of a scanline before start of vblank. + * The registers still get latched at start of vblank however. + * This means we must not write any registers on the first + * line of vblank (since not the whole line is actually in + * vblank). And unfortunately we can't use the interrupt to + * wait here since it will fire too soon. We could use the + * frame start interrupt instead since it will fire after the + * critical scanline, but that would require more changes + * in the interrupt code. So for now we'll just do the nasty + * thing and poll for the bad scanline to pass us by. + * + * FIXME figure out if BXT+ DSI suffers from this as well + */ + while (evade->need_vlv_dsi_wa && scanline == evade->vblank_start) + scanline = intel_get_crtc_scanline(crtc); + + return scanline; +} diff --git a/drivers/gpu/drm/i915/display/intel_vblank.h b/drivers/gpu/drm/i915/display/intel_vblank.h index 17636f140c71dbaaac06547edd1724bdf2c369e9..ec6c3da3eeac0ec737cfd4ee130a5f19dc207080 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.h +++ b/drivers/gpu/drm/i915/display/intel_vblank.h @@ -13,6 +13,18 @@ struct drm_crtc; struct intel_crtc; struct intel_crtc_state; +struct intel_vblank_evade_ctx { + struct intel_crtc *crtc; + int min, max, vblank_start; + bool need_vlv_dsi_wa; +}; + +void intel_vblank_evade_init(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state, + struct intel_vblank_evade_ctx *evade); +/* must be called with vblank interrupt already enabled! */ +int intel_vblank_evade(struct intel_vblank_evade_ctx *evade); + u32 i915_get_vblank_counter(struct drm_crtc *crtc); u32 g4x_get_vblank_counter(struct drm_crtc *crtc); bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error, diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 511dc1544854f42aaa5176afca615b0a61ca4a4b..392d93e97bf8320db6706353ed6736a2ef82116e 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -2624,3 +2624,31 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, error: kfree(intel_fb); } + +bool skl_fixup_initial_plane_config(struct intel_crtc *crtc, + const struct intel_initial_plane_config *plane_config) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + const struct intel_plane_state *plane_state = + to_intel_plane_state(plane->base.state); + enum plane_id plane_id = plane->id; + enum pipe pipe = crtc->pipe; + u32 base; + + if (!plane_state->uapi.visible) + return false; + + base = intel_plane_ggtt_offset(plane_state); + + /* + * We may have moved the surface to a different + * part of ggtt, make the plane aware of that. + */ + if (plane_config->base == base) + return false; + + intel_de_write(i915, PLANE_SURF(pipe, plane_id), base); + + return true; +} diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h index be64c201f9b3e7ffea371546ae08d649a86d7aa3..e92e00c01b29a91890ae428c6514810303c00ff8 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.h +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h @@ -22,6 +22,8 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv, void skl_get_initial_plane_config(struct intel_crtc *crtc, struct intel_initial_plane_config *plane_config); +bool skl_fixup_initial_plane_config(struct intel_crtc *crtc, + const struct intel_initial_plane_config *plane_config); int skl_format_to_fourcc(int format, bool rgb_order, bool alpha); diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 56588d6e24ae6bc0c6118ae5511955e1576015af..614f319d754e9fe02970637a9ef6f7be45322022 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -443,12 +443,35 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state) for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + struct skl_pipe_wm *pipe_wm = &new_crtc_state->wm.skl.optimal; + new_bw_state = intel_atomic_get_bw_state(state); if (IS_ERR(new_bw_state)) return PTR_ERR(new_bw_state); old_bw_state = intel_atomic_get_old_bw_state(state); + /* + * We store use_sagv_wm in the crtc state rather than relying on + * that bw state since we have no convenient way to get at the + * latter from the plane commit hooks (especially in the legacy + * cursor case). + * + * drm_atomic_check_only() gets upset if we pull more crtcs + * into the state, so we have to calculate this based on the + * individual intel_crtc_can_enable_sagv() rather than + * the overall intel_can_enable_sagv(). Otherwise the + * crtcs not included in the commit would not switch to the + * SAGV watermarks when we are about to enable SAGV, and that + * would lead to underruns. This does mean extra power draw + * when only a subset of the crtcs are blocking SAGV as the + * other crtcs can't be allowed to use the more optimal + * normal (ie. non-SAGV) watermarks. + */ + pipe_wm->use_sagv_wm = !HAS_HW_SAGV_WM(i915) && + DISPLAY_VER(i915) >= 12 && + intel_crtc_can_enable_sagv(new_crtc_state); + if (intel_crtc_can_enable_sagv(new_crtc_state)) new_bw_state->pipe_sagv_reject &= ~BIT(crtc->pipe); else @@ -478,21 +501,6 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state) return ret; } - for_each_new_intel_crtc_in_state(state, crtc, - new_crtc_state, i) { - struct skl_pipe_wm *pipe_wm = &new_crtc_state->wm.skl.optimal; - - /* - * We store use_sagv_wm in the crtc state rather than relying on - * that bw state since we have no convenient way to get at the - * latter from the plane commit hooks (especially in the legacy - * cursor case) - */ - pipe_wm->use_sagv_wm = !HAS_HW_SAGV_WM(i915) && - DISPLAY_VER(i915) >= 12 && - intel_can_enable_sagv(i915, new_bw_state); - } - return 0; } @@ -1367,7 +1375,7 @@ skl_total_relative_data_rate(const struct intel_crtc_state *crtc_state) u64 data_rate = 0; for_each_plane_id_on_crtc(crtc, plane_id) { - if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) + if (plane_id == PLANE_CURSOR) continue; data_rate += crtc_state->rel_data_rate[plane_id]; @@ -1514,12 +1522,10 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, return 0; /* Allocate fixed number of blocks for cursor. */ - if (DISPLAY_VER(i915) < 20) { - cursor_size = skl_cursor_allocation(crtc_state, num_active); - iter.size -= cursor_size; - skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR], - alloc->end - cursor_size, alloc->end); - } + cursor_size = skl_cursor_allocation(crtc_state, num_active); + iter.size -= cursor_size; + skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR], + alloc->end - cursor_size, alloc->end); iter.data_rate = skl_total_relative_data_rate(crtc_state); @@ -1533,7 +1539,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) { + if (plane_id == PLANE_CURSOR) { const struct skl_ddb_entry *ddb = &crtc_state->wm.skl.plane_ddb[plane_id]; @@ -1581,7 +1587,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) + if (plane_id == PLANE_CURSOR) continue; if (DISPLAY_VER(i915) < 11 && diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 555022c0652c804d55efbfa94b2d0ca5f9f97225..d3a771afb083e05272be0cf0349446604dab6505 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -2160,12 +2160,6 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) #ifdef CONFIG_MMU_NOTIFIER if (!err && (eb->args->flags & __EXEC_USERPTR_USED)) { - read_lock(&eb->i915->mm.notifier_lock); - - /* - * count is always at least 1, otherwise __EXEC_USERPTR_USED - * could not have been set - */ for (i = 0; i < count; i++) { struct eb_vma *ev = &eb->vma[i]; struct drm_i915_gem_object *obj = ev->vma->obj; @@ -2177,8 +2171,6 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) if (err) break; } - - read_unlock(&eb->i915->mm.notifier_lock); } #endif diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c index 0d812f4d787d7418d89d60f809d5b94179cc0133..3b27218aabe2016950fbadd49de5b8f0eb251da7 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c @@ -28,6 +28,13 @@ void i915_gem_suspend(struct drm_i915_private *i915) GEM_TRACE("%s\n", dev_name(i915->drm.dev)); intel_wakeref_auto(&i915->runtime_pm.userfault_wakeref, 0); + /* + * On rare occasions, we've observed the fence completion triggers + * free_engines asynchronously via rcu_call. Ensure those are done. + * This path is only called on suspend, so it's an acceptable cost. + */ + rcu_barrier(); + flush_workqueue(i915->wq); /* @@ -160,6 +167,9 @@ void i915_gem_suspend_late(struct drm_i915_private *i915) * machine in an unusable condition. */ + /* Like i915_gem_suspend, flush tasks staged from fence triggers */ + rcu_barrier(); + for_each_gt(gt, i915, i) intel_gt_suspend_late(gt); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c index a4fb577eceb412e3406ad9eb246f2b04f62c10a2..b09b74a2448b55ec6d704eecf3a717e2e2a228d3 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_region.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c @@ -129,7 +129,7 @@ i915_gem_object_create_region_at(struct intel_memory_region *mem, return ERR_PTR(-EINVAL); if (!(flags & I915_BO_ALLOC_GPU_ONLY) && - offset + size > mem->io_size && + offset + size > resource_size(&mem->io) && !i915_ggtt_has_aperture(to_gt(mem->i915)->ggtt)) return ERR_PTR(-ENOSPC); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 8c88075eeab237a189d74c08b54f2441d182e5a0..ad6dd7f3259bccb7de55c5622afd2a857ba6c2a8 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -541,7 +541,9 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) /* Exclude the reserved region from driver use */ mem->region.end = i915->dsm.reserved.start - 1; - mem->io_size = min(mem->io_size, resource_size(&mem->region)); + mem->io = DEFINE_RES_MEM(mem->io.start, + min(resource_size(&mem->io), + resource_size(&mem->region))); i915->dsm.usable_size = resource_size(&mem->region); @@ -752,7 +754,7 @@ static int _i915_gem_object_stolen_init(struct intel_memory_region *mem, * With discrete devices, where we lack a mappable aperture there is no * possible way to ever access this memory on the CPU side. */ - if (mem->type == INTEL_MEMORY_STOLEN_LOCAL && !mem->io_size && + if (mem->type == INTEL_MEMORY_STOLEN_LOCAL && !resource_size(&mem->io) && !(flags & I915_BO_ALLOC_GPU_ONLY)) return -ENOSPC; @@ -826,7 +828,6 @@ static const struct intel_memory_region_ops i915_region_stolen_smem_ops = { static int init_stolen_lmem(struct intel_memory_region *mem) { - struct drm_i915_private *i915 = mem->i915; int err; if (GEM_WARN_ON(resource_size(&mem->region) == 0)) @@ -838,14 +839,10 @@ static int init_stolen_lmem(struct intel_memory_region *mem) return 0; } - if (mem->io_size && - !io_mapping_init_wc(&mem->iomap, mem->io_start, mem->io_size)) + if (resource_size(&mem->io) && + !io_mapping_init_wc(&mem->iomap, mem->io.start, resource_size(&mem->io))) goto err_cleanup; - drm_dbg(&i915->drm, "Stolen Local memory IO start: %pa\n", - &mem->io_start); - drm_dbg(&i915->drm, "Stolen Local DSM base: %pa\n", &mem->region.start); - return 0; err_cleanup: @@ -855,7 +852,7 @@ err_cleanup: static int release_stolen_lmem(struct intel_memory_region *mem) { - if (mem->io_size) + if (resource_size(&mem->io)) io_mapping_fini(&mem->iomap); i915_gem_cleanup_stolen(mem->i915); return 0; @@ -938,13 +935,17 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, GEM_BUG_ON((dsm_base + dsm_size) > lmem_size); } else { /* Use DSM base address instead for stolen memory */ - dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE) & GEN12_BDSM_MASK; + dsm_base = intel_uncore_read64(uncore, GEN6_DSMBASE) & GEN11_BDSM_MASK; if (WARN_ON(lmem_size < dsm_base)) return ERR_PTR(-ENODEV); dsm_size = ALIGN_DOWN(lmem_size - dsm_base, SZ_1M); } - if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) { + if (i915_direct_stolen_access(i915)) { + drm_dbg(&i915->drm, "Using direct DSM access\n"); + io_start = intel_uncore_read64(uncore, GEN6_DSMBASE) & GEN11_BDSM_MASK; + io_size = dsm_size; + } else if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) { io_start = 0; io_size = 0; } else { diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 9227f8146a583fc45a5a391ac4a9be48bb3b8a60..27dcfd8a34bb1ddfbdee9c1cc44444be580e4dca 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -65,8 +65,6 @@ static const struct ttm_place sys_placement_flags = { static struct ttm_placement i915_sys_placement = { .num_placement = 1, .placement = &sys_placement_flags, - .num_busy_placement = 1, - .busy_placement = &sys_placement_flags, }; /** @@ -144,45 +142,41 @@ i915_ttm_place_from_region(const struct intel_memory_region *mr, place->fpfn = offset >> PAGE_SHIFT; WARN_ON(overflows_type(place->fpfn + (size >> PAGE_SHIFT), place->lpfn)); place->lpfn = place->fpfn + (size >> PAGE_SHIFT); - } else if (mr->io_size && mr->io_size < mr->total) { + } else if (resource_size(&mr->io) && resource_size(&mr->io) < mr->total) { if (flags & I915_BO_ALLOC_GPU_ONLY) { place->flags |= TTM_PL_FLAG_TOPDOWN; } else { place->fpfn = 0; - WARN_ON(overflows_type(mr->io_size >> PAGE_SHIFT, place->lpfn)); - place->lpfn = mr->io_size >> PAGE_SHIFT; + WARN_ON(overflows_type(resource_size(&mr->io) >> PAGE_SHIFT, place->lpfn)); + place->lpfn = resource_size(&mr->io) >> PAGE_SHIFT; } } } static void i915_ttm_placement_from_obj(const struct drm_i915_gem_object *obj, - struct ttm_place *requested, - struct ttm_place *busy, + struct ttm_place *places, struct ttm_placement *placement) { unsigned int num_allowed = obj->mm.n_placements; unsigned int flags = obj->flags; unsigned int i; - placement->num_placement = 1; + places[0].flags |= TTM_PL_FLAG_DESIRED; i915_ttm_place_from_region(num_allowed ? obj->mm.placements[0] : - obj->mm.region, requested, obj->bo_offset, + obj->mm.region, &places[0], obj->bo_offset, obj->base.size, flags); /* Cache this on object? */ - placement->num_busy_placement = num_allowed; - for (i = 0; i < placement->num_busy_placement; ++i) - i915_ttm_place_from_region(obj->mm.placements[i], busy + i, - obj->bo_offset, obj->base.size, flags); - - if (num_allowed == 0) { - *busy = *requested; - placement->num_busy_placement = 1; + for (i = 0; i < num_allowed; ++i) { + i915_ttm_place_from_region(obj->mm.placements[i], + &places[i + 1], obj->bo_offset, + obj->base.size, flags); + places[i + 1].flags |= TTM_PL_FLAG_FALLBACK; } - placement->placement = requested; - placement->busy_placement = busy; + placement->num_placement = num_allowed + 1; + placement->placement = places; } static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev, @@ -789,7 +783,8 @@ static int __i915_ttm_get_pages(struct drm_i915_gem_object *obj, int ret; /* First try only the requested placement. No eviction. */ - real_num_busy = fetch_and_zero(&placement->num_busy_placement); + real_num_busy = placement->num_placement; + placement->num_placement = 1; ret = ttm_bo_validate(bo, placement, &ctx); if (ret) { ret = i915_ttm_err_to_gem(ret); @@ -805,7 +800,7 @@ static int __i915_ttm_get_pages(struct drm_i915_gem_object *obj, * If the initial attempt fails, allow all accepted placements, * evicting if necessary. */ - placement->num_busy_placement = real_num_busy; + placement->num_placement = real_num_busy; ret = ttm_bo_validate(bo, placement, &ctx); if (ret) return i915_ttm_err_to_gem(ret); @@ -839,7 +834,7 @@ static int __i915_ttm_get_pages(struct drm_i915_gem_object *obj, static int i915_ttm_get_pages(struct drm_i915_gem_object *obj) { - struct ttm_place requested, busy[I915_TTM_MAX_PLACEMENTS]; + struct ttm_place places[I915_TTM_MAX_PLACEMENTS + 1]; struct ttm_placement placement; /* restricted by sg_alloc_table */ @@ -849,7 +844,7 @@ static int i915_ttm_get_pages(struct drm_i915_gem_object *obj) GEM_BUG_ON(obj->mm.n_placements > I915_TTM_MAX_PLACEMENTS); /* Move to the requested placement. */ - i915_ttm_placement_from_obj(obj, &requested, busy, &placement); + i915_ttm_placement_from_obj(obj, places, &placement); return __i915_ttm_get_pages(obj, &placement); } @@ -879,9 +874,7 @@ static int __i915_ttm_migrate(struct drm_i915_gem_object *obj, i915_ttm_place_from_region(mr, &requested, obj->bo_offset, obj->base.size, flags); placement.num_placement = 1; - placement.num_busy_placement = 1; placement.placement = &requested; - placement.busy_placement = &requested; ret = __i915_ttm_get_pages(obj, &placement); if (ret) @@ -1090,7 +1083,7 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) struct intel_memory_region *mr = obj->mm.placements[i]; unsigned int flags; - if (!mr->io_size && mr->type != INTEL_MEMORY_SYSTEM) + if (!resource_size(&mr->io) && mr->type != INTEL_MEMORY_SYSTEM) continue; flags = obj->flags; @@ -1101,8 +1094,9 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) } if (err) { - drm_dbg(dev, "Unable to make resource CPU accessible(err = %pe)\n", - ERR_PTR(err)); + drm_dbg_ratelimited(dev, + "Unable to make resource CPU accessible(err = %pe)\n", + ERR_PTR(err)); dma_resv_unlock(bo->base.resv); ret = VM_FAULT_SIGBUS; goto out_rpm; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c index 1d3ebdf4069b5d0fea98aefdb2b1609f82b9650e..0e21ce9d3e5ac04377cb385a2f5a1893e8b1b19b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c @@ -42,7 +42,6 @@ #include "i915_drv.h" #include "i915_gem_ioctls.h" #include "i915_gem_object.h" -#include "i915_gem_userptr.h" #include "i915_scatterlist.h" #ifdef CONFIG_MMU_NOTIFIER @@ -61,36 +60,7 @@ static bool i915_gem_userptr_invalidate(struct mmu_interval_notifier *mni, const struct mmu_notifier_range *range, unsigned long cur_seq) { - struct drm_i915_gem_object *obj = container_of(mni, struct drm_i915_gem_object, userptr.notifier); - struct drm_i915_private *i915 = to_i915(obj->base.dev); - long r; - - if (!mmu_notifier_range_blockable(range)) - return false; - - write_lock(&i915->mm.notifier_lock); - mmu_interval_set_seq(mni, cur_seq); - - write_unlock(&i915->mm.notifier_lock); - - /* - * We don't wait when the process is exiting. This is valid - * because the object will be cleaned up anyway. - * - * This is also temporarily required as a hack, because we - * cannot currently force non-consistent batch buffers to preempt - * and reschedule by waiting on it, hanging processes on exit. - */ - if (current->flags & PF_EXITING) - return true; - - /* we will unbind on next submission, still have userptr pins */ - r = dma_resv_wait_timeout(obj->base.resv, DMA_RESV_USAGE_BOOKKEEP, false, - MAX_SCHEDULE_TIMEOUT); - if (r <= 0) - drm_err(&i915->drm, "(%ld) failed to wait for idle\n", r); - return true; } @@ -580,15 +550,3 @@ i915_gem_userptr_ioctl(struct drm_device *dev, #endif } -int i915_gem_init_userptr(struct drm_i915_private *dev_priv) -{ -#ifdef CONFIG_MMU_NOTIFIER - rwlock_init(&dev_priv->mm.notifier_lock); -#endif - - return 0; -} - -void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv) -{ -} diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.h b/drivers/gpu/drm/i915/gem/i915_gem_userptr.h deleted file mode 100644 index 8dadb2f8436d4426b09939eee97d162f8bb1b26c..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2021 Intel Corporation - */ - -#ifndef __I915_GEM_USERPTR_H__ -#define __I915_GEM_USERPTR_H__ - -struct drm_i915_private; - -int i915_gem_init_userptr(struct drm_i915_private *dev_priv); -void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv); - -#endif /* __I915_GEM_USERPTR_H__ */ diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index 2c51a2c452fc5c4194c9f9e3b21b66587ce92ae6..99a9ade739562ed8c2e9a9de32bb7b5655795cdf 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -1054,7 +1054,7 @@ static int igt_fill_mappable(struct intel_memory_region *mr, int err; total = 0; - size = mr->io_size; + size = resource_size(&mr->io); do { struct drm_i915_gem_object *obj; @@ -1315,28 +1315,28 @@ static int igt_mmap_migrate(void *arg) struct intel_memory_region *mixed[] = { mr, system }; struct intel_memory_region *single[] = { mr }; struct ttm_resource_manager *man = mr->region_private; - resource_size_t saved_io_size; + struct resource saved_io; int err; if (mr->private) continue; - if (!mr->io_size) + if (!resource_size(&mr->io)) continue; /* * For testing purposes let's force small BAR, if not already * present. */ - saved_io_size = mr->io_size; - if (mr->io_size == mr->total) { - resource_size_t io_size = mr->io_size; + saved_io = mr->io; + if (resource_size(&mr->io) == mr->total) { + resource_size_t io_size = resource_size(&mr->io); io_size = rounddown_pow_of_two(io_size >> 1); if (io_size < PAGE_SIZE) continue; - mr->io_size = io_size; + mr->io = DEFINE_RES_MEM(mr->io.start, io_size); i915_ttm_buddy_man_force_visible_size(man, io_size >> PAGE_SHIFT); } @@ -1396,9 +1396,9 @@ static int igt_mmap_migrate(void *arg) IGT_MMAP_MIGRATE_FAIL_GPU | IGT_MMAP_MIGRATE_UNFAULTABLE); out_io_size: - mr->io_size = saved_io_size; + mr->io = saved_io; i915_ttm_buddy_man_force_visible_size(man, - mr->io_size >> PAGE_SHIFT); + resource_size(&mr->io) >> PAGE_SHIFT); if (err) return err; } diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index 86a04afff64b3fc76700b6d7e9793470858f11e6..e1bf13e3d307073956379da22d2d8e989b56cff6 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -226,7 +226,7 @@ u32 *gen12_emit_aux_table_inv(struct intel_engine_cs *engine, u32 *cs) static int mtl_dummy_pipe_control(struct i915_request *rq) { /* Wa_14016712196 */ - if (IS_GFX_GT_IP_RANGE(rq->engine->gt, IP_VER(12, 70), IP_VER(12, 71)) || + if (IS_GFX_GT_IP_RANGE(rq->engine->gt, IP_VER(12, 70), IP_VER(12, 74)) || IS_DG2(rq->i915)) { u32 *cs; @@ -822,7 +822,7 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) flags |= PIPE_CONTROL_FLUSH_L3; /* Wa_14016712196 */ - if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)) || IS_DG2(i915)) + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74)) || IS_DG2(i915)) /* dummy PIPE_CONTROL + depth flush */ cs = gen12_emit_pipe_control(cs, 0, PIPE_CONTROL_DEPTH_CACHE_FLUSH, 0); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 40687806d22a6dc1d1dd797f7dc64ee970517daf..1ade568ffbfa43409129228881abe60d965e8d10 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -1190,7 +1190,8 @@ static int intel_engine_init_tlb_invalidation(struct intel_engine_cs *engine) num = ARRAY_SIZE(xelpmp_regs); } } else { - if (GRAPHICS_VER_FULL(i915) == IP_VER(12, 71) || + if (GRAPHICS_VER_FULL(i915) == IP_VER(12, 74) || + GRAPHICS_VER_FULL(i915) == IP_VER(12, 71) || GRAPHICS_VER_FULL(i915) == IP_VER(12, 70) || GRAPHICS_VER_FULL(i915) == IP_VER(12, 50) || GRAPHICS_VER_FULL(i915) == IP_VER(12, 55)) { diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c index 1a8e2b7db0138f4928482f3ce8d1b42ff5b30cc3..5f8d86e25993a8f9991410254506d310062de01c 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c @@ -96,7 +96,8 @@ static void heartbeat_commit(struct i915_request *rq, static void show_heartbeat(const struct i915_request *rq, struct intel_engine_cs *engine) { - struct drm_printer p = drm_debug_printer("heartbeat"); + struct drm_printer p = drm_dbg_printer(&rq->i915->drm, DRM_UT_DRIVER, + "heartbeat"); if (!rq) { intel_engine_dump(engine, &p, @@ -290,6 +291,9 @@ static int __intel_engine_pulse(struct intel_engine_cs *engine) heartbeat_commit(rq, &attr); GEM_BUG_ON(rq->sched.attr.priority < I915_PRIORITY_BARRIER); + /* Ensure the forced pulse gets a full period to execute */ + next_heartbeat(engine); + return 0; } diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 21a7e3191c1827be0632bce4103af1465f560ebb..ec1cbe229f0e42c7be96f83da2cee40cc41bc93f 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -24,6 +24,7 @@ #include "intel_ring.h" #include "i915_drv.h" #include "i915_pci.h" +#include "i915_reg.h" #include "i915_request.h" #include "i915_scatterlist.h" #include "i915_utils.h" @@ -1152,13 +1153,20 @@ static unsigned int gen6_gttadr_offset(struct drm_i915_private *i915) static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) { struct drm_i915_private *i915 = ggtt->vm.i915; + struct intel_uncore *uncore = ggtt->vm.gt->uncore; struct pci_dev *pdev = to_pci_dev(i915->drm.dev); phys_addr_t phys_addr; u32 pte_flags; int ret; GEM_WARN_ON(pci_resource_len(pdev, GEN4_GTTMMADR_BAR) != gen6_gttmmadr_size(i915)); - phys_addr = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) + gen6_gttadr_offset(i915); + + if (i915_direct_stolen_access(i915)) { + drm_dbg(&i915->drm, "Using direct GSM access\n"); + phys_addr = intel_uncore_read64(uncore, GEN6_GSMBASE) & GEN11_BDSM_MASK; + } else { + phys_addr = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) + gen6_gttadr_offset(i915); + } if (needs_wc_ggtt_mapping(i915)) ggtt->gsm = ioremap_wc(phys_addr, size); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c index f0dea54880af258ba607b8989b9a3d3fd712f32c..c0b2022239406dac637acff5c0da899fb6c341ee 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c @@ -176,27 +176,13 @@ static u32 get_residency(struct intel_gt *gt, enum intel_rc6_res_type id) return DIV_ROUND_CLOSEST_ULL(res, 1000); } -static u8 get_rc6_mask(struct intel_gt *gt) -{ - u8 mask = 0; - - if (HAS_RC6(gt->i915)) - mask |= BIT(0); - if (HAS_RC6p(gt->i915)) - mask |= BIT(1); - if (HAS_RC6pp(gt->i915)) - mask |= BIT(2); - - return mask; -} - static ssize_t rc6_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); - return sysfs_emit(buff, "%x\n", get_rc6_mask(gt)); + return sysfs_emit(buff, "%x\n", gt->rc6.enabled); } static ssize_t rc6_enable_dev_show(struct device *dev, @@ -205,7 +191,7 @@ static ssize_t rc6_enable_dev_show(struct device *dev, { struct intel_gt *gt = intel_gt_sysfs_get_drvdata(&dev->kobj, attr->attr.name); - return sysfs_emit(buff, "%x\n", get_rc6_mask(gt)); + return sysfs_emit(buff, "%x\n", gt->rc6.enabled); } static u32 __rc6_residency_ms_show(struct intel_gt *gt) diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index 86f73fe558ca6eb88051c8e77938460bbc043dec..7811a8c9da0672e4853b3ddfa44123cb5727f4fd 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -24,7 +24,8 @@ bool i915_ggtt_require_binder(struct drm_i915_private *i915) { /* Wa_13010847436 & Wa_14019519902 */ - return MEDIA_VER_FULL(i915) == IP_VER(13, 0); + return !i915_direct_stolen_access(i915) && + MEDIA_VER_FULL(i915) == IP_VER(13, 0); } static bool intel_ggtt_update_needs_vtd_wa(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c index 353f93baaca051d1c21a7fd361c43a2efa488c72..25c1023eb5f9fa5afd63fc48c3847e2a57cdaafd 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.c +++ b/drivers/gpu/drm/i915/gt/intel_mocs.c @@ -495,7 +495,7 @@ static unsigned int get_mocs_settings(struct drm_i915_private *i915, memset(table, 0, sizeof(struct drm_i915_mocs_table)); table->unused_entries_index = I915_MOCS_PTE; - if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 71))) { + if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 74))) { table->size = ARRAY_SIZE(mtl_mocs_table); table->table = mtl_mocs_table; table->n_entries = MTL_NUM_MOCS_ENTRIES; diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index 7090e4be29cb69bb6f2fdf459cf4062fc4a1ce3a..8f4b3c8af09cce57a71bfb93a2b7d0c32ac473f8 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -123,7 +123,7 @@ static void gen11_rc6_enable(struct intel_rc6 *rc6) * temporary wa and should be removed after fixing real cause * of forcewake timeouts. */ - if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) pg_enable = GEN9_MEDIA_PG_ENABLE | GEN11_MEDIA_SAMPLER_PG_ENABLE; diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c index f8512aee58a830fb9f723ae3c9e24c9888b04ffe..51bb27e10a4f87190dbcaea020b10cbe1dea0fad 100644 --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c @@ -144,8 +144,8 @@ region_lmem_init(struct intel_memory_region *mem) int ret; if (!io_mapping_init_wc(&mem->iomap, - mem->io_start, - mem->io_size)) + mem->io.start, + resource_size(&mem->io))) return -EIO; ret = intel_region_ttm_init(mem); @@ -240,7 +240,7 @@ static struct intel_memory_region *setup_lmem(struct intel_gt *gt) lmem_size -= tile_stolen; } else { /* Stolen starts from GSMBASE without CCS */ - lmem_size = intel_uncore_read64(&i915->uncore, GEN12_GSMBASE); + lmem_size = intel_uncore_read64(&i915->uncore, GEN6_GSMBASE); } i915_resize_lmem_bar(i915, lmem_size); @@ -273,14 +273,6 @@ static struct intel_memory_region *setup_lmem(struct intel_gt *gt) if (err) goto err_region_put; - drm_dbg(&i915->drm, "Local memory: %pR\n", &mem->region); - drm_dbg(&i915->drm, "Local memory IO start: %pa\n", - &mem->io_start); - drm_info(&i915->drm, "Local memory IO size: %pa\n", - &mem->io_size); - drm_info(&i915->drm, "Local memory available: %pa\n", - &lmem_size); - if (io_size < lmem_size) drm_info(&i915->drm, "Using a reduced BAR size of %lluMiB. Consider enabling 'Resizable BAR' or similar, if available in the BIOS.\n", (u64)io_size >> 20); diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 6801f8b95c53d1ed989f6bb7c72205b2d7cd236a..c8e9aa41fdeac51e93a3490e0d4d1c59de551a51 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -1015,7 +1015,8 @@ void intel_gt_set_wedged(struct intel_gt *gt) mutex_lock(>->reset.mutex); if (GEM_SHOW_DEBUG()) { - struct drm_printer p = drm_debug_printer(__func__); + struct drm_printer p = drm_dbg_printer(>->i915->drm, + DRM_UT_DRIVER, __func__); struct intel_engine_cs *engine; enum intel_engine_id id; diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 3eacbc50caf8d98fd92f45640cf64a5d106c9052..d67d44611c2834e5a76df5bee9a972e0974bb589 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -789,8 +789,13 @@ static void xelpg_ctx_gt_tuning_init(struct intel_engine_cs *engine, dg2_ctx_gt_tuning_init(engine, wal); - if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) || - IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER)) + /* + * Due to Wa_16014892111, the DRAW_WATERMARK tuning must be done in + * gen12_emit_indirect_ctx_rcs() rather than here on some early + * steppings. + */ + if (!(IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0))) wa_add(wal, DRAW_WATERMARK, VERT_WM_VAL, 0x3FF, 0, false); } @@ -820,6 +825,9 @@ static void xelpg_ctx_workarounds_init(struct intel_engine_cs *engine, /* Wa_18019271663 */ wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE); + + /* Wa_14019877138 */ + wa_mcr_masked_en(wal, XEHP_PSS_CHICKEN, FD_END_COLLECT); } static void fakewa_disable_nestedbb_mode(struct intel_engine_cs *engine, @@ -908,7 +916,7 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine, if (engine->class != RENDER_CLASS) goto done; - if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 71))) + if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 74))) xelpg_ctx_workarounds_init(engine, wal); else if (IS_PONTEVECCHIO(i915)) ; /* noop; none at this time */ @@ -1233,7 +1241,8 @@ static void __set_mcr_steering(struct i915_wa_list *wal, static void debug_dump_steering(struct intel_gt *gt) { - struct drm_printer p = drm_debug_printer("MCR Steering:"); + struct drm_printer p = drm_dbg_printer(>->i915->drm, DRM_UT_DRIVER, + "MCR Steering:"); if (drm_debug_enabled(DRM_UT_DRIVER)) intel_gt_mcr_report_steering(&p, gt, false); @@ -1643,7 +1652,7 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) static void xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { - /* Wa_14018778641 / Wa_18018781329 */ + /* Wa_14018575942 / Wa_18018781329 */ wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB); /* Wa_22016670082 */ @@ -1710,7 +1719,7 @@ xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) */ static void gt_tuning_settings(struct intel_gt *gt, struct i915_wa_list *wal) { - if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) { + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) { wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS); wa_mcr_write_or(wal, XEHP_SQCM, EN_32B_ACCESS); } @@ -1743,7 +1752,7 @@ gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal) return; } - if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) xelpg_gt_workarounds_init(gt, wal); else if (IS_PONTEVECCHIO(i915)) pvc_gt_workarounds_init(gt, wal); @@ -2216,7 +2225,7 @@ void intel_engine_init_whitelist(struct intel_engine_cs *engine) if (engine->gt->type == GT_MEDIA) ; /* none yet */ - else if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 71))) + else if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 74))) xelpg_whitelist_build(engine); else if (IS_PONTEVECCHIO(i915)) pvc_whitelist_build(engine); @@ -2828,7 +2837,7 @@ add_render_compute_tuning_settings(struct intel_gt *gt, { struct drm_i915_private *i915 = gt->i915; - if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)) || IS_DG2(i915)) + if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74)) || IS_DG2(i915)) wa_mcr_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512); /* @@ -2881,7 +2890,8 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li } if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) || - IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER)) + IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER) || + IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 74), IP_VER(12, 74))) /* Wa_14017856879 */ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN3, MTL_DISABLE_FIX_FOR_EOT_FLUSH); diff --git a/drivers/gpu/drm/i915/gt/selftest_context.c b/drivers/gpu/drm/i915/gt/selftest_context.c index 47070cba7eb145688a37d09e0dfc26cead7ffe54..12eca750f7d012f24d05e2ff4d72aeaa7d97d4fa 100644 --- a/drivers/gpu/drm/i915/gt/selftest_context.c +++ b/drivers/gpu/drm/i915/gt/selftest_context.c @@ -285,7 +285,8 @@ out_engine: intel_engine_pm_flush(engine); if (intel_engine_pm_is_awake(engine)) { - struct drm_printer p = drm_debug_printer(__func__); + struct drm_printer p = drm_dbg_printer(&engine->i915->drm, + DRM_UT_DRIVER, __func__); intel_engine_dump(engine, &p, "%s is still awake:%d after idle-barriers\n", diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c index bc441ce7b380d37de01c548c160281b76f1ada9e..ef014df4c4fccc1b0855459196520cbf78c7261b 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c @@ -122,9 +122,9 @@ static int __live_idle_pulse(struct intel_engine_cs *engine, GEM_BUG_ON(!llist_empty(&engine->barrier_tasks)); if (engine_sync_barrier(engine)) { - struct drm_printer m = drm_err_printer("pulse"); + struct drm_printer m = drm_err_printer(&engine->i915->drm, "pulse"); - pr_err("%s: no heartbeat pulse?\n", engine->name); + drm_printf(&m, "%s: no heartbeat pulse?\n", engine->name); intel_engine_dump(engine, &m, "%s", engine->name); err = -ETIME; @@ -136,10 +136,10 @@ static int __live_idle_pulse(struct intel_engine_cs *engine, pulse_unlock_wait(p); /* synchronize with the retirement callback */ if (!i915_active_is_idle(&p->active)) { - struct drm_printer m = drm_err_printer("pulse"); + struct drm_printer m = drm_err_printer(&engine->i915->drm, "pulse"); - pr_err("%s: heartbeat pulse did not flush idle tasks\n", - engine->name); + drm_printf(&m, "%s: heartbeat pulse did not flush idle tasks\n", + engine->name); i915_active_print(&p->active, &m); err = -EINVAL; diff --git a/drivers/gpu/drm/i915/gt/selftest_rc6.c b/drivers/gpu/drm/i915/gt/selftest_rc6.c index a7189c2d660cc557c309565e9bfc69f26798e840..1aa1446c8fb09b2c5a21b3bcd3573fa58dad620e 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rc6.c +++ b/drivers/gpu/drm/i915/gt/selftest_rc6.c @@ -62,12 +62,12 @@ int live_rc6_manual(void *arg) dt = ktime_get(); rc0_power = librapl_energy_uJ(); - msleep(250); + msleep(1000); rc0_power = librapl_energy_uJ() - rc0_power; dt = ktime_sub(ktime_get(), dt); res[1] = rc6_residency(rc6); if ((res[1] - res[0]) >> 10) { - pr_err("RC6 residency increased by %lldus while disabled for 250ms!\n", + pr_err("RC6 residency increased by %lldus while disabled for 1000ms!\n", (res[1] - res[0]) >> 10); err = -EINVAL; goto out_unlock; diff --git a/drivers/gpu/drm/i915/gt/selftest_tlb.c b/drivers/gpu/drm/i915/gt/selftest_tlb.c index 00b872b6380b15ba6dd0da994ba1a73e2680ee48..3941f2d6fa47d72595b6ac13d028ce637ec1a725 100644 --- a/drivers/gpu/drm/i915/gt/selftest_tlb.c +++ b/drivers/gpu/drm/i915/gt/selftest_tlb.c @@ -206,8 +206,8 @@ static struct drm_i915_gem_object *create_lmem(struct intel_gt *gt) * of pages. To succeed with both allocations, especially in case of Small * BAR, try to allocate no more than quarter of mappable memory. */ - if (mr && size > mr->io_size / 4) - size = mr->io_size / 4; + if (mr && size > resource_size(&mr->io) / 4) + size = resource_size(&mr->io) / 4; return i915_gem_object_create_lmem(gt->i915, size, I915_BO_ALLOC_CONTIGUOUS); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index 63724e17829a746c55dd8baa6acb7fd9477e7abe..f7372f736a776028f84e552a2e5aba86829c543d 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -377,8 +377,13 @@ static int guc_mmio_regset_init(struct temp_regset *regset, CCS_MASK(engine->gt)) ret |= GUC_MMIO_REG_ADD(gt, regset, GEN12_RCU_MODE, true); + /* + * some of the WA registers are MCR registers. As it is safe to + * use MCR form for non-MCR registers, for code simplicity, all + * WA registers are added with MCR form. + */ for (i = 0, wa = wal->list; i < wal->count; i++, wa++) - ret |= GUC_MMIO_REG_ADD(gt, regset, wa->reg, wa->masked_reg); + ret |= GUC_MCR_REG_ADD(gt, regset, wa->mcr_reg, wa->masked_reg); /* Be extra paranoid and include all whitelist registers. */ for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) @@ -394,13 +399,13 @@ static int guc_mmio_regset_init(struct temp_regset *regset, ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false); if (GRAPHICS_VER(engine->i915) >= 12) { - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL0, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL1, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL2, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL3, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL4, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL5, false); - ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL6, false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL0)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL1)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL2)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL3)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL4)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL5)), false); + ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL6)), false); } return ret ? -1 : 0; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c index 0f79cb658518268efec6e0244307f0698dad4ed3..52332bb143395e80b362a0ba91386b8eef5f7d41 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c @@ -184,7 +184,7 @@ static int guc_wait_ucode(struct intel_guc *guc) * in the seconds range. However, there is a limit on how long an * individual wait_for() can wait. So wrap it in a loop. */ - before_freq = intel_rps_read_actual_frequency(&uncore->gt->rps); + before_freq = intel_rps_read_actual_frequency(>->rps); before = ktime_get(); for (count = 0; count < GUC_LOAD_RETRY_LIMIT; count++) { ret = wait_for(guc_load_done(uncore, &status, &success), 1000); @@ -192,7 +192,7 @@ static int guc_wait_ucode(struct intel_guc *guc) break; guc_dbg(guc, "load still in progress, count = %d, freq = %dMHz, status = 0x%08X [0x%02X/%02X]\n", - count, intel_rps_read_actual_frequency(&uncore->gt->rps), status, + count, intel_rps_read_actual_frequency(>->rps), status, REG_FIELD_GET(GS_BOOTROM_MASK, status), REG_FIELD_GET(GS_UKERNEL_MASK, status)); } @@ -204,7 +204,7 @@ static int guc_wait_ucode(struct intel_guc *guc) u32 bootrom = REG_FIELD_GET(GS_BOOTROM_MASK, status); guc_info(guc, "load failed: status = 0x%08X, time = %lldms, freq = %dMHz, ret = %d\n", - status, delta_ms, intel_rps_read_actual_frequency(&uncore->gt->rps), ret); + status, delta_ms, intel_rps_read_actual_frequency(>->rps), ret); guc_info(guc, "load failed: status: Reset = %d, BootROM = 0x%02X, UKernel = 0x%02X, MIA = 0x%02X, Auth = 0x%02X\n", REG_FIELD_GET(GS_MIA_IN_RESET, status), bootrom, ukernel, @@ -254,11 +254,11 @@ static int guc_wait_ucode(struct intel_guc *guc) guc_warn(guc, "excessive init time: %lldms! [status = 0x%08X, count = %d, ret = %d]\n", delta_ms, status, count, ret); guc_warn(guc, "excessive init time: [freq = %dMHz, before = %dMHz, perf_limit_reasons = 0x%08X]\n", - intel_rps_read_actual_frequency(&uncore->gt->rps), before_freq, + intel_rps_read_actual_frequency(>->rps), before_freq, intel_uncore_read(uncore, intel_gt_perf_limit_reasons_reg(gt))); } else { guc_dbg(guc, "init took %lldms, freq = %dMHz, before = %dMHz, status = 0x%08X, count = %d, ret = %d\n", - delta_ms, intel_rps_read_actual_frequency(&uncore->gt->rps), + delta_ms, intel_rps_read_actual_frequency(>->rps), before_freq, status, count, ret); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index a259f1118c5ab1f660d506e4719a8b54a7a6fcc8..f3dcae4b9d455ed37d3cc3fd1635760cd9e264af 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -236,6 +236,13 @@ set_context_destroyed(struct intel_context *ce) ce->guc_state.sched_state |= SCHED_STATE_DESTROYED; } +static inline void +clr_context_destroyed(struct intel_context *ce) +{ + lockdep_assert_held(&ce->guc_state.lock); + ce->guc_state.sched_state &= ~SCHED_STATE_DESTROYED; +} + static inline bool context_pending_disable(struct intel_context *ce) { return ce->guc_state.sched_state & SCHED_STATE_PENDING_DISABLE; @@ -613,6 +620,8 @@ static int guc_submission_send_busy_loop(struct intel_guc *guc, u32 g2h_len_dw, bool loop) { + int ret; + /* * We always loop when a send requires a reply (i.e. g2h_len_dw > 0), * so we don't handle the case where we don't get a reply because we @@ -623,7 +632,11 @@ static int guc_submission_send_busy_loop(struct intel_guc *guc, if (g2h_len_dw) atomic_inc(&guc->outstanding_submission_g2h); - return intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop); + ret = intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop); + if (ret) + atomic_dec(&guc->outstanding_submission_g2h); + + return ret; } int intel_guc_wait_for_pending_msg(struct intel_guc *guc, @@ -1362,7 +1375,45 @@ static void guc_enable_busyness_worker(struct intel_guc *guc) static void guc_cancel_busyness_worker(struct intel_guc *guc) { - cancel_delayed_work_sync(&guc->timestamp.work); + /* + * There are many different call stacks that can get here. Some of them + * hold the reset mutex. The busyness worker also attempts to acquire the + * reset mutex. Synchronously flushing a worker thread requires acquiring + * the worker mutex. Lockdep sees this as a conflict. It thinks that the + * flush can deadlock because it holds the worker mutex while waiting for + * the reset mutex, but another thread is holding the reset mutex and might + * attempt to use other worker functions. + * + * In practice, this scenario does not exist because the busyness worker + * does not block waiting for the reset mutex. It does a try-lock on it and + * immediately exits if the lock is already held. Unfortunately, the mutex + * in question (I915_RESET_BACKOFF) is an i915 implementation which has lockdep + * annotation but not to the extent of explaining the 'might lock' is also a + * 'does not need to lock'. So one option would be to add more complex lockdep + * annotations to ignore the issue (if at all possible). A simpler option is to + * just not flush synchronously when a rest in progress. Given that the worker + * will just early exit and re-schedule itself anyway, there is no advantage + * to running it immediately. + * + * If a reset is not in progress, then the synchronous flush may be required. + * As noted many call stacks lead here, some during suspend and driver unload + * which do require a synchronous flush to make sure the worker is stopped + * before memory is freed. + * + * Trying to pass a 'need_sync' or 'in_reset' flag all the way down through + * every possible call stack is unfeasible. It would be too intrusive to many + * areas that really don't care about the GuC backend. However, there is the + * 'reset_in_progress' flag available, so just use that. + * + * And note that in the case of a reset occurring during driver unload + * (wedge_on_fini), skipping the cancel in _prepare (when the reset flag is set + * is fine because there is another cancel in _finish (when the reset flag is + * not). + */ + if (guc_to_gt(guc)->uc.reset_in_progress) + cancel_delayed_work(&guc->timestamp.work); + else + cancel_delayed_work_sync(&guc->timestamp.work); } static void __reset_guc_busyness_stats(struct intel_guc *guc) @@ -1613,6 +1664,11 @@ static void guc_flush_submissions(struct intel_guc *guc) spin_unlock_irqrestore(&sched_engine->lock, flags); } +void intel_guc_submission_flush_work(struct intel_guc *guc) +{ + flush_work(&guc->submission_state.destroyed_worker); +} + static void guc_flush_destroyed_contexts(struct intel_guc *guc); void intel_guc_submission_reset_prepare(struct intel_guc *guc) @@ -1948,8 +2004,16 @@ void intel_guc_submission_cancel_requests(struct intel_guc *guc) void intel_guc_submission_reset_finish(struct intel_guc *guc) { + /* + * Ensure the busyness worker gets cancelled even on a fatal wedge. + * Note that reset_prepare is not allowed to because it confuses lockdep. + */ + if (guc_submission_initialized(guc)) + guc_cancel_busyness_worker(guc); + /* Reset called during driver load or during wedge? */ if (unlikely(!guc_submission_initialized(guc) || + !intel_guc_is_fw_running(guc) || intel_gt_is_wedged(guc_to_gt(guc)))) { return; } @@ -3283,12 +3347,13 @@ static void guc_context_close(struct intel_context *ce) spin_unlock_irqrestore(&ce->guc_state.lock, flags); } -static inline void guc_lrc_desc_unpin(struct intel_context *ce) +static inline int guc_lrc_desc_unpin(struct intel_context *ce) { struct intel_guc *guc = ce_to_guc(ce); struct intel_gt *gt = guc_to_gt(guc); unsigned long flags; bool disabled; + int ret; GEM_BUG_ON(!intel_gt_pm_is_awake(gt)); GEM_BUG_ON(!ctx_id_mapped(guc, ce->guc_id.id)); @@ -3299,18 +3364,41 @@ static inline void guc_lrc_desc_unpin(struct intel_context *ce) spin_lock_irqsave(&ce->guc_state.lock, flags); disabled = submission_disabled(guc); if (likely(!disabled)) { + /* + * Take a gt-pm ref and change context state to be destroyed. + * NOTE: a G2H IRQ that comes after will put this gt-pm ref back + */ __intel_gt_pm_get(gt); set_context_destroyed(ce); clr_context_registered(ce); } spin_unlock_irqrestore(&ce->guc_state.lock, flags); + if (unlikely(disabled)) { release_guc_id(guc, ce); __guc_context_destroy(ce); - return; + return 0; } - deregister_context(ce, ce->guc_id.id); + /* + * GuC is active, lets destroy this context, but at this point we can still be racing + * with suspend, so we undo everything if the H2G fails in deregister_context so + * that GuC reset will find this context during clean up. + */ + ret = deregister_context(ce, ce->guc_id.id); + if (ret) { + spin_lock(&ce->guc_state.lock); + set_context_registered(ce); + clr_context_destroyed(ce); + spin_unlock(&ce->guc_state.lock); + /* + * As gt-pm is awake at function entry, intel_wakeref_put_async merely decrements + * the wakeref immediately but per function spec usage call this after unlock. + */ + intel_wakeref_put_async(>->wakeref); + } + + return ret; } static void __guc_context_destroy(struct intel_context *ce) @@ -3378,7 +3466,22 @@ static void deregister_destroyed_contexts(struct intel_guc *guc) if (!ce) break; - guc_lrc_desc_unpin(ce); + if (guc_lrc_desc_unpin(ce)) { + /* + * This means GuC's CT link severed mid-way which could happen + * in suspend-resume corner cases. In this case, put the + * context back into the destroyed_contexts list which will + * get picked up on the next context deregistration event or + * purged in a GuC sanitization event (reset/unload/wedged/...). + */ + spin_lock_irqsave(&guc->submission_state.lock, flags); + list_add_tail(&ce->destroyed_link, + &guc->submission_state.destroyed_contexts); + spin_unlock_irqrestore(&guc->submission_state.lock, flags); + /* Bail now since the list might never be emptied if h2gs fail */ + break; + } + } } @@ -3389,6 +3492,17 @@ static void destroyed_worker_func(struct work_struct *w) struct intel_gt *gt = guc_to_gt(guc); intel_wakeref_t wakeref; + /* + * In rare cases we can get here via async context-free fence-signals that + * come very late in suspend flow or very early in resume flows. In these + * cases, GuC won't be ready but just skipping it here is fine as these + * pending-destroy-contexts get destroyed totally at GuC reset time at the + * end of suspend.. OR.. this worker can be picked up later on the next + * context destruction trigger after resume-completes + */ + if (!intel_guc_is_ready(guc)) + return; + with_intel_gt_pm(gt, wakeref) deregister_destroyed_contexts(guc); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h index c57b29cdb1a64eeb2057101e7d59d0ec761d74c9..b6df75622d3b9fa777ebb6f7a4f4cc8a285cd6f9 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h @@ -38,6 +38,8 @@ int intel_guc_wait_for_pending_msg(struct intel_guc *guc, bool interruptible, long timeout); +void intel_guc_submission_flush_work(struct intel_guc *guc); + static inline bool intel_guc_submission_is_supported(struct intel_guc *guc) { return guc->submission_supported; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index ba9e07fc2b57706d658ddc46eb46dd706842e310..0945b177d5f975f403c9133ba9e59a978bd307b5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -6,6 +6,7 @@ #include #include "gt/intel_gt.h" +#include "gt/intel_rps.h" #include "intel_guc_reg.h" #include "intel_huc.h" #include "intel_huc_print.h" @@ -447,17 +448,68 @@ static const char *auth_mode_string(struct intel_huc *huc, return partial ? "clear media" : "all workloads"; } +/* + * Use a longer timeout for debug builds so that problems can be detected + * and analysed. But a shorter timeout for releases so that user's don't + * wait forever to find out there is a problem. Note that the only reason + * an end user should hit the timeout is in case of extreme thermal throttling. + * And a system that is that hot during boot is probably dead anyway! + */ +#if defined(CONFIG_DRM_I915_DEBUG_GEM) +#define HUC_LOAD_RETRY_LIMIT 20 +#else +#define HUC_LOAD_RETRY_LIMIT 3 +#endif + int intel_huc_wait_for_auth_complete(struct intel_huc *huc, enum intel_huc_authentication_type type) { struct intel_gt *gt = huc_to_gt(huc); - int ret; + struct intel_uncore *uncore = gt->uncore; + ktime_t before, after, delta; + int ret, count; + u64 delta_ms; + u32 before_freq; - ret = __intel_wait_for_register(gt->uncore, - huc->status[type].reg, - huc->status[type].mask, - huc->status[type].value, - 2, 50, NULL); + /* + * The KMD requests maximum frequency during driver load, however thermal + * throttling can force the frequency down to minimum (although the board + * really should never get that hot in real life!). IFWI issues have been + * seen to cause sporadic failures to grant the higher frequency. And at + * minimum frequency, the authentication time can be in the seconds range. + * Note that there is a limit on how long an individual wait_for() can wait. + * So wrap it in a loop. + */ + before_freq = intel_rps_read_actual_frequency(>->rps); + before = ktime_get(); + for (count = 0; count < HUC_LOAD_RETRY_LIMIT; count++) { + ret = __intel_wait_for_register(gt->uncore, + huc->status[type].reg, + huc->status[type].mask, + huc->status[type].value, + 2, 1000, NULL); + if (!ret) + break; + + huc_dbg(huc, "auth still in progress, count = %d, freq = %dMHz, status = 0x%08X\n", + count, intel_rps_read_actual_frequency(>->rps), + huc->status[type].reg.reg); + } + after = ktime_get(); + delta = ktime_sub(after, before); + delta_ms = ktime_to_ms(delta); + + if (delta_ms > 50) { + huc_warn(huc, "excessive auth time: %lldms! [status = 0x%08X, count = %d, ret = %d]\n", + delta_ms, huc->status[type].reg.reg, count, ret); + huc_warn(huc, "excessive auth time: [freq = %dMHz, before = %dMHz, perf_limit_reasons = 0x%08X]\n", + intel_rps_read_actual_frequency(>->rps), before_freq, + intel_uncore_read(uncore, intel_gt_perf_limit_reasons_reg(gt))); + } else { + huc_dbg(huc, "auth took %lldms, freq = %dMHz, before = %dMHz, status = 0x%08X, count = %d, ret = %d\n", + delta_ms, intel_rps_read_actual_frequency(>->rps), + before_freq, huc->status[type].reg.reg, count, ret); + } /* mark the load process as complete even if the wait failed */ delayed_huc_load_complete(huc); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index 3872d309ed31fa6a313bd7d0d72f3e5ccde679ec..6dfe5d9456c69e06987be23367c243bb1f8f908e 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -640,7 +640,7 @@ void intel_uc_reset_finish(struct intel_uc *uc) uc->reset_in_progress = false; /* Firmware expected to be running when this function is called */ - if (intel_guc_is_fw_running(guc) && intel_uc_uses_guc_submission(uc)) + if (intel_uc_uses_guc_submission(uc)) intel_guc_submission_reset_finish(guc); } @@ -690,6 +690,8 @@ void intel_uc_suspend(struct intel_uc *uc) return; } + intel_guc_submission_flush_work(guc); + with_intel_runtime_pm(&uc_to_gt(uc)->i915->runtime_pm, wakeref) { err = intel_guc_suspend(guc); if (err) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index faf21be724c3ac6128378d2ced807f88f147ba90..4f74d867fe1af160c3a42b15919ba9aaf5a29326 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -574,7 +574,7 @@ int intel_gvt_set_opregion(struct intel_vgpu *vgpu) ret = intel_vgpu_register_reg(vgpu, PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE, VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, - &intel_vgpu_regops_opregion, OPREGION_SIZE, + &intel_vgpu_regops_opregion, INTEL_GVT_OPREGION_SIZE, VFIO_REGION_INFO_FLAG_READ, base); return ret; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index db99c2ef66db84726129c9fba1926730ad753472..990eaa029d9c258935f5bb256be97f424ae6f44c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -147,7 +147,7 @@ static const char *i915_cache_level_str(struct drm_i915_gem_object *obj) { struct drm_i915_private *i915 = obj_to_i915(obj); - if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 71))) { + if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 74))) { switch (obj->pat_index) { case 0: return " WB"; case 1: return " WT"; diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index c7d7c3b7ecc638f433b6b018c8b9562bf09eb0d6..9ee902d5b72c491152d42f197da8cb85008b00bd 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -681,7 +681,8 @@ i915_print_iommu_status(struct drm_i915_private *i915, struct drm_printer *p) static void i915_welcome_messages(struct drm_i915_private *dev_priv) { if (drm_debug_enabled(DRM_UT_DRIVER)) { - struct drm_printer p = drm_debug_printer("i915 device info:"); + struct drm_printer p = drm_dbg_printer(&dev_priv->drm, DRM_UT_DRIVER, + "device info:"); struct intel_gt *gt; unsigned int i; @@ -1003,8 +1004,10 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_runtime_pm_disable(&i915->runtime_pm); intel_power_domains_disable(i915); + intel_fbdev_set_suspend(&i915->drm, FBINFO_STATE_SUSPENDED, true); if (HAS_DISPLAY(i915)) { drm_kms_helper_poll_disable(&i915->drm); + intel_display_driver_disable_user_access(i915); drm_atomic_helper_shutdown(&i915->drm); } @@ -1014,6 +1017,9 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_runtime_pm_disable_interrupts(i915); intel_hpd_cancel_work(i915); + if (HAS_DISPLAY(i915)) + intel_display_driver_suspend_access(i915); + intel_suspend_encoders(i915); intel_shutdown_encoders(i915); @@ -1080,8 +1086,11 @@ static int i915_drm_suspend(struct drm_device *dev) /* We do a lot of poking in a lot of registers, make sure they work * properly. */ intel_power_domains_disable(dev_priv); - if (HAS_DISPLAY(dev_priv)) + intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); + if (HAS_DISPLAY(dev_priv)) { drm_kms_helper_poll_disable(dev); + intel_display_driver_disable_user_access(dev_priv); + } pci_save_state(pdev); @@ -1092,6 +1101,9 @@ static int i915_drm_suspend(struct drm_device *dev) intel_runtime_pm_disable_interrupts(dev_priv); intel_hpd_cancel_work(dev_priv); + if (HAS_DISPLAY(dev_priv)) + intel_display_driver_suspend_access(dev_priv); + intel_suspend_encoders(dev_priv); /* Must be called before GGTT is suspended. */ @@ -1103,8 +1115,6 @@ static int i915_drm_suspend(struct drm_device *dev) opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold; intel_opregion_suspend(dev_priv, opregion_target_state); - intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); - dev_priv->suspend_count++; intel_dmc_suspend(dev_priv); @@ -1243,15 +1253,21 @@ static int i915_drm_resume(struct drm_device *dev) intel_display_driver_init_hw(dev_priv); intel_clock_gating_init(dev_priv); + + if (HAS_DISPLAY(dev_priv)) + intel_display_driver_resume_access(dev_priv); + intel_hpd_init(dev_priv); /* MST sideband requires HPD interrupts enabled */ intel_dp_mst_resume(dev_priv); intel_display_driver_resume(dev_priv); - intel_hpd_poll_disable(dev_priv); - if (HAS_DISPLAY(dev_priv)) + if (HAS_DISPLAY(dev_priv)) { + intel_display_driver_enable_user_access(dev_priv); drm_kms_helper_poll_enable(dev); + } + intel_hpd_poll_disable(dev_priv); intel_opregion_resume(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 861567362abd105c835c3d357f5d8cc2f0954998..e81b3b2858acccd3146fb9de2b93a897c511bf96 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -165,14 +165,6 @@ struct i915_gem_mm { struct notifier_block vmap_notifier; struct shrinker *shrinker; -#ifdef CONFIG_MMU_NOTIFIER - /** - * notifier_lock for mmu notifiers, memory may not be allocated - * while holding this lock. - */ - rwlock_t notifier_lock; -#endif - /* shrinker accounting, also useful for userland debugging */ u64 shrink_memory; u32 shrink_count; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 92758b6b41f011376d1f8cdf7ca1456d22b89f5e..1391c01d7663ee0d938b58cb32184b7f561d3d58 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -48,7 +48,6 @@ #include "gem/i915_gem_object_frontbuffer.h" #include "gem/i915_gem_pm.h" #include "gem/i915_gem_region.h" -#include "gem/i915_gem_userptr.h" #include "gt/intel_engine_user.h" #include "gt/intel_gt.h" #include "gt/intel_gt_pm.h" @@ -1165,10 +1164,6 @@ int i915_gem_init(struct drm_i915_private *dev_priv) if (intel_vgpu_active(dev_priv) && !intel_vgpu_has_huge_gtt(dev_priv)) RUNTIME_INFO(dev_priv)->page_sizes = I915_GTT_PAGE_SIZE_4K; - ret = i915_gem_init_userptr(dev_priv); - if (ret) - return ret; - for_each_gt(gt, dev_priv, i) { intel_uc_fetch_firmwares(>->uc); intel_wopcm_init(>->wopcm); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index d04660b60046370d436428e996e9634bb5e722cb..a0b784ebaddda4ee00518a40ebcbde24b4285465 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1157,7 +1157,7 @@ i915_vma_coredump_create(const struct intel_gt *gt, dma_addr_t offset = dma - mem->region.start; void __iomem *s; - if (offset + PAGE_SIZE > mem->io_size) { + if (offset + PAGE_SIZE > resource_size(&mem->io)) { ret = -EINVAL; break; } diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 2d695818f0062bc24819f89607e4964c58ae8804..bd9d812b1afa77ee02cd0324875157fe858e6a8a 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -3225,7 +3225,7 @@ u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915) struct intel_gt *gt = to_gt(i915); /* Wa_18013179988 */ - if (IS_DG2(i915) || IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) { + if (IS_DG2(i915) || IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) { intel_wakeref_t wakeref; u32 reg, shift; diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index 00871ef9979204efabec2a88e2a122c98e963547..3baa2f54a86ed8aa246381b858d3a513365c5694 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -502,7 +502,7 @@ static int query_memregion_info(struct drm_i915_private *i915, info.probed_size = mr->total; if (mr->type == INTEL_MEMORY_LOCAL) - info.probed_cpu_visible_size = mr->io_size; + info.probed_cpu_visible_size = resource_size(&mr->io); else info.probed_cpu_visible_size = mr->total; @@ -551,6 +551,38 @@ static int query_hwconfig_blob(struct drm_i915_private *i915, return hwconfig->size; } +static int +query_guc_submission_version(struct drm_i915_private *i915, + struct drm_i915_query_item *query) +{ + struct drm_i915_query_guc_submission_version __user *query_ptr = + u64_to_user_ptr(query->data_ptr); + struct drm_i915_query_guc_submission_version ver; + struct intel_guc *guc = &to_gt(i915)->uc.guc; + const size_t size = sizeof(ver); + int ret; + + if (!intel_uc_uses_guc_submission(&to_gt(i915)->uc)) + return -ENODEV; + + ret = copy_query_item(&ver, size, size, query); + if (ret != 0) + return ret; + + if (ver.branch || ver.major || ver.minor || ver.patch) + return -EINVAL; + + ver.branch = 0; + ver.major = guc->submission_version.major; + ver.minor = guc->submission_version.minor; + ver.patch = guc->submission_version.patch; + + if (copy_to_user(query_ptr, &ver, size)) + return -EFAULT; + + return 0; +} + static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv, struct drm_i915_query_item *query_item) = { query_topology_info, @@ -559,6 +591,7 @@ static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv, query_memregion_info, query_hwconfig_blob, query_geometry_subslices, + query_guc_submission_version, }; int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 27dc903f0553c0b47d8a066c1352aee0333092d5..e00557e1a57f0cc69ed71dd3dc0e29b8c06cebb1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3059,6 +3059,7 @@ #define MCURSOR_MODE_64_ARGB_AX (0x20 | MCURSOR_MODE_64_32B_AX) #define _CURABASE 0x70084 #define _CURAPOS 0x70088 +#define _CURAPOS_ERLY_TPT 0x7008c #define CURSOR_POS_Y_SIGN REG_BIT(31) #define CURSOR_POS_Y_MASK REG_GENMASK(30, 16) #define CURSOR_POS_Y(y) REG_FIELD_PREP(CURSOR_POS_Y_MASK, (y)) @@ -3087,6 +3088,7 @@ #define CURCNTR(pipe) _MMIO_CURSOR2(pipe, _CURACNTR) #define CURBASE(pipe) _MMIO_CURSOR2(pipe, _CURABASE) #define CURPOS(pipe) _MMIO_CURSOR2(pipe, _CURAPOS) +#define CURPOS_ERLY_TPT(pipe) _MMIO_CURSOR2(pipe, _CURAPOS_ERLY_TPT) #define CURSIZE(pipe) _MMIO_CURSOR2(pipe, _CURASIZE) #define CUR_FBC_CTL(pipe) _MMIO_CURSOR2(pipe, _CUR_FBC_CTL_A) #define CUR_CHICKEN(pipe) _MMIO_CURSOR2(pipe, _CUR_CHICKEN_A) @@ -5412,6 +5414,9 @@ #define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 #define GEN6_PCODE_DATA1 _MMIO(0x13812C) +#define MTL_PCODE_STOLEN_ACCESS _MMIO(0x138914) +#define STOLEN_ACCESS_ALLOWED 0x1 + /* IVYBRIDGE DPF */ #define GEN7_L3CDERRST1(slice) _MMIO(0xB008 + (slice) * 0x200) /* L3CD Error Status 1 */ #define GEN7_L3CDERRST1_ROW_MASK (0x7ff << 14) @@ -5652,6 +5657,10 @@ enum skl_power_gate { #define DP_TP_CTL_MODE_SST (0 << 27) #define DP_TP_CTL_MODE_MST (1 << 27) #define DP_TP_CTL_FORCE_ACT (1 << 25) +#define DP_TP_CTL_TRAIN_PAT4_SEL_MASK (3 << 19) +#define DP_TP_CTL_TRAIN_PAT4_SEL_TP4A (0 << 19) +#define DP_TP_CTL_TRAIN_PAT4_SEL_TP4B (1 << 19) +#define DP_TP_CTL_TRAIN_PAT4_SEL_TP4C (2 << 19) #define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1 << 18) #define DP_TP_CTL_FDI_AUTOTRAIN (1 << 15) #define DP_TP_CTL_LINK_TRAIN_MASK (7 << 8) @@ -5684,6 +5693,8 @@ enum skl_power_gate { /* Known as DDI_CTL_DE in MTL+ */ #define DDI_BUF_CTL(port) _MMIO_PORT(port, _DDI_BUF_CTL_A, _DDI_BUF_CTL_B) #define DDI_BUF_CTL_ENABLE (1 << 31) +#define XE2LPD_DDI_BUF_D2D_LINK_ENABLE REG_BIT(29) +#define XE2LPD_DDI_BUF_D2D_LINK_STATE REG_BIT(28) #define DDI_BUF_TRANS_SELECT(n) ((n) << 24) #define DDI_BUF_EMP_MASK (0xf << 24) #define DDI_BUF_PHY_LINK_RATE(r) ((r) << 20) @@ -6314,9 +6325,10 @@ enum skl_power_gate { #define GMS_MASK REG_GENMASK(15, 8) #define GGMS_MASK REG_GENMASK(7, 6) -#define GEN12_GSMBASE _MMIO(0x108100) -#define GEN12_DSMBASE _MMIO(0x1080C0) -#define GEN12_BDSM_MASK REG_GENMASK64(63, 20) +#define GEN6_GSMBASE _MMIO(0x108100) +#define GEN6_DSMBASE _MMIO(0x1080C0) +#define GEN6_BDSM_MASK REG_GENMASK64(31, 20) +#define GEN11_BDSM_MASK REG_GENMASK64(63, 20) #define XEHP_CLOCK_GATE_DIS _MMIO(0x101014) #define SGSI_SIDECLK_DIS REG_BIT(17) diff --git a/drivers/gpu/drm/i915/i915_syncmap.c b/drivers/gpu/drm/i915/i915_syncmap.c index 60404dbb2e9fa9f3484989cdfe34bacd202d0ca9..df6437c37373df20f6a93b71887eb82a015757bd 100644 --- a/drivers/gpu/drm/i915/i915_syncmap.c +++ b/drivers/gpu/drm/i915/i915_syncmap.c @@ -75,13 +75,10 @@ struct i915_syncmap { unsigned int height; unsigned int bitmap; struct i915_syncmap *parent; - /* - * Following this header is an array of either seqno or child pointers: - * union { - * u32 seqno[KSYNCMAP]; - * struct i915_syncmap *child[KSYNCMAP]; - * }; - */ + union { + DECLARE_FLEX_ARRAY(u32, seqno); + DECLARE_FLEX_ARRAY(struct i915_syncmap *, child); + }; }; /** @@ -99,13 +96,13 @@ void i915_syncmap_init(struct i915_syncmap **root) static inline u32 *__sync_seqno(struct i915_syncmap *p) { GEM_BUG_ON(p->height); - return (u32 *)(p + 1); + return p->seqno; } static inline struct i915_syncmap **__sync_child(struct i915_syncmap *p) { GEM_BUG_ON(!p->height); - return (struct i915_syncmap **)(p + 1); + return p->child; } static inline unsigned int @@ -200,7 +197,7 @@ __sync_alloc_leaf(struct i915_syncmap *parent, u64 id) { struct i915_syncmap *p; - p = kmalloc(sizeof(*p) + KSYNCMAP * sizeof(u32), GFP_KERNEL); + p = kmalloc(struct_size(p, seqno, KSYNCMAP), GFP_KERNEL); if (unlikely(!p)) return NULL; @@ -282,7 +279,7 @@ static noinline int __sync_set(struct i915_syncmap **root, u64 id, u32 seqno) unsigned int above; /* Insert a join above the current layer */ - next = kzalloc(sizeof(*next) + KSYNCMAP * sizeof(next), + next = kzalloc(struct_size(next, child, KSYNCMAP), GFP_KERNEL); if (unlikely(!next)) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_utils.c b/drivers/gpu/drm/i915/i915_utils.c index 29fd02bf5ea8c5d96eb904b2d9265a6c7259abc3..6f9e7b354b5441dbe518827ad6e48df99cdbccea 100644 --- a/drivers/gpu/drm/i915/i915_utils.c +++ b/drivers/gpu/drm/i915/i915_utils.c @@ -8,6 +8,7 @@ #include #include "i915_drv.h" +#include "i915_reg.h" #include "i915_utils.h" #define FDO_BUG_MSG "Please file a bug on drm/i915; see " FDO_BUG_URL " for details." @@ -125,3 +126,19 @@ bool i915_vtd_active(struct drm_i915_private *i915) /* Running as a guest, we assume the host is enforcing VT'd */ return i915_run_as_guest(); } + +bool i915_direct_stolen_access(struct drm_i915_private *i915) +{ + /* + * Wa_22018444074 + * + * Access via BAR can hang MTL, go directly to GSM/DSM, + * except for VM guests which won't have access to it. + * + * Normally this would not work but on MTL the system firmware + * should have relaxed the access permissions sufficiently. + * 0x138914==0x1 indicates that the firmware has done its job. + */ + return IS_METEORLAKE(i915) && !i915_run_as_guest() && + intel_uncore_read(&i915->uncore, MTL_PCODE_STOLEN_ACCESS) == STOLEN_ACCESS_ALLOWED; +} diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index f98577967b7fc91480d7355c9ace095a09f98573..b45ef0560611a8fc5653b6bb4237d12db806c55f 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -391,4 +391,6 @@ static inline bool i915_run_as_guest(void) bool i915_vtd_active(struct drm_i915_private *i915); +bool i915_direct_stolen_access(struct drm_i915_private *i915); + #endif /* !__I915_UTILS_H */ diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c index 60a03340bbd43f125c7ffd5e6e56cc6b2d3af90d..52d998e5c21adf8fb44b6ecc64bf45f6aa66f284 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.c +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -50,7 +50,7 @@ static int __iopagetest(struct intel_memory_region *mem, if (memchr_inv(result, value, sizeof(result))) { dev_err(mem->i915->drm.dev, "Failed to read back from memory region:%pR at [%pa + %pa] for %ps; wrote %x, read (%x, %x, %x)\n", - &mem->region, &mem->io_start, &offset, caller, + &mem->region, &mem->io.start, &offset, caller, value, result[0], result[1], result[2]); return -EINVAL; } @@ -67,11 +67,11 @@ static int iopagetest(struct intel_memory_region *mem, int err; int i; - va = ioremap_wc(mem->io_start + offset, PAGE_SIZE); + va = ioremap_wc(mem->io.start + offset, PAGE_SIZE); if (!va) { dev_err(mem->i915->drm.dev, "Failed to ioremap memory region [%pa + %pa] for %ps\n", - &mem->io_start, &offset, caller); + &mem->io.start, &offset, caller); return -EFAULT; } @@ -102,10 +102,10 @@ static int iomemtest(struct intel_memory_region *mem, resource_size_t last, page; int err; - if (mem->io_size < PAGE_SIZE) + if (resource_size(&mem->io) < PAGE_SIZE) return 0; - last = mem->io_size - PAGE_SIZE; + last = resource_size(&mem->io) - PAGE_SIZE; /* * Quick test to check read/write access to the iomap (backing store). @@ -207,7 +207,7 @@ static int intel_memory_region_memtest(struct intel_memory_region *mem, struct drm_i915_private *i915 = mem->i915; int err = 0; - if (!mem->io_start) + if (!mem->io.start) return 0; if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) || i915->params.memtest) @@ -252,8 +252,7 @@ intel_memory_region_create(struct drm_i915_private *i915, mem->i915 = i915; mem->region = DEFINE_RES_MEM(start, size); - mem->io_start = io_start; - mem->io_size = io_size; + mem->io = DEFINE_RES_MEM(io_start, io_size); mem->min_page_size = min_page_size; mem->ops = ops; mem->total = size; @@ -373,6 +372,24 @@ int intel_memory_regions_hw_probe(struct drm_i915_private *i915) i915->mm.regions[i] = mem; } + for (i = 0; i < ARRAY_SIZE(i915->mm.regions); i++) { + struct intel_memory_region *mem = i915->mm.regions[i]; + u64 region_size, io_size; + + if (!mem) + continue; + + region_size = resource_size(&mem->region) >> 20; + io_size = resource_size(&mem->io) >> 20; + + if (resource_size(&mem->io)) + drm_dbg(&i915->drm, "Memory region(%d): %s: %llu MiB %pR, io: %llu MiB %pR\n", + mem->id, mem->name, region_size, &mem->region, io_size, &mem->io); + else + drm_dbg(&i915->drm, "Memory region(%d): %s: %llu MiB %pR, io: n/a\n", + mem->id, mem->name, region_size, &mem->region); + } + return 0; out_cleanup: diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index 9ba36454e51b0a99c4b2dc76be07bdc118067ca1..40810cfb3fd9a2a1d5036525a3b122305fee3d9f 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -71,8 +71,7 @@ struct intel_memory_region { struct io_mapping iomap; struct resource region; - resource_size_t io_start; - resource_size_t io_size; + struct resource io; resource_size_t min_page_size; resource_size_t total; diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c index bf6097e7433d57757c8d0bf72a766e887bcc9807..04525d92bec5e782b7b3de54c1a4fe6db9e76036 100644 --- a/drivers/gpu/drm/i915/intel_region_ttm.c +++ b/drivers/gpu/drm/i915/intel_region_ttm.c @@ -87,7 +87,7 @@ int intel_region_ttm_init(struct intel_memory_region *mem) ret = i915_ttm_buddy_man_init(bdev, mem_type, false, resource_size(&mem->region), - mem->io_size, + resource_size(&mem->io), mem->min_page_size, PAGE_SIZE); if (ret) return ret; @@ -219,16 +219,16 @@ intel_region_ttm_resource_alloc(struct intel_memory_region *mem, goto out; } place.lpfn = place.fpfn + (size >> PAGE_SHIFT); - } else if (mem->io_size && mem->io_size < mem->total) { + } else if (resource_size(&mem->io) && resource_size(&mem->io) < mem->total) { if (flags & I915_BO_ALLOC_GPU_ONLY) { place.flags |= TTM_PL_FLAG_TOPDOWN; } else { place.fpfn = 0; - if (WARN_ON(overflows_type(mem->io_size >> PAGE_SHIFT, place.lpfn))) { + if (WARN_ON(overflows_type(resource_size(&mem->io) >> PAGE_SHIFT, place.lpfn))) { ret = -E2BIG; goto out; } - place.lpfn = mem->io_size >> PAGE_SHIFT; + place.lpfn = resource_size(&mem->io) >> PAGE_SHIFT; } } diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index dfefad5a5fec9e6fd1da6dd9bf9ec64905d8e958..76400e9c40f056a2059967b5cf960adbac112bd5 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1800,7 +1800,10 @@ static const struct intel_forcewake_range __mtl_fw_ranges[] = { GEN_FW_RANGE(0x24000, 0x2ffff, 0), /* 0x24000 - 0x2407f: always on 0x24080 - 0x2ffff: reserved */ - GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT) + GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT), + GEN_FW_RANGE(0x40000, 0x1901ef, 0), + GEN_FW_RANGE(0x1901f0, 0x1901f3, FORCEWAKE_GT) + /* FIXME: WA to wake GT while triggering H2G */ }; /* diff --git a/drivers/gpu/drm/i915/selftests/i915_active.c b/drivers/gpu/drm/i915/selftests/i915_active.c index b61fe850e92493e963bda07b2546cbaa28cf0202..0d89d70b9c362ab2e207e4e8b9f6697735b207fd 100644 --- a/drivers/gpu/drm/i915/selftests/i915_active.c +++ b/drivers/gpu/drm/i915/selftests/i915_active.c @@ -156,9 +156,9 @@ static int live_active_wait(void *arg) __i915_active_wait(&active->base, TASK_UNINTERRUPTIBLE); if (!READ_ONCE(active->retired)) { - struct drm_printer p = drm_err_printer(__func__); + struct drm_printer p = drm_err_printer(&i915->drm, __func__); - pr_err("i915_active not retired after waiting!\n"); + drm_printf(&p, "i915_active not retired after waiting!\n"); i915_active_print(&active->base, &p); err = -EINVAL; @@ -189,9 +189,9 @@ static int live_active_retire(void *arg) err = -EIO; if (!READ_ONCE(active->retired)) { - struct drm_printer p = drm_err_printer(__func__); + struct drm_printer p = drm_err_printer(&i915->drm, __func__); - pr_err("i915_active not retired after flushing!\n"); + drm_printf(&p, "i915_active not retired after flushing!\n"); i915_active_print(&active->base, &p); err = -EINVAL; diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c index d985d9bae2e8a5021891ec1c047a777e57f249e7..ae6070b5bf07a37badf10ec1794cf85bccf2a046 100644 --- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c +++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c @@ -544,8 +544,8 @@ static u64 igt_object_mappable_total(struct drm_i915_gem_object *obj) u64 start = drm_buddy_block_offset(block); u64 end = start + drm_buddy_block_size(mm, block); - if (start < mr->io_size) - total += min_t(u64, end, mr->io_size) - start; + if (start < resource_size(&mr->io)) + total += min_t(u64, end, resource_size(&mr->io)) - start; } return total; diff --git a/drivers/gpu/drm/i915/soc/intel_pch.c b/drivers/gpu/drm/i915/soc/intel_pch.c index 240beafb38ed96fe7c94996b9f1ad95af3e47bfe..3cad6dac06b01128afd25f8ef20a929c6899dcbc 100644 --- a/drivers/gpu/drm/i915/soc/intel_pch.c +++ b/drivers/gpu/drm/i915/soc/intel_pch.c @@ -140,11 +140,6 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) drm_WARN_ON(&dev_priv->drm, !IS_ALDERLAKE_S(dev_priv) && !IS_ALDERLAKE_P(dev_priv)); return PCH_ADP; - case INTEL_PCH_MTP_DEVICE_ID_TYPE: - case INTEL_PCH_MTP2_DEVICE_ID_TYPE: - drm_dbg_kms(&dev_priv->drm, "Found Meteor Lake PCH\n"); - drm_WARN_ON(&dev_priv->drm, !IS_METEORLAKE(dev_priv)); - return PCH_MTP; default: return PCH_NONE; } @@ -173,9 +168,7 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv, * make an educated guess as to which PCH is really there. */ - if (IS_METEORLAKE(dev_priv)) - id = INTEL_PCH_MTP_DEVICE_ID_TYPE; - else if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) + if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) id = INTEL_PCH_ADP_DEVICE_ID_TYPE; else if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) id = INTEL_PCH_TGP_DEVICE_ID_TYPE; @@ -225,6 +218,13 @@ void intel_detect_pch(struct drm_i915_private *dev_priv) if (DISPLAY_VER(dev_priv) >= 20) { dev_priv->pch_type = PCH_LNL; return; + } else if (IS_METEORLAKE(dev_priv)) { + /* + * Both north display and south display are on the SoC die. + * The real PCH is uninvolved in display. + */ + dev_priv->pch_type = PCH_MTL; + return; } else if (IS_DG2(dev_priv)) { dev_priv->pch_type = PCH_DG2; return; diff --git a/drivers/gpu/drm/i915/soc/intel_pch.h b/drivers/gpu/drm/i915/soc/intel_pch.h index 1b03ea60a7a87e28c2f5e1aa4c2dea3d675faa52..89e89ede265db787f450af0b2c58579aae0d0525 100644 --- a/drivers/gpu/drm/i915/soc/intel_pch.h +++ b/drivers/gpu/drm/i915/soc/intel_pch.h @@ -25,11 +25,11 @@ enum intel_pch { PCH_ICP, /* Ice Lake/Jasper Lake PCH */ PCH_TGP, /* Tiger Lake/Mule Creek Canyon PCH */ PCH_ADP, /* Alder Lake PCH */ - PCH_MTP, /* Meteor Lake PCH */ /* Fake PCHs, functionality handled on the same PCI dev */ PCH_DG1 = 1024, PCH_DG2, + PCH_MTL, PCH_LNL, }; @@ -59,16 +59,12 @@ enum intel_pch { #define INTEL_PCH_ADP2_DEVICE_ID_TYPE 0x5180 #define INTEL_PCH_ADP3_DEVICE_ID_TYPE 0x7A00 #define INTEL_PCH_ADP4_DEVICE_ID_TYPE 0x5480 -#define INTEL_PCH_MTP_DEVICE_ID_TYPE 0x7E00 -#define INTEL_PCH_MTP2_DEVICE_ID_TYPE 0xAE00 #define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 #define INTEL_PCH_P3X_DEVICE_ID_TYPE 0x7000 #define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ #define INTEL_PCH_TYPE(dev_priv) ((dev_priv)->pch_type) #define INTEL_PCH_ID(dev_priv) ((dev_priv)->pch_id) -#define HAS_PCH_LNL(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_LNL) -#define HAS_PCH_MTP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_MTP) #define HAS_PCH_DG2(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_DG2) #define HAS_PCH_ADP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_ADP) #define HAS_PCH_DG1(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_DG1) diff --git a/drivers/gpu/drm/imx/dcss/dcss-blkctl.c b/drivers/gpu/drm/imx/dcss/dcss-blkctl.c index c9b54bb2692d719e12b9c95afeaeb8c3fd6ac6c8..803e3fcdb50f18f71f9e1ab4dafc7f2c5a6d62e4 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-blkctl.c +++ b/drivers/gpu/drm/imx/dcss/dcss-blkctl.c @@ -42,14 +42,13 @@ int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base) { struct dcss_blkctl *blkctl; - blkctl = kzalloc(sizeof(*blkctl), GFP_KERNEL); + blkctl = devm_kzalloc(dcss->dev, sizeof(*blkctl), GFP_KERNEL); if (!blkctl) return -ENOMEM; - blkctl->base_reg = ioremap(blkctl_base, SZ_4K); + blkctl->base_reg = devm_ioremap(dcss->dev, blkctl_base, SZ_4K); if (!blkctl->base_reg) { dev_err(dcss->dev, "unable to remap BLK CTRL base\n"); - kfree(blkctl); return -ENOMEM; } @@ -60,11 +59,3 @@ int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base) return 0; } - -void dcss_blkctl_exit(struct dcss_blkctl *blkctl) -{ - if (blkctl->base_reg) - iounmap(blkctl->base_reg); - - kfree(blkctl); -} diff --git a/drivers/gpu/drm/imx/dcss/dcss-ctxld.c b/drivers/gpu/drm/imx/dcss/dcss-ctxld.c index 3a84cb3209c4ad03d6c43ab1e845da7fd2539590..e41d5c2a3ea4bf382e955ab1da068f10711cff7b 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-ctxld.c +++ b/drivers/gpu/drm/imx/dcss/dcss-ctxld.c @@ -202,7 +202,7 @@ int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base) struct dcss_ctxld *ctxld; int ret; - ctxld = kzalloc(sizeof(*ctxld), GFP_KERNEL); + ctxld = devm_kzalloc(dcss->dev, sizeof(*ctxld), GFP_KERNEL); if (!ctxld) return -ENOMEM; @@ -217,7 +217,7 @@ int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base) goto err; } - ctxld->ctxld_reg = ioremap(ctxld_base, SZ_4K); + ctxld->ctxld_reg = devm_ioremap(dcss->dev, ctxld_base, SZ_4K); if (!ctxld->ctxld_reg) { dev_err(dcss->dev, "ctxld: unable to remap ctxld base\n"); ret = -ENOMEM; @@ -226,18 +226,14 @@ int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base) ret = dcss_ctxld_irq_config(ctxld, to_platform_device(dcss->dev)); if (ret) - goto err_irq; + goto err; dcss_ctxld_hw_cfg(ctxld); return 0; -err_irq: - iounmap(ctxld->ctxld_reg); - err: dcss_ctxld_free_ctx(ctxld); - kfree(ctxld); return ret; } @@ -246,11 +242,7 @@ void dcss_ctxld_exit(struct dcss_ctxld *ctxld) { free_irq(ctxld->irq, ctxld); - if (ctxld->ctxld_reg) - iounmap(ctxld->ctxld_reg); - dcss_ctxld_free_ctx(ctxld); - kfree(ctxld); } static int dcss_ctxld_enable_locked(struct dcss_ctxld *ctxld) diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.c b/drivers/gpu/drm/imx/dcss/dcss-dev.c index 4f3af0dfb34499f6a502bf935a56e8c8956be75e..597e9b7bd4bfa4faf3864322af318835e95d0f80 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-dev.c +++ b/drivers/gpu/drm/imx/dcss/dcss-dev.c @@ -109,8 +109,6 @@ dtg_err: dcss_ctxld_exit(dcss->ctxld); ctxld_err: - dcss_blkctl_exit(dcss->blkctl); - dcss_clocks_disable(dcss); return ret; @@ -124,7 +122,6 @@ static void dcss_submodules_stop(struct dcss_dev *dcss) dcss_ss_exit(dcss->ss); dcss_dtg_exit(dcss->dtg); dcss_ctxld_exit(dcss->ctxld); - dcss_blkctl_exit(dcss->blkctl); dcss_clocks_disable(dcss); } @@ -170,6 +167,7 @@ struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output) struct resource *res; struct dcss_dev *dcss; const struct dcss_type_data *devtype; + resource_size_t res_len; devtype = of_device_get_match_data(dev); if (!devtype) { @@ -183,7 +181,13 @@ struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output) return ERR_PTR(-EINVAL); } - dcss = kzalloc(sizeof(*dcss), GFP_KERNEL); + res_len = res->end - res->start; + if (!devm_request_mem_region(dev, res->start, res_len, "dcss")) { + dev_err(dev, "cannot request memory region\n"); + return ERR_PTR(-EBUSY); + } + + dcss = devm_kzalloc(dev, sizeof(*dcss), GFP_KERNEL); if (!dcss) return ERR_PTR(-ENOMEM); @@ -194,7 +198,7 @@ struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output) ret = dcss_clks_init(dcss); if (ret) { dev_err(dev, "clocks initialization failed\n"); - goto err; + return ERR_PTR(ret); } dcss->of_port = of_graph_get_port_by_id(dev->of_node, 0); @@ -226,9 +230,6 @@ struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output) clks_err: dcss_clks_release(dcss); -err: - kfree(dcss); - return ERR_PTR(ret); } @@ -246,8 +247,6 @@ void dcss_dev_destroy(struct dcss_dev *dcss) dcss_submodules_stop(dcss); dcss_clks_release(dcss); - - kfree(dcss); } static int dcss_dev_suspend(struct device *dev) diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.h b/drivers/gpu/drm/imx/dcss/dcss-dev.h index f27b87c0959915322e31cde1b85d9fd3646c4a7c..b032e873d227ce3d25757fb43c1a623aaa7c9abb 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-dev.h +++ b/drivers/gpu/drm/imx/dcss/dcss-dev.h @@ -104,7 +104,6 @@ extern const struct dev_pm_ops dcss_dev_pm_ops; /* BLKCTL */ int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base); void dcss_blkctl_cfg(struct dcss_blkctl *blkctl); -void dcss_blkctl_exit(struct dcss_blkctl *blkctl); /* CTXLD */ int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base); diff --git a/drivers/gpu/drm/imx/dcss/dcss-dpr.c b/drivers/gpu/drm/imx/dcss/dcss-dpr.c index df9dab949bf2b8bc95f2c20073a643982b293004..072eb209249f46000fe3ae8c3a7d7a880ad5cc01 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-dpr.c +++ b/drivers/gpu/drm/imx/dcss/dcss-dpr.c @@ -135,7 +135,7 @@ static int dcss_dpr_ch_init_all(struct dcss_dpr *dpr, unsigned long dpr_base) ch->base_ofs = dpr_base + i * 0x1000; - ch->base_reg = ioremap(ch->base_ofs, SZ_4K); + ch->base_reg = devm_ioremap(dpr->dev, ch->base_ofs, SZ_4K); if (!ch->base_reg) { dev_err(dpr->dev, "dpr: unable to remap ch %d base\n", i); @@ -155,7 +155,7 @@ int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base) { struct dcss_dpr *dpr; - dpr = kzalloc(sizeof(*dpr), GFP_KERNEL); + dpr = devm_kzalloc(dcss->dev, sizeof(*dpr), GFP_KERNEL); if (!dpr) return -ENOMEM; @@ -164,18 +164,8 @@ int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base) dpr->ctxld = dcss->ctxld; dpr->ctx_id = CTX_SB_HP; - if (dcss_dpr_ch_init_all(dpr, dpr_base)) { - int i; - - for (i = 0; i < 3; i++) { - if (dpr->ch[i].base_reg) - iounmap(dpr->ch[i].base_reg); - } - - kfree(dpr); - + if (dcss_dpr_ch_init_all(dpr, dpr_base)) return -ENOMEM; - } return 0; } @@ -189,12 +179,7 @@ void dcss_dpr_exit(struct dcss_dpr *dpr) struct dcss_dpr_ch *ch = &dpr->ch[ch_no]; dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0); - - if (ch->base_reg) - iounmap(ch->base_reg); } - - kfree(dpr); } static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide, diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c index ad5f29ea8f6a156c3b7fc7022ecf723a83277ae7..d881f5a347608652b93fe2f77260266688b49d44 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-drv.c +++ b/drivers/gpu/drm/imx/dcss/dcss-drv.c @@ -51,15 +51,13 @@ static int dcss_drv_platform_probe(struct platform_device *pdev) of_node_put(remote); - mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL); + mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL); if (!mdrv) return -ENOMEM; mdrv->dcss = dcss_dev_create(dev, hdmi_output); - if (IS_ERR(mdrv->dcss)) { - err = PTR_ERR(mdrv->dcss); - goto err; - } + if (IS_ERR(mdrv->dcss)) + return PTR_ERR(mdrv->dcss); dev_set_drvdata(dev, mdrv); @@ -75,8 +73,6 @@ static int dcss_drv_platform_probe(struct platform_device *pdev) dcss_shutoff: dcss_dev_destroy(mdrv->dcss); -err: - kfree(mdrv); return err; } @@ -86,8 +82,6 @@ static void dcss_drv_platform_remove(struct platform_device *pdev) dcss_kms_detach(mdrv->kms); dcss_dev_destroy(mdrv->dcss); - - kfree(mdrv); } static void dcss_drv_platform_shutdown(struct platform_device *pdev) diff --git a/drivers/gpu/drm/imx/dcss/dcss-dtg.c b/drivers/gpu/drm/imx/dcss/dcss-dtg.c index 30de00540f63a3448968889d0bb325b35a39272e..2968f5d5bd412e2276f8724de8e0a49ea786fcc5 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-dtg.c +++ b/drivers/gpu/drm/imx/dcss/dcss-dtg.c @@ -152,7 +152,7 @@ int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base) int ret = 0; struct dcss_dtg *dtg; - dtg = kzalloc(sizeof(*dtg), GFP_KERNEL); + dtg = devm_kzalloc(dcss->dev, sizeof(*dtg), GFP_KERNEL); if (!dtg) return -ENOMEM; @@ -160,11 +160,10 @@ int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base) dtg->dev = dcss->dev; dtg->ctxld = dcss->ctxld; - dtg->base_reg = ioremap(dtg_base, SZ_4K); + dtg->base_reg = devm_ioremap(dtg->dev, dtg_base, SZ_4K); if (!dtg->base_reg) { - dev_err(dcss->dev, "dtg: unable to remap dtg base\n"); - ret = -ENOMEM; - goto err_ioremap; + dev_err(dtg->dev, "dtg: unable to remap dtg base\n"); + return -ENOMEM; } dtg->base_ofs = dtg_base; @@ -175,17 +174,7 @@ int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base) dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL | ((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK); - ret = dcss_dtg_irq_config(dtg, to_platform_device(dcss->dev)); - if (ret) - goto err_irq; - - return 0; - -err_irq: - iounmap(dtg->base_reg); - -err_ioremap: - kfree(dtg); + ret = dcss_dtg_irq_config(dtg, to_platform_device(dtg->dev)); return ret; } @@ -193,11 +182,6 @@ err_ioremap: void dcss_dtg_exit(struct dcss_dtg *dtg) { free_irq(dtg->ctxld_kick_irq, dtg); - - if (dtg->base_reg) - iounmap(dtg->base_reg); - - kfree(dtg); } void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm) diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c index 47852b9dd5eaa281471ef77df3c948802aefeea8..825728c356ffbebd598a2c4851512668b19c93a2 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c +++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c @@ -302,7 +302,7 @@ static int dcss_scaler_ch_init_all(struct dcss_scaler *scl, ch->base_ofs = scaler_base + i * 0x400; - ch->base_reg = ioremap(ch->base_ofs, SZ_4K); + ch->base_reg = devm_ioremap(scl->dev, ch->base_ofs, SZ_4K); if (!ch->base_reg) { dev_err(scl->dev, "scaler: unable to remap ch base\n"); return -ENOMEM; @@ -318,7 +318,7 @@ int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base) { struct dcss_scaler *scaler; - scaler = kzalloc(sizeof(*scaler), GFP_KERNEL); + scaler = devm_kzalloc(dcss->dev, sizeof(*scaler), GFP_KERNEL); if (!scaler) return -ENOMEM; @@ -327,18 +327,8 @@ int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base) scaler->ctxld = dcss->ctxld; scaler->ctx_id = CTX_SB_HP; - if (dcss_scaler_ch_init_all(scaler, scaler_base)) { - int i; - - for (i = 0; i < 3; i++) { - if (scaler->ch[i].base_reg) - iounmap(scaler->ch[i].base_reg); - } - - kfree(scaler); - + if (dcss_scaler_ch_init_all(scaler, scaler_base)) return -ENOMEM; - } return 0; } @@ -351,12 +341,7 @@ void dcss_scaler_exit(struct dcss_scaler *scl) struct dcss_scaler_ch *ch = &scl->ch[ch_no]; dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL); - - if (ch->base_reg) - iounmap(ch->base_reg); } - - kfree(scl); } void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en) diff --git a/drivers/gpu/drm/imx/dcss/dcss-ss.c b/drivers/gpu/drm/imx/dcss/dcss-ss.c index 8ddf08da911b7ecafd2d7287ca7d78ef255add72..0df81866fb7b9895802ac4bf9ccc17892c95b40f 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-ss.c +++ b/drivers/gpu/drm/imx/dcss/dcss-ss.c @@ -83,7 +83,7 @@ int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base) { struct dcss_ss *ss; - ss = kzalloc(sizeof(*ss), GFP_KERNEL); + ss = devm_kzalloc(dcss->dev, sizeof(*ss), GFP_KERNEL); if (!ss) return -ENOMEM; @@ -91,10 +91,9 @@ int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base) ss->dev = dcss->dev; ss->ctxld = dcss->ctxld; - ss->base_reg = ioremap(ss_base, SZ_4K); + ss->base_reg = devm_ioremap(ss->dev, ss_base, SZ_4K); if (!ss->base_reg) { - dev_err(dcss->dev, "ss: unable to remap ss base\n"); - kfree(ss); + dev_err(ss->dev, "ss: unable to remap ss base\n"); return -ENOMEM; } @@ -108,11 +107,6 @@ void dcss_ss_exit(struct dcss_ss *ss) { /* stop SS */ dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL); - - if (ss->base_reg) - iounmap(ss->base_reg); - - kfree(ss); } void dcss_ss_subsam_set(struct dcss_ss *ss) diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c index 53840ab054c725bb7648419a8391e70992062dd8..71d70194fcbd5efbebab41e896b629b88a250ef3 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c @@ -655,7 +655,7 @@ static int imx_ldb_probe(struct platform_device *pdev) for (i = 0; i < 4; i++) { char clkname[16]; - sprintf(clkname, "di%d_sel", i); + snprintf(clkname, sizeof(clkname), "di%d_sel", i); imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev, clkname); if (IS_ERR(imx_ldb->clk_sel[i])) { ret = PTR_ERR(imx_ldb->clk_sel[i]); diff --git a/drivers/gpu/drm/ingenic/Kconfig b/drivers/gpu/drm/ingenic/Kconfig index b440e0cdc05794f566ea2cecc25d8834be45ff2b..3db117c5edd9161b83d85dd1d195856902de2648 100644 --- a/drivers/gpu/drm/ingenic/Kconfig +++ b/drivers/gpu/drm/ingenic/Kconfig @@ -11,7 +11,6 @@ config DRM_INGENIC select DRM_GEM_DMA_HELPER select REGMAP select REGMAP_MMIO - select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE help Choose this option for DRM support for the Ingenic SoCs. diff --git a/drivers/gpu/drm/lima/lima_ctx.c b/drivers/gpu/drm/lima/lima_ctx.c index 8389f2d7d021fb69ee75acd070883e7edad8498d..0e668fc1e0f9e7823cc406346662e56013ff6bfc 100644 --- a/drivers/gpu/drm/lima/lima_ctx.c +++ b/drivers/gpu/drm/lima/lima_ctx.c @@ -19,7 +19,7 @@ int lima_ctx_create(struct lima_device *dev, struct lima_ctx_mgr *mgr, u32 *id) kref_init(&ctx->refcnt); for (i = 0; i < lima_pipe_num; i++) { - err = lima_sched_context_init(dev->pipe + i, ctx->context + i, &ctx->guilty); + err = lima_sched_context_init(dev->pipe + i, ctx->context + i); if (err) goto err_out0; } diff --git a/drivers/gpu/drm/lima/lima_ctx.h b/drivers/gpu/drm/lima/lima_ctx.h index 74e2be09090f65ef24872c6c534ff0a419c17e88..5b1063ce968bd3263669252bb78fa30004b60407 100644 --- a/drivers/gpu/drm/lima/lima_ctx.h +++ b/drivers/gpu/drm/lima/lima_ctx.h @@ -13,7 +13,6 @@ struct lima_ctx { struct kref refcnt; struct lima_device *dev; struct lima_sched_context context[lima_pipe_num]; - atomic_t guilty; /* debug info */ char pname[TASK_COMM_LEN]; diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c index 4f9736e5f929beecb84d2abee435ff64baa1bb25..7ea244d876ca63ccd1a91ba934d6f8871a3ac6ad 100644 --- a/drivers/gpu/drm/lima/lima_gem.c +++ b/drivers/gpu/drm/lima/lima_gem.c @@ -75,29 +75,34 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm) } else { bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL); if (!bo->base.sgt) { - sg_free_table(&sgt); - return -ENOMEM; + ret = -ENOMEM; + goto err_out0; } } ret = dma_map_sgtable(dev, &sgt, DMA_BIDIRECTIONAL, 0); - if (ret) { - sg_free_table(&sgt); - kfree(bo->base.sgt); - bo->base.sgt = NULL; - return ret; - } + if (ret) + goto err_out1; *bo->base.sgt = sgt; if (vm) { ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT); if (ret) - return ret; + goto err_out2; } bo->heap_size = new_size; return 0; + +err_out2: + dma_unmap_sgtable(dev, &sgt, DMA_BIDIRECTIONAL, 0); +err_out1: + kfree(bo->base.sgt); + bo->base.sgt = NULL; +err_out0: + sg_free_table(&sgt); + return ret; } int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c index 8dd501b7a3d0d8bd3656429c2508e0f937f66e04..6b354e2fb61d43438becf1483ab71ac16bf8dbed 100644 --- a/drivers/gpu/drm/lima/lima_gp.c +++ b/drivers/gpu/drm/lima/lima_gp.c @@ -34,11 +34,11 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data) if (state & LIMA_GP_IRQ_MASK_ERROR) { if ((state & LIMA_GP_IRQ_MASK_ERROR) == LIMA_GP_IRQ_PLBU_OUT_OF_MEM) { - dev_dbg(dev->dev, "gp out of heap irq status=%x\n", - status); + dev_dbg(dev->dev, "%s out of heap irq status=%x\n", + lima_ip_name(ip), status); } else { - dev_err(dev->dev, "gp error irq state=%x status=%x\n", - state, status); + dev_err(dev->dev, "%s error irq state=%x status=%x\n", + lima_ip_name(ip), state, status); if (task) task->recoverable = false; } @@ -89,7 +89,8 @@ static int lima_gp_soft_reset_async_wait(struct lima_ip *ip) v & LIMA_GP_IRQ_RESET_COMPLETED, 0, 100); if (err) { - dev_err(dev->dev, "gp soft reset time out\n"); + dev_err(dev->dev, "%s soft reset time out\n", + lima_ip_name(ip)); return err; } @@ -166,6 +167,11 @@ static void lima_gp_task_run(struct lima_sched_pipe *pipe, gp_write(LIMA_GP_CMD, cmd); } +static int lima_gp_bus_stop_poll(struct lima_ip *ip) +{ + return !!(gp_read(LIMA_GP_STATUS) & LIMA_GP_STATUS_BUS_STOPPED); +} + static int lima_gp_hard_reset_poll(struct lima_ip *ip) { gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC01A0000); @@ -179,16 +185,30 @@ static int lima_gp_hard_reset(struct lima_ip *ip) gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC0FFE000); gp_write(LIMA_GP_INT_MASK, 0); + + gp_write(LIMA_GP_CMD, LIMA_GP_CMD_STOP_BUS); + ret = lima_poll_timeout(ip, lima_gp_bus_stop_poll, 10, 100); + if (ret) { + dev_err(dev->dev, "%s bus stop timeout\n", lima_ip_name(ip)); + return ret; + } gp_write(LIMA_GP_CMD, LIMA_GP_CMD_RESET); ret = lima_poll_timeout(ip, lima_gp_hard_reset_poll, 10, 100); if (ret) { - dev_err(dev->dev, "gp hard reset timeout\n"); + dev_err(dev->dev, "%s hard reset timeout\n", lima_ip_name(ip)); return ret; } gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0); gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL); gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); + + /* + * if there was an async soft reset queued, + * don't wait for it in the next job + */ + ip->data.async_reset = false; + return 0; } @@ -201,8 +221,9 @@ static void lima_gp_task_error(struct lima_sched_pipe *pipe) { struct lima_ip *ip = pipe->processor[0]; - dev_err(ip->dev->dev, "gp task error int_state=%x status=%x\n", - gp_read(LIMA_GP_INT_STAT), gp_read(LIMA_GP_STATUS)); + dev_err(ip->dev->dev, "%s task error int_state=%x status=%x\n", + lima_ip_name(ip), gp_read(LIMA_GP_INT_STAT), + gp_read(LIMA_GP_STATUS)); lima_gp_hard_reset(ip); } @@ -305,7 +326,7 @@ int lima_gp_init(struct lima_ip *ip) err = devm_request_irq(dev->dev, ip->irq, lima_gp_irq_handler, IRQF_SHARED, lima_ip_name(ip), ip); if (err) { - dev_err(dev->dev, "gp %s fail to request irq\n", + dev_err(dev->dev, "%s fail to request irq\n", lima_ip_name(ip)); return err; } diff --git a/drivers/gpu/drm/lima/lima_l2_cache.c b/drivers/gpu/drm/lima/lima_l2_cache.c index c4080a02957ba808307d31190babae70ed116aa1..184106ce55f8cd01c62a731fc88c18a8fe2cdf31 100644 --- a/drivers/gpu/drm/lima/lima_l2_cache.c +++ b/drivers/gpu/drm/lima/lima_l2_cache.c @@ -21,7 +21,8 @@ static int lima_l2_cache_wait_idle(struct lima_ip *ip) !(v & LIMA_L2_CACHE_STATUS_COMMAND_BUSY), 0, 1000); if (err) { - dev_err(dev->dev, "l2 cache wait command timeout\n"); + dev_err(dev->dev, "%s wait command timeout\n", + lima_ip_name(ip)); return err; } return 0; @@ -83,7 +84,8 @@ int lima_l2_cache_init(struct lima_ip *ip) spin_lock_init(&ip->data.lock); size = l2_cache_read(LIMA_L2_CACHE_SIZE); - dev_info(dev->dev, "l2 cache %uK, %u-way, %ubyte cache line, %ubit external bus\n", + dev_info(dev->dev, "%s %uK, %u-way, %ubyte cache line, %ubit external bus\n", + lima_ip_name(ip), 1 << (((size >> 16) & 0xff) - 10), 1 << ((size >> 8) & 0xff), 1 << (size & 0xff), diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c index a1ae6c252dc2b546bad5f12226cad197ff006808..e18317c5ca8c19eafc32f8b4e4950f5a7d414a3d 100644 --- a/drivers/gpu/drm/lima/lima_mmu.c +++ b/drivers/gpu/drm/lima/lima_mmu.c @@ -22,7 +22,8 @@ cond, 0, 100); \ if (__ret) \ dev_err(dev->dev, \ - "mmu command %x timeout\n", cmd); \ + "%s command %x timeout\n", \ + lima_ip_name(ip), cmd); \ __ret; \ }) @@ -40,14 +41,13 @@ static irqreturn_t lima_mmu_irq_handler(int irq, void *data) if (status & LIMA_MMU_INT_PAGE_FAULT) { u32 fault = mmu_read(LIMA_MMU_PAGE_FAULT_ADDR); - dev_err(dev->dev, "mmu page fault at 0x%x from bus id %d of type %s on %s\n", - fault, LIMA_MMU_STATUS_BUS_ID(status), - status & LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE ? "write" : "read", - lima_ip_name(ip)); + dev_err(dev->dev, "%s page fault at 0x%x from bus id %d of type %s\n", + lima_ip_name(ip), fault, LIMA_MMU_STATUS_BUS_ID(status), + status & LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE ? "write" : "read"); } if (status & LIMA_MMU_INT_READ_BUS_ERROR) - dev_err(dev->dev, "mmu %s irq bus error\n", lima_ip_name(ip)); + dev_err(dev->dev, "%s irq bus error\n", lima_ip_name(ip)); /* mask all interrupts before resume */ mmu_write(LIMA_MMU_INT_MASK, 0); @@ -102,14 +102,14 @@ int lima_mmu_init(struct lima_ip *ip) mmu_write(LIMA_MMU_DTE_ADDR, 0xCAFEBABE); if (mmu_read(LIMA_MMU_DTE_ADDR) != 0xCAFEB000) { - dev_err(dev->dev, "mmu %s dte write test fail\n", lima_ip_name(ip)); + dev_err(dev->dev, "%s dte write test fail\n", lima_ip_name(ip)); return -EIO; } err = devm_request_irq(dev->dev, ip->irq, lima_mmu_irq_handler, IRQF_SHARED, lima_ip_name(ip), ip); if (err) { - dev_err(dev->dev, "mmu %s fail to request irq\n", lima_ip_name(ip)); + dev_err(dev->dev, "%s fail to request irq\n", lima_ip_name(ip)); return err; } @@ -152,7 +152,7 @@ void lima_mmu_page_fault_resume(struct lima_ip *ip) u32 v; if (status & LIMA_MMU_STATUS_PAGE_FAULT_ACTIVE) { - dev_info(dev->dev, "mmu resume\n"); + dev_info(dev->dev, "%s resume\n", lima_ip_name(ip)); mmu_write(LIMA_MMU_INT_MASK, 0); mmu_write(LIMA_MMU_DTE_ADDR, 0xCAFEBABE); diff --git a/drivers/gpu/drm/lima/lima_pmu.c b/drivers/gpu/drm/lima/lima_pmu.c index e397e1146e96314808b4964576fc419988b11053..113cb9b215cd4678bf45367110de849041b6dd75 100644 --- a/drivers/gpu/drm/lima/lima_pmu.c +++ b/drivers/gpu/drm/lima/lima_pmu.c @@ -21,7 +21,8 @@ static int lima_pmu_wait_cmd(struct lima_ip *ip) v, v & LIMA_PMU_INT_CMD_MASK, 100, 100000); if (err) { - dev_err(dev->dev, "timeout wait pmu cmd\n"); + dev_err(dev->dev, "%s timeout wait pmu cmd\n", + lima_ip_name(ip)); return err; } diff --git a/drivers/gpu/drm/lima/lima_pp.c b/drivers/gpu/drm/lima/lima_pp.c index a5c95bed08c09c580795b67327295d40357dddec..d0d2db0ef1ce8060e704d7d0ab2a6637f7750f4f 100644 --- a/drivers/gpu/drm/lima/lima_pp.c +++ b/drivers/gpu/drm/lima/lima_pp.c @@ -26,8 +26,8 @@ static void lima_pp_handle_irq(struct lima_ip *ip, u32 state) if (state & LIMA_PP_IRQ_MASK_ERROR) { u32 status = pp_read(LIMA_PP_STATUS); - dev_err(dev->dev, "pp error irq state=%x status=%x\n", - state, status); + dev_err(dev->dev, "%s error irq state=%x status=%x\n", + lima_ip_name(ip), state, status); pipe->error = true; @@ -125,7 +125,7 @@ static int lima_pp_soft_reset_async_wait_one(struct lima_ip *ip) ret = lima_poll_timeout(ip, lima_pp_soft_reset_poll, 0, 100); if (ret) { - dev_err(dev->dev, "pp %s reset time out\n", lima_ip_name(ip)); + dev_err(dev->dev, "%s reset time out\n", lima_ip_name(ip)); return ret; } @@ -168,6 +168,11 @@ static void lima_pp_write_frame(struct lima_ip *ip, u32 *frame, u32 *wb) } } +static int lima_pp_bus_stop_poll(struct lima_ip *ip) +{ + return !!(pp_read(LIMA_PP_STATUS) & LIMA_PP_STATUS_BUS_STOPPED); +} + static int lima_pp_hard_reset_poll(struct lima_ip *ip) { pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0xC01A0000); @@ -181,16 +186,31 @@ static int lima_pp_hard_reset(struct lima_ip *ip) pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0xC0FFE000); pp_write(LIMA_PP_INT_MASK, 0); + + pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_STOP_BUS); + ret = lima_poll_timeout(ip, lima_pp_bus_stop_poll, 10, 100); + if (ret) { + dev_err(dev->dev, "%s bus stop timeout\n", lima_ip_name(ip)); + return ret; + } + pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_FORCE_RESET); ret = lima_poll_timeout(ip, lima_pp_hard_reset_poll, 10, 100); if (ret) { - dev_err(dev->dev, "pp hard reset timeout\n"); + dev_err(dev->dev, "%s hard reset timeout\n", lima_ip_name(ip)); return ret; } pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0); pp_write(LIMA_PP_INT_CLEAR, LIMA_PP_IRQ_MASK_ALL); pp_write(LIMA_PP_INT_MASK, LIMA_PP_IRQ_MASK_USED); + + /* + * if there was an async soft reset queued, + * don't wait for it in the next job + */ + ip->data.async_reset = false; + return 0; } @@ -254,7 +274,7 @@ int lima_pp_init(struct lima_ip *ip) err = devm_request_irq(dev->dev, ip->irq, lima_pp_irq_handler, IRQF_SHARED, lima_ip_name(ip), ip); if (err) { - dev_err(dev->dev, "pp %s fail to request irq\n", + dev_err(dev->dev, "%s fail to request irq\n", lima_ip_name(ip)); return err; } @@ -289,7 +309,7 @@ int lima_pp_bcast_init(struct lima_ip *ip) err = devm_request_irq(dev->dev, ip->irq, lima_pp_bcast_irq_handler, IRQF_SHARED, lima_ip_name(ip), ip); if (err) { - dev_err(dev->dev, "pp %s fail to request irq\n", + dev_err(dev->dev, "%s fail to request irq\n", lima_ip_name(ip)); return err; } @@ -403,8 +423,9 @@ static void lima_pp_task_error(struct lima_sched_pipe *pipe) for (i = 0; i < pipe->num_processor; i++) { struct lima_ip *ip = pipe->processor[i]; - dev_err(ip->dev->dev, "pp task error %d int_state=%x status=%x\n", - i, pp_read(LIMA_PP_INT_STATUS), pp_read(LIMA_PP_STATUS)); + dev_err(ip->dev->dev, "%s task error %d int_state=%x status=%x\n", + lima_ip_name(ip), i, pp_read(LIMA_PP_INT_STATUS), + pp_read(LIMA_PP_STATUS)); lima_pp_hard_reset(ip); } diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index c3bf8cda84982c89232900ac1fe14a6166139f9d..00b19adfc8881a1bffaa61781bf50dc1b5ecf33e 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /* Copyright 2017-2019 Qiang Yu */ +#include #include #include #include @@ -153,13 +154,12 @@ void lima_sched_task_fini(struct lima_sched_task *task) } int lima_sched_context_init(struct lima_sched_pipe *pipe, - struct lima_sched_context *context, - atomic_t *guilty) + struct lima_sched_context *context) { struct drm_gpu_scheduler *sched = &pipe->base; return drm_sched_entity_init(&context->base, DRM_SCHED_PRIORITY_NORMAL, - &sched, 1, guilty); + &sched, 1, NULL); } void lima_sched_context_fini(struct lima_sched_pipe *pipe, @@ -401,9 +401,35 @@ static enum drm_gpu_sched_stat lima_sched_timedout_job(struct drm_sched_job *job struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); struct lima_sched_task *task = to_lima_task(job); struct lima_device *ldev = pipe->ldev; + struct lima_ip *ip = pipe->processor[0]; + int i; + + /* + * If the GPU managed to complete this jobs fence, the timeout is + * spurious. Bail out. + */ + if (dma_fence_is_signaled(task->fence)) { + DRM_WARN("%s spurious timeout\n", lima_ip_name(ip)); + return DRM_GPU_SCHED_STAT_NOMINAL; + } + + /* + * Lima IRQ handler may take a long time to process an interrupt + * if there is another IRQ handler hogging the processing. + * In order to catch such cases and not report spurious Lima job + * timeouts, synchronize the IRQ handler and re-check the fence + * status. + */ + for (i = 0; i < pipe->num_processor; i++) + synchronize_irq(pipe->processor[i]->irq); + + if (dma_fence_is_signaled(task->fence)) { + DRM_WARN("%s unexpectedly high interrupt latency\n", lima_ip_name(ip)); + return DRM_GPU_SCHED_STAT_NOMINAL; + } if (!pipe->error) - DRM_ERROR("lima job timeout\n"); + DRM_ERROR("%s job timeout\n", lima_ip_name(ip)); drm_sched_stop(&pipe->base, &task->base); @@ -417,8 +443,6 @@ static enum drm_gpu_sched_stat lima_sched_timedout_job(struct drm_sched_job *job if (pipe->bcast_mmu) lima_mmu_page_fault_resume(pipe->bcast_mmu); else { - int i; - for (i = 0; i < pipe->num_mmu; i++) lima_mmu_page_fault_resume(pipe->mmu[i]); } @@ -481,7 +505,7 @@ static void lima_sched_recover_work(struct work_struct *work) int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) { unsigned int timeout = lima_sched_timeout_ms > 0 ? - lima_sched_timeout_ms : 500; + lima_sched_timeout_ms : 10000; pipe->fence_context = dma_fence_context_alloc(1); spin_lock_init(&pipe->fence_lock); diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h index 6a11764d87b389ad24f10746e2de7f2ff3126d2d..6bd4f3b70109133d494d3f5f9cb1019ab6e207f8 100644 --- a/drivers/gpu/drm/lima/lima_sched.h +++ b/drivers/gpu/drm/lima/lima_sched.h @@ -91,8 +91,7 @@ int lima_sched_task_init(struct lima_sched_task *task, void lima_sched_task_fini(struct lima_sched_task *task); int lima_sched_context_init(struct lima_sched_pipe *pipe, - struct lima_sched_context *context, - atomic_t *guilty); + struct lima_sched_context *context); void lima_sched_context_fini(struct lima_sched_pipe *pipe, struct lima_sched_context *context); struct dma_fence *lima_sched_context_queue_task(struct lima_sched_task *task); diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c index 89ccc0c431690f7d458e999b464924b0af1b8107..d8ff60b46abe6e6f46d2b04935c2fc11ced6beb0 100644 --- a/drivers/gpu/drm/loongson/lsdc_drv.c +++ b/drivers/gpu/drm/loongson/lsdc_drv.c @@ -184,7 +184,7 @@ static int lsdc_get_dedicated_vram(struct lsdc_device *ldev, drm_info(ddev, "Dedicated vram start: 0x%llx, size: %uMiB\n", (u64)base, (u32)(size >> 20)); - return 0; + return (size > SZ_1M) ? 0 : -ENODEV; } static struct lsdc_device * diff --git a/drivers/gpu/drm/loongson/lsdc_ttm.c b/drivers/gpu/drm/loongson/lsdc_ttm.c index bf79dc55afa49c1dc1dbfe70fa35936895921cbb..465f622ac05db72731dd9d33ead7d3fc414d17ff 100644 --- a/drivers/gpu/drm/loongson/lsdc_ttm.c +++ b/drivers/gpu/drm/loongson/lsdc_ttm.c @@ -54,7 +54,6 @@ static void lsdc_bo_set_placement(struct lsdc_bo *lbo, u32 domain) pflags |= TTM_PL_FLAG_TOPDOWN; lbo->placement.placement = lbo->placements; - lbo->placement.busy_placement = lbo->placements; if (domain & LSDC_GEM_DOMAIN_VRAM) { lbo->placements[c].mem_type = TTM_PL_VRAM; @@ -77,7 +76,6 @@ static void lsdc_bo_set_placement(struct lsdc_bo *lbo, u32 domain) } lbo->placement.num_placement = c; - lbo->placement.num_busy_placement = c; for (i = 0; i < c; ++i) { lbo->placements[i].fpfn = 0; diff --git a/drivers/gpu/drm/mcde/Kconfig b/drivers/gpu/drm/mcde/Kconfig index 4f3d68e11bc123a1bf35661446ea8ba974b9a159..907460b69d4f527481de1ec3dfc277b233a811f7 100644 --- a/drivers/gpu/drm/mcde/Kconfig +++ b/drivers/gpu/drm/mcde/Kconfig @@ -11,7 +11,6 @@ config DRM_MCDE select DRM_PANEL_BRIDGE select DRM_KMS_HELPER select DRM_GEM_DMA_HELPER - select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE help Choose this option for DRM support for the ST-Ericsson MCDE Multi-Channel Display Engine. diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index 2136a596efa18570b4f171da92a340991048880e..0ba72102636aa8c66288fa919d7d3a1144fdb898 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2042,12 +2042,12 @@ static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge) return ret; } -static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *mtk_dp_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge); bool enabled = mtk_dp->enabled; - struct edid *new_edid = NULL; + const struct drm_edid *drm_edid; struct mtk_dp_audio_cfg *audio_caps = &mtk_dp->info.audio_cur_cfg; if (!enabled) { @@ -2055,7 +2055,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, mtk_dp_aux_panel_poweron(mtk_dp, true); } - new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc); + drm_edid = drm_edid_read_ddc(connector, &mtk_dp->aux.ddc); /* * Parse capability here to let atomic_get_input_bus_fmts and @@ -2063,17 +2063,26 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, */ if (mtk_dp_parse_capabilities(mtk_dp)) { drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n"); - kfree(new_edid); - new_edid = NULL; + drm_edid_free(drm_edid); + drm_edid = NULL; } - if (new_edid) { + if (drm_edid) { + /* + * FIXME: get rid of drm_edid_raw() + */ + const struct edid *edid = drm_edid_raw(drm_edid); struct cea_sad *sads; - audio_caps->sad_count = drm_edid_to_sad(new_edid, &sads); + audio_caps->sad_count = drm_edid_to_sad(edid, &sads); kfree(sads); - audio_caps->detect_monitor = drm_detect_monitor_audio(new_edid); + /* + * FIXME: This should use connector->display_info.has_audio from + * a path that has read the EDID and called + * drm_edid_connector_update(). + */ + audio_caps->detect_monitor = drm_detect_monitor_audio(edid); } if (!enabled) { @@ -2081,7 +2090,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, drm_atomic_bridge_chain_post_disable(bridge, connector->state->state); } - return new_edid; + return drm_edid; } static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux, @@ -2433,7 +2442,7 @@ static const struct drm_bridge_funcs mtk_dp_bridge_funcs = { .atomic_enable = mtk_dp_bridge_atomic_enable, .atomic_disable = mtk_dp_bridge_atomic_disable, .mode_valid = mtk_dp_bridge_mode_valid, - .get_edid = mtk_dp_get_edid, + .edid_read = mtk_dp_edid_read, .detect = mtk_dp_bdg_detect, }; diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 86133bf16326b1c42c2ac9bbf4447e925c860536..c6bdc565e4a90ee481315f4c59548ae17357645f 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1265,19 +1265,27 @@ static enum drm_connector_status mtk_hdmi_bridge_detect(struct drm_bridge *bridg return mtk_hdmi_detect(hdmi); } -static struct edid *mtk_hdmi_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *mtk_hdmi_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge); - struct edid *edid; + const struct drm_edid *drm_edid; if (!hdmi->ddc_adpt) return NULL; - edid = drm_get_edid(connector, hdmi->ddc_adpt); - if (!edid) - return NULL; - hdmi->dvi_mode = !drm_detect_monitor_audio(edid); - return edid; + drm_edid = drm_edid_read_ddc(connector, hdmi->ddc_adpt); + if (drm_edid) { + /* + * FIXME: This should use !connector->display_info.has_audio (or + * !connector->display_info.is_hdmi) from a path that has read + * the EDID and called drm_edid_connector_update(). + */ + const struct edid *edid = drm_edid_raw(drm_edid); + + hdmi->dvi_mode = !drm_detect_monitor_audio(edid); + } + + return drm_edid; } static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge, @@ -1417,7 +1425,7 @@ static const struct drm_bridge_funcs mtk_hdmi_bridge_funcs = { .atomic_pre_enable = mtk_hdmi_bridge_atomic_pre_enable, .atomic_enable = mtk_hdmi_bridge_atomic_enable, .detect = mtk_hdmi_bridge_detect, - .get_edid = mtk_hdmi_bridge_get_edid, + .edid_read = mtk_hdmi_bridge_edid_read, }; static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index 25ea765586908f14d08715f45ca9def85a6a07f3..fff6ce394f98d991450632a392a801ca134f18a6 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -323,19 +323,31 @@ static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge, enum drm_connector_status status) { struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); - struct edid *edid; if (!encoder_hdmi->cec_notifier) return; if (status == connector_status_connected) { - edid = drm_bridge_get_edid(encoder_hdmi->next_bridge, encoder_hdmi->connector); - if (!edid) + const struct drm_edid *drm_edid; + const struct edid *edid; + + drm_edid = drm_bridge_edid_read(encoder_hdmi->next_bridge, + encoder_hdmi->connector); + if (!drm_edid) return; + /* + * FIXME: The CEC physical address should be set using + * cec_notifier_set_phys_addr(encoder_hdmi->cec_notifier, + * connector->display_info.source_physical_address) from a path + * that has read the EDID and called + * drm_edid_connector_update(). + */ + edid = drm_edid_raw(drm_edid); + cec_notifier_set_phys_addr_from_edid(encoder_hdmi->cec_notifier, edid); - kfree(edid); + drm_edid_free(drm_edid); } else cec_notifier_phys_addr_invalidate(encoder_hdmi->cec_notifier); } diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 2fb18b782b05366fd549ac3fc6d9ede24364ed22..54fce00e2136e08de31680ac8d2f416ca1b4b281 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -146,14 +146,13 @@ int mgag200_device_preinit(struct mga_device *mdev) } mdev->vram_res = res; - /* Don't fail on errors, but performance might be reduced. */ - devm_arch_io_reserve_memtype_wc(dev->dev, res->start, resource_size(res)); - devm_arch_phys_wc_add(dev->dev, res->start, resource_size(res)); - - mdev->vram = devm_ioremap(dev->dev, res->start, resource_size(res)); + mdev->vram = devm_ioremap_wc(dev->dev, res->start, resource_size(res)); if (!mdev->vram) return -ENOMEM; + /* Don't fail on errors, but performance might be reduced. */ + devm_arch_phys_wc_add(dev->dev, res->start, resource_size(res)); + return 0; } diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 0f0d59938c3a07912c3f1cb2a0c3b78f393617aa..0eb769dd76ce0a3019a5b0ae75618b61ba0bb4c5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -14,13 +14,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include "mgag200_drv.h" @@ -717,17 +717,23 @@ void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_st int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector) { struct mga_device *mdev = to_mga_device(connector->dev); - int ret; + const struct drm_edid *drm_edid; + int count; /* * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ mutex_lock(&mdev->rmmio_lock); - ret = drm_connector_helper_get_modes_from_ddc(connector); + + drm_edid = drm_edid_read(connector); + drm_edid_connector_update(connector, drm_edid); + count = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); + mutex_unlock(&mdev->rmmio_lock); - return ret; + return count; } /* diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index d37d599aec273b41b7ec54eb04b55ee86770d1a5..c8e1bbebdffe24934c1feaf4bdd3473cd278479e 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "msm_drv.h" #include "msm_kms.h" diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index f5e01471b0b039e746152aee03710d2720076878..4a5b5112227f516dfc4279d0f319ec1e5b17f240 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -236,24 +236,33 @@ static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge, msm_hdmi_audio_update(hdmi); } -static struct edid *msm_hdmi_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = hdmi_bridge->hdmi; - struct edid *edid; + const struct drm_edid *drm_edid; uint32_t hdmi_ctrl; hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL); hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE); - edid = drm_get_edid(connector, hdmi->i2c); + drm_edid = drm_edid_read_ddc(connector, hdmi->i2c); hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl); - hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid); + if (drm_edid) { + /* + * FIXME: This should use connector->display_info.is_hdmi from a + * path that has read the EDID and called + * drm_edid_connector_update(). + */ + const struct edid *edid = drm_edid_raw(drm_edid); - return edid; + hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid); + } + + return drm_edid; } static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge, @@ -290,12 +299,12 @@ static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge } static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = { - .pre_enable = msm_hdmi_bridge_pre_enable, - .post_disable = msm_hdmi_bridge_post_disable, - .mode_set = msm_hdmi_bridge_mode_set, - .mode_valid = msm_hdmi_bridge_mode_valid, - .get_edid = msm_hdmi_bridge_get_edid, - .detect = msm_hdmi_bridge_detect, + .pre_enable = msm_hdmi_bridge_pre_enable, + .post_disable = msm_hdmi_bridge_post_disable, + .mode_set = msm_hdmi_bridge_mode_set, + .mode_valid = msm_hdmi_bridge_mode_valid, + .edid_read = msm_hdmi_bridge_edid_read, + .detect = msm_hdmi_bridge_detect, }; static void diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index a34917b048f96f4c755c6fe605ab7e92c674e28a..4310ad71870b109697cc07047cbc29f4a631272f 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -449,7 +449,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) regp->Attribute[NV_CIO_AR_CSEL_INDEX] = 0x00; } -/** +/* * Sets up registers for the given mode/adjusted_mode pair. * * The clocks, CRTCs and outputs attached to this CRTC must be off. @@ -625,7 +625,7 @@ nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) return ret; } -/** +/* * Sets up registers for the given mode/adjusted_mode pair. * * The clocks, CRTCs and outputs attached to this CRTC must be off. diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index 5f490fbf18772137c8048ce03604a8849dd06759..83355dbc15eeb3fe8633bf72114db77cc97f3a27 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -32,6 +32,7 @@ #include #include +#include #include #include "nouveau_connector.h" diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 00cc7d1abaa39b7330f4ade2551d881f649cd255..56dcd25db1ce2c79b8a6be7c0ea684838e74e655 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -404,27 +404,6 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align, return 0; } -static void -set_placement_list(struct ttm_place *pl, unsigned *n, uint32_t domain) -{ - *n = 0; - - if (domain & NOUVEAU_GEM_DOMAIN_VRAM) { - pl[*n].mem_type = TTM_PL_VRAM; - pl[*n].flags = 0; - (*n)++; - } - if (domain & NOUVEAU_GEM_DOMAIN_GART) { - pl[*n].mem_type = TTM_PL_TT; - pl[*n].flags = 0; - (*n)++; - } - if (domain & NOUVEAU_GEM_DOMAIN_CPU) { - pl[*n].mem_type = TTM_PL_SYSTEM; - pl[(*n)++].flags = 0; - } -} - static void set_placement_range(struct nouveau_bo *nvbo, uint32_t domain) { @@ -452,10 +431,6 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t domain) nvbo->placements[i].fpfn = fpfn; nvbo->placements[i].lpfn = lpfn; } - for (i = 0; i < nvbo->placement.num_busy_placement; ++i) { - nvbo->busy_placements[i].fpfn = fpfn; - nvbo->busy_placements[i].lpfn = lpfn; - } } } @@ -463,15 +438,32 @@ void nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t domain, uint32_t busy) { - struct ttm_placement *pl = &nvbo->placement; + unsigned int *n = &nvbo->placement.num_placement; + struct ttm_place *pl = nvbo->placements; - pl->placement = nvbo->placements; - set_placement_list(nvbo->placements, &pl->num_placement, domain); + domain |= busy; - pl->busy_placement = nvbo->busy_placements; - set_placement_list(nvbo->busy_placements, &pl->num_busy_placement, - domain | busy); + *n = 0; + if (domain & NOUVEAU_GEM_DOMAIN_VRAM) { + pl[*n].mem_type = TTM_PL_VRAM; + pl[*n].flags = busy & NOUVEAU_GEM_DOMAIN_VRAM ? + TTM_PL_FLAG_FALLBACK : 0; + (*n)++; + } + if (domain & NOUVEAU_GEM_DOMAIN_GART) { + pl[*n].mem_type = TTM_PL_TT; + pl[*n].flags = busy & NOUVEAU_GEM_DOMAIN_GART ? + TTM_PL_FLAG_FALLBACK : 0; + (*n)++; + } + if (domain & NOUVEAU_GEM_DOMAIN_CPU) { + pl[*n].mem_type = TTM_PL_SYSTEM; + pl[*n].flags = busy & NOUVEAU_GEM_DOMAIN_CPU ? + TTM_PL_FLAG_FALLBACK : 0; + (*n)++; + } + nvbo->placement.placement = nvbo->placements; set_placement_range(nvbo, domain); } @@ -1314,11 +1306,6 @@ vm_fault_t nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) nvbo->placements[i].lpfn = mappable; } - for (i = 0; i < nvbo->placement.num_busy_placement; ++i) { - nvbo->busy_placements[i].fpfn = 0; - nvbo->busy_placements[i].lpfn = mappable; - } - nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, 0); } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index 70c551921a9ee917ffda2633f2b300c9ada2c4e3..e9dfab6a81560e5f68371363ce676008f1b8b901 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -15,7 +15,6 @@ struct nouveau_bo { struct ttm_placement placement; u32 valid_domains; struct ttm_place placements[3]; - struct ttm_place busy_placements[3]; bool force_coherent; struct ttm_bo_kmap_obj kmap; struct list_head head; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index a2df4918340cb8b4653554bd8e3050782de17763..0608cabed058e3e43f6d344c21609ef79f30b15c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -35,7 +35,6 @@ #include #include -#include #include #include @@ -44,6 +43,7 @@ struct nvkm_i2c_port; struct dcb_output; +struct edid; #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT struct nouveau_backlight { diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 5057d976fa578cebe2e9e847c6e78634d2b08968..93f08f9479d89bfda87fbeef246c9dd702f047a1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -62,7 +62,7 @@ nouveau_fence_signal(struct nouveau_fence *fence) if (test_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags)) { struct nouveau_fence_chan *fctx = nouveau_fctx(fence); - if (atomic_dec_and_test(&fctx->notify_ref)) + if (!--fctx->notify_ref) drop = 1; } @@ -103,7 +103,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) void nouveau_fence_context_del(struct nouveau_fence_chan *fctx) { - cancel_work_sync(&fctx->allow_block_work); + cancel_work_sync(&fctx->uevent_work); nouveau_fence_context_kill(fctx, 0); nvif_event_dtor(&fctx->event); fctx->dead = 1; @@ -146,12 +146,13 @@ nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fc return drop; } -static int -nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc) +static void +nouveau_fence_uevent_work(struct work_struct *work) { - struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event); + struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan, + uevent_work); unsigned long flags; - int ret = NVIF_EVENT_KEEP; + int drop = 0; spin_lock_irqsave(&fctx->lock, flags); if (!list_empty(&fctx->pending)) { @@ -161,23 +162,20 @@ nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc fence = list_entry(fctx->pending.next, typeof(*fence), head); chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); if (nouveau_fence_update(chan, fctx)) - ret = NVIF_EVENT_DROP; + drop = 1; } - spin_unlock_irqrestore(&fctx->lock, flags); + if (drop) + nvif_event_block(&fctx->event); - return ret; + spin_unlock_irqrestore(&fctx->lock, flags); } -static void -nouveau_fence_work_allow_block(struct work_struct *work) +static int +nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc) { - struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan, - allow_block_work); - - if (atomic_read(&fctx->notify_ref) == 0) - nvif_event_block(&fctx->event); - else - nvif_event_allow(&fctx->event); + struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event); + schedule_work(&fctx->uevent_work); + return NVIF_EVENT_KEEP; } void @@ -191,7 +189,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha } args; int ret; - INIT_WORK(&fctx->allow_block_work, nouveau_fence_work_allow_block); + INIT_WORK(&fctx->uevent_work, nouveau_fence_uevent_work); INIT_LIST_HEAD(&fctx->flip); INIT_LIST_HEAD(&fctx->pending); spin_lock_init(&fctx->lock); @@ -535,19 +533,15 @@ static bool nouveau_fence_enable_signaling(struct dma_fence *f) struct nouveau_fence *fence = from_fence(f); struct nouveau_fence_chan *fctx = nouveau_fctx(fence); bool ret; - bool do_work; - if (atomic_inc_return(&fctx->notify_ref) == 0) - do_work = true; + if (!fctx->notify_ref++) + nvif_event_allow(&fctx->event); ret = nouveau_fence_no_signaling(f); if (ret) set_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags); - else if (atomic_dec_and_test(&fctx->notify_ref)) - do_work = true; - - if (do_work) - schedule_work(&fctx->allow_block_work); + else if (!--fctx->notify_ref) + nvif_event_block(&fctx->event); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 28f5cf013b8983240204d028c8367249a63912e0..8bc065acfe35870f62bd0f2e37df47a35eb8ae38 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -3,7 +3,6 @@ #define __NOUVEAU_FENCE_H__ #include -#include #include struct nouveau_drm; @@ -45,10 +44,9 @@ struct nouveau_fence_chan { u32 context; char name[32]; + struct work_struct uevent_work; struct nvif_event event; - struct work_struct allow_block_work; - atomic_t notify_ref; - int dead, killed; + int notify_ref, dead, killed; }; struct nouveau_fence_priv { diff --git a/drivers/gpu/drm/nouveau/nouveau_ioc32.c b/drivers/gpu/drm/nouveau/nouveau_ioc32.c index adf01ca9e035d50cea5537dac985dbdd42324224..2af3615c5205cd58b6afcaf91eb2263a4cca1e61 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ioc32.c +++ b/drivers/gpu/drm/nouveau/nouveau_ioc32.c @@ -1,4 +1,4 @@ -/** +/* * \file mga_ioc32.c * * 32-bit ioctl compatibility routines for the MGA DRM. @@ -38,7 +38,7 @@ #include "nouveau_ioctl.h" -/** +/* * Called whenever a 32-bit process running under a 64-bit kernel * performs an ioctl on /dev/dri/card. * diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c index cc03e0c22ff3fec65cf6a40ae34db2af20bb349e..4d10089154991bf7eab945caddb11d6b16dc8059 100644 --- a/drivers/gpu/drm/nouveau/nouveau_svm.c +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c @@ -112,7 +112,7 @@ nouveau_svmm_bind(struct drm_device *dev, void *data, { struct nouveau_cli *cli = nouveau_cli(file_priv); struct drm_nouveau_svm_bind *args = data; - unsigned target, cmd, priority; + unsigned target, cmd; unsigned long addr, end; struct mm_struct *mm; @@ -136,9 +136,6 @@ nouveau_svmm_bind(struct drm_device *dev, void *data, return -EINVAL; } - priority = args->header >> NOUVEAU_SVM_BIND_PRIORITY_SHIFT; - priority &= NOUVEAU_SVM_BIND_PRIORITY_MASK; - /* FIXME support CPU target ie all target value < GPU_VRAM */ target = args->header >> NOUVEAU_SVM_BIND_TARGET_SHIFT; target &= NOUVEAU_SVM_BIND_TARGET_MASK; @@ -926,15 +923,14 @@ nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm, unsigned long addr, u64 *pfns, unsigned long npages) { struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns); - int ret; args->p.addr = addr; args->p.size = npages << PAGE_SHIFT; mutex_lock(&svmm->mutex); - ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, - struct_size(args, p.phys, npages), NULL); + nvif_object_ioctl(&svmm->vmm->vmm.object, args, + struct_size(args, p.phys, npages), NULL); mutex_unlock(&svmm->mutex); } diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 5d3190c05250a959019ee43e919a666e4082a753..6daeb7f0b09b63fcd8d6f0149c18b4dfd624672f 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -452,13 +452,12 @@ nvif_outp_edid_get(struct nvif_outp *outp, u8 **pedid) if (ret) goto done; - *pedid = kmalloc(args->size, GFP_KERNEL); + *pedid = kmemdup(args->data, args->size, GFP_KERNEL); if (!*pedid) { ret = -ENOMEM; goto done; } - memcpy(*pedid, args->data, args->size); ret = args->size; done: kfree(args); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index c494a1ff2d5727cef5ce01131379462be4c4a16e..986e8d547c94246a5f7bd058e6ddf555ffc651a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1040,7 +1040,7 @@ gf100_gr_zbc_init(struct gf100_gr *gr) } } -/** +/* * Wait until GR goes idle. GR is considered idle if it is disabled by the * MC (0x200) register, or GR is not busy and a context switch is not in * progress. diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c index f36a359d4531c44bc12bcff46c53cbd57d9f255f..bd104a030243a555cabf320666a81fcc3e0f73d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/lsfw.c @@ -218,7 +218,7 @@ nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *subdev, const struct firmware *hsbl; const struct nvfw_ls_hsbl_bin_hdr *hdr; const struct nvfw_ls_hsbl_hdr *hshdr; - u32 loc, sig, cnt, *meta; + u32 sig, cnt, *meta; ret = nvkm_firmware_load_name(subdev, path, "hs_bl_sig", ver, &hsbl); if (ret) @@ -227,7 +227,6 @@ nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *subdev, hdr = nvfw_ls_hsbl_bin_hdr(subdev, hsbl->data); hshdr = nvfw_ls_hsbl_hdr(subdev, hsbl->data + hdr->header_offset); meta = (u32 *)(hsbl->data + hshdr->meta_data_offset); - loc = *(u32 *)(hsbl->data + hshdr->patch_loc); sig = *(u32 *)(hsbl->data + hshdr->patch_sig); cnt = *(u32 *)(hsbl->data + hshdr->num_sig); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 1420794038642549363453d1649816fce16f6e34..b54f044c4483b1f1cd9e19fd285f0c47809bb581 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -575,7 +575,7 @@ init_tmds_reg(struct nvbios_init *init, u8 tmds) * init opcode handlers *****************************************************************************/ -/** +/* * init_reserved - stub for various unknown/unused single-byte opcodes * */ @@ -602,7 +602,7 @@ init_reserved(struct nvbios_init *init) init->offset += length; } -/** +/* * INIT_DONE - opcode 0x71 * */ @@ -613,7 +613,7 @@ init_done(struct nvbios_init *init) init->offset = 0x0000; } -/** +/* * INIT_IO_RESTRICT_PROG - opcode 0x32 * */ @@ -650,7 +650,7 @@ init_io_restrict_prog(struct nvbios_init *init) trace("}]\n"); } -/** +/* * INIT_REPEAT - opcode 0x33 * */ @@ -676,7 +676,7 @@ init_repeat(struct nvbios_init *init) init->repeat = repeat; } -/** +/* * INIT_IO_RESTRICT_PLL - opcode 0x34 * */ @@ -716,7 +716,7 @@ init_io_restrict_pll(struct nvbios_init *init) trace("}]\n"); } -/** +/* * INIT_END_REPEAT - opcode 0x36 * */ @@ -732,7 +732,7 @@ init_end_repeat(struct nvbios_init *init) } } -/** +/* * INIT_COPY - opcode 0x37 * */ @@ -759,7 +759,7 @@ init_copy(struct nvbios_init *init) init_wrvgai(init, port, index, data); } -/** +/* * INIT_NOT - opcode 0x38 * */ @@ -771,7 +771,7 @@ init_not(struct nvbios_init *init) init_exec_inv(init); } -/** +/* * INIT_IO_FLAG_CONDITION - opcode 0x39 * */ @@ -788,7 +788,7 @@ init_io_flag_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_GENERIC_CONDITION - opcode 0x3a * */ @@ -840,7 +840,7 @@ init_generic_condition(struct nvbios_init *init) } } -/** +/* * INIT_IO_MASK_OR - opcode 0x3b * */ @@ -859,7 +859,7 @@ init_io_mask_or(struct nvbios_init *init) init_wrvgai(init, 0x03d4, index, data &= ~(1 << or)); } -/** +/* * INIT_IO_OR - opcode 0x3c * */ @@ -878,7 +878,7 @@ init_io_or(struct nvbios_init *init) init_wrvgai(init, 0x03d4, index, data | (1 << or)); } -/** +/* * INIT_ANDN_REG - opcode 0x47 * */ @@ -895,7 +895,7 @@ init_andn_reg(struct nvbios_init *init) init_mask(init, reg, mask, 0); } -/** +/* * INIT_OR_REG - opcode 0x48 * */ @@ -912,7 +912,7 @@ init_or_reg(struct nvbios_init *init) init_mask(init, reg, 0, mask); } -/** +/* * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49 * */ @@ -942,7 +942,7 @@ init_idx_addr_latched(struct nvbios_init *init) } } -/** +/* * INIT_IO_RESTRICT_PLL2 - opcode 0x4a * */ @@ -977,7 +977,7 @@ init_io_restrict_pll2(struct nvbios_init *init) trace("}]\n"); } -/** +/* * INIT_PLL2 - opcode 0x4b * */ @@ -994,7 +994,7 @@ init_pll2(struct nvbios_init *init) init_prog_pll(init, reg, freq); } -/** +/* * INIT_I2C_BYTE - opcode 0x4c * */ @@ -1025,7 +1025,7 @@ init_i2c_byte(struct nvbios_init *init) } } -/** +/* * INIT_ZM_I2C_BYTE - opcode 0x4d * */ @@ -1051,7 +1051,7 @@ init_zm_i2c_byte(struct nvbios_init *init) } } -/** +/* * INIT_ZM_I2C - opcode 0x4e * */ @@ -1085,7 +1085,7 @@ init_zm_i2c(struct nvbios_init *init) } } -/** +/* * INIT_TMDS - opcode 0x4f * */ @@ -1111,7 +1111,7 @@ init_tmds(struct nvbios_init *init) init_wr32(init, reg + 0, addr); } -/** +/* * INIT_ZM_TMDS_GROUP - opcode 0x50 * */ @@ -1138,7 +1138,7 @@ init_zm_tmds_group(struct nvbios_init *init) } } -/** +/* * INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51 * */ @@ -1168,7 +1168,7 @@ init_cr_idx_adr_latch(struct nvbios_init *init) init_wrvgai(init, 0x03d4, addr0, save0); } -/** +/* * INIT_CR - opcode 0x52 * */ @@ -1188,7 +1188,7 @@ init_cr(struct nvbios_init *init) init_wrvgai(init, 0x03d4, addr, val | data); } -/** +/* * INIT_ZM_CR - opcode 0x53 * */ @@ -1205,7 +1205,7 @@ init_zm_cr(struct nvbios_init *init) init_wrvgai(init, 0x03d4, addr, data); } -/** +/* * INIT_ZM_CR_GROUP - opcode 0x54 * */ @@ -1229,7 +1229,7 @@ init_zm_cr_group(struct nvbios_init *init) } } -/** +/* * INIT_CONDITION_TIME - opcode 0x56 * */ @@ -1256,7 +1256,7 @@ init_condition_time(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_LTIME - opcode 0x57 * */ @@ -1273,7 +1273,7 @@ init_ltime(struct nvbios_init *init) mdelay(msec); } -/** +/* * INIT_ZM_REG_SEQUENCE - opcode 0x58 * */ @@ -1298,7 +1298,7 @@ init_zm_reg_sequence(struct nvbios_init *init) } } -/** +/* * INIT_PLL_INDIRECT - opcode 0x59 * */ @@ -1317,7 +1317,7 @@ init_pll_indirect(struct nvbios_init *init) init_prog_pll(init, reg, freq); } -/** +/* * INIT_ZM_REG_INDIRECT - opcode 0x5a * */ @@ -1336,7 +1336,7 @@ init_zm_reg_indirect(struct nvbios_init *init) init_wr32(init, addr, data); } -/** +/* * INIT_SUB_DIRECT - opcode 0x5b * */ @@ -1362,7 +1362,7 @@ init_sub_direct(struct nvbios_init *init) init->offset += 3; } -/** +/* * INIT_JUMP - opcode 0x5c * */ @@ -1380,7 +1380,7 @@ init_jump(struct nvbios_init *init) init->offset += 3; } -/** +/* * INIT_I2C_IF - opcode 0x5e * */ @@ -1407,7 +1407,7 @@ init_i2c_if(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_COPY_NV_REG - opcode 0x5f * */ @@ -1433,7 +1433,7 @@ init_copy_nv_reg(struct nvbios_init *init) init_mask(init, dreg, ~dmask, (data & smask) ^ sxor); } -/** +/* * INIT_ZM_INDEX_IO - opcode 0x62 * */ @@ -1451,7 +1451,7 @@ init_zm_index_io(struct nvbios_init *init) init_wrvgai(init, port, index, data); } -/** +/* * INIT_COMPUTE_MEM - opcode 0x63 * */ @@ -1469,7 +1469,7 @@ init_compute_mem(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_RESET - opcode 0x65 * */ @@ -1496,7 +1496,7 @@ init_reset(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_CONFIGURE_MEM - opcode 0x66 * */ @@ -1555,7 +1555,7 @@ init_configure_mem(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_CONFIGURE_CLK - opcode 0x67 * */ @@ -1589,7 +1589,7 @@ init_configure_clk(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_CONFIGURE_PREINIT - opcode 0x68 * */ @@ -1615,7 +1615,7 @@ init_configure_preinit(struct nvbios_init *init) init_exec_force(init, false); } -/** +/* * INIT_IO - opcode 0x69 * */ @@ -1655,7 +1655,7 @@ init_io(struct nvbios_init *init) init_wrport(init, port, data | value); } -/** +/* * INIT_SUB - opcode 0x6b * */ @@ -1682,7 +1682,7 @@ init_sub(struct nvbios_init *init) init->offset += 2; } -/** +/* * INIT_RAM_CONDITION - opcode 0x6d * */ @@ -1701,7 +1701,7 @@ init_ram_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_NV_REG - opcode 0x6e * */ @@ -1719,7 +1719,7 @@ init_nv_reg(struct nvbios_init *init) init_mask(init, reg, ~mask, data); } -/** +/* * INIT_MACRO - opcode 0x6f * */ @@ -1743,7 +1743,7 @@ init_macro(struct nvbios_init *init) init->offset += 2; } -/** +/* * INIT_RESUME - opcode 0x72 * */ @@ -1755,7 +1755,7 @@ init_resume(struct nvbios_init *init) init_exec_set(init, true); } -/** +/* * INIT_STRAP_CONDITION - opcode 0x73 * */ @@ -1773,7 +1773,7 @@ init_strap_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_TIME - opcode 0x74 * */ @@ -1794,7 +1794,7 @@ init_time(struct nvbios_init *init) } } -/** +/* * INIT_CONDITION - opcode 0x75 * */ @@ -1811,7 +1811,7 @@ init_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_IO_CONDITION - opcode 0x76 * */ @@ -1828,7 +1828,7 @@ init_io_condition(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_ZM_REG16 - opcode 0x77 * */ @@ -1845,7 +1845,7 @@ init_zm_reg16(struct nvbios_init *init) init_wr32(init, addr, data); } -/** +/* * INIT_INDEX_IO - opcode 0x78 * */ @@ -1867,7 +1867,7 @@ init_index_io(struct nvbios_init *init) init_wrvgai(init, port, index, data | value); } -/** +/* * INIT_PLL - opcode 0x79 * */ @@ -1884,7 +1884,7 @@ init_pll(struct nvbios_init *init) init_prog_pll(init, reg, freq); } -/** +/* * INIT_ZM_REG - opcode 0x7a * */ @@ -1904,7 +1904,7 @@ init_zm_reg(struct nvbios_init *init) init_wr32(init, addr, data); } -/** +/* * INIT_RAM_RESTRICT_PLL - opcde 0x87 * */ @@ -1934,7 +1934,7 @@ init_ram_restrict_pll(struct nvbios_init *init) } } -/** +/* * INIT_RESET_BEGUN - opcode 0x8c * */ @@ -1945,7 +1945,7 @@ init_reset_begun(struct nvbios_init *init) init->offset += 1; } -/** +/* * INIT_RESET_END - opcode 0x8d * */ @@ -1956,7 +1956,7 @@ init_reset_end(struct nvbios_init *init) init->offset += 1; } -/** +/* * INIT_GPIO - opcode 0x8e * */ @@ -1972,7 +1972,7 @@ init_gpio(struct nvbios_init *init) nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED); } -/** +/* * INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f * */ @@ -2010,7 +2010,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init) } } -/** +/* * INIT_COPY_ZM_REG - opcode 0x90 * */ @@ -2027,7 +2027,7 @@ init_copy_zm_reg(struct nvbios_init *init) init_wr32(init, dreg, init_rd32(init, sreg)); } -/** +/* * INIT_ZM_REG_GROUP - opcode 0x91 * */ @@ -2049,7 +2049,7 @@ init_zm_reg_group(struct nvbios_init *init) } } -/** +/* * INIT_XLAT - opcode 0x96 * */ @@ -2077,7 +2077,7 @@ init_xlat(struct nvbios_init *init) init_mask(init, daddr, ~dmask, data); } -/** +/* * INIT_ZM_MASK_ADD - opcode 0x97 * */ @@ -2098,7 +2098,7 @@ init_zm_mask_add(struct nvbios_init *init) init_wr32(init, addr, data); } -/** +/* * INIT_AUXCH - opcode 0x98 * */ @@ -2122,7 +2122,7 @@ init_auxch(struct nvbios_init *init) } } -/** +/* * INIT_AUXCH - opcode 0x99 * */ @@ -2144,7 +2144,7 @@ init_zm_auxch(struct nvbios_init *init) } } -/** +/* * INIT_I2C_LONG_IF - opcode 0x9a * */ @@ -2183,7 +2183,7 @@ init_i2c_long_if(struct nvbios_init *init) init_exec_set(init, false); } -/** +/* * INIT_GPIO_NE - opcode 0xa9 * */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c index 9ee58e2a0eb2ad99c198ea7a58e6e1cf02a667d0..5e1fa176aac4a4b9e33562236b8b93889dae58ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c @@ -1078,7 +1078,6 @@ r535_gsp_rpc_set_registry(struct nvkm_gsp *gsp) if (IS_ERR(rpc)) return PTR_ERR(rpc); - rpc->size = sizeof(*rpc); rpc->numEntries = NV_GSP_REG_NUM_ENTRIES; str_offset = offsetof(typeof(*rpc), entries[NV_GSP_REG_NUM_ENTRIES]); @@ -1094,6 +1093,7 @@ r535_gsp_rpc_set_registry(struct nvkm_gsp *gsp) strings += name_len; str_offset += name_len; } + rpc->size = str_offset; return nvkm_gsp_rpc_wr(gsp, rpc, false); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 8c2faa9645111932c6920befc021d71363d7869c..ccac88da8864849911b14625abbf375ca3a097b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -45,7 +45,7 @@ static const struct cvb_coef gk20a_cvb_coef[] = { /* 852 */ { 1608418, -21643, -269, 0, 763, -48}, }; -/** +/* * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) */ static inline int @@ -58,7 +58,7 @@ gk20a_volt_get_cvb_voltage(int speedo, int s_scale, const struct cvb_coef *coef) return mv; } -/** +/* * cvb_t_mv = * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) + * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index a26b77d99d52ae111f4901114fa35e667d869e27..9b8747d83ee877046ed9d0dfae626a4f3bccb6b2 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -436,11 +436,11 @@ static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge, hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); } -static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *hdmi4_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); - struct edid *edid = NULL; + const struct drm_edid *drm_edid = NULL; unsigned int cec_addr; bool need_enable; int r; @@ -461,13 +461,21 @@ static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge, if (r) goto done; - edid = drm_do_get_edid(connector, hdmi4_core_ddc_read, &hdmi->core); + drm_edid = drm_edid_read_custom(connector, hdmi4_core_ddc_read, &hdmi->core); done: hdmi_runtime_put(hdmi); mutex_unlock(&hdmi->lock); - if (edid && edid->extensions) { + if (drm_edid) { + /* + * FIXME: The CEC physical address should be set using + * hdmi4_cec_set_phys_addr(&hdmi->core, + * connector->display_info.source_physical_address) from a path + * that has read the EDID and called + * drm_edid_connector_update(). + */ + const struct edid *edid = drm_edid_raw(drm_edid); unsigned int len = (edid->extensions + 1) * EDID_LENGTH; cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL); @@ -480,7 +488,7 @@ done: if (need_enable) hdmi4_core_disable(&hdmi->core); - return edid; + return drm_edid; } static const struct drm_bridge_funcs hdmi4_bridge_funcs = { @@ -492,7 +500,7 @@ static const struct drm_bridge_funcs hdmi4_bridge_funcs = { .atomic_enable = hdmi4_bridge_enable, .atomic_disable = hdmi4_bridge_disable, .hpd_notify = hdmi4_bridge_hpd_notify, - .get_edid = hdmi4_bridge_get_edid, + .edid_read = hdmi4_bridge_edid_read, }; static void hdmi4_bridge_init(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index e6611c683857a51d330039a4242b0fa922f5af2c..c7ae2235ae99b0f9b6cb3f9cbb70a74488907723 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -425,11 +425,11 @@ static void hdmi5_bridge_disable(struct drm_bridge *bridge, mutex_unlock(&hdmi->lock); } -static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *hdmi5_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); - struct edid *edid; + const struct drm_edid *drm_edid; bool need_enable; int idlemode; int r; @@ -452,7 +452,7 @@ static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge, hdmi5_core_ddc_init(&hdmi->core); - edid = drm_do_get_edid(connector, hdmi5_core_ddc_read, &hdmi->core); + drm_edid = drm_edid_read_custom(connector, hdmi5_core_ddc_read, &hdmi->core); hdmi5_core_ddc_uninit(&hdmi->core); @@ -464,7 +464,7 @@ static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge, if (need_enable) hdmi_core_disable(hdmi); - return (struct edid *)edid; + return drm_edid; } static const struct drm_bridge_funcs hdmi5_bridge_funcs = { @@ -475,7 +475,7 @@ static const struct drm_bridge_funcs hdmi5_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset, .atomic_enable = hdmi5_bridge_enable, .atomic_disable = hdmi5_bridge_disable, - .get_edid = hdmi5_bridge_get_edid, + .edid_read = hdmi5_bridge_edid_read, }; static void hdmi5_bridge_init(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index dad938cf6decfb0658a73439a6ca602c78fce2fb..b61abacd1b22790eb1fdae7143c5a70ea18db700 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -67,61 +67,25 @@ config DRM_PANEL_BOE_HIMAX8279D 24 bit RGB per pixel. It provides a MIPI DSI interface to the host and has a built-in LED backlight. -config DRM_PANEL_BOE_TV101WUM_NL6 - tristate "BOE TV101WUM and AUO KD101N80 45NA 1200x1920 panel" +config DRM_PANEL_BOE_TH101MB31UIG002_28A + tristate "Boe TH101MB31UIG002-28A panel" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help - Say Y here if you want to support for BOE TV101WUM and AUO KD101N80 - 45NA WUXGA PANEL DSI Video Mode panel + Say Y here if you want to enable support for Boe + TH101MB31UIG002-28A TFT-LCD modules. The panel has a 800x1280 + resolution and uses 24 bit RGB per pixel. It provides a MIPI DSI + interface to the host and has a built-in LED backlight. -config DRM_PANEL_DSI_CM - tristate "Generic DSI command mode panels" +config DRM_PANEL_BOE_TV101WUM_NL6 + tristate "BOE TV101WUM and AUO KD101N80 45NA 1200x1920 panel" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help - DRM panel driver for DSI command mode panels with support for - embedded and external backlights. - -config DRM_PANEL_LVDS - tristate "Generic LVDS panel driver" - depends on OF - depends on BACKLIGHT_CLASS_DEVICE - select VIDEOMODE_HELPERS - help - This driver supports LVDS panels that don't require device-specific - handling of power supplies or control signals. It implements automatic - backlight handling if the panel is attached to a backlight controller. - -config DRM_PANEL_SIMPLE - tristate "support for simple panels (other than eDP ones)" - depends on OF - depends on BACKLIGHT_CLASS_DEVICE - depends on PM - select VIDEOMODE_HELPERS - help - DRM panel driver for dumb non-eDP panels that need at most a regulator - and a GPIO to be powered up. Optionally a backlight can be attached so - that it can be automatically turned off when the panel goes into a - low power state. - -config DRM_PANEL_EDP - tristate "support for simple Embedded DisplayPort panels" - depends on OF - depends on BACKLIGHT_CLASS_DEVICE - depends on PM - select VIDEOMODE_HELPERS - select DRM_DISPLAY_DP_HELPER - select DRM_DISPLAY_HELPER - select DRM_DP_AUX_BUS - select DRM_KMS_HELPER - help - DRM panel driver for dumb eDP panels that need at most a regulator and - a GPIO to be powered up. Optionally a backlight can be attached so - that it can be automatically turned off when the panel goes into a - low power state. + Say Y here if you want to support for BOE TV101WUM and AUO KD101N80 + 45NA WUXGA PANEL DSI Video Mode panel config DRM_PANEL_EBBG_FT8719 tristate "EBBG FT8719 panel driver" @@ -162,6 +126,25 @@ config DRM_PANEL_FEIYANG_FY07024DI26A30D Say Y if you want to enable support for panels based on the Feiyang FY07024DI26A30-D MIPI-DSI interface. +config DRM_PANEL_DSI_CM + tristate "Generic DSI command mode panels" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + DRM panel driver for DSI command mode panels with support for + embedded and external backlights. + +config DRM_PANEL_LVDS + tristate "Generic LVDS panel driver" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + help + This driver supports LVDS panels that don't require device-specific + handling of power supplies or control signals. It implements automatic + backlight handling if the panel is attached to a backlight controller. + config DRM_PANEL_HIMAX_HX8394 tristate "HIMAX HX8394 MIPI-DSI LCD panels" depends on OF @@ -251,17 +234,6 @@ config DRM_PANEL_JADARD_JD9365DA_H3 WXGA MIPI DSI panel. The panel support TFT dot matrix LCD with 800RGBx1280 dots at maximum. -config DRM_PANEL_JDI_LT070ME05000 - tristate "JDI LT070ME05000 WUXGA DSI panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for JDI DSI video mode - panel as found in Google Nexus 7 (2013) devices. - The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses - 24 bit per pixel. - config DRM_PANEL_JDI_LPM102A188A tristate "JDI LPM102A188A DSI panel" depends on OF && GPIOLIB @@ -273,6 +245,17 @@ config DRM_PANEL_JDI_LPM102A188A The panel has a 2560×1800 resolution. It provides a MIPI DSI interface to the host. +config DRM_PANEL_JDI_LT070ME05000 + tristate "JDI LT070ME05000 WUXGA DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for JDI DSI video mode + panel as found in Google Nexus 7 (2013) devices. + The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses + 24 bit per pixel. + config DRM_PANEL_JDI_R63452 tristate "JDI R63452 Full HD DSI panel" depends on OF @@ -326,12 +309,6 @@ config DRM_PANEL_LEADTEK_LTK500HD1829 24 bit RGB per pixel. It provides a MIPI DSI interface to the host and has a built-in LED backlight. -config DRM_PANEL_SAMSUNG_LD9040 - tristate "Samsung LD9040 RGB/SPI panel" - depends on OF && SPI - depends on BACKLIGHT_CLASS_DEVICE - select VIDEOMODE_HELPERS - config DRM_PANEL_LG_LB035Q02 tristate "LG LB035Q024573 RGB panel" depends on GPIOLIB && OF && SPI @@ -359,6 +336,17 @@ config DRM_PANEL_MAGNACHIP_D53E6EA8966 with the Magnachip D53E6EA8966 panel IC. This panel receives video data via DSI but commands via 9-bit SPI using DBI. +config DRM_PANEL_MANTIX_MLAF057WE51 + tristate "Mantix MLAF057WE51-X MIPI-DSI LCD panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the Mantix + MLAF057WE51-X MIPI DSI panel as e.g. used in the Librem 5. It + has a resolution of 720x1440 pixels, a built in backlight and touch + controller. + config DRM_PANEL_NEC_NL8048HL11 tristate "NEC NL8048HL11 RGB panel" depends on GPIOLIB && OF && SPI @@ -438,6 +426,16 @@ config DRM_PANEL_NOVATEK_NT36672A around the Novatek NT36672A display controller, such as some Tianma panels used in a few Xiaomi Poco F1 mobile phones. +config DRM_PANEL_NOVATEK_NT36672E + tristate "Novatek NT36672E DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Novatek NT36672E DSI Video Mode + LCD panel module. The panel has a resolution of 1080x2408 and uses 24 bit + RGB per pixel. + config DRM_PANEL_NOVATEK_NT39016 tristate "Novatek NT39016 RGB/SPI panel" depends on OF && SPI @@ -447,17 +445,6 @@ config DRM_PANEL_NOVATEK_NT39016 Say Y here if you want to enable support for the panels built around the Novatek NT39016 display controller. -config DRM_PANEL_MANTIX_MLAF057WE51 - tristate "Mantix MLAF057WE51-X MIPI-DSI LCD panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for the Mantix - MLAF057WE51-X MIPI DSI panel as e.g. used in the Librem 5. It - has a resolution of 720x1440 pixels, a built in backlight and touch - controller. - config DRM_PANEL_OLIMEX_LCD_OLINUXINO tristate "Olimex LCD-OLinuXino panel" depends on OF @@ -539,6 +526,8 @@ config DRM_PANEL_RAYDIUM_RM692E5 depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER help Say Y here if you want to enable support for Raydium RM692E5-based display panels, such as the one found in the Fairphone 5 smartphone. @@ -552,6 +541,12 @@ config DRM_PANEL_RONBO_RB070D30 Say Y here if you want to enable support for Ronbo Electronics RB070D30 1024x600 DSI panel. +config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 + tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller" + depends on OF + select DRM_MIPI_DSI + select VIDEOMODE_HELPERS + config DRM_PANEL_SAMSUNG_ATNA33XC20 tristate "Samsung ATNA33XC20 eDP panel" depends on OF @@ -575,6 +570,12 @@ config DRM_PANEL_SAMSUNG_DB7430 DB7430 DPI display controller used in such devices as the LMS397KF04 480x800 DPI panel. +config DRM_PANEL_SAMSUNG_LD9040 + tristate "Samsung LD9040 RGB/SPI panel" + depends on OF && SPI + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + config DRM_PANEL_SAMSUNG_S6D16D0 tristate "Samsung S6D16D0 DSI video mode panel" depends on OF @@ -640,12 +641,6 @@ config DRM_PANEL_SAMSUNG_S6E63M0_DSI Say Y here if you want to be able to access the Samsung S6E63M0 panel using DSI. -config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 - tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller" - depends on OF - select DRM_MIPI_DSI - select VIDEOMODE_HELPERS - config DRM_PANEL_SAMSUNG_S6E8AA0 tristate "Samsung S6E8AA0 DSI video mode panel" depends on OF @@ -744,15 +739,6 @@ config DRM_PANEL_SITRONIX_ST7789V Say Y here if you want to enable support for the Sitronix ST7789V controller for 240x320 LCD panels -config DRM_PANEL_SYNAPTICS_R63353 - tristate "Synaptics R63353-based panels" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y if you want to enable support for panels based on the - Synaptics R63353 controller. - config DRM_PANEL_SONY_ACX565AKM tristate "Sony ACX565AKM panel" depends on GPIOLIB && OF && SPI @@ -792,6 +778,43 @@ config DRM_PANEL_STARTEK_KD070FHFID015 with a resolution of 1024 x 600 pixels. It provides a MIPI DSI interface to the host, a built-in LED backlight and touch controller. +config DRM_PANEL_EDP + tristate "support for simple Embedded DisplayPort panels" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + depends on PM + select VIDEOMODE_HELPERS + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER + select DRM_DP_AUX_BUS + select DRM_KMS_HELPER + help + DRM panel driver for dumb eDP panels that need at most a regulator and + a GPIO to be powered up. Optionally a backlight can be attached so + that it can be automatically turned off when the panel goes into a + low power state. + +config DRM_PANEL_SIMPLE + tristate "support for simple panels (other than eDP ones)" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + depends on PM + select VIDEOMODE_HELPERS + help + DRM panel driver for dumb non-eDP panels that need at most a regulator + and a GPIO to be powered up. Optionally a backlight can be attached so + that it can be automatically turned off when the panel goes into a + low power state. + +config DRM_PANEL_SYNAPTICS_R63353 + tristate "Synaptics R63353-based panels" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for panels based on the + Synaptics R63353 controller. + config DRM_PANEL_TDO_TL070WSH30 tristate "TDO TL070WSH30 DSI panel" depends on OF @@ -835,6 +858,17 @@ config DRM_PANEL_TRULY_NT35597_WQXGA Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI Video Mode panel +config DRM_PANEL_VISIONOX_R66451 + tristate "Visionox R66451" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER + help + Say Y here if you want to enable support for Visionox + R66451 1080x2340 AMOLED DSI panel. + config DRM_PANEL_VISIONOX_RM69299 tristate "Visionox RM69299" depends on OF @@ -852,17 +886,6 @@ config DRM_PANEL_VISIONOX_VTDR6130 Say Y here if you want to enable support for Visionox VTDR6130 1080x2400 AMOLED DSI panel. -config DRM_PANEL_VISIONOX_R66451 - tristate "Visionox R66451" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - select DRM_DISPLAY_DP_HELPER - select DRM_DISPLAY_HELPER - help - Say Y here if you want to enable support for Visionox - R66451 1080x2340 AMOLED DSI panel. - config DRM_PANEL_WIDECHIPS_WS2401 tristate "Widechips WS2401 DPI panel driver" depends on SPI && GPIOLIB diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index d94a644d0a6cea274f1748f11d8558b809cc91fc..1c4f4e7f25bb86f2dfb6e01bdea80106baedd988 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596. obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o +obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o @@ -41,6 +42,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c index 11b64acbe8a9f23107b6c5118b4d114c446c4957..e225840b0d67bf0ff2d07902e9c3d7d4cfa32b47 100644 --- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c +++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c @@ -854,26 +854,20 @@ static int panel_add(struct panel_info *pinfo) pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH); if (IS_ERR(pinfo->pp18_gpio)) { - ret = PTR_ERR(pinfo->pp18_gpio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get pp18 gpio: %d\n", ret); - return ret; + return dev_err_probe(dev, PTR_ERR(pinfo->pp18_gpio), + "failed to get pp18 gpio\n"); } pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH); if (IS_ERR(pinfo->pp33_gpio)) { - ret = PTR_ERR(pinfo->pp33_gpio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get pp33 gpio: %d\n", ret); - return ret; + return dev_err_probe(dev, PTR_ERR(pinfo->pp33_gpio), + "failed to get pp33 gpio\n"); } pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(pinfo->enable_gpio)) { - ret = PTR_ERR(pinfo->enable_gpio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get enable gpio: %d\n", ret); - return ret; + return dev_err_probe(dev, PTR_ERR(pinfo->enable_gpio), + "failed to get enable gpio\n"); } drm_panel_init(&pinfo->base, dev, &panel_funcs, diff --git a/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c new file mode 100644 index 0000000000000000000000000000000000000000..763e9f8342d3c029ce9a147899c4c60feea4c64a --- /dev/null +++ b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Alexander Warnecke + * Copyright (c) 2023 Manuel Traut + * Copyright (c) 2023 Dang Huynh + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct boe_th101mb31ig002 { + struct drm_panel panel; + + struct mipi_dsi_device *dsi; + + struct regulator *power; + struct gpio_desc *enable; + struct gpio_desc *reset; + + enum drm_panel_orientation orientation; +}; + +static void boe_th101mb31ig002_reset(struct boe_th101mb31ig002 *ctx) +{ + gpiod_direction_output(ctx->reset, 0); + usleep_range(10, 100); + gpiod_direction_output(ctx->reset, 1); + usleep_range(10, 100); + gpiod_direction_output(ctx->reset, 0); + usleep_range(5000, 6000); +} + +static int boe_th101mb31ig002_enable(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + mipi_dsi_dcs_write_seq(dsi, 0xE0, 0xAB, 0xBA); + mipi_dsi_dcs_write_seq(dsi, 0xE1, 0xBA, 0xAB); + mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x10, 0x01, 0x47, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x0C, 0x14, 0x04, 0x50, 0x50, 0x14); + mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x56, 0x53, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x33, 0x30, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xB6, 0xB0, 0x00, 0x00, 0x10, 0x00, 0x10, + 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x05, 0x12, 0x29, 0x49, 0x48, 0x00, + 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x7C, 0x65, 0x55, 0x49, 0x46, 0x36, + 0x3B, 0x24, 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, + 0x55, 0x47, 0x46, 0x39, 0x26, 0x06, 0x7C, + 0x65, 0x55, 0x49, 0x46, 0x36, 0x3B, 0x24, + 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, 0x55, 0x47, + 0x46, 0x39, 0x26, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0xFF, 0x87, 0x12, 0x34, 0x44, 0x44, + 0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0F, + 0x00, 0x00, 0xC1); + mipi_dsi_dcs_write_seq(dsi, 0xC1, 0x54, 0x94, 0x02, 0x85, 0x9F, 0x00, + 0x7F, 0x00, 0x54, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11, + 0x22, 0x20, 0x44, 0xFF, 0x18, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC3, 0x86, 0x46, 0x05, 0x05, 0x1C, 0x1C, + 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, + 0x0F, 0x0F, 0x0D, 0x0D, 0x13, 0x13, 0x11, + 0x11, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC4, 0x07, 0x07, 0x04, 0x04, 0x1C, 0x1C, + 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, + 0x0E, 0x0E, 0x0C, 0x0C, 0x12, 0x12, 0x10, + 0x10, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xC6, 0x2A, 0x2A); + mipi_dsi_dcs_write_seq(dsi, 0xC8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16); + mipi_dsi_dcs_write_seq(dsi, 0xCA, 0xCB, 0x43); + mipi_dsi_dcs_write_seq(dsi, 0xCD, 0x0E, 0x4B, 0x4B, 0x20, 0x19, 0x6B, + 0x06, 0xB3); + mipi_dsi_dcs_write_seq(dsi, 0xD2, 0xE3, 0x2B, 0x38, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xD4, 0x00, 0x01, 0x00, 0x0E, 0x04, 0x44, + 0x08, 0x10, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xE6, 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xF0, 0x12, 0x03, 0x20, 0x00, 0xFF); + mipi_dsi_dcs_write_seq(dsi, 0xF3, 0x00); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + + msleep(120); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set panel on: %d\n", ret); + return ret; + } + + return 0; +} + +static int boe_th101mb31ig002_disable(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) + dev_err(dev, "Failed to set panel off: %d\n", ret); + + msleep(120); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) + dev_err(dev, "Failed to enter sleep mode: %d\n", ret); + + return 0; +} + +static int boe_th101mb31ig002_unprepare(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + + gpiod_set_value_cansleep(ctx->reset, 1); + gpiod_set_value_cansleep(ctx->enable, 0); + regulator_disable(ctx->power); + + return 0; +} + +static int boe_th101mb31ig002_prepare(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_enable(ctx->power); + if (ret) { + dev_err(dev, "Failed to enable power supply: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ctx->enable, 1); + msleep(50); + boe_th101mb31ig002_reset(ctx); + boe_th101mb31ig002_enable(panel); + + return 0; +} + +static const struct drm_display_mode boe_th101mb31ig002_default_mode = { + .clock = 73500, + .hdisplay = 800, + .hsync_start = 800 + 64, + .hsync_end = 800 + 64 + 16, + .htotal = 800 + 64 + 16 + 64, + .vdisplay = 1280, + .vsync_start = 1280 + 2, + .vsync_end = 1280 + 2 + 4, + .vtotal = 1280 + 2 + 4 + 12, + .width_mm = 135, + .height_mm = 216, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static int boe_th101mb31ig002_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, + &boe_th101mb31ig002_default_mode); + if (!mode) { + dev_err(panel->dev, "Failed to add mode %ux%u@%u\n", + boe_th101mb31ig002_default_mode.hdisplay, + boe_th101mb31ig002_default_mode.vdisplay, + drm_mode_vrefresh(&boe_th101mb31ig002_default_mode)); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + connector->display_info.bpc = 8; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + + /* + * TODO: Remove once all drm drivers call + * drm_connector_set_orientation_from_panel() + */ + drm_connector_set_panel_orientation(connector, ctx->orientation); + + drm_mode_probed_add(connector, mode); + + return 1; +} + +static enum drm_panel_orientation +boe_th101mb31ig002_get_orientation(struct drm_panel *panel) +{ + struct boe_th101mb31ig002 *ctx = container_of(panel, + struct boe_th101mb31ig002, + panel); + + return ctx->orientation; +} + +static const struct drm_panel_funcs boe_th101mb31ig002_funcs = { + .prepare = boe_th101mb31ig002_prepare, + .unprepare = boe_th101mb31ig002_unprepare, + .disable = boe_th101mb31ig002_disable, + .get_modes = boe_th101mb31ig002_get_modes, + .get_orientation = boe_th101mb31ig002_get_orientation, +}; + +static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi) +{ + struct boe_th101mb31ig002 *ctx; + int ret; + + ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mipi_dsi_set_drvdata(dsi, ctx); + ctx->dsi = dsi; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_MODE_LPM; + + ctx->power = devm_regulator_get(&dsi->dev, "power"); + if (IS_ERR(ctx->power)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power), + "Failed to get power regulator\n"); + + ctx->enable = devm_gpiod_get(&dsi->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(ctx->enable)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->enable), + "Failed to get enable GPIO\n"); + + ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset)) + return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset), + "Failed to get reset GPIO\n"); + + ret = of_drm_get_panel_orientation(dsi->dev.of_node, + &ctx->orientation); + if (ret) + return dev_err_probe(&dsi->dev, ret, + "Failed to get orientation\n"); + + drm_panel_init(&ctx->panel, &dsi->dev, &boe_th101mb31ig002_funcs, + DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return ret; + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err_probe(&dsi->dev, ret, + "Failed to attach panel to DSI host\n"); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void boe_th101mb31ig002_dsi_remove(struct mipi_dsi_device *dsi) +{ + struct boe_th101mb31ig002 *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id boe_th101mb31ig002_of_match[] = { + { .compatible = "boe,th101mb31ig002-28a", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, boe_th101mb31ig002_of_match); + +static struct mipi_dsi_driver boe_th101mb31ig002_driver = { + .driver = { + .name = "boe-th101mb31ig002-28a", + .of_match_table = boe_th101mb31ig002_of_match, + }, + .probe = boe_th101mb31ig002_dsi_probe, + .remove = boe_th101mb31ig002_dsi_remove, +}; +module_mipi_dsi_driver(boe_th101mb31ig002_driver); + +MODULE_AUTHOR("Alexander Warnecke "); +MODULE_DESCRIPTION("BOE TH101MB31IG002-28A MIPI-DSI LCD panel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index a0b6f69b916f92511e81944246448db4401386fd..7d556b1bfa82c2d4bfd5de1cef26d54b8e2af12f 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -70,6 +70,21 @@ struct panel_delay { */ unsigned int hpd_absent; + /** + * @powered_on_to_enable: Time between panel powered on and enable. + * + * The minimum time, in milliseconds, that needs to have passed + * between when panel powered on and enable may begin. + * + * This is (T3+T4+T5+T6+T8)-min on eDP timing diagrams or after the + * power supply enabled until we can turn the backlight on and see + * valid data. + * + * This doesn't normally need to be set if timings are already met by + * prepare_to_enable or enable. + */ + unsigned int powered_on_to_enable; + /** * @prepare_to_enable: Time between prepare and enable. * @@ -216,6 +231,7 @@ struct panel_edp { bool prepared; ktime_t prepared_time; + ktime_t powered_on_time; ktime_t unprepared_time; const struct panel_desc *desc; @@ -413,8 +429,7 @@ static int panel_edp_unprepare(struct drm_panel *panel) if (!p->prepared) return 0; - pm_runtime_mark_last_busy(panel->dev); - ret = pm_runtime_put_autosuspend(panel->dev); + ret = pm_runtime_put_sync_suspend(panel->dev); if (ret < 0) return ret; p->prepared = false; @@ -455,6 +470,8 @@ static int panel_edp_prepare_once(struct panel_edp *p) gpiod_set_value_cansleep(p->enable_gpio, 1); + p->powered_on_time = ktime_get_boottime(); + delay = p->desc->delay.hpd_reliable; if (p->no_hpd) delay = max(delay, p->desc->delay.hpd_absent); @@ -579,6 +596,8 @@ static int panel_edp_enable(struct drm_panel *panel) panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable); + panel_edp_wait(p->powered_on_time, p->desc->delay.powered_on_to_enable); + p->enabled = true; return 0; @@ -1837,6 +1856,13 @@ static const struct panel_delay delay_200_500_p2e80 = { .prepare_to_enable = 80, }; +static const struct panel_delay delay_200_500_e50_p2e80 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .prepare_to_enable = 80, +}; + static const struct panel_delay delay_200_500_p2e100 = { .hpd_absent = 200, .unprepare = 500, @@ -1874,6 +1900,13 @@ static const struct panel_delay delay_200_500_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e200_d200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 200, + .disable = 200, +}; + static const struct panel_delay delay_200_500_e200_d10 = { .hpd_absent = 200, .unprepare = 500, @@ -1887,6 +1920,13 @@ static const struct panel_delay delay_200_150_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e50_po2e200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .powered_on_to_enable = 200, +}; + #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ { \ .name = _name, \ @@ -1912,7 +1952,9 @@ static const struct panel_delay delay_200_150_e200 = { * Sort first by vendor, then by product ID. */ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), @@ -1923,54 +1965,91 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", &auo_b116xa3_mode), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1", &auo_b116xa3_mode), EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0705, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, "NV133FHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0744, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x074c, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0751, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, "NV116WHM-N45"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0771, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0797, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d3, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f8, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0813, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, "NT140WHM-N44 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0843, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0848, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0849, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x096e, &delay_200_500_e50_po2e200, "NV116WHM-T07 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0993, &delay_200_500_e80, "NV116WHM-T14 V8.0"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ad, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80, "NV116WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1141, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1145, &delay_200_500_e80_d50, "N116BCN-EB1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x114a, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1156, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1157, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50, "MNC207QS1-1"), + + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x048e, &delay_200_500_e200_d10, "M116NWR6 R5"), @@ -1979,11 +2058,25 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x044f, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x1118, &delay_200_500_e50, "KD116N29-30NK-A005"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x044f, &delay_200_500_e50, "KD116N9-30NH-F3"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x05f1, &delay_200_500_e80_d50, "KD116N5-30NV-G7"), EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0000, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x048d, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0497, &delay_200_500_e200_d200, "LP116WH7-SPB1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x052c, &delay_200_500_e200_d200, "LP133WF2-SPL7"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0537, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x054a, &delay_200_500_e200_d200, "LP116WH8-SPC1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0567, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 30919c872ac8d50fc638c468cd968e52bc61855e..9d87cc1a357e3853979ce2b0b4c7f7e45018adda 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -646,26 +646,17 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) return -EINVAL; ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) { - dev_err(dev, "cannot get reset gpio\n"); - return PTR_ERR(ctx->reset_gpio); - } + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n"); ctx->vci = devm_regulator_get(dev, "vci"); - if (IS_ERR(ctx->vci)) { - ret = PTR_ERR(ctx->vci); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request vci regulator: %d\n", ret); - return ret; - } + if (IS_ERR(ctx->vci)) + return dev_err_probe(dev, PTR_ERR(ctx->vci), "Failed to request vci regulator\n"); ctx->iovcc = devm_regulator_get(dev, "iovcc"); - if (IS_ERR(ctx->iovcc)) { - ret = PTR_ERR(ctx->iovcc); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); - return ret; - } + if (IS_ERR(ctx->iovcc)) + return dev_err_probe(dev, PTR_ERR(ctx->iovcc), + "Failed to request iovcc regulator\n"); mipi_dsi_set_drvdata(dsi, ctx); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index 83a9cf53d2690defbf8a07fd428e4f5853fac09e..d3bfdfc9cff641635a7a292e1c76383cb6259f7e 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c @@ -36,6 +36,9 @@ #include #include +#define NT35510_CMD_CORRECT_GAMMA BIT(0) +#define NT35510_CMD_CONTROL_DISPLAY BIT(1) + #define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */ #define MCS_CMD_READ_ID1 0xDA #define MCS_CMD_READ_ID2 0xDB @@ -112,18 +115,33 @@ /* AVDD and AVEE setting 3 bytes */ #define NT35510_P1_AVDD_LEN 3 #define NT35510_P1_AVEE_LEN 3 +#define NT35510_P1_VCL_LEN 3 #define NT35510_P1_VGH_LEN 3 #define NT35510_P1_VGL_LEN 3 #define NT35510_P1_VGP_LEN 3 #define NT35510_P1_VGN_LEN 3 +#define NT35510_P1_VCMOFF_LEN 2 /* BT1CTR thru BT5CTR setting 3 bytes */ #define NT35510_P1_BT1CTR_LEN 3 #define NT35510_P1_BT2CTR_LEN 3 +#define NT35510_P1_BT3CTR_LEN 3 #define NT35510_P1_BT4CTR_LEN 3 #define NT35510_P1_BT5CTR_LEN 3 /* 52 gamma parameters times two per color: positive and negative */ #define NT35510_P1_GAMMA_LEN 52 +#define NT35510_WRCTRLD_BCTRL BIT(5) +#define NT35510_WRCTRLD_A BIT(4) +#define NT35510_WRCTRLD_DD BIT(3) +#define NT35510_WRCTRLD_BL BIT(2) +#define NT35510_WRCTRLD_DB BIT(1) +#define NT35510_WRCTRLD_G BIT(0) + +#define NT35510_WRCABC_OFF 0 +#define NT35510_WRCABC_UI_MODE 1 +#define NT35510_WRCABC_STILL_MODE 2 +#define NT35510_WRCABC_MOVING_MODE 3 + /** * struct nt35510_config - the display-specific NT35510 configuration * @@ -171,6 +189,14 @@ struct nt35510_config { * timing in the display controller. */ const struct drm_display_mode mode; + /** + * @mode_flags: DSI operation mode related flags + */ + unsigned long mode_flags; + /** + * @cmds: enable DSI commands + */ + u32 cmds; /** * @avdd: setting for AVDD ranging from 0x00 = 6.5V to 0x14 = 4.5V * in 0.1V steps the default is 0x05 which means 6.0V @@ -220,6 +246,25 @@ struct nt35510_config { * The defaults are 4 and 3 yielding 0x34 */ u8 bt2ctr[NT35510_P1_BT2CTR_LEN]; + /** + * @vcl: setting for VCL ranging from 0x00 = -2.5V to 0x11 = -4.0V + * in 1V steps, the default is 0x00 which means -2.5V + */ + u8 vcl[NT35510_P1_VCL_LEN]; + /** + * @bt3ctr: setting for boost power control for the VCL step-up + * circuit (3) + * bits 0..2 in the lower nibble controls CLCK, the booster clock + * frequency, the values are the same as for PCK in @bt1ctr. + * bits 4..5 in the upper nibble controls BTCL, the boosting + * amplification for the step-up circuit. + * 0 = Disable + * 1 = -0.5 x VDDB + * 2 = -1 x VDDB + * 3 = -2 x VDDB + * The defaults are 4 and 2 yielding 0x24 + */ + u8 bt3ctr[NT35510_P1_BT3CTR_LEN]; /** * @vgh: setting for VGH ranging from 0x00 = 7.0V to 0x0B = 18.0V * in 1V steps, the default is 0x08 which means 15V @@ -273,6 +318,113 @@ struct nt35510_config { * same layout of bytes as @vgp. */ u8 vgn[NT35510_P1_VGN_LEN]; + /** + * @vcmoff: setting the DC VCOM offset voltage + * The first byte contains bit 8 of VCM in bit 0 and VCMOFFSEL in bit 4. + * The second byte contains bits 0..7 of VCM. + * VCMOFFSEL the common voltage offset mode. + * VCMOFFSEL 0x00 = VCOM .. 0x01 Gamma. + * The default is 0x00. + * VCM the VCOM output voltage (VCMOFFSEL = 0) or the internal register + * offset for gamma voltage (VCMOFFSEL = 1). + * VCM 0x00 = 0V/0 .. 0x118 = 3.5V/280 in steps of 12.5mV/1step + * The default is 0x00 = 0V/0. + */ + u8 vcmoff[NT35510_P1_VCMOFF_LEN]; + /** + * @dopctr: setting optional control for display + * ERR bits 0..1 in the first byte is the ERR pin output signal setting. + * 0 = Disable, ERR pin output low + * 1 = ERR pin output CRC error only + * 2 = ERR pin output ECC error only + * 3 = ERR pin output CRC and ECC error + * The default is 0. + * N565 bit 2 in the first byte is the 16-bit/pixel format selection. + * 0 = R[4:0] + G[5:3] & G[2:0] + B[4:0] + * 1 = G[2:0] + R[4:0] & B[4:0] + G[5:3] + * The default is 0. + * DIS_EoTP_HS bit 3 in the first byte is "DSI protocol violation" error + * reporting. + * 0 = reporting when error + * 1 = not reporting when error + * DSIM bit 4 in the first byte is the video mode data type enable + * 0 = Video mode data type disable + * 1 = Video mode data type enable + * The default is 0. + * DSIG bit 5 int the first byte is the generic r/w data type enable + * 0 = Generic r/w disable + * 1 = Generic r/w enable + * The default is 0. + * DSITE bit 6 in the first byte is TE line enable + * 0 = TE line is disabled + * 1 = TE line is enabled + * The default is 0. + * RAMKP bit 7 in the first byte is the frame memory keep/loss in + * sleep-in mode + * 0 = contents loss in sleep-in + * 1 = contents keep in sleep-in + * The default is 0. + * CRL bit 1 in the second byte is the source driver data shift + * direction selection. This bit is XOR operation with bit RSMX + * of 3600h command. + * 0 (RMSX = 0) = S1 -> S1440 + * 0 (RMSX = 1) = S1440 -> S1 + * 1 (RMSX = 0) = S1440 -> S1 + * 1 (RMSX = 1) = S1 -> S1440 + * The default is 0. + * CTB bit 2 in the second byte is the vertical scanning direction + * selection for gate control signals. This bit is XOR operation + * with bit ML of 3600h command. + * 0 (ML = 0) = Forward (top -> bottom) + * 0 (ML = 1) = Reverse (bottom -> top) + * 1 (ML = 0) = Reverse (bottom -> top) + * 1 (ML = 1) = Forward (top -> bottom) + * The default is 0. + * CRGB bit 3 in the second byte is RGB-BGR order selection. This + * bit is XOR operation with bit RGB of 3600h command. + * 0 (RGB = 0) = RGB/Normal + * 0 (RGB = 1) = BGR/RB swap + * 1 (RGB = 0) = BGR/RB swap + * 1 (RGB = 1) = RGB/Normal + * The default is 0. + * TE_PWR_SEL bit 4 in the second byte is the TE output voltage + * level selection (only valid when DSTB_SEL = 0 or DSTB_SEL = 1, + * VSEL = High and VDDI = 1.665~3.3V). + * 0 = TE output voltage level is VDDI + * 1 = TE output voltage level is VDDA + * The default is 0. + */ + u8 dopctr[NT35510_P0_DOPCTR_LEN]; + /** + * @madctl: Memory data access control + * RSMY bit 0 is flip vertical. Flips the display image top to down. + * RSMX bit 1 is flip horizontal. Flips the display image left to right. + * MH bit 2 is the horizontal refresh order. + * RGB bit 3 is the RGB-BGR order. + * 0 = RGB color sequence + * 1 = BGR color sequence + * ML bit 4 is the vertical refresh order. + * MV bit 5 is the row/column exchange. + * MX bit 6 is the column address order. + * MY bit 7 is the row address order. + */ + u8 madctl; + /** + * @sdhdtctr: source output data hold time + * 0x00..0x3F = 0..31.5us in steps of 0.5us + * The default is 0x05 = 2.5us. + */ + u8 sdhdtctr; + /** + * @gseqctr: EQ control for gate signals + * GFEQ_XX[3:0]: time setting of EQ step for falling edge in steps + * of 0.5us. + * The default is 0x07 = 3.5us + * GREQ_XX[7:4]: time setting of EQ step for rising edge in steps + * of 0.5us. + * The default is 0x07 = 3.5us + */ + u8 gseqctr[NT35510_P0_GSEQCTR_LEN]; /** * @sdeqctr: Source driver control settings, first byte is * 0 for mode 1 and 1 for mode 2. Mode 1 uses two steps and @@ -343,6 +495,43 @@ struct nt35510_config { * @gamma_corr_neg_b: Blue gamma correction parameters, negative */ u8 gamma_corr_neg_b[NT35510_P1_GAMMA_LEN]; + /** + * @wrdisbv: write display brightness + * 0x00 value means the lowest brightness and 0xff value means + * the highest brightness. + * The default is 0x00. + */ + u8 wrdisbv; + /** + * @wrctrld: write control display + * G bit 0 selects gamma curve: 0 = Manual, 1 = Automatic + * DB bit 1 selects display brightness: 0 = Manual, 1 = Automatic + * BL bit 2 controls backlight control: 0 = Off, 1 = On + * DD bit 3 controls display dimming: 0 = Off, 1 = On + * A bit 4 controls LABC block: 0 = Off, 1 = On + * BCTRL bit 5 controls brightness block: 0 = Off, 1 = On + */ + u8 wrctrld; + /** + * @wrcabc: write content adaptive brightness control + * There is possible to use 4 different modes for content adaptive + * image functionality: + * 0: Off + * 1: User Interface Image (UI-Mode) + * 2: Still Picture Image (Still-Mode) + * 3: Moving Picture Image (Moving-Mode) + * The default is 0 + */ + u8 wrcabc; + /** + * @wrcabcmb: write CABC minimum brightness + * Set the minimum brightness value of the display for CABC + * function. + * 0x00 value means the lowest brightness for CABC and 0xff + * value means the highest brightness for CABC. + * The default is 0x00. + */ + u8 wrcabcmb; }; /** @@ -486,6 +675,16 @@ static int nt35510_setup_power(struct nt35510 *nt) nt->conf->bt2ctr); if (ret) return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCL, + NT35510_P1_VCL_LEN, + nt->conf->vcl); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_BT3CTR, + NT35510_P1_BT3CTR_LEN, + nt->conf->bt3ctr); + if (ret) + return ret; ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVGH, NT35510_P1_VGH_LEN, nt->conf->vgh); @@ -522,6 +721,12 @@ static int nt35510_setup_power(struct nt35510 *nt) if (ret) return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCMOFF, + NT35510_P1_VCMOFF_LEN, + nt->conf->vcmoff); + if (ret) + return ret; + /* Typically 10 ms */ usleep_range(10000, 20000); @@ -536,46 +741,28 @@ static int nt35510_setup_display(struct nt35510 *nt) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); const struct nt35510_config *conf = nt->conf; - u8 dopctr[NT35510_P0_DOPCTR_LEN]; - u8 gseqctr[NT35510_P0_GSEQCTR_LEN]; u8 dpfrctr[NT35510_P0_DPFRCTR1_LEN]; - /* FIXME: set up any rotation (assume none for now) */ - u8 addr_mode = NT35510_ROTATE_0_SETTING; - u8 val; int ret; - /* Enable TE, EoTP and RGB pixel format */ - dopctr[0] = NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP | - NT35510_DOPCTR_0_N565; - dopctr[1] = NT35510_DOPCTR_1_CTB; ret = nt35510_send_long(nt, dsi, NT35510_P0_DOPCTR, NT35510_P0_DOPCTR_LEN, - dopctr); + conf->dopctr); if (ret) return ret; - ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &addr_mode, - sizeof(addr_mode)); + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &conf->madctl, + sizeof(conf->madctl)); if (ret < 0) return ret; - /* - * Source data hold time, default 0x05 = 2.5us - * 0x00..0x3F = 0 .. 31.5us in steps of 0.5us - * 0x0A = 5us - */ - val = 0x0A; - ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, &val, - sizeof(val)); + ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, &conf->sdhdtctr, + sizeof(conf->sdhdtctr)); if (ret < 0) return ret; - /* EQ control for gate signals, 0x00 = 0 us */ - gseqctr[0] = 0x00; - gseqctr[1] = 0x00; ret = nt35510_send_long(nt, dsi, NT35510_P0_GSEQCTR, NT35510_P0_GSEQCTR_LEN, - gseqctr); + conf->gseqctr); if (ret) return ret; @@ -719,36 +906,38 @@ static int nt35510_power_on(struct nt35510 *nt) if (ret) return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_r); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_g); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_pos_b); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_r); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_g); - if (ret) - return ret; - ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG, - NT35510_P1_GAMMA_LEN, - nt->conf->gamma_corr_neg_b); - if (ret) - return ret; + if (nt->conf->cmds & NT35510_CMD_CORRECT_GAMMA) { + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_r); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_g); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_pos_b); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_r); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_g); + if (ret) + return ret; + ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG, + NT35510_P1_GAMMA_LEN, + nt->conf->gamma_corr_neg_b); + if (ret) + return ret; + } /* Set up stuff in manufacturer control, page 0 */ ret = nt35510_send_long(nt, dsi, MCS_CMD_MAUCCTR, @@ -827,6 +1016,26 @@ static int nt35510_prepare(struct drm_panel *panel) /* Up to 120 ms */ usleep_range(120000, 150000); + if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) { + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, + &nt->conf->wrctrld, + sizeof(nt->conf->wrctrld)); + if (ret < 0) + return ret; + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE, + &nt->conf->wrcabc, + sizeof(nt->conf->wrcabc)); + if (ret < 0) + return ret; + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, + &nt->conf->wrcabcmb, + sizeof(nt->conf->wrcabcmb)); + if (ret < 0) + return ret; + } + ret = mipi_dsi_dcs_set_display_on(dsi); if (ret) { dev_err(nt->dev, "failed to turn display on (%d)\n", ret); @@ -896,7 +1105,6 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) */ dsi->hs_rate = 349440000; dsi->lp_rate = 9600000; - dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS; /* * Every new incarnation of this display must have a unique @@ -908,6 +1116,8 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) return -ENODEV; } + dsi->mode_flags = nt->conf->mode_flags; + nt->supplies[0].supply = "vdd"; /* 2.3-4.8 V */ nt->supplies[1].supply = "vddi"; /* 1.65-3.3V */ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(nt->supplies), @@ -923,7 +1133,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - nt->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + nt->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(nt->reset_gpio)) { dev_err(dev, "error getting RESET GPIO\n"); return PTR_ERR(nt->reset_gpio); @@ -952,7 +1162,10 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) return PTR_ERR(bl); } bl->props.max_brightness = 255; - bl->props.brightness = 255; + if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) + bl->props.brightness = nt->conf->wrdisbv; + else + bl->props.brightness = 255; bl->props.power = FB_BLANK_POWERDOWN; nt->panel.backlight = bl; } @@ -1030,6 +1243,8 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .vtotal = 800 + 2 + 0 + 5, /* VBP = 5 */ .flags = 0, }, + .mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS, + .cmds = NT35510_CMD_CORRECT_GAMMA, /* 0x09: AVDD = 5.6V */ .avdd = { 0x09, 0x09, 0x09 }, /* 0x34: PCK = Hsync/2, BTP = 2 x VDDB */ @@ -1038,6 +1253,10 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .avee = { 0x09, 0x09, 0x09 }, /* 0x24: NCK = Hsync/2, BTN = -2 x VDDB */ .bt2ctr = { 0x24, 0x24, 0x24 }, + /* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -2.5V */ + .vcl = { 0x00, 0x00, 0x00 }, + /* 0x24: CLCK = Hsync/2, BTN = -1 x VDDB */ + .bt3ctr = { 0x24, 0x24, 0x24 }, /* 0x05 = 12V */ .vgh = { 0x05, 0x05, 0x05 }, /* 0x24: NCKA = Hsync/2, VGH = 2 x AVDD - AVEE */ @@ -1050,6 +1269,16 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .vgp = { 0x00, 0xA3, 0x00 }, /* VGMP: 0x0A3 = 5.0375V, VGSP = 0V */ .vgn = { 0x00, 0xA3, 0x00 }, + /* VCMOFFSEL = VCOM voltage offset mode, VCM = 0V */ + .vcmoff = { 0x00, 0x00 }, + /* Enable TE, EoTP and RGB pixel format */ + .dopctr = { NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP | + NT35510_DOPCTR_0_N565, NT35510_DOPCTR_1_CTB }, + .madctl = NT35510_ROTATE_0_SETTING, + /* 0x0A: SDT = 5 us */ + .sdhdtctr = 0x0A, + /* EQ control for gate signals, 0x00 = 0 us */ + .gseqctr = { 0x00, 0x00 }, /* SDEQCTR: source driver EQ mode 2, 2.5 us rise time on each step */ .sdeqctr = { 0x01, 0x05, 0x05, 0x05 }, /* SDVPCTR: Normal operation off color during v porch */ @@ -1073,7 +1302,88 @@ static const struct nt35510_config nt35510_hydis_hva40wv1 = { .gamma_corr_neg_b = { NT35510_GAMMA_NEG_DEFAULT }, }; +static const struct nt35510_config nt35510_frida_frd400b25025 = { + .width_mm = 52, + .height_mm = 86, + .mode = { + .clock = 23000, + .hdisplay = 480, + .hsync_start = 480 + 34, /* HFP = 34 */ + .hsync_end = 480 + 34 + 2, /* HSync = 2 */ + .htotal = 480 + 34 + 2 + 34, /* HBP = 34 */ + .vdisplay = 800, + .vsync_start = 800 + 15, /* VFP = 15 */ + .vsync_end = 800 + 15 + 12, /* VSync = 12 */ + .vtotal = 800 + 15 + 12 + 15, /* VBP = 15 */ + .flags = 0, + }, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM, + .cmds = NT35510_CMD_CONTROL_DISPLAY, + /* 0x03: AVDD = 6.2V */ + .avdd = { 0x03, 0x03, 0x03 }, + /* 0x46: PCK = 2 x Hsync, BTP = 2.5 x VDDB */ + .bt1ctr = { 0x46, 0x46, 0x46 }, + /* 0x03: AVEE = -6.2V */ + .avee = { 0x03, 0x03, 0x03 }, + /* 0x36: PCK = 2 x Hsync, BTP = 2 x VDDB */ + .bt2ctr = { 0x36, 0x36, 0x36 }, + /* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -3.5V */ + .vcl = { 0x00, 0x00, 0x02 }, + /* 0x26: CLCK = 2 x Hsync, BTN = -1 x VDDB */ + .bt3ctr = { 0x26, 0x26, 0x26 }, + /* 0x09 = 16V */ + .vgh = { 0x09, 0x09, 0x09 }, + /* 0x36: HCK = 2 x Hsync, VGH = 2 x AVDD - AVEE */ + .bt4ctr = { 0x36, 0x36, 0x36 }, + /* 0x08 = -10V */ + .vgl = { 0x08, 0x08, 0x08 }, + /* 0x26: LCK = 2 x Hsync, VGL = AVDD + VCL - AVDD */ + .bt5ctr = { 0x26, 0x26, 0x26 }, + /* VGMP: 0x080 = 4.6V, VGSP = 0V */ + .vgp = { 0x00, 0x80, 0x00 }, + /* VGMP: 0x080 = 4.6V, VGSP = 0V */ + .vgn = { 0x00, 0x80, 0x00 }, + /* VCMOFFSEL = VCOM voltage offset mode, VCM = -1V */ + .vcmoff = { 0x00, 0x50 }, + .dopctr = { NT35510_DOPCTR_0_RAMKP | NT35510_DOPCTR_0_DSITE | + NT35510_DOPCTR_0_DSIG | NT35510_DOPCTR_0_DSIM | + NT35510_DOPCTR_0_EOTP | NT35510_DOPCTR_0_N565, 0 }, + .madctl = NT35510_ROTATE_180_SETTING, + /* 0x03: SDT = 1.5 us */ + .sdhdtctr = 0x03, + /* EQ control for gate signals, 0x00 = 0 us */ + .gseqctr = { 0x00, 0x00 }, + /* SDEQCTR: source driver EQ mode 2, 1 us rise time on each step */ + .sdeqctr = { 0x01, 0x02, 0x02, 0x02 }, + /* SDVPCTR: Normal operation off color during v porch */ + .sdvpctr = 0x01, + /* T1: number of pixel clocks on one scanline: 0x184 = 389 clocks */ + .t1 = 0x0184, + /* VBP: vertical back porch toward the panel */ + .vbp = 0x1C, + /* VFP: vertical front porch toward the panel */ + .vfp = 0x1C, + /* PSEL: divide pixel clock 23MHz with 1 (no clock downscaling) */ + .psel = 0, + /* DPTMCTR12: 0x03: LVGL = VGLX, overlap mode, swap R->L O->E */ + .dpmctr12 = { 0x03, 0x00, 0x00, }, + /* write display brightness */ + .wrdisbv = 0x7f, + /* write control display */ + .wrctrld = NT35510_WRCTRLD_BCTRL | NT35510_WRCTRLD_DD | + NT35510_WRCTRLD_BL, + /* write content adaptive brightness control */ + .wrcabc = NT35510_WRCABC_STILL_MODE, + /* write CABC minimum brightness */ + .wrcabcmb = 0xff, +}; + static const struct of_device_id nt35510_of_match[] = { + { + .compatible = "frida,frd400b25025", + .data = &nt35510_frida_frd400b25025, + }, { .compatible = "hydis,hva40wv1", .data = &nt35510_hydis_hva40wv1, diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c index a189ce23632856a0492446bcc2759101fee8407c..18bd2ee7120100a17fbf66fa0d6659636ed97b69 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c @@ -933,8 +933,7 @@ static int j606f_boe_init_sequence(struct panel_info *pinfo) static const struct drm_display_mode elish_boe_modes[] = { { - /* There is only one 120 Hz timing, but it doesn't work perfectly, 104 Hz preferred */ - .clock = (1600 + 60 + 8 + 60) * (2560 + 26 + 4 + 168) * 104 / 1000, + .clock = (1600 + 60 + 8 + 60) * (2560 + 26 + 4 + 168) * 120 / 1000, .hdisplay = 1600, .hsync_start = 1600 + 60, .hsync_end = 1600 + 60 + 8, @@ -948,8 +947,7 @@ static const struct drm_display_mode elish_boe_modes[] = { static const struct drm_display_mode elish_csot_modes[] = { { - /* There is only one 120 Hz timing, but it doesn't work perfectly, 104 Hz preferred */ - .clock = (1600 + 200 + 40 + 52) * (2560 + 26 + 4 + 168) * 104 / 1000, + .clock = (1600 + 200 + 40 + 52) * (2560 + 26 + 4 + 168) * 120 / 1000, .hdisplay = 1600, .hsync_start = 1600 + 200, .hsync_end = 1600 + 200 + 40, @@ -1270,6 +1268,8 @@ static int nt36523_probe(struct mipi_dsi_device *dsi) return ret; } + pinfo->panel.prepare_prev_first = true; + if (pinfo->desc->has_dcs_backlight) { pinfo->panel.backlight = nt36523_create_backlight(dsi); if (IS_ERR(pinfo->panel.backlight)) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672e.c b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c new file mode 100644 index 0000000000000000000000000000000000000000..cb7406d7446695ebd3566230f3e11fca3b4cc323 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c @@ -0,0 +1,643 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include