diff options
750 files changed, 23731 insertions, 7803 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml new file mode 100644 index 000000000000..d60208359234 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml @@ -0,0 +1,176 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/lontium,lt9611.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lontium LT9611 2 Port MIPI to HDMI Bridge + +maintainers: + - Vinod Koul <[email protected]> + +description: | + The LT9611 is a bridge device which converts DSI to HDMI + +properties: + compatible: + enum: + - lontium,lt9611 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + description: GPIO connected to active high RESET pin. + + vdd-supply: + description: Regulator for 1.8V MIPI phy power. + + vcc-supply: + description: Regulator for 3.3V IO power. + + ports: + type: object + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + port@0: + type: object + description: | + Primary MIPI port-1 for MIPI input + + properties: + reg: + const: 0 + + patternProperties: + "^endpoint(@[0-9])$": + type: object + additionalProperties: false + + properties: + remote-endpoint: + $ref: /schemas/types.yaml#/definitions/phandle + + required: + - reg + + port@1: + type: object + description: | + Additional MIPI port-2 for MIPI input, used in combination + with primary MIPI port-1 to drive higher resolution displays + + properties: + reg: + const: 1 + + patternProperties: + "^endpoint(@[0-9])$": + type: object + additionalProperties: false + + properties: + remote-endpoint: + $ref: /schemas/types.yaml#/definitions/phandle + + required: + - reg + + port@2: + type: object + description: | + HDMI port for HDMI output + + properties: + reg: + const: 2 + + patternProperties: + "^endpoint(@[0-9])$": + type: object + additionalProperties: false + + properties: + remote-endpoint: + $ref: /schemas/types.yaml#/definitions/phandle + + required: + - reg + + required: + - "#address-cells" + - "#size-cells" + - port@0 + - port@2 + +required: + - compatible + - reg + - interrupts + - vdd-supply + - vcc-supply + - ports + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c10 { + #address-cells = <1>; + #size-cells = <0>; + + hdmi-bridge@3b { + compatible = "lontium,lt9611"; + reg = <0x3b>; + + reset-gpios = <&tlmm 128 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&tlmm 84 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <<9611_1v8>; + vcc-supply = <<9611_3v3>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lt9611_a: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + lt9611_b: endpoint { + remote-endpoint = <&dsi1_out>; + }; + }; + + port@2 { + reg = <2>; + lt9611_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml new file mode 100644 index 000000000000..195025e6803c --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/toshiba,tc358762.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Toshiba TC358762 MIPI DSI to MIPI DPI bridge + +maintainers: + - Marek Vasut <[email protected]> + +description: | + The TC358762 is bridge device which converts MIPI DSI to MIPI DPI. + +properties: + compatible: + enum: + - toshiba,tc358762 + + reg: + maxItems: 1 + description: virtual channel number of a DSI peripheral + + vddc-supply: + description: Regulator for 1.2V internal core power. + + ports: + type: object + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + port@0: + type: object + additionalProperties: false + + description: | + Video port for MIPI DSI input + + properties: + reg: + const: 0 + + patternProperties: + endpoint: + type: object + additionalProperties: false + + properties: + remote-endpoint: true + + required: + - reg + + port@1: + type: object + additionalProperties: false + + description: | + Video port for MIPI DPI output (panel or connector). + + properties: + reg: + const: 1 + + patternProperties: + endpoint: + type: object + additionalProperties: false + + properties: + remote-endpoint: true + + required: + - reg + + required: + - "#address-cells" + - "#size-cells" + - port@0 + - port@1 + +required: + - compatible + - reg + - vddc-supply + - ports + +additionalProperties: false + +examples: + - | + i2c1 { + #address-cells = <1>; + #size-cells = <0>; + + bridge@0 { + reg = <0>; + compatible = "toshiba,tc358762"; + vddc-supply = <&vcc_1v2_reg>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + bridge_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + + port@1 { + reg = <1>; + bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml new file mode 100644 index 000000000000..31f085d8ab13 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml @@ -0,0 +1,215 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/toshiba,tc358775.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Toshiba TC358775 DSI to LVDS bridge bindings + +maintainers: + - Vinay Simha BN <[email protected]> + +description: | + This binding supports DSI to LVDS bridge TC358775 + + MIPI DSI-RX Data 4-lane, CLK 1-lane with data rates up to 800 Mbps/lane. + Video frame size: + Up to 1600x1200 24-bit/pixel resolution for single-link LVDS display panel + limited by 135 MHz LVDS speed + Up to WUXGA (1920x1200 24-bit pixels) resolution for dual-link LVDS display + panel, limited by 270 MHz LVDS speed. + +properties: + compatible: + const: toshiba,tc358775 + + reg: + maxItems: 1 + description: i2c address of the bridge, 0x0f + + vdd-supply: + maxItems: 1 + description: 1.2V LVDS Power Supply + + vddio-supply: + maxItems: 1 + description: 1.8V IO Power Supply + + stby-gpios: + maxItems: 1 + description: Standby pin, Low active + + reset-gpios: + maxItems: 1 + description: Hardware reset, Low active + + ports: + type: object + description: + A node containing input and output port nodes with endpoint definitions + as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + port@0: + type: object + description: | + DSI Input. The remote endpoint phandle should be a + reference to a valid mipi_dsi_host device node. + + port@1: + type: object + description: | + Video port for LVDS output (panel or connector). + + port@2: + type: object + description: | + Video port for Dual link LVDS output (panel or connector). + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - vdd-supply + - vddio-supply + - stby-gpios + - reset-gpios + - ports + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + /* For single-link LVDS display panel */ + + i2c@78b8000 { + /* On High speed expansion */ + label = "HS-I2C2"; + reg = <0x078b8000 0x500>; + clock-frequency = <400000>; /* fastmode operation */ + #address-cells = <1>; + #size-cells = <0>; + + tc_bridge: bridge@f { + compatible = "toshiba,tc358775"; + reg = <0x0f>; + + vdd-supply = <&pm8916_l2>; + vddio-supply = <&pm8916_l6>; + + stby-gpios = <&msmgpio 99 GPIO_ACTIVE_LOW>; + reset-gpios = <&msmgpio 72 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + d2l_in_test: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + lvds_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; + }; + + dsi@1a98000 { + reg = <0x1a98000 0x25c>; + reg-names = "dsi_ctrl"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@1 { + reg = <1>; + dsi0_out: endpoint { + remote-endpoint = <&d2l_in_test>; + data-lanes = <0 1 2 3>; + }; + }; + }; + }; + + - | + /* For dual-link LVDS display panel */ + + i2c@78b8000 { + /* On High speed expansion */ + label = "HS-I2C2"; + reg = <0x078b8000 0x500>; + clock-frequency = <400000>; /* fastmode operation */ + #address-cells = <1>; + #size-cells = <0>; + + tc_bridge_dual: bridge@f { + compatible = "toshiba,tc358775"; + reg = <0x0f>; + + vdd-supply = <&pm8916_l2>; + vddio-supply = <&pm8916_l6>; + + stby-gpios = <&msmgpio 99 GPIO_ACTIVE_LOW>; + reset-gpios = <&msmgpio 72 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + d2l_in_dual: endpoint { + remote-endpoint = <&dsi0_out_dual>; + }; + }; + + port@1 { + reg = <1>; + lvds0_out: endpoint { + remote-endpoint = <&panel_in0>; + }; + }; + + port@2 { + reg = <2>; + lvds1_out: endpoint { + remote-endpoint = <&panel_in1>; + }; + }; + }; + }; + }; + + dsi@1a98000 { + reg = <0x1a98000 0x25c>; + reg-names = "dsi_ctrl"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@1 { + reg = <1>; + dsi0_out_dual: endpoint { + remote-endpoint = <&d2l_in_dual>; + data-lanes = <0 1 2 3>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml index 76a9068a85dd..c60b3bd74337 100644 --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml @@ -13,7 +13,9 @@ properties: compatible: items: - enum: - - bananapi,lhr050h41 + - bananapi,lhr050h41 + - feixin,k101-im2byl02 + - const: ilitek,ili9881c backlight: true diff --git a/Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml b/Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml new file mode 100644 index 000000000000..937323cc9aaa --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/mantix,mlaf057we51-x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mantix MLAF057WE51-X 5.7" 720x1440 TFT LCD panel + +maintainers: + - Guido Günther <[email protected]> + +description: + Mantix MLAF057WE51 X is a 720x1440 TFT LCD panel connected using + a MIPI-DSI video interface. + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + enum: + - mantix,mlaf057we51-x + + port: true + reg: + maxItems: 1 + description: DSI virtual channel + + avdd-supply: + description: Positive analog power supply + + avee-supply: + description: Negative analog power supply + + vddi-supply: + description: 1.8V I/O voltage supply + + reset-gpios: true + + backlight: true + +required: + - compatible + - reg + - avdd-supply + - avee-supply + - vddi-supply + - reset-gpios + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + dsi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "mantix,mlaf057we51-x"; + reg = <0>; + avdd-supply = <®_avdd>; + avee-supply = <®_avee>; + vddi-supply = <®_1v8_p>; + reset-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>; + backlight = <&backlight>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 6deeeed59e59..f2204f17a9dc 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -87,6 +87,8 @@ properties: - cdtech,s070swv29hg-dc44 # CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel - cdtech,s070wv95-ct16 + # Chefree CH101OLHLWH-002 10.1" (1280x800) color TFT LCD panel + - chefree,ch101olhlwh-002 # Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel - chunghwa,claa070wp03xg # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel @@ -159,6 +161,8 @@ properties: - innolux,n156bge-l21 # Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel - innolux,zj070na-01p + # King & Display KD116N21-30NV-A010 eDP TFT LCD panel + - kingdisplay,kd116n21-30nv-a010 # Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel - koe,tx14d24vm1bpa # Kaohsiung Opto-Electronics Inc. 10.1" WUXGA (1920 x 1200) LVDS TFT LCD panel @@ -219,6 +223,8 @@ properties: - osddisplays,osd070t1718-19ts # One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel - osddisplays,osd101t2045-53ts + # POWERTIP PH800480T013-IDF2 7.0" WVGA TFT LCD panel + - powertip,ph800480t013-idf02 # QiaoDian XianShi Corporation 4"3 TFT LCD panel - qiaodian,qd43003c0-40 # Rocktech Displays Ltd. RK101II01D-CT 10.1" TFT 1280x800 diff --git a/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml b/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml index d5733ef30954..09b5eb7542f8 100644 --- a/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml +++ b/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml @@ -8,10 +8,11 @@ title: Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel maintainers: - Ondrej Jirman <[email protected]> + - Guido Gŭnther <[email protected]> -description: | - Rocktech JH057N00900 is a 720x1440 TFT LCD panel - connected using a MIPI-DSI video interface. +description: + Rocktech JH057N00900 is a 720x1440 TFT LCD panel + connected using a MIPI-DSI video interface. allOf: - $ref: panel-common.yaml# @@ -19,9 +20,9 @@ allOf: properties: compatible: enum: - # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel + # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel - rocktech,jh057n00900 - # Xingbangda XBD599 5.99" 720x1440 TFT LCD panel + # Xingbangda XBD599 5.99" 720x1440 TFT LCD panel - xingbangda,xbd599 port: true @@ -35,13 +36,9 @@ properties: iovcc-supply: description: I/O voltage supply - reset-gpios: - description: GPIO used for the reset pin - maxItems: 1 + reset-gpios: true - backlight: - description: Backlight used by the panel - $ref: "/schemas/types.yaml#/definitions/phandle" + backlight: true required: - compatible @@ -57,15 +54,16 @@ examples: #include <dt-bindings/gpio/gpio.h> dsi { - #address-cells = <1>; - #size-cells = <0>; - panel@0 { - compatible = "rocktech,jh057n00900"; - reg = <0>; - vcc-supply = <®_2v8_p>; - iovcc-supply = <®_1v8_p>; - reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>; - backlight = <&backlight>; - }; + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "rocktech,jh057n00900"; + reg = <0>; + vcc-supply = <®_2v8_p>; + iovcc-supply = <®_1v8_p>; + reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>; + backlight = <&backlight>; + }; }; + ... diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 63996ab03521..8f27994d4497 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -197,6 +197,8 @@ patternProperties: description: Ceva, Inc. "^checkpoint,.*": description: Check Point Software Technologies Ltd. + "^chefree,.*": + description: Chefree Technology Corp. "^chipidea,.*": description: Chipidea, Inc "^chipone,.*": @@ -601,6 +603,8 @@ patternProperties: description: Logic Technologies Limited "^longcheer,.*": description: Longcheer Technology (Shanghai) Co., Ltd. + "^lontium,.*": + description: Lontium Semiconductor Corporation "^loongson,.*": description: Loongson Technology Corporation Limited "^lsi,.*": @@ -611,6 +615,8 @@ patternProperties: description: Linux Automation GmbH "^macnica,.*": description: Macnica Americas + "^mantix,.*": + description: Mantix Display Technology Co.,Ltd. "^mapleboard,.*": description: Mapleboard.org "^marvell,.*": @@ -830,6 +836,8 @@ patternProperties: description: Poslab Technology Co., Ltd. "^pov,.*": description: Point of View International B.V. + "^powertip,.*": + description: Powertip Tech. Corp. "^powervr,.*": description: PowerVR (deprecated, use img) "^primux,.*": diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index 17112352f605..29ca5f5feb35 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -153,7 +153,7 @@ This section covers hwmon and power/thermal controls. HWMON Interfaces ---------------- -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: hwmon GPU sysfs Power State Interfaces @@ -164,48 +164,54 @@ GPU power controls are exposed via sysfs files. power_dpm_state ~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: power_dpm_state power_dpm_force_performance_level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: power_dpm_force_performance_level pp_table ~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: pp_table pp_od_clk_voltage ~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: pp_od_clk_voltage pp_dpm_* ~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk pp_dpm_pcie pp_power_profile_mode ~~~~~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: pp_power_profile_mode *_busy_percent ~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: gpu_busy_percent -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: mem_busy_percent +gpu_metrics +~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c + :doc: gpu_metrics + GPU Product Information ======================= @@ -233,7 +239,7 @@ serial_number unique_id --------- -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: unique_id GPU Memory Usage Information @@ -283,7 +289,7 @@ PCIe Accounting Information pcie_bw ------- -.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: pcie_bw pcie_replay_count diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 496d8fcd4da0..7dce175f6d75 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -1,3 +1,5 @@ +.. Copyright 2020 DisplayLink (UK) Ltd. + =================== Userland interfaces =================== @@ -162,6 +164,116 @@ other hand, a driver requires shared state between clients which is visible to user-space and accessible beyond open-file boundaries, they cannot support render nodes. +Device Hot-Unplug +================= + +.. note:: + The following is the plan. Implementation is not there yet + (2020 May). + +Graphics devices (display and/or render) may be connected via USB (e.g. +display adapters or docking stations) or Thunderbolt (e.g. eGPU). An end +user is able to hot-unplug this kind of devices while they are being +used, and expects that the very least the machine does not crash. Any +damage from hot-unplugging a DRM device needs to be limited as much as +possible and userspace must be given the chance to handle it if it wants +to. Ideally, unplugging a DRM device still lets a desktop continue to +run, but that is going to need explicit support throughout the whole +graphics stack: from kernel and userspace drivers, through display +servers, via window system protocols, and in applications and libraries. + +Other scenarios that should lead to the same are: unrecoverable GPU +crash, PCI device disappearing off the bus, or forced unbind of a driver +from the physical device. + +In other words, from userspace perspective everything needs to keep on +working more or less, until userspace stops using the disappeared DRM +device and closes it completely. Userspace will learn of the device +disappearance from the device removed uevent, ioctls returning ENODEV +(or driver-specific ioctls returning driver-specific things), or open() +returning ENXIO. + +Only after userspace has closed all relevant DRM device and dmabuf file +descriptors and removed all mmaps, the DRM driver can tear down its +instance for the device that no longer exists. If the same physical +device somehow comes back in the mean time, it shall be a new DRM +device. + +Similar to PIDs, chardev minor numbers are not recycled immediately. A +new DRM device always picks the next free minor number compared to the +previous one allocated, and wraps around when minor numbers are +exhausted. + +The goal raises at least the following requirements for the kernel and +drivers. + +Requirements for KMS UAPI +------------------------- + +- KMS connectors must change their status to disconnected. + +- Legacy modesets and pageflips, and atomic commits, both real and + TEST_ONLY, and any other ioctls either fail with ENODEV or fake + success. + +- Pending non-blocking KMS operations deliver the DRM events userspace + is expecting. This applies also to ioctls that faked success. + +- open() on a device node whose underlying device has disappeared will + fail with ENXIO. + +- Attempting to create a DRM lease on a disappeared DRM device will + fail with ENODEV. Existing DRM leases remain and work as listed + above. + +Requirements for Render and Cross-Device UAPI +--------------------------------------------- + +- All GPU jobs that can no longer run must have their fences + force-signalled to avoid inflicting hangs on userspace. + The associated error code is ENODEV. + +- Some userspace APIs already define what should happen when the device + disappears (OpenGL, GL ES: `GL_KHR_robustness`_; `Vulkan`_: + VK_ERROR_DEVICE_LOST; etc.). DRM drivers are free to implement this + behaviour the way they see best, e.g. returning failures in + driver-specific ioctls and handling those in userspace drivers, or + rely on uevents, and so on. + +- dmabuf which point to memory that has disappeared will either fail to + import with ENODEV or continue to be successfully imported if it would + have succeeded before the disappearance. See also about memory maps + below for already imported dmabufs. + +- Attempting to import a dmabuf to a disappeared device will either fail + with ENODEV or succeed if it would have succeeded without the + disappearance. + +- open() on a device node whose underlying device has disappeared will + fail with ENXIO. + +.. _GL_KHR_robustness: https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_robustness.txt +.. _Vulkan: https://www.khronos.org/vulkan/ + +Requirements for Memory Maps +---------------------------- + +Memory maps have further requirements that apply to both existing maps +and maps created after the device has disappeared. If the underlying +memory disappears, the map is created or modified such that reads and +writes will still complete successfully but the result is undefined. +This applies to both userspace mmap()'d memory and memory pointed to by +dmabuf which might be mapped to other devices (cross-device dmabuf +imports). + +Raising SIGBUS is not an option, because userspace cannot realistically +handle it. Signal handlers are global, which makes them extremely +difficult to use correctly from libraries like those that Mesa produces. +Signal handlers are not composable, you can't have different handlers +for GPU1 and GPU2 from different vendors, and a third handler for +mmapped regular files. Threads cause additional pain with signal +handling as well. + .. _drm_driver_ioctl: IOCTL Support on Device Nodes @@ -199,7 +311,7 @@ EPERM/EACCES: difference between EACCES and EPERM. ENODEV: - The device is not (yet) present or fully initialized. + The device is not present anymore or is not yet fully initialized. EOPNOTSUPP: Feature (like PRIME, modesetting, GEM) is not supported by the driver. diff --git a/Documentation/gpu/pl111.rst b/Documentation/gpu/pl111.rst index 9b03736d33dd..6d9a1b59a545 100644 --- a/Documentation/gpu/pl111.rst +++ b/Documentation/gpu/pl111.rst @@ -1,6 +1,6 @@ -========================================== - drm/pl111 ARM PrimeCell PL111 CLCD Driver -========================================== +==================================================== + drm/pl111 ARM PrimeCell PL110 and PL111 CLCD Driver +==================================================== .. kernel-doc:: drivers/gpu/drm/pl111/pl111_drv.c - :doc: ARM PrimeCell PL111 CLCD Driver + :doc: ARM PrimeCell PL110 and PL111 CLCD Driver diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 7969f106877d..b0ea17da8ff6 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -403,6 +403,52 @@ Contact: Emil Velikov, respective driver maintainers Level: Intermediate +Plumb drm_atomic_state all over +------------------------------- + +Currently various atomic functions take just a single or a handful of +object states (eg. plane state). While that single object state can +suffice for some simple cases, we often have to dig out additional +object states for dealing with various dependencies between the individual +objects or the hardware they represent. The process of digging out the +additional states is rather non-intuitive and error prone. + +To fix that most functions should rather take the overall +drm_atomic_state as one of their parameters. The other parameters +would generally be the object(s) we mainly want to interact with. + +For example, instead of + +.. code-block:: c + + int (*atomic_check)(struct drm_plane *plane, struct drm_plane_state *state); + +we would have something like + +.. code-block:: c + + int (*atomic_check)(struct drm_plane *plane, struct drm_atomic_state *state); + +The implementation can then trivially gain access to any required object +state(s) via drm_atomic_get_plane_state(), drm_atomic_get_new_plane_state(), +drm_atomic_get_old_plane_state(), and their equivalents for +other object types. + +Additionally many drivers currently access the object->state pointer +directly in their commit functions. That is not going to work if we +eg. want to allow deeper commit pipelines as those pointers could +then point to the states corresponding to a future commit instead of +the current commit we're trying to process. Also non-blocking commits +execute locklessly so there are serious concerns with dereferencing +the object->state pointers without holding the locks that protect them. +Use of drm_atomic_get_new_plane_state(), drm_atomic_get_old_plane_state(), +etc. avoids these problems as well since they relate to a specific +commit via the passed in drm_atomic_state. + +Contact: Ville Syrjälä, Daniel Vetter + +Level: Intermediate + Core refactorings ================= diff --git a/MAINTAINERS b/MAINTAINERS index b5cfab015bd6..a2fc087b7d37 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5493,12 +5493,19 @@ S: Maintained F: drivers/gpu/drm/panel/panel-lvds.c F: Documentation/devicetree/bindings/display/panel/lvds.yaml +DRM DRIVER FOR MANTIX MLAF057WE51 PANELS +M: Guido Günther <[email protected]> +R: Purism Kernel Team <[email protected]> +S: Maintained +F: Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml +F: drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c + DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS S: Orphan / Obsolete F: drivers/gpu/drm/mga/ F: include/uapi/drm/mga_drm.h -DRM DRIVER FOR MGA G200 SERVER GRAPHICS CHIPS +DRM DRIVER FOR MGA G200 GRAPHICS CHIPS M: Dave Airlie <[email protected]> S: Odd Fixes F: drivers/gpu/drm/mgag200/ @@ -5786,7 +5793,7 @@ F: drivers/gpu/drm/gma500/ DRM DRIVERS FOR HISILICON M: Xinliang Liu <[email protected]> -M: Rongrong Zou <[email protected]> +M: Tian Tao <[email protected]> R: John Stultz <[email protected]> R: Xinwei Kong <[email protected]> R: Chen Feng <[email protected]> diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 403ec3db29df..39976c7b100c 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -30,7 +30,7 @@ FULL_AMD_DISPLAY_PATH = $(FULL_AMD_PATH)/$(DISPLAY_FOLDER_NAME) ccflags-y := -I$(FULL_AMD_PATH)/include/asic_reg \ -I$(FULL_AMD_PATH)/include \ -I$(FULL_AMD_PATH)/amdgpu \ - -I$(FULL_AMD_PATH)/powerplay/inc \ + -I$(FULL_AMD_PATH)/pm/inc \ -I$(FULL_AMD_PATH)/acp/include \ -I$(FULL_AMD_DISPLAY_PATH) \ -I$(FULL_AMD_DISPLAY_PATH)/include \ @@ -47,7 +47,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \ amdgpu_encoders.o amdgpu_display.o amdgpu_i2c.o \ amdgpu_fb.o amdgpu_gem.o amdgpu_ring.o \ amdgpu_cs.o amdgpu_bios.o amdgpu_benchmark.o amdgpu_test.o \ - amdgpu_pm.o atombios_dp.o amdgpu_afmt.o amdgpu_trace_points.o \ + atombios_dp.o amdgpu_afmt.o amdgpu_trace_points.o \ atombios_encoders.o amdgpu_sa.o atombios_i2c.o \ amdgpu_dma_buf.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \ amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \ @@ -55,15 +55,15 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \ amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o amdgpu_ids.o \ amdgpu_gmc.o amdgpu_mmhub.o amdgpu_xgmi.o amdgpu_csa.o amdgpu_ras.o amdgpu_vm_cpu.o \ amdgpu_vm_sdma.o amdgpu_discovery.o amdgpu_ras_eeprom.o amdgpu_nbio.o \ - amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o + amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o amdgpu-$(CONFIG_PERF_EVENTS) += amdgpu_pmu.o # add asic specific block -amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \ +amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o \ dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o -amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce_v6_0.o si_dpm.o si_smc.o \ +amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce_v6_0.o \ uvd_v3_1.o amdgpu-y += \ @@ -85,7 +85,7 @@ amdgpu-y += \ # add UMC block amdgpu-y += \ - umc_v6_1.o umc_v6_0.o + umc_v6_1.o umc_v6_0.o umc_v8_7.o # add IH block amdgpu-y += \ @@ -105,10 +105,6 @@ amdgpu-y += \ psp_v11_0.o \ psp_v12_0.o -# add SMC block -amdgpu-y += \ - amdgpu_dpm.o - # add DCE block amdgpu-y += \ dce_v10_0.o \ @@ -212,7 +208,7 @@ amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o amdgpu-$(CONFIG_HMM_MIRROR) += amdgpu_mn.o -include $(FULL_AMD_PATH)/powerplay/Makefile +include $(FULL_AMD_PATH)/pm/Makefile amdgpu-y += $(AMD_POWERPLAY_FILES) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 327a0daf4a1d..4009d2e30727 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -178,6 +178,7 @@ extern uint amdgpu_dm_abm_level; extern struct amdgpu_mgpu_info mgpu_info; extern int amdgpu_ras_enable; extern uint amdgpu_ras_mask; +extern int amdgpu_bad_page_threshold; extern int amdgpu_async_gfx_ring; extern int amdgpu_mcbp; extern int amdgpu_discovery; @@ -187,9 +188,11 @@ extern int amdgpu_force_asic_type; #ifdef CONFIG_HSA_AMD extern int sched_policy; extern bool debug_evictions; +extern bool no_system_mem_limit; #else static const int sched_policy = KFD_SCHED_POLICY_HWS; static const bool debug_evictions; /* = false */ +static const bool no_system_mem_limit; #endif extern int amdgpu_tmz; @@ -201,6 +204,7 @@ extern int amdgpu_si_support; #ifdef CONFIG_DRM_AMDGPU_CIK extern int amdgpu_cik_support; #endif +extern int amdgpu_num_kcq; #define AMDGPU_VM_MAX_NUM_CTX 4096 #define AMDGPU_SG_THRESHOLD (256*1024*1024) @@ -212,6 +216,8 @@ extern int amdgpu_cik_support; #define AMDGPUFB_CONN_LIMIT 4 #define AMDGPU_BIOS_NUM_SCRATCH 16 +#define AMDGPU_VBIOS_VGA_ALLOCATION (9 * 1024 * 1024) /* reserve 8MB for vga emulator and 1 MB for FB */ + /* hard reset data */ #define AMDGPU_ASIC_RESET_DATA 0x39d5e86b @@ -245,6 +251,7 @@ struct amdgpu_fpriv; struct amdgpu_bo_va_mapping; struct amdgpu_atif; struct kfd_vm_fault_info; +struct amdgpu_hive_info; enum amdgpu_cp_irq { AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP = 0, @@ -611,6 +618,8 @@ struct amdgpu_asic_funcs { uint64_t (*get_pcie_replay_count)(struct amdgpu_device *adev); /* device supports BACO */ bool (*supports_baco)(struct amdgpu_device *adev); + /* pre asic_init quirks */ + void (*pre_asic_init)(struct amdgpu_device *adev); }; /* @@ -648,16 +657,6 @@ struct amdgpu_atcs { }; /* - * Firmware VRAM reservation - */ -struct amdgpu_fw_vram_usage { - u64 start_offset; - u64 size; - struct amdgpu_bo *reserved_bo; - void *va; -}; - -/* * CGS */ struct cgs_device *amdgpu_cgs_create_device(struct amdgpu_device *adev); @@ -725,13 +724,13 @@ struct amd_powerplay { #define AMDGPU_MAX_DF_PERFMONS 4 struct amdgpu_device { struct device *dev; - struct drm_device *ddev; struct pci_dev *pdev; + struct drm_device ddev; #ifdef CONFIG_DRM_AMD_ACP struct amdgpu_acp acp; #endif - + struct amdgpu_hive_info *hive; /* ASIC */ enum amd_asic_type asic_type; uint32_t family; @@ -765,7 +764,6 @@ struct amdgpu_device { bool is_atom_fw; uint8_t *bios; uint32_t bios_size; - struct amdgpu_bo *stolen_vga_memory; uint32_t bios_scratch_reg_offset; uint32_t bios_scratch[AMDGPU_BIOS_NUM_SCRATCH]; @@ -917,11 +915,6 @@ struct amdgpu_device { /* display related functionality */ struct amdgpu_display_manager dm; - /* discovery */ - uint8_t *discovery_bin; - uint32_t discovery_tmr_size; - struct amdgpu_bo *discovery_memory; - /* mes */ bool enable_mes; struct amdgpu_mes mes; @@ -946,8 +939,6 @@ struct amdgpu_device { struct delayed_work delayed_init_work; struct amdgpu_virt virt; - /* firmware VRAM reservation */ - struct amdgpu_fw_vram_usage fw_vram_usage; /* link all shadow bo */ struct list_head shadow_list; @@ -961,9 +952,9 @@ struct amdgpu_device { bool in_suspend; bool in_hibernate; - bool in_gpu_reset; + atomic_t in_gpu_reset; enum pp_mp1_state mp1_state; - struct mutex lock_reset; + struct rw_semaphore reset_sem; struct amdgpu_doorbell_index doorbell_index; struct mutex notifier_lock; @@ -995,16 +986,25 @@ struct amdgpu_device { atomic_t throttling_logging_enabled; struct ratelimit_state throttling_logging_rs; + uint32_t ras_features; }; +static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev) +{ + return container_of(ddev, struct amdgpu_device, ddev); +} + +static inline struct drm_device *adev_to_drm(struct amdgpu_device *adev) +{ + return &adev->ddev; +} + static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev) { return container_of(bdev, struct amdgpu_device, mman.bdev); } int amdgpu_device_init(struct amdgpu_device *adev, - struct drm_device *ddev, - struct pci_dev *pdev, uint32_t flags); void amdgpu_device_fini(struct amdgpu_device *adev); int amdgpu_gpu_wait_for_idle(struct amdgpu_device *adev); @@ -1141,10 +1141,12 @@ int emu_soc_asic_init(struct amdgpu_device *adev); #define amdgpu_asic_need_reset_on_init(adev) (adev)->asic_funcs->need_reset_on_init((adev)) #define amdgpu_asic_get_pcie_replay_count(adev) ((adev)->asic_funcs->get_pcie_replay_count((adev))) #define amdgpu_asic_supports_baco(adev) (adev)->asic_funcs->supports_baco((adev)) +#define amdgpu_asic_pre_asic_init(adev) (adev)->asic_funcs->pre_asic_init((adev)) #define amdgpu_inc_vram_lost(adev) atomic_inc(&((adev)->vram_lost_counter)); /* Common functions */ +bool amdgpu_device_has_job_running(struct amdgpu_device *adev); bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev); int amdgpu_device_gpu_recover(struct amdgpu_device *adev, struct amdgpu_job* job); @@ -1194,7 +1196,7 @@ static inline void *amdgpu_atpx_get_dhandle(void) { return NULL; } extern const struct drm_ioctl_desc amdgpu_ioctls_kms[]; extern const int amdgpu_max_kms_ioctl; -int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags); +int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags); void amdgpu_driver_unload_kms(struct drm_device *dev); void amdgpu_driver_lastclose_kms(struct drm_device *dev); int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv); @@ -1278,4 +1280,8 @@ static inline bool amdgpu_is_tmz(struct amdgpu_device *adev) return adev->gmc.tmz_enabled; } +static inline int amdgpu_in_reset(struct amdgpu_device *adev) +{ + return atomic_read(&adev->in_gpu_reset); +} #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index 12247a32f9ef..d3e51d361179 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c @@ -136,9 +136,7 @@ static int acp_poweroff(struct generic_pm_domain *genpd) * 2. power off the acp tiles * 3. check and enter ulv state */ - if (adev->powerplay.pp_funcs && - adev->powerplay.pp_funcs->set_powergating_by_smu) - amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true); } return 0; } @@ -157,8 +155,7 @@ static int acp_poweron(struct generic_pm_domain *genpd) * 2. turn on acp clock * 3. power on acp tiles */ - if (adev->powerplay.pp_funcs->set_powergating_by_smu) - amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false); } return 0; } @@ -529,9 +526,7 @@ static int acp_set_powergating_state(void *handle, struct amdgpu_device *adev = (struct amdgpu_device *)handle; bool enable = (state == AMD_PG_STATE_GATE); - if (adev->powerplay.pp_funcs && - adev->powerplay.pp_funcs->set_powergating_by_smu) - amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 913c8f0513bd..4a93b880c6bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -463,11 +463,11 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, if (req.pending & ATIF_DGPU_DISPLAY_EVENT) { if (adev->flags & AMD_IS_PX) { - pm_runtime_get_sync(adev->ddev->dev); + pm_runtime_get_sync(adev_to_drm(adev)->dev); /* Just fire off a uevent and let userspace tell us what to do */ - drm_helper_hpd_irq_event(adev->ddev); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + drm_helper_hpd_irq_event(adev_to_drm(adev)); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); } } /* TODO: check other events */ @@ -817,7 +817,7 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) struct drm_encoder *tmp; /* Find the encoder controlling the brightness */ - list_for_each_entry(tmp, &adev->ddev->mode_config.encoder_list, + list_for_each_entry(tmp, &adev_to_drm(adev)->mode_config.encoder_list, head) { struct amdgpu_encoder *enc = to_amdgpu_encoder(tmp); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 1b865fed74ca..edff1b7f282a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -119,7 +119,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) .gpuvm_size = min(adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT, AMDGPU_GMC_HOLE_START), - .drm_render_minor = adev->ddev->render->index, + .drm_render_minor = adev_to_drm(adev)->render->index, .sdma_doorbell_idx = adev->doorbell_index.sdma_engine, }; @@ -160,7 +160,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) adev->doorbell_index.last_non_cp; } - kgd2kfd_device_init(adev->kfd.dev, adev->ddev, &gpu_resources); + kgd2kfd_device_init(adev->kfd.dev, adev_to_drm(adev), &gpu_resources); } } @@ -479,11 +479,11 @@ int amdgpu_amdkfd_get_dmabuf_info(struct kgd_dev *kgd, int dma_buf_fd, goto out_put; obj = dma_buf->priv; - if (obj->dev->driver != adev->ddev->driver) + if (obj->dev->driver != adev_to_drm(adev)->driver) /* Can't handle buffers from different drivers */ goto out_put; - adev = obj->dev->dev_private; + adev = drm_to_adev(obj->dev); bo = gem_to_amdgpu_bo(obj); if (!(bo->preferred_domains & (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT))) @@ -517,8 +517,9 @@ out_put: uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd) { struct amdgpu_device *adev = (struct amdgpu_device *)kgd; + struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); - return amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); + return amdgpu_vram_mgr_usage(vram_man); } uint64_t amdgpu_amdkfd_get_hive_id(struct kgd_dev *kgd) @@ -612,6 +613,7 @@ int amdgpu_amdkfd_submit_ib(struct kgd_dev *kgd, enum kgd_engine_type engine, job->vmid = vmid; ret = amdgpu_ib_schedule(ring, 1, ib, job, &f); + if (ret) { DRM_ERROR("amdgpu: failed to schedule IB.\n"); goto err_ib_sched; @@ -755,4 +757,8 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry) void kgd2kfd_set_sram_ecc_flag(struct kfd_dev *kfd) { } + +void kgd2kfd_smi_event_throttle(struct kfd_dev *kfd, uint32_t throttle_bitmask) +{ +} #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index ffe149aafc39..a10507ecb750 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -270,5 +270,6 @@ int kgd2kfd_resume_mm(struct mm_struct *mm); int kgd2kfd_schedule_evict_and_restore_process(struct mm_struct *mm, struct dma_fence *fence); void kgd2kfd_set_sram_ecc_flag(struct kfd_dev *kfd); +void kgd2kfd_smi_event_throttle(struct kfd_dev *kfd, uint32_t throttle_bitmask); #endif /* AMDGPU_AMDKFD_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c index 35d4a5ab0228..1afa8f122e7d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c @@ -283,22 +283,6 @@ static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, return 0; } -static void kgd_set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid, - uint64_t page_table_base) -{ - struct amdgpu_device *adev = get_amdgpu_device(kgd); - - if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) { - pr_err("trying to set page table base for wrong VMID %u\n", - vmid); - return; - } - - mmhub_v9_4_setup_vm_pt_regs(adev, vmid, page_table_base); - - gfxhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base); -} - const struct kfd2kgd_calls arcturus_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, @@ -317,7 +301,7 @@ const struct kfd2kgd_calls arcturus_kfd2kgd = { .wave_control_execute = kgd_gfx_v9_wave_control_execute, .address_watch_get_offset = kgd_gfx_v9_address_watch_get_offset, .get_atc_vmid_pasid_mapping_info = - kgd_gfx_v9_get_atc_vmid_pasid_mapping_info, - .set_vm_context_page_table_base = kgd_set_vm_context_page_table_base, - .get_hive_id = amdgpu_amdkfd_get_hive_id, + kgd_gfx_v9_get_atc_vmid_pasid_mapping_info, + .set_vm_context_page_table_base = + kgd_gfx_v9_set_vm_context_page_table_base, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c index bf927f432506..df0aab0fc67e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c @@ -542,7 +542,7 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd, uint32_t temp; struct v10_compute_mqd *m = get_mqd(mqd); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EIO; #if 0 @@ -776,6 +776,4 @@ const struct kfd2kgd_calls gfx_v10_kfd2kgd = { .get_atc_vmid_pasid_mapping_info = get_atc_vmid_pasid_mapping_info, .set_vm_context_page_table_base = set_vm_context_page_table_base, - .get_hive_id = amdgpu_amdkfd_get_hive_id, - .get_unique_id = amdgpu_amdkfd_get_unique_id, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c index cdea1338c8dc..5b38f848b772 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c @@ -822,7 +822,6 @@ const struct kfd2kgd_calls gfx_v10_3_kfd2kgd = { .address_watch_get_offset = address_watch_get_offset_v10_3, .get_atc_vmid_pasid_mapping_info = NULL, .set_vm_context_page_table_base = set_vm_context_page_table_base_v10_3, - .get_hive_id = amdgpu_amdkfd_get_hive_id, #if 0 .enable_debug_trap = enable_debug_trap_v10_3, .disable_debug_trap = disable_debug_trap_v10_3, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 744366c7ee85..275f20399373 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -423,7 +423,7 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd, unsigned long flags, end_jiffies; int retry; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EIO; acquire_queue(kgd, pipe_id, queue_id); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index feab4cc6e836..4997189d8b36 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -419,7 +419,7 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd, int retry; struct vi_mqd *m = get_mqd(mqd); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EIO; acquire_queue(kgd, pipe_id, queue_id); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index 1102de76d876..e6aede725197 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -552,7 +552,7 @@ int kgd_gfx_v9_hqd_destroy(struct kgd_dev *kgd, void *mqd, uint32_t temp; struct v9_mqd *m = get_mqd(mqd); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EIO; acquire_queue(kgd, pipe_id, queue_id); @@ -690,7 +690,7 @@ uint32_t kgd_gfx_v9_address_watch_get_offset(struct kgd_dev *kgd, return 0; } -static void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, +void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid, uint64_t page_table_base) { struct amdgpu_device *adev = get_amdgpu_device(kgd); @@ -701,7 +701,7 @@ static void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, return; } - mmhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base); + adev->mmhub.funcs->setup_vm_pt_regs(adev, vmid, page_table_base); gfxhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base); } @@ -726,6 +726,4 @@ const struct kfd2kgd_calls gfx_v9_kfd2kgd = { .get_atc_vmid_pasid_mapping_info = kgd_gfx_v9_get_atc_vmid_pasid_mapping_info, .set_vm_context_page_table_base = kgd_gfx_v9_set_vm_context_page_table_base, - .get_hive_id = amdgpu_amdkfd_get_hive_id, - .get_unique_id = amdgpu_amdkfd_get_unique_id, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h index aedf67d57449..f098e88d3a0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h @@ -60,3 +60,6 @@ uint32_t kgd_gfx_v9_address_watch_get_offset(struct kgd_dev *kgd, bool kgd_gfx_v9_get_atc_vmid_pasid_mapping_info(struct kgd_dev *kgd, uint8_t vmid, uint16_t *p_pasid); + +void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, + uint32_t vmid, uint64_t page_table_base); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index a58af513c952..b6b821500d30 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -148,8 +148,12 @@ static int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, spin_lock(&kfd_mem_limit.mem_limit_lock); + if (kfd_mem_limit.system_mem_used + system_mem_needed > + kfd_mem_limit.max_system_mem_limit) + pr_debug("Set no_system_mem_limit=1 if using shared memory\n"); + if ((kfd_mem_limit.system_mem_used + system_mem_needed > - kfd_mem_limit.max_system_mem_limit) || + kfd_mem_limit.max_system_mem_limit && !no_system_mem_limit) || (kfd_mem_limit.ttm_mem_used + ttm_mem_needed > kfd_mem_limit.max_ttm_mem_limit) || (adev->kfd.vram_used + vram_needed > @@ -562,7 +566,7 @@ static int init_user_pages(struct kgd_mem *mem, uint64_t user_addr) mutex_lock(&process_info->lock); - ret = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, user_addr, 0); + ret = amdgpu_ttm_tt_set_userptr(&bo->tbo, user_addr, 0); if (ret) { pr_err("%s: Failed to set userptr: %d\n", __func__, ret); goto out; @@ -1668,7 +1672,7 @@ int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd, return -EINVAL; obj = dma_buf->priv; - if (obj->dev->dev_private != adev) + if (drm_to_adev(obj->dev) != adev) /* Can't handle buffers from other devices */ return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index 29f767e026e4..469352e2d6ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -148,7 +148,7 @@ void amdgpu_atombios_i2c_init(struct amdgpu_device *adev) if (i2c.valid) { sprintf(stmp, "0x%x", i2c.i2c_id); - adev->i2c_bus[i] = amdgpu_i2c_create(adev->ddev, &i2c, stmp); + adev->i2c_bus[i] = amdgpu_i2c_create(adev_to_drm(adev), &i2c, stmp); } gpio = (ATOM_GPIO_I2C_ASSIGMENT *) ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); @@ -541,7 +541,7 @@ bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device * } } - amdgpu_link_encoder_connector(adev->ddev); + amdgpu_link_encoder_connector(adev_to_drm(adev)); return true; } @@ -1786,9 +1786,9 @@ static int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev) (uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION << ATOM_VRAM_OPERATION_FLAGS_SHIFT)) { /* Firmware request VRAM reservation for SR-IOV */ - adev->fw_vram_usage.start_offset = (start_addr & + adev->mman.fw_vram_usage_start_offset = (start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10; - adev->fw_vram_usage.size = size << 10; + adev->mman.fw_vram_usage_size = size << 10; /* Use the default scratch size */ usage_bytes = 0; } else { @@ -1882,7 +1882,7 @@ static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val) */ static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) { - struct amdgpu_device *adev = info->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(info->dev); WREG32(reg, val); } @@ -1898,7 +1898,7 @@ static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) */ static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) { - struct amdgpu_device *adev = info->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(info->dev); uint32_t r; r = RREG32(reg); @@ -1916,7 +1916,7 @@ static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) */ static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val) { - struct amdgpu_device *adev = info->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(info->dev); WREG32_IO(reg, val); } @@ -1932,7 +1932,7 @@ static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val) */ static uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg) { - struct amdgpu_device *adev = info->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(info->dev); uint32_t r; r = RREG32_IO(reg); @@ -1944,7 +1944,7 @@ static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); struct atom_context *ctx = adev->mode_info.atom_context; return snprintf(buf, PAGE_SIZE, "%s\n", ctx->vbios_version); @@ -1995,7 +1995,7 @@ int amdgpu_atombios_init(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.atom_card_info = atom_card_info; - atom_card_info->dev = adev->ddev; + atom_card_info->dev = adev_to_drm(adev); atom_card_info->reg_read = cail_reg_read; atom_card_info->reg_write = cail_reg_write; /* needed for iio ops */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c index 1279053324f9..17c010d0431f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c @@ -89,9 +89,9 @@ int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev) (uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION << ATOM_VRAM_OPERATION_FLAGS_SHIFT)) { /* Firmware request VRAM reservation for SR-IOV */ - adev->fw_vram_usage.start_offset = (start_addr & + adev->mman.fw_vram_usage_start_offset = (start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10; - adev->fw_vram_usage.size = size << 10; + adev->mman.fw_vram_usage_size = size << 10; /* Use the default scratch size */ usage_bytes = 0; } else { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index b1172d93c99c..6333cada1e09 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c @@ -417,26 +417,40 @@ static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) bool amdgpu_get_bios(struct amdgpu_device *adev) { - if (amdgpu_atrm_get_bios(adev)) + if (amdgpu_atrm_get_bios(adev)) { + dev_info(adev->dev, "Fetched VBIOS from ATRM\n"); goto success; + } - if (amdgpu_acpi_vfct_bios(adev)) + if (amdgpu_acpi_vfct_bios(adev)) { + dev_info(adev->dev, "Fetched VBIOS from VFCT\n"); goto success; + } - if (igp_read_bios_from_vram(adev)) + if (igp_read_bios_from_vram(adev)) { + dev_info(adev->dev, "Fetched VBIOS from VRAM BAR\n"); goto success; + } - if (amdgpu_read_bios(adev)) + if (amdgpu_read_bios(adev)) { + dev_info(adev->dev, "Fetched VBIOS from ROM BAR\n"); goto success; + } - if (amdgpu_read_bios_from_rom(adev)) + if (amdgpu_read_bios_from_rom(adev)) { + dev_info(adev->dev, "Fetched VBIOS from ROM\n"); goto success; + } - if (amdgpu_read_disabled_bios(adev)) + if (amdgpu_read_disabled_bios(adev)) { + dev_info(adev->dev, "Fetched VBIOS from disabled ROM BAR\n"); goto success; + } - if (amdgpu_read_platform_bios(adev)) + if (amdgpu_read_platform_bios(adev)) { + dev_info(adev->dev, "Fetched VBIOS from platform\n"); goto success; + } DRM_ERROR("Unable to locate a BIOS ROM\n"); return false; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 4053597b3af2..15c45b2a3983 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -265,7 +265,7 @@ error_free: int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv = filp->driver_priv; union drm_amdgpu_bo_list *args = data; uint32_t handle = args->in.list_handle; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index a1aec205435d..65d1b23d7e74 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -26,6 +26,7 @@ #include <drm/drm_edid.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_dp_helper.h> #include <drm/drm_probe_helper.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" @@ -41,7 +42,7 @@ void amdgpu_connector_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); /* bail if the connector does not have hpd pin, e.g., @@ -279,7 +280,7 @@ amdgpu_connector_get_hardcoded_edid(struct amdgpu_device *adev) static void amdgpu_connector_get_edid(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); if (amdgpu_connector->edid) @@ -463,7 +464,7 @@ static int amdgpu_connector_set_property(struct drm_connector *connector, uint64_t val) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; @@ -834,7 +835,7 @@ static enum drm_mode_status amdgpu_connector_vga_mode_valid(struct drm_connector struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); /* XXX check mode bandwidth */ @@ -941,7 +942,7 @@ static bool amdgpu_connector_check_hpd_status_unchanged(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); enum drm_connector_status status; @@ -972,7 +973,7 @@ static enum drm_connector_status amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); const struct drm_encoder_helper_funcs *encoder_funcs; int r; @@ -1159,7 +1160,7 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); /* XXX check mode bandwidth */ @@ -1311,7 +1312,7 @@ static bool amdgpu_connector_encoder_is_hbr2(struct drm_connector *connector) bool amdgpu_connector_is_dp12_capable(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if ((adev->clock.default_dispclk >= 53900) && amdgpu_connector_encoder_is_hbr2(connector)) { @@ -1325,7 +1326,7 @@ static enum drm_connector_status amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); enum drm_connector_status ret = connector_status_disconnected; struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv; @@ -1413,6 +1414,10 @@ out: pm_runtime_put_autosuspend(connector->dev->dev); } + drm_dp_set_subconnector_property(&amdgpu_connector->base, + ret, + amdgpu_dig_connector->dpcd, + amdgpu_dig_connector->downstream_ports); return ret; } @@ -1521,7 +1526,7 @@ amdgpu_connector_add(struct amdgpu_device *adev, struct amdgpu_hpd *hpd, struct amdgpu_router *router) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; struct amdgpu_connector *amdgpu_connector; @@ -1959,6 +1964,11 @@ amdgpu_connector_add(struct amdgpu_device *adev, if (has_aux) amdgpu_atombios_dp_aux_init(amdgpu_connector); + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector_type == DRM_MODE_CONNECTOR_eDP) { + drm_connector_attach_dp_subconnector_property(&amdgpu_connector->base); + } + return; failed: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index a512ccbc4dea..12598a4b5c78 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -299,7 +299,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, { s64 time_us, increment_us; u64 free_vram, total_vram, used_vram; - + struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); /* Allow a maximum of 200 accumulated ms. This is basically per-IB * throttling. * @@ -316,7 +316,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, } total_vram = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size); - used_vram = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); + used_vram = amdgpu_vram_mgr_usage(vram_man); free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram; spin_lock(&adev->mm_stats.lock); @@ -363,7 +363,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) { u64 total_vis_vram = adev->gmc.visible_vram_size; u64 used_vis_vram = - amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); + amdgpu_vram_mgr_vis_usage(vram_man); if (used_vis_vram < total_vis_vram) { u64 free_vis_vram = total_vis_vram - used_vis_vram; @@ -1275,13 +1275,24 @@ error_unlock: return r; } +static void trace_amdgpu_cs_ibs(struct amdgpu_cs_parser *parser) +{ + int i; + + if (!trace_amdgpu_cs_enabled()) + return; + + for (i = 0; i < parser->job->num_ibs; i++) + trace_amdgpu_cs(parser, i); +} + int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); union drm_amdgpu_cs *cs = data; struct amdgpu_cs_parser parser = {}; bool reserved_buffers = false; - int i, r; + int r; if (amdgpu_ras_intr_triggered()) return -EHWPOISON; @@ -1294,7 +1305,8 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) r = amdgpu_cs_parser_init(&parser, data); if (r) { - DRM_ERROR("Failed to initialize parser %d!\n", r); + if (printk_ratelimit()) + DRM_ERROR("Failed to initialize parser %d!\n", r); goto out; } @@ -1319,8 +1331,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) reserved_buffers = true; - for (i = 0; i < parser.job->num_ibs; i++) - trace_amdgpu_cs(&parser, i); + trace_amdgpu_cs_ibs(&parser); r = amdgpu_cs_vm_handling(&parser); if (r) @@ -1421,7 +1432,7 @@ static struct dma_fence *amdgpu_cs_get_fence(struct amdgpu_device *adev, int amdgpu_cs_fence_to_handle_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); union drm_amdgpu_fence_to_handle *info = data; struct dma_fence *fence; struct drm_syncobj *syncobj; @@ -1597,7 +1608,7 @@ err_free_fence_array: int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); union drm_amdgpu_wait_fences *wait = data; uint32_t fence_count = wait->in.fence_count; struct drm_amdgpu_fence *fences_user; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 8842c55d4490..c80d8339f58c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -46,7 +46,7 @@ const unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM] = { static int amdgpu_ctx_priority_permit(struct drm_file *filp, enum drm_sched_priority priority) { - if (priority < 0 || priority >= DRM_SCHED_PRIORITY_MAX) + if (priority < 0 || priority >= DRM_SCHED_PRIORITY_COUNT) return -EINVAL; /* NORMAL and below are accessible by everyone */ @@ -65,7 +65,7 @@ static int amdgpu_ctx_priority_permit(struct drm_file *filp, static enum gfx_pipe_priority amdgpu_ctx_sched_prio_to_compute_prio(enum drm_sched_priority prio) { switch (prio) { - case DRM_SCHED_PRIORITY_HIGH_HW: + case DRM_SCHED_PRIORITY_HIGH: case DRM_SCHED_PRIORITY_KERNEL: return AMDGPU_GFX_PIPE_PRIO_HIGH; default: @@ -114,7 +114,11 @@ static int amdgpu_ctx_init_entity(struct amdgpu_ctx *ctx, u32 hw_ip, scheds = adev->gpu_sched[hw_ip][hw_prio].sched; num_scheds = adev->gpu_sched[hw_ip][hw_prio].num_scheds; - if (hw_ip == AMDGPU_HW_IP_VCN_ENC || hw_ip == AMDGPU_HW_IP_VCN_DEC) { + /* disable load balance if the hw engine retains context among dependent jobs */ + if (hw_ip == AMDGPU_HW_IP_VCN_ENC || + hw_ip == AMDGPU_HW_IP_VCN_DEC || + hw_ip == AMDGPU_HW_IP_UVD_ENC || + hw_ip == AMDGPU_HW_IP_UVD) { sched = drm_sched_pick_best(scheds, num_scheds); scheds = &sched; num_scheds = 1; @@ -385,16 +389,15 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data, enum drm_sched_priority priority; union drm_amdgpu_ctx *args = data; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv = filp->driver_priv; - r = 0; id = args->in.ctx_id; - priority = amdgpu_to_sched_priority(args->in.priority); + r = amdgpu_to_sched_priority(args->in.priority, &priority); /* For backwards compatibility reasons, we need to accept * ioctls with garbage in the priority field */ - if (priority == DRM_SCHED_PRIORITY_INVALID) + if (r == -EINVAL) priority = DRM_SCHED_PRIORITY_NORMAL; switch (args->in.op) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 193ffdb957b6..abe0c2729e1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -34,6 +34,7 @@ #include "amdgpu_pm.h" #include "amdgpu_dm_debugfs.h" #include "amdgpu_ras.h" +#include "amdgpu_rap.h" /** * amdgpu_debugfs_add_files - Add simple debugfs entries @@ -68,8 +69,8 @@ int amdgpu_debugfs_add_files(struct amdgpu_device *adev, adev->debugfs_count = i; #if defined(CONFIG_DEBUG_FS) drm_debugfs_create_files(files, nfiles, - adev->ddev->primary->debugfs_root, - adev->ddev->primary); + adev_to_drm(adev)->primary->debugfs_root, + adev_to_drm(adev)->primary); #endif return 0; } @@ -100,14 +101,18 @@ static int amdgpu_debugfs_autodump_open(struct inode *inode, struct file *file) file->private_data = adev; - mutex_lock(&adev->lock_reset); + ret = down_read_killable(&adev->reset_sem); + if (ret) + return ret; + if (adev->autodump.dumping.done) { reinit_completion(&adev->autodump.dumping); ret = 0; } else { ret = -EBUSY; } - mutex_unlock(&adev->lock_reset); + + up_read(&adev->reset_sem); return ret; } @@ -126,7 +131,7 @@ static unsigned int amdgpu_debugfs_autodump_poll(struct file *file, struct poll_ poll_wait(file, &adev->autodump.gpu_hang, poll_table); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return POLLIN | POLLRDNORM | POLLWRNORM; return 0; @@ -146,7 +151,7 @@ static void amdgpu_debugfs_autodump_init(struct amdgpu_device *adev) init_waitqueue_head(&adev->autodump.gpu_hang); debugfs_create_file("amdgpu_autodump", 0600, - adev->ddev->primary->debugfs_root, + adev_to_drm(adev)->primary->debugfs_root, adev, &autodump_debug_fops); } @@ -222,23 +227,23 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f, *pos &= (1UL << 22) - 1; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } if (use_bank) { if ((sh_bank != 0xFFFFFFFF && sh_bank >= adev->gfx.config.max_sh_per_se) || (se_bank != 0xFFFFFFFF && se_bank >= adev->gfx.config.max_shader_engines)) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return -EINVAL; } @@ -287,8 +292,8 @@ end: if (pm_pg_lock) mutex_unlock(&adev->pm.mutex); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return result; @@ -335,15 +340,15 @@ static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, if (size & 0x3 || *pos & 0x3) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -353,8 +358,8 @@ static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, value = RREG32_PCIE(*pos >> 2); r = put_user(value, (uint32_t *)buf); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return r; } @@ -365,8 +370,8 @@ static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, size -= 4; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return result; @@ -394,15 +399,15 @@ static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user if (size & 0x3 || *pos & 0x3) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -411,8 +416,8 @@ static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user r = get_user(value, (uint32_t *)buf); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return r; } @@ -425,8 +430,8 @@ static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user size -= 4; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return result; @@ -454,15 +459,15 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, if (size & 0x3 || *pos & 0x3) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -472,8 +477,8 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, value = RREG32_DIDT(*pos >> 2); r = put_user(value, (uint32_t *)buf); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return r; } @@ -484,8 +489,8 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, size -= 4; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return result; @@ -513,15 +518,15 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user if (size & 0x3 || *pos & 0x3) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -530,8 +535,8 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user r = get_user(value, (uint32_t *)buf); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return r; } @@ -544,8 +549,8 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user size -= 4; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return result; @@ -573,15 +578,15 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, if (size & 0x3 || *pos & 0x3) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -591,8 +596,8 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, value = RREG32_SMC(*pos); r = put_user(value, (uint32_t *)buf); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return r; } @@ -603,8 +608,8 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, size -= 4; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return result; @@ -632,15 +637,15 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user * if (size & 0x3 || *pos & 0x3) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -649,8 +654,8 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user * r = get_user(value, (uint32_t *)buf); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return r; } @@ -663,8 +668,8 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user * size -= 4; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); amdgpu_virt_disable_access_debugfs(adev); return result; @@ -791,22 +796,22 @@ static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf, valuesize = sizeof(values); - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_dpm_read_sensor(adev, idx, &values[0], &valuesize); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) { amdgpu_virt_disable_access_debugfs(adev); @@ -873,15 +878,15 @@ static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf, wave = (*pos & GENMASK_ULL(36, 31)) >> 31; simd = (*pos & GENMASK_ULL(44, 37)) >> 37; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_virt_enable_access_debugfs(adev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -896,8 +901,8 @@ static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf, amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); mutex_unlock(&adev->grbm_idx_mutex); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (!x) { amdgpu_virt_disable_access_debugfs(adev); @@ -971,7 +976,7 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf, if (!data) return -ENOMEM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) goto err; @@ -994,8 +999,8 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf, amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); mutex_unlock(&adev->grbm_idx_mutex); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); while (size) { uint32_t value; @@ -1017,7 +1022,7 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf, return result; err: - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); kfree(data); return r; } @@ -1042,9 +1047,9 @@ static ssize_t amdgpu_debugfs_gfxoff_write(struct file *f, const char __user *bu if (size & 0x3 || *pos & 0x3) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -1053,8 +1058,8 @@ static ssize_t amdgpu_debugfs_gfxoff_write(struct file *f, const char __user *bu r = get_user(value, (uint32_t *)buf); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -1066,8 +1071,8 @@ static ssize_t amdgpu_debugfs_gfxoff_write(struct file *f, const char __user *bu size -= 4; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return result; } @@ -1091,7 +1096,7 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf, if (size & 0x3 || *pos & 0x3) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) return r; @@ -1100,15 +1105,15 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf, r = amdgpu_get_gfx_off_status(adev, &value); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = put_user(value, (uint32_t *)buf); if (r) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -1118,8 +1123,8 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf, size -= 4; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return result; } @@ -1211,7 +1216,7 @@ static const char *debugfs_regs_names[] = { */ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) { - struct drm_minor *minor = adev->ddev->primary; + struct drm_minor *minor = adev_to_drm(adev)->primary; struct dentry *ent, *root = minor->debugfs_root; unsigned int i; @@ -1231,17 +1236,19 @@ static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int r = 0, i; r = pm_runtime_get_sync(dev->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } /* Avoid accidently unparking the sched thread during GPU reset */ - mutex_lock(&adev->lock_reset); + r = down_read_killable(&adev->reset_sem); + if (r) + return r; /* hold on the scheduler */ for (i = 0; i < AMDGPU_MAX_RINGS; i++) { @@ -1268,7 +1275,7 @@ static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data) kthread_unpark(ring->sched.thread); } - mutex_unlock(&adev->lock_reset); + up_read(&adev->reset_sem); pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); @@ -1280,7 +1287,7 @@ static int amdgpu_debugfs_get_vbios_dump(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); seq_write(m, adev->bios, adev->bios_size); return 0; @@ -1290,12 +1297,12 @@ static int amdgpu_debugfs_evict_vram(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int r; r = pm_runtime_get_sync(dev->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -1311,12 +1318,12 @@ static int amdgpu_debugfs_evict_gtt(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int r; r = pm_runtime_get_sync(dev->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -1458,7 +1465,9 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) return -ENOMEM; /* Avoid accidently unparking the sched thread during GPU reset */ - mutex_lock(&adev->lock_reset); + r = down_read_killable(&adev->reset_sem); + if (r) + goto pro_end; /* stop the scheduler */ kthread_park(ring->sched.thread); @@ -1499,13 +1508,14 @@ failure: /* restart the scheduler */ kthread_unpark(ring->sched.thread); - mutex_unlock(&adev->lock_reset); + up_read(&adev->reset_sem); ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); +pro_end: kfree(fences); - return 0; + return r; } static int amdgpu_debugfs_sclk_set(void *data, u64 val) @@ -1517,9 +1527,9 @@ static int amdgpu_debugfs_sclk_set(void *data, u64 val) if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) return -EINVAL; - ret = pm_runtime_get_sync(adev->ddev->dev); + ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (ret < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return ret; } @@ -1532,8 +1542,8 @@ static int amdgpu_debugfs_sclk_set(void *data, u64 val) return 0; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (ret) return -EINVAL; @@ -1553,7 +1563,7 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev) adev->debugfs_preempt = debugfs_create_file("amdgpu_preempt_ib", 0600, - adev->ddev->primary->debugfs_root, adev, + adev_to_drm(adev)->primary->debugfs_root, adev, &fops_ib_preempt); if (!(adev->debugfs_preempt)) { DRM_ERROR("unable to create amdgpu_preempt_ib debugsfs file\n"); @@ -1562,7 +1572,7 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev) adev->smu.debugfs_sclk = debugfs_create_file("amdgpu_force_sclk", 0200, - adev->ddev->primary->debugfs_root, adev, + adev_to_drm(adev)->primary->debugfs_root, adev, &fops_sclk_set); if (!(adev->smu.debugfs_sclk)) { DRM_ERROR("unable to create amdgpu_set_sclk debugsfs file\n"); @@ -1623,6 +1633,8 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev) amdgpu_debugfs_autodump_init(adev); + amdgpu_rap_debugfs_init(adev); + return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_list, ARRAY_SIZE(amdgpu_debugfs_list)); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index eb7cfe87042e..f7307af76452 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -132,7 +132,7 @@ static ssize_t amdgpu_device_get_pcie_replay_count(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint64_t cnt = amdgpu_asic_get_pcie_replay_count(adev); return snprintf(buf, PAGE_SIZE, "%llu\n", cnt); @@ -157,7 +157,7 @@ static ssize_t amdgpu_device_get_product_name(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); return snprintf(buf, PAGE_SIZE, "%s\n", adev->product_name); } @@ -179,7 +179,7 @@ static ssize_t amdgpu_device_get_product_number(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); return snprintf(buf, PAGE_SIZE, "%s\n", adev->product_number); } @@ -201,7 +201,7 @@ static ssize_t amdgpu_device_get_serial_number(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); return snprintf(buf, PAGE_SIZE, "%s\n", adev->serial); } @@ -219,7 +219,7 @@ static DEVICE_ATTR(serial_number, S_IRUGO, */ bool amdgpu_device_supports_boco(struct drm_device *dev) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if (adev->flags & AMD_IS_PX) return true; @@ -236,7 +236,7 @@ bool amdgpu_device_supports_boco(struct drm_device *dev) */ bool amdgpu_device_supports_baco(struct drm_device *dev) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); return amdgpu_asic_supports_baco(adev); } @@ -319,8 +319,12 @@ uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg, { uint32_t ret; - if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) - return amdgpu_kiq_rreg(adev, reg); + if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev) && + down_read_trylock(&adev->reset_sem)) { + ret = amdgpu_kiq_rreg(adev, reg); + up_read(&adev->reset_sem); + return ret; + } if ((reg * 4) < adev->rmmio_size) ret = readl(((void __iomem *)adev->rmmio) + (reg * 4)); @@ -332,6 +336,7 @@ uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg, ret = readl(((void __iomem *)adev->rmmio) + (mmMM_DATA * 4)); spin_unlock_irqrestore(&adev->mmio_idx_lock, flags); } + trace_amdgpu_mm_rreg(adev->pdev->device, reg, ret); return ret; } @@ -378,7 +383,9 @@ void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value) BUG(); } -void static inline amdgpu_mm_wreg_mmio(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags) +static inline void amdgpu_mm_wreg_mmio(struct amdgpu_device *adev, + uint32_t reg, uint32_t v, + uint32_t acc_flags) { trace_amdgpu_mm_wreg(adev->pdev->device, reg, v); @@ -407,8 +414,12 @@ void static inline amdgpu_mm_wreg_mmio(struct amdgpu_device *adev, uint32_t reg, void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint32_t acc_flags) { - if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) - return amdgpu_kiq_wreg(adev, reg, v); + if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev) && + down_read_trylock(&adev->reset_sem)) { + amdgpu_kiq_wreg(adev, reg, v); + up_read(&adev->reset_sem); + return; + } amdgpu_mm_wreg_mmio(adev, reg, v, acc_flags); } @@ -654,6 +665,20 @@ static void amdgpu_block_invalid_wreg(struct amdgpu_device *adev, } /** + * amdgpu_device_asic_init - Wrapper for atom asic_init + * + * @dev: drm_device pointer + * + * Does any asic specific work and then calls atom asic init. + */ +static int amdgpu_device_asic_init(struct amdgpu_device *adev) +{ + amdgpu_asic_pre_asic_init(adev); + + return amdgpu_atom_asic_init(adev->mode_info.atom_context); +} + +/** * amdgpu_device_vram_scratch_init - allocate the VRAM scratch page * * @adev: amdgpu device pointer @@ -1199,6 +1224,11 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev) amdgpu_gmc_tmz_set(adev); + if (amdgpu_num_kcq > 8 || amdgpu_num_kcq < 0) { + amdgpu_num_kcq = 8; + dev_warn(adev->dev, "set kernel compute queue number to 8 due to invalid parameter provided by user\n"); + } + return 0; } @@ -1211,7 +1241,8 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev) * Callback for the switcheroo driver. Suspends or resumes the * the asics before or after it is powered up using ACPI methods. */ -static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) +static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, + enum vga_switcheroo_state state) { struct drm_device *dev = pci_get_drvdata(pdev); int r; @@ -1504,7 +1535,7 @@ static void amdgpu_device_enable_virtual_display(struct amdgpu_device *adev) adev->enable_virtual_display = false; if (amdgpu_virtual_display) { - struct drm_device *ddev = adev->ddev; + struct drm_device *ddev = adev_to_drm(adev); const char *pci_address_name = pci_name(ddev->pdev); char *pciaddstr, *pciaddstr_tmp, *pciaddname_tmp, *pciaddname; @@ -1563,7 +1594,7 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev) adev->firmware.gpu_info_fw = NULL; - if (adev->discovery_bin) { + if (adev->mman.discovery_bin) { amdgpu_discovery_get_gfx_info(adev); /* @@ -1935,7 +1966,7 @@ static int amdgpu_device_fw_loading(struct amdgpu_device *adev) if (adev->ip_blocks[i].status.hw == true) break; - if (adev->in_gpu_reset || adev->in_suspend) { + if (amdgpu_in_reset(adev) || adev->in_suspend) { r = adev->ip_blocks[i].version->funcs->resume(adev); if (r) { DRM_ERROR("resume of IP block <%s> failed %d\n", @@ -2055,13 +2086,19 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) * it should be called after amdgpu_device_ip_hw_init_phase2 since * for some ASICs the RAS EEPROM code relies on SMU fully functioning * for I2C communication which only true at this point. - * recovery_init may fail, but it can free all resources allocated by - * itself and its failure should not stop amdgpu init process. + * + * amdgpu_ras_recovery_init may fail, but the upper only cares the + * failure from bad gpu situation and stop amdgpu init process + * accordingly. For other failed cases, it will still release all + * the resource and print error message, rather than returning one + * negative value to upper level. * * Note: theoretically, this should be called before all vram allocations * to protect retired page from abusing */ - amdgpu_ras_recovery_init(adev); + r = amdgpu_ras_recovery_init(adev); + if (r) + goto init_failed; if (adev->gmc.xgmi.num_physical_nodes > 1) amdgpu_xgmi_add_device(adev); @@ -2106,7 +2143,7 @@ static bool amdgpu_device_check_vram_lost(struct amdgpu_device *adev) AMDGPU_RESET_MAGIC_NUM)) return true; - if (!adev->in_gpu_reset) + if (!amdgpu_in_reset(adev)) return false; /* @@ -2217,9 +2254,7 @@ static int amdgpu_device_enable_mgpu_fan_boost(void) gpu_ins = &(mgpu_info.gpu_ins[i]); adev = gpu_ins->adev; if (!(adev->flags & AMD_IS_APU) && - !gpu_ins->mgpu_fan_enabled && - adev->powerplay.pp_funcs && - adev->powerplay.pp_funcs->enable_mgpu_fan_boost) { + !gpu_ins->mgpu_fan_enabled) { ret = amdgpu_dpm_enable_mgpu_fan_boost(adev); if (ret) break; @@ -2574,17 +2609,16 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev) AMD_IP_BLOCK_TYPE_IH, }; - for (i = 0; i < adev->num_ip_blocks; i++) - adev->ip_blocks[i].status.hw = false; - for (i = 0; i < ARRAY_SIZE(ip_order); i++) { int j; struct amdgpu_ip_block *block; - for (j = 0; j < adev->num_ip_blocks; j++) { - block = &adev->ip_blocks[j]; + block = &adev->ip_blocks[i]; + block->status.hw = false; - if (block->version->type != ip_order[i] || + for (j = 0; j < ARRAY_SIZE(ip_order); j++) { + + if (block->version->type != ip_order[j] || !block->status.valid) continue; @@ -2777,6 +2811,12 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) { switch (asic_type) { #if defined(CONFIG_DRM_AMD_DC) +#if defined(CONFIG_DRM_AMD_DC_SI) + case CHIP_TAHITI: + case CHIP_PITCAIRN: + case CHIP_VERDE: + case CHIP_OLAND: +#endif case CHIP_BONAIRE: case CHIP_KAVERI: case CHIP_KABINI: @@ -2831,7 +2871,7 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) */ bool amdgpu_device_has_dc_support(struct amdgpu_device *adev) { - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev) || adev->enable_virtual_display) return false; return amdgpu_device_asic_has_dc_support(adev->asic_type); @@ -2842,7 +2882,7 @@ static void amdgpu_device_xgmi_reset_func(struct work_struct *__work) { struct amdgpu_device *adev = container_of(__work, struct amdgpu_device, xgmi_reset_work); - struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev, 0); + struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev); /* It's a bug to not have a hive within this function */ if (WARN_ON(!hive)) @@ -2857,13 +2897,13 @@ static void amdgpu_device_xgmi_reset_func(struct work_struct *__work) if (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) { task_barrier_enter(&hive->tb); - adev->asic_reset_res = amdgpu_device_baco_enter(adev->ddev); + adev->asic_reset_res = amdgpu_device_baco_enter(adev_to_drm(adev)); if (adev->asic_reset_res) goto fail; task_barrier_exit(&hive->tb); - adev->asic_reset_res = amdgpu_device_baco_exit(adev->ddev); + adev->asic_reset_res = amdgpu_device_baco_exit(adev_to_drm(adev)); if (adev->asic_reset_res) goto fail; @@ -2879,7 +2919,8 @@ static void amdgpu_device_xgmi_reset_func(struct work_struct *__work) fail: if (adev->asic_reset_res) DRM_WARN("ASIC reset failed with error, %d for drm dev, %s", - adev->asic_reset_res, adev->ddev->unique); + adev->asic_reset_res, adev_to_drm(adev)->unique); + amdgpu_put_xgmi_hive(hive); } static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev) @@ -2962,8 +3003,6 @@ static const struct attribute *amdgpu_dev_attributes[] = { * amdgpu_device_init - initialize the driver * * @adev: amdgpu_device pointer - * @ddev: drm dev pointer - * @pdev: pci dev pointer * @flags: driver flags * * Initializes the driver info and hw (all asics). @@ -2971,18 +3010,15 @@ static const struct attribute *amdgpu_dev_attributes[] = { * Called at driver startup. */ int amdgpu_device_init(struct amdgpu_device *adev, - struct drm_device *ddev, - struct pci_dev *pdev, uint32_t flags) { + struct drm_device *ddev = adev_to_drm(adev); + struct pci_dev *pdev = adev->pdev; int r, i; bool boco = false; u32 max_MBps; adev->shutdown = false; - adev->dev = &pdev->dev; - adev->ddev = ddev; - adev->pdev = pdev; adev->flags = flags; if (amdgpu_force_asic_type >= 0 && amdgpu_force_asic_type < CHIP_LAST) @@ -3038,7 +3074,8 @@ int amdgpu_device_init(struct amdgpu_device *adev, mutex_init(&adev->mn_lock); mutex_init(&adev->virt.vf_errors.lock); hash_init(adev->mn_hash); - mutex_init(&adev->lock_reset); + atomic_set(&adev->in_gpu_reset, 0); + init_rwsem(&adev->reset_sem); mutex_init(&adev->psp.mutex); mutex_init(&adev->notifier_lock); @@ -3188,7 +3225,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, goto failed; } DRM_INFO("GPU posting now...\n"); - r = amdgpu_atom_asic_init(adev->mode_info.atom_context); + r = amdgpu_device_asic_init(adev); if (r) { dev_err(adev->dev, "gpu post error!\n"); goto failed; @@ -3226,7 +3263,7 @@ fence_driver_init: } /* init the mode config */ - drm_mode_config_init(adev->ddev); + drm_mode_config_init(adev_to_drm(adev)); r = amdgpu_device_ip_init(adev); if (r) { @@ -3352,9 +3389,7 @@ failed: */ void amdgpu_device_fini(struct amdgpu_device *adev) { - int r; - - DRM_INFO("amdgpu: finishing device.\n"); + dev_info(adev->dev, "amdgpu: finishing device.\n"); flush_delayed_work(&adev->delayed_init_work); adev->shutdown = true; @@ -3368,15 +3403,15 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_irq_disable_all(adev); if (adev->mode_info.mode_config_initialized){ if (!amdgpu_device_has_dc_support(adev)) - drm_helper_force_disable_all(adev->ddev); + drm_helper_force_disable_all(adev_to_drm(adev)); else - drm_atomic_helper_shutdown(adev->ddev); + drm_atomic_helper_shutdown(adev_to_drm(adev)); } amdgpu_fence_driver_fini(adev); if (adev->pm_sysfs_en) amdgpu_pm_sysfs_fini(adev); amdgpu_fbdev_fini(adev); - r = amdgpu_device_ip_fini(adev); + amdgpu_device_ip_fini(adev); release_firmware(adev->firmware.gpu_info_fw); adev->firmware.gpu_info_fw = NULL; adev->accel_working = false; @@ -3394,7 +3429,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_has_atpx_dgpu_power_cntl()) && !pci_is_thunderbolt_attached(adev->pdev)) vga_switcheroo_unregister_client(adev->pdev); - if (amdgpu_device_supports_boco(adev->ddev)) + if (amdgpu_device_supports_boco(adev_to_drm(adev))) vga_switcheroo_fini_domain_pm_ops(adev->dev); vga_client_register(adev->pdev, NULL, NULL, NULL); if (adev->rio_mem) @@ -3410,7 +3445,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes); if (IS_ENABLED(CONFIG_PERF_EVENTS)) amdgpu_pmu_fini(adev); - if (adev->discovery_bin) + if (adev->mman.discovery_bin) amdgpu_discovery_fini(adev); } @@ -3436,11 +3471,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) struct drm_connector_list_iter iter; int r; - if (dev == NULL || dev->dev_private == NULL) { - return -ENODEV; - } - - adev = dev->dev_private; + adev = drm_to_adev(dev); if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; @@ -3528,7 +3559,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) { struct drm_connector *connector; struct drm_connector_list_iter iter; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_crtc *crtc; int r = 0; @@ -3537,14 +3568,14 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) /* post card */ if (amdgpu_device_need_post(adev)) { - r = amdgpu_atom_asic_init(adev->mode_info.atom_context); + r = amdgpu_device_asic_init(adev); if (r) - DRM_ERROR("amdgpu asic init failed\n"); + dev_err(adev->dev, "amdgpu asic init failed\n"); } r = amdgpu_device_ip_resume(adev); if (r) { - DRM_ERROR("amdgpu_device_ip_resume failed (%d).\n", r); + dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r); return r; } amdgpu_fence_driver_resume(adev); @@ -3568,7 +3599,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) if (r == 0) { r = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); if (r != 0) - DRM_ERROR("Failed to pin cursor BO (%d)\n", r); + dev_err(adev->dev, "Failed to pin cursor BO (%d)\n", r); amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); amdgpu_bo_unreserve(aobj); } @@ -3658,7 +3689,7 @@ static bool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev) adev->ip_blocks[i].status.hang = adev->ip_blocks[i].version->funcs->check_soft_reset(adev); if (adev->ip_blocks[i].status.hang) { - DRM_INFO("IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name); + dev_info(adev->dev, "IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name); asic_hang = true; } } @@ -3719,7 +3750,7 @@ static bool amdgpu_device_ip_need_full_reset(struct amdgpu_device *adev) (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) || adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) { if (adev->ip_blocks[i].status.hang) { - DRM_INFO("Some block need full reset!\n"); + dev_info(adev->dev, "Some block need full reset!\n"); return true; } } @@ -3807,7 +3838,7 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) else tmo = msecs_to_jiffies(100); - DRM_INFO("recover vram bo from shadow start\n"); + dev_info(adev->dev, "recover vram bo from shadow start\n"); mutex_lock(&adev->shadow_list_lock); list_for_each_entry(shadow, &adev->shadow_list, shadow_list) { @@ -3843,11 +3874,11 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) dma_fence_put(fence); if (r < 0 || tmo <= 0) { - DRM_ERROR("recover vram bo from shadow failed, r is %ld, tmo is %ld\n", r, tmo); + dev_err(adev->dev, "recover vram bo from shadow failed, r is %ld, tmo is %ld\n", r, tmo); return -EIO; } - DRM_INFO("recover vram bo from shadow done\n"); + dev_info(adev->dev, "recover vram bo from shadow done\n"); return 0; } @@ -3882,7 +3913,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, amdgpu_virt_init_data_exchange(adev); /* we need recover gart prior to run SMC/CP/SDMA resume */ - amdgpu_gtt_mgr_recover(&adev->mman.bdev.man[TTM_PL_TT]); + amdgpu_gtt_mgr_recover(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)); r = amdgpu_device_fw_loading(adev); if (r) @@ -3908,6 +3939,34 @@ error: } /** + * amdgpu_device_has_job_running - check if there is any job in mirror list + * + * @adev: amdgpu device pointer + * + * check if there is any job in mirror list + */ +bool amdgpu_device_has_job_running(struct amdgpu_device *adev) +{ + int i; + struct drm_sched_job *job; + + for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { + struct amdgpu_ring *ring = adev->rings[i]; + + if (!ring || !ring->sched.thread) + continue; + + spin_lock(&ring->sched.job_list_lock); + job = list_first_entry_or_null(&ring->sched.ring_mirror_list, + struct drm_sched_job, node); + spin_unlock(&ring->sched.job_list_lock); + if (job) + return true; + } + return false; +} + +/** * amdgpu_device_should_recover_gpu - check if we should try GPU recovery * * @adev: amdgpu device pointer @@ -3918,7 +3977,7 @@ error: bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) { if (!amdgpu_device_ip_check_soft_reset(adev)) { - DRM_INFO("Timeout, but no hardware hang detected.\n"); + dev_info(adev->dev, "Timeout, but no hardware hang detected.\n"); return false; } @@ -3958,7 +4017,7 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) return true; disabled: - DRM_INFO("GPU recovery disabled.\n"); + dev_info(adev->dev, "GPU recovery disabled.\n"); return false; } @@ -3997,7 +4056,7 @@ static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, r = amdgpu_device_ip_soft_reset(adev); amdgpu_device_ip_post_soft_reset(adev); if (r || amdgpu_device_ip_check_soft_reset(adev)) { - DRM_INFO("soft reset failed, will fallback to full reset!\n"); + dev_info(adev->dev, "soft reset failed, will fallback to full reset!\n"); need_full_reset = true; } } @@ -4033,8 +4092,8 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, r = amdgpu_asic_reset(tmp_adev); if (r) { - DRM_ERROR("ASIC reset failed with error, %d for drm dev, %s", - r, tmp_adev->ddev->unique); + dev_err(tmp_adev->dev, "ASIC reset failed with error, %d for drm dev, %s", + r, adev_to_drm(tmp_adev)->unique); break; } } @@ -4066,8 +4125,8 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { if (need_full_reset) { /* post card */ - if (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) - DRM_WARN("asic atom init failed!"); + if (amdgpu_device_asic_init(tmp_adev)) + dev_warn(tmp_adev->dev, "asic atom init failed!"); if (!r) { dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); @@ -4081,8 +4140,7 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, amdgpu_inc_vram_lost(tmp_adev); } - r = amdgpu_gtt_mgr_recover( - &tmp_adev->mman.bdev.man[TTM_PL_TT]); + r = amdgpu_gtt_mgr_recover(ttm_manager_type(&tmp_adev->mman.bdev, TTM_PL_TT)); if (r) goto out; @@ -4109,8 +4167,23 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, amdgpu_fbdev_set_suspend(tmp_adev, 0); - /* must succeed. */ - amdgpu_ras_resume(tmp_adev); + /* + * The GPU enters bad state once faulty pages + * by ECC has reached the threshold, and ras + * recovery is scheduled next. So add one check + * here to break recovery if it indeed exceeds + * bad page threshold, and remind user to + * retire this GPU or setting one bigger + * bad_page_threshold value to fix this once + * probing driver again. + */ + if (!amdgpu_ras_check_err_threshold(tmp_adev)) { + /* must succeed. */ + amdgpu_ras_resume(tmp_adev); + } else { + r = -EINVAL; + goto out; + } /* Update PSP FW topology after reset */ if (hive && tmp_adev->gmc.xgmi.num_physical_nodes > 1) @@ -4118,7 +4191,6 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, } } - out: if (!r) { amdgpu_irq_gpu_reset_resume_helper(tmp_adev); @@ -4143,16 +4215,19 @@ end: return r; } -static bool amdgpu_device_lock_adev(struct amdgpu_device *adev, bool trylock) +static bool amdgpu_device_lock_adev(struct amdgpu_device *adev, + struct amdgpu_hive_info *hive) { - if (trylock) { - if (!mutex_trylock(&adev->lock_reset)) - return false; - } else - mutex_lock(&adev->lock_reset); + if (atomic_cmpxchg(&adev->in_gpu_reset, 0, 1) != 0) + return false; + + if (hive) { + down_write_nest_lock(&adev->reset_sem, &hive->hive_lock); + } else { + down_write(&adev->reset_sem); + } atomic_inc(&adev->gpu_reset_counter); - adev->in_gpu_reset = true; switch (amdgpu_asic_reset_method(adev)) { case AMD_RESET_METHOD_MODE1: adev->mp1_state = PP_MP1_STATE_SHUTDOWN; @@ -4172,8 +4247,8 @@ static void amdgpu_device_unlock_adev(struct amdgpu_device *adev) { amdgpu_vf_error_trans_all(adev); adev->mp1_state = PP_MP1_STATE_NONE; - adev->in_gpu_reset = false; - mutex_unlock(&adev->lock_reset); + atomic_set(&adev->in_gpu_reset, 0); + up_write(&adev->reset_sem); } static void amdgpu_device_resume_display_audio(struct amdgpu_device *adev) @@ -4283,12 +4358,15 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, * We always reset all schedulers for device and all devices for XGMI * hive so that should take care of them too. */ - hive = amdgpu_get_xgmi_hive(adev, true); - if (hive && !mutex_trylock(&hive->reset_lock)) { - DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as another already in progress", - job ? job->base.id : -1, hive->hive_id); - mutex_unlock(&hive->hive_lock); - return 0; + hive = amdgpu_get_xgmi_hive(adev); + if (hive) { + if (atomic_cmpxchg(&hive->in_reset, 0, 1) != 0) { + DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as another already in progress", + job ? job->base.id : -1, hive->hive_id); + amdgpu_put_xgmi_hive(hive); + return 0; + } + mutex_lock(&hive->hive_lock); } /* @@ -4310,11 +4388,11 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, /* block all schedulers and reset given job's ring */ list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { - if (!amdgpu_device_lock_adev(tmp_adev, !hive)) { - DRM_INFO("Bailing on TDR for s_job:%llx, as another already in progress", + if (!amdgpu_device_lock_adev(tmp_adev, hive)) { + dev_info(tmp_adev->dev, "Bailing on TDR for s_job:%llx, as another already in progress", job ? job->base.id : -1); - mutex_unlock(&hive->hive_lock); - return 0; + r = 0; + goto skip_recovery; } /* @@ -4386,8 +4464,8 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */ &need_full_reset); /*TODO Should we stop ?*/ if (r) { - DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", - r, tmp_adev->ddev->unique); + dev_err(tmp_adev->dev, "GPU pre asic reset failed with err, %d for drm dev, %s ", + r, adev_to_drm(tmp_adev)->unique); tmp_adev->asic_reset_res = r; } } @@ -4423,7 +4501,7 @@ skip_hw_reset: } if (!amdgpu_device_has_dc_support(tmp_adev) && !job_signaled) { - drm_helper_resume_force_mode(tmp_adev->ddev); + drm_helper_resume_force_mode(adev_to_drm(tmp_adev)); } tmp_adev->asic_reset_res = 0; @@ -4447,9 +4525,11 @@ skip_sched_resume: amdgpu_device_unlock_adev(tmp_adev); } +skip_recovery: if (hive) { - mutex_unlock(&hive->reset_lock); + atomic_set(&hive->in_reset, 0); mutex_unlock(&hive->hive_lock); + amdgpu_put_xgmi_hive(hive); } if (r) @@ -4595,10 +4675,10 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) int amdgpu_device_baco_enter(struct drm_device *dev) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); - if (!amdgpu_device_supports_baco(adev->ddev)) + if (!amdgpu_device_supports_baco(adev_to_drm(adev))) return -ENOTSUPP; if (ras && ras->supported) @@ -4609,11 +4689,11 @@ int amdgpu_device_baco_enter(struct drm_device *dev) int amdgpu_device_baco_exit(struct drm_device *dev) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); int ret = 0; - if (!amdgpu_device_supports_baco(adev->ddev)) + if (!amdgpu_device_supports_baco(adev_to_drm(adev))) return -ENOTSUPP; ret = amdgpu_dpm_baco_exit(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index a50ff2306504..bfb95143ba5e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -136,7 +136,7 @@ static int amdgpu_discovery_read_binary(struct amdgpu_device *adev, uint8_t *bin uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET; amdgpu_device_vram_access(adev, pos, (uint32_t *)binary, - adev->discovery_tmr_size, false); + adev->mman.discovery_tmr_size, false); return 0; } @@ -168,18 +168,18 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) uint16_t checksum; int r; - adev->discovery_tmr_size = DISCOVERY_TMR_SIZE; - adev->discovery_bin = kzalloc(adev->discovery_tmr_size, GFP_KERNEL); - if (!adev->discovery_bin) + adev->mman.discovery_tmr_size = DISCOVERY_TMR_SIZE; + adev->mman.discovery_bin = kzalloc(adev->mman.discovery_tmr_size, GFP_KERNEL); + if (!adev->mman.discovery_bin) return -ENOMEM; - r = amdgpu_discovery_read_binary(adev, adev->discovery_bin); + r = amdgpu_discovery_read_binary(adev, adev->mman.discovery_bin); if (r) { DRM_ERROR("failed to read ip discovery binary\n"); goto out; } - bhdr = (struct binary_header *)adev->discovery_bin; + bhdr = (struct binary_header *)adev->mman.discovery_bin; if (le32_to_cpu(bhdr->binary_signature) != BINARY_SIGNATURE) { DRM_ERROR("invalid ip discovery binary signature\n"); @@ -192,7 +192,7 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) size = bhdr->binary_size - offset; checksum = bhdr->binary_checksum; - if (!amdgpu_discovery_verify_checksum(adev->discovery_bin + offset, + if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset, size, checksum)) { DRM_ERROR("invalid ip discovery binary checksum\n"); r = -EINVAL; @@ -202,7 +202,7 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) info = &bhdr->table_list[IP_DISCOVERY]; offset = le16_to_cpu(info->offset); checksum = le16_to_cpu(info->checksum); - ihdr = (struct ip_discovery_header *)(adev->discovery_bin + offset); + ihdr = (struct ip_discovery_header *)(adev->mman.discovery_bin + offset); if (le32_to_cpu(ihdr->signature) != DISCOVERY_TABLE_SIGNATURE) { DRM_ERROR("invalid ip discovery data table signature\n"); @@ -210,7 +210,7 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) goto out; } - if (!amdgpu_discovery_verify_checksum(adev->discovery_bin + offset, + if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset, ihdr->size, checksum)) { DRM_ERROR("invalid ip discovery data table checksum\n"); r = -EINVAL; @@ -220,9 +220,9 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) info = &bhdr->table_list[GC]; offset = le16_to_cpu(info->offset); checksum = le16_to_cpu(info->checksum); - ghdr = (struct gpu_info_header *)(adev->discovery_bin + offset); + ghdr = (struct gpu_info_header *)(adev->mman.discovery_bin + offset); - if (!amdgpu_discovery_verify_checksum(adev->discovery_bin + offset, + if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset, ghdr->size, checksum)) { DRM_ERROR("invalid gc data table checksum\n"); r = -EINVAL; @@ -232,16 +232,16 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) return 0; out: - kfree(adev->discovery_bin); - adev->discovery_bin = NULL; + kfree(adev->mman.discovery_bin); + adev->mman.discovery_bin = NULL; return r; } void amdgpu_discovery_fini(struct amdgpu_device *adev) { - kfree(adev->discovery_bin); - adev->discovery_bin = NULL; + kfree(adev->mman.discovery_bin); + adev->mman.discovery_bin = NULL; } int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) @@ -265,8 +265,8 @@ int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) return r; } - bhdr = (struct binary_header *)adev->discovery_bin; - ihdr = (struct ip_discovery_header *)(adev->discovery_bin + + bhdr = (struct binary_header *)adev->mman.discovery_bin; + ihdr = (struct ip_discovery_header *)(adev->mman.discovery_bin + le16_to_cpu(bhdr->table_list[IP_DISCOVERY].offset)); num_dies = le16_to_cpu(ihdr->num_dies); @@ -274,7 +274,7 @@ int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) for (i = 0; i < num_dies; i++) { die_offset = le16_to_cpu(ihdr->die_info[i].die_offset); - dhdr = (struct die_header *)(adev->discovery_bin + die_offset); + dhdr = (struct die_header *)(adev->mman.discovery_bin + die_offset); num_ips = le16_to_cpu(dhdr->num_ips); ip_offset = die_offset + sizeof(*dhdr); @@ -288,7 +288,7 @@ int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) le16_to_cpu(dhdr->die_id), num_ips); for (j = 0; j < num_ips; j++) { - ip = (struct ip *)(adev->discovery_bin + ip_offset); + ip = (struct ip *)(adev->mman.discovery_bin + ip_offset); num_base_address = ip->num_base_address; DRM_DEBUG("%s(%d) #%d v%d.%d.%d:\n", @@ -337,24 +337,24 @@ int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, uint16_t num_ips; int i, j; - if (!adev->discovery_bin) { + if (!adev->mman.discovery_bin) { DRM_ERROR("ip discovery uninitialized\n"); return -EINVAL; } - bhdr = (struct binary_header *)adev->discovery_bin; - ihdr = (struct ip_discovery_header *)(adev->discovery_bin + + bhdr = (struct binary_header *)adev->mman.discovery_bin; + ihdr = (struct ip_discovery_header *)(adev->mman.discovery_bin + le16_to_cpu(bhdr->table_list[IP_DISCOVERY].offset)); num_dies = le16_to_cpu(ihdr->num_dies); for (i = 0; i < num_dies; i++) { die_offset = le16_to_cpu(ihdr->die_info[i].die_offset); - dhdr = (struct die_header *)(adev->discovery_bin + die_offset); + dhdr = (struct die_header *)(adev->mman.discovery_bin + die_offset); num_ips = le16_to_cpu(dhdr->num_ips); ip_offset = die_offset + sizeof(*dhdr); for (j = 0; j < num_ips; j++) { - ip = (struct ip *)(adev->discovery_bin + ip_offset); + ip = (struct ip *)(adev->mman.discovery_bin + ip_offset); if (le16_to_cpu(ip->hw_id) == hw_id) { if (major) @@ -377,13 +377,13 @@ int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev) struct binary_header *bhdr; struct gc_info_v1_0 *gc_info; - if (!adev->discovery_bin) { + if (!adev->mman.discovery_bin) { DRM_ERROR("ip discovery uninitialized\n"); return -EINVAL; } - bhdr = (struct binary_header *)adev->discovery_bin; - gc_info = (struct gc_info_v1_0 *)(adev->discovery_bin + + bhdr = (struct binary_header *)adev->mman.discovery_bin; + gc_info = (struct gc_info_v1_0 *)(adev->mman.discovery_bin + le16_to_cpu(bhdr->table_list[GC].offset)); adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->gc_num_se); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index d76172965199..c81206e6096f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -93,7 +93,7 @@ static void amdgpu_display_flip_work_func(struct work_struct *__work) * targeted by the flip */ if (amdgpu_crtc->enabled && - (amdgpu_display_get_crtc_scanoutpos(adev->ddev, work->crtc_id, 0, + (amdgpu_display_get_crtc_scanoutpos(adev_to_drm(adev), work->crtc_id, 0, &vpos, &hpos, NULL, NULL, &crtc->hwmode) & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == @@ -152,7 +152,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_gem_object *obj; struct amdgpu_flip_work *work; @@ -292,7 +292,7 @@ int amdgpu_display_crtc_set_config(struct drm_mode_set *set, pm_runtime_mark_last_busy(dev->dev); - adev = dev->dev_private; + adev = drm_to_adev(dev); /* if we have active crtcs and we don't have a power ref, take the current one */ if (active && !adev->have_disp_power_ref) { @@ -619,51 +619,51 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) int sz; adev->mode_info.coherent_mode_property = - drm_property_create_range(adev->ddev, 0 , "coherent", 0, 1); + drm_property_create_range(adev_to_drm(adev), 0, "coherent", 0, 1); if (!adev->mode_info.coherent_mode_property) return -ENOMEM; adev->mode_info.load_detect_property = - drm_property_create_range(adev->ddev, 0, "load detection", 0, 1); + drm_property_create_range(adev_to_drm(adev), 0, "load detection", 0, 1); if (!adev->mode_info.load_detect_property) return -ENOMEM; - drm_mode_create_scaling_mode_property(adev->ddev); + drm_mode_create_scaling_mode_property(adev_to_drm(adev)); sz = ARRAY_SIZE(amdgpu_underscan_enum_list); adev->mode_info.underscan_property = - drm_property_create_enum(adev->ddev, 0, - "underscan", - amdgpu_underscan_enum_list, sz); + drm_property_create_enum(adev_to_drm(adev), 0, + "underscan", + amdgpu_underscan_enum_list, sz); adev->mode_info.underscan_hborder_property = - drm_property_create_range(adev->ddev, 0, - "underscan hborder", 0, 128); + drm_property_create_range(adev_to_drm(adev), 0, + "underscan hborder", 0, 128); if (!adev->mode_info.underscan_hborder_property) return -ENOMEM; adev->mode_info.underscan_vborder_property = - drm_property_create_range(adev->ddev, 0, - "underscan vborder", 0, 128); + drm_property_create_range(adev_to_drm(adev), 0, + "underscan vborder", 0, 128); if (!adev->mode_info.underscan_vborder_property) return -ENOMEM; sz = ARRAY_SIZE(amdgpu_audio_enum_list); adev->mode_info.audio_property = - drm_property_create_enum(adev->ddev, 0, + drm_property_create_enum(adev_to_drm(adev), 0, "audio", amdgpu_audio_enum_list, sz); sz = ARRAY_SIZE(amdgpu_dither_enum_list); adev->mode_info.dither_property = - drm_property_create_enum(adev->ddev, 0, + drm_property_create_enum(adev_to_drm(adev), 0, "dither", amdgpu_dither_enum_list, sz); if (amdgpu_device_has_dc_support(adev)) { adev->mode_info.abm_level_property = - drm_property_create_range(adev->ddev, 0, - "abm level", 0, 4); + drm_property_create_range(adev_to_drm(adev), 0, + "abm level", 0, 4); if (!adev->mode_info.abm_level_property) return -ENOMEM; } @@ -813,7 +813,7 @@ int amdgpu_display_get_crtc_scanoutpos(struct drm_device *dev, int vbl_start, vbl_end, vtotal, ret = 0; bool in_vbl = true; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index 519ce4427fce..427a7c5ba93d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -35,6 +35,7 @@ #include "amdgpu_display.h" #include "amdgpu_gem.h" #include "amdgpu_dma_buf.h" +#include "amdgpu_xgmi.h" #include <drm/amdgpu_drm.h> #include <linux/dma-buf.h> #include <linux/dma-fence-array.h> @@ -454,7 +455,7 @@ static struct drm_gem_object * amdgpu_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf) { struct dma_resv *resv = dma_buf->resv; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_bo *bo; struct amdgpu_bo_param bp; int ret; @@ -595,3 +596,36 @@ struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, obj->import_attach = attach; return obj; } + +/** + * amdgpu_dmabuf_is_xgmi_accessible - Check if xgmi available for P2P transfer + * + * @adev: amdgpu_device pointer of the importer + * @bo: amdgpu buffer object + * + * Returns: + * True if dmabuf accessible over xgmi, false otherwise. + */ +bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev, + struct amdgpu_bo *bo) +{ + struct drm_gem_object *obj = &bo->tbo.base; + struct drm_gem_object *gobj; + + if (obj->import_attach) { + struct dma_buf *dma_buf = obj->import_attach->dmabuf; + + if (dma_buf->ops != &amdgpu_dmabuf_ops) + /* No XGMI with non AMD GPUs */ + return false; + + gobj = dma_buf->priv; + bo = gem_to_amdgpu_bo(gobj); + } + + if (amdgpu_xgmi_same_hive(adev, amdgpu_ttm_adev(bo->tbo.bdev)) && + (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM)) + return true; + + return false; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h index ec447a7b6b28..2c5c84a06bb9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h @@ -29,6 +29,8 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj, int flags); struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf); +bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev, + struct amdgpu_bo *bo); void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj); void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 26127c7d2f32..6edde2b9e402 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -26,6 +26,7 @@ #include <drm/drm_drv.h> #include <drm/drm_gem.h> #include <drm/drm_vblank.h> +#include <drm/drm_managed.h> #include "amdgpu_drv.h" #include <drm/drm_pciids.h> @@ -88,9 +89,10 @@ * - 3.37.0 - L2 is invalidated before SDMA IBs, needed for correctness * - 3.38.0 - Add AMDGPU_IB_FLAG_EMIT_MEM_SYNC * - 3.39.0 - DMABUF implicit sync does a full pipeline sync + * - 3.40.0 - Add AMDGPU_IDS_FLAGS_TMZ */ #define KMS_DRIVER_MAJOR 3 -#define KMS_DRIVER_MINOR 39 +#define KMS_DRIVER_MINOR 40 #define KMS_DRIVER_PATCHLEVEL 0 int amdgpu_vram_limit = 0; @@ -150,12 +152,14 @@ int amdgpu_noretry; int amdgpu_force_asic_type = -1; int amdgpu_tmz = 0; int amdgpu_reset_method = -1; /* auto */ +int amdgpu_num_kcq = -1; struct amdgpu_mgpu_info mgpu_info = { .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex), }; int amdgpu_ras_enable = -1; uint amdgpu_ras_mask = 0xffffffff; +int amdgpu_bad_page_threshold = -1; /** * DOC: vramlimit (int) @@ -393,12 +397,12 @@ MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444); /** - * DOC: ppfeaturemask (uint) + * DOC: ppfeaturemask (hexint) * Override power features enabled. See enum PP_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h. * The default is the current set of stable power features. */ MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))"); -module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, uint, 0444); +module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, hexint, 0444); /** * DOC: forcelongtraining (uint) @@ -676,11 +680,14 @@ MODULE_PARM_DESC(debug_largebar, * Ignore CRAT table during KFD initialization. By default, KFD uses the ACPI CRAT * table to get information about AMD APUs. This option can serve as a workaround on * systems with a broken CRAT table. + * + * Default is auto (according to asic type, iommu_v2, and crat table, to decide + * whehter use CRAT) */ int ignore_crat; module_param(ignore_crat, int, 0444); MODULE_PARM_DESC(ignore_crat, - "Ignore CRAT table during KFD initialization (0 = use CRAT (default), 1 = ignore CRAT)"); + "Ignore CRAT table during KFD initialization (0 = auto (default), 1 = ignore CRAT)"); /** * DOC: halt_if_hws_hang (int) @@ -715,6 +722,15 @@ MODULE_PARM_DESC(queue_preemption_timeout_ms, "queue preemption timeout in ms (1 bool debug_evictions; module_param(debug_evictions, bool, 0644); MODULE_PARM_DESC(debug_evictions, "enable eviction debug messages (false = default)"); + +/** + * DOC: no_system_mem_limit(bool) + * Disable system memory limit, to support multiple process shared memory + */ +bool no_system_mem_limit; +module_param(no_system_mem_limit, bool, 0644); +MODULE_PARM_DESC(no_system_mem_limit, "disable system memory limit (false = default)"); + #endif /** @@ -765,6 +781,19 @@ module_param_named(tmz, amdgpu_tmz, int, 0444); MODULE_PARM_DESC(reset_method, "GPU reset method (-1 = auto (default), 0 = legacy, 1 = mode0, 2 = mode1, 3 = mode2, 4 = baco)"); module_param_named(reset_method, amdgpu_reset_method, int, 0444); +/** + * DOC: bad_page_threshold (int) + * Bad page threshold is to specify the threshold value of faulty pages + * detected by RAS ECC, that may result in GPU entering bad status if total + * faulty pages by ECC exceed threshold value and leave it for user's further + * check. + */ +MODULE_PARM_DESC(bad_page_threshold, "Bad page threshold(-1 = auto(default value), 0 = disable bad page retirement)"); +module_param_named(bad_page_threshold, amdgpu_bad_page_threshold, int, 0444); + +MODULE_PARM_DESC(num_kcq, "number of kernel compute queue user want to setup (8 if set to greater than 8 or less than 0, only affect gfx 8+)"); +module_param_named(num_kcq, amdgpu_num_kcq, int, 0444); + static const struct pci_device_id pciidlist[] = { #ifdef CONFIG_DRM_AMDGPU_SI {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI}, @@ -1057,7 +1086,7 @@ static struct drm_driver kms_driver; static int amdgpu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct drm_device *dev; + struct drm_device *ddev; struct amdgpu_device *adev; unsigned long flags = ent->driver_data; int ret, retry = 0; @@ -1113,36 +1142,44 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, if (ret) return ret; - dev = drm_dev_alloc(&kms_driver, &pdev->dev); - if (IS_ERR(dev)) - return PTR_ERR(dev); + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + adev->dev = &pdev->dev; + adev->pdev = pdev; + ddev = adev_to_drm(adev); + ret = drm_dev_init(ddev, &kms_driver, &pdev->dev); + if (ret) + goto err_free; + + drmm_add_final_kfree(ddev, adev); if (!supports_atomic) - dev->driver_features &= ~DRIVER_ATOMIC; + ddev->driver_features &= ~DRIVER_ATOMIC; ret = pci_enable_device(pdev); if (ret) goto err_free; - dev->pdev = pdev; - - pci_set_drvdata(pdev, dev); + ddev->pdev = pdev; + pci_set_drvdata(pdev, ddev); - ret = amdgpu_driver_load_kms(dev, ent->driver_data); + ret = amdgpu_driver_load_kms(adev, ent->driver_data); if (ret) goto err_pci; retry_init: - ret = drm_dev_register(dev, ent->driver_data); + ret = drm_dev_register(ddev, ent->driver_data); if (ret == -EAGAIN && ++retry <= 3) { DRM_INFO("retry init %d\n", retry); /* Don't request EX mode too frequently which is attacking */ msleep(5000); goto retry_init; - } else if (ret) + } else if (ret) { goto err_pci; + } - adev = dev->dev_private; ret = amdgpu_debugfs_init(adev); if (ret) DRM_ERROR("Creating debugfs files failed (%d).\n", ret); @@ -1152,7 +1189,7 @@ retry_init: err_pci: pci_disable_device(pdev); err_free: - drm_dev_put(dev); + drm_dev_put(ddev); return ret; } @@ -1176,7 +1213,7 @@ static void amdgpu_pci_shutdown(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if (amdgpu_ras_intr_triggered()) return; @@ -1209,7 +1246,7 @@ static int amdgpu_pmops_resume(struct device *dev) static int amdgpu_pmops_freeze(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - struct amdgpu_device *adev = drm_dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(drm_dev); int r; adev->in_hibernate = true; @@ -1245,7 +1282,7 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct amdgpu_device *adev = drm_dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(drm_dev); int ret, i; if (!adev->runpm) { @@ -1296,7 +1333,7 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct amdgpu_device *adev = drm_dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(drm_dev); int ret; if (!adev->runpm) @@ -1332,7 +1369,7 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) static int amdgpu_pmops_runtime_idle(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - struct amdgpu_device *adev = drm_dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(drm_dev); /* we don't want the main rpm_idle to call suspend - we want to autosuspend */ int ret = 1; @@ -1500,8 +1537,6 @@ static struct pci_driver amdgpu_kms_pci_driver = { .driver.pm = &amdgpu_pm_ops, }; - - static int __init amdgpu_init(void) { int r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c index 61fcf247a638..af4ef84e27a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c @@ -35,7 +35,7 @@ void amdgpu_link_encoder_connector(struct drm_device *dev) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_connector *connector; struct drm_connector_list_iter iter; struct amdgpu_connector *amdgpu_connector; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index db731f573f98..e2c2eb45a793 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -135,7 +135,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | AMDGPU_GEM_CREATE_VRAM_CLEARED; - info = drm_get_format_info(adev->ddev, mode_cmd); + info = drm_get_format_info(adev_to_drm(adev), mode_cmd); cpp = info->cpp[0]; /* need to align pitch with crtc limits */ @@ -231,7 +231,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, goto out; } - ret = amdgpu_display_framebuffer_init(adev->ddev, &rfbdev->rfb, + ret = amdgpu_display_framebuffer_init(adev_to_drm(adev), &rfbdev->rfb, &mode_cmd, gobj); if (ret) { DRM_ERROR("failed to initialize framebuffer %d\n", ret); @@ -254,7 +254,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, drm_fb_helper_fill_info(info, &rfbdev->helper, sizes); /* setup aperture base/size for vesafb takeover */ - info->apertures->ranges[0].base = adev->ddev->mode_config.fb_base; + info->apertures->ranges[0].base = adev_to_drm(adev)->mode_config.fb_base; info->apertures->ranges[0].size = adev->gmc.aper_size; /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ @@ -270,7 +270,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, DRM_INFO("fb depth is %d\n", fb->format->depth); DRM_INFO(" pitch is %d\n", fb->pitches[0]); - vga_switcheroo_client_fb_set(adev->ddev->pdev, info); + vga_switcheroo_client_fb_set(adev_to_drm(adev)->pdev, info); return 0; out: @@ -318,7 +318,7 @@ int amdgpu_fbdev_init(struct amdgpu_device *adev) return 0; /* don't init fbdev if there are no connectors */ - if (list_empty(&adev->ddev->mode_config.connector_list)) + if (list_empty(&adev_to_drm(adev)->mode_config.connector_list)) return 0; /* select 8 bpp console on low vram cards */ @@ -332,10 +332,10 @@ int amdgpu_fbdev_init(struct amdgpu_device *adev) rfbdev->adev = adev; adev->mode_info.rfbdev = rfbdev; - drm_fb_helper_prepare(adev->ddev, &rfbdev->helper, - &amdgpu_fb_helper_funcs); + drm_fb_helper_prepare(adev_to_drm(adev), &rfbdev->helper, + &amdgpu_fb_helper_funcs); - ret = drm_fb_helper_init(adev->ddev, &rfbdev->helper); + ret = drm_fb_helper_init(adev_to_drm(adev), &rfbdev->helper); if (ret) { kfree(rfbdev); return ret; @@ -343,7 +343,7 @@ int amdgpu_fbdev_init(struct amdgpu_device *adev) /* disable all the possible outputs/crtcs before entering KMS mode */ if (!amdgpu_device_has_dc_support(adev)) - drm_helper_disable_unused_functions(adev->ddev); + drm_helper_disable_unused_functions(adev_to_drm(adev)); drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); return 0; @@ -354,7 +354,7 @@ void amdgpu_fbdev_fini(struct amdgpu_device *adev) if (!adev->mode_info.rfbdev) return; - amdgpu_fbdev_destroy(adev->ddev, adev->mode_info.rfbdev); + amdgpu_fbdev_destroy(adev_to_drm(adev), adev->mode_info.rfbdev); kfree(adev->mode_info.rfbdev); adev->mode_info.rfbdev = NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 58d4c219178a..fe2d495d08ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -155,7 +155,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, seq); amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, seq, flags | AMDGPU_FENCE_FLAG_INT); - pm_runtime_get_noresume(adev->ddev->dev); + pm_runtime_get_noresume(adev_to_drm(adev)->dev); ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask]; if (unlikely(rcu_dereference_protected(*ptr, 1))) { struct dma_fence *old; @@ -284,8 +284,8 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring) BUG(); dma_fence_put(fence); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); } while (last_seq != seq); return true; @@ -700,7 +700,7 @@ static int amdgpu_debugfs_fence_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int i; for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { @@ -749,7 +749,7 @@ static int amdgpu_debugfs_gpu_recover(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int r; r = pm_runtime_get_sync(dev->dev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 7f9e50247413..aa7f230c71bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -93,7 +93,7 @@ retry: void amdgpu_gem_force_release(struct amdgpu_device *adev) { - struct drm_device *ddev = adev->ddev; + struct drm_device *ddev = adev_to_drm(adev); struct drm_file *file; mutex_lock(&ddev->filelist_mutex); @@ -217,7 +217,7 @@ out_unlock: int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv = filp->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; union drm_amdgpu_gem_create *args = data; @@ -298,7 +298,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct ttm_operation_ctx ctx = { true, false }; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_amdgpu_gem_userptr *args = data; struct drm_gem_object *gobj; struct amdgpu_bo *bo; @@ -332,7 +332,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, bo = gem_to_amdgpu_bo(gobj); bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT; - r = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags); + r = amdgpu_ttm_tt_set_userptr(&bo->tbo, args->addr, args->flags); if (r) goto release_object; @@ -587,7 +587,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, struct drm_amdgpu_gem_va *args = data; struct drm_gem_object *gobj; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv = filp->driver_priv; struct amdgpu_bo *abo; struct amdgpu_bo_va *bo_va; @@ -711,7 +711,7 @@ error_unref: int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_amdgpu_gem_op *args = data; struct drm_gem_object *gobj; struct amdgpu_vm_bo_base *base; @@ -788,7 +788,7 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_gem_object *gobj; uint32_t handle; u64 flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 78d37f92c7be..d6981425ec51 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -202,40 +202,29 @@ bool amdgpu_gfx_is_high_priority_compute_queue(struct amdgpu_device *adev, void amdgpu_gfx_compute_queue_acquire(struct amdgpu_device *adev) { - int i, queue, pipe, mec; + int i, queue, pipe; bool multipipe_policy = amdgpu_gfx_is_multipipe_capable(adev); - - /* policy for amdgpu compute queue ownership */ - for (i = 0; i < AMDGPU_MAX_COMPUTE_QUEUES; ++i) { - queue = i % adev->gfx.mec.num_queue_per_pipe; - pipe = (i / adev->gfx.mec.num_queue_per_pipe) - % adev->gfx.mec.num_pipe_per_mec; - mec = (i / adev->gfx.mec.num_queue_per_pipe) - / adev->gfx.mec.num_pipe_per_mec; - - /* we've run out of HW */ - if (mec >= adev->gfx.mec.num_mec) - break; - - if (multipipe_policy) { - /* policy: amdgpu owns the first two queues of the first MEC */ - if (mec == 0 && queue < 2) - set_bit(i, adev->gfx.mec.queue_bitmap); - } else { - /* policy: amdgpu owns all queues in the first pipe */ - if (mec == 0 && pipe == 0) - set_bit(i, adev->gfx.mec.queue_bitmap); + int max_queues_per_mec = min(adev->gfx.mec.num_pipe_per_mec * + adev->gfx.mec.num_queue_per_pipe, + adev->gfx.num_compute_rings); + + if (multipipe_policy) { + /* policy: make queues evenly cross all pipes on MEC1 only */ + for (i = 0; i < max_queues_per_mec; i++) { + pipe = i % adev->gfx.mec.num_pipe_per_mec; + queue = (i / adev->gfx.mec.num_pipe_per_mec) % + adev->gfx.mec.num_queue_per_pipe; + + set_bit(pipe * adev->gfx.mec.num_queue_per_pipe + queue, + adev->gfx.mec.queue_bitmap); } + } else { + /* policy: amdgpu owns all queues in the given pipe */ + for (i = 0; i < max_queues_per_mec; ++i) + set_bit(i, adev->gfx.mec.queue_bitmap); } - /* update the number of active compute rings */ - adev->gfx.num_compute_rings = - bitmap_weight(adev->gfx.mec.queue_bitmap, AMDGPU_MAX_COMPUTE_QUEUES); - - /* If you hit this case and edited the policy, you probably just - * need to increase AMDGPU_MAX_COMPUTE_RINGS */ - if (WARN_ON(adev->gfx.num_compute_rings > AMDGPU_MAX_COMPUTE_RINGS)) - adev->gfx.num_compute_rings = AMDGPU_MAX_COMPUTE_RINGS; + dev_dbg(adev->dev, "mec queue bitmap weight=%d\n", bitmap_weight(adev->gfx.mec.queue_bitmap, AMDGPU_MAX_COMPUTE_QUEUES)); } void amdgpu_gfx_graphics_queue_acquire(struct amdgpu_device *adev) @@ -571,8 +560,14 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable) if (enable && !adev->gfx.gfx_off_state && !adev->gfx.gfx_off_req_count) { schedule_delayed_work(&adev->gfx.gfx_off_delay_work, GFX_OFF_DELAY_ENABLE); } else if (!enable && adev->gfx.gfx_off_state) { - if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false)) + if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false)) { adev->gfx.gfx_off_state = false; + + if (adev->gfx.funcs->init_spm_golden) { + dev_dbg(adev->dev, "GFXOFF is disabled, re-init SPM golden settings\n"); + amdgpu_gfx_init_spm_golden(adev); + } + } } mutex_unlock(&adev->gfx.gfx_off_mutex); @@ -724,7 +719,7 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg) * * also don't wait anymore for IRQ context * */ - if (r < 1 && (adev->in_gpu_reset || in_interrupt())) + if (r < 1 && (amdgpu_in_reset(adev) || in_interrupt())) goto failed_kiq_read; might_sleep(); @@ -748,7 +743,7 @@ failed_unlock: failed_kiq_read: if (reg_val_offs) amdgpu_device_wb_free(adev, reg_val_offs); - pr_err("failed to read reg:%x\n", reg); + dev_err(adev->dev, "failed to read reg:%x\n", reg); return ~0; } @@ -782,7 +777,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) * * also don't wait anymore for IRQ context * */ - if (r < 1 && (adev->in_gpu_reset || in_interrupt())) + if (r < 1 && (amdgpu_in_reset(adev) || in_interrupt())) goto failed_kiq_write; might_sleep(); @@ -801,5 +796,5 @@ failed_undo: amdgpu_ring_undo(ring); spin_unlock_irqrestore(&kiq->ring_lock, flags); failed_kiq_write: - pr_err("failed to write reg:%x\n", reg); + dev_err(adev->dev, "failed to write reg:%x\n", reg); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 1e7a2b0997c5..a611e78dd4ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -216,6 +216,7 @@ struct amdgpu_gfx_funcs { int (*ras_error_inject)(struct amdgpu_device *adev, void *inject_if); int (*query_ras_error_count) (struct amdgpu_device *adev, void *ras_error_status); void (*reset_ras_error_count) (struct amdgpu_device *adev); + void (*init_spm_golden)(struct amdgpu_device *adev); }; struct sq_work { @@ -324,6 +325,7 @@ struct amdgpu_gfx { #define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev)) #define amdgpu_gfx_select_se_sh(adev, se, sh, instance) (adev)->gfx.funcs->select_se_sh((adev), (se), (sh), (instance)) #define amdgpu_gfx_select_me_pipe_q(adev, me, pipe, q, vmid) (adev)->gfx.funcs->select_me_pipe_q((adev), (me), (pipe), (q), (vmid)) +#define amdgpu_gfx_init_spm_golden(adev) (adev)->gfx.funcs->init_spm_golden((adev)) /** * amdgpu_gfx_create_bitmask - create a bitmask diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 34cbd6f6a56b..213ef090bb0e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -27,6 +27,7 @@ #include <linux/io-64-nonatomic-lo-hi.h> #include "amdgpu.h" +#include "amdgpu_gmc.h" #include "amdgpu_ras.h" #include "amdgpu_xgmi.h" @@ -411,3 +412,64 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev) break; } } + +void amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type, + bool enable) +{ + struct amdgpu_vmhub *hub; + u32 tmp, reg, i; + + hub = &adev->vmhub[hub_type]; + for (i = 0; i < 16; i++) { + reg = hub->vm_context0_cntl + hub->ctx_distance * i; + + tmp = RREG32(reg); + if (enable) + tmp |= hub->vm_cntx_cntl_vm_fault; + else + tmp &= ~hub->vm_cntx_cntl_vm_fault; + + WREG32(reg, tmp); + } +} + +void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev) +{ + unsigned size; + + /* + * TODO: + * Currently there is a bug where some memory client outside + * of the driver writes to first 8M of VRAM on S3 resume, + * this overrides GART which by default gets placed in first 8M and + * causes VM_FAULTS once GTT is accessed. + * Keep the stolen memory reservation until the while this is not solved. + */ + switch (adev->asic_type) { + case CHIP_VEGA10: + case CHIP_RAVEN: + case CHIP_RENOIR: + adev->mman.keep_stolen_vga_memory = true; + break; + default: + adev->mman.keep_stolen_vga_memory = false; + break; + } + + if (!amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_DCE)) + size = 0; + else + size = amdgpu_gmc_get_vbios_fb_size(adev); + + /* set to 0 if the pre-OS buffer uses up most of vram */ + if ((adev->gmc.real_vram_size - size) < (8 * 1024 * 1024)) + size = 0; + + if (size > AMDGPU_VBIOS_VGA_ALLOCATION) { + adev->mman.stolen_vga_size = AMDGPU_VBIOS_VGA_ALLOCATION; + adev->mman.stolen_extended_size = size - adev->mman.stolen_vga_size; + } else { + adev->mman.stolen_vga_size = size; + adev->mman.stolen_extended_size = 0; + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index acdb61cfa24c..d61bbde4c7d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -74,6 +74,12 @@ struct amdgpu_gmc_fault { /* * VMHUB structures, functions & helpers */ +struct amdgpu_vmhub_funcs { + void (*print_l2_protection_fault_status)(struct amdgpu_device *adev, + uint32_t status); + uint32_t (*get_invalidate_req)(unsigned int vmid, uint32_t flush_type); +}; + struct amdgpu_vmhub { uint32_t ctx0_ptb_addr_lo32; uint32_t ctx0_ptb_addr_hi32; @@ -92,6 +98,10 @@ struct amdgpu_vmhub { uint32_t ctx_addr_distance; /* include LO32/HI32 */ uint32_t eng_distance; uint32_t eng_addr_distance; /* include LO32/HI32 */ + + uint32_t vm_cntx_cntl_vm_fault; + + const struct amdgpu_vmhub_funcs *vmhub_funcs; }; /* @@ -121,6 +131,8 @@ struct amdgpu_gmc_funcs { void (*get_vm_pte)(struct amdgpu_device *adev, struct amdgpu_bo_va_mapping *mapping, uint64_t *flags); + /* get the amount of memory used by the vbios for pre-OS console */ + unsigned int (*get_vbios_fb_size)(struct amdgpu_device *adev); }; struct amdgpu_xgmi { @@ -203,7 +215,6 @@ struct amdgpu_gmc { uint8_t vram_vendor; uint32_t srbm_soft_reset; bool prt_warning; - uint64_t stolen_size; uint32_t sdpif_register; /* apertures */ u64 shared_aperture_start; @@ -239,6 +250,7 @@ struct amdgpu_gmc { #define amdgpu_gmc_map_mtype(adev, flags) (adev)->gmc.gmc_funcs->map_mtype((adev),(flags)) #define amdgpu_gmc_get_vm_pde(adev, level, dst, flags) (adev)->gmc.gmc_funcs->get_vm_pde((adev), (level), (dst), (flags)) #define amdgpu_gmc_get_vm_pte(adev, mapping, flags) (adev)->gmc.gmc_funcs->get_vm_pte((adev), (mapping), (flags)) +#define amdgpu_gmc_get_vbios_fb_size(adev) (adev)->gmc.gmc_funcs->get_vbios_fb_size((adev)) /** * amdgpu_gmc_vram_full_visible - Check if full VRAM is visible through the BAR @@ -289,4 +301,10 @@ int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev); extern void amdgpu_gmc_tmz_set(struct amdgpu_device *adev); +extern void +amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type, + bool enable); + +void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c index 77fae40197ab..2b1b7c136343 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c @@ -24,11 +24,10 @@ #include "amdgpu.h" -struct amdgpu_gtt_mgr { - struct drm_mm mm; - spinlock_t lock; - atomic64_t available; -}; +static inline struct amdgpu_gtt_mgr *to_gtt_mgr(struct ttm_resource_manager *man) +{ + return container_of(man, struct amdgpu_gtt_mgr, manager); +} struct amdgpu_gtt_node { struct drm_mm_node node; @@ -47,10 +46,11 @@ static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); return snprintf(buf, PAGE_SIZE, "%llu\n", - (adev->mman.bdev.man[TTM_PL_TT].size) * PAGE_SIZE); + man->size * PAGE_SIZE); } /** @@ -65,10 +65,11 @@ static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); return snprintf(buf, PAGE_SIZE, "%llu\n", - amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT])); + amdgpu_gtt_mgr_usage(man)); } static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, @@ -76,6 +77,7 @@ static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, amdgpu_mem_info_gtt_used_show, NULL); +static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func; /** * amdgpu_gtt_mgr_init - init GTT manager and DRM MM * @@ -84,24 +86,25 @@ static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, * * Allocate and initialize the GTT manager. */ -static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, - unsigned long p_size) +int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) { - struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); - struct amdgpu_gtt_mgr *mgr; + struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; + struct ttm_resource_manager *man = &mgr->manager; uint64_t start, size; int ret; - mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); - if (!mgr) - return -ENOMEM; + man->use_tt = true; + man->func = &amdgpu_gtt_mgr_func; + man->available_caching = TTM_PL_MASK_CACHING; + man->default_caching = TTM_PL_FLAG_CACHED; + + ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT); start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; drm_mm_init(&mgr->mm, start, size); spin_lock_init(&mgr->lock); - atomic64_set(&mgr->available, p_size); - man->priv = mgr; + atomic64_set(&mgr->available, gtt_size >> PAGE_SHIFT); ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_total); if (ret) { @@ -114,6 +117,8 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, return ret; } + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager); + ttm_resource_manager_set_used(man, true); return 0; } @@ -125,20 +130,27 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, * Destroy and free the GTT manager, returns -EBUSY if ranges are still * allocated inside it. */ -static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man) +void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev) { - struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); - struct amdgpu_gtt_mgr *mgr = man->priv; + struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; + struct ttm_resource_manager *man = &mgr->manager; + int ret; + + ttm_resource_manager_set_used(man, false); + + ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man); + if (ret) + return; + spin_lock(&mgr->lock); drm_mm_takedown(&mgr->mm); spin_unlock(&mgr->lock); - kfree(mgr); - man->priv = NULL; device_remove_file(adev->dev, &dev_attr_mem_info_gtt_total); device_remove_file(adev->dev, &dev_attr_mem_info_gtt_used); - return 0; + ttm_resource_manager_cleanup(man); + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL); } /** @@ -148,7 +160,7 @@ static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man) * * Check if a mem object has already address space allocated. */ -bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem) +bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem) { return mem->mm_node != NULL; } @@ -163,12 +175,12 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem) * * Dummy, allocate the node but no space for it yet. */ -static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man, +static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, struct ttm_buffer_object *tbo, const struct ttm_place *place, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { - struct amdgpu_gtt_mgr *mgr = man->priv; + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); struct amdgpu_gtt_node *node; int r; @@ -226,10 +238,10 @@ err_out: * * Free the allocated GTT again. */ -static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man, - struct ttm_mem_reg *mem) +static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, + struct ttm_resource *mem) { - struct amdgpu_gtt_mgr *mgr = man->priv; + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); struct amdgpu_gtt_node *node = mem->mm_node; if (node) { @@ -249,17 +261,17 @@ static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man, * * Return how many bytes are used in the GTT domain */ -uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man) +uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man) { - struct amdgpu_gtt_mgr *mgr = man->priv; + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); s64 result = man->size - atomic64_read(&mgr->available); return (result > 0 ? result : 0) * PAGE_SIZE; } -int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man) +int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man) { - struct amdgpu_gtt_mgr *mgr = man->priv; + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); struct amdgpu_gtt_node *node; struct drm_mm_node *mm_node; int r = 0; @@ -284,10 +296,10 @@ int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man) * * Dump the table content using printk. */ -static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man, +static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man, struct drm_printer *printer) { - struct amdgpu_gtt_mgr *mgr = man->priv; + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); spin_lock(&mgr->lock); drm_mm_print(&mgr->mm, printer); @@ -298,10 +310,8 @@ static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man, amdgpu_gtt_mgr_usage(man) >> 20); } -const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = { - .init = amdgpu_gtt_mgr_init, - .takedown = amdgpu_gtt_mgr_fini, - .get_node = amdgpu_gtt_mgr_new, - .put_node = amdgpu_gtt_mgr_del, +static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = { + .alloc = amdgpu_gtt_mgr_new, + .free = amdgpu_gtt_mgr_del, .debug = amdgpu_gtt_mgr_debug }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c index 70dbe343f51d..47cad23a6b9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c @@ -40,7 +40,7 @@ static int amdgpu_i2c_pre_xfer(struct i2c_adapter *i2c_adap) { struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap); - struct amdgpu_device *adev = i2c->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(i2c->dev); struct amdgpu_i2c_bus_rec *rec = &i2c->rec; uint32_t temp; @@ -82,7 +82,7 @@ static int amdgpu_i2c_pre_xfer(struct i2c_adapter *i2c_adap) static void amdgpu_i2c_post_xfer(struct i2c_adapter *i2c_adap) { struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap); - struct amdgpu_device *adev = i2c->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(i2c->dev); struct amdgpu_i2c_bus_rec *rec = &i2c->rec; uint32_t temp; @@ -101,7 +101,7 @@ static void amdgpu_i2c_post_xfer(struct i2c_adapter *i2c_adap) static int amdgpu_i2c_get_clock(void *i2c_priv) { struct amdgpu_i2c_chan *i2c = i2c_priv; - struct amdgpu_device *adev = i2c->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(i2c->dev); struct amdgpu_i2c_bus_rec *rec = &i2c->rec; uint32_t val; @@ -116,7 +116,7 @@ static int amdgpu_i2c_get_clock(void *i2c_priv) static int amdgpu_i2c_get_data(void *i2c_priv) { struct amdgpu_i2c_chan *i2c = i2c_priv; - struct amdgpu_device *adev = i2c->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(i2c->dev); struct amdgpu_i2c_bus_rec *rec = &i2c->rec; uint32_t val; @@ -130,7 +130,7 @@ static int amdgpu_i2c_get_data(void *i2c_priv) static void amdgpu_i2c_set_clock(void *i2c_priv, int clock) { struct amdgpu_i2c_chan *i2c = i2c_priv; - struct amdgpu_device *adev = i2c->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(i2c->dev); struct amdgpu_i2c_bus_rec *rec = &i2c->rec; uint32_t val; @@ -143,7 +143,7 @@ static void amdgpu_i2c_set_clock(void *i2c_priv, int clock) static void amdgpu_i2c_set_data(void *i2c_priv, int data) { struct amdgpu_i2c_chan *i2c = i2c_priv; - struct amdgpu_device *adev = i2c->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(i2c->dev); struct amdgpu_i2c_bus_rec *rec = &i2c->rec; uint32_t val; @@ -253,7 +253,7 @@ void amdgpu_i2c_add(struct amdgpu_device *adev, const struct amdgpu_i2c_bus_rec *rec, const char *name) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); int i; for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index dcd492170598..2f53fa0ae9a6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -445,7 +445,7 @@ static int amdgpu_debugfs_sa_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); seq_printf(m, "--------------------- DELAYED --------------------- \n"); amdgpu_sa_bo_dump_debug_info(&adev->ib_pools[AMDGPU_IB_POOL_DELAYED], diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index 0cc4c67f95f7..300ac73b4738 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -85,7 +85,7 @@ static void amdgpu_hotplug_work_func(struct work_struct *work) { struct amdgpu_device *adev = container_of(work, struct amdgpu_device, hotplug_work); - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; struct drm_connector_list_iter iter; @@ -151,7 +151,7 @@ void amdgpu_irq_disable_all(struct amdgpu_device *adev) irqreturn_t amdgpu_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); irqreturn_t ret; ret = amdgpu_ih_process(adev, &adev->irq.ih); @@ -268,9 +268,9 @@ int amdgpu_irq_init(struct amdgpu_device *adev) if (!adev->enable_virtual_display) /* Disable vblank IRQs aggressively for power-saving */ /* XXX: can this be enabled for DC? */ - adev->ddev->vblank_disable_immediate = true; + adev_to_drm(adev)->vblank_disable_immediate = true; - r = drm_vblank_init(adev->ddev, adev->mode_info.num_crtc); + r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc); if (r) return r; @@ -284,14 +284,14 @@ int amdgpu_irq_init(struct amdgpu_device *adev) adev->irq.installed = true; /* Use vector 0 for MSI-X */ - r = drm_irq_install(adev->ddev, pci_irq_vector(adev->pdev, 0)); + r = drm_irq_install(adev_to_drm(adev), pci_irq_vector(adev->pdev, 0)); if (r) { adev->irq.installed = false; if (!amdgpu_device_has_dc_support(adev)) flush_work(&adev->hotplug_work); return r; } - adev->ddev->max_vblank_count = 0x00ffffff; + adev_to_drm(adev)->max_vblank_count = 0x00ffffff; DRM_DEBUG("amdgpu: irq initialized.\n"); return 0; @@ -311,7 +311,7 @@ void amdgpu_irq_fini(struct amdgpu_device *adev) unsigned i, j; if (adev->irq.installed) { - drm_irq_uninstall(adev->ddev); + drm_irq_uninstall(adev_to_drm(adev)); adev->irq.installed = false; if (adev->irq.msi_enabled) pci_free_irq_vectors(adev->pdev); @@ -522,7 +522,7 @@ void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev) int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type) { - if (!adev->ddev->irq_enabled) + if (!adev_to_drm(adev)->irq_enabled) return -ENOENT; if (type >= src->num_types) @@ -552,7 +552,7 @@ int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src, int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type) { - if (!adev->ddev->irq_enabled) + if (!adev_to_drm(adev)->irq_enabled) return -ENOENT; if (type >= src->num_types) @@ -583,7 +583,7 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type) { - if (!adev->ddev->irq_enabled) + if (!adev_to_drm(adev)->irq_enabled) return false; if (type >= src->num_types) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 937029ad5271..dcfe8a3b03ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -251,7 +251,7 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched) int i; /* Signal all jobs not yet scheduled */ - for (i = DRM_SCHED_PRIORITY_MAX - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { + for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { struct drm_sched_rq *rq = &sched->sched_rq[i]; if (!rq) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 414548064648..456a4a93b337 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -78,7 +78,7 @@ void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev) */ void amdgpu_driver_unload_kms(struct drm_device *dev) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if (adev == NULL) return; @@ -86,7 +86,7 @@ void amdgpu_driver_unload_kms(struct drm_device *dev) amdgpu_unregister_gpu_instance(adev); if (adev->rmmio == NULL) - goto done_free; + return; if (adev->runpm) { pm_runtime_get_sync(dev->dev); @@ -94,12 +94,7 @@ void amdgpu_driver_unload_kms(struct drm_device *dev) } amdgpu_acpi_fini(adev); - amdgpu_device_fini(adev); - -done_free: - kfree(adev); - dev->dev_private = NULL; } void amdgpu_register_gpu_instance(struct amdgpu_device *adev) @@ -130,22 +125,18 @@ void amdgpu_register_gpu_instance(struct amdgpu_device *adev) /** * amdgpu_driver_load_kms - Main load function for KMS. * - * @dev: drm dev pointer + * @adev: pointer to struct amdgpu_device * @flags: device flags * * This is the main load function for KMS (all asics). * Returns 0 on success, error on failure. */ -int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) +int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags) { - struct amdgpu_device *adev; + struct drm_device *dev; int r, acpi_status; - adev = kzalloc(sizeof(struct amdgpu_device), GFP_KERNEL); - if (adev == NULL) { - return -ENOMEM; - } - dev->dev_private = (void *)adev; + dev = adev_to_drm(adev); if (amdgpu_has_atpx() && (amdgpu_is_atpx_hybrid() || @@ -160,7 +151,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) * properly initialize the GPU MC controller and permit * VRAM allocation */ - r = amdgpu_device_init(adev, dev, dev->pdev, flags); + r = amdgpu_device_init(adev, flags); if (r) { dev_err(&dev->pdev->dev, "Fatal error during GPU init\n"); goto out; @@ -480,7 +471,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev, */ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_amdgpu_info *info = data; struct amdgpu_mode_info *minfo = &adev->mode_info; void __user *out = (void __user *)(uintptr_t)info->return_pointer; @@ -595,13 +586,13 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file ui64 = atomic64_read(&adev->num_vram_cpu_page_faults); return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; case AMDGPU_INFO_VRAM_USAGE: - ui64 = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); + ui64 = amdgpu_vram_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM)); return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; case AMDGPU_INFO_VIS_VRAM_USAGE: - ui64 = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); + ui64 = amdgpu_vram_mgr_vis_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM)); return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; case AMDGPU_INFO_GTT_USAGE: - ui64 = amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]); + ui64 = amdgpu_gtt_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)); return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; case AMDGPU_INFO_GDS_CONFIG: { struct drm_amdgpu_info_gds gds_info; @@ -624,7 +615,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file min(adev->gmc.visible_vram_size - atomic64_read(&adev->visible_pin_size), vram_gtt.vram_size); - vram_gtt.gtt_size = adev->mman.bdev.man[TTM_PL_TT].size; + vram_gtt.gtt_size = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)->size; vram_gtt.gtt_size *= PAGE_SIZE; vram_gtt.gtt_size -= atomic64_read(&adev->gart_pin_size); return copy_to_user(out, &vram_gtt, @@ -632,14 +623,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file } case AMDGPU_INFO_MEMORY: { struct drm_amdgpu_memory_info mem; - + struct ttm_resource_manager *vram_man = + ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); + struct ttm_resource_manager *gtt_man = + ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); memset(&mem, 0, sizeof(mem)); mem.vram.total_heap_size = adev->gmc.real_vram_size; mem.vram.usable_heap_size = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size) - AMDGPU_VM_RESERVED_VRAM; mem.vram.heap_usage = - amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); + amdgpu_vram_mgr_usage(vram_man); mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4; mem.cpu_accessible_vram.total_heap_size = @@ -649,16 +643,16 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file atomic64_read(&adev->visible_pin_size), mem.vram.usable_heap_size); mem.cpu_accessible_vram.heap_usage = - amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); + amdgpu_vram_mgr_vis_usage(vram_man); mem.cpu_accessible_vram.max_allocation = mem.cpu_accessible_vram.usable_heap_size * 3 / 4; - mem.gtt.total_heap_size = adev->mman.bdev.man[TTM_PL_TT].size; + mem.gtt.total_heap_size = gtt_man->size; mem.gtt.total_heap_size *= PAGE_SIZE; mem.gtt.usable_heap_size = mem.gtt.total_heap_size - atomic64_read(&adev->gart_pin_size); mem.gtt.heap_usage = - amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]); + amdgpu_gtt_mgr_usage(gtt_man); mem.gtt.max_allocation = mem.gtt.usable_heap_size * 3 / 4; return copy_to_user(out, &mem, @@ -742,6 +736,8 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file dev_info.ids_flags |= AMDGPU_IDS_FLAGS_FUSION; if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) dev_info.ids_flags |= AMDGPU_IDS_FLAGS_PREEMPTION; + if (amdgpu_is_tmz(adev)) + dev_info.ids_flags |= AMDGPU_IDS_FLAGS_TMZ; vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE; vm_size -= AMDGPU_VA_RESERVED_SIZE; @@ -995,7 +991,7 @@ void amdgpu_driver_lastclose_kms(struct drm_device *dev) */ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv; int r, pasid; @@ -1080,7 +1076,7 @@ pm_put: void amdgpu_driver_postclose_kms(struct drm_device *dev, struct drm_file *file_priv) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv = file_priv->driver_priv; struct amdgpu_bo_list *list; struct amdgpu_bo *pd; @@ -1145,7 +1141,7 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; unsigned int pipe = crtc->index; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int vpos, hpos, stat; u32 count; @@ -1213,7 +1209,7 @@ int amdgpu_enable_vblank_kms(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; unsigned int pipe = crtc->index; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int idx = amdgpu_display_crtc_idx_to_irq_type(adev, pipe); return amdgpu_irq_get(adev, &adev->crtc_irq, idx); @@ -1230,7 +1226,7 @@ void amdgpu_disable_vblank_kms(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; unsigned int pipe = crtc->index; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int idx = amdgpu_display_crtc_idx_to_irq_type(adev, pipe); amdgpu_irq_put(adev, &adev->crtc_irq, idx); @@ -1266,7 +1262,7 @@ static int amdgpu_debugfs_firmware_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_amdgpu_info_firmware fw_info; struct drm_amdgpu_query_fw query_fw; struct atom_context *ctx = adev->mode_info.atom_context; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h index e89fb35fec71..0c43d7fe893c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h @@ -27,6 +27,19 @@ struct amdgpu_mmhub_funcs { void (*query_ras_error_count)(struct amdgpu_device *adev, void *ras_error_status); void (*reset_ras_error_count)(struct amdgpu_device *adev); + u64 (*get_fb_location)(struct amdgpu_device *adev); + void (*init)(struct amdgpu_device *adev); + int (*gart_enable)(struct amdgpu_device *adev); + void (*set_fault_enable_default)(struct amdgpu_device *adev, + bool value); + void (*gart_disable)(struct amdgpu_device *adev); + int (*set_clockgating)(struct amdgpu_device *adev, + enum amd_clockgating_state state); + void (*get_clockgating)(struct amdgpu_device *adev, u32 *flags); + void (*setup_vm_pt_regs)(struct amdgpu_device *adev, uint32_t vmid, + uint64_t page_table_base); + void (*update_power_gating)(struct amdgpu_device *adev, + bool enable); }; struct amdgpu_mmhub { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 37ba07e2feb5..04a430e0e2e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -469,6 +469,7 @@ struct amdgpu_encoder { struct amdgpu_connector_atom_dig { /* displayport */ u8 dpcd[DP_RECEIVER_CAP_SIZE]; + u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; u8 dp_sink_type; int dp_clock; int dp_lane_count; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 5ac7b5561475..887a4da5eefc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -374,6 +374,9 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev, if (r) return r; + if ((*bo_ptr) == NULL) + return 0; + /* * Remove the original mem node and create a new one at the request * position. @@ -381,7 +384,7 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev, if (cpu_addr) amdgpu_bo_kunmap(*bo_ptr); - ttm_bo_mem_put(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem); + ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem); for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) { (*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT; @@ -442,14 +445,14 @@ void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr, static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, unsigned long size, u32 domain) { - struct ttm_mem_type_manager *man = NULL; + struct ttm_resource_manager *man = NULL; /* * If GTT is part of requested domains the check must succeed to * allow fall back to GTT */ if (domain & AMDGPU_GEM_DOMAIN_GTT) { - man = &adev->mman.bdev.man[TTM_PL_TT]; + man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); if (size < (man->size << PAGE_SHIFT)) return true; @@ -458,7 +461,7 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, } if (domain & AMDGPU_GEM_DOMAIN_VRAM) { - man = &adev->mman.bdev.man[TTM_PL_VRAM]; + man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); if (size < (man->size << PAGE_SHIFT)) return true; @@ -552,7 +555,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, bo = kzalloc(sizeof(struct amdgpu_bo), GFP_KERNEL); if (bo == NULL) return -ENOMEM; - drm_gem_private_object_init(adev->ddev, &bo->tbo.base, size); + drm_gem_private_object_init(adev_to_drm(adev), &bo->tbo.base, size); INIT_LIST_HEAD(&bo->shadow_list); bo->vm_bo = NULL; bo->preferred_domains = bp->preferred_domain ? bp->preferred_domain : @@ -1268,11 +1271,11 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, */ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct amdgpu_bo *abo; - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; if (!amdgpu_bo_is_amdgpu_bo(bo)) return; @@ -1299,7 +1302,7 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, } /** - * amdgpu_bo_move_notify - notification about a BO being released + * amdgpu_bo_release_notify - notification about a BO being released * @bo: pointer to a buffer object * * Wipes VRAM buffers whose contents should not be leaked before the diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index afa5189dba7d..5ddb6cf96030 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -160,7 +160,7 @@ static inline int amdgpu_bo_reserve(struct amdgpu_bo *bo, bool no_intr) struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); int r; - r = __ttm_bo_reserve(&bo->tbo, !no_intr, false, NULL); + r = ttm_bo_reserve(&bo->tbo, !no_intr, false, NULL); if (unlikely(r != 0)) { if (r != -ERESTARTSYS) dev_err(adev->dev, "%p reserve failed\n", bo); @@ -283,7 +283,7 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, uint64_t *flags); void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *new_mem); + struct ttm_resource *new_mem); void amdgpu_bo_release_notify(struct ttm_buffer_object *bo); int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo); void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pmu.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pmu.c index 1311d6aec5d4..69af462db34d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pmu.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pmu.c @@ -226,7 +226,7 @@ static int init_pmu_by_type(struct amdgpu_device *adev, pmu_entry->pmu.attr_groups = attr_groups; pmu_entry->pmu_perf_type = pmu_perf_type; snprintf(pmu_name, PMU_NAME_SIZE, "%s_%d", - pmu_file_prefix, adev->ddev->primary->index); + pmu_file_prefix, adev_to_drm(adev)->primary->index); ret = perf_pmu_register(&pmu_entry->pmu, pmu_name, -1); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index d8c6520ff74a..d6c38e24f130 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1429,6 +1429,168 @@ static int psp_dtm_terminate(struct psp_context *psp) } // DTM end +// RAP start +static int psp_rap_init_shared_buf(struct psp_context *psp) +{ + int ret; + + /* + * Allocate 16k memory aligned to 4k from Frame Buffer (local + * physical) for rap ta <-> Driver + */ + ret = amdgpu_bo_create_kernel(psp->adev, PSP_RAP_SHARED_MEM_SIZE, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, + &psp->rap_context.rap_shared_bo, + &psp->rap_context.rap_shared_mc_addr, + &psp->rap_context.rap_shared_buf); + + return ret; +} + +static int psp_rap_load(struct psp_context *psp) +{ + int ret; + struct psp_gfx_cmd_resp *cmd; + + cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + memset(psp->fw_pri_buf, 0, PSP_1_MEG); + memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size); + + psp_prep_ta_load_cmd_buf(cmd, + psp->fw_pri_mc_addr, + psp->ta_rap_ucode_size, + psp->rap_context.rap_shared_mc_addr, + PSP_RAP_SHARED_MEM_SIZE); + + ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + + if (!ret) { + psp->rap_context.rap_initialized = true; + psp->rap_context.session_id = cmd->resp.session_id; + mutex_init(&psp->rap_context.mutex); + } + + kfree(cmd); + + return ret; +} + +static int psp_rap_unload(struct psp_context *psp) +{ + int ret; + struct psp_gfx_cmd_resp *cmd; + + cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + psp_prep_ta_unload_cmd_buf(cmd, psp->rap_context.session_id); + + ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + + kfree(cmd); + + return ret; +} + +static int psp_rap_initialize(struct psp_context *psp) +{ + int ret; + + /* + * TODO: bypass the initialize in sriov for now + */ + if (amdgpu_sriov_vf(psp->adev)) + return 0; + + if (!psp->adev->psp.ta_rap_ucode_size || + !psp->adev->psp.ta_rap_start_addr) { + dev_info(psp->adev->dev, "RAP: optional rap ta ucode is not available\n"); + return 0; + } + + if (!psp->rap_context.rap_initialized) { + ret = psp_rap_init_shared_buf(psp); + if (ret) + return ret; + } + + ret = psp_rap_load(psp); + if (ret) + return ret; + + ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE); + if (ret != TA_RAP_STATUS__SUCCESS) { + psp_rap_unload(psp); + + amdgpu_bo_free_kernel(&psp->rap_context.rap_shared_bo, + &psp->rap_context.rap_shared_mc_addr, + &psp->rap_context.rap_shared_buf); + + psp->rap_context.rap_initialized = false; + + dev_warn(psp->adev->dev, "RAP TA initialize fail.\n"); + return -EINVAL; + } + + return 0; +} + +static int psp_rap_terminate(struct psp_context *psp) +{ + int ret; + + if (!psp->rap_context.rap_initialized) + return 0; + + ret = psp_rap_unload(psp); + + psp->rap_context.rap_initialized = false; + + /* free rap shared memory */ + amdgpu_bo_free_kernel(&psp->rap_context.rap_shared_bo, + &psp->rap_context.rap_shared_mc_addr, + &psp->rap_context.rap_shared_buf); + + return ret; +} + +int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id) +{ + struct ta_rap_shared_memory *rap_cmd; + int ret; + + if (!psp->rap_context.rap_initialized) + return -EINVAL; + + if (ta_cmd_id != TA_CMD_RAP__INITIALIZE && + ta_cmd_id != TA_CMD_RAP__VALIDATE_L0) + return -EINVAL; + + mutex_lock(&psp->rap_context.mutex); + + rap_cmd = (struct ta_rap_shared_memory *) + psp->rap_context.rap_shared_buf; + memset(rap_cmd, 0, sizeof(struct ta_rap_shared_memory)); + + rap_cmd->cmd_id = ta_cmd_id; + rap_cmd->validation_method_id = METHOD_A; + + ret = psp_ta_invoke(psp, rap_cmd->cmd_id, psp->rap_context.session_id); + if (ret) { + mutex_unlock(&psp->rap_context.mutex); + return ret; + } + + mutex_unlock(&psp->rap_context.mutex); + + return rap_cmd->rap_status; +} +// RAP end + static int psp_hw_start(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; @@ -1706,7 +1868,7 @@ static int psp_load_smu_fw(struct psp_context *psp) return 0; - if (adev->in_gpu_reset && ras && ras->supported) { + if (amdgpu_in_reset(adev) && ras && ras->supported) { ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD); if (ret) { DRM_WARN("Failed to set MP1 state prepare for reload\n"); @@ -1821,7 +1983,7 @@ static int psp_load_fw(struct amdgpu_device *adev) int ret; struct psp_context *psp = &adev->psp; - if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset) { + if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev)) { psp_ring_stop(psp, PSP_RING_TYPE__KM); /* should not destroy ring, only stop */ goto skip_memalloc; } @@ -1891,6 +2053,11 @@ skip_memalloc: if (ret) dev_err(psp->adev->dev, "DTM: Failed to initialize DTM\n"); + + ret = psp_rap_initialize(psp); + if (ret) + dev_err(psp->adev->dev, + "RAP: Failed to initialize RAP\n"); } return 0; @@ -1941,6 +2108,7 @@ static int psp_hw_fini(void *handle) if (psp->adev->psp.ta_fw) { psp_ras_terminate(psp); + psp_rap_terminate(psp); psp_dtm_terminate(psp); psp_hdcp_terminate(psp); } @@ -1999,6 +2167,11 @@ static int psp_suspend(void *handle) DRM_ERROR("Failed to terminate dtm ta\n"); return ret; } + ret = psp_rap_terminate(psp); + if (ret) { + DRM_ERROR("Failed to terminate rap ta\n"); + return ret; + } } ret = psp_asd_unload(psp); @@ -2077,6 +2250,11 @@ static int psp_resume(void *handle) if (ret) dev_err(psp->adev->dev, "DTM: Failed to initialize DTM\n"); + + ret = psp_rap_initialize(psp); + if (ret) + dev_err(psp->adev->dev, + "RAP: Failed to initialize RAP\n"); } mutex_unlock(&adev->firmware.mutex); @@ -2342,6 +2520,11 @@ int parse_ta_bin_descriptor(struct psp_context *psp, psp->ta_dtm_ucode_size = le32_to_cpu(desc->size_bytes); psp->ta_dtm_start_addr = ucode_start_addr; break; + case TA_FW_TYPE_PSP_RAP: + psp->ta_rap_ucode_version = le32_to_cpu(desc->fw_version); + psp->ta_rap_ucode_size = le32_to_cpu(desc->size_bytes); + psp->ta_rap_start_addr = ucode_start_addr; + break; default: dev_warn(psp->adev->dev, "Unsupported TA type: %d\n", desc->fw_type); break; @@ -2420,7 +2603,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint32_t fw_ver; int ret; @@ -2447,7 +2630,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); void *cpu_addr; dma_addr_t dma_addr; int ret; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 623888bf30cb..919d2fb7427b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -29,6 +29,7 @@ #include "psp_gfx_if.h" #include "ta_xgmi_if.h" #include "ta_ras_if.h" +#include "ta_rap_if.h" #define PSP_FENCE_BUFFER_SIZE 0x1000 #define PSP_CMD_BUFFER_SIZE 0x1000 @@ -38,6 +39,7 @@ #define PSP_TMR_SIZE 0x400000 #define PSP_HDCP_SHARED_MEM_SIZE 0x4000 #define PSP_DTM_SHARED_MEM_SIZE 0x4000 +#define PSP_RAP_SHARED_MEM_SIZE 0x4000 #define PSP_SHARED_MEM_SIZE 0x4000 struct psp_context; @@ -159,6 +161,15 @@ struct psp_dtm_context { struct mutex mutex; }; +struct psp_rap_context { + bool rap_initialized; + uint32_t session_id; + struct amdgpu_bo *rap_shared_bo; + uint64_t rap_shared_mc_addr; + void *rap_shared_buf; + struct mutex mutex; +}; + #define MEM_TRAIN_SYSTEM_SIGNATURE 0x54534942 #define GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES 0x1000 #define GDDR6_MEM_TRAINING_OFFSET 0x8000 @@ -277,11 +288,16 @@ struct psp_context uint32_t ta_dtm_ucode_size; uint8_t *ta_dtm_start_addr; + uint32_t ta_rap_ucode_version; + uint32_t ta_rap_ucode_size; + uint8_t *ta_rap_start_addr; + struct psp_asd_context asd_context; struct psp_xgmi_context xgmi_context; struct psp_ras_context ras; struct psp_hdcp_context hdcp_context; struct psp_dtm_context dtm_context; + struct psp_rap_context rap_context; struct mutex mutex; struct psp_memory_training_context mem_train_ctx; }; @@ -357,6 +373,7 @@ int psp_ras_trigger_error(struct psp_context *psp, 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); +int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id); int psp_rlc_autoload_start(struct psp_context *psp); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rap.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rap.c new file mode 100644 index 000000000000..8da5356c36f1 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rap.c @@ -0,0 +1,127 @@ +/* + * Copyright 2020 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 <linux/debugfs.h> +#include <linux/pm_runtime.h> + +#include "amdgpu.h" +#include "amdgpu_rap.h" + +/** + * DOC: AMDGPU RAP debugfs test interface + * + * how to use? + * echo opcode > <debugfs_dir>/dri/xxx/rap_test + * + * opcode: + * currently, only 2 is supported by Linux host driver, + * opcode 2 stands for TA_CMD_RAP__VALIDATE_L0, used to + * trigger L0 policy validation, you can refer more detail + * from header file ta_rap_if.h + * + */ +static ssize_t amdgpu_rap_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private; + struct ta_rap_shared_memory *rap_shared_mem; + struct ta_rap_cmd_output_data *rap_cmd_output; + struct drm_device *dev = adev_to_drm(adev); + uint32_t op; + int ret; + + if (*pos || size != 2) + return -EINVAL; + + ret = kstrtouint_from_user(buf, size, *pos, &op); + if (ret) + return ret; + + ret = pm_runtime_get_sync(dev->dev); + if (ret < 0) { + pm_runtime_put_autosuspend(dev->dev); + return ret; + } + + /* make sure gfx core is on, RAP TA cann't handle + * GFX OFF case currently. + */ + amdgpu_gfx_off_ctrl(adev, false); + + switch (op) { + case 2: + ret = psp_rap_invoke(&adev->psp, op); + + if (ret == TA_RAP_STATUS__SUCCESS) { + dev_info(adev->dev, "RAP L0 validate test success.\n"); + } else { + rap_shared_mem = (struct ta_rap_shared_memory *) + adev->psp.rap_context.rap_shared_buf; + rap_cmd_output = &(rap_shared_mem->rap_out_message.output); + + dev_info(adev->dev, "RAP test failed, the output is:\n"); + dev_info(adev->dev, "\tlast_subsection: 0x%08x.\n", + rap_cmd_output->last_subsection); + dev_info(adev->dev, "\tnum_total_validate: 0x%08x.\n", + rap_cmd_output->num_total_validate); + dev_info(adev->dev, "\tnum_valid: 0x%08x.\n", + rap_cmd_output->num_valid); + dev_info(adev->dev, "\tlast_validate_addr: 0x%08x.\n", + rap_cmd_output->last_validate_addr); + dev_info(adev->dev, "\tlast_validate_val: 0x%08x.\n", + rap_cmd_output->last_validate_val); + dev_info(adev->dev, "\tlast_validate_val_exptd: 0x%08x.\n", + rap_cmd_output->last_validate_val_exptd); + } + break; + default: + dev_info(adev->dev, "Unsupported op id: %d, ", op); + dev_info(adev->dev, "Only support op 2(L0 validate test).\n"); + } + + amdgpu_gfx_off_ctrl(adev, true); + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + + return size; +} + +static const struct file_operations amdgpu_rap_debugfs_ops = { + .owner = THIS_MODULE, + .read = NULL, + .write = amdgpu_rap_debugfs_write, + .llseek = default_llseek +}; + +void amdgpu_rap_debugfs_init(struct amdgpu_device *adev) +{ +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = adev_to_drm(adev)->primary; + + if (!adev->psp.rap_context.rap_initialized) + return; + + debugfs_create_file("rap_test", S_IWUSR, minor->debugfs_root, + adev, &amdgpu_rap_debugfs_ops); +#endif +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rap.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_rap.h new file mode 100644 index 000000000000..ec6d7632d3a0 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rap.h @@ -0,0 +1,30 @@ +/* + * Copyright 2020 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_RAP_H +#define _AMDGPU_RAP_H + +#include "amdgpu.h" + +void amdgpu_rap_debugfs_init(struct amdgpu_device *adev); +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 1bedb416eebd..e5ea14774c0c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -34,6 +34,8 @@ #include "amdgpu_xgmi.h" #include "ivsrcid/nbio/irqsrcs_nbif_7_4.h" +static const char *RAS_FS_NAME = "ras"; + const char *ras_error_string[] = { "none", "parity", @@ -62,13 +64,14 @@ const char *ras_block_string[] = { #define ras_err_str(i) (ras_error_string[ffs(i)]) #define ras_block_str(i) (ras_block_string[i]) -#define AMDGPU_RAS_FLAG_INIT_BY_VBIOS 1 -#define AMDGPU_RAS_FLAG_INIT_NEED_RESET 2 #define RAS_DEFAULT_FLAGS (AMDGPU_RAS_FLAG_INIT_BY_VBIOS) /* inject address is 52 bits */ #define RAS_UMC_INJECT_ADDR_LIMIT (0x1ULL << 52) +/* typical ECC bad page rate(1 bad page per 100MB VRAM) */ +#define RAS_BAD_PAGE_RATE (100 * 1024 * 1024ULL) + enum amdgpu_ras_retire_page_reservation { AMDGPU_RAS_RETIRE_PAGE_RESERVED, AMDGPU_RAS_RETIRE_PAGE_PENDING, @@ -367,12 +370,19 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, const char __user * static ssize_t amdgpu_ras_debugfs_eeprom_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private; + struct amdgpu_device *adev = + (struct amdgpu_device *)file_inode(f)->i_private; int ret; - ret = amdgpu_ras_eeprom_reset_table(&adev->psp.ras.ras->eeprom_control); + ret = amdgpu_ras_eeprom_reset_table( + &(amdgpu_ras_get_context(adev)->eeprom_control)); - return ret == 1 ? size : -EIO; + if (ret == 1) { + amdgpu_ras_get_context(adev)->flags = RAS_DEFAULT_FLAGS; + return size; + } else { + return -EIO; + } } static const struct file_operations amdgpu_ras_debugfs_ctrl_ops = { @@ -1017,6 +1027,33 @@ static ssize_t amdgpu_ras_sysfs_features_read(struct device *dev, return scnprintf(buf, PAGE_SIZE, "feature mask: 0x%x\n", con->features); } +static void amdgpu_ras_sysfs_add_bad_page_node(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + struct attribute_group group; + struct bin_attribute *bin_attrs[] = { + &con->badpages_attr, + NULL, + }; + + con->badpages_attr = (struct bin_attribute) { + .attr = { + .name = "gpu_vram_bad_pages", + .mode = S_IRUGO, + }, + .size = 0, + .private = NULL, + .read = amdgpu_ras_sysfs_badpages_read, + }; + + group.name = RAS_FS_NAME; + group.bin_attrs = bin_attrs; + + sysfs_bin_attr_init(bin_attrs[0]); + + sysfs_update_group(&adev->dev->kobj, &group); +} + static int amdgpu_ras_sysfs_create_feature_node(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); @@ -1024,14 +1061,9 @@ static int amdgpu_ras_sysfs_create_feature_node(struct amdgpu_device *adev) &con->features_attr.attr, NULL }; - struct bin_attribute *bin_attrs[] = { - &con->badpages_attr, - NULL - }; struct attribute_group group = { - .name = "ras", + .name = RAS_FS_NAME, .attrs = attrs, - .bin_attrs = bin_attrs, }; con->features_attr = (struct device_attribute) { @@ -1042,22 +1074,20 @@ static int amdgpu_ras_sysfs_create_feature_node(struct amdgpu_device *adev) .show = amdgpu_ras_sysfs_features_read, }; - con->badpages_attr = (struct bin_attribute) { - .attr = { - .name = "gpu_vram_bad_pages", - .mode = S_IRUGO, - }, - .size = 0, - .private = NULL, - .read = amdgpu_ras_sysfs_badpages_read, - }; - sysfs_attr_init(attrs[0]); - sysfs_bin_attr_init(bin_attrs[0]); return sysfs_create_group(&adev->dev->kobj, &group); } +static void amdgpu_ras_sysfs_remove_bad_page_node(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + + sysfs_remove_file_from_group(&adev->dev->kobj, + &con->badpages_attr.attr, + RAS_FS_NAME); +} + static int amdgpu_ras_sysfs_remove_feature_node(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); @@ -1065,14 +1095,9 @@ static int amdgpu_ras_sysfs_remove_feature_node(struct amdgpu_device *adev) &con->features_attr.attr, NULL }; - struct bin_attribute *bin_attrs[] = { - &con->badpages_attr, - NULL - }; struct attribute_group group = { - .name = "ras", + .name = RAS_FS_NAME, .attrs = attrs, - .bin_attrs = bin_attrs, }; sysfs_remove_group(&adev->dev->kobj, &group); @@ -1105,7 +1130,7 @@ int amdgpu_ras_sysfs_create(struct amdgpu_device *adev, if (sysfs_add_file_to_group(&adev->dev->kobj, &obj->sysfs_attr.attr, - "ras")) { + RAS_FS_NAME)) { put_obj(obj); return -EINVAL; } @@ -1125,7 +1150,7 @@ int amdgpu_ras_sysfs_remove(struct amdgpu_device *adev, sysfs_remove_file_from_group(&adev->dev->kobj, &obj->sysfs_attr.attr, - "ras"); + RAS_FS_NAME); obj->attr_inuse = 0; put_obj(obj); @@ -1141,6 +1166,9 @@ static int amdgpu_ras_sysfs_remove_all(struct amdgpu_device *adev) amdgpu_ras_sysfs_remove(adev, &obj->head); } + if (amdgpu_bad_page_threshold != 0) + amdgpu_ras_sysfs_remove_bad_page_node(adev); + amdgpu_ras_sysfs_remove_feature_node(adev); return 0; @@ -1169,9 +1197,9 @@ static int amdgpu_ras_sysfs_remove_all(struct amdgpu_device *adev) static void amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - struct drm_minor *minor = adev->ddev->primary; + struct drm_minor *minor = adev_to_drm(adev)->primary; - con->dir = debugfs_create_dir("ras", minor->debugfs_root); + con->dir = debugfs_create_dir(RAS_FS_NAME, minor->debugfs_root); debugfs_create_file("ras_ctrl", S_IWUGO | S_IRUGO, con->dir, adev, &amdgpu_ras_debugfs_ctrl_ops); debugfs_create_file("ras_eeprom_reset", S_IWUGO | S_IRUGO, con->dir, @@ -1187,6 +1215,13 @@ static void amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *adev) */ debugfs_create_bool("auto_reboot", S_IWUGO | S_IRUGO, con->dir, &con->reboot); + + /* + * User could set this not to clean up hardware's error count register + * of RAS IPs during ras recovery. + */ + debugfs_create_bool("disable_ras_err_cnt_harvest", 0644, + con->dir, &con->disable_ras_err_cnt_harvest); } void amdgpu_ras_debugfs_create(struct amdgpu_device *adev, @@ -1211,6 +1246,7 @@ void amdgpu_ras_debugfs_create(struct amdgpu_device *adev, void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev) { +#if defined(CONFIG_DEBUG_FS) struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct ras_manager *obj; struct ras_fs_if fs_info; @@ -1233,6 +1269,7 @@ void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev) amdgpu_ras_debugfs_create(adev, &fs_info); } } +#endif } void amdgpu_ras_debugfs_remove(struct amdgpu_device *adev, @@ -1249,6 +1286,7 @@ void amdgpu_ras_debugfs_remove(struct amdgpu_device *adev, static void amdgpu_ras_debugfs_remove_all(struct amdgpu_device *adev) { +#if defined(CONFIG_DEBUG_FS) struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct ras_manager *obj, *tmp; @@ -1257,6 +1295,7 @@ static void amdgpu_ras_debugfs_remove_all(struct amdgpu_device *adev) } con->dir = NULL; +#endif } /* debugfs end */ @@ -1266,6 +1305,9 @@ static int amdgpu_ras_fs_init(struct amdgpu_device *adev) { amdgpu_ras_sysfs_create_feature_node(adev); + if (amdgpu_bad_page_threshold != 0) + amdgpu_ras_sysfs_add_bad_page_node(adev); + return 0; } @@ -1512,23 +1554,28 @@ static void amdgpu_ras_do_recovery(struct work_struct *work) struct amdgpu_device *remote_adev = NULL; struct amdgpu_device *adev = ras->adev; struct list_head device_list, *device_list_handle = NULL; - struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev, false); - - /* Build list of devices to query RAS related errors */ - if (hive && adev->gmc.xgmi.num_physical_nodes > 1) - device_list_handle = &hive->device_list; - else { - INIT_LIST_HEAD(&device_list); - list_add_tail(&adev->gmc.xgmi.head, &device_list); - device_list_handle = &device_list; - } - list_for_each_entry(remote_adev, device_list_handle, gmc.xgmi.head) { - amdgpu_ras_log_on_err_counter(remote_adev); + if (!ras->disable_ras_err_cnt_harvest) { + struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev); + + /* Build list of devices to query RAS related errors */ + if (hive && adev->gmc.xgmi.num_physical_nodes > 1) { + device_list_handle = &hive->device_list; + } else { + INIT_LIST_HEAD(&device_list); + list_add_tail(&adev->gmc.xgmi.head, &device_list); + device_list_handle = &device_list; + } + + list_for_each_entry(remote_adev, + device_list_handle, gmc.xgmi.head) + amdgpu_ras_log_on_err_counter(remote_adev); + + amdgpu_put_xgmi_hive(hive); } if (amdgpu_device_should_recover_gpu(ras->adev)) - amdgpu_device_gpu_recover(ras->adev, 0); + amdgpu_device_gpu_recover(ras->adev, NULL); atomic_set(&ras->in_recovery, 0); } @@ -1643,7 +1690,7 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev) int ret = 0; /* no bad page record, skip eeprom access */ - if (!control->num_recs) + if (!control->num_recs || (amdgpu_bad_page_threshold == 0)) return ret; bps = kcalloc(control->num_recs, sizeof(*bps), GFP_KERNEL); @@ -1697,6 +1744,47 @@ out: return ret; } +static void amdgpu_ras_validate_threshold(struct amdgpu_device *adev, + uint32_t max_length) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + int tmp_threshold = amdgpu_bad_page_threshold; + u64 val; + + /* + * Justification of value bad_page_cnt_threshold in ras structure + * + * Generally, -1 <= amdgpu_bad_page_threshold <= max record length + * in eeprom, and introduce two scenarios accordingly. + * + * Bad page retirement enablement: + * - If amdgpu_bad_page_threshold = -1, + * bad_page_cnt_threshold = typical value by formula. + * + * - When the value from user is 0 < amdgpu_bad_page_threshold < + * max record length in eeprom, use it directly. + * + * Bad page retirement disablement: + * - If amdgpu_bad_page_threshold = 0, bad page retirement + * functionality is disabled, and bad_page_cnt_threshold will + * take no effect. + */ + + if (tmp_threshold < -1) + tmp_threshold = -1; + else if (tmp_threshold > max_length) + tmp_threshold = max_length; + + if (tmp_threshold == -1) { + val = adev->gmc.mc_vram_size; + do_div(val, RAS_BAD_PAGE_RATE); + con->bad_page_cnt_threshold = min(lower_32_bits(val), + max_length); + } else { + con->bad_page_cnt_threshold = tmp_threshold; + } +} + /* called in gpu recovery/init */ int amdgpu_ras_reserve_bad_pages(struct amdgpu_device *adev) { @@ -1706,7 +1794,8 @@ int amdgpu_ras_reserve_bad_pages(struct amdgpu_device *adev) struct amdgpu_bo *bo = NULL; int i, ret = 0; - if (!con || !con->eh_data) + /* Not reserve bad page when amdgpu_bad_page_threshold == 0. */ + if (!con || !con->eh_data || (amdgpu_bad_page_threshold == 0)) return 0; mutex_lock(&con->recovery_lock); @@ -1774,6 +1863,8 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct ras_err_handler_data **data; + uint32_t max_eeprom_records_len = 0; + bool exc_err_limit = false; int ret; if (con) @@ -1792,8 +1883,15 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) atomic_set(&con->in_recovery, 0); con->adev = adev; - ret = amdgpu_ras_eeprom_init(&con->eeprom_control); - if (ret) + max_eeprom_records_len = amdgpu_ras_eeprom_get_record_max_length(); + amdgpu_ras_validate_threshold(adev, max_eeprom_records_len); + + ret = amdgpu_ras_eeprom_init(&con->eeprom_control, &exc_err_limit); + /* + * This calling fails when exc_err_limit is true or + * ret != 0. + */ + if (exc_err_limit || ret) goto free; if (con->eeprom_control.num_recs) { @@ -1817,6 +1915,15 @@ free: out: dev_warn(adev->dev, "Failed to initialize ras recovery!\n"); + /* + * Except error threshold exceeding case, other failure cases in this + * function would not fail amdgpu driver init. + */ + if (!exc_err_limit) + ret = 0; + else + ret = -EINVAL; + return ret; } @@ -1856,6 +1963,17 @@ int amdgpu_ras_request_reset_on_boot(struct amdgpu_device *adev, return 0; } +static int amdgpu_ras_check_asic_type(struct amdgpu_device *adev) +{ + if (adev->asic_type != CHIP_VEGA10 && + adev->asic_type != CHIP_VEGA20 && + adev->asic_type != CHIP_ARCTURUS && + adev->asic_type != CHIP_SIENNA_CICHLID) + return 1; + else + return 0; +} + /* * 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 @@ -1872,8 +1990,7 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev, *supported = 0; if (amdgpu_sriov_vf(adev) || !adev->is_atom_fw || - (adev->asic_type != CHIP_VEGA20 && - adev->asic_type != CHIP_ARCTURUS)) + amdgpu_ras_check_asic_type(adev)) return; if (amdgpu_atomfirmware_mem_ecc_supported(adev)) { @@ -1895,6 +2012,7 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev, *supported = amdgpu_ras_enable == 0 ? 0 : *hw_supported & amdgpu_ras_mask; + adev->ras_features = *supported; } int amdgpu_ras_init(struct amdgpu_device *adev) @@ -1917,9 +2035,9 @@ int amdgpu_ras_init(struct amdgpu_device *adev) amdgpu_ras_check_supported(adev, &con->hw_supported, &con->supported); - if (!con->hw_supported) { + if (!con->hw_supported || (adev->asic_type == CHIP_VEGA10)) { r = 0; - goto err_out; + goto release_con; } con->features = 0; @@ -1930,25 +2048,25 @@ int amdgpu_ras_init(struct amdgpu_device *adev) if (adev->nbio.funcs->init_ras_controller_interrupt) { r = adev->nbio.funcs->init_ras_controller_interrupt(adev); if (r) - goto err_out; + goto release_con; } if (adev->nbio.funcs->init_ras_err_event_athub_interrupt) { r = adev->nbio.funcs->init_ras_err_event_athub_interrupt(adev); if (r) - goto err_out; + goto release_con; } if (amdgpu_ras_fs_init(adev)) { r = -EINVAL; - goto err_out; + goto release_con; } dev_info(adev->dev, "RAS INFO: ras initialized successfully, " "hardware ability[%x] ras_mask[%x]\n", con->hw_supported, con->supported); return 0; -err_out: +release_con: amdgpu_ras_set_context(adev, NULL); kfree(con); @@ -1976,7 +2094,7 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev, amdgpu_ras_request_reset_on_boot(adev, ras_block->block); return 0; - } else if (adev->in_suspend || adev->in_gpu_reset) { + } else if (adev->in_suspend || amdgpu_in_reset(adev)) { /* in resume phase, if fail to enable ras, * clean up all ras fs nodes, and disable ras */ goto cleanup; @@ -1985,7 +2103,7 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev, } /* in resume phase, no need to create ras fs node */ - if (adev->in_suspend || adev->in_gpu_reset) + if (adev->in_suspend || amdgpu_in_reset(adev)) return 0; if (ih_info->cb) { @@ -2143,3 +2261,19 @@ bool amdgpu_ras_need_emergency_restart(struct amdgpu_device *adev) return false; } + +bool amdgpu_ras_check_err_threshold(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + bool exc_err_limit = false; + + if (con && (amdgpu_bad_page_threshold != 0)) + amdgpu_ras_eeprom_check_err_threshold(&con->eeprom_control, + &exc_err_limit); + + /* + * We are only interested in variable exc_err_limit, + * as it says if GPU is in bad state or not. + */ + return exc_err_limit; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index b2667342cf67..6b8d7bb83bb3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -31,6 +31,10 @@ #include "ta_ras_if.h" #include "amdgpu_ras_eeprom.h" +#define AMDGPU_RAS_FLAG_INIT_BY_VBIOS (0x1 << 0) +#define AMDGPU_RAS_FLAG_INIT_NEED_RESET (0x1 << 1) +#define AMDGPU_RAS_FLAG_SKIP_BAD_PAGE_RESV (0x1 << 2) + enum amdgpu_ras_block { AMDGPU_RAS_BLOCK__UMC = 0, AMDGPU_RAS_BLOCK__SDMA, @@ -336,6 +340,12 @@ struct amdgpu_ras { struct amdgpu_ras_eeprom_control eeprom_control; bool error_query_ready; + + /* bad page count threshold */ + uint32_t bad_page_cnt_threshold; + + /* disable ras error count harvest in recovery */ + bool disable_ras_err_cnt_harvest; }; struct ras_fs_data { @@ -490,6 +500,8 @@ void amdgpu_ras_suspend(struct amdgpu_device *adev); unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev, bool is_ce); +bool amdgpu_ras_check_err_threshold(struct amdgpu_device *adev); + /* error handling functions */ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, struct eeprom_table_record *bps, int pages); @@ -500,10 +512,14 @@ static inline int amdgpu_ras_reset_gpu(struct amdgpu_device *adev) { struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); - /* save bad page to eeprom before gpu reset, - * i2c may be unstable in gpu reset + /* + * Save bad page to eeprom before gpu reset, i2c may be unstable + * in gpu reset. + * + * Also, exclude the case when ras recovery issuer is + * eeprom page write itself. */ - if (in_task()) + if (!(ras->flags & AMDGPU_RAS_FLAG_SKIP_BAD_PAGE_RESV) && in_task()) amdgpu_ras_reserve_bad_pages(adev); if (atomic_cmpxchg(&ras->in_recovery, 0, 1) == 0) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index c0096097bbcf..0e64c39a2372 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -46,6 +46,9 @@ #define EEPROM_TABLE_HDR_VAL 0x414d4452 #define EEPROM_TABLE_VER 0x00010000 +/* Bad GPU tag ‘BADG’ */ +#define EEPROM_TABLE_HDR_BAD 0x42414447 + /* Assume 2 Mbit size */ #define EEPROM_SIZE_BYTES 256000 #define EEPROM_PAGE__SIZE_BYTES 256 @@ -56,6 +59,15 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_ras, eeprom_control))->adev +static bool __is_ras_eeprom_supported(struct amdgpu_device *adev) +{ + if ((adev->asic_type == CHIP_VEGA20) || + (adev->asic_type == CHIP_ARCTURUS)) + return true; + + return false; +} + static bool __get_eeprom_i2c_addr_arct(struct amdgpu_device *adev, uint16_t *i2c_addr) { @@ -213,6 +225,24 @@ static bool __validate_tbl_checksum(struct amdgpu_ras_eeprom_control *control, return true; } +static int amdgpu_ras_eeprom_correct_header_tag( + struct amdgpu_ras_eeprom_control *control, + uint32_t header) +{ + unsigned char buff[EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE]; + struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr; + int ret = 0; + + memset(buff, 0, EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE); + + mutex_lock(&control->tbl_mutex); + hdr->header = header; + ret = __update_table_header(control, buff); + mutex_unlock(&control->tbl_mutex); + + return ret; +} + int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) { unsigned char buff[EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE] = { 0 }; @@ -238,12 +268,14 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) } -int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) +int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, + bool *exceed_err_limit) { int ret = 0; struct amdgpu_device *adev = to_amdgpu_device(control); unsigned char buff[EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE] = { 0 }; struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr; + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); struct i2c_msg msg = { .addr = 0, .flags = I2C_M_RD, @@ -251,6 +283,11 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) .buf = buff, }; + *exceed_err_limit = false; + + if (!__is_ras_eeprom_supported(adev)) + return 0; + /* Verify i2c adapter is initialized */ if (!adev->pm.smu_i2c.algo) return -ENOENT; @@ -279,6 +316,18 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) DRM_DEBUG_DRIVER("Found existing EEPROM table with %d records", control->num_recs); + } else if ((hdr->header == EEPROM_TABLE_HDR_BAD) && + (amdgpu_bad_page_threshold != 0)) { + if (ras->bad_page_cnt_threshold > control->num_recs) { + dev_info(adev->dev, "Using one valid bigger bad page " + "threshold and correcting eeprom header tag.\n"); + ret = amdgpu_ras_eeprom_correct_header_tag(control, + EEPROM_TABLE_HDR_VAL); + } else { + *exceed_err_limit = true; + dev_err(adev->dev, "Exceeding the bad_page_threshold parameter, " + "disabling the GPU.\n"); + } } else { DRM_INFO("Creating new EEPROM table"); @@ -375,6 +424,49 @@ static uint32_t __correct_eeprom_dest_address(uint32_t curr_address) return curr_address; } +int amdgpu_ras_eeprom_check_err_threshold( + struct amdgpu_ras_eeprom_control *control, + bool *exceed_err_limit) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + unsigned char buff[EEPROM_ADDRESS_SIZE + + EEPROM_TABLE_HEADER_SIZE] = { 0 }; + struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr; + struct i2c_msg msg = { + .addr = control->i2c_address, + .flags = I2C_M_RD, + .len = EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE, + .buf = buff, + }; + int ret; + + *exceed_err_limit = false; + + if (!__is_ras_eeprom_supported(adev)) + return 0; + + /* read EEPROM table header */ + mutex_lock(&control->tbl_mutex); + ret = i2c_transfer(&adev->pm.smu_i2c, &msg, 1); + if (ret < 1) { + dev_err(adev->dev, "Failed to read EEPROM table header.\n"); + goto err; + } + + __decode_table_header_from_buff(hdr, &buff[2]); + + if (hdr->header == EEPROM_TABLE_HDR_BAD) { + dev_warn(adev->dev, "This GPU is in BAD status."); + dev_warn(adev->dev, "Please retire it or setting one bigger " + "threshold value when reloading driver.\n"); + *exceed_err_limit = true; + } + +err: + mutex_unlock(&control->tbl_mutex); + return 0; +} + int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, struct eeprom_table_record *records, bool write, @@ -383,10 +475,12 @@ int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, int i, ret = 0; struct i2c_msg *msgs, *msg; unsigned char *buffs, *buff; + bool sched_ras_recovery = false; struct eeprom_table_record *record; struct amdgpu_device *adev = to_amdgpu_device(control); + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); - if (adev->asic_type != CHIP_VEGA20 && adev->asic_type != CHIP_ARCTURUS) + if (!__is_ras_eeprom_supported(adev)) return 0; buffs = kcalloc(num, EEPROM_ADDRESS_SIZE + EEPROM_TABLE_RECORD_SIZE, @@ -402,11 +496,30 @@ int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, goto free_buff; } + /* + * If saved bad pages number exceeds the bad page threshold for + * the whole VRAM, update table header to mark the BAD GPU tag + * and schedule one ras recovery after eeprom write is done, + * this can avoid the missing for latest records. + * + * This new header will be picked up and checked in the bootup + * by ras recovery, which may break bootup process to notify + * user this GPU is in bad state and to retire such GPU for + * further check. + */ + if (write && (amdgpu_bad_page_threshold != 0) && + ((control->num_recs + num) >= ras->bad_page_cnt_threshold)) { + dev_warn(adev->dev, + "Saved bad pages(%d) reaches threshold value(%d).\n", + control->num_recs + num, ras->bad_page_cnt_threshold); + control->tbl_hdr.header = EEPROM_TABLE_HDR_BAD; + sched_ras_recovery = true; + } + /* In case of overflow just start from beginning to not lose newest records */ if (write && (control->next_addr + EEPROM_TABLE_RECORD_SIZE * num > EEPROM_SIZE_BYTES)) control->next_addr = EEPROM_RECORD_START; - /* * TODO Currently makes EEPROM writes for each record, this creates * internal fragmentation. Optimized the code to do full page write of @@ -482,6 +595,20 @@ int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, __update_tbl_checksum(control, records, num, old_hdr_byte_sum); __update_table_header(control, buffs); + + if (sched_ras_recovery) { + /* + * Before scheduling ras recovery, assert the related + * flag first, which shall bypass common bad page + * reservation execution in amdgpu_ras_reset_gpu. + */ + amdgpu_ras_get_context(adev)->flags |= + AMDGPU_RAS_FLAG_SKIP_BAD_PAGE_RESV; + + dev_warn(adev->dev, "Conduct ras recovery due to bad " + "page threshold reached.\n"); + amdgpu_ras_reset_gpu(adev); + } } else if (!__validate_tbl_checksum(control, records, num)) { DRM_WARN("EEPROM Table checksum mismatch!"); /* TODO Uncomment when EEPROM read/write is relliable */ @@ -499,6 +626,11 @@ free_buff: return ret == num ? 0 : -EIO; } +inline uint32_t amdgpu_ras_eeprom_get_record_max_length(void) +{ + return EEPROM_MAX_RECORD_NUM; +} + /* Used for testing if bugs encountered */ #if 0 void amdgpu_ras_eeprom_test(struct amdgpu_ras_eeprom_control *control) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index 9e7d640920fb..c7a5e5c7c61e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -76,14 +76,21 @@ struct eeprom_table_record { unsigned char mcumc_id; }__attribute__((__packed__)); -int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control); +int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, + bool *exceed_err_limit); int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control); +int amdgpu_ras_eeprom_check_err_threshold( + struct amdgpu_ras_eeprom_control *control, + bool *exceed_err_limit); + int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, struct eeprom_table_record *records, bool write, int num); +inline uint32_t amdgpu_ras_eeprom_get_record_max_length(void); + void amdgpu_ras_eeprom_test(struct amdgpu_ras_eeprom_control *control); #endif // _AMDGPU_RAS_EEPROM_H diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 13ea8ebc421c..15ee13c3bd9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -267,7 +267,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, &ring->sched; } - for (i = 0; i < DRM_SCHED_PRIORITY_MAX; ++i) + for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_COUNT; ++i) atomic_set(&ring->num_jobs[i], 0); return 0; @@ -420,7 +420,7 @@ int amdgpu_debugfs_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring) { #if defined(CONFIG_DEBUG_FS) - struct drm_minor *minor = adev->ddev->primary; + struct drm_minor *minor = adev_to_drm(adev)->primary; struct dentry *ent, *root = minor->debugfs_root; char name[32]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index da871d84b742..7112137689db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -243,7 +243,7 @@ struct amdgpu_ring { bool has_compute_vm_bug; bool no_scheduler; - atomic_t num_jobs[DRM_SCHED_PRIORITY_MAX]; + atomic_t num_jobs[DRM_SCHED_PRIORITY_COUNT]; struct mutex priority_mutex; /* protected by priority_mutex */ int priority; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index c799691dfa84..0da0a0d98672 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -32,24 +32,32 @@ #include "amdgpu_vm.h" -enum drm_sched_priority amdgpu_to_sched_priority(int amdgpu_priority) +int amdgpu_to_sched_priority(int amdgpu_priority, + enum drm_sched_priority *prio) { switch (amdgpu_priority) { case AMDGPU_CTX_PRIORITY_VERY_HIGH: - return DRM_SCHED_PRIORITY_HIGH_HW; + *prio = DRM_SCHED_PRIORITY_HIGH; + break; case AMDGPU_CTX_PRIORITY_HIGH: - return DRM_SCHED_PRIORITY_HIGH_SW; + *prio = DRM_SCHED_PRIORITY_HIGH; + break; case AMDGPU_CTX_PRIORITY_NORMAL: - return DRM_SCHED_PRIORITY_NORMAL; + *prio = DRM_SCHED_PRIORITY_NORMAL; + break; case AMDGPU_CTX_PRIORITY_LOW: case AMDGPU_CTX_PRIORITY_VERY_LOW: - return DRM_SCHED_PRIORITY_LOW; + *prio = DRM_SCHED_PRIORITY_MIN; + break; case AMDGPU_CTX_PRIORITY_UNSET: - return DRM_SCHED_PRIORITY_UNSET; + *prio = DRM_SCHED_PRIORITY_UNSET; + break; default: WARN(1, "Invalid context priority %d\n", amdgpu_priority); - return DRM_SCHED_PRIORITY_INVALID; + return -EINVAL; } + + return 0; } static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, @@ -115,13 +123,24 @@ int amdgpu_sched_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { union drm_amdgpu_sched *args = data; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); enum drm_sched_priority priority; int r; - priority = amdgpu_to_sched_priority(args->in.priority); - if (priority == DRM_SCHED_PRIORITY_INVALID) + /* First check the op, then the op's argument. + */ + switch (args->in.op) { + case AMDGPU_SCHED_OP_PROCESS_PRIORITY_OVERRIDE: + case AMDGPU_SCHED_OP_CONTEXT_PRIORITY_OVERRIDE: + break; + default: + DRM_ERROR("Invalid sched op specified: %d\n", args->in.op); return -EINVAL; + } + + r = amdgpu_to_sched_priority(args->in.priority, &priority); + if (r) + return r; switch (args->in.op) { case AMDGPU_SCHED_OP_PROCESS_PRIORITY_OVERRIDE: @@ -136,7 +155,8 @@ int amdgpu_sched_ioctl(struct drm_device *dev, void *data, priority); break; default: - DRM_ERROR("Invalid sched op specified: %d\n", args->in.op); + /* Impossible. + */ r = -EINVAL; break; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.h index 12299fd95691..67e5b2472f6a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.h @@ -30,7 +30,8 @@ enum drm_sched_priority; struct drm_device; struct drm_file; -enum drm_sched_priority amdgpu_to_sched_priority(int amdgpu_priority); +int amdgpu_to_sched_priority(int amdgpu_priority, + enum drm_sched_priority *prio); int amdgpu_sched_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index e11c5d69843d..371bc099fda2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -63,61 +63,13 @@ #define AMDGPU_TTM_VRAM_MAX_DW_READ (size_t)128 - -/** - * amdgpu_init_mem_type - Initialize a memory manager for a specific type of - * memory request. - * - * @bdev: The TTM BO device object (contains a reference to amdgpu_device) - * @type: The type of memory requested - * @man: The memory type manager for each domain - * - * This is called by ttm_bo_init_mm() when a buffer object is being - * initialized. - */ -static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, - struct ttm_mem_type_manager *man) +static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev, + unsigned int type, + uint64_t size) { - struct amdgpu_device *adev; - - adev = amdgpu_ttm_adev(bdev); - - switch (type) { - case TTM_PL_SYSTEM: - /* System memory */ - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case TTM_PL_TT: - /* GTT memory */ - man->func = &amdgpu_gtt_mgr_func; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; - break; - case TTM_PL_VRAM: - /* "On-card" video ram */ - man->func = &amdgpu_vram_mgr_func; - man->flags = TTM_MEMTYPE_FLAG_FIXED | - TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; - break; - case AMDGPU_PL_GDS: - case AMDGPU_PL_GWS: - case AMDGPU_PL_OA: - /* On-chip GDS memory*/ - man->func = &ttm_bo_manager_func; - man->flags = TTM_MEMTYPE_FLAG_FIXED; - man->available_caching = TTM_PL_FLAG_UNCACHED; - man->default_caching = TTM_PL_FLAG_UNCACHED; - break; - default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); - return -EINVAL; - } - return 0; + return ttm_range_man_init(&adev->mman.bdev, type, + TTM_PL_FLAG_UNCACHED, TTM_PL_FLAG_UNCACHED, + false, size >> PAGE_SHIFT); } /** @@ -231,9 +183,9 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp) * Assign the memory from new_mem to the memory of the buffer object bo. */ static void amdgpu_move_null(struct ttm_buffer_object *bo, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; BUG_ON(old_mem->mm_node != NULL); *old_mem = *new_mem; @@ -250,7 +202,7 @@ static void amdgpu_move_null(struct ttm_buffer_object *bo, */ static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo, struct drm_mm_node *mm_node, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { uint64_t addr = 0; @@ -270,7 +222,7 @@ static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo, * @offset: The offset that drm_mm_node is used for finding. * */ -static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem, +static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_resource *mem, uint64_t *offset) { struct drm_mm_node *mm_node = mem->mm_node; @@ -298,7 +250,7 @@ static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem, * the physical address for local memory. */ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, struct drm_mm_node *mm_node, unsigned num_pages, uint64_t offset, unsigned window, struct amdgpu_ring *ring, @@ -522,8 +474,8 @@ error: */ static int amdgpu_move_blit(struct ttm_buffer_object *bo, bool evict, bool no_wait_gpu, - struct ttm_mem_reg *new_mem, - struct ttm_mem_reg *old_mem) + struct ttm_resource *new_mem, + struct ttm_resource *old_mem) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); @@ -582,10 +534,10 @@ error: */ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { - struct ttm_mem_reg *old_mem = &bo->mem; - struct ttm_mem_reg tmp_mem; + struct ttm_resource *old_mem = &bo->mem; + struct ttm_resource tmp_mem; struct ttm_place placements; struct ttm_placement placement; int r; @@ -627,7 +579,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict, /* move BO (in tmp_mem) to new_mem */ r = ttm_bo_move_ttm(bo, ctx, new_mem); out_cleanup: - ttm_bo_mem_put(bo, &tmp_mem); + ttm_resource_free(bo, &tmp_mem); return r; } @@ -638,10 +590,10 @@ out_cleanup: */ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { - struct ttm_mem_reg *old_mem = &bo->mem; - struct ttm_mem_reg tmp_mem; + struct ttm_resource *old_mem = &bo->mem; + struct ttm_resource tmp_mem; struct ttm_placement placement; struct ttm_place placements; int r; @@ -674,7 +626,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict, goto out_cleanup; } out_cleanup: - ttm_bo_mem_put(bo, &tmp_mem); + ttm_resource_free(bo, &tmp_mem); return r; } @@ -684,7 +636,7 @@ out_cleanup: * Called by amdgpu_bo_move() */ static bool amdgpu_mem_visible(struct amdgpu_device *adev, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { struct drm_mm_node *nodes = mem->mm_node; @@ -694,7 +646,7 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev, if (mem->mem_type != TTM_PL_VRAM) return false; - /* ttm_mem_reg_ioremap only supports contiguous memory */ + /* ttm_resource_ioremap only supports contiguous memory */ if (nodes->size != mem->num_pages) return false; @@ -709,11 +661,11 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev, */ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct amdgpu_device *adev; struct amdgpu_bo *abo; - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; int r; /* Can't move a pinned BO */ @@ -795,19 +747,12 @@ memcpy: * * Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault() */ -static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) +static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem) { - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); struct drm_mm_node *mm_node = mem->mm_node; + size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; - mem->bus.addr = NULL; - mem->bus.offset = 0; - mem->bus.size = mem->num_pages << PAGE_SHIFT; - mem->bus.base = 0; - mem->bus.is_iomem = false; - if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) - return -EINVAL; switch (mem->mem_type) { case TTM_PL_SYSTEM: /* system memory */ @@ -817,11 +762,11 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; /* check if it's visible */ - if ((mem->bus.offset + mem->bus.size) > adev->gmc.visible_vram_size) + if ((mem->bus.offset + bus_size) > adev->gmc.visible_vram_size) return -EINVAL; /* Only physically contiguous buffers apply. In a contiguous * buffer, size of the first mm_node would match the number of - * pages in ttm_mem_reg. + * pages in ttm_resource. */ if (adev->mman.aper_base_kaddr && (mm_node->size == mem->num_pages)) @@ -1166,7 +1111,7 @@ gart_bind_fail: * This handles binding GTT memory to the device address space. */ static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm, - struct ttm_mem_reg *bo_mem) + struct ttm_resource *bo_mem) { struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev); struct amdgpu_ttm_tt *gtt = (void*)ttm; @@ -1217,7 +1162,7 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct ttm_operation_ctx ctx = { false, false }; struct amdgpu_ttm_tt *gtt = (void*)bo->ttm; - struct ttm_mem_reg tmp; + struct ttm_resource tmp; struct ttm_placement placement; struct ttm_place placements; uint64_t addr, flags; @@ -1254,11 +1199,11 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) gtt->offset = (u64)tmp.start << PAGE_SHIFT; r = amdgpu_ttm_gart_bind(adev, bo, flags); if (unlikely(r)) { - ttm_bo_mem_put(bo, &tmp); + ttm_resource_free(bo, &tmp); return r; } - ttm_bo_mem_put(bo, &bo->mem); + ttm_resource_free(bo, &bo->mem); bo->mem = tmp; } @@ -1457,21 +1402,26 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm) * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current * task * - * @ttm: The ttm_tt object to bind this userptr object to + * @bo: The ttm_buffer_object to bind this userptr to * @addr: The address in the current tasks VM space to use * @flags: Requirements of userptr object. * * Called by amdgpu_gem_userptr_ioctl() to bind userptr pages * to current task */ -int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, - uint32_t flags) +int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, + uint64_t addr, uint32_t flags) { - struct amdgpu_ttm_tt *gtt = (void *)ttm; + struct amdgpu_ttm_tt *gtt; - if (gtt == NULL) - return -EINVAL; + if (!bo->ttm) { + /* TODO: We want a separate TTM object type for userptrs */ + bo->ttm = amdgpu_ttm_tt_create(bo, 0); + if (bo->ttm == NULL) + return -ENOMEM; + } + gtt = (void*)bo->ttm; gtt->userptr = addr; gtt->userflags = flags; @@ -1557,7 +1507,7 @@ bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm) * * Figure out the flags to use for a VM PDE (Page Directory Entry). */ -uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem) +uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem) { uint64_t flags = 0; @@ -1583,7 +1533,7 @@ uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem) * Figure out the flags to use for a VM PTE (Page Table Entry). */ uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { uint64_t flags = amdgpu_ttm_tt_pde_flags(ttm, mem); @@ -1741,7 +1691,6 @@ static struct ttm_bo_driver amdgpu_bo_driver = { .ttm_tt_create = &amdgpu_ttm_tt_create, .ttm_tt_populate = &amdgpu_ttm_tt_populate, .ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate, - .init_mem_type = &amdgpu_init_mem_type, .eviction_valuable = amdgpu_ttm_bo_eviction_valuable, .evict_flags = &amdgpu_evict_flags, .move = &amdgpu_bo_move, @@ -1767,8 +1716,8 @@ static struct ttm_bo_driver amdgpu_bo_driver = { */ static void amdgpu_ttm_fw_reserve_vram_fini(struct amdgpu_device *adev) { - amdgpu_bo_free_kernel(&adev->fw_vram_usage.reserved_bo, - NULL, &adev->fw_vram_usage.va); + amdgpu_bo_free_kernel(&adev->mman.fw_vram_usage_reserved_bo, + NULL, &adev->mman.fw_vram_usage_va); } /** @@ -1782,19 +1731,19 @@ static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev) { uint64_t vram_size = adev->gmc.visible_vram_size; - adev->fw_vram_usage.va = NULL; - adev->fw_vram_usage.reserved_bo = NULL; + adev->mman.fw_vram_usage_va = NULL; + adev->mman.fw_vram_usage_reserved_bo = NULL; - if (adev->fw_vram_usage.size == 0 || - adev->fw_vram_usage.size > vram_size) + if (adev->mman.fw_vram_usage_size == 0 || + adev->mman.fw_vram_usage_size > vram_size) return 0; return amdgpu_bo_create_kernel_at(adev, - adev->fw_vram_usage.start_offset, - adev->fw_vram_usage.size, + adev->mman.fw_vram_usage_start_offset, + adev->mman.fw_vram_usage_size, AMDGPU_GEM_DOMAIN_VRAM, - &adev->fw_vram_usage.reserved_bo, - &adev->fw_vram_usage.va); + &adev->mman.fw_vram_usage_reserved_bo, + &adev->mman.fw_vram_usage_va); } /* @@ -1826,7 +1775,7 @@ static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev) memset(ctx, 0, sizeof(*ctx)); ctx->c2p_train_data_offset = - ALIGN((adev->gmc.mc_vram_size - adev->discovery_tmr_size - SZ_1M), SZ_1M); + ALIGN((adev->gmc.mc_vram_size - adev->mman.discovery_tmr_size - SZ_1M), SZ_1M); ctx->p2c_train_data_offset = (adev->gmc.mc_vram_size - GDDR6_MEM_TRAINING_OFFSET); ctx->train_data_size = @@ -1865,10 +1814,10 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) * Otherwise, fallback to legacy approach to check and reserve tmr block for ip * discovery data and G6 memory training data respectively */ - adev->discovery_tmr_size = + adev->mman.discovery_tmr_size = amdgpu_atomfirmware_get_fw_reserved_fb_size(adev); - if (!adev->discovery_tmr_size) - adev->discovery_tmr_size = DISCOVERY_TMR_OFFSET; + if (!adev->mman.discovery_tmr_size) + adev->mman.discovery_tmr_size = DISCOVERY_TMR_OFFSET; if (mem_train_support) { /* reserve vram for mem train according to TMR location */ @@ -1888,14 +1837,14 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) } ret = amdgpu_bo_create_kernel_at(adev, - adev->gmc.real_vram_size - adev->discovery_tmr_size, - adev->discovery_tmr_size, + adev->gmc.real_vram_size - adev->mman.discovery_tmr_size, + adev->mman.discovery_tmr_size, AMDGPU_GEM_DOMAIN_VRAM, - &adev->discovery_memory, + &adev->mman.discovery_memory, NULL); if (ret) { DRM_ERROR("alloc tmr failed(%d)!\n", ret); - amdgpu_bo_free_kernel(&adev->discovery_memory, NULL, NULL); + amdgpu_bo_free_kernel(&adev->mman.discovery_memory, NULL, NULL); return ret; } @@ -1916,15 +1865,14 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) uint64_t gtt_size; int r; u64 vis_vram_limit; - void *stolen_vga_buf; mutex_init(&adev->mman.gtt_window_lock); /* No others user of address space so set it to 0 */ r = ttm_bo_device_init(&adev->mman.bdev, &amdgpu_bo_driver, - adev->ddev->anon_inode->i_mapping, - adev->ddev->vma_offset_manager, + adev_to_drm(adev)->anon_inode->i_mapping, + adev_to_drm(adev)->vma_offset_manager, dma_addressing_limited(adev->dev)); if (r) { DRM_ERROR("failed initializing buffer object driver(%d).\n", r); @@ -1936,8 +1884,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) adev->mman.bdev.no_retry = true; /* Initialize VRAM pool with all of VRAM divided into pages */ - r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM, - adev->gmc.real_vram_size >> PAGE_SHIFT); + r = amdgpu_vram_mgr_init(adev); if (r) { DRM_ERROR("Failed initializing VRAM heap.\n"); return r; @@ -1970,7 +1917,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) * If IP discovery enabled, a block of memory should be * reserved for IP discovey. */ - if (adev->discovery_bin) { + if (adev->mman.discovery_bin) { r = amdgpu_ttm_reserve_tmr(adev); if (r) return r; @@ -1980,10 +1927,17 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) * This is used for VGA emulation and pre-OS scanout buffers to * avoid display artifacts while transitioning between pre-OS * and driver. */ - r = amdgpu_bo_create_kernel(adev, adev->gmc.stolen_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, - &adev->stolen_vga_memory, - NULL, &stolen_vga_buf); + r = amdgpu_bo_create_kernel_at(adev, 0, adev->mman.stolen_vga_size, + AMDGPU_GEM_DOMAIN_VRAM, + &adev->mman.stolen_vga_memory, + NULL); + if (r) + return r; + r = amdgpu_bo_create_kernel_at(adev, adev->mman.stolen_vga_size, + adev->mman.stolen_extended_size, + AMDGPU_GEM_DOMAIN_VRAM, + &adev->mman.stolen_extended_memory, + NULL); if (r) return r; @@ -2004,7 +1958,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) gtt_size = (uint64_t)amdgpu_gtt_size << 20; /* Initialize GTT memory pool */ - r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_TT, gtt_size >> PAGE_SHIFT); + r = amdgpu_gtt_mgr_init(adev, gtt_size); if (r) { DRM_ERROR("Failed initializing GTT heap.\n"); return r; @@ -2013,22 +1967,19 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) (unsigned)(gtt_size / (1024 * 1024))); /* Initialize various on-chip memory pools */ - r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GDS, - adev->gds.gds_size); + r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size); if (r) { DRM_ERROR("Failed initializing GDS heap.\n"); return r; } - r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GWS, - adev->gds.gws_size); + r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size); if (r) { DRM_ERROR("Failed initializing gws heap.\n"); return r; } - r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_OA, - adev->gds.oa_size); + r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size); if (r) { DRM_ERROR("Failed initializing oa heap.\n"); return r; @@ -2042,9 +1993,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) */ void amdgpu_ttm_late_init(struct amdgpu_device *adev) { - void *stolen_vga_buf; /* return the VGA stolen memory (if any) back to VRAM */ - amdgpu_bo_free_kernel(&adev->stolen_vga_memory, NULL, &stolen_vga_buf); + if (!adev->mman.keep_stolen_vga_memory) + amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL); + amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL); } /** @@ -2056,19 +2008,22 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) return; amdgpu_ttm_training_reserve_vram_fini(adev); + /* return the stolen vga memory back to VRAM */ + if (adev->mman.keep_stolen_vga_memory) + amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL); /* return the IP Discovery TMR memory back to VRAM */ - amdgpu_bo_free_kernel(&adev->discovery_memory, NULL, NULL); + amdgpu_bo_free_kernel(&adev->mman.discovery_memory, NULL, NULL); amdgpu_ttm_fw_reserve_vram_fini(adev); if (adev->mman.aper_base_kaddr) iounmap(adev->mman.aper_base_kaddr); adev->mman.aper_base_kaddr = NULL; - ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_VRAM); - ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_TT); - ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GDS); - ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS); - ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA); + amdgpu_vram_mgr_fini(adev); + amdgpu_gtt_mgr_fini(adev); + ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS); + ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS); + ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA); ttm_bo_device_release(&adev->mman.bdev); adev->mman.initialized = false; DRM_INFO("amdgpu: ttm finalized\n"); @@ -2085,11 +2040,11 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) */ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) { - struct ttm_mem_type_manager *man = &adev->mman.bdev.man[TTM_PL_VRAM]; + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); uint64_t size; int r; - if (!adev->mman.initialized || adev->in_gpu_reset || + if (!adev->mman.initialized || amdgpu_in_reset(adev) || adev->mman.buffer_funcs_enabled == enable) return; @@ -2100,7 +2055,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) ring = adev->mman.buffer_funcs_ring; sched = &ring->sched; r = drm_sched_entity_init(&adev->mman.entity, - DRM_SCHED_PRIORITY_KERNEL, &sched, + DRM_SCHED_PRIORITY_KERNEL, &sched, 1, NULL); if (r) { DRM_ERROR("Failed setting up TTM BO move entity (%d)\n", @@ -2125,7 +2080,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *file_priv = filp->private_data; - struct amdgpu_device *adev = file_priv->minor->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(file_priv->minor->dev); if (adev == NULL) return -EINVAL; @@ -2306,8 +2261,8 @@ static int amdgpu_mm_dump_table(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *)m->private; unsigned ttm_pl = (uintptr_t)node->info_ent->data; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; - struct ttm_mem_type_manager *man = &adev->mman.bdev.man[ttm_pl]; + struct amdgpu_device *adev = drm_to_adev(dev); + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, ttm_pl); struct drm_printer p = drm_seq_file_printer(m); man->func->debug(man, &p); @@ -2597,7 +2552,7 @@ int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev) #if defined(CONFIG_DEBUG_FS) unsigned count; - struct drm_minor *minor = adev->ddev->primary; + struct drm_minor *minor = adev_to_drm(adev)->primary; struct dentry *ent, *root = minor->debugfs_root; for (count = 0; count < ARRAY_SIZE(ttm_debugfs_entries); count++) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 17c8d0d7bcc3..68c5e3662b87 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -41,6 +41,21 @@ #define AMDGPU_POISON 0xd0bed0be +struct amdgpu_vram_mgr { + struct ttm_resource_manager manager; + struct drm_mm mm; + spinlock_t lock; + atomic64_t usage; + atomic64_t vis_usage; +}; + +struct amdgpu_gtt_mgr { + struct ttm_resource_manager manager; + struct drm_mm mm; + spinlock_t lock; + atomic64_t available; +}; + struct amdgpu_mman { struct ttm_bo_device bdev; bool mem_global_referenced; @@ -59,24 +74,46 @@ struct amdgpu_mman { struct mutex gtt_window_lock; /* Scheduler entity for buffer moves */ struct drm_sched_entity entity; + + struct amdgpu_vram_mgr vram_mgr; + struct amdgpu_gtt_mgr gtt_mgr; + + uint64_t stolen_vga_size; + struct amdgpu_bo *stolen_vga_memory; + uint64_t stolen_extended_size; + struct amdgpu_bo *stolen_extended_memory; + bool keep_stolen_vga_memory; + + /* discovery */ + uint8_t *discovery_bin; + uint32_t discovery_tmr_size; + struct amdgpu_bo *discovery_memory; + + /* firmware VRAM reservation */ + u64 fw_vram_usage_start_offset; + u64 fw_vram_usage_size; + struct amdgpu_bo *fw_vram_usage_reserved_bo; + void *fw_vram_usage_va; }; struct amdgpu_copy_mem { struct ttm_buffer_object *bo; - struct ttm_mem_reg *mem; + struct ttm_resource *mem; unsigned long offset; }; -extern const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func; -extern const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func; +int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size); +void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev); +int amdgpu_vram_mgr_init(struct amdgpu_device *adev); +void amdgpu_vram_mgr_fini(struct amdgpu_device *adev); -bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem); -uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man); -int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man); +bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem); +uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man); +int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man); u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo); int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, struct device *dev, enum dma_data_direction dir, struct sg_table **sgt); @@ -84,8 +121,8 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev, struct device *dev, enum dma_data_direction dir, struct sg_table *sgt); -uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man); -uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man); +uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man); +uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man); int amdgpu_ttm_init(struct amdgpu_device *adev); void amdgpu_ttm_late_init(struct amdgpu_device *adev); @@ -130,8 +167,8 @@ static inline bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm) #endif void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages); -int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, - uint32_t flags); +int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, + uint64_t addr, uint32_t flags); bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm); struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm); bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, @@ -140,9 +177,9 @@ bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm, int *last_invalidated); bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm); bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm); -uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem); +uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem); uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 183743c5fb7b..55fe19a2f332 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -408,7 +408,7 @@ static ssize_t show_##name(struct device *dev, \ char *buf) \ { \ struct drm_device *ddev = dev_get_drvdata(dev); \ - struct amdgpu_device *adev = ddev->dev_private; \ + struct amdgpu_device *adev = drm_to_adev(ddev); \ \ return snprintf(buf, PAGE_SIZE, "0x%08x\n", adev->field); \ } \ @@ -628,7 +628,7 @@ int amdgpu_ucode_init_bo(struct amdgpu_device *adev) struct amdgpu_firmware_info *ucode = NULL; /* for baremetal, the ucode is allocated in gtt, so don't need to fill the bo when reset/suspend */ - if (!amdgpu_sriov_vf(adev) && (adev->in_gpu_reset || adev->in_suspend)) + if (!amdgpu_sriov_vf(adev) && (amdgpu_in_reset(adev) || adev->in_suspend)) return 0; /* * if SMU loaded firmware, it needn't add SMC, UVD, and VCE diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 12a8bc8fca0b..3c23c6293ff9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -131,6 +131,7 @@ enum ta_fw_type { TA_FW_TYPE_PSP_RAS, TA_FW_TYPE_PSP_HDCP, TA_FW_TYPE_PSP_DTM, + TA_FW_TYPE_PSP_RAP, }; struct ta_fw_bin_desc { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index af1b1ccf613c..262baf0f61ea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -125,8 +125,9 @@ int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev, "detected in UMC block\n", err_data->ue_count); - if (err_data->err_addr_cnt && - amdgpu_ras_add_bad_pages(adev, err_data->err_addr, + 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)) dev_warn(adev->dev, "Failed to add ras bad page!\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index a615a1eb750b..183814493658 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -21,6 +21,20 @@ #ifndef __AMDGPU_UMC_H__ #define __AMDGPU_UMC_H__ +/* + * (addr / 256) * 8192, the higher 26 bits in ErrorAddr + * is the index of 8KB block + */ +#define ADDR_OF_8KB_BLOCK(addr) (((addr) & ~0xffULL) << 5) +/* channel index is the index of 256B block */ +#define ADDR_OF_256B_BLOCK(channel_index) ((channel_index) << 8) +/* offset in 256B block */ +#define OFFSET_IN_256B_BLOCK(addr) ((addr) & 0xffULL) + +#define LOOP_UMC_INST(umc_inst) for ((umc_inst) = 0; (umc_inst) < adev->umc.umc_inst_num; (umc_inst)++) +#define LOOP_UMC_CH_INST(ch_inst) for ((ch_inst) = 0; (ch_inst) < adev->umc.channel_inst_num; (ch_inst)++) +#define LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) LOOP_UMC_INST((umc_inst)) LOOP_UMC_CH_INST((ch_inst)) + struct amdgpu_umc_funcs { void (*err_cnt_init)(struct amdgpu_device *adev); int (*ras_late_init)(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 1203c20491e6..f76961d17246 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -45,7 +45,7 @@ void amdgpu_virt_init_setting(struct amdgpu_device *adev) if (adev->mode_info.num_crtc == 0) adev->mode_info.num_crtc = 1; adev->enable_virtual_display = true; - adev->ddev->driver->driver_features &= ~DRIVER_ATOMIC; + adev_to_drm(adev)->driver->driver_features &= ~DRIVER_ATOMIC; adev->cg_flags = 0; adev->pg_flags = 0; } @@ -93,7 +93,7 @@ failed_undo: amdgpu_ring_undo(ring); spin_unlock_irqrestore(&kiq->ring_lock, flags); failed_kiq: - pr_err("failed to write reg %x wait reg %x\n", reg0, reg1); + dev_err(adev->dev, "failed to write reg %x wait reg %x\n", reg0, reg1); } /** @@ -401,7 +401,7 @@ static void amdgpu_virt_add_bad_page(struct amdgpu_device *adev, if (bp_block_size) { bp_cnt = bp_block_size / sizeof(uint64_t); for (bp_idx = 0; bp_idx < bp_cnt; bp_idx++) { - retired_page = *(uint64_t *)(adev->fw_vram_usage.va + + retired_page = *(uint64_t *)(adev->mman.fw_vram_usage_va + bp_block_offset + bp_idx * sizeof(uint64_t)); bp.retired_page = retired_page; @@ -428,10 +428,10 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) adev->virt.fw_reserve.p_pf2vf = NULL; adev->virt.fw_reserve.p_vf2pf = NULL; - if (adev->fw_vram_usage.va != NULL) { + if (adev->mman.fw_vram_usage_va != NULL) { adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *)( - adev->fw_vram_usage.va + AMDGIM_DATAEXCHANGE_OFFSET); + adev->mman.fw_vram_usage_va + AMDGIM_DATAEXCHANGE_OFFSET); AMDGPU_FW_VRAM_PF2VF_READ(adev, header.size, &pf2vf_size); AMDGPU_FW_VRAM_PF2VF_READ(adev, checksum, &checksum); AMDGPU_FW_VRAM_PF2VF_READ(adev, feature_flags, &adev->virt.gim_feature); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index f826945989c7..b2046c3a404d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -325,9 +325,9 @@ static inline bool is_virtual_machine(void) #define amdgpu_sriov_is_pp_one_vf(adev) \ ((adev)->virt.gim_feature & AMDGIM_FEATURE_PP_ONE_VF) #define amdgpu_sriov_is_debug(adev) \ - ((!adev->in_gpu_reset) && adev->virt.tdr_debug) + ((!amdgpu_in_reset(adev)) && adev->virt.tdr_debug) #define amdgpu_sriov_is_normal(adev) \ - ((!adev->in_gpu_reset) && (!adev->virt.tdr_debug)) + ((!amdgpu_in_reset(adev)) && (!adev->virt.tdr_debug)) bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev); void amdgpu_virt_init_setting(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 71e005cf2952..420931d36732 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -28,6 +28,7 @@ #include <linux/dma-fence-array.h> #include <linux/interval_tree_generic.h> #include <linux/idr.h> +#include <linux/dma-buf.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" @@ -35,6 +36,7 @@ #include "amdgpu_amdkfd.h" #include "amdgpu_gmc.h" #include "amdgpu_xgmi.h" +#include "amdgpu_dma_buf.h" /** * DOC: GPUVM @@ -1691,13 +1693,13 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, uint64_t max_entries; uint64_t addr, last; + max_entries = mapping->last - start + 1; if (nodes) { addr = nodes->start << PAGE_SHIFT; - max_entries = (nodes->size - pfn) * - AMDGPU_GPU_PAGES_IN_CPU_PAGE; + max_entries = min((nodes->size - pfn) * + AMDGPU_GPU_PAGES_IN_CPU_PAGE, max_entries); } else { addr = 0; - max_entries = S64_MAX; } if (pages_addr) { @@ -1727,7 +1729,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, addr += pfn << PAGE_SHIFT; } - last = min((uint64_t)mapping->last, start + max_entries - 1); + last = start + max_entries - 1; r = amdgpu_vm_bo_update_mapping(adev, vm, false, false, resv, start, last, flags, addr, dma_addr, fence); @@ -1765,7 +1767,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, struct amdgpu_vm *vm = bo_va->base.vm; struct amdgpu_bo_va_mapping *mapping; dma_addr_t *pages_addr = NULL; - struct ttm_mem_reg *mem; + struct ttm_resource *mem; struct drm_mm_node *nodes; struct dma_fence **last_update; struct dma_resv *resv; @@ -1778,15 +1780,24 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, nodes = NULL; resv = vm->root.base.bo->tbo.base.resv; } else { + struct drm_gem_object *obj = &bo->tbo.base; struct ttm_dma_tt *ttm; + resv = bo->tbo.base.resv; + if (obj->import_attach && bo_va->is_xgmi) { + struct dma_buf *dma_buf = obj->import_attach->dmabuf; + struct drm_gem_object *gobj = dma_buf->priv; + struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj); + + if (abo->tbo.mem.mem_type == TTM_PL_VRAM) + bo = gem_to_amdgpu_bo(gobj); + } mem = &bo->tbo.mem; nodes = mem->mm_node; if (mem->mem_type == TTM_PL_TT) { ttm = container_of(bo->tbo.ttm, struct ttm_dma_tt, ttm); pages_addr = ttm->dma_address; } - resv = bo->tbo.base.resv; } if (bo) { @@ -2132,8 +2143,10 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev, INIT_LIST_HEAD(&bo_va->valids); INIT_LIST_HEAD(&bo_va->invalids); - if (bo && amdgpu_xgmi_same_hive(adev, amdgpu_ttm_adev(bo->tbo.bdev)) && - (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM)) { + if (!bo) + return bo_va; + + if (amdgpu_dmabuf_is_xgmi_accessible(adev, bo)) { bo_va->is_xgmi = true; /* Power up XGMI if it can be potentially used */ amdgpu_xgmi_set_pstate(adev, AMDGPU_XGMI_PSTATE_MAX_VEGA20); @@ -3209,7 +3222,7 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev) int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { union drm_amdgpu_vm *args = data; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv = filp->driver_priv; long timeout = msecs_to_jiffies(2000); int r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 0739e259bf91..b2adc2abc581 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -28,12 +28,15 @@ #include "amdgpu_atomfirmware.h" #include "atom.h" -struct amdgpu_vram_mgr { - struct drm_mm mm; - spinlock_t lock; - atomic64_t usage; - atomic64_t vis_usage; -}; +static inline struct amdgpu_vram_mgr *to_vram_mgr(struct ttm_resource_manager *man) +{ + return container_of(man, struct amdgpu_vram_mgr, manager); +} + +static inline struct amdgpu_device *to_amdgpu_device(struct amdgpu_vram_mgr *mgr) +{ + return container_of(mgr, struct amdgpu_device, mman.vram_mgr); +} /** * DOC: mem_info_vram_total @@ -47,7 +50,7 @@ static ssize_t amdgpu_mem_info_vram_total_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.real_vram_size); } @@ -64,7 +67,7 @@ static ssize_t amdgpu_mem_info_vis_vram_total_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.visible_vram_size); } @@ -81,10 +84,11 @@ static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); return snprintf(buf, PAGE_SIZE, "%llu\n", - amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM])); + amdgpu_vram_mgr_usage(man)); } /** @@ -99,10 +103,11 @@ static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); return snprintf(buf, PAGE_SIZE, "%llu\n", - amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM])); + amdgpu_vram_mgr_vis_usage(man)); } static ssize_t amdgpu_mem_info_vram_vendor(struct device *dev, @@ -110,7 +115,7 @@ static ssize_t amdgpu_mem_info_vram_vendor(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); switch (adev->gmc.vram_vendor) { case SAMSUNG: @@ -158,6 +163,8 @@ static const struct attribute *amdgpu_vram_mgr_attributes[] = { NULL }; +static const struct ttm_resource_manager_func amdgpu_vram_mgr_func; + /** * amdgpu_vram_mgr_init - init VRAM manager and DRM MM * @@ -166,26 +173,29 @@ static const struct attribute *amdgpu_vram_mgr_attributes[] = { * * Allocate and initialize the VRAM manager. */ -static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man, - unsigned long p_size) +int amdgpu_vram_mgr_init(struct amdgpu_device *adev) { - struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); - struct amdgpu_vram_mgr *mgr; + struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; + struct ttm_resource_manager *man = &mgr->manager; int ret; - mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); - if (!mgr) - return -ENOMEM; + man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + + ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT); - drm_mm_init(&mgr->mm, 0, p_size); + man->func = &amdgpu_vram_mgr_func; + + drm_mm_init(&mgr->mm, 0, man->size); spin_lock_init(&mgr->lock); - man->priv = mgr; /* Add the two VRAM-related sysfs files */ ret = sysfs_create_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes); if (ret) DRM_ERROR("Failed to register sysfs\n"); + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager); + ttm_resource_manager_set_used(man, true); return 0; } @@ -197,18 +207,26 @@ static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man, * Destroy and free the VRAM manager, returns -EBUSY if ranges are still * allocated inside it. */ -static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man) +void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) { - struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); - struct amdgpu_vram_mgr *mgr = man->priv; + struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; + struct ttm_resource_manager *man = &mgr->manager; + int ret; + + ttm_resource_manager_set_used(man, false); + + ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man); + if (ret) + return; spin_lock(&mgr->lock); drm_mm_takedown(&mgr->mm); spin_unlock(&mgr->lock); - kfree(mgr); - man->priv = NULL; + sysfs_remove_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes); - return 0; + + ttm_resource_manager_cleanup(man); + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL); } /** @@ -243,7 +261,7 @@ static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev, u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); - struct ttm_mem_reg *mem = &bo->tbo.mem; + struct ttm_resource *mem = &bo->tbo.mem; struct drm_mm_node *nodes = mem->mm_node; unsigned pages = mem->num_pages; u64 usage; @@ -263,13 +281,13 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) /** * amdgpu_vram_mgr_virt_start - update virtual start address * - * @mem: ttm_mem_reg to update + * @mem: ttm_resource to update * @node: just allocated node * * Calculate a virtual BO start address to easily check if everything is CPU * accessible. */ -static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem, +static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem, struct drm_mm_node *node) { unsigned long start; @@ -292,13 +310,13 @@ static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem, * * Allocate VRAM for the given BO. */ -static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man, +static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, struct ttm_buffer_object *tbo, const struct ttm_place *place, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { - struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); - struct amdgpu_vram_mgr *mgr = man->priv; + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); + struct amdgpu_device *adev = to_amdgpu_device(mgr); struct drm_mm *mm = &mgr->mm; struct drm_mm_node *nodes; enum drm_mm_insert_mode mode; @@ -410,11 +428,11 @@ error: * * Free the allocated VRAM again. */ -static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, - struct ttm_mem_reg *mem) +static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, + struct ttm_resource *mem) { - struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); - struct amdgpu_vram_mgr *mgr = man->priv; + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); + struct amdgpu_device *adev = to_amdgpu_device(mgr); struct drm_mm_node *nodes = mem->mm_node; uint64_t usage = 0, vis_usage = 0; unsigned pages = mem->num_pages; @@ -451,7 +469,7 @@ static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, * Allocate and fill a sg table from a VRAM allocation. */ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, struct device *dev, enum dma_data_direction dir, struct sg_table **sgt) @@ -544,9 +562,9 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev, * * Returns how many bytes are used in this domain. */ -uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man) +uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man) { - struct amdgpu_vram_mgr *mgr = man->priv; + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); return atomic64_read(&mgr->usage); } @@ -558,9 +576,9 @@ uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man) * * Returns how many bytes are used in the visible part of VRAM */ -uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man) +uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man) { - struct amdgpu_vram_mgr *mgr = man->priv; + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); return atomic64_read(&mgr->vis_usage); } @@ -573,10 +591,10 @@ uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man) * * Dump the table content using printk. */ -static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man, +static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man, struct drm_printer *printer) { - struct amdgpu_vram_mgr *mgr = man->priv; + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); spin_lock(&mgr->lock); drm_mm_print(&mgr->mm, printer); @@ -587,10 +605,8 @@ static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man, amdgpu_vram_mgr_vis_usage(man) >> 20); } -const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = { - .init = amdgpu_vram_mgr_init, - .takedown = amdgpu_vram_mgr_fini, - .get_node = amdgpu_vram_mgr_new, - .put_node = amdgpu_vram_mgr_del, - .debug = amdgpu_vram_mgr_debug +static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = { + .alloc = amdgpu_vram_mgr_new, + .free = amdgpu_vram_mgr_del, + .debug = amdgpu_vram_mgr_debug }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index e3a3755cb999..1162913c8bf4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -35,11 +35,9 @@ static DEFINE_MUTEX(xgmi_mutex); -#define AMDGPU_MAX_XGMI_HIVE 8 #define AMDGPU_MAX_XGMI_DEVICE_PER_HIVE 4 -static struct amdgpu_hive_info xgmi_hives[AMDGPU_MAX_XGMI_HIVE]; -static unsigned hive_count = 0; +static LIST_HEAD(xgmi_hive_list); static const int xgmi_pcs_err_status_reg_vg20[] = { smnXGMI0_PCS_GOPX16_PCS_ERROR_STATUS, @@ -171,65 +169,53 @@ static const struct amdgpu_pcs_ras_field wafl_pcs_ras_fields[] = { * */ +static struct attribute amdgpu_xgmi_hive_id = { + .name = "xgmi_hive_id", + .mode = S_IRUGO +}; -static ssize_t amdgpu_xgmi_show_hive_id(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct amdgpu_hive_info *hive = - container_of(attr, struct amdgpu_hive_info, dev_attr); - - return snprintf(buf, PAGE_SIZE, "%llu\n", hive->hive_id); -} +static struct attribute *amdgpu_xgmi_hive_attrs[] = { + &amdgpu_xgmi_hive_id, + NULL +}; -static int amdgpu_xgmi_sysfs_create(struct amdgpu_device *adev, - struct amdgpu_hive_info *hive) +static ssize_t amdgpu_xgmi_show_attrs(struct kobject *kobj, + struct attribute *attr, char *buf) { - int ret = 0; + struct amdgpu_hive_info *hive = container_of( + kobj, struct amdgpu_hive_info, kobj); - if (WARN_ON(hive->kobj)) - return -EINVAL; - - hive->kobj = kobject_create_and_add("xgmi_hive_info", &adev->dev->kobj); - if (!hive->kobj) { - dev_err(adev->dev, "XGMI: Failed to allocate sysfs entry!\n"); - return -EINVAL; - } - - hive->dev_attr = (struct device_attribute) { - .attr = { - .name = "xgmi_hive_id", - .mode = S_IRUGO, - - }, - .show = amdgpu_xgmi_show_hive_id, - }; + if (attr == &amdgpu_xgmi_hive_id) + return snprintf(buf, PAGE_SIZE, "%llu\n", hive->hive_id); - ret = sysfs_create_file(hive->kobj, &hive->dev_attr.attr); - if (ret) { - dev_err(adev->dev, "XGMI: Failed to create device file xgmi_hive_id\n"); - kobject_del(hive->kobj); - kobject_put(hive->kobj); - hive->kobj = NULL; - } - - return ret; + return 0; } -static void amdgpu_xgmi_sysfs_destroy(struct amdgpu_device *adev, - struct amdgpu_hive_info *hive) +static void amdgpu_xgmi_hive_release(struct kobject *kobj) { - sysfs_remove_file(hive->kobj, &hive->dev_attr.attr); - kobject_del(hive->kobj); - kobject_put(hive->kobj); - hive->kobj = NULL; + struct amdgpu_hive_info *hive = container_of( + kobj, struct amdgpu_hive_info, kobj); + + mutex_destroy(&hive->hive_lock); + kfree(hive); } +static const struct sysfs_ops amdgpu_xgmi_hive_ops = { + .show = amdgpu_xgmi_show_attrs, +}; + +struct kobj_type amdgpu_xgmi_hive_type = { + .release = amdgpu_xgmi_hive_release, + .sysfs_ops = &amdgpu_xgmi_hive_ops, + .default_attrs = amdgpu_xgmi_hive_attrs, +}; + static ssize_t amdgpu_xgmi_show_device_id(struct device *dev, struct device_attribute *attr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.xgmi.node_id); @@ -241,7 +227,7 @@ static ssize_t amdgpu_xgmi_show_error(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint32_t ficaa_pie_ctl_in, ficaa_pie_status_in; uint64_t fica_out; unsigned int error_count = 0; @@ -287,8 +273,8 @@ static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev, /* Create sysfs link to hive info folder on the first device */ - if (adev != hive->adev) { - ret = sysfs_create_link(&adev->dev->kobj, hive->kobj, + if (hive->kobj.parent != (&adev->dev->kobj)) { + ret = sysfs_create_link(&adev->dev->kobj, &hive->kobj, "xgmi_hive_info"); if (ret) { dev_err(adev->dev, "XGMI: Failed to create link to hive info"); @@ -296,9 +282,9 @@ static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev, } } - sprintf(node, "node%d", hive->number_devices); + sprintf(node, "node%d", atomic_read(&hive->number_devices)); /* Create sysfs link form the hive folder to yourself */ - ret = sysfs_create_link(hive->kobj, &adev->dev->kobj, node); + ret = sysfs_create_link(&hive->kobj, &adev->dev->kobj, node); if (ret) { dev_err(adev->dev, "XGMI: Failed to create link from hive info"); goto remove_link; @@ -308,7 +294,7 @@ static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev, remove_link: - sysfs_remove_link(&adev->dev->kobj, adev->ddev->unique); + sysfs_remove_link(&adev->dev->kobj, adev_to_drm(adev)->unique); remove_file: device_remove_file(adev->dev, &dev_attr_xgmi_device_id); @@ -326,78 +312,96 @@ static void amdgpu_xgmi_sysfs_rem_dev_info(struct amdgpu_device *adev, device_remove_file(adev->dev, &dev_attr_xgmi_device_id); device_remove_file(adev->dev, &dev_attr_xgmi_error); - if (adev != hive->adev) + if (hive->kobj.parent != (&adev->dev->kobj)) sysfs_remove_link(&adev->dev->kobj,"xgmi_hive_info"); - sprintf(node, "node%d", hive->number_devices); - sysfs_remove_link(hive->kobj, node); + sprintf(node, "node%d", atomic_read(&hive->number_devices)); + sysfs_remove_link(&hive->kobj, node); } -struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev, int lock) +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) { - int i; - struct amdgpu_hive_info *tmp; + struct amdgpu_hive_info *hive = NULL, *tmp = NULL; + int ret; if (!adev->gmc.xgmi.hive_id) return NULL; + if (adev->hive) { + kobject_get(&adev->hive->kobj); + return adev->hive; + } + mutex_lock(&xgmi_mutex); - for (i = 0 ; i < hive_count; ++i) { - tmp = &xgmi_hives[i]; - if (tmp->hive_id == adev->gmc.xgmi.hive_id) { - if (lock) - mutex_lock(&tmp->hive_lock); - mutex_unlock(&xgmi_mutex); - return tmp; + if (!list_empty(&xgmi_hive_list)) { + list_for_each_entry_safe(hive, tmp, &xgmi_hive_list, node) { + if (hive->hive_id == adev->gmc.xgmi.hive_id) + goto pro_end; } } - if (i >= AMDGPU_MAX_XGMI_HIVE) { - mutex_unlock(&xgmi_mutex); - return NULL; + + hive = kzalloc(sizeof(*hive), GFP_KERNEL); + if (!hive) { + dev_err(adev->dev, "XGMI: allocation failed\n"); + hive = NULL; + goto pro_end; } /* initialize new hive if not exist */ - tmp = &xgmi_hives[hive_count++]; - - if (amdgpu_xgmi_sysfs_create(adev, tmp)) { - mutex_unlock(&xgmi_mutex); - return NULL; + ret = kobject_init_and_add(&hive->kobj, + &amdgpu_xgmi_hive_type, + &adev->dev->kobj, + "%s", "xgmi_hive_info"); + if (ret) { + dev_err(adev->dev, "XGMI: failed initializing kobject for xgmi hive\n"); + kfree(hive); + hive = NULL; + goto pro_end; } - tmp->adev = adev; - tmp->hive_id = adev->gmc.xgmi.hive_id; - INIT_LIST_HEAD(&tmp->device_list); - mutex_init(&tmp->hive_lock); - mutex_init(&tmp->reset_lock); - task_barrier_init(&tmp->tb); - - if (lock) - mutex_lock(&tmp->hive_lock); - tmp->pstate = AMDGPU_XGMI_PSTATE_UNKNOWN; - tmp->hi_req_gpu = NULL; + hive->hive_id = adev->gmc.xgmi.hive_id; + INIT_LIST_HEAD(&hive->device_list); + INIT_LIST_HEAD(&hive->node); + mutex_init(&hive->hive_lock); + atomic_set(&hive->in_reset, 0); + atomic_set(&hive->number_devices, 0); + task_barrier_init(&hive->tb); + hive->pstate = AMDGPU_XGMI_PSTATE_UNKNOWN; + hive->hi_req_gpu = NULL; /* * hive pstate on boot is high in vega20 so we have to go to low * pstate on after boot. */ - tmp->hi_req_count = AMDGPU_MAX_XGMI_DEVICE_PER_HIVE; + hive->hi_req_count = AMDGPU_MAX_XGMI_DEVICE_PER_HIVE; + list_add_tail(&hive->node, &xgmi_hive_list); + +pro_end: + if (hive) + kobject_get(&hive->kobj); mutex_unlock(&xgmi_mutex); + return hive; +} - return tmp; +void amdgpu_put_xgmi_hive(struct amdgpu_hive_info *hive) +{ + if (hive) + kobject_put(&hive->kobj); } int amdgpu_xgmi_set_pstate(struct amdgpu_device *adev, int pstate) { int ret = 0; - struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev, 0); + struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev); struct amdgpu_device *request_adev = hive->hi_req_gpu ? hive->hi_req_gpu : adev; bool is_hi_req = pstate == AMDGPU_XGMI_PSTATE_MAX_VEGA20; bool init_low = hive->pstate == AMDGPU_XGMI_PSTATE_UNKNOWN; + amdgpu_put_xgmi_hive(hive); /* fw bug so temporarily disable pstate switching */ return 0; @@ -449,7 +453,7 @@ int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_dev /* Each psp need to set the latest topology */ ret = psp_xgmi_set_topology_info(&adev->psp, - hive->number_devices, + atomic_read(&hive->number_devices), &adev->psp.xgmi_context.top_info); if (ret) dev_err(adev->dev, @@ -511,7 +515,7 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) adev->gmc.xgmi.node_id = adev->gmc.xgmi.physical_node_id + 16; } - hive = amdgpu_get_xgmi_hive(adev, 1); + hive = amdgpu_get_xgmi_hive(adev); if (!hive) { ret = -EINVAL; dev_err(adev->dev, @@ -519,6 +523,7 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) adev->gmc.xgmi.node_id, adev->gmc.xgmi.hive_id); goto exit; } + mutex_lock(&hive->hive_lock); top_info = &adev->psp.xgmi_context.top_info; @@ -526,7 +531,7 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) list_for_each_entry(entry, &hive->device_list, head) top_info->nodes[count++].node_id = entry->node_id; top_info->num_nodes = count; - hive->number_devices = count; + atomic_set(&hive->number_devices, count); task_barrier_add_task(&hive->tb); @@ -541,7 +546,7 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) } ret = amdgpu_xgmi_update_topology(hive, tmp_adev); if (ret) - goto exit; + goto exit_unlock; } /* get latest topology info for each device from psp */ @@ -554,7 +559,7 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) tmp_adev->gmc.xgmi.node_id, tmp_adev->gmc.xgmi.hive_id, ret); /* To do : continue with some node failed or disable the whole hive */ - goto exit; + goto exit_unlock; } } } @@ -562,39 +567,51 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) if (!ret) ret = amdgpu_xgmi_sysfs_add_dev_info(adev, hive); - +exit_unlock: mutex_unlock(&hive->hive_lock); exit: - if (!ret) + if (!ret) { + adev->hive = hive; dev_info(adev->dev, "XGMI: Add node %d, hive 0x%llx.\n", adev->gmc.xgmi.physical_node_id, adev->gmc.xgmi.hive_id); - else + } else { + amdgpu_put_xgmi_hive(hive); dev_err(adev->dev, "XGMI: Failed to add node %d, hive 0x%llx ret: %d\n", adev->gmc.xgmi.physical_node_id, adev->gmc.xgmi.hive_id, ret); + } return ret; } int amdgpu_xgmi_remove_device(struct amdgpu_device *adev) { - struct amdgpu_hive_info *hive; + struct amdgpu_hive_info *hive = adev->hive; if (!adev->gmc.xgmi.supported) return -EINVAL; - hive = amdgpu_get_xgmi_hive(adev, 1); if (!hive) return -EINVAL; + mutex_lock(&hive->hive_lock); task_barrier_rem_task(&hive->tb); amdgpu_xgmi_sysfs_rem_dev_info(adev, hive); + if (hive->hi_req_gpu == adev) + hive->hi_req_gpu = NULL; + list_del(&adev->gmc.xgmi.head); mutex_unlock(&hive->hive_lock); - if(!(--hive->number_devices)){ - amdgpu_xgmi_sysfs_destroy(adev, hive); - mutex_destroy(&hive->hive_lock); - mutex_destroy(&hive->reset_lock); + amdgpu_put_xgmi_hive(hive); + adev->hive = NULL; + + if (atomic_dec_return(&hive->number_devices) == 0) { + /* Remove the hive from global hive list */ + mutex_lock(&xgmi_mutex); + list_del(&hive->node); + mutex_unlock(&xgmi_mutex); + + amdgpu_put_xgmi_hive(hive); } return psp_xgmi_terminate(&adev->psp); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h index 6999eab16a72..148560d63554 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h @@ -27,13 +27,13 @@ struct amdgpu_hive_info { - uint64_t hive_id; - struct list_head device_list; - int number_devices; - struct mutex hive_lock, reset_lock; - struct kobject *kobj; - struct device_attribute dev_attr; - struct amdgpu_device *adev; + struct kobject kobj; + uint64_t hive_id; + struct list_head device_list; + struct list_head node; + atomic_t number_devices; + struct mutex hive_lock; + atomic_t in_reset; int hi_req_count; struct amdgpu_device *hi_req_gpu; struct task_barrier tb; @@ -50,7 +50,8 @@ struct amdgpu_pcs_ras_field { uint32_t pcs_err_shift; }; -struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev, int lock); +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); +void amdgpu_put_xgmi_hive(struct amdgpu_hive_info *hive); int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev); int amdgpu_xgmi_add_device(struct amdgpu_device *adev); int amdgpu_xgmi_remove_device(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/athub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/athub_v1_0.c index 847ca9b3ce4e..3ea557864320 100644 --- a/drivers/gpu/drm/amd/amdgpu/athub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/athub_v1_0.c @@ -73,6 +73,7 @@ int athub_v1_0_set_clockgating(struct amdgpu_device *adev, case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_RAVEN: + case CHIP_RENOIR: athub_update_medium_grain_clock_gating(adev, state == AMD_CG_STATE_GATE); athub_update_medium_grain_light_sleep(adev, diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c index 213e62a28ba0..159a2a4385a1 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c @@ -41,7 +41,7 @@ void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); SET_CRTC_OVERSCAN_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); @@ -84,7 +84,7 @@ void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc, void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); ENABLE_SCALER_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); @@ -114,7 +114,7 @@ void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int index = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); ENABLE_CRTC_PS_ALLOCATION args; @@ -131,7 +131,7 @@ void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); ENABLE_CRTC_PS_ALLOCATION args; @@ -147,7 +147,7 @@ void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); BLANK_CRTC_PS_ALLOCATION args; @@ -163,7 +163,7 @@ void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); ENABLE_DISP_POWER_GATING_PS_ALLOCATION args; @@ -192,7 +192,7 @@ void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc, { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); SET_CRTC_USING_DTD_TIMING_PARAMETERS args; int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); u16 misc = 0; @@ -307,7 +307,7 @@ static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc, { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_encoder *encoder = amdgpu_crtc->encoder; struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -588,7 +588,7 @@ void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc, struct amdgpu_atom_ss *ss) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u8 frev, crev; int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); union set_pixel_clock args; @@ -749,7 +749,7 @@ int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc, { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(amdgpu_crtc->encoder); int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder); @@ -818,7 +818,7 @@ void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(amdgpu_crtc->encoder); u32 pll_clock = mode->clock; diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index 9b74cfdba7b8..a3ba9ca11e98 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c @@ -60,7 +60,7 @@ static int amdgpu_atombios_dp_process_aux_ch(struct amdgpu_i2c_chan *chan, u8 delay, u8 *ack) { struct drm_device *dev = chan->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); union aux_channel_transaction args; int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); unsigned char *base; @@ -305,7 +305,7 @@ static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev, u8 amdgpu_atombios_dp_get_sinktype(struct amdgpu_connector *amdgpu_connector) { struct drm_device *dev = amdgpu_connector->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); return amdgpu_atombios_dp_encoder_service(adev, ATOM_DP_ACTION_GET_SINK_TYPE, 0, amdgpu_connector->ddc_bus->rec.i2c_id, 0); @@ -328,6 +328,22 @@ static void amdgpu_atombios_dp_probe_oui(struct amdgpu_connector *amdgpu_connect buf[0], buf[1], buf[2]); } +static void amdgpu_atombios_dp_ds_ports(struct amdgpu_connector *amdgpu_connector) +{ + struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv; + int ret; + + if (dig_connector->dpcd[DP_DPCD_REV] > 0x10) { + ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, + DP_DOWNSTREAM_PORT_0, + dig_connector->downstream_ports, + DP_MAX_DOWNSTREAM_PORTS); + if (ret) + memset(dig_connector->downstream_ports, 0, + DP_MAX_DOWNSTREAM_PORTS); + } +} + int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector) { struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv; @@ -343,7 +359,7 @@ int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector) dig_connector->dpcd); amdgpu_atombios_dp_probe_oui(amdgpu_connector); - + amdgpu_atombios_dp_ds_ports(amdgpu_connector); return 0; } @@ -702,7 +718,7 @@ void amdgpu_atombios_dp_link_train(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_connector *amdgpu_connector; struct amdgpu_connector_atom_dig *dig_connector; diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c index 1e94a9b652f7..8339c8c3a328 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c @@ -70,7 +70,7 @@ u8 amdgpu_atombios_encoder_get_backlight_level(struct amdgpu_encoder *amdgpu_encoder) { struct drm_device *dev = amdgpu_encoder->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) return 0; @@ -84,7 +84,7 @@ amdgpu_atombios_encoder_set_backlight_level(struct amdgpu_encoder *amdgpu_encode { struct drm_encoder *encoder = &amdgpu_encoder->base; struct drm_device *dev = amdgpu_encoder->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder_atom_dig *dig; if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) @@ -152,7 +152,7 @@ amdgpu_atombios_encoder_get_backlight_brightness(struct backlight_device *bd) struct amdgpu_backlight_privdata *pdata = bl_get_data(bd); struct amdgpu_encoder *amdgpu_encoder = pdata->encoder; struct drm_device *dev = amdgpu_encoder->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); return amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); } @@ -166,7 +166,7 @@ void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encode struct drm_connector *drm_connector) { struct drm_device *dev = amdgpu_encoder->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct backlight_device *bd; struct backlight_properties props; struct amdgpu_backlight_privdata *pdata; @@ -229,7 +229,7 @@ void amdgpu_atombios_encoder_fini_backlight(struct amdgpu_encoder *amdgpu_encoder) { struct drm_device *dev = amdgpu_encoder->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct backlight_device *bd = NULL; struct amdgpu_encoder_atom_dig *dig; @@ -319,7 +319,7 @@ static void amdgpu_atombios_encoder_setup_dac(struct drm_encoder *encoder, int action) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); DAC_ENCODER_CONTROL_PS_ALLOCATION args; int index = 0; @@ -382,7 +382,7 @@ static void amdgpu_atombios_encoder_setup_dvo(struct drm_encoder *encoder, int action) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); union dvo_encoder_control args; int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); @@ -573,7 +573,7 @@ amdgpu_atombios_encoder_setup_dig_encoder(struct drm_encoder *encoder, int action, int panel_mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -762,7 +762,7 @@ amdgpu_atombios_encoder_setup_dig_transmitter(struct drm_encoder *encoder, int a uint8_t lane_num, uint8_t lane_set) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1178,7 +1178,7 @@ amdgpu_atombios_encoder_set_edp_panel_power(struct drm_connector *connector, { struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct drm_device *dev = amdgpu_connector->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); union dig_transmitter_control args; int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); uint8_t frev, crev; @@ -1225,7 +1225,7 @@ amdgpu_atombios_encoder_setup_external_encoder(struct drm_encoder *encoder, int action) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder *ext_amdgpu_encoder = to_amdgpu_encoder(ext_encoder); union external_encoder_control args; @@ -1466,7 +1466,7 @@ void amdgpu_atombios_encoder_set_crtc_source(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); union crtc_source_param args; @@ -1673,7 +1673,7 @@ amdgpu_atombios_encoder_set_crtc_source(struct drm_encoder *encoder) void amdgpu_atombios_encoder_init_dig(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_encoder *encoder; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -1701,7 +1701,7 @@ amdgpu_atombios_encoder_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); @@ -1751,7 +1751,7 @@ amdgpu_atombios_encoder_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); uint32_t bios_0_scratch; @@ -1790,7 +1790,7 @@ amdgpu_atombios_encoder_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder); @@ -1848,7 +1848,7 @@ amdgpu_atombios_encoder_set_bios_scratch_regs(struct drm_connector *connector, bool connected) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); @@ -1999,7 +1999,7 @@ struct amdgpu_encoder_atom_dig * amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder) { struct drm_device *dev = encoder->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_mode_info *mode_info = &adev->mode_info; int index = GetIndexIntoMasterTable(DATA, LVDS_Info); uint16_t data_offset, misc; diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c index b4cc7c55fa16..09a538465ffd 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c @@ -40,7 +40,7 @@ static int amdgpu_atombios_i2c_process_i2c_ch(struct amdgpu_i2c_chan *chan, u8 *buf, u8 num) { struct drm_device *dev = chan->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction); unsigned char *base; diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index c2c67ab68a43..03ff8bd1fee8 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1366,8 +1366,10 @@ static int cik_asic_reset(struct amdgpu_device *adev) int r; if (cik_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) { + dev_info(adev->dev, "BACO reset\n"); r = amdgpu_dpm_baco_reset(adev); } else { + dev_info(adev->dev, "PCI CONFIG reset\n"); r = cik_asic_pci_config_reset(adev); } @@ -1919,6 +1921,10 @@ static uint64_t cik_get_pcie_replay_count(struct amdgpu_device *adev) return (nak_r + nak_g); } +static void cik_pre_asic_init(struct amdgpu_device *adev) +{ +} + static const struct amdgpu_asic_funcs cik_asic_funcs = { .read_disabled_bios = &cik_read_disabled_bios, @@ -1939,6 +1945,7 @@ static const struct amdgpu_asic_funcs cik_asic_funcs = .need_reset_on_init = &cik_need_reset_on_init, .get_pcie_replay_count = &cik_get_pcie_replay_count, .supports_baco = &cik_asic_supports_baco, + .pre_asic_init = &cik_pre_asic_init, }; static int cik_common_early_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 84b45a019a36..5963cbe0d455 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -328,7 +328,7 @@ static void dce_v10_0_hpd_set_polarity(struct amdgpu_device *adev, */ static void dce_v10_0_hpd_init(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; u32 tmp; @@ -383,7 +383,7 @@ static void dce_v10_0_hpd_init(struct amdgpu_device *adev) */ static void dce_v10_0_hpd_fini(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; u32 tmp; @@ -504,7 +504,7 @@ void dce_v10_0_disable_dce(struct amdgpu_device *adev) static void dce_v10_0_program_fmt(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -1209,7 +1209,7 @@ static struct amdgpu_audio_pin *dce_v10_0_audio_get_pin(struct amdgpu_device *ad static void dce_v10_0_afmt_audio_select_pin(struct drm_encoder *encoder) { - struct amdgpu_device *adev = encoder->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(encoder->dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 tmp; @@ -1226,7 +1226,7 @@ static void dce_v10_0_audio_write_latency_fields(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1272,7 +1272,7 @@ static void dce_v10_0_audio_write_latency_fields(struct drm_encoder *encoder, static void dce_v10_0_audio_write_speaker_allocation(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1328,7 +1328,7 @@ static void dce_v10_0_audio_write_speaker_allocation(struct drm_encoder *encoder static void dce_v10_0_audio_write_sad_regs(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1483,7 +1483,7 @@ static void dce_v10_0_audio_fini(struct amdgpu_device *adev) static void dce_v10_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_afmt_acr acr = amdgpu_afmt_acr(clock); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1519,7 +1519,7 @@ static void dce_v10_0_afmt_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, size_t size) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; uint8_t *frame = buffer + 3; @@ -1538,7 +1538,7 @@ static void dce_v10_0_afmt_update_avi_infoframe(struct drm_encoder *encoder, static void dce_v10_0_audio_set_dto(struct drm_encoder *encoder, u32 clock) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); @@ -1569,7 +1569,7 @@ static void dce_v10_0_afmt_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -1749,7 +1749,7 @@ static void dce_v10_0_afmt_setmode(struct drm_encoder *encoder, static void dce_v10_0_afmt_enable(struct drm_encoder *encoder, bool enable) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1822,7 +1822,7 @@ static void dce_v10_0_vga_enable(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 vga_control; vga_control = RREG32(vga_control_regs[amdgpu_crtc->crtc_id]) & ~1; @@ -1836,7 +1836,7 @@ static void dce_v10_0_grph_enable(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if (enable) WREG32(mmGRPH_ENABLE + amdgpu_crtc->crtc_offset, 1); @@ -1850,7 +1850,7 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_framebuffer *target_fb; struct drm_gem_object *obj; struct amdgpu_bo *abo; @@ -2095,7 +2095,7 @@ static void dce_v10_0_set_interleave(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); u32 tmp; @@ -2111,7 +2111,7 @@ static void dce_v10_0_crtc_load_lut(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u16 *r, *g, *b; int i; u32 tmp; @@ -2250,7 +2250,7 @@ static u32 dce_v10_0_pick_pll(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 pll_in_use; int pll; @@ -2285,7 +2285,7 @@ static u32 dce_v10_0_pick_pll(struct drm_crtc *crtc) static void dce_v10_0_lock_cursor(struct drm_crtc *crtc, bool lock) { - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); uint32_t cur_lock; @@ -2300,7 +2300,7 @@ static void dce_v10_0_lock_cursor(struct drm_crtc *crtc, bool lock) static void dce_v10_0_hide_cursor(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); u32 tmp; tmp = RREG32(mmCUR_CONTROL + amdgpu_crtc->crtc_offset); @@ -2311,7 +2311,7 @@ static void dce_v10_0_hide_cursor(struct drm_crtc *crtc) static void dce_v10_0_show_cursor(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); u32 tmp; WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, @@ -2329,7 +2329,7 @@ static int dce_v10_0_cursor_move_locked(struct drm_crtc *crtc, int x, int y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); int xorigin = 0, yorigin = 0; amdgpu_crtc->cursor_x = x; @@ -2503,7 +2503,7 @@ static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = { static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); unsigned type; @@ -2557,7 +2557,7 @@ static void dce_v10_0_crtc_disable(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_atom_ss ss; int i; @@ -2701,7 +2701,7 @@ static int dce_v10_0_crtc_init(struct amdgpu_device *adev, int index) if (amdgpu_crtc == NULL) return -ENOMEM; - drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_v10_0_crtc_funcs); + drm_crtc_init(adev_to_drm(adev), &amdgpu_crtc->base, &dce_v10_0_crtc_funcs); drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256); amdgpu_crtc->crtc_id = index; @@ -2709,8 +2709,8 @@ static int dce_v10_0_crtc_init(struct amdgpu_device *adev, int index) amdgpu_crtc->max_cursor_width = 128; amdgpu_crtc->max_cursor_height = 128; - adev->ddev->mode_config.cursor_width = amdgpu_crtc->max_cursor_width; - adev->ddev->mode_config.cursor_height = amdgpu_crtc->max_cursor_height; + adev_to_drm(adev)->mode_config.cursor_width = amdgpu_crtc->max_cursor_width; + adev_to_drm(adev)->mode_config.cursor_height = amdgpu_crtc->max_cursor_height; switch (amdgpu_crtc->crtc_id) { case 0: @@ -2792,24 +2792,24 @@ static int dce_v10_0_sw_init(void *handle) if (r) return r; - adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; + adev_to_drm(adev)->mode_config.funcs = &amdgpu_mode_funcs; - adev->ddev->mode_config.async_page_flip = true; + adev_to_drm(adev)->mode_config.async_page_flip = true; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; - adev->ddev->mode_config.preferred_depth = 24; - adev->ddev->mode_config.prefer_shadow = 1; + adev_to_drm(adev)->mode_config.preferred_depth = 24; + adev_to_drm(adev)->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->gmc.aper_base; + adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; r = amdgpu_display_modeset_create_props(adev); if (r) return r; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; /* allocate crtcs */ for (i = 0; i < adev->mode_info.num_crtc; i++) { @@ -2819,7 +2819,7 @@ static int dce_v10_0_sw_init(void *handle) } if (amdgpu_atombios_get_connector_info_from_object_table(adev)) - amdgpu_display_print_display_setup(adev->ddev); + amdgpu_display_print_display_setup(adev_to_drm(adev)); else return -EINVAL; @@ -2832,7 +2832,7 @@ static int dce_v10_0_sw_init(void *handle) if (r) return r; - drm_kms_helper_poll_init(adev->ddev); + drm_kms_helper_poll_init(adev_to_drm(adev)); adev->mode_info.mode_config_initialized = true; return 0; @@ -2844,13 +2844,13 @@ static int dce_v10_0_sw_fini(void *handle) kfree(adev->mode_info.bios_hardcoded_edid); - drm_kms_helper_poll_fini(adev->ddev); + drm_kms_helper_poll_fini(adev_to_drm(adev)); dce_v10_0_audio_fini(adev); dce_v10_0_afmt_fini(adev); - drm_mode_config_cleanup(adev->ddev); + drm_mode_config_cleanup(adev_to_drm(adev)); adev->mode_info.mode_config_initialized = false; return 0; @@ -3157,14 +3157,14 @@ static int dce_v10_0_pageflip_irq(struct amdgpu_device *adev, if (amdgpu_crtc == NULL) return 0; - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); works = amdgpu_crtc->pflip_works; if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) { DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != " "AMDGPU_FLIP_SUBMITTED(%d)\n", amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); return 0; } @@ -3176,7 +3176,7 @@ static int dce_v10_0_pageflip_irq(struct amdgpu_device *adev, if (works->event) drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); drm_crtc_vblank_put(&amdgpu_crtc->base); schedule_work(&works->unpin_work); @@ -3245,7 +3245,7 @@ static int dce_v10_0_crtc_irq(struct amdgpu_device *adev, DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); + drm_handle_vblank(adev_to_drm(adev), crtc); } DRM_DEBUG("IH: D%d vblank\n", crtc + 1); @@ -3345,7 +3345,7 @@ dce_v10_0_encoder_mode_set(struct drm_encoder *encoder, static void dce_v10_0_encoder_prepare(struct drm_encoder *encoder) { - struct amdgpu_device *adev = encoder->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(encoder->dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -3385,7 +3385,7 @@ static void dce_v10_0_encoder_prepare(struct drm_encoder *encoder) static void dce_v10_0_encoder_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); /* need to call this here as we need the crtc set up */ amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_ON); @@ -3485,7 +3485,7 @@ static void dce_v10_0_encoder_add(struct amdgpu_device *adev, uint32_t supported_device, u16 caps) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 01ce52266966..1954472c8e8f 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -346,7 +346,7 @@ static void dce_v11_0_hpd_set_polarity(struct amdgpu_device *adev, */ static void dce_v11_0_hpd_init(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; u32 tmp; @@ -400,7 +400,7 @@ static void dce_v11_0_hpd_init(struct amdgpu_device *adev) */ static void dce_v11_0_hpd_fini(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; u32 tmp; @@ -530,7 +530,7 @@ void dce_v11_0_disable_dce(struct amdgpu_device *adev) static void dce_v11_0_program_fmt(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -1235,7 +1235,7 @@ static struct amdgpu_audio_pin *dce_v11_0_audio_get_pin(struct amdgpu_device *ad static void dce_v11_0_afmt_audio_select_pin(struct drm_encoder *encoder) { - struct amdgpu_device *adev = encoder->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(encoder->dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 tmp; @@ -1252,7 +1252,7 @@ static void dce_v11_0_audio_write_latency_fields(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1298,7 +1298,7 @@ static void dce_v11_0_audio_write_latency_fields(struct drm_encoder *encoder, static void dce_v11_0_audio_write_speaker_allocation(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1354,7 +1354,7 @@ static void dce_v11_0_audio_write_speaker_allocation(struct drm_encoder *encoder static void dce_v11_0_audio_write_sad_regs(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1525,7 +1525,7 @@ static void dce_v11_0_audio_fini(struct amdgpu_device *adev) static void dce_v11_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_afmt_acr acr = amdgpu_afmt_acr(clock); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1561,7 +1561,7 @@ static void dce_v11_0_afmt_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, size_t size) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; uint8_t *frame = buffer + 3; @@ -1580,7 +1580,7 @@ static void dce_v11_0_afmt_update_avi_infoframe(struct drm_encoder *encoder, static void dce_v11_0_audio_set_dto(struct drm_encoder *encoder, u32 clock) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); @@ -1611,7 +1611,7 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -1791,7 +1791,7 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder, static void dce_v11_0_afmt_enable(struct drm_encoder *encoder, bool enable) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1864,7 +1864,7 @@ static void dce_v11_0_vga_enable(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 vga_control; vga_control = RREG32(vga_control_regs[amdgpu_crtc->crtc_id]) & ~1; @@ -1878,7 +1878,7 @@ static void dce_v11_0_grph_enable(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if (enable) WREG32(mmGRPH_ENABLE + amdgpu_crtc->crtc_offset, 1); @@ -1892,7 +1892,7 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_framebuffer *target_fb; struct drm_gem_object *obj; struct amdgpu_bo *abo; @@ -2137,7 +2137,7 @@ static void dce_v11_0_set_interleave(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); u32 tmp; @@ -2153,7 +2153,7 @@ static void dce_v11_0_crtc_load_lut(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u16 *r, *g, *b; int i; u32 tmp; @@ -2283,7 +2283,7 @@ static u32 dce_v11_0_pick_pll(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 pll_in_use; int pll; @@ -2364,7 +2364,7 @@ static u32 dce_v11_0_pick_pll(struct drm_crtc *crtc) static void dce_v11_0_lock_cursor(struct drm_crtc *crtc, bool lock) { - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); uint32_t cur_lock; @@ -2379,7 +2379,7 @@ static void dce_v11_0_lock_cursor(struct drm_crtc *crtc, bool lock) static void dce_v11_0_hide_cursor(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); u32 tmp; tmp = RREG32(mmCUR_CONTROL + amdgpu_crtc->crtc_offset); @@ -2390,7 +2390,7 @@ static void dce_v11_0_hide_cursor(struct drm_crtc *crtc) static void dce_v11_0_show_cursor(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); u32 tmp; WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, @@ -2408,7 +2408,7 @@ static int dce_v11_0_cursor_move_locked(struct drm_crtc *crtc, int x, int y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); int xorigin = 0, yorigin = 0; amdgpu_crtc->cursor_x = x; @@ -2582,7 +2582,7 @@ static const struct drm_crtc_funcs dce_v11_0_crtc_funcs = { static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); unsigned type; @@ -2636,7 +2636,7 @@ static void dce_v11_0_crtc_disable(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_atom_ss ss; int i; @@ -2706,7 +2706,7 @@ static int dce_v11_0_crtc_mode_set(struct drm_crtc *crtc, { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if (!amdgpu_crtc->adjusted_clock) return -EINVAL; @@ -2809,7 +2809,7 @@ static int dce_v11_0_crtc_init(struct amdgpu_device *adev, int index) if (amdgpu_crtc == NULL) return -ENOMEM; - drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_v11_0_crtc_funcs); + drm_crtc_init(adev_to_drm(adev), &amdgpu_crtc->base, &dce_v11_0_crtc_funcs); drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256); amdgpu_crtc->crtc_id = index; @@ -2817,8 +2817,8 @@ static int dce_v11_0_crtc_init(struct amdgpu_device *adev, int index) amdgpu_crtc->max_cursor_width = 128; amdgpu_crtc->max_cursor_height = 128; - adev->ddev->mode_config.cursor_width = amdgpu_crtc->max_cursor_width; - adev->ddev->mode_config.cursor_height = amdgpu_crtc->max_cursor_height; + adev_to_drm(adev)->mode_config.cursor_width = amdgpu_crtc->max_cursor_width; + adev_to_drm(adev)->mode_config.cursor_height = amdgpu_crtc->max_cursor_height; switch (amdgpu_crtc->crtc_id) { case 0: @@ -2913,24 +2913,24 @@ static int dce_v11_0_sw_init(void *handle) if (r) return r; - adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; + adev_to_drm(adev)->mode_config.funcs = &amdgpu_mode_funcs; - adev->ddev->mode_config.async_page_flip = true; + adev_to_drm(adev)->mode_config.async_page_flip = true; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; - adev->ddev->mode_config.preferred_depth = 24; - adev->ddev->mode_config.prefer_shadow = 1; + adev_to_drm(adev)->mode_config.preferred_depth = 24; + adev_to_drm(adev)->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->gmc.aper_base; + adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; r = amdgpu_display_modeset_create_props(adev); if (r) return r; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; /* allocate crtcs */ @@ -2941,7 +2941,7 @@ static int dce_v11_0_sw_init(void *handle) } if (amdgpu_atombios_get_connector_info_from_object_table(adev)) - amdgpu_display_print_display_setup(adev->ddev); + amdgpu_display_print_display_setup(adev_to_drm(adev)); else return -EINVAL; @@ -2954,7 +2954,7 @@ static int dce_v11_0_sw_init(void *handle) if (r) return r; - drm_kms_helper_poll_init(adev->ddev); + drm_kms_helper_poll_init(adev_to_drm(adev)); adev->mode_info.mode_config_initialized = true; return 0; @@ -2966,13 +2966,13 @@ static int dce_v11_0_sw_fini(void *handle) kfree(adev->mode_info.bios_hardcoded_edid); - drm_kms_helper_poll_fini(adev->ddev); + drm_kms_helper_poll_fini(adev_to_drm(adev)); dce_v11_0_audio_fini(adev); dce_v11_0_afmt_fini(adev); - drm_mode_config_cleanup(adev->ddev); + drm_mode_config_cleanup(adev_to_drm(adev)); adev->mode_info.mode_config_initialized = false; return 0; @@ -3283,14 +3283,14 @@ static int dce_v11_0_pageflip_irq(struct amdgpu_device *adev, if(amdgpu_crtc == NULL) return 0; - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); works = amdgpu_crtc->pflip_works; if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){ DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != " "AMDGPU_FLIP_SUBMITTED(%d)\n", amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); return 0; } @@ -3302,7 +3302,7 @@ static int dce_v11_0_pageflip_irq(struct amdgpu_device *adev, if(works->event) drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); drm_crtc_vblank_put(&amdgpu_crtc->base); schedule_work(&works->unpin_work); @@ -3372,7 +3372,7 @@ static int dce_v11_0_crtc_irq(struct amdgpu_device *adev, DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); + drm_handle_vblank(adev_to_drm(adev), crtc); } DRM_DEBUG("IH: D%d vblank\n", crtc + 1); @@ -3471,7 +3471,7 @@ dce_v11_0_encoder_mode_set(struct drm_encoder *encoder, static void dce_v11_0_encoder_prepare(struct drm_encoder *encoder) { - struct amdgpu_device *adev = encoder->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(encoder->dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -3511,7 +3511,7 @@ static void dce_v11_0_encoder_prepare(struct drm_encoder *encoder) static void dce_v11_0_encoder_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); /* need to call this here as we need the crtc set up */ amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_ON); @@ -3611,7 +3611,7 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev, uint32_t supported_device, u16 caps) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index cbddead3dafb..3a44753a80d1 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -279,7 +279,7 @@ static void dce_v6_0_hpd_set_polarity(struct amdgpu_device *adev, */ static void dce_v6_0_hpd_init(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; u32 tmp; @@ -324,7 +324,7 @@ static void dce_v6_0_hpd_init(struct amdgpu_device *adev) */ static void dce_v6_0_hpd_fini(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; u32 tmp; @@ -401,7 +401,7 @@ static void dce_v6_0_program_fmt(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); @@ -1114,7 +1114,7 @@ static struct amdgpu_audio_pin *dce_v6_0_audio_get_pin(struct amdgpu_device *ade static void dce_v6_0_audio_select_pin(struct drm_encoder *encoder) { - struct amdgpu_device *adev = encoder->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(encoder->dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1130,7 +1130,7 @@ static void dce_v6_0_audio_write_latency_fields(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1174,7 +1174,7 @@ static void dce_v6_0_audio_write_latency_fields(struct drm_encoder *encoder, static void dce_v6_0_audio_write_speaker_allocation(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1235,7 +1235,7 @@ static void dce_v6_0_audio_write_speaker_allocation(struct drm_encoder *encoder) static void dce_v6_0_audio_write_sad_regs(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1392,7 +1392,7 @@ static void dce_v6_0_audio_fini(struct amdgpu_device *adev) static void dce_v6_0_audio_set_vbi_packet(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 tmp; @@ -1408,7 +1408,7 @@ static void dce_v6_0_audio_set_acr(struct drm_encoder *encoder, uint32_t clock, int bpc) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_afmt_acr acr = amdgpu_afmt_acr(clock); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1446,7 +1446,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -1488,7 +1488,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder, static void dce_v6_0_audio_set_dto(struct drm_encoder *encoder, u32 clock) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); int em = amdgpu_atombios_encoder_get_encoder_mode(encoder); u32 tmp; @@ -1522,7 +1522,7 @@ static void dce_v6_0_audio_set_dto(struct drm_encoder *encoder, u32 clock) static void dce_v6_0_audio_set_packet(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 tmp; @@ -1566,7 +1566,7 @@ static void dce_v6_0_audio_set_packet(struct drm_encoder *encoder) static void dce_v6_0_audio_set_mute(struct drm_encoder *encoder, bool mute) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 tmp; @@ -1579,7 +1579,7 @@ static void dce_v6_0_audio_set_mute(struct drm_encoder *encoder, bool mute) static void dce_v6_0_audio_hdmi_enable(struct drm_encoder *encoder, bool enable) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 tmp; @@ -1616,7 +1616,7 @@ static void dce_v6_0_audio_hdmi_enable(struct drm_encoder *encoder, bool enable) static void dce_v6_0_audio_dp_enable(struct drm_encoder *encoder, bool enable) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 tmp; @@ -1645,7 +1645,7 @@ static void dce_v6_0_afmt_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1714,7 +1714,7 @@ static void dce_v6_0_afmt_setmode(struct drm_encoder *encoder, static void dce_v6_0_afmt_enable(struct drm_encoder *encoder, bool enable) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1788,7 +1788,7 @@ static void dce_v6_0_vga_enable(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 vga_control; vga_control = RREG32(vga_control_regs[amdgpu_crtc->crtc_id]) & ~1; @@ -1799,7 +1799,7 @@ static void dce_v6_0_grph_enable(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); WREG32(mmGRPH_ENABLE + amdgpu_crtc->crtc_offset, enable ? 1 : 0); } @@ -1810,7 +1810,7 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_framebuffer *target_fb; struct drm_gem_object *obj; struct amdgpu_bo *abo; @@ -2033,7 +2033,7 @@ static void dce_v6_0_set_interleave(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); if (mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -2048,7 +2048,7 @@ static void dce_v6_0_crtc_load_lut(struct drm_crtc *crtc) struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u16 *r, *g, *b; int i; @@ -2148,7 +2148,7 @@ static u32 dce_v6_0_pick_pll(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 pll_in_use; int pll; @@ -2177,7 +2177,7 @@ static u32 dce_v6_0_pick_pll(struct drm_crtc *crtc) static void dce_v6_0_lock_cursor(struct drm_crtc *crtc, bool lock) { - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); uint32_t cur_lock; @@ -2192,7 +2192,7 @@ static void dce_v6_0_lock_cursor(struct drm_crtc *crtc, bool lock) static void dce_v6_0_hide_cursor(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); WREG32(mmCUR_CONTROL + amdgpu_crtc->crtc_offset, (CURSOR_24_8_PRE_MULT << CUR_CONTROL__CURSOR_MODE__SHIFT) | @@ -2204,7 +2204,7 @@ static void dce_v6_0_hide_cursor(struct drm_crtc *crtc) static void dce_v6_0_show_cursor(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, upper_32_bits(amdgpu_crtc->cursor_addr)); @@ -2222,7 +2222,7 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc, int x, int y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); int xorigin = 0, yorigin = 0; int w = amdgpu_crtc->cursor_width; @@ -2397,7 +2397,7 @@ static const struct drm_crtc_funcs dce_v6_0_crtc_funcs = { static void dce_v6_0_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); unsigned type; @@ -2447,7 +2447,7 @@ static void dce_v6_0_crtc_disable(struct drm_crtc *crtc) struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_atom_ss ss; int i; @@ -2591,7 +2591,7 @@ static int dce_v6_0_crtc_init(struct amdgpu_device *adev, int index) if (amdgpu_crtc == NULL) return -ENOMEM; - drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_v6_0_crtc_funcs); + drm_crtc_init(adev_to_drm(adev), &amdgpu_crtc->base, &dce_v6_0_crtc_funcs); drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256); amdgpu_crtc->crtc_id = index; @@ -2599,8 +2599,8 @@ static int dce_v6_0_crtc_init(struct amdgpu_device *adev, int index) amdgpu_crtc->max_cursor_width = CURSOR_WIDTH; amdgpu_crtc->max_cursor_height = CURSOR_HEIGHT; - adev->ddev->mode_config.cursor_width = amdgpu_crtc->max_cursor_width; - adev->ddev->mode_config.cursor_height = amdgpu_crtc->max_cursor_height; + adev_to_drm(adev)->mode_config.cursor_width = amdgpu_crtc->max_cursor_width; + adev_to_drm(adev)->mode_config.cursor_height = amdgpu_crtc->max_cursor_height; amdgpu_crtc->crtc_offset = crtc_offsets[amdgpu_crtc->crtc_id]; @@ -2669,20 +2669,20 @@ static int dce_v6_0_sw_init(void *handle) adev->mode_info.mode_config_initialized = true; - adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; - adev->ddev->mode_config.async_page_flip = true; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; - adev->ddev->mode_config.preferred_depth = 24; - adev->ddev->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->gmc.aper_base; + adev_to_drm(adev)->mode_config.funcs = &amdgpu_mode_funcs; + adev_to_drm(adev)->mode_config.async_page_flip = true; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.preferred_depth = 24; + adev_to_drm(adev)->mode_config.prefer_shadow = 1; + adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; r = amdgpu_display_modeset_create_props(adev); if (r) return r; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; /* allocate crtcs */ for (i = 0; i < adev->mode_info.num_crtc; i++) { @@ -2693,7 +2693,7 @@ static int dce_v6_0_sw_init(void *handle) ret = amdgpu_atombios_get_connector_info_from_object_table(adev); if (ret) - amdgpu_display_print_display_setup(adev->ddev); + amdgpu_display_print_display_setup(adev_to_drm(adev)); else return -EINVAL; @@ -2706,7 +2706,7 @@ static int dce_v6_0_sw_init(void *handle) if (r) return r; - drm_kms_helper_poll_init(adev->ddev); + drm_kms_helper_poll_init(adev_to_drm(adev)); return r; } @@ -2717,12 +2717,12 @@ static int dce_v6_0_sw_fini(void *handle) kfree(adev->mode_info.bios_hardcoded_edid); - drm_kms_helper_poll_fini(adev->ddev); + drm_kms_helper_poll_fini(adev_to_drm(adev)); dce_v6_0_audio_fini(adev); dce_v6_0_afmt_fini(adev); - drm_mode_config_cleanup(adev->ddev); + drm_mode_config_cleanup(adev_to_drm(adev)); adev->mode_info.mode_config_initialized = false; return 0; @@ -2967,7 +2967,7 @@ static int dce_v6_0_crtc_irq(struct amdgpu_device *adev, DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); + drm_handle_vblank(adev_to_drm(adev), crtc); } DRM_DEBUG("IH: D%d vblank\n", crtc + 1); break; @@ -3036,14 +3036,14 @@ static int dce_v6_0_pageflip_irq(struct amdgpu_device *adev, if (amdgpu_crtc == NULL) return 0; - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); works = amdgpu_crtc->pflip_works; if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){ DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != " "AMDGPU_FLIP_SUBMITTED(%d)\n", amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); return 0; } @@ -3055,7 +3055,7 @@ static int dce_v6_0_pageflip_irq(struct amdgpu_device *adev, if (works->event) drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); drm_crtc_vblank_put(&amdgpu_crtc->base); schedule_work(&works->unpin_work); @@ -3146,7 +3146,7 @@ dce_v6_0_encoder_mode_set(struct drm_encoder *encoder, static void dce_v6_0_encoder_prepare(struct drm_encoder *encoder) { - struct amdgpu_device *adev = encoder->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(encoder->dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -3187,7 +3187,7 @@ static void dce_v6_0_encoder_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); /* need to call this here as we need the crtc set up */ amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_ON); @@ -3297,7 +3297,7 @@ static void dce_v6_0_encoder_add(struct amdgpu_device *adev, uint32_t supported_device, u16 caps) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index fa0ad50b628c..3603e5f13077 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -273,7 +273,7 @@ static void dce_v8_0_hpd_set_polarity(struct amdgpu_device *adev, */ static void dce_v8_0_hpd_init(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; u32 tmp; @@ -318,7 +318,7 @@ static void dce_v8_0_hpd_init(struct amdgpu_device *adev) */ static void dce_v8_0_hpd_fini(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; u32 tmp; @@ -444,7 +444,7 @@ void dce_v8_0_disable_dce(struct amdgpu_device *adev) static void dce_v8_0_program_fmt(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -1146,7 +1146,7 @@ static struct amdgpu_audio_pin *dce_v8_0_audio_get_pin(struct amdgpu_device *ade static void dce_v8_0_afmt_audio_select_pin(struct drm_encoder *encoder) { - struct amdgpu_device *adev = encoder->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(encoder->dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 offset; @@ -1164,7 +1164,7 @@ static void dce_v8_0_audio_write_latency_fields(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1225,7 +1225,7 @@ static void dce_v8_0_audio_write_latency_fields(struct drm_encoder *encoder, static void dce_v8_0_audio_write_speaker_allocation(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector; @@ -1278,7 +1278,7 @@ static void dce_v8_0_audio_write_speaker_allocation(struct drm_encoder *encoder) static void dce_v8_0_audio_write_sad_regs(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; u32 offset; @@ -1446,7 +1446,7 @@ static void dce_v8_0_audio_fini(struct amdgpu_device *adev) static void dce_v8_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_afmt_acr acr = amdgpu_afmt_acr(clock); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1469,7 +1469,7 @@ static void dce_v8_0_afmt_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, size_t size) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; uint32_t offset = dig->afmt->offset; @@ -1489,7 +1489,7 @@ static void dce_v8_0_afmt_update_avi_infoframe(struct drm_encoder *encoder, static void dce_v8_0_audio_set_dto(struct drm_encoder *encoder, u32 clock) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc); @@ -1516,7 +1516,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -1678,7 +1678,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder, static void dce_v8_0_afmt_enable(struct drm_encoder *encoder, bool enable) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -1751,7 +1751,7 @@ static void dce_v8_0_vga_enable(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 vga_control; vga_control = RREG32(vga_control_regs[amdgpu_crtc->crtc_id]) & ~1; @@ -1765,7 +1765,7 @@ static void dce_v8_0_grph_enable(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); if (enable) WREG32(mmGRPH_ENABLE + amdgpu_crtc->crtc_offset, 1); @@ -1779,7 +1779,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_framebuffer *target_fb; struct drm_gem_object *obj; struct amdgpu_bo *abo; @@ -2004,7 +2004,7 @@ static void dce_v8_0_set_interleave(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); if (mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -2018,7 +2018,7 @@ static void dce_v8_0_crtc_load_lut(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u16 *r, *g, *b; int i; @@ -2140,7 +2140,7 @@ static u32 dce_v8_0_pick_pll(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 pll_in_use; int pll; @@ -2188,7 +2188,7 @@ static u32 dce_v8_0_pick_pll(struct drm_crtc *crtc) static void dce_v8_0_lock_cursor(struct drm_crtc *crtc, bool lock) { - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); uint32_t cur_lock; @@ -2203,7 +2203,7 @@ static void dce_v8_0_lock_cursor(struct drm_crtc *crtc, bool lock) static void dce_v8_0_hide_cursor(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); WREG32(mmCUR_CONTROL + amdgpu_crtc->crtc_offset, (CURSOR_24_8_PRE_MULT << CUR_CONTROL__CURSOR_MODE__SHIFT) | @@ -2213,7 +2213,7 @@ static void dce_v8_0_hide_cursor(struct drm_crtc *crtc) static void dce_v8_0_show_cursor(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, upper_32_bits(amdgpu_crtc->cursor_addr)); @@ -2230,7 +2230,7 @@ static int dce_v8_0_cursor_move_locked(struct drm_crtc *crtc, int x, int y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); int xorigin = 0, yorigin = 0; amdgpu_crtc->cursor_x = x; @@ -2404,7 +2404,7 @@ static const struct drm_crtc_funcs dce_v8_0_crtc_funcs = { static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); unsigned type; @@ -2458,7 +2458,7 @@ static void dce_v8_0_crtc_disable(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_atom_ss ss; int i; @@ -2609,7 +2609,7 @@ static int dce_v8_0_crtc_init(struct amdgpu_device *adev, int index) if (amdgpu_crtc == NULL) return -ENOMEM; - drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_v8_0_crtc_funcs); + drm_crtc_init(adev_to_drm(adev), &amdgpu_crtc->base, &dce_v8_0_crtc_funcs); drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256); amdgpu_crtc->crtc_id = index; @@ -2617,8 +2617,8 @@ static int dce_v8_0_crtc_init(struct amdgpu_device *adev, int index) amdgpu_crtc->max_cursor_width = CIK_CURSOR_WIDTH; amdgpu_crtc->max_cursor_height = CIK_CURSOR_HEIGHT; - adev->ddev->mode_config.cursor_width = amdgpu_crtc->max_cursor_width; - adev->ddev->mode_config.cursor_height = amdgpu_crtc->max_cursor_height; + adev_to_drm(adev)->mode_config.cursor_width = amdgpu_crtc->max_cursor_width; + adev_to_drm(adev)->mode_config.cursor_height = amdgpu_crtc->max_cursor_height; amdgpu_crtc->crtc_offset = crtc_offsets[amdgpu_crtc->crtc_id]; @@ -2689,24 +2689,24 @@ static int dce_v8_0_sw_init(void *handle) if (r) return r; - adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; + adev_to_drm(adev)->mode_config.funcs = &amdgpu_mode_funcs; - adev->ddev->mode_config.async_page_flip = true; + adev_to_drm(adev)->mode_config.async_page_flip = true; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; - adev->ddev->mode_config.preferred_depth = 24; - adev->ddev->mode_config.prefer_shadow = 1; + adev_to_drm(adev)->mode_config.preferred_depth = 24; + adev_to_drm(adev)->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->gmc.aper_base; + adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; r = amdgpu_display_modeset_create_props(adev); if (r) return r; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; /* allocate crtcs */ for (i = 0; i < adev->mode_info.num_crtc; i++) { @@ -2716,7 +2716,7 @@ static int dce_v8_0_sw_init(void *handle) } if (amdgpu_atombios_get_connector_info_from_object_table(adev)) - amdgpu_display_print_display_setup(adev->ddev); + amdgpu_display_print_display_setup(adev_to_drm(adev)); else return -EINVAL; @@ -2729,7 +2729,7 @@ static int dce_v8_0_sw_init(void *handle) if (r) return r; - drm_kms_helper_poll_init(adev->ddev); + drm_kms_helper_poll_init(adev_to_drm(adev)); adev->mode_info.mode_config_initialized = true; return 0; @@ -2741,13 +2741,13 @@ static int dce_v8_0_sw_fini(void *handle) kfree(adev->mode_info.bios_hardcoded_edid); - drm_kms_helper_poll_fini(adev->ddev); + drm_kms_helper_poll_fini(adev_to_drm(adev)); dce_v8_0_audio_fini(adev); dce_v8_0_afmt_fini(adev); - drm_mode_config_cleanup(adev->ddev); + drm_mode_config_cleanup(adev_to_drm(adev)); adev->mode_info.mode_config_initialized = false; return 0; @@ -3057,7 +3057,7 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev, DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); + drm_handle_vblank(adev_to_drm(adev), crtc); } DRM_DEBUG("IH: D%d vblank\n", crtc + 1); break; @@ -3126,14 +3126,14 @@ static int dce_v8_0_pageflip_irq(struct amdgpu_device *adev, if (amdgpu_crtc == NULL) return 0; - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); works = amdgpu_crtc->pflip_works; if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){ DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != " "AMDGPU_FLIP_SUBMITTED(%d)\n", amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); return 0; } @@ -3145,7 +3145,7 @@ static int dce_v8_0_pageflip_irq(struct amdgpu_device *adev, if (works->event) drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); drm_crtc_vblank_put(&amdgpu_crtc->base); schedule_work(&works->unpin_work); @@ -3233,7 +3233,7 @@ dce_v8_0_encoder_mode_set(struct drm_encoder *encoder, static void dce_v8_0_encoder_prepare(struct drm_encoder *encoder) { - struct amdgpu_device *adev = encoder->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(encoder->dev); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder); @@ -3273,7 +3273,7 @@ static void dce_v8_0_encoder_prepare(struct drm_encoder *encoder) static void dce_v8_0_encoder_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); /* need to call this here as we need the crtc set up */ amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_ON); @@ -3373,7 +3373,7 @@ static void dce_v8_0_encoder_add(struct amdgpu_device *adev, uint32_t supported_device, u16 caps) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index d5ff7b6331ff..cc93577dee03 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -132,7 +132,7 @@ static const struct drm_crtc_funcs dce_virtual_crtc_funcs = { static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); unsigned type; @@ -235,7 +235,7 @@ static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index) if (amdgpu_crtc == NULL) return -ENOMEM; - drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_virtual_crtc_funcs); + drm_crtc_init(adev_to_drm(adev), &amdgpu_crtc->base, &dce_virtual_crtc_funcs); drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256); amdgpu_crtc->crtc_id = index; @@ -374,24 +374,24 @@ static int dce_virtual_sw_init(void *handle) if (r) return r; - adev->ddev->max_vblank_count = 0; + adev_to_drm(adev)->max_vblank_count = 0; - adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; + adev_to_drm(adev)->mode_config.funcs = &amdgpu_mode_funcs; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; - adev->ddev->mode_config.preferred_depth = 24; - adev->ddev->mode_config.prefer_shadow = 1; + adev_to_drm(adev)->mode_config.preferred_depth = 24; + adev_to_drm(adev)->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->gmc.aper_base; + adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; r = amdgpu_display_modeset_create_props(adev); if (r) return r; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; /* allocate crtcs, encoders, connectors */ for (i = 0; i < adev->mode_info.num_crtc; i++) { @@ -403,7 +403,7 @@ static int dce_virtual_sw_init(void *handle) return r; } - drm_kms_helper_poll_init(adev->ddev); + drm_kms_helper_poll_init(adev_to_drm(adev)); adev->mode_info.mode_config_initialized = true; return 0; @@ -415,9 +415,9 @@ static int dce_virtual_sw_fini(void *handle) kfree(adev->mode_info.bios_hardcoded_edid); - drm_kms_helper_poll_fini(adev->ddev); + drm_kms_helper_poll_fini(adev_to_drm(adev)); - drm_mode_config_cleanup(adev->ddev); + drm_mode_config_cleanup(adev_to_drm(adev)); /* clear crtcs pointer to avoid dce irq finish routine access freed data */ memset(adev->mode_info.crtcs, 0, sizeof(adev->mode_info.crtcs[0]) * AMDGPU_MAX_CRTCS); adev->mode_info.mode_config_initialized = false; @@ -602,7 +602,7 @@ static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, if (!encoder) return -ENOMEM; encoder->possible_crtcs = 1 << index; - drm_encoder_init(adev->ddev, encoder, &dce_virtual_encoder_funcs, + drm_encoder_init(adev_to_drm(adev), encoder, &dce_virtual_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs); @@ -613,7 +613,7 @@ static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, } /* add a new connector */ - drm_connector_init(adev->ddev, connector, &dce_virtual_connector_funcs, + drm_connector_init(adev_to_drm(adev), connector, &dce_virtual_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); drm_connector_helper_add(connector, &dce_virtual_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; @@ -663,14 +663,14 @@ static int dce_virtual_pageflip(struct amdgpu_device *adev, if (amdgpu_crtc == NULL) return 0; - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); works = amdgpu_crtc->pflip_works; if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) { DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != " "AMDGPU_FLIP_SUBMITTED(%d)\n", amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); return 0; } @@ -682,7 +682,7 @@ static int dce_virtual_pageflip(struct amdgpu_device *adev, if (works->event) drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); drm_crtc_vblank_put(&amdgpu_crtc->base); amdgpu_bo_unref(&works->old_abo); @@ -697,7 +697,7 @@ static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vbla struct amdgpu_crtc *amdgpu_crtc = container_of(vblank_timer, struct amdgpu_crtc, vblank_timer); struct drm_device *ddev = amdgpu_crtc->base.dev; - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); drm_handle_vblank(ddev, amdgpu_crtc->crtc_id); dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id); diff --git a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c index 1ab261836983..2eab808fffeb 100644 --- a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c +++ b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c @@ -251,7 +251,7 @@ static ssize_t df_v3_6_get_df_cntr_avail(struct device *dev, int i, count; ddev = dev_get_drvdata(dev); - adev = ddev->dev_private; + adev = drm_to_adev(ddev); count = 0; for (i = 0; i < DF_V3_6_MAX_COUNTERS; i++) { @@ -646,7 +646,7 @@ static void df_v3_6_pmc_get_count(struct amdgpu_device *adev, uint64_t config, uint64_t *count) { - uint32_t lo_base_addr, hi_base_addr, lo_val = 0, hi_val = 0; + uint32_t lo_base_addr = 0, hi_base_addr = 0, lo_val = 0, hi_val = 0; *count = 0; switch (adev->asic_type) { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 037a187aa42f..d502e30f67d9 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -3307,6 +3307,29 @@ static void gfx_v10_0_set_kiq_pm4_funcs(struct amdgpu_device *adev) adev->gfx.kiq.pmf = &gfx_v10_0_kiq_pm4_funcs; } +static void gfx_v10_0_init_spm_golden_registers(struct amdgpu_device *adev) +{ + switch (adev->asic_type) { + case CHIP_NAVI10: + soc15_program_register_sequence(adev, + golden_settings_gc_rlc_spm_10_0_nv10, + (const u32)ARRAY_SIZE(golden_settings_gc_rlc_spm_10_0_nv10)); + break; + case CHIP_NAVI14: + soc15_program_register_sequence(adev, + golden_settings_gc_rlc_spm_10_1_nv14, + (const u32)ARRAY_SIZE(golden_settings_gc_rlc_spm_10_1_nv14)); + break; + case CHIP_NAVI12: + soc15_program_register_sequence(adev, + golden_settings_gc_rlc_spm_10_1_2_nv12, + (const u32)ARRAY_SIZE(golden_settings_gc_rlc_spm_10_1_2_nv12)); + break; + default: + break; + } +} + static void gfx_v10_0_init_golden_registers(struct amdgpu_device *adev) { switch (adev->asic_type) { @@ -3317,9 +3340,6 @@ static void gfx_v10_0_init_golden_registers(struct amdgpu_device *adev) soc15_program_register_sequence(adev, golden_settings_gc_10_0_nv10, (const u32)ARRAY_SIZE(golden_settings_gc_10_0_nv10)); - soc15_program_register_sequence(adev, - golden_settings_gc_rlc_spm_10_0_nv10, - (const u32)ARRAY_SIZE(golden_settings_gc_rlc_spm_10_0_nv10)); break; case CHIP_NAVI14: soc15_program_register_sequence(adev, @@ -3328,9 +3348,6 @@ static void gfx_v10_0_init_golden_registers(struct amdgpu_device *adev) soc15_program_register_sequence(adev, golden_settings_gc_10_1_nv14, (const u32)ARRAY_SIZE(golden_settings_gc_10_1_nv14)); - soc15_program_register_sequence(adev, - golden_settings_gc_rlc_spm_10_1_nv14, - (const u32)ARRAY_SIZE(golden_settings_gc_rlc_spm_10_1_nv14)); break; case CHIP_NAVI12: soc15_program_register_sequence(adev, @@ -3339,9 +3356,6 @@ static void gfx_v10_0_init_golden_registers(struct amdgpu_device *adev) soc15_program_register_sequence(adev, golden_settings_gc_10_1_2_nv12, (const u32)ARRAY_SIZE(golden_settings_gc_10_1_2_nv12)); - soc15_program_register_sequence(adev, - golden_settings_gc_rlc_spm_10_1_2_nv12, - (const u32)ARRAY_SIZE(golden_settings_gc_rlc_spm_10_1_2_nv12)); break; case CHIP_SIENNA_CICHLID: soc15_program_register_sequence(adev, @@ -3360,6 +3374,7 @@ static void gfx_v10_0_init_golden_registers(struct amdgpu_device *adev) default: break; } + gfx_v10_0_init_spm_golden_registers(adev); } static void gfx_v10_0_scratch_init(struct amdgpu_device *adev) @@ -4022,21 +4037,23 @@ static int gfx_v10_0_mec_init(struct amdgpu_device *adev) amdgpu_gfx_compute_queue_acquire(adev); mec_hpd_size = adev->gfx.num_compute_rings * GFX10_MEC_HPD_SIZE; - r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_GTT, - &adev->gfx.mec.hpd_eop_obj, - &adev->gfx.mec.hpd_eop_gpu_addr, - (void **)&hpd); - if (r) { - dev_warn(adev->dev, "(%d) create HDP EOP bo failed\n", r); - gfx_v10_0_mec_fini(adev); - return r; - } + if (mec_hpd_size) { + r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, + &adev->gfx.mec.hpd_eop_obj, + &adev->gfx.mec.hpd_eop_gpu_addr, + (void **)&hpd); + if (r) { + dev_warn(adev->dev, "(%d) create HDP EOP bo failed\n", r); + gfx_v10_0_mec_fini(adev); + return r; + } - memset(hpd, 0, mec_hpd_size); + memset(hpd, 0, mec_hpd_size); - amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); - amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); + amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); + amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); + } if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) { mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; @@ -4147,6 +4164,7 @@ static const struct amdgpu_gfx_funcs gfx_v10_0_gfx_funcs = { .read_wave_sgprs = &gfx_v10_0_read_wave_sgprs, .read_wave_vgprs = &gfx_v10_0_read_wave_vgprs, .select_me_pipe_q = &gfx_v10_0_select_me_pipe_q, + .init_spm_golden = &gfx_v10_0_init_spm_golden_registers, }; static void gfx_v10_0_gpu_early_init(struct amdgpu_device *adev) @@ -6180,7 +6198,7 @@ static int gfx_v10_0_gfx_init_queue(struct amdgpu_ring *ring) struct v10_gfx_mqd *mqd = ring->mqd_ptr; int mqd_idx = ring - &adev->gfx.gfx_ring[0]; - if (!adev->in_gpu_reset && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { memset((void *)mqd, 0, sizeof(*mqd)); mutex_lock(&adev->srbm_mutex); nv_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); @@ -6192,7 +6210,7 @@ static int gfx_v10_0_gfx_init_queue(struct amdgpu_ring *ring) mutex_unlock(&adev->srbm_mutex); if (adev->gfx.me.mqd_backup[mqd_idx]) memcpy(adev->gfx.me.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); - } else if (adev->in_gpu_reset) { + } else if (amdgpu_in_reset(adev)) { /* reset mqd with the backup copy */ if (adev->gfx.me.mqd_backup[mqd_idx]) memcpy(mqd, adev->gfx.me.mqd_backup[mqd_idx], sizeof(*mqd)); @@ -6433,6 +6451,10 @@ static int gfx_v10_0_kiq_init_register(struct amdgpu_ring *ring) struct v10_compute_mqd *mqd = ring->mqd_ptr; int j; + /* inactivate the queue */ + if (amdgpu_sriov_vf(adev)) + WREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE, 0); + /* disable wptr polling */ WREG32_FIELD15(GC, 0, CP_PQ_WPTR_POLL_CNTL, EN, 0); @@ -6541,7 +6563,7 @@ static int gfx_v10_0_kiq_init_queue(struct amdgpu_ring *ring) gfx_v10_0_kiq_setting(ring); - if (adev->in_gpu_reset) { /* for GPU_RESET case */ + if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(*mqd)); @@ -6577,7 +6599,7 @@ static int gfx_v10_0_kcq_init_queue(struct amdgpu_ring *ring) struct v10_compute_mqd *mqd = ring->mqd_ptr; int mqd_idx = ring - &adev->gfx.compute_ring[0]; - if (!adev->in_gpu_reset && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { memset((void *)mqd, 0, sizeof(*mqd)); mutex_lock(&adev->srbm_mutex); nv_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); @@ -6587,7 +6609,7 @@ static int gfx_v10_0_kcq_init_queue(struct amdgpu_ring *ring) if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); - } else if (adev->in_gpu_reset) { /* for GPU_RESET case */ + } else if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(*mqd)); @@ -7033,8 +7055,7 @@ static int gfx_v10_0_soft_reset(void *handle) GRBM_STATUS__BCI_BUSY_MASK | GRBM_STATUS__SX_BUSY_MASK | GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK | GRBM_STATUS__GDS_BUSY_MASK | - GRBM_STATUS__SPI_BUSY_MASK | GRBM_STATUS__GE_BUSY_NO_DMA_MASK - | GRBM_STATUS__BCI_BUSY_MASK)) { + GRBM_STATUS__SPI_BUSY_MASK | GRBM_STATUS__GE_BUSY_NO_DMA_MASK)) { grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP, 1); @@ -7159,7 +7180,7 @@ static int gfx_v10_0_early_init(void *handle) break; } - adev->gfx.num_compute_rings = AMDGPU_MAX_COMPUTE_RINGS; + adev->gfx.num_compute_rings = amdgpu_num_kcq; gfx_v10_0_set_kiq_pm4_funcs(adev); gfx_v10_0_set_ring_funcs(adev); @@ -7427,7 +7448,6 @@ static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev, (AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_CGLS | AMD_CG_SUPPORT_GFX_CGCG | - AMD_CG_SUPPORT_GFX_CGLS | AMD_CG_SUPPORT_GFX_3D_CGCG | AMD_CG_SUPPORT_GFX_3D_CGLS)) gfx_v10_0_enable_gui_idle_interrupt(adev, enable); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 88f63d7ea371..94b7e0531d09 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1343,21 +1343,22 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev) amdgpu_gfx_compute_queue_acquire(adev); mec_hpd_size = adev->gfx.num_compute_rings * GFX8_MEC_HPD_SIZE; + if (mec_hpd_size) { + r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &adev->gfx.mec.hpd_eop_obj, + &adev->gfx.mec.hpd_eop_gpu_addr, + (void **)&hpd); + if (r) { + dev_warn(adev->dev, "(%d) create HDP EOP bo failed\n", r); + return r; + } - r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, - &adev->gfx.mec.hpd_eop_obj, - &adev->gfx.mec.hpd_eop_gpu_addr, - (void **)&hpd); - if (r) { - dev_warn(adev->dev, "(%d) create HDP EOP bo failed\n", r); - return r; - } - - memset(hpd, 0, mec_hpd_size); + memset(hpd, 0, mec_hpd_size); - amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); - amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); + amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); + amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); + } return 0; } @@ -4632,7 +4633,7 @@ static int gfx_v8_0_kiq_init_queue(struct amdgpu_ring *ring) gfx_v8_0_kiq_setting(ring); - if (adev->in_gpu_reset) { /* for GPU_RESET case */ + if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct vi_mqd_allocation)); @@ -4669,7 +4670,7 @@ static int gfx_v8_0_kcq_init_queue(struct amdgpu_ring *ring) struct vi_mqd *mqd = ring->mqd_ptr; int mqd_idx = ring - &adev->gfx.compute_ring[0]; - if (!adev->in_gpu_reset && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { memset((void *)mqd, 0, sizeof(struct vi_mqd_allocation)); ((struct vi_mqd_allocation *)mqd)->dynamic_cu_mask = 0xFFFFFFFF; ((struct vi_mqd_allocation *)mqd)->dynamic_rb_mask = 0xFFFFFFFF; @@ -4681,7 +4682,7 @@ static int gfx_v8_0_kcq_init_queue(struct amdgpu_ring *ring) if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct vi_mqd_allocation)); - } else if (adev->in_gpu_reset) { /* for GPU_RESET case */ + } else if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct vi_mqd_allocation)); @@ -5294,7 +5295,7 @@ static int gfx_v8_0_early_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; adev->gfx.num_gfx_rings = GFX8_NUM_GFX_RINGS; - adev->gfx.num_compute_rings = AMDGPU_MAX_COMPUTE_RINGS; + adev->gfx.num_compute_rings = amdgpu_num_kcq; adev->gfx.funcs = &gfx_v8_0_gfx_funcs; gfx_v8_0_set_ring_funcs(adev); gfx_v8_0_set_irq_funcs(adev); @@ -5342,10 +5343,9 @@ static int gfx_v8_0_late_init(void *handle) static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, bool enable) { - if (((adev->asic_type == CHIP_POLARIS11) || + if ((adev->asic_type == CHIP_POLARIS11) || (adev->asic_type == CHIP_POLARIS12) || - (adev->asic_type == CHIP_VEGAM)) && - adev->powerplay.pp_funcs->set_powergating_by_smu) + (adev->asic_type == CHIP_VEGAM)) /* Send msg to SMU via Powerplay */ amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, enable); @@ -5879,8 +5879,7 @@ static int gfx_v8_0_tonga_update_gfx_clock_gating(struct amdgpu_device *adev, PP_BLOCK_GFX_CG, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_MGLS)) { @@ -5901,8 +5900,7 @@ static int gfx_v8_0_tonga_update_gfx_clock_gating(struct amdgpu_device *adev, PP_BLOCK_GFX_MG, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } return 0; @@ -5931,8 +5929,7 @@ static int gfx_v8_0_polaris_update_gfx_clock_gating(struct amdgpu_device *adev, PP_BLOCK_GFX_CG, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_3D_CGCG | AMD_CG_SUPPORT_GFX_3D_CGLS)) { @@ -5951,8 +5948,7 @@ static int gfx_v8_0_polaris_update_gfx_clock_gating(struct amdgpu_device *adev, PP_BLOCK_GFX_3D, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_MGLS)) { @@ -5973,8 +5969,7 @@ static int gfx_v8_0_polaris_update_gfx_clock_gating(struct amdgpu_device *adev, PP_BLOCK_GFX_MG, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & AMD_CG_SUPPORT_GFX_RLC_LS) { @@ -5989,8 +5984,7 @@ static int gfx_v8_0_polaris_update_gfx_clock_gating(struct amdgpu_device *adev, PP_BLOCK_GFX_RLC, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS) { @@ -6004,8 +5998,7 @@ static int gfx_v8_0_polaris_update_gfx_clock_gating(struct amdgpu_device *adev, PP_BLOCK_GFX_CP, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index b95f22262a90..93c63ff3b35e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1939,22 +1939,23 @@ static int gfx_v9_0_mec_init(struct amdgpu_device *adev) /* take ownership of the relevant compute queues */ amdgpu_gfx_compute_queue_acquire(adev); mec_hpd_size = adev->gfx.num_compute_rings * GFX9_MEC_HPD_SIZE; + if (mec_hpd_size) { + r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &adev->gfx.mec.hpd_eop_obj, + &adev->gfx.mec.hpd_eop_gpu_addr, + (void **)&hpd); + if (r) { + dev_warn(adev->dev, "(%d) create HDP EOP bo failed\n", r); + gfx_v9_0_mec_fini(adev); + return r; + } - r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, - &adev->gfx.mec.hpd_eop_obj, - &adev->gfx.mec.hpd_eop_gpu_addr, - (void **)&hpd); - if (r) { - dev_warn(adev->dev, "(%d) create HDP EOP bo failed\n", r); - gfx_v9_0_mec_fini(adev); - return r; - } - - memset(hpd, 0, mec_hpd_size); + memset(hpd, 0, mec_hpd_size); - amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); - amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); + amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj); + amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj); + } mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; @@ -3685,7 +3686,7 @@ static int gfx_v9_0_kiq_init_queue(struct amdgpu_ring *ring) gfx_v9_0_kiq_setting(ring); - if (adev->in_gpu_reset) { /* for GPU_RESET case */ + if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct v9_mqd_allocation)); @@ -3723,7 +3724,7 @@ static int gfx_v9_0_kcq_init_queue(struct amdgpu_ring *ring) struct v9_mqd *mqd = ring->mqd_ptr; int mqd_idx = ring - &adev->gfx.compute_ring[0]; - if (!adev->in_gpu_reset && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { memset((void *)mqd, 0, sizeof(struct v9_mqd_allocation)); ((struct v9_mqd_allocation *)mqd)->dynamic_cu_mask = 0xFFFFFFFF; ((struct v9_mqd_allocation *)mqd)->dynamic_rb_mask = 0xFFFFFFFF; @@ -3735,7 +3736,7 @@ static int gfx_v9_0_kcq_init_queue(struct amdgpu_ring *ring) if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(struct v9_mqd_allocation)); - } else if (adev->in_gpu_reset) { /* for GPU_RESET case */ + } else if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct v9_mqd_allocation)); @@ -3929,7 +3930,7 @@ static int gfx_v9_0_hw_fini(void *handle) /* Use deinitialize sequence from CAIL when unbinding device from driver, * otherwise KIQ is hanging when binding back */ - if (!adev->in_gpu_reset && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { mutex_lock(&adev->srbm_mutex); soc15_grbm_select(adev, adev->gfx.kiq.ring.me, adev->gfx.kiq.ring.pipe, @@ -4087,7 +4088,7 @@ static uint64_t gfx_v9_0_kiq_read_clock(struct amdgpu_device *adev) * * also don't wait anymore for IRQ context * */ - if (r < 1 && (adev->in_gpu_reset || in_interrupt())) + if (r < 1 && (amdgpu_in_reset(adev) || in_interrupt())) goto failed_kiq_read; might_sleep(); @@ -4626,7 +4627,7 @@ static int gfx_v9_0_early_init(void *handle) adev->gfx.num_gfx_rings = 0; else adev->gfx.num_gfx_rings = GFX9_NUM_GFX_RINGS; - adev->gfx.num_compute_rings = AMDGPU_MAX_COMPUTE_RINGS; + adev->gfx.num_compute_rings = amdgpu_num_kcq; gfx_v9_0_set_kiq_pm4_funcs(adev); gfx_v9_0_set_ring_funcs(adev); gfx_v9_0_set_irq_funcs(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c index 46351db36922..bd85aed3523a 100755..100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c @@ -57,10 +57,10 @@ static const struct soc15_reg_entry gfx_v9_4_edc_counter_regs[] = { /* SPI */ { SOC15_REG_ENTRY(GC, 0, mmSPI_EDC_CNT), 0, 4, 1 }, /* SQ */ - { SOC15_REG_ENTRY(GC, 0, mmSQ_EDC_CNT), 0, 4, 16 }, - { SOC15_REG_ENTRY(GC, 0, mmSQ_EDC_DED_CNT), 0, 4, 16 }, - { SOC15_REG_ENTRY(GC, 0, mmSQ_EDC_INFO), 0, 4, 16 }, - { SOC15_REG_ENTRY(GC, 0, mmSQ_EDC_SEC_CNT), 0, 4, 16 }, + { SOC15_REG_ENTRY(GC, 0, mmSQ_EDC_CNT), 0, 8, 16 }, + { SOC15_REG_ENTRY(GC, 0, mmSQ_EDC_DED_CNT), 0, 8, 16 }, + { SOC15_REG_ENTRY(GC, 0, mmSQ_EDC_INFO), 0, 8, 16 }, + { SOC15_REG_ENTRY(GC, 0, mmSQ_EDC_SEC_CNT), 0, 8, 16 }, /* SQC */ { SOC15_REG_ENTRY(GC, 0, mmSQC_EDC_CNT), 0, 4, 6 }, { SOC15_REG_ENTRY(GC, 0, mmSQC_EDC_CNT2), 0, 4, 6 }, diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c index 394e6f56948a..b882ac59879a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c @@ -31,6 +31,77 @@ #include "soc15_common.h" +static const char *gfxhub_client_ids[] = { + "CB/DB", + "Reserved", + "GE1", + "GE2", + "CPF", + "CPC", + "CPG", + "RLC", + "TCP", + "SQC (inst)", + "SQC (data)", + "SQG", + "Reserved", + "SDMA0", + "SDMA1", + "GCR", + "SDMA2", + "SDMA3", +}; + +static uint32_t gfxhub_v2_0_get_invalidate_req(unsigned int vmid, + uint32_t flush_type) +{ + u32 req = 0; + + /* invalidate using legacy mode on vmid*/ + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, + PER_VMID_INVALIDATE_REQ, 1 << vmid); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, FLUSH_TYPE, flush_type); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PTES, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE0, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE1, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE2, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L1_PTES, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, + CLEAR_PROTECTION_FAULT_STATUS_ADDR, 0); + + return req; +} + +static void +gfxhub_v2_0_print_l2_protection_fault_status(struct amdgpu_device *adev, + uint32_t status) +{ + u32 cid = REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, CID); + + dev_err(adev->dev, + "GCVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", + status); + dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", + cid >= ARRAY_SIZE(gfxhub_client_ids) ? "unknown" : gfxhub_client_ids[cid], + cid); + dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, MORE_FAULTS)); + dev_err(adev->dev, "\t WALKER_ERROR: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, WALKER_ERROR)); + dev_err(adev->dev, "\t PERMISSION_FAULTS: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, PERMISSION_FAULTS)); + dev_err(adev->dev, "\t MAPPING_ERROR: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, MAPPING_ERROR)); + dev_err(adev->dev, "\t RW: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, RW)); +} + u64 gfxhub_v2_0_get_fb_location(struct amdgpu_device *adev) { u64 base = RREG32_SOC15(GC, 0, mmGCMC_VM_FB_LOCATION_BASE); @@ -360,6 +431,11 @@ void gfxhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev, WREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL, tmp); } +static const struct amdgpu_vmhub_funcs gfxhub_v2_0_vmhub_funcs = { + .print_l2_protection_fault_status = gfxhub_v2_0_print_l2_protection_fault_status, + .get_invalidate_req = gfxhub_v2_0_get_invalidate_req, +}; + void gfxhub_v2_0_init(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_GFXHUB_0]; @@ -390,4 +466,14 @@ void gfxhub_v2_0_init(struct amdgpu_device *adev) mmGCVM_INVALIDATE_ENG0_REQ; hub->eng_addr_distance = mmGCVM_INVALIDATE_ENG1_ADDR_RANGE_LO32 - mmGCVM_INVALIDATE_ENG0_ADDR_RANGE_LO32; + + hub->vm_cntx_cntl_vm_fault = GCVM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; + + hub->vmhub_funcs = &gfxhub_v2_0_vmhub_funcs; } diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c index 5d2505956f84..237a9ff5afa0 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c @@ -31,6 +31,77 @@ #include "soc15_common.h" +static const char *gfxhub_client_ids[] = { + "CB/DB", + "Reserved", + "GE1", + "GE2", + "CPF", + "CPC", + "CPG", + "RLC", + "TCP", + "SQC (inst)", + "SQC (data)", + "SQG", + "Reserved", + "SDMA0", + "SDMA1", + "GCR", + "SDMA2", + "SDMA3", +}; + +static uint32_t gfxhub_v2_1_get_invalidate_req(unsigned int vmid, + uint32_t flush_type) +{ + u32 req = 0; + + /* invalidate using legacy mode on vmid*/ + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, + PER_VMID_INVALIDATE_REQ, 1 << vmid); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, FLUSH_TYPE, flush_type); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PTES, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE0, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE1, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE2, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L1_PTES, 1); + req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, + CLEAR_PROTECTION_FAULT_STATUS_ADDR, 0); + + return req; +} + +static void +gfxhub_v2_1_print_l2_protection_fault_status(struct amdgpu_device *adev, + uint32_t status) +{ + u32 cid = REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, CID); + + dev_err(adev->dev, + "GCVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", + status); + dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", + cid >= ARRAY_SIZE(gfxhub_client_ids) ? "unknown" : gfxhub_client_ids[cid], + cid); + dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, MORE_FAULTS)); + dev_err(adev->dev, "\t WALKER_ERROR: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, WALKER_ERROR)); + dev_err(adev->dev, "\t PERMISSION_FAULTS: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, PERMISSION_FAULTS)); + dev_err(adev->dev, "\t MAPPING_ERROR: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, MAPPING_ERROR)); + dev_err(adev->dev, "\t RW: 0x%lx\n", + REG_GET_FIELD(status, + GCVM_L2_PROTECTION_FAULT_STATUS, RW)); +} + u64 gfxhub_v2_1_get_fb_location(struct amdgpu_device *adev) { u64 base = RREG32_SOC15(GC, 0, mmGCMC_VM_FB_LOCATION_BASE); @@ -378,6 +449,11 @@ void gfxhub_v2_1_set_fault_enable_default(struct amdgpu_device *adev, WREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL, tmp); } +static const struct amdgpu_vmhub_funcs gfxhub_v2_1_vmhub_funcs = { + .print_l2_protection_fault_status = gfxhub_v2_1_print_l2_protection_fault_status, + .get_invalidate_req = gfxhub_v2_1_get_invalidate_req, +}; + void gfxhub_v2_1_init(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_GFXHUB_0]; @@ -408,6 +484,16 @@ void gfxhub_v2_1_init(struct amdgpu_device *adev) mmGCVM_INVALIDATE_ENG0_REQ; hub->eng_addr_distance = mmGCVM_INVALIDATE_ENG1_ADDR_RANGE_LO32 - mmGCVM_INVALIDATE_ENG0_ADDR_RANGE_LO32; + + hub->vm_cntx_cntl_vm_fault = GCVM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + GCVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; + + hub->vmhub_funcs = &gfxhub_v2_1_vmhub_funcs; } int gfxhub_v2_1_get_xgmi_info(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index ec90c62078d9..31359e519d69 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -25,11 +25,10 @@ #include "amdgpu.h" #include "amdgpu_atomfirmware.h" #include "gmc_v10_0.h" +#include "umc_v8_7.h" #include "hdp/hdp_5_0_0_offset.h" #include "hdp/hdp_5_0_0_sh_mask.h" -#include "gc/gc_10_1_0_sh_mask.h" -#include "mmhub/mmhub_2_0_0_sh_mask.h" #include "athub/athub_2_0_0_sh_mask.h" #include "athub/athub_2_0_0_offset.h" #include "dcn/dcn_2_0_0_offset.h" @@ -57,68 +56,31 @@ static const struct soc15_reg_golden golden_settings_navi10_hdp[] = }; #endif +static int gmc_v10_0_ecc_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *src, + unsigned type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + static int gmc_v10_0_vm_fault_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type, enum amdgpu_interrupt_state state) { - struct amdgpu_vmhub *hub; - u32 tmp, reg, bits[AMDGPU_MAX_VMHUBS], i; - - bits[AMDGPU_GFXHUB_0] = GCVM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - GCVM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - GCVM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - GCVM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - GCVM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - GCVM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - GCVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; - - bits[AMDGPU_MMHUB_0] = MMVM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - MMVM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - MMVM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - MMVM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - MMVM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - MMVM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; - switch (state) { case AMDGPU_IRQ_STATE_DISABLE: /* MM HUB */ - hub = &adev->vmhub[AMDGPU_MMHUB_0]; - for (i = 0; i < 16; i++) { - reg = hub->vm_context0_cntl + hub->ctx_distance * i; - tmp = RREG32(reg); - tmp &= ~bits[AMDGPU_MMHUB_0]; - WREG32(reg, tmp); - } - + amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, false); /* GFX HUB */ - hub = &adev->vmhub[AMDGPU_GFXHUB_0]; - for (i = 0; i < 16; i++) { - reg = hub->vm_context0_cntl + hub->ctx_distance * i; - tmp = RREG32(reg); - tmp &= ~bits[AMDGPU_GFXHUB_0]; - WREG32(reg, tmp); - } + amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false); break; case AMDGPU_IRQ_STATE_ENABLE: /* MM HUB */ - hub = &adev->vmhub[AMDGPU_MMHUB_0]; - for (i = 0; i < 16; i++) { - reg = hub->vm_context0_cntl + hub->ctx_distance * i; - tmp = RREG32(reg); - tmp |= bits[AMDGPU_MMHUB_0]; - WREG32(reg, tmp); - } - + amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, true); /* GFX HUB */ - hub = &adev->vmhub[AMDGPU_GFXHUB_0]; - for (i = 0; i < 16; i++) { - reg = hub->vm_context0_cntl + hub->ctx_distance * i; - tmp = RREG32(reg); - tmp |= bits[AMDGPU_GFXHUB_0]; - WREG32(reg, tmp); - } + amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true); break; default: break; @@ -166,29 +128,8 @@ static int gmc_v10_0_process_interrupt(struct amdgpu_device *adev, task_info.task_name, task_info.pid); dev_err(adev->dev, " in page starting at address 0x%016llx from client %d\n", addr, entry->client_id); - if (!amdgpu_sriov_vf(adev)) { - dev_err(adev->dev, - "GCVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", - status); - dev_err(adev->dev, "\t Faulty UTCL2 client ID: 0x%lx\n", - REG_GET_FIELD(status, - GCVM_L2_PROTECTION_FAULT_STATUS, CID)); - dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", - REG_GET_FIELD(status, - GCVM_L2_PROTECTION_FAULT_STATUS, MORE_FAULTS)); - dev_err(adev->dev, "\t WALKER_ERROR: 0x%lx\n", - REG_GET_FIELD(status, - GCVM_L2_PROTECTION_FAULT_STATUS, WALKER_ERROR)); - dev_err(adev->dev, "\t PERMISSION_FAULTS: 0x%lx\n", - REG_GET_FIELD(status, - GCVM_L2_PROTECTION_FAULT_STATUS, PERMISSION_FAULTS)); - dev_err(adev->dev, "\t MAPPING_ERROR: 0x%lx\n", - REG_GET_FIELD(status, - GCVM_L2_PROTECTION_FAULT_STATUS, MAPPING_ERROR)); - dev_err(adev->dev, "\t RW: 0x%lx\n", - REG_GET_FIELD(status, - GCVM_L2_PROTECTION_FAULT_STATUS, RW)); - } + if (!amdgpu_sriov_vf(adev)) + hub->vmhub_funcs->print_l2_protection_fault_status(adev, status); } return 0; @@ -199,30 +140,20 @@ static const struct amdgpu_irq_src_funcs gmc_v10_0_irq_funcs = { .process = gmc_v10_0_process_interrupt, }; -static void gmc_v10_0_set_irq_funcs(struct amdgpu_device *adev) +static const struct amdgpu_irq_src_funcs gmc_v10_0_ecc_funcs = { + .set = gmc_v10_0_ecc_interrupt_state, + .process = amdgpu_umc_process_ecc_irq, +}; + + static void gmc_v10_0_set_irq_funcs(struct amdgpu_device *adev) { adev->gmc.vm_fault.num_types = 1; adev->gmc.vm_fault.funcs = &gmc_v10_0_irq_funcs; -} -static uint32_t gmc_v10_0_get_invalidate_req(unsigned int vmid, - uint32_t flush_type) -{ - u32 req = 0; - - /* invalidate using legacy mode on vmid*/ - req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, - PER_VMID_INVALIDATE_REQ, 1 << vmid); - req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, FLUSH_TYPE, flush_type); - req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PTES, 1); - req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE0, 1); - req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE1, 1); - req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE2, 1); - req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, INVALIDATE_L1_PTES, 1); - req = REG_SET_FIELD(req, GCVM_INVALIDATE_ENG0_REQ, - CLEAR_PROTECTION_FAULT_STATUS_ADDR, 0); - - return req; + if (!amdgpu_sriov_vf(adev)) { + adev->gmc.ecc_irq.num_types = 1; + adev->gmc.ecc_irq.funcs = &gmc_v10_0_ecc_funcs; + } } /** @@ -265,7 +196,7 @@ static void gmc_v10_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid, { bool use_semaphore = gmc_v10_0_use_invalidate_semaphore(adev, vmhub); struct amdgpu_vmhub *hub = &adev->vmhub[vmhub]; - u32 inv_req = gmc_v10_0_get_invalidate_req(vmid, flush_type); + u32 inv_req = hub->vmhub_funcs->get_invalidate_req(vmid, flush_type); u32 tmp; /* Use register 17 for GART */ const unsigned eng = 17; @@ -356,16 +287,17 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, */ if (adev->gfx.kiq.ring.sched.ready && (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev)) && - !adev->in_gpu_reset) { - + down_read_trylock(&adev->reset_sem)) { struct amdgpu_vmhub *hub = &adev->vmhub[vmhub]; const unsigned eng = 17; - u32 inv_req = gmc_v10_0_get_invalidate_req(vmid, flush_type); + u32 inv_req = hub->vmhub_funcs->get_invalidate_req(vmid, flush_type); u32 req = hub->vm_inv_eng0_req + hub->eng_distance * eng; u32 ack = hub->vm_inv_eng0_ack + hub->eng_distance * eng; amdgpu_virt_kiq_reg_write_reg_wait(adev, req, ack, inv_req, 1 << vmid); + + up_read(&adev->reset_sem); return; } @@ -381,7 +313,7 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, if (!adev->mman.buffer_funcs_enabled || !adev->ib_pool_ready || - adev->in_gpu_reset || + amdgpu_in_reset(adev) || ring->sched.ready == false) { gmc_v10_0_flush_vm_hub(adev, vmid, AMDGPU_GFXHUB_0, 0); mutex_unlock(&adev->mman.gtt_window_lock); @@ -459,7 +391,7 @@ static int gmc_v10_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, spin_unlock(&adev->gfx.kiq.ring_lock); r = amdgpu_fence_wait_polling(ring, seq, adev->usec_timeout); if (r < 1) { - DRM_ERROR("wait for kiq fence error: %ld.\n", r); + dev_err(adev->dev, "wait for kiq fence error: %ld.\n", r); return -ETIME; } @@ -491,7 +423,7 @@ static uint64_t gmc_v10_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, { bool use_semaphore = gmc_v10_0_use_invalidate_semaphore(ring->adev, ring->funcs->vmhub); struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t req = gmc_v10_0_get_invalidate_req(vmid, 0); + uint32_t req = hub->vmhub_funcs->get_invalidate_req(vmid, 0); unsigned eng = ring->vm_inv_eng; /* @@ -641,6 +573,28 @@ static void gmc_v10_0_get_vm_pte(struct amdgpu_device *adev, } } +static unsigned gmc_v10_0_get_vbios_fb_size(struct amdgpu_device *adev) +{ + u32 d1vga_control = RREG32_SOC15(DCE, 0, mmD1VGA_CONTROL); + unsigned size; + + if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { + size = AMDGPU_VBIOS_VGA_ALLOCATION; + } else { + u32 viewport; + u32 pitch; + + viewport = RREG32_SOC15(DCE, 0, mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION); + pitch = RREG32_SOC15(DCE, 0, mmHUBPREQ0_DCSURF_SURFACE_PITCH); + size = (REG_GET_FIELD(viewport, + HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT) * + REG_GET_FIELD(pitch, HUBPREQ0_DCSURF_SURFACE_PITCH, PITCH) * + 4); + } + + return size; +} + static const struct amdgpu_gmc_funcs gmc_v10_0_gmc_funcs = { .flush_gpu_tlb = gmc_v10_0_flush_gpu_tlb, .flush_gpu_tlb_pasid = gmc_v10_0_flush_gpu_tlb_pasid, @@ -648,7 +602,8 @@ static const struct amdgpu_gmc_funcs gmc_v10_0_gmc_funcs = { .emit_pasid_mapping = gmc_v10_0_emit_pasid_mapping, .map_mtype = gmc_v10_0_map_mtype, .get_vm_pde = gmc_v10_0_get_vm_pde, - .get_vm_pte = gmc_v10_0_get_vm_pte + .get_vm_pte = gmc_v10_0_get_vm_pte, + .get_vbios_fb_size = gmc_v10_0_get_vbios_fb_size, }; static void gmc_v10_0_set_gmc_funcs(struct amdgpu_device *adev) @@ -657,12 +612,36 @@ static void gmc_v10_0_set_gmc_funcs(struct amdgpu_device *adev) adev->gmc.gmc_funcs = &gmc_v10_0_gmc_funcs; } +static void gmc_v10_0_set_umc_funcs(struct amdgpu_device *adev) +{ + switch (adev->asic_type) { + case CHIP_SIENNA_CICHLID: + adev->umc.max_ras_err_cnt_per_query = UMC_V8_7_TOTAL_CHANNEL_NUM; + adev->umc.channel_inst_num = UMC_V8_7_CHANNEL_INSTANCE_NUM; + adev->umc.umc_inst_num = UMC_V8_7_UMC_INSTANCE_NUM; + adev->umc.channel_offs = UMC_V8_7_PER_CHANNEL_OFFSET_SIENNA; + adev->umc.channel_idx_tbl = &umc_v8_7_channel_idx_tbl[0][0]; + adev->umc.funcs = &umc_v8_7_funcs; + break; + default: + break; + } +} + + +static void gmc_v10_0_set_mmhub_funcs(struct amdgpu_device *adev) +{ + adev->mmhub.funcs = &mmhub_v2_0_funcs; +} + static int gmc_v10_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + gmc_v10_0_set_mmhub_funcs(adev); gmc_v10_0_set_gmc_funcs(adev); gmc_v10_0_set_irq_funcs(adev); + gmc_v10_0_set_umc_funcs(adev); adev->gmc.shared_aperture_start = 0x2000000000000000ULL; adev->gmc.shared_aperture_end = @@ -685,6 +664,10 @@ static int gmc_v10_0_late_init(void *handle) if (r) return r; + r = amdgpu_gmc_ras_late_init(adev); + if (r) + return r; + return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0); } @@ -789,36 +772,6 @@ static int gmc_v10_0_gart_init(struct amdgpu_device *adev) return amdgpu_gart_table_vram_alloc(adev); } -static unsigned gmc_v10_0_get_vbios_fb_size(struct amdgpu_device *adev) -{ - u32 d1vga_control = RREG32_SOC15(DCE, 0, mmD1VGA_CONTROL); - unsigned size; - - if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { - size = 9 * 1024 * 1024; /* reserve 8MB for vga emulator and 1 MB for FB */ - } else { - u32 viewport; - u32 pitch; - - viewport = RREG32_SOC15(DCE, 0, mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION); - pitch = RREG32_SOC15(DCE, 0, mmHUBPREQ0_DCSURF_SURFACE_PITCH); - size = (REG_GET_FIELD(viewport, - HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT) * - REG_GET_FIELD(pitch, HUBPREQ0_DCSURF_SURFACE_PITCH, PITCH) * - 4); - } - /* return 0 if the pre-OS buffer uses up most of vram */ - if ((adev->gmc.real_vram_size - size) < (8 * 1024 * 1024)) { - DRM_ERROR("Warning: pre-OS buffer uses most of vram, \ - be aware of gart table overwrite\n"); - return 0; - } - - return size; -} - - - static int gmc_v10_0_sw_init(void *handle) { int r, vram_width = 0, vram_type = 0, vram_vendor = 0; @@ -830,7 +783,7 @@ static int gmc_v10_0_sw_init(void *handle) else gfxhub_v2_0_init(adev); - mmhub_v2_0_init(adev); + adev->mmhub.funcs->init(adev); spin_lock_init(&adev->gmc.invalidate_lock); @@ -878,6 +831,14 @@ static int gmc_v10_0_sw_init(void *handle) if (r) return r; + if (!amdgpu_sriov_vf(adev)) { + /* interrupt sent to DF. */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DF, 0, + &adev->gmc.ecc_irq); + if (r) + return r; + } + /* * Set the internal MC address mask This is the max address of the GPU's * internal address space. @@ -900,7 +861,7 @@ static int gmc_v10_0_sw_init(void *handle) if (r) return r; - adev->gmc.stolen_size = gmc_v10_0_get_vbios_fb_size(adev); + amdgpu_gmc_get_vbios_allocations(adev); /* Memory manager */ r = amdgpu_bo_init(adev); @@ -991,7 +952,7 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev) if (r) return r; - r = mmhub_v2_0_gart_enable(adev); + r = adev->mmhub.funcs->gart_enable(adev); if (r) return r; @@ -1013,7 +974,7 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev) gfxhub_v2_1_set_fault_enable_default(adev, value); else gfxhub_v2_0_set_fault_enable_default(adev, value); - mmhub_v2_0_set_fault_enable_default(adev, value); + adev->mmhub.funcs->set_fault_enable_default(adev, value); gmc_v10_0_flush_gpu_tlb(adev, 0, AMDGPU_MMHUB_0, 0); gmc_v10_0_flush_gpu_tlb(adev, 0, AMDGPU_GFXHUB_0, 0); @@ -1038,6 +999,9 @@ static int gmc_v10_0_hw_init(void *handle) if (r) return r; + if (adev->umc.funcs && adev->umc.funcs->init_registers) + adev->umc.funcs->init_registers(adev); + return 0; } @@ -1055,7 +1019,7 @@ static void gmc_v10_0_gart_disable(struct amdgpu_device *adev) gfxhub_v2_1_gart_disable(adev); else gfxhub_v2_0_gart_disable(adev); - mmhub_v2_0_gart_disable(adev); + adev->mmhub.funcs->gart_disable(adev); amdgpu_gart_table_vram_unpin(adev); } @@ -1069,6 +1033,7 @@ static int gmc_v10_0_hw_fini(void *handle) return 0; } + amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v10_0_gart_disable(adev); @@ -1121,7 +1086,7 @@ static int gmc_v10_0_set_clockgating_state(void *handle, int r; struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = mmhub_v2_0_set_clockgating(adev, state); + r = adev->mmhub.funcs->set_clockgating(adev, state); if (r) return r; @@ -1136,7 +1101,7 @@ static void gmc_v10_0_get_clockgating_state(void *handle, u32 *flags) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - mmhub_v2_0_get_clockgating(adev, flags); + adev->mmhub.funcs->get_clockgating(adev, flags); if (adev->asic_type == CHIP_SIENNA_CICHLID || adev->asic_type == CHIP_NAVY_FLOUNDER) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 538e7ee35cdf..95a9117e9564 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -805,16 +805,13 @@ static unsigned gmc_v6_0_get_vbios_fb_size(struct amdgpu_device *adev) unsigned size; if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { - size = 9 * 1024 * 1024; /* reserve 8MB for vga emulator and 1 MB for FB */ + size = AMDGPU_VBIOS_VGA_ALLOCATION; } else { u32 viewport = RREG32(mmVIEWPORT_SIZE); size = (REG_GET_FIELD(viewport, VIEWPORT_SIZE, VIEWPORT_HEIGHT) * REG_GET_FIELD(viewport, VIEWPORT_SIZE, VIEWPORT_WIDTH) * 4); } - /* return 0 if the pre-OS buffer uses up most of vram */ - if ((adev->gmc.real_vram_size - size) < (8 * 1024 * 1024)) - return 0; return size; } @@ -862,7 +859,7 @@ static int gmc_v6_0_sw_init(void *handle) if (r) return r; - adev->gmc.stolen_size = gmc_v6_0_get_vbios_fb_size(adev); + amdgpu_gmc_get_vbios_allocations(adev); r = amdgpu_bo_init(adev); if (r) @@ -1136,6 +1133,7 @@ static const struct amdgpu_gmc_funcs gmc_v6_0_gmc_funcs = { .set_prt = gmc_v6_0_set_prt, .get_vm_pde = gmc_v6_0_get_vm_pde, .get_vm_pte = gmc_v6_0_get_vm_pte, + .get_vbios_fb_size = gmc_v6_0_get_vbios_fb_size, }; static const struct amdgpu_irq_src_funcs gmc_v6_0_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index e18296dc1386..80c146df338a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -434,7 +434,7 @@ static int gmc_v7_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, int vmid; unsigned int tmp; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EIO; for (vmid = 1; vmid < 16; vmid++) { @@ -970,16 +970,14 @@ static unsigned gmc_v7_0_get_vbios_fb_size(struct amdgpu_device *adev) unsigned size; if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { - size = 9 * 1024 * 1024; /* reserve 8MB for vga emulator and 1 MB for FB */ + size = AMDGPU_VBIOS_VGA_ALLOCATION; } else { u32 viewport = RREG32(mmVIEWPORT_SIZE); size = (REG_GET_FIELD(viewport, VIEWPORT_SIZE, VIEWPORT_HEIGHT) * REG_GET_FIELD(viewport, VIEWPORT_SIZE, VIEWPORT_WIDTH) * 4); } - /* return 0 if the pre-OS buffer uses up most of vram */ - if ((adev->gmc.real_vram_size - size) < (8 * 1024 * 1024)) - return 0; + return size; } @@ -1035,7 +1033,7 @@ static int gmc_v7_0_sw_init(void *handle) if (r) return r; - adev->gmc.stolen_size = gmc_v7_0_get_vbios_fb_size(adev); + amdgpu_gmc_get_vbios_allocations(adev); /* Memory manager */ r = amdgpu_bo_init(adev); @@ -1372,7 +1370,8 @@ static const struct amdgpu_gmc_funcs gmc_v7_0_gmc_funcs = { .emit_pasid_mapping = gmc_v7_0_emit_pasid_mapping, .set_prt = gmc_v7_0_set_prt, .get_vm_pde = gmc_v7_0_get_vm_pde, - .get_vm_pte = gmc_v7_0_get_vm_pte + .get_vm_pte = gmc_v7_0_get_vm_pte, + .get_vbios_fb_size = gmc_v7_0_get_vbios_fb_size, }; static const struct amdgpu_irq_src_funcs gmc_v7_0_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index a9e722b8a458..9ab65ca7df77 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -635,7 +635,7 @@ static int gmc_v8_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, int vmid; unsigned int tmp; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EIO; for (vmid = 1; vmid < 16; vmid++) { @@ -1087,16 +1087,14 @@ static unsigned gmc_v8_0_get_vbios_fb_size(struct amdgpu_device *adev) unsigned size; if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { - size = 9 * 1024 * 1024; /* reserve 8MB for vga emulator and 1 MB for FB */ + size = AMDGPU_VBIOS_VGA_ALLOCATION; } else { u32 viewport = RREG32(mmVIEWPORT_SIZE); size = (REG_GET_FIELD(viewport, VIEWPORT_SIZE, VIEWPORT_HEIGHT) * REG_GET_FIELD(viewport, VIEWPORT_SIZE, VIEWPORT_WIDTH) * 4); } - /* return 0 if the pre-OS buffer uses up most of vram */ - if ((adev->gmc.real_vram_size - size) < (8 * 1024 * 1024)) - return 0; + return size; } @@ -1160,7 +1158,7 @@ static int gmc_v8_0_sw_init(void *handle) if (r) return r; - adev->gmc.stolen_size = gmc_v8_0_get_vbios_fb_size(adev); + amdgpu_gmc_get_vbios_allocations(adev); /* Memory manager */ r = amdgpu_bo_init(adev); @@ -1739,7 +1737,8 @@ static const struct amdgpu_gmc_funcs gmc_v8_0_gmc_funcs = { .emit_pasid_mapping = gmc_v8_0_emit_pasid_mapping, .set_prt = gmc_v8_0_set_prt, .get_vm_pde = gmc_v8_0_get_vm_pde, - .get_vm_pte = gmc_v8_0_get_vm_pte + .get_vm_pte = gmc_v8_0_get_vm_pte, + .get_vbios_fb_size = gmc_v8_0_get_vbios_fb_size, }; static const struct amdgpu_irq_src_funcs gmc_v8_0_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index b67ba38a195f..91629c2b1d5c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -67,6 +67,222 @@ #define HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION__PRI_VIEWPORT_HEIGHT__SHIFT 0x10 #define HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION__PRI_VIEWPORT_WIDTH_MASK 0x00003FFFL #define HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION__PRI_VIEWPORT_HEIGHT_MASK 0x3FFF0000L +#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0 0x049d +#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0_BASE_IDX 2 + + +static const char *gfxhub_client_ids[] = { + "CB", + "DB", + "IA", + "WD", + "CPF", + "CPC", + "CPG", + "RLC", + "TCP", + "SQC (inst)", + "SQC (data)", + "SQG", + "PA", +}; + +static const char *mmhub_client_ids_raven[][2] = { + [0][0] = "MP1", + [1][0] = "MP0", + [2][0] = "VCN", + [3][0] = "VCNU", + [4][0] = "HDP", + [5][0] = "DCE", + [13][0] = "UTCL2", + [19][0] = "TLS", + [26][0] = "OSS", + [27][0] = "SDMA0", + [0][1] = "MP1", + [1][1] = "MP0", + [2][1] = "VCN", + [3][1] = "VCNU", + [4][1] = "HDP", + [5][1] = "XDP", + [6][1] = "DBGU0", + [7][1] = "DCE", + [8][1] = "DCEDWB0", + [9][1] = "DCEDWB1", + [26][1] = "OSS", + [27][1] = "SDMA0", +}; + +static const char *mmhub_client_ids_renoir[][2] = { + [0][0] = "MP1", + [1][0] = "MP0", + [2][0] = "HDP", + [4][0] = "DCEDMC", + [5][0] = "DCEVGA", + [13][0] = "UTCL2", + [19][0] = "TLS", + [26][0] = "OSS", + [27][0] = "SDMA0", + [28][0] = "VCN", + [29][0] = "VCNU", + [30][0] = "JPEG", + [0][1] = "MP1", + [1][1] = "MP0", + [2][1] = "HDP", + [3][1] = "XDP", + [6][1] = "DBGU0", + [7][1] = "DCEDMC", + [8][1] = "DCEVGA", + [9][1] = "DCEDWB", + [26][1] = "OSS", + [27][1] = "SDMA0", + [28][1] = "VCN", + [29][1] = "VCNU", + [30][1] = "JPEG", +}; + +static const char *mmhub_client_ids_vega10[][2] = { + [0][0] = "MP0", + [1][0] = "UVD", + [2][0] = "UVDU", + [3][0] = "HDP", + [13][0] = "UTCL2", + [14][0] = "OSS", + [15][0] = "SDMA1", + [32+0][0] = "VCE0", + [32+1][0] = "VCE0U", + [32+2][0] = "XDMA", + [32+3][0] = "DCE", + [32+4][0] = "MP1", + [32+14][0] = "SDMA0", + [0][1] = "MP0", + [1][1] = "UVD", + [2][1] = "UVDU", + [3][1] = "DBGU0", + [4][1] = "HDP", + [5][1] = "XDP", + [14][1] = "OSS", + [15][1] = "SDMA0", + [32+0][1] = "VCE0", + [32+1][1] = "VCE0U", + [32+2][1] = "XDMA", + [32+3][1] = "DCE", + [32+4][1] = "DCEDWB", + [32+5][1] = "MP1", + [32+6][1] = "DBGU1", + [32+14][1] = "SDMA1", +}; + +static const char *mmhub_client_ids_vega12[][2] = { + [0][0] = "MP0", + [1][0] = "VCE0", + [2][0] = "VCE0U", + [3][0] = "HDP", + [13][0] = "UTCL2", + [14][0] = "OSS", + [15][0] = "SDMA1", + [32+0][0] = "DCE", + [32+1][0] = "XDMA", + [32+2][0] = "UVD", + [32+3][0] = "UVDU", + [32+4][0] = "MP1", + [32+15][0] = "SDMA0", + [0][1] = "MP0", + [1][1] = "VCE0", + [2][1] = "VCE0U", + [3][1] = "DBGU0", + [4][1] = "HDP", + [5][1] = "XDP", + [14][1] = "OSS", + [15][1] = "SDMA0", + [32+0][1] = "DCE", + [32+1][1] = "DCEDWB", + [32+2][1] = "XDMA", + [32+3][1] = "UVD", + [32+4][1] = "UVDU", + [32+5][1] = "MP1", + [32+6][1] = "DBGU1", + [32+15][1] = "SDMA1", +}; + +static const char *mmhub_client_ids_vega20[][2] = { + [0][0] = "XDMA", + [1][0] = "DCE", + [2][0] = "VCE0", + [3][0] = "VCE0U", + [4][0] = "UVD", + [5][0] = "UVD1U", + [13][0] = "OSS", + [14][0] = "HDP", + [15][0] = "SDMA0", + [32+0][0] = "UVD", + [32+1][0] = "UVDU", + [32+2][0] = "MP1", + [32+3][0] = "MP0", + [32+12][0] = "UTCL2", + [32+14][0] = "SDMA1", + [0][1] = "XDMA", + [1][1] = "DCE", + [2][1] = "DCEDWB", + [3][1] = "VCE0", + [4][1] = "VCE0U", + [5][1] = "UVD1", + [6][1] = "UVD1U", + [7][1] = "DBGU0", + [8][1] = "XDP", + [13][1] = "OSS", + [14][1] = "HDP", + [15][1] = "SDMA0", + [32+0][1] = "UVD", + [32+1][1] = "UVDU", + [32+2][1] = "DBGU1", + [32+3][1] = "MP1", + [32+4][1] = "MP0", + [32+14][1] = "SDMA1", +}; + +static const char *mmhub_client_ids_arcturus[][2] = { + [2][0] = "MP1", + [3][0] = "MP0", + [10][0] = "UTCL2", + [13][0] = "OSS", + [14][0] = "HDP", + [15][0] = "SDMA0", + [32+15][0] = "SDMA1", + [64+15][0] = "SDMA2", + [96+15][0] = "SDMA3", + [128+15][0] = "SDMA4", + [160+11][0] = "JPEG", + [160+12][0] = "VCN", + [160+13][0] = "VCNU", + [160+15][0] = "SDMA5", + [192+10][0] = "UTCL2", + [192+11][0] = "JPEG1", + [192+12][0] = "VCN1", + [192+13][0] = "VCN1U", + [192+15][0] = "SDMA6", + [224+15][0] = "SDMA7", + [0][1] = "DBGU1", + [1][1] = "XDP", + [2][1] = "MP1", + [3][1] = "MP0", + [13][1] = "OSS", + [14][1] = "HDP", + [15][1] = "SDMA0", + [32+15][1] = "SDMA1", + [32+15][1] = "SDMA1", + [64+15][1] = "SDMA2", + [96+15][1] = "SDMA3", + [128+15][1] = "SDMA4", + [160+11][1] = "JPEG", + [160+12][1] = "VCN", + [160+13][1] = "VCNU", + [160+15][1] = "SDMA5", + [192+11][1] = "JPEG1", + [192+12][1] = "VCN1", + [192+13][1] = "VCN1U", + [192+15][1] = "SDMA6", + [224+15][1] = "SDMA7", +}; static const u32 golden_settings_vega10_hdp[] = { @@ -300,9 +516,10 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, { struct amdgpu_vmhub *hub; bool retry_fault = !!(entry->src_data[1] & 0x80); - uint32_t status = 0; + uint32_t status = 0, cid = 0, rw = 0; u64 addr; char hub_name[10]; + const char *mmhub_cid; addr = (u64)entry->src_data[0] << 12; addr |= ((u64)entry->src_data[1] & 0xf) << 44; @@ -337,6 +554,10 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, RREG32(hub->vm_l2_pro_fault_status); status = RREG32(hub->vm_l2_pro_fault_status); + cid = REG_GET_FIELD(status, + VM_L2_PROTECTION_FAULT_STATUS, CID); + rw = REG_GET_FIELD(status, + VM_L2_PROTECTION_FAULT_STATUS, RW); WREG32_P(hub->vm_l2_pro_fault_cntl, 1, ~1); } @@ -359,9 +580,37 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, dev_err(adev->dev, "VM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", status); - dev_err(adev->dev, "\t Faulty UTCL2 client ID: 0x%lx\n", - REG_GET_FIELD(status, - VM_L2_PROTECTION_FAULT_STATUS, CID)); + if (hub == &adev->vmhub[AMDGPU_GFXHUB_0]) { + dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", + cid >= ARRAY_SIZE(gfxhub_client_ids) ? "unknown" : gfxhub_client_ids[cid], + cid); + } else { + switch (adev->asic_type) { + case CHIP_VEGA10: + mmhub_cid = mmhub_client_ids_vega10[cid][rw]; + break; + case CHIP_VEGA12: + mmhub_cid = mmhub_client_ids_vega12[cid][rw]; + break; + case CHIP_VEGA20: + mmhub_cid = mmhub_client_ids_vega20[cid][rw]; + break; + case CHIP_ARCTURUS: + mmhub_cid = mmhub_client_ids_arcturus[cid][rw]; + break; + case CHIP_RAVEN: + mmhub_cid = mmhub_client_ids_raven[cid][rw]; + break; + case CHIP_RENOIR: + mmhub_cid = mmhub_client_ids_renoir[cid][rw]; + break; + default: + mmhub_cid = NULL; + break; + } + dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", + mmhub_cid ? mmhub_cid : "unknown", cid); + } dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", REG_GET_FIELD(status, VM_L2_PROTECTION_FAULT_STATUS, MORE_FAULTS)); @@ -374,10 +623,7 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, dev_err(adev->dev, "\t MAPPING_ERROR: 0x%lx\n", REG_GET_FIELD(status, VM_L2_PROTECTION_FAULT_STATUS, MAPPING_ERROR)); - dev_err(adev->dev, "\t RW: 0x%lx\n", - REG_GET_FIELD(status, - VM_L2_PROTECTION_FAULT_STATUS, RW)); - + dev_err(adev->dev, "\t RW: 0x%x\n", rw); } } @@ -500,13 +746,14 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, * as GFXOFF under bare metal */ if (adev->gfx.kiq.ring.sched.ready && - (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev)) && - !adev->in_gpu_reset) { + (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev)) && + down_read_trylock(&adev->reset_sem)) { 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); + up_read(&adev->reset_sem); return; } @@ -596,10 +843,10 @@ static int gmc_v9_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, struct amdgpu_ring *ring = &adev->gfx.kiq.ring; struct amdgpu_kiq *kiq = &adev->gfx.kiq; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EIO; - if (ring->sched.ready) { + if (ring->sched.ready && down_read_trylock(&adev->reset_sem)) { /* Vega20+XGMI caches PTEs in TC and TLB. Add a * heavy-weight TLB flush (type 2), which flushes * both. Due to a race condition with concurrent @@ -626,6 +873,7 @@ static int gmc_v9_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, if (r) { amdgpu_ring_undo(ring); spin_unlock(&adev->gfx.kiq.ring_lock); + up_read(&adev->reset_sem); return -ETIME; } @@ -633,10 +881,11 @@ static int gmc_v9_0_flush_gpu_tlb_pasid(struct amdgpu_device *adev, spin_unlock(&adev->gfx.kiq.ring_lock); r = amdgpu_fence_wait_polling(ring, seq, adev->usec_timeout); if (r < 1) { - DRM_ERROR("wait for kiq fence error: %ld.\n", r); + dev_err(adev->dev, "wait for kiq fence error: %ld.\n", r); + up_read(&adev->reset_sem); return -ETIME; } - + up_read(&adev->reset_sem); return 0; } @@ -826,6 +1075,41 @@ static void gmc_v9_0_get_vm_pte(struct amdgpu_device *adev, *flags |= AMDGPU_PTE_SNOOPED; } +static unsigned gmc_v9_0_get_vbios_fb_size(struct amdgpu_device *adev) +{ + u32 d1vga_control = RREG32_SOC15(DCE, 0, mmD1VGA_CONTROL); + unsigned size; + + if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { + size = AMDGPU_VBIOS_VGA_ALLOCATION; + } else { + u32 viewport; + + switch (adev->asic_type) { + case CHIP_RAVEN: + case CHIP_RENOIR: + viewport = RREG32_SOC15(DCE, 0, mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION); + size = (REG_GET_FIELD(viewport, + HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT) * + REG_GET_FIELD(viewport, + HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_WIDTH) * + 4); + break; + case CHIP_VEGA10: + case CHIP_VEGA12: + case CHIP_VEGA20: + default: + viewport = RREG32_SOC15(DCE, 0, mmSCL0_VIEWPORT_SIZE); + size = (REG_GET_FIELD(viewport, SCL0_VIEWPORT_SIZE, VIEWPORT_HEIGHT) * + REG_GET_FIELD(viewport, SCL0_VIEWPORT_SIZE, VIEWPORT_WIDTH) * + 4); + break; + } + } + + return size; +} + static const struct amdgpu_gmc_funcs gmc_v9_0_gmc_funcs = { .flush_gpu_tlb = gmc_v9_0_flush_gpu_tlb, .flush_gpu_tlb_pasid = gmc_v9_0_flush_gpu_tlb_pasid, @@ -833,7 +1117,8 @@ static const struct amdgpu_gmc_funcs gmc_v9_0_gmc_funcs = { .emit_pasid_mapping = gmc_v9_0_emit_pasid_mapping, .map_mtype = gmc_v9_0_map_mtype, .get_vm_pde = gmc_v9_0_get_vm_pde, - .get_vm_pte = gmc_v9_0_get_vm_pte + .get_vm_pte = gmc_v9_0_get_vm_pte, + .get_vbios_fb_size = gmc_v9_0_get_vbios_fb_size, }; static void gmc_v9_0_set_gmc_funcs(struct amdgpu_device *adev) @@ -871,13 +1156,11 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev) static void gmc_v9_0_set_mmhub_funcs(struct amdgpu_device *adev) { switch (adev->asic_type) { - case CHIP_VEGA20: - adev->mmhub.funcs = &mmhub_v1_0_funcs; - break; case CHIP_ARCTURUS: adev->mmhub.funcs = &mmhub_v9_4_funcs; break; default: + adev->mmhub.funcs = &mmhub_v1_0_funcs; break; } } @@ -901,38 +1184,12 @@ static int gmc_v9_0_early_init(void *handle) return 0; } -static bool gmc_v9_0_keep_stolen_memory(struct amdgpu_device *adev) -{ - - /* - * TODO: - * Currently there is a bug where some memory client outside - * of the driver writes to first 8M of VRAM on S3 resume, - * this overrides GART which by default gets placed in first 8M and - * causes VM_FAULTS once GTT is accessed. - * Keep the stolen memory reservation until the while this is not solved. - * Also check code in gmc_v9_0_get_vbios_fb_size and gmc_v9_0_late_init - */ - switch (adev->asic_type) { - case CHIP_VEGA10: - case CHIP_RAVEN: - case CHIP_ARCTURUS: - case CHIP_RENOIR: - return true; - case CHIP_VEGA12: - case CHIP_VEGA20: - default: - return false; - } -} - static int gmc_v9_0_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - if (!gmc_v9_0_keep_stolen_memory(adev)) - amdgpu_bo_late_init(adev); + amdgpu_bo_late_init(adev); r = amdgpu_gmc_allocate_vm_inv_eng(adev); if (r) @@ -969,10 +1226,8 @@ static void gmc_v9_0_vram_gtt_location(struct amdgpu_device *adev, { u64 base = 0; - if (adev->asic_type == CHIP_ARCTURUS) - base = mmhub_v9_4_get_fb_location(adev); - else if (!amdgpu_sriov_vf(adev)) - base = mmhub_v1_0_get_fb_location(adev); + if (!amdgpu_sriov_vf(adev)) + base = adev->mmhub.funcs->get_fb_location(adev); /* add the xgmi offset of the physical node */ base += adev->gmc.xgmi.physical_node_id * adev->gmc.xgmi.node_segment_size; @@ -1066,50 +1321,18 @@ static int gmc_v9_0_gart_init(struct amdgpu_device *adev) return amdgpu_gart_table_vram_alloc(adev); } -static unsigned gmc_v9_0_get_vbios_fb_size(struct amdgpu_device *adev) +/** + * gmc_v9_0_save_registers - saves regs + * + * @adev: amdgpu_device pointer + * + * This saves potential register values that should be + * restored upon resume + */ +static void gmc_v9_0_save_registers(struct amdgpu_device *adev) { - u32 d1vga_control; - unsigned size; - - /* - * TODO Remove once GART corruption is resolved - * Check related code in gmc_v9_0_sw_fini - * */ - if (gmc_v9_0_keep_stolen_memory(adev)) - return 9 * 1024 * 1024; - - d1vga_control = RREG32_SOC15(DCE, 0, mmD1VGA_CONTROL); - if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { - size = 9 * 1024 * 1024; /* reserve 8MB for vga emulator and 1 MB for FB */ - } else { - u32 viewport; - - switch (adev->asic_type) { - case CHIP_RAVEN: - case CHIP_RENOIR: - viewport = RREG32_SOC15(DCE, 0, mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION); - size = (REG_GET_FIELD(viewport, - HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT) * - REG_GET_FIELD(viewport, - HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_WIDTH) * - 4); - break; - case CHIP_VEGA10: - case CHIP_VEGA12: - case CHIP_VEGA20: - default: - viewport = RREG32_SOC15(DCE, 0, mmSCL0_VIEWPORT_SIZE); - size = (REG_GET_FIELD(viewport, SCL0_VIEWPORT_SIZE, VIEWPORT_HEIGHT) * - REG_GET_FIELD(viewport, SCL0_VIEWPORT_SIZE, VIEWPORT_WIDTH) * - 4); - break; - } - } - /* return 0 if the pre-OS buffer uses up most of vram */ - if ((adev->gmc.real_vram_size - size) < (8 * 1024 * 1024)) - return 0; - - return size; + if (adev->asic_type == CHIP_RAVEN) + adev->gmc.sdpif_register = RREG32_SOC15(DCE, 0, mmDCHUBBUB_SDPIF_MMIO_CNTRL_0); } static int gmc_v9_0_sw_init(void *handle) @@ -1118,10 +1341,8 @@ static int gmc_v9_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; gfxhub_v1_0_init(adev); - if (adev->asic_type == CHIP_ARCTURUS) - mmhub_v9_4_init(adev); - else - mmhub_v1_0_init(adev); + + adev->mmhub.funcs->init(adev); spin_lock_init(&adev->gmc.invalidate_lock); @@ -1242,7 +1463,7 @@ static int gmc_v9_0_sw_init(void *handle) if (r) return r; - adev->gmc.stolen_size = gmc_v9_0_get_vbios_fb_size(adev); + amdgpu_gmc_get_vbios_allocations(adev); /* Memory manager */ r = amdgpu_bo_init(adev); @@ -1268,21 +1489,18 @@ static int gmc_v9_0_sw_init(void *handle) amdgpu_vm_manager_init(adev); + gmc_v9_0_save_registers(adev); + return 0; } static int gmc_v9_0_sw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - void *stolen_vga_buf; amdgpu_gmc_ras_fini(adev); amdgpu_gem_force_release(adev); amdgpu_vm_manager_fini(adev); - - if (gmc_v9_0_keep_stolen_memory(adev)) - amdgpu_bo_free_kernel(&adev->stolen_vga_memory, NULL, &stolen_vga_buf); - amdgpu_gart_table_vram_free(adev); amdgpu_bo_fini(adev); amdgpu_gart_fini(adev); @@ -1326,10 +1544,10 @@ static void gmc_v9_0_init_golden_registers(struct amdgpu_device *adev) * * This restores register values, saved at suspend. */ -static void gmc_v9_0_restore_registers(struct amdgpu_device *adev) +void gmc_v9_0_restore_registers(struct amdgpu_device *adev) { if (adev->asic_type == CHIP_RAVEN) - WREG32(mmDCHUBBUB_SDPIF_MMIO_CNTRL_0, adev->gmc.sdpif_register); + WREG32_SOC15(DCE, 0, mmDCHUBBUB_SDPIF_MMIO_CNTRL_0, adev->gmc.sdpif_register); } /** @@ -1353,10 +1571,7 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev) if (r) return r; - if (adev->asic_type == CHIP_ARCTURUS) - r = mmhub_v9_4_gart_enable(adev); - else - r = mmhub_v1_0_gart_enable(adev); + r = adev->mmhub.funcs->gart_enable(adev); if (r) return r; @@ -1391,11 +1606,10 @@ static int gmc_v9_0_hw_init(void *handle) golden_settings_vega10_hdp, ARRAY_SIZE(golden_settings_vega10_hdp)); + if (adev->mmhub.funcs->update_power_gating) + adev->mmhub.funcs->update_power_gating(adev, true); + switch (adev->asic_type) { - case CHIP_RAVEN: - /* TODO for renoir */ - mmhub_v1_0_update_power_gating(adev, true); - break; case CHIP_ARCTURUS: WREG32_FIELD15(HDP, 0, HDP_MMHUB_CNTL, HDP_MMHUB_GCC, 1); break; @@ -1421,10 +1635,7 @@ static int gmc_v9_0_hw_init(void *handle) if (!amdgpu_sriov_vf(adev)) { gfxhub_v1_0_set_fault_enable_default(adev, value); - if (adev->asic_type == CHIP_ARCTURUS) - mmhub_v9_4_set_fault_enable_default(adev, value); - else - mmhub_v1_0_set_fault_enable_default(adev, value); + adev->mmhub.funcs->set_fault_enable_default(adev, value); } for (i = 0; i < adev->num_vmhubs; ++i) gmc_v9_0_flush_gpu_tlb(adev, 0, i, 0); @@ -1438,20 +1649,6 @@ static int gmc_v9_0_hw_init(void *handle) } /** - * gmc_v9_0_save_registers - saves regs - * - * @adev: amdgpu_device pointer - * - * This saves potential register values that should be - * restored upon resume - */ -static void gmc_v9_0_save_registers(struct amdgpu_device *adev) -{ - if (adev->asic_type == CHIP_RAVEN) - adev->gmc.sdpif_register = RREG32(mmDCHUBBUB_SDPIF_MMIO_CNTRL_0); -} - -/** * gmc_v9_0_gart_disable - gart disable * * @adev: amdgpu_device pointer @@ -1461,10 +1658,7 @@ static void gmc_v9_0_save_registers(struct amdgpu_device *adev) static void gmc_v9_0_gart_disable(struct amdgpu_device *adev) { gfxhub_v1_0_gart_disable(adev); - if (adev->asic_type == CHIP_ARCTURUS) - mmhub_v9_4_gart_disable(adev); - else - mmhub_v1_0_gart_disable(adev); + adev->mmhub.funcs->gart_disable(adev); amdgpu_gart_table_vram_unpin(adev); } @@ -1494,8 +1688,6 @@ static int gmc_v9_0_suspend(void *handle) if (r) return r; - gmc_v9_0_save_registers(adev); - return 0; } @@ -1504,7 +1696,6 @@ static int gmc_v9_0_resume(void *handle) int r; struct amdgpu_device *adev = (struct amdgpu_device *)handle; - gmc_v9_0_restore_registers(adev); r = gmc_v9_0_hw_init(adev); if (r) return r; @@ -1537,10 +1728,7 @@ static int gmc_v9_0_set_clockgating_state(void *handle, { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (adev->asic_type == CHIP_ARCTURUS) - mmhub_v9_4_set_clockgating(adev, state); - else - mmhub_v1_0_set_clockgating(adev, state); + adev->mmhub.funcs->set_clockgating(adev, state); athub_v1_0_set_clockgating(adev, state); @@ -1551,10 +1739,7 @@ static void gmc_v9_0_get_clockgating_state(void *handle, u32 *flags) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (adev->asic_type == CHIP_ARCTURUS) - mmhub_v9_4_get_clockgating(adev, flags); - else - mmhub_v1_0_get_clockgating(adev, flags); + adev->mmhub.funcs->get_clockgating(adev, flags); athub_v1_0_get_clockgating(adev, flags); } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h index e0585e8c6c1b..c415c439f690 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h @@ -26,4 +26,6 @@ extern const struct amd_ip_funcs gmc_v9_0_ip_funcs; extern const struct amdgpu_ip_block_version gmc_v9_0_ip_block; + +void gmc_v9_0_restore_registers(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c index 7a51c615d22d..845306f63cdb 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c @@ -55,22 +55,18 @@ static int amdgpu_ih_clientid_jpeg[] = { static int jpeg_v2_5_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (adev->asic_type == CHIP_ARCTURUS) { - u32 harvest; - int i; - - adev->jpeg.num_jpeg_inst = JPEG25_MAX_HW_INSTANCES_ARCTURUS; - for (i = 0; i < adev->jpeg.num_jpeg_inst; i++) { - harvest = RREG32_SOC15(JPEG, i, mmCC_UVD_HARVESTING); - if (harvest & CC_UVD_HARVESTING__UVD_DISABLE_MASK) - adev->jpeg.harvest_config |= 1 << i; - } + u32 harvest; + int i; - if (adev->jpeg.harvest_config == (AMDGPU_JPEG_HARVEST_JPEG0 | - AMDGPU_JPEG_HARVEST_JPEG1)) - return -ENOENT; - } else - adev->jpeg.num_jpeg_inst = 1; + adev->jpeg.num_jpeg_inst = JPEG25_MAX_HW_INSTANCES_ARCTURUS; + for (i = 0; i < adev->jpeg.num_jpeg_inst; i++) { + harvest = RREG32_SOC15(JPEG, i, mmCC_UVD_HARVESTING); + if (harvest & CC_UVD_HARVESTING__UVD_DISABLE_MASK) + adev->jpeg.harvest_config |= 1 << i; + } + if (adev->jpeg.harvest_config == (AMDGPU_JPEG_HARVEST_JPEG0 | + AMDGPU_JPEG_HARVEST_JPEG1)) + return -ENOENT; jpeg_v2_5_set_dec_ring_funcs(adev); jpeg_v2_5_set_irq_funcs(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c index c41e5590a701..3a0dff53654d 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c @@ -460,15 +460,10 @@ static bool jpeg_v3_0_is_idle(void *handle) static int jpeg_v3_0_wait_for_idle(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - int ret; - ret = SOC15_WAIT_ON_RREG(JPEG, 0, mmUVD_JRBC_STATUS, + return SOC15_WAIT_ON_RREG(JPEG, 0, mmUVD_JRBC_STATUS, UVD_JRBC_STATUS__RB_JOB_DONE_MASK, UVD_JRBC_STATUS__RB_JOB_DONE_MASK); - if (ret) - return ret; - - return ret; } static int jpeg_v3_0_set_clockgating_state(void *handle, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index dffcb93ecee5..45a902b1acb7 100755..100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -34,7 +34,7 @@ #define mmDAGB0_CNTL_MISC2_RV 0x008f #define mmDAGB0_CNTL_MISC2_RV_BASE_IDX 0 -u64 mmhub_v1_0_get_fb_location(struct amdgpu_device *adev) +static u64 mmhub_v1_0_get_fb_location(struct amdgpu_device *adev) { u64 base = RREG32_SOC15(MMHUB, 0, mmMC_VM_FB_LOCATION_BASE); u64 top = RREG32_SOC15(MMHUB, 0, mmMC_VM_FB_LOCATION_TOP); @@ -51,7 +51,7 @@ u64 mmhub_v1_0_get_fb_location(struct amdgpu_device *adev) return base; } -void mmhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, +static void mmhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, uint64_t page_table_base) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB_0]; @@ -297,20 +297,19 @@ static void mmhub_v1_0_program_invalidation(struct amdgpu_device *adev) } } -void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev, +static void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev, bool enable) { if (amdgpu_sriov_vf(adev)) return; if (enable && adev->pg_flags & AMD_PG_SUPPORT_MMHUB) { - if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->set_powergating_by_smu) - amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GMC, true); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GMC, true); } } -int mmhub_v1_0_gart_enable(struct amdgpu_device *adev) +static int mmhub_v1_0_gart_enable(struct amdgpu_device *adev) { if (amdgpu_sriov_vf(adev)) { /* @@ -338,7 +337,7 @@ int mmhub_v1_0_gart_enable(struct amdgpu_device *adev) return 0; } -void mmhub_v1_0_gart_disable(struct amdgpu_device *adev) +static void mmhub_v1_0_gart_disable(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB_0]; u32 tmp; @@ -373,7 +372,7 @@ void mmhub_v1_0_gart_disable(struct amdgpu_device *adev) * @adev: amdgpu_device pointer * @value: true redirects VM faults to the default page */ -void mmhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev, bool value) +static void mmhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev, bool value) { u32 tmp; @@ -415,7 +414,7 @@ void mmhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev, bool value) WREG32_SOC15(MMHUB, 0, mmVM_L2_PROTECTION_FAULT_CNTL, tmp); } -void mmhub_v1_0_init(struct amdgpu_device *adev) +static void mmhub_v1_0_init(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB_0]; @@ -525,7 +524,7 @@ static void mmhub_v1_0_update_medium_grain_light_sleep(struct amdgpu_device *ade WREG32_SOC15(MMHUB, 0, mmATC_L2_MISC_CG, data); } -int mmhub_v1_0_set_clockgating(struct amdgpu_device *adev, +static int mmhub_v1_0_set_clockgating(struct amdgpu_device *adev, enum amd_clockgating_state state) { if (amdgpu_sriov_vf(adev)) @@ -549,7 +548,7 @@ int mmhub_v1_0_set_clockgating(struct amdgpu_device *adev, return 0; } -void mmhub_v1_0_get_clockgating(struct amdgpu_device *adev, u32 *flags) +static void mmhub_v1_0_get_clockgating(struct amdgpu_device *adev, u32 *flags) { int data, data1; @@ -781,4 +780,13 @@ const struct amdgpu_mmhub_funcs mmhub_v1_0_funcs = { .ras_late_init = amdgpu_mmhub_ras_late_init, .query_ras_error_count = mmhub_v1_0_query_ras_error_count, .reset_ras_error_count = mmhub_v1_0_reset_ras_error_count, + .get_fb_location = mmhub_v1_0_get_fb_location, + .init = mmhub_v1_0_init, + .gart_enable = mmhub_v1_0_gart_enable, + .set_fault_enable_default = mmhub_v1_0_set_fault_enable_default, + .gart_disable = mmhub_v1_0_gart_disable, + .set_clockgating = mmhub_v1_0_set_clockgating, + .get_clockgating = mmhub_v1_0_get_clockgating, + .setup_vm_pt_regs = mmhub_v1_0_setup_vm_pt_regs, + .update_power_gating = mmhub_v1_0_update_power_gating, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h index c43319e8f945..d77f5b65a618 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h @@ -25,18 +25,4 @@ extern const struct amdgpu_mmhub_funcs mmhub_v1_0_funcs; -u64 mmhub_v1_0_get_fb_location(struct amdgpu_device *adev); -int mmhub_v1_0_gart_enable(struct amdgpu_device *adev); -void mmhub_v1_0_gart_disable(struct amdgpu_device *adev); -void mmhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev, - bool value); -void mmhub_v1_0_init(struct amdgpu_device *adev); -int mmhub_v1_0_set_clockgating(struct amdgpu_device *adev, - enum amd_clockgating_state state); -void mmhub_v1_0_get_clockgating(struct amdgpu_device *adev, u32 *flags); -void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev, - bool enable); -void mmhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, - uint64_t page_table_base); - #endif diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c index c79fc54bc3c4..2d88278c50bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c @@ -36,7 +36,130 @@ #define mmDAGB0_CNTL_MISC2_Sienna_Cichlid 0x0070 #define mmDAGB0_CNTL_MISC2_Sienna_Cichlid_BASE_IDX 0 -void mmhub_v2_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, +static const char *mmhub_client_ids_navi1x[][2] = { + [3][0] = "DCEDMC", + [4][0] = "DCEVGA", + [5][0] = "MP0", + [6][0] = "MP1", + [13][0] = "VMC", + [14][0] = "HDP", + [15][0] = "OSS", + [16][0] = "VCNU", + [17][0] = "JPEG", + [18][0] = "VCN", + [3][1] = "DCEDMC", + [4][1] = "DCEXFC", + [5][1] = "DCEVGA", + [6][1] = "DCEDWB", + [7][1] = "MP0", + [8][1] = "MP1", + [9][1] = "DBGU1", + [10][1] = "DBGU0", + [11][1] = "XDP", + [14][1] = "HDP", + [15][1] = "OSS", + [16][1] = "VCNU", + [17][1] = "JPEG", + [18][1] = "VCN", +}; + +static const char *mmhub_client_ids_sienna_cichlid[][2] = { + [3][0] = "DCEDMC", + [4][0] = "DCEVGA", + [5][0] = "MP0", + [6][0] = "MP1", + [8][0] = "VMC", + [9][0] = "VCNU0", + [10][0] = "JPEG", + [12][0] = "VCNU1", + [13][0] = "VCN1", + [14][0] = "HDP", + [15][0] = "OSS", + [32+11][0] = "VCN0", + [0][1] = "DBGU0", + [1][1] = "DBGU1", + [2][1] = "DCEDWB", + [3][1] = "DCEDMC", + [4][1] = "DCEVGA", + [5][1] = "MP0", + [6][1] = "MP1", + [7][1] = "XDP", + [9][1] = "VCNU0", + [10][1] = "JPEG", + [11][1] = "VCN0", + [12][1] = "VCNU1", + [13][1] = "VCN1", + [14][1] = "HDP", + [15][1] = "OSS", +}; + +static uint32_t mmhub_v2_0_get_invalidate_req(unsigned int vmid, + uint32_t flush_type) +{ + u32 req = 0; + + /* invalidate using legacy mode on vmid*/ + req = REG_SET_FIELD(req, MMVM_INVALIDATE_ENG0_REQ, + PER_VMID_INVALIDATE_REQ, 1 << vmid); + req = REG_SET_FIELD(req, MMVM_INVALIDATE_ENG0_REQ, FLUSH_TYPE, flush_type); + req = REG_SET_FIELD(req, MMVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PTES, 1); + req = REG_SET_FIELD(req, MMVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE0, 1); + req = REG_SET_FIELD(req, MMVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE1, 1); + req = REG_SET_FIELD(req, MMVM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE2, 1); + req = REG_SET_FIELD(req, MMVM_INVALIDATE_ENG0_REQ, INVALIDATE_L1_PTES, 1); + req = REG_SET_FIELD(req, MMVM_INVALIDATE_ENG0_REQ, + CLEAR_PROTECTION_FAULT_STATUS_ADDR, 0); + + return req; +} + +static void +mmhub_v2_0_print_l2_protection_fault_status(struct amdgpu_device *adev, + uint32_t status) +{ + uint32_t cid, rw; + const char *mmhub_cid = NULL; + + cid = REG_GET_FIELD(status, + MMVM_L2_PROTECTION_FAULT_STATUS, CID); + rw = REG_GET_FIELD(status, + MMVM_L2_PROTECTION_FAULT_STATUS, RW); + + dev_err(adev->dev, + "MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n", + status); + switch (adev->asic_type) { + case CHIP_NAVI10: + case CHIP_NAVI12: + case CHIP_NAVI14: + mmhub_cid = mmhub_client_ids_navi1x[cid][rw]; + break; + case CHIP_SIENNA_CICHLID: + case CHIP_NAVY_FLOUNDER: + mmhub_cid = mmhub_client_ids_sienna_cichlid[cid][rw]; + break; + default: + mmhub_cid = NULL; + break; + } + dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", + mmhub_cid ? mmhub_cid : "unknown", cid); + dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", + REG_GET_FIELD(status, + MMVM_L2_PROTECTION_FAULT_STATUS, MORE_FAULTS)); + dev_err(adev->dev, "\t WALKER_ERROR: 0x%lx\n", + REG_GET_FIELD(status, + MMVM_L2_PROTECTION_FAULT_STATUS, WALKER_ERROR)); + dev_err(adev->dev, "\t PERMISSION_FAULTS: 0x%lx\n", + REG_GET_FIELD(status, + MMVM_L2_PROTECTION_FAULT_STATUS, PERMISSION_FAULTS)); + dev_err(adev->dev, "\t MAPPING_ERROR: 0x%lx\n", + REG_GET_FIELD(status, + MMVM_L2_PROTECTION_FAULT_STATUS, MAPPING_ERROR)); + dev_err(adev->dev, "\t RW: 0x%x\n", rw); +} + +static void mmhub_v2_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, uint64_t page_table_base) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB_0]; @@ -280,7 +403,7 @@ static void mmhub_v2_0_program_invalidation(struct amdgpu_device *adev) } } -int mmhub_v2_0_gart_enable(struct amdgpu_device *adev) +static int mmhub_v2_0_gart_enable(struct amdgpu_device *adev) { /* GART Enable. */ mmhub_v2_0_init_gart_aperture_regs(adev); @@ -296,7 +419,7 @@ int mmhub_v2_0_gart_enable(struct amdgpu_device *adev) return 0; } -void mmhub_v2_0_gart_disable(struct amdgpu_device *adev) +static void mmhub_v2_0_gart_disable(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB_0]; u32 tmp; @@ -327,7 +450,7 @@ void mmhub_v2_0_gart_disable(struct amdgpu_device *adev) * @adev: amdgpu_device pointer * @value: true redirects VM faults to the default page */ -void mmhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev, bool value) +static void mmhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev, bool value) { u32 tmp; @@ -370,7 +493,12 @@ void mmhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev, bool value) WREG32_SOC15(MMHUB, 0, mmMMVM_L2_PROTECTION_FAULT_CNTL, tmp); } -void mmhub_v2_0_init(struct amdgpu_device *adev) +static const struct amdgpu_vmhub_funcs mmhub_v2_0_vmhub_funcs = { + .print_l2_protection_fault_status = mmhub_v2_0_print_l2_protection_fault_status, + .get_invalidate_req = mmhub_v2_0_get_invalidate_req, +}; + +static void mmhub_v2_0_init(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB_0]; @@ -400,6 +528,16 @@ void mmhub_v2_0_init(struct amdgpu_device *adev) mmMMVM_INVALIDATE_ENG0_REQ; hub->eng_addr_distance = mmMMVM_INVALIDATE_ENG1_ADDR_RANGE_LO32 - mmMMVM_INVALIDATE_ENG0_ADDR_RANGE_LO32; + + hub->vm_cntx_cntl_vm_fault = MMVM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + MMVM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + MMVM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + MMVM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + MMVM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + MMVM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | + MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK; + + hub->vmhub_funcs = &mmhub_v2_0_vmhub_funcs; } static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *adev, @@ -490,7 +628,7 @@ static void mmhub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *ade } } -int mmhub_v2_0_set_clockgating(struct amdgpu_device *adev, +static int mmhub_v2_0_set_clockgating(struct amdgpu_device *adev, enum amd_clockgating_state state) { if (amdgpu_sriov_vf(adev)) @@ -514,7 +652,7 @@ int mmhub_v2_0_set_clockgating(struct amdgpu_device *adev, return 0; } -void mmhub_v2_0_get_clockgating(struct amdgpu_device *adev, u32 *flags) +static void mmhub_v2_0_get_clockgating(struct amdgpu_device *adev, u32 *flags) { int data, data1; @@ -547,3 +685,14 @@ void mmhub_v2_0_get_clockgating(struct amdgpu_device *adev, u32 *flags) if (data & MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK) *flags |= AMD_CG_SUPPORT_MC_LS; } + +const struct amdgpu_mmhub_funcs mmhub_v2_0_funcs = { + .ras_late_init = amdgpu_mmhub_ras_late_init, + .init = mmhub_v2_0_init, + .gart_enable = mmhub_v2_0_gart_enable, + .set_fault_enable_default = mmhub_v2_0_set_fault_enable_default, + .gart_disable = mmhub_v2_0_gart_disable, + .set_clockgating = mmhub_v2_0_set_clockgating, + .get_clockgating = mmhub_v2_0_get_clockgating, + .setup_vm_pt_regs = mmhub_v2_0_setup_vm_pt_regs, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.h b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.h index 3ea4344f0315..f80f461d67da 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.h +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.h @@ -23,15 +23,6 @@ #ifndef __MMHUB_V2_0_H__ #define __MMHUB_V2_0_H__ -int mmhub_v2_0_gart_enable(struct amdgpu_device *adev); -void mmhub_v2_0_gart_disable(struct amdgpu_device *adev); -void mmhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev, - bool value); -void mmhub_v2_0_init(struct amdgpu_device *adev); -int mmhub_v2_0_set_clockgating(struct amdgpu_device *adev, - enum amd_clockgating_state state); -void mmhub_v2_0_get_clockgating(struct amdgpu_device *adev, u32 *flags); -void mmhub_v2_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, - uint64_t page_table_base); +extern const struct amdgpu_mmhub_funcs mmhub_v2_0_funcs; #endif diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c index 9979f54fef57..6c6ad529c65c 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c @@ -36,7 +36,7 @@ #define MMHUB_NUM_INSTANCES 2 #define MMHUB_INSTANCE_REGISTER_OFFSET 0x3000 -u64 mmhub_v9_4_get_fb_location(struct amdgpu_device *adev) +static u64 mmhub_v9_4_get_fb_location(struct amdgpu_device *adev) { /* The base should be same b/t 2 mmhubs on Acrturus. Read one here. */ u64 base = RREG32_SOC15(MMHUB, 0, mmVMSHAREDVC0_MC_VM_FB_LOCATION_BASE); @@ -97,7 +97,7 @@ static void mmhub_v9_4_init_gart_aperture_regs(struct amdgpu_device *adev, (u32)(adev->gmc.gart_end >> 44)); } -void mmhub_v9_4_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, +static void mmhub_v9_4_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, uint64_t page_table_base) { int i; @@ -375,7 +375,7 @@ static void mmhub_v9_4_program_invalidation(struct amdgpu_device *adev, } } -int mmhub_v9_4_gart_enable(struct amdgpu_device *adev) +static int mmhub_v9_4_gart_enable(struct amdgpu_device *adev) { int i; @@ -397,7 +397,7 @@ int mmhub_v9_4_gart_enable(struct amdgpu_device *adev) return 0; } -void mmhub_v9_4_gart_disable(struct amdgpu_device *adev) +static void mmhub_v9_4_gart_disable(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB_0]; u32 tmp; @@ -442,7 +442,7 @@ void mmhub_v9_4_gart_disable(struct amdgpu_device *adev) * @adev: amdgpu_device pointer * @value: true redirects VM faults to the default page */ -void mmhub_v9_4_set_fault_enable_default(struct amdgpu_device *adev, bool value) +static void mmhub_v9_4_set_fault_enable_default(struct amdgpu_device *adev, bool value) { u32 tmp; int i; @@ -500,7 +500,7 @@ void mmhub_v9_4_set_fault_enable_default(struct amdgpu_device *adev, bool value) } } -void mmhub_v9_4_init(struct amdgpu_device *adev) +static void mmhub_v9_4_init(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub[MMHUB_NUM_INSTANCES] = {&adev->vmhub[AMDGPU_MMHUB_0], &adev->vmhub[AMDGPU_MMHUB_1]}; @@ -630,7 +630,7 @@ static void mmhub_v9_4_update_medium_grain_light_sleep(struct amdgpu_device *ade } } -int mmhub_v9_4_set_clockgating(struct amdgpu_device *adev, +static int mmhub_v9_4_set_clockgating(struct amdgpu_device *adev, enum amd_clockgating_state state) { if (amdgpu_sriov_vf(adev)) @@ -650,7 +650,7 @@ int mmhub_v9_4_set_clockgating(struct amdgpu_device *adev, return 0; } -void mmhub_v9_4_get_clockgating(struct amdgpu_device *adev, u32 *flags) +static void mmhub_v9_4_get_clockgating(struct amdgpu_device *adev, u32 *flags) { int data, data1; @@ -1628,4 +1628,12 @@ const struct amdgpu_mmhub_funcs mmhub_v9_4_funcs = { .ras_late_init = amdgpu_mmhub_ras_late_init, .query_ras_error_count = mmhub_v9_4_query_ras_error_count, .reset_ras_error_count = mmhub_v9_4_reset_ras_error_count, + .get_fb_location = mmhub_v9_4_get_fb_location, + .init = mmhub_v9_4_init, + .gart_enable = mmhub_v9_4_gart_enable, + .set_fault_enable_default = mmhub_v9_4_set_fault_enable_default, + .gart_disable = mmhub_v9_4_gart_disable, + .set_clockgating = mmhub_v9_4_set_clockgating, + .get_clockgating = mmhub_v9_4_get_clockgating, + .setup_vm_pt_regs = mmhub_v9_4_setup_vm_pt_regs, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.h b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.h index 1b979773776c..92404a8f66f3 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.h +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.h @@ -25,16 +25,4 @@ extern const struct amdgpu_mmhub_funcs mmhub_v9_4_funcs; -u64 mmhub_v9_4_get_fb_location(struct amdgpu_device *adev); -int mmhub_v9_4_gart_enable(struct amdgpu_device *adev); -void mmhub_v9_4_gart_disable(struct amdgpu_device *adev); -void mmhub_v9_4_set_fault_enable_default(struct amdgpu_device *adev, - bool value); -void mmhub_v9_4_init(struct amdgpu_device *adev); -int mmhub_v9_4_set_clockgating(struct amdgpu_device *adev, - enum amd_clockgating_state state); -void mmhub_v9_4_get_clockgating(struct amdgpu_device *adev, u32 *flags); -void mmhub_v9_4_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, - uint64_t page_table_base); - #endif diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c index 5fd67e1cc2a0..9c07014d9bd6 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c @@ -238,19 +238,15 @@ static void xgpu_ai_mailbox_flr_work(struct work_struct *work) struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, flr_work); struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt); int timeout = AI_MAILBOX_POLL_FLR_TIMEDOUT; - int locked; /* block amdgpu_gpu_recover till msg FLR COMPLETE received, * otherwise the mailbox msg will be ruined/reseted by * the VF FLR. - * - * we can unlock the lock_reset to allow "amdgpu_job_timedout" - * to run gpu_recover() after FLR_NOTIFICATION_CMPL received - * which means host side had finished this VF's FLR. */ - locked = mutex_trylock(&adev->lock_reset); - if (locked) - adev->in_gpu_reset = true; + if (!down_read_trylock(&adev->reset_sem)) + return; + + atomic_set(&adev->in_gpu_reset, 1); do { if (xgpu_ai_mailbox_peek_msg(adev) == IDH_FLR_NOTIFICATION_CMPL) @@ -261,14 +257,12 @@ static void xgpu_ai_mailbox_flr_work(struct work_struct *work) } while (timeout > 1); flr_done: - if (locked) { - adev->in_gpu_reset = false; - mutex_unlock(&adev->lock_reset); - } + atomic_set(&adev->in_gpu_reset, 0); + up_read(&adev->reset_sem); /* Trigger recovery for world switch failure if no TDR */ if (amdgpu_device_should_recover_gpu(adev) - && adev->sdma_timeout == MAX_SCHEDULE_TIMEOUT) + && (amdgpu_device_has_job_running(adev) || adev->sdma_timeout == MAX_SCHEDULE_TIMEOUT)) amdgpu_device_gpu_recover(adev, NULL); } diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c index ce2bf1fb79ed..9c23abf9b140 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c @@ -259,19 +259,15 @@ static void xgpu_nv_mailbox_flr_work(struct work_struct *work) struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, flr_work); struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt); int timeout = NV_MAILBOX_POLL_FLR_TIMEDOUT; - int locked; /* block amdgpu_gpu_recover till msg FLR COMPLETE received, * otherwise the mailbox msg will be ruined/reseted by * the VF FLR. - * - * we can unlock the lock_reset to allow "amdgpu_job_timedout" - * to run gpu_recover() after FLR_NOTIFICATION_CMPL received - * which means host side had finished this VF's FLR. */ - locked = mutex_trylock(&adev->lock_reset); - if (locked) - adev->in_gpu_reset = true; + if (!down_read_trylock(&adev->reset_sem)) + return; + + atomic_set(&adev->in_gpu_reset, 1); do { if (xgpu_nv_mailbox_peek_msg(adev) == IDH_FLR_NOTIFICATION_CMPL) @@ -282,14 +278,13 @@ static void xgpu_nv_mailbox_flr_work(struct work_struct *work) } while (timeout > 1); flr_done: - if (locked) { - adev->in_gpu_reset = false; - mutex_unlock(&adev->lock_reset); - } + atomic_set(&adev->in_gpu_reset, 0); + up_read(&adev->reset_sem); /* Trigger recovery for world switch failure if no TDR */ if (amdgpu_device_should_recover_gpu(adev) - && (adev->sdma_timeout == MAX_SCHEDULE_TIMEOUT || + && (amdgpu_device_has_job_running(adev) || + adev->sdma_timeout == MAX_SCHEDULE_TIMEOUT || adev->gfx_timeout == MAX_SCHEDULE_TIMEOUT || adev->compute_timeout == MAX_SCHEDULE_TIMEOUT || adev->video_timeout == MAX_SCHEDULE_TIMEOUT)) diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c index 350f1bf063c6..74b1e7dc49a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c @@ -306,7 +306,8 @@ static int navi10_ih_irq_init(struct amdgpu_device *adev) } else { WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl); } - navi10_ih_reroute_ih(adev); + if (adev->irq.ih1.ring_size) + navi10_ih_reroute_ih(adev); if (unlikely(adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT)) { if (ih->use_bus_addr) { @@ -668,19 +669,26 @@ static int navi10_ih_sw_init(void *handle) adev->irq.ih.use_doorbell = true; adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1; - r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true); - if (r) - return r; + adev->irq.ih1.ring_size = 0; + adev->irq.ih2.ring_size = 0; - adev->irq.ih1.use_doorbell = true; - adev->irq.ih1.doorbell_index = (adev->doorbell_index.ih + 1) << 1; + if (adev->asic_type < CHIP_NAVI10) { + r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true); + if (r) + return r; - r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true); - if (r) - return r; + adev->irq.ih1.use_doorbell = true; + adev->irq.ih1.doorbell_index = + (adev->doorbell_index.ih + 1) << 1; + + r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true); + if (r) + return r; - adev->irq.ih2.use_doorbell = true; - adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1; + adev->irq.ih2.use_doorbell = true; + adev->irq.ih2.doorbell_index = + (adev->doorbell_index.ih + 2) << 1; + } r = amdgpu_irq_init(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c index e629156173d3..eadc9526d33f 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c @@ -302,6 +302,7 @@ static void nbio_v7_4_handle_ras_controller_intr_no_bifring(struct amdgpu_device uint32_t bif_doorbell_intr_cntl; struct ras_manager *obj = amdgpu_ras_find_obj(adev, adev->nbio.ras_if); struct ras_err_data err_data = {0, 0, 0, NULL}; + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); bif_doorbell_intr_cntl = RREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL); if (REG_GET_FIELD(bif_doorbell_intr_cntl, @@ -312,28 +313,31 @@ static void nbio_v7_4_handle_ras_controller_intr_no_bifring(struct amdgpu_device RAS_CNTLR_INTERRUPT_CLEAR, 1); WREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl); - /* - * clear error status after ras_controller_intr according to - * hw team and count ue number for query - */ - nbio_v7_4_query_ras_error_count(adev, &err_data); - - /* logging on error counter and printing for awareness */ - obj->err_data.ue_count += err_data.ue_count; - obj->err_data.ce_count += err_data.ce_count; - - if (err_data.ce_count) - dev_info(adev->dev, "%ld correctable hardware " - "errors detected in %s block, " - "no user action is needed.\n", - obj->err_data.ce_count, - adev->nbio.ras_if->name); - - if (err_data.ue_count) - dev_info(adev->dev, "%ld uncorrectable hardware " - "errors detected in %s block\n", - obj->err_data.ue_count, - adev->nbio.ras_if->name); + if (!ras->disable_ras_err_cnt_harvest) { + /* + * clear error status after ras_controller_intr + * according to hw team and count ue number + * for query + */ + nbio_v7_4_query_ras_error_count(adev, &err_data); + + /* logging on error cnt and printing for awareness */ + obj->err_data.ue_count += err_data.ue_count; + obj->err_data.ce_count += err_data.ce_count; + + if (err_data.ce_count) + dev_info(adev->dev, "%ld correctable hardware " + "errors detected in %s block, " + "no user action is needed.\n", + obj->err_data.ce_count, + adev->nbio.ras_if->name); + + if (err_data.ue_count) + dev_info(adev->dev, "%ld uncorrectable hardware " + "errors detected in %s block\n", + obj->err_data.ue_count, + adev->nbio.ras_if->name); + } dev_info(adev->dev, "RAS controller interrupt triggered " "by NBIF error\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index ca11253e787c..4d1402356262 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -380,7 +380,7 @@ static int nv_asic_reset(struct amdgpu_device *adev) struct smu_context *smu = &adev->smu; if (nv_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) { - dev_info(adev->dev, "GPU BACO reset\n"); + dev_info(adev->dev, "BACO reset\n"); ret = smu_baco_enter(smu); if (ret) @@ -388,8 +388,10 @@ static int nv_asic_reset(struct amdgpu_device *adev) ret = smu_baco_exit(smu); if (ret) return ret; - } else + } else { + dev_info(adev->dev, "MODE1 reset\n"); ret = nv_asic_mode1_reset(adev); + } return ret; } @@ -690,6 +692,10 @@ static void nv_init_doorbell_index(struct amdgpu_device *adev) adev->doorbell_index.sdma_doorbell_range = 20; } +static void nv_pre_asic_init(struct amdgpu_device *adev) +{ +} + static const struct amdgpu_asic_funcs nv_asic_funcs = { .read_disabled_bios = &nv_read_disabled_bios, @@ -709,6 +715,7 @@ static const struct amdgpu_asic_funcs nv_asic_funcs = .need_reset_on_init = &nv_need_reset_on_init, .get_pcie_replay_count = &nv_get_pcie_replay_count, .supports_baco = &nv_asic_supports_baco, + .pre_asic_init = &nv_pre_asic_init, }; static int nv_common_early_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c index 6c9614f77d33..75489313dbad 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c @@ -38,6 +38,8 @@ #include "oss/osssys_4_0_sh_mask.h" MODULE_FIRMWARE("amdgpu/renoir_asd.bin"); +MODULE_FIRMWARE("amdgpu/renoir_ta.bin"); + /* address block */ #define smnMP1_FIRMWARE_FLAGS 0x3010024 @@ -45,7 +47,10 @@ static int psp_v12_0_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; const char *chip_name; + char fw_name[30]; int err = 0; + const struct ta_firmware_header_v1_0 *ta_hdr; + DRM_DEBUG("\n"); switch (adev->asic_type) { case CHIP_RENOIR: @@ -56,6 +61,55 @@ static int psp_v12_0_init_microcode(struct psp_context *psp) } err = psp_init_asd_microcode(psp, chip_name); + if (err) + goto out; + + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name); + err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev); + if (err) { + release_firmware(adev->psp.ta_fw); + adev->psp.ta_fw = NULL; + dev_info(adev->dev, + "psp v12.0: Failed to load firmware \"%s\"\n", + fw_name); + } else { + err = amdgpu_ucode_validate(adev->psp.ta_fw); + if (err) + goto out2; + + ta_hdr = (const struct ta_firmware_header_v1_0 *) + adev->psp.ta_fw->data; + adev->psp.ta_hdcp_ucode_version = + le32_to_cpu(ta_hdr->ta_hdcp_ucode_version); + adev->psp.ta_hdcp_ucode_size = + le32_to_cpu(ta_hdr->ta_hdcp_size_bytes); + adev->psp.ta_hdcp_start_addr = + (uint8_t *)ta_hdr + + le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); + + adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version); + + adev->psp.ta_dtm_ucode_version = + le32_to_cpu(ta_hdr->ta_dtm_ucode_version); + adev->psp.ta_dtm_ucode_size = + le32_to_cpu(ta_hdr->ta_dtm_size_bytes); + adev->psp.ta_dtm_start_addr = + (uint8_t *)adev->psp.ta_hdcp_start_addr + + le32_to_cpu(ta_hdr->ta_dtm_offset_bytes); + } + + return 0; + +out2: + release_firmware(adev->psp.ta_fw); + adev->psp.ta_fw = NULL; +out: + if (err) { + dev_err(adev->dev, + "psp v12.0: Failed to load firmware \"%s\"\n", + fw_name); + } + return err; } diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 1b449291f068..455d5e366c69 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -52,6 +52,8 @@ #include "bif/bif_3_0_d.h" #include "bif/bif_3_0_sh_mask.h" +#include "amdgpu_dm.h" + static const u32 tahiti_golden_registers[] = { mmAZALIA_SCLK_CONTROL, 0x00000030, 0x00000011, @@ -1215,10 +1217,100 @@ static bool si_read_bios_from_rom(struct amdgpu_device *adev, return true; } -//xxx: not implemented +static void si_set_clk_bypass_mode(struct amdgpu_device *adev) +{ + u32 tmp, i; + + tmp = RREG32(CG_SPLL_FUNC_CNTL); + tmp |= SPLL_BYPASS_EN; + WREG32(CG_SPLL_FUNC_CNTL, tmp); + + tmp = RREG32(CG_SPLL_FUNC_CNTL_2); + tmp |= SPLL_CTLREQ_CHG; + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + + for (i = 0; i < adev->usec_timeout; i++) { + if (RREG32(SPLL_STATUS) & SPLL_CHG_STATUS) + break; + udelay(1); + } + + tmp = RREG32(CG_SPLL_FUNC_CNTL_2); + tmp &= ~(SPLL_CTLREQ_CHG | SCLK_MUX_UPDATE); + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + + tmp = RREG32(MPLL_CNTL_MODE); + tmp &= ~MPLL_MCLK_SEL; + WREG32(MPLL_CNTL_MODE, tmp); +} + +static void si_spll_powerdown(struct amdgpu_device *adev) +{ + u32 tmp; + + tmp = RREG32(SPLL_CNTL_MODE); + tmp |= SPLL_SW_DIR_CONTROL; + WREG32(SPLL_CNTL_MODE, tmp); + + tmp = RREG32(CG_SPLL_FUNC_CNTL); + tmp |= SPLL_RESET; + WREG32(CG_SPLL_FUNC_CNTL, tmp); + + tmp = RREG32(CG_SPLL_FUNC_CNTL); + tmp |= SPLL_SLEEP; + WREG32(CG_SPLL_FUNC_CNTL, tmp); + + tmp = RREG32(SPLL_CNTL_MODE); + tmp &= ~SPLL_SW_DIR_CONTROL; + WREG32(SPLL_CNTL_MODE, tmp); +} + +static int si_gpu_pci_config_reset(struct amdgpu_device *adev) +{ + u32 i; + int r = -EINVAL; + + dev_info(adev->dev, "GPU pci config reset\n"); + + /* set mclk/sclk to bypass */ + si_set_clk_bypass_mode(adev); + /* powerdown spll */ + si_spll_powerdown(adev); + /* disable BM */ + pci_clear_master(adev->pdev); + /* reset */ + amdgpu_device_pci_config_reset(adev); + + udelay(100); + + /* wait for asic to come out of reset */ + for (i = 0; i < adev->usec_timeout; i++) { + if (RREG32(mmCONFIG_MEMSIZE) != 0xffffffff) { + /* enable BM */ + pci_set_master(adev->pdev); + adev->has_hw_reset = true; + r = 0; + break; + } + udelay(1); + } + + return r; +} + static int si_asic_reset(struct amdgpu_device *adev) { - return 0; + int r; + + dev_info(adev->dev, "PCI CONFIG reset\n"); + + amdgpu_atombios_scratch_regs_engine_hung(adev, true); + + r = si_gpu_pci_config_reset(adev); + + amdgpu_atombios_scratch_regs_engine_hung(adev, false); + + return r; } static bool si_asic_supports_baco(struct amdgpu_device *adev) @@ -1779,6 +1871,10 @@ static int si_set_vce_clocks(struct amdgpu_device *adev, u32 evclk, u32 ecclk) return 0; } +static void si_pre_asic_init(struct amdgpu_device *adev) +{ +} + static const struct amdgpu_asic_funcs si_asic_funcs = { .read_disabled_bios = &si_read_disabled_bios, @@ -1800,6 +1896,7 @@ static const struct amdgpu_asic_funcs si_asic_funcs = .need_reset_on_init = &si_need_reset_on_init, .get_pcie_replay_count = &si_get_pcie_replay_count, .supports_baco = &si_asic_supports_baco, + .pre_asic_init = &si_pre_asic_init, }; static uint32_t si_get_rev_id(struct amdgpu_device *adev) @@ -2546,6 +2643,10 @@ int si_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &si_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); +#if defined(CONFIG_DRM_AMD_DC) && defined(CONFIG_DRM_AMD_DC_SI) + else if (amdgpu_device_has_dc_support(adev)) + amdgpu_device_ip_block_add(adev, &dm_ip_block); +#endif else amdgpu_device_ip_block_add(adev, &dce_v6_0_ip_block); amdgpu_device_ip_block_add(adev, &uvd_v3_1_ip_block); @@ -2560,6 +2661,10 @@ int si_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &si_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); +#if defined(CONFIG_DRM_AMD_DC) && defined(CONFIG_DRM_AMD_DC_SI) + else if (amdgpu_device_has_dc_support(adev)) + amdgpu_device_ip_block_add(adev, &dm_ip_block); +#endif else amdgpu_device_ip_block_add(adev, &dce_v6_4_ip_block); amdgpu_device_ip_block_add(adev, &uvd_v3_1_ip_block); diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c index d55bf64770c4..7fb240c4990c 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -508,14 +508,9 @@ static bool smu_v11_0_i2c_bus_lock(struct i2c_adapter *control) struct amdgpu_device *adev = to_amdgpu_device(control); /* Send PPSMC_MSG_RequestI2CBus */ - if (!adev->powerplay.pp_funcs->smu_i2c_bus_access) - goto Fail; - - - if (!adev->powerplay.pp_funcs->smu_i2c_bus_access(adev->powerplay.pp_handle, true)) + if (!amdgpu_dpm_smu_i2c_bus_access(adev, true)) return true; -Fail: return false; } @@ -523,16 +518,10 @@ static bool smu_v11_0_i2c_bus_unlock(struct i2c_adapter *control) { struct amdgpu_device *adev = to_amdgpu_device(control); - /* Send PPSMC_MSG_RequestI2CBus */ - if (!adev->powerplay.pp_funcs->smu_i2c_bus_access) - goto Fail; - /* Send PPSMC_MSG_ReleaseI2CBus */ - if (!adev->powerplay.pp_funcs->smu_i2c_bus_access(adev->powerplay.pp_handle, - false)) + if (!amdgpu_dpm_smu_i2c_bus_access(adev, false)) return true; -Fail: return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 84d811b6e48b..2f93c475d6d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -580,10 +580,13 @@ static int soc15_asic_reset(struct amdgpu_device *adev) switch (soc15_asic_reset_method(adev)) { case AMD_RESET_METHOD_BACO: + dev_info(adev->dev, "BACO reset\n"); return soc15_asic_baco_reset(adev); case AMD_RESET_METHOD_MODE2: + dev_info(adev->dev, "MODE2 reset\n"); return amdgpu_dpm_mode2_reset(adev); default: + dev_info(adev->dev, "MODE1 reset\n"); return soc15_asic_mode1_reset(adev); } } @@ -1026,6 +1029,11 @@ static uint64_t soc15_get_pcie_replay_count(struct amdgpu_device *adev) return (nak_r + nak_g); } +static void soc15_pre_asic_init(struct amdgpu_device *adev) +{ + gmc_v9_0_restore_registers(adev); +} + static const struct amdgpu_asic_funcs soc15_asic_funcs = { .read_disabled_bios = &soc15_read_disabled_bios, @@ -1046,6 +1054,7 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs = .need_reset_on_init = &soc15_need_reset_on_init, .get_pcie_replay_count = &soc15_get_pcie_replay_count, .supports_baco = &soc15_supports_baco, + .pre_asic_init = &soc15_pre_asic_init, }; static const struct amdgpu_asic_funcs vega20_asic_funcs = @@ -1069,6 +1078,7 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs = .need_reset_on_init = &soc15_need_reset_on_init, .get_pcie_replay_count = &soc15_get_pcie_replay_count, .supports_baco = &soc15_supports_baco, + .pre_asic_init = &soc15_pre_asic_init, }; static int soc15_common_early_init(void *handle) @@ -1449,7 +1459,8 @@ static void soc15_update_hdp_light_sleep(struct amdgpu_device *adev, bool enable uint32_t def, data; if (adev->asic_type == CHIP_VEGA20 || - adev->asic_type == CHIP_ARCTURUS) { + adev->asic_type == CHIP_ARCTURUS || + adev->asic_type == CHIP_RENOIR) { def = data = RREG32(SOC15_REG_OFFSET(HDP, 0, mmHDP_MEM_POWER_CTRL)); if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS)) diff --git a/drivers/gpu/drm/amd/amdgpu/ta_rap_if.h b/drivers/gpu/drm/amd/amdgpu/ta_rap_if.h new file mode 100644 index 000000000000..f14833fae07c --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/ta_rap_if.h @@ -0,0 +1,84 @@ +/* + * Copyright 2020 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 _TA_RAP_IF_H +#define _TA_RAP_IF_H + +/* Responses have bit 31 set */ +#define RSP_ID_MASK (1U << 31) +#define RSP_ID(cmdId) (((uint32_t)(cmdId)) | RSP_ID_MASK) + +enum ta_rap_status { + TA_RAP_STATUS__SUCCESS = 1, + TA_RAP_STATUS__ERROR_GENERIC_FAILURE = 2, + TA_RAP_STATUS__ERROR_CMD_NOT_SUPPORTED = 3, + TA_RAP_STATUS__ERROR_INVALID_VALIDATION_METHOD = 4, + TA_RAP_STATUS__ERROR_NULL_POINTER = 5, + TA_RAP_STATUS__ERROR_NOT_INITIALIZED = 6, + TA_RAP_STATUS__ERROR_VALIDATION_FAILED = 7, + TA_RAP_STATUS__ERROR_ASIC_NOT_SUPPORTED = 8, + TA_RAP_STATUS__ERROR_OPERATION_NOT_PERMISSABLE = 9, + TA_RAP_STATUS__ERROR_ALREADY_INIT = 10, +}; + +enum ta_rap_cmd { + TA_CMD_RAP__INITIALIZE = 1, + TA_CMD_RAP__VALIDATE_L0 = 2, +}; + +enum ta_rap_validation_method { + METHOD_A = 1, +}; + +struct ta_rap_cmd_input_data { + uint8_t reserved[8]; +}; + +struct ta_rap_cmd_output_data { + uint32_t last_subsection; + uint32_t num_total_validate; + uint32_t num_valid; + uint32_t last_validate_addr; + uint32_t last_validate_val; + uint32_t last_validate_val_exptd; +}; + +union ta_rap_cmd_input { + struct ta_rap_cmd_input_data input; +}; + +union ta_rap_cmd_output { + struct ta_rap_cmd_output_data output; +}; + +struct ta_rap_shared_memory { + uint32_t cmd_id; + uint32_t validation_method_id; + uint32_t resp_id; + enum ta_rap_status rap_status; + union ta_rap_cmd_input rap_in_message; + union ta_rap_cmd_output rap_out_message; + uint8_t reserved[64]; +}; + +#endif // #define _TA_RAP_IF_H diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_1.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_1.c index 418cf097c918..5288617ca552 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_1.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_1.c @@ -32,20 +32,6 @@ #define UMC_6_INST_DIST 0x40000 -/* - * (addr / 256) * 8192, the higher 26 bits in ErrorAddr - * is the index of 8KB block - */ -#define ADDR_OF_8KB_BLOCK(addr) (((addr) & ~0xffULL) << 5) -/* channel index is the index of 256B block */ -#define ADDR_OF_256B_BLOCK(channel_index) ((channel_index) << 8) -/* offset in 256B block */ -#define OFFSET_IN_256B_BLOCK(addr) ((addr) & 0xffULL) - -#define LOOP_UMC_INST(umc_inst) for ((umc_inst) = 0; (umc_inst) < adev->umc.umc_inst_num; (umc_inst)++) -#define LOOP_UMC_CH_INST(ch_inst) for ((ch_inst) = 0; (ch_inst) < adev->umc.channel_inst_num; (ch_inst)++) -#define LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) LOOP_UMC_INST((umc_inst)) LOOP_UMC_CH_INST((ch_inst)) - const uint32_t umc_v6_1_channel_idx_tbl[UMC_V6_1_UMC_INSTANCE_NUM][UMC_V6_1_CHANNEL_INSTANCE_NUM] = { {2, 18, 11, 27}, {4, 20, 13, 29}, diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v8_7.c b/drivers/gpu/drm/amd/amdgpu/umc_v8_7.c new file mode 100644 index 000000000000..5665c77a9d58 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/umc_v8_7.c @@ -0,0 +1,331 @@ +/* + * Copyright 2020 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 "umc_v8_7.h" +#include "amdgpu_ras.h" +#include "amdgpu.h" + +#include "rsmu/rsmu_0_0_2_offset.h" +#include "rsmu/rsmu_0_0_2_sh_mask.h" +#include "umc/umc_8_7_0_offset.h" +#include "umc/umc_8_7_0_sh_mask.h" + +#define UMC_8_INST_DIST 0x40000 + +const uint32_t + umc_v8_7_channel_idx_tbl[UMC_V8_7_UMC_INSTANCE_NUM][UMC_V8_7_CHANNEL_INSTANCE_NUM] = { + {2, 11}, {4, 13}, + {1, 8}, {7, 14}, + {10, 3}, {12, 5}, + {9, 0}, {15, 6} +}; + +static inline uint32_t get_umc_8_reg_offset(struct amdgpu_device *adev, + uint32_t umc_inst, + uint32_t ch_inst) +{ + return adev->umc.channel_offs*ch_inst + UMC_8_INST_DIST*umc_inst; +} + +static void umc_v8_7_clear_error_count_per_channel(struct amdgpu_device *adev, + uint32_t umc_reg_offset) +{ + uint32_t ecc_err_cnt_addr; + uint32_t ecc_err_cnt_sel, ecc_err_cnt_sel_addr; + + ecc_err_cnt_sel_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_GeccErrCntSel); + ecc_err_cnt_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_GeccErrCnt); + + /* select the lower chip */ + ecc_err_cnt_sel = RREG32_PCIE((ecc_err_cnt_sel_addr + + umc_reg_offset) * 4); + ecc_err_cnt_sel = REG_SET_FIELD(ecc_err_cnt_sel, + UMCCH0_0_GeccErrCntSel, + GeccErrCntCsSel, 0); + WREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4, + ecc_err_cnt_sel); + + /* clear lower chip error count */ + WREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4, + UMC_V8_7_CE_CNT_INIT); + + /* select the higher chip */ + ecc_err_cnt_sel = RREG32_PCIE((ecc_err_cnt_sel_addr + + umc_reg_offset) * 4); + ecc_err_cnt_sel = REG_SET_FIELD(ecc_err_cnt_sel, + UMCCH0_0_GeccErrCntSel, + GeccErrCntCsSel, 1); + WREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4, + ecc_err_cnt_sel); + + /* clear higher chip error count */ + WREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4, + UMC_V8_7_CE_CNT_INIT); +} + +static void umc_v8_7_clear_error_count(struct amdgpu_device *adev) +{ + uint32_t umc_inst = 0; + uint32_t ch_inst = 0; + uint32_t umc_reg_offset = 0; + + LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { + umc_reg_offset = get_umc_8_reg_offset(adev, + umc_inst, + ch_inst); + + umc_v8_7_clear_error_count_per_channel(adev, + umc_reg_offset); + } +} + +static void umc_v8_7_query_correctable_error_count(struct amdgpu_device *adev, + uint32_t umc_reg_offset, + unsigned long *error_count) +{ + uint32_t ecc_err_cnt_sel, ecc_err_cnt_sel_addr; + uint32_t ecc_err_cnt, ecc_err_cnt_addr; + uint64_t mc_umc_status; + uint32_t mc_umc_status_addr; + + /* UMC 8_7_2 registers */ + ecc_err_cnt_sel_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_GeccErrCntSel); + ecc_err_cnt_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_GeccErrCnt); + mc_umc_status_addr = + SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0); + + /* select the lower chip and check the error count */ + ecc_err_cnt_sel = RREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4); + ecc_err_cnt_sel = REG_SET_FIELD(ecc_err_cnt_sel, UMCCH0_0_GeccErrCntSel, + GeccErrCntCsSel, 0); + WREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4, ecc_err_cnt_sel); + + ecc_err_cnt = RREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4); + *error_count += + (REG_GET_FIELD(ecc_err_cnt, UMCCH0_0_GeccErrCnt, GeccErrCnt) - + UMC_V8_7_CE_CNT_INIT); + + /* select the higher chip and check the err counter */ + ecc_err_cnt_sel = REG_SET_FIELD(ecc_err_cnt_sel, UMCCH0_0_GeccErrCntSel, + GeccErrCntCsSel, 1); + WREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4, ecc_err_cnt_sel); + + ecc_err_cnt = RREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4); + *error_count += + (REG_GET_FIELD(ecc_err_cnt, UMCCH0_0_GeccErrCnt, GeccErrCnt) - + UMC_V8_7_CE_CNT_INIT); + + /* check for SRAM correctable error + MCUMC_STATUS is a 64 bit register */ + mc_umc_status = RREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4); + if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, ErrorCodeExt) == 6 && + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 && + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, CECC) == 1) + *error_count += 1; +} + +static void umc_v8_7_querry_uncorrectable_error_count(struct amdgpu_device *adev, + uint32_t umc_reg_offset, + unsigned long *error_count) +{ + uint64_t mc_umc_status; + uint32_t mc_umc_status_addr; + + mc_umc_status_addr = SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0); + + /* check the MCUMC_STATUS */ + mc_umc_status = RREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4); + 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, Deferred) == 1 || + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UECC) == 1 || + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, PCC) == 1 || + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UC) == 1 || + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, TCC) == 1)) + *error_count += 1; +} + +static void umc_v8_7_query_ras_error_count(struct amdgpu_device *adev, + void *ras_error_status) +{ + struct ras_err_data* err_data = (struct ras_err_data*)ras_error_status; + + uint32_t umc_inst = 0; + uint32_t ch_inst = 0; + uint32_t umc_reg_offset = 0; + + LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { + umc_reg_offset = get_umc_8_reg_offset(adev, + umc_inst, + ch_inst); + + umc_v8_7_query_correctable_error_count(adev, + umc_reg_offset, + &(err_data->ce_count)); + umc_v8_7_querry_uncorrectable_error_count(adev, + umc_reg_offset, + &(err_data->ue_count)); + } + + umc_v8_7_clear_error_count(adev); +} + +static void umc_v8_7_query_error_address(struct amdgpu_device *adev, + struct ras_err_data *err_data, + uint32_t umc_reg_offset, + uint32_t ch_inst, + uint32_t umc_inst) +{ + uint32_t lsb, mc_umc_status_addr; + uint64_t mc_umc_status, err_addr, retired_page, mc_umc_addrt0; + struct eeprom_table_record *err_rec; + uint32_t channel_index = adev->umc.channel_idx_tbl[umc_inst * adev->umc.channel_inst_num + ch_inst]; + + mc_umc_status_addr = + SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0); + mc_umc_addrt0 = + SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_ADDRT0); + + mc_umc_status = RREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4); + + if (mc_umc_status == 0) + return; + + if (!err_data->err_addr) { + /* clear umc status */ + WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); + return; + } + + err_rec = &err_data->err_addr[err_data->err_addr_cnt]; + + /* calculate error address if ue/ce 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, UECC) == 1 || + REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, CECC) == 1)) { + + err_addr = RREG64_PCIE((mc_umc_addrt0 + umc_reg_offset) * 4); + /* the lowest lsb bits should be ignored */ + lsb = REG_GET_FIELD(err_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, LSB); + err_addr = REG_GET_FIELD(err_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr); + err_addr &= ~((0x1ULL << lsb) - 1); + + /* translate umc channel address to soc pa, 3 parts are included */ + retired_page = ADDR_OF_8KB_BLOCK(err_addr) | + ADDR_OF_256B_BLOCK(channel_index) | + OFFSET_IN_256B_BLOCK(err_addr); + + /* we only save ue error information currently, ce is skipped */ + if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UECC) + == 1) { + err_rec->address = err_addr; + /* page frame address is saved */ + err_rec->retired_page = retired_page >> AMDGPU_GPU_PAGE_SHIFT; + err_rec->ts = (uint64_t)ktime_get_real_seconds(); + err_rec->err_type = AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE; + err_rec->cu = 0; + err_rec->mem_channel = channel_index; + err_rec->mcumc_id = umc_inst; + + err_data->err_addr_cnt++; + } + } + + /* clear umc status */ + WREG64_PCIE((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); +} + +static void umc_v8_7_query_ras_error_address(struct amdgpu_device *adev, + void *ras_error_status) +{ + struct ras_err_data* err_data = (struct ras_err_data*)ras_error_status; + + uint32_t umc_inst = 0; + uint32_t ch_inst = 0; + uint32_t umc_reg_offset = 0; + + LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { + umc_reg_offset = get_umc_8_reg_offset(adev, + umc_inst, + ch_inst); + + umc_v8_7_query_error_address(adev, + err_data, + umc_reg_offset, + ch_inst, + umc_inst); + } +} + +static void umc_v8_7_err_cnt_init_per_channel(struct amdgpu_device *adev, + uint32_t umc_reg_offset) +{ + uint32_t ecc_err_cnt_sel, ecc_err_cnt_sel_addr; + uint32_t ecc_err_cnt_addr; + + ecc_err_cnt_sel_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_GeccErrCntSel); + ecc_err_cnt_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_GeccErrCnt); + + /* select the lower chip and check the error count */ + ecc_err_cnt_sel = RREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4); + ecc_err_cnt_sel = REG_SET_FIELD(ecc_err_cnt_sel, UMCCH0_0_GeccErrCntSel, + GeccErrCntCsSel, 0); + /* set ce error interrupt type to APIC based interrupt */ + ecc_err_cnt_sel = REG_SET_FIELD(ecc_err_cnt_sel, UMCCH0_0_GeccErrCntSel, + GeccErrInt, 0x1); + WREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4, ecc_err_cnt_sel); + /* set error count to initial value */ + WREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4, UMC_V8_7_CE_CNT_INIT); + + /* select the higher chip and check the err counter */ + ecc_err_cnt_sel = REG_SET_FIELD(ecc_err_cnt_sel, UMCCH0_0_GeccErrCntSel, + GeccErrCntCsSel, 1); + WREG32_PCIE((ecc_err_cnt_sel_addr + umc_reg_offset) * 4, ecc_err_cnt_sel); + WREG32_PCIE((ecc_err_cnt_addr + umc_reg_offset) * 4, UMC_V8_7_CE_CNT_INIT); +} + +static void umc_v8_7_err_cnt_init(struct amdgpu_device *adev) +{ + uint32_t umc_inst = 0; + uint32_t ch_inst = 0; + uint32_t umc_reg_offset = 0; + + LOOP_UMC_INST_AND_CH(umc_inst, ch_inst) { + umc_reg_offset = get_umc_8_reg_offset(adev, + umc_inst, + ch_inst); + + umc_v8_7_err_cnt_init_per_channel(adev, umc_reg_offset); + } +} + +const struct amdgpu_umc_funcs umc_v8_7_funcs = { + .err_cnt_init = umc_v8_7_err_cnt_init, + .ras_late_init = amdgpu_umc_ras_late_init, + .query_ras_error_count = umc_v8_7_query_ras_error_count, + .query_ras_error_address = umc_v8_7_query_ras_error_address, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v8_7.h b/drivers/gpu/drm/amd/amdgpu/umc_v8_7.h new file mode 100644 index 000000000000..d4d0468e3df5 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/umc_v8_7.h @@ -0,0 +1,51 @@ +/* + * Copyright 2020 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 __UMC_V8_7_H__ +#define __UMC_V8_7_H__ + +#include "soc15_common.h" +#include "amdgpu.h" + +/* HBM Memory Channel Width */ +#define UMC_V8_7_HBM_MEMORY_CHANNEL_WIDTH 128 +/* number of umc channel instance with memory map register access */ +#define UMC_V8_7_CHANNEL_INSTANCE_NUM 2 +/* number of umc instance with memory map register access */ +#define UMC_V8_7_UMC_INSTANCE_NUM 8 +/* total channel instances in one umc block */ +#define UMC_V8_7_TOTAL_CHANNEL_NUM (UMC_V8_7_CHANNEL_INSTANCE_NUM * UMC_V8_7_UMC_INSTANCE_NUM) +/* UMC regiser per channel offset */ +#define UMC_V8_7_PER_CHANNEL_OFFSET_SIENNA 0x400 + +/* EccErrCnt max value */ +#define UMC_V8_7_CE_CNT_MAX 0xffff +/* umc ce interrupt threshold */ +#define UMC_V8_7_CE_INT_THRESHOLD 0xffff +/* umc ce count initial value */ +#define UMC_V8_7_CE_CNT_INIT (UMC_V8_7_CE_CNT_MAX - UMC_V8_7_CE_INT_THRESHOLD) + +extern const struct amdgpu_umc_funcs umc_v8_7_funcs; +extern const uint32_t + umc_v8_7_channel_idx_tbl[UMC_V8_7_UMC_INSTANCE_NUM][UMC_V8_7_CHANNEL_INSTANCE_NUM]; + +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index e99bef6e2354..139fac0d8e76 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -80,23 +80,18 @@ static int vcn_v2_5_early_init(void *handle) adev->vcn.harvest_config = 0; adev->vcn.num_enc_rings = 1; } else { - if (adev->asic_type == CHIP_ARCTURUS) { - u32 harvest; - int i; - - adev->vcn.num_vcn_inst = VCN25_MAX_HW_INSTANCES_ARCTURUS; - for (i = 0; i < adev->vcn.num_vcn_inst; i++) { - harvest = RREG32_SOC15(VCN, i, mmCC_UVD_HARVESTING); - if (harvest & CC_UVD_HARVESTING__UVD_DISABLE_MASK) - adev->vcn.harvest_config |= 1 << i; - } - - if (adev->vcn.harvest_config == (AMDGPU_VCN_HARVEST_VCN0 | - AMDGPU_VCN_HARVEST_VCN1)) - /* both instances are harvested, disable the block */ - return -ENOENT; - } else - adev->vcn.num_vcn_inst = 1; + u32 harvest; + int i; + adev->vcn.num_vcn_inst = VCN25_MAX_HW_INSTANCES_ARCTURUS; + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + harvest = RREG32_SOC15(VCN, i, mmCC_UVD_HARVESTING); + if (harvest & CC_UVD_HARVESTING__UVD_DISABLE_MASK) + adev->vcn.harvest_config |= 1 << i; + } + if (adev->vcn.harvest_config == (AMDGPU_VCN_HARVEST_VCN0 | + AMDGPU_VCN_HARVEST_VCN1)) + /* both instances are harvested, disable the block */ + return -ENOENT; adev->vcn.num_enc_rings = 2; } @@ -1108,7 +1103,7 @@ static int vcn_v2_5_mmsch_start(struct amdgpu_device *adev, { uint32_t data = 0, loop = 0, size = 0; uint64_t addr = table->gpu_addr; - struct mmsch_v1_1_init_header *header = NULL;; + struct mmsch_v1_1_init_header *header = NULL; header = (struct mmsch_v1_1_init_header *)table->cpu_addr; size = header->total_size; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 63e5547cfb16..589d6cd8adec 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -198,7 +198,7 @@ static int vcn_v3_0_sw_init(void *handle) } else { ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 8 * i; } - if (i != 0) + if (adev->asic_type == CHIP_SIENNA_CICHLID && i != 0) ring->no_scheduler = true; sprintf(ring->name, "vcn_dec_%d", i); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0, @@ -222,7 +222,7 @@ static int vcn_v3_0_sw_init(void *handle) } else { ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + j + 8 * i; } - if (i != 1) + if (adev->asic_type == CHIP_SIENNA_CICHLID && i != 1) ring->no_scheduler = true; sprintf(ring->name, "vcn_enc_%d.%d", i, j); r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0, diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index f6f2ed0830b1..9bcd0eebc6d7 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -752,8 +752,10 @@ static int vi_asic_reset(struct amdgpu_device *adev) int r; if (vi_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) { + dev_info(adev->dev, "BACO reset\n"); r = amdgpu_dpm_baco_reset(adev); } else { + dev_info(adev->dev, "PCI CONFIG reset\n"); r = vi_asic_pci_config_reset(adev); } @@ -1066,6 +1068,10 @@ static bool vi_need_reset_on_init(struct amdgpu_device *adev) return false; } +static void vi_pre_asic_init(struct amdgpu_device *adev) +{ +} + static const struct amdgpu_asic_funcs vi_asic_funcs = { .read_disabled_bios = &vi_read_disabled_bios, @@ -1086,6 +1092,7 @@ static const struct amdgpu_asic_funcs vi_asic_funcs = .need_reset_on_init = &vi_need_reset_on_init, .get_pcie_replay_count = &vi_get_pcie_replay_count, .supports_baco = &vi_asic_supports_baco, + .pre_asic_init = &vi_pre_asic_init, }; #define CZ_REV_BRISTOL(rev) \ @@ -1507,8 +1514,7 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, PP_BLOCK_SYS_MC, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & (AMD_CG_SUPPORT_SDMA_LS | AMD_CG_SUPPORT_SDMA_MGCG)) { @@ -1526,8 +1532,7 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, PP_BLOCK_SYS_SDMA, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_MGCG)) { @@ -1545,8 +1550,7 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, PP_BLOCK_SYS_HDP, pp_support_state, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } @@ -1560,8 +1564,7 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, PP_BLOCK_SYS_BIF, PP_STATE_SUPPORT_LS, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & AMD_CG_SUPPORT_BIF_MGCG) { if (state == AMD_CG_STATE_UNGATE) @@ -1573,8 +1576,7 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, PP_BLOCK_SYS_BIF, PP_STATE_SUPPORT_CG, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & AMD_CG_SUPPORT_DRM_LS) { @@ -1588,8 +1590,7 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, PP_BLOCK_SYS_DRM, PP_STATE_SUPPORT_LS, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } if (adev->cg_flags & AMD_CG_SUPPORT_ROM_MGCG) { @@ -1603,8 +1604,7 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, PP_BLOCK_SYS_ROM, PP_STATE_SUPPORT_CG, pp_state); - if (adev->powerplay.pp_funcs->set_clockgating_by_smu) - amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); + amdgpu_dpm_set_clockgating_by_smu(adev, msg_id); } return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index 577d901fdb63..affbca7c0050 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -911,7 +911,7 @@ static const uint32_t cwsr_trap_nv1x_hex[] = { 0x705d0000, 0x807c817c, 0x8070ff70, 0x00000080, 0xbf0a7b7c, 0xbf85fff8, - 0xbf82014f, 0xbef4037e, + 0xbf820151, 0xbef4037e, 0x8775ff7f, 0x0000ffff, 0x8875ff75, 0x00040000, 0xbef60380, 0xbef703ff, @@ -1024,61 +1024,62 @@ static const uint32_t cwsr_trap_nv1x_hex[] = { 0xbe883108, 0xbe8a310a, 0xbe8c310c, 0xbe8e310e, 0xbf06807c, 0xbf84fff0, - 0xb9782a05, 0x80788178, - 0xbf0d9972, 0xbf850002, - 0x8f788978, 0xbf820001, - 0x8f788a78, 0xb96e1e06, - 0x8f6e8a6e, 0x80786e78, - 0x8078ff78, 0x00000200, - 0xbef603ff, 0x01000000, - 0xf4211bfa, 0xf0000000, - 0x80788478, 0xf4211b3a, + 0xba80f801, 0x00000000, + 0xbf8a0000, 0xb9782a05, + 0x80788178, 0xbf0d9972, + 0xbf850002, 0x8f788978, + 0xbf820001, 0x8f788a78, + 0xb96e1e06, 0x8f6e8a6e, + 0x80786e78, 0x8078ff78, + 0x00000200, 0xbef603ff, + 0x01000000, 0xf4211bfa, 0xf0000000, 0x80788478, - 0xf4211b7a, 0xf0000000, - 0x80788478, 0xf4211c3a, + 0xf4211b3a, 0xf0000000, + 0x80788478, 0xf4211b7a, 0xf0000000, 0x80788478, - 0xf4211c7a, 0xf0000000, - 0x80788478, 0xf4211eba, + 0xf4211c3a, 0xf0000000, + 0x80788478, 0xf4211c7a, 0xf0000000, 0x80788478, - 0xf4211efa, 0xf0000000, - 0x80788478, 0xf4211e7a, + 0xf4211eba, 0xf0000000, + 0x80788478, 0xf4211efa, 0xf0000000, 0x80788478, - 0xf4211cfa, 0xf0000000, - 0x80788478, 0xf4211bba, + 0xf4211e7a, 0xf0000000, + 0x80788478, 0xf4211cfa, 0xf0000000, 0x80788478, - 0xbf8cc07f, 0xb9eef814, 0xf4211bba, 0xf0000000, 0x80788478, 0xbf8cc07f, - 0xb9eef815, 0xbefc036f, - 0xbefe0370, 0xbeff0371, - 0x876f7bff, 0x000003ff, - 0xb9ef4803, 0xb9f9f816, - 0x876f7bff, 0xfffff800, - 0x906f8b6f, 0xb9efa2c3, - 0xb9f3f801, 0xb96e2a05, - 0x806e816e, 0xbf0d9972, - 0xbf850002, 0x8f6e896e, - 0xbf820001, 0x8f6e8a6e, - 0x806eff6e, 0x00000200, - 0x806e746e, 0x826f8075, - 0x876fff6f, 0x0000ffff, - 0xf4091c37, 0xfa000050, - 0xf4091d37, 0xfa000060, - 0xf4011e77, 0xfa000074, - 0xbf8cc07f, 0x876fff6d, - 0xfc000000, 0x906f9a6f, - 0x8f6f906f, 0xbeee0380, + 0xb9eef814, 0xf4211bba, + 0xf0000000, 0x80788478, + 0xbf8cc07f, 0xb9eef815, + 0xbefc036f, 0xbefe0370, + 0xbeff0371, 0x876f7bff, + 0x000003ff, 0xb9ef4803, + 0xb9f9f816, 0x876f7bff, + 0xfffff800, 0x906f8b6f, + 0xb9efa2c3, 0xb9f3f801, + 0xb96e2a05, 0x806e816e, + 0xbf0d9972, 0xbf850002, + 0x8f6e896e, 0xbf820001, + 0x8f6e8a6e, 0x806eff6e, + 0x00000200, 0x806e746e, + 0x826f8075, 0x876fff6f, + 0x0000ffff, 0xf4091c37, + 0xfa000050, 0xf4091d37, + 0xfa000060, 0xf4011e77, + 0xfa000074, 0xbf8cc07f, + 0x876fff6d, 0xfc000000, + 0x906f9a6f, 0x8f6f906f, + 0xbeee0380, 0x886e6f6e, + 0x876fff6d, 0x02000000, + 0x906f996f, 0x8f6f8f6f, 0x886e6f6e, 0x876fff6d, - 0x02000000, 0x906f996f, - 0x8f6f8f6f, 0x886e6f6e, - 0x876fff6d, 0x01000000, - 0x906f986f, 0x8f6f996f, - 0x886e6f6e, 0x876fff7a, - 0x00800000, 0x906f976f, - 0xb9eef807, 0x876dff6d, - 0x0000ffff, 0x87fe7e7e, - 0x87ea6a6a, 0xb9faf802, - 0xbf8a0000, 0xbe80226c, + 0x01000000, 0x906f986f, + 0x8f6f996f, 0x886e6f6e, + 0x876fff7a, 0x00800000, + 0x906f976f, 0xb9eef807, + 0x876dff6d, 0x0000ffff, + 0x87fe7e7e, 0x87ea6a6a, + 0xb9faf802, 0xbe80226c, 0xbf810000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, @@ -1807,7 +1808,7 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0x705d0000, 0x807c817c, 0x8070ff70, 0x00000080, 0xbf0a7b7c, 0xbf85fff8, - 0xbf82013a, 0xbef4037e, + 0xbf82013c, 0xbef4037e, 0x8775ff7f, 0x0000ffff, 0x8875ff75, 0x00040000, 0xbef60380, 0xbef703ff, @@ -1920,50 +1921,51 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0xbe883108, 0xbe8a310a, 0xbe8c310c, 0xbe8e310e, 0xbf06807c, 0xbf84fff0, - 0xb9782a05, 0x80788178, - 0xbf0d9972, 0xbf850002, - 0x8f788978, 0xbf820001, - 0x8f788a78, 0xb96e1e06, - 0x8f6e8a6e, 0x80786e78, - 0x8078ff78, 0x00000200, - 0xbef603ff, 0x01000000, - 0xf4211bfa, 0xf0000000, - 0x80788478, 0xf4211b3a, + 0xba80f801, 0x00000000, + 0xbf8a0000, 0xb9782a05, + 0x80788178, 0xbf0d9972, + 0xbf850002, 0x8f788978, + 0xbf820001, 0x8f788a78, + 0xb96e1e06, 0x8f6e8a6e, + 0x80786e78, 0x8078ff78, + 0x00000200, 0xbef603ff, + 0x01000000, 0xf4211bfa, 0xf0000000, 0x80788478, - 0xf4211b7a, 0xf0000000, - 0x80788478, 0xf4211c3a, + 0xf4211b3a, 0xf0000000, + 0x80788478, 0xf4211b7a, 0xf0000000, 0x80788478, - 0xf4211c7a, 0xf0000000, - 0x80788478, 0xf4211eba, + 0xf4211c3a, 0xf0000000, + 0x80788478, 0xf4211c7a, 0xf0000000, 0x80788478, - 0xf4211efa, 0xf0000000, - 0x80788478, 0xf4211e7a, + 0xf4211eba, 0xf0000000, + 0x80788478, 0xf4211efa, 0xf0000000, 0x80788478, - 0xf4211cfa, 0xf0000000, - 0x80788478, 0xf4211bba, + 0xf4211e7a, 0xf0000000, + 0x80788478, 0xf4211cfa, 0xf0000000, 0x80788478, - 0xbf8cc07f, 0xb9eef814, 0xf4211bba, 0xf0000000, 0x80788478, 0xbf8cc07f, - 0xb9eef815, 0xbefc036f, - 0xbefe0370, 0xbeff0371, - 0x876f7bff, 0x000003ff, - 0xb9ef4803, 0x876f7bff, - 0xfffff800, 0x906f8b6f, - 0xb9efa2c3, 0xb9f3f801, - 0xb96e2a05, 0x806e816e, - 0xbf0d9972, 0xbf850002, - 0x8f6e896e, 0xbf820001, - 0x8f6e8a6e, 0x806eff6e, - 0x00000200, 0x806e746e, - 0x826f8075, 0x876fff6f, - 0x0000ffff, 0xf4091c37, - 0xfa000050, 0xf4091d37, - 0xfa000060, 0xf4011e77, - 0xfa000074, 0xbf8cc07f, - 0x876dff6d, 0x0000ffff, - 0x87fe7e7e, 0x87ea6a6a, - 0xb9faf802, 0xbf8a0000, + 0xb9eef814, 0xf4211bba, + 0xf0000000, 0x80788478, + 0xbf8cc07f, 0xb9eef815, + 0xbefc036f, 0xbefe0370, + 0xbeff0371, 0x876f7bff, + 0x000003ff, 0xb9ef4803, + 0x876f7bff, 0xfffff800, + 0x906f8b6f, 0xb9efa2c3, + 0xb9f3f801, 0xb96e2a05, + 0x806e816e, 0xbf0d9972, + 0xbf850002, 0x8f6e896e, + 0xbf820001, 0x8f6e8a6e, + 0x806eff6e, 0x00000200, + 0x806e746e, 0x826f8075, + 0x876fff6f, 0x0000ffff, + 0xf4091c37, 0xfa000050, + 0xf4091d37, 0xfa000060, + 0xf4011e77, 0xfa000074, + 0xbf8cc07f, 0x876dff6d, + 0x0000ffff, 0x87fe7e7e, + 0x87ea6a6a, 0xb9faf802, 0xbe80226c, 0xbf810000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 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 5b220f2a7501..5081f91190b8 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm @@ -894,6 +894,11 @@ L_RESTORE_SGPR: s_cmp_eq_u32 m0, 0 //scc = (m0 < s_sgpr_save_num) ? 1 : 0 s_cbranch_scc0 L_RESTORE_SGPR_LOOP + // s_barrier with MODE.DEBUG_EN=1, STATUS.PRIV=1 incorrectly asserts debug exception. + // Clear DEBUG_EN before and restore MODE after the barrier. + s_setreg_imm32_b32 hwreg(HW_REG_MODE), 0 + s_barrier //barrier to ensure the readiness of LDS before access attemps from any other wave in the same TG + /* restore HW registers */ L_RESTORE_HWREG: // HWREG SR memory offset : size(VGPR)+size(SVGPR)+size(SGPR) @@ -976,8 +981,6 @@ L_RESTORE_HWREG: s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32 s_setreg_b32 hwreg(HW_REG_STATUS), s_restore_status // SCC is included, which is changed by previous salu - s_barrier //barrier to ensure the readiness of LDS before access attemps from any other wave in the same TG - s_rfe_b64 s_restore_pc_lo //Return to the main shader program and resume execution L_END_PGM: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index e9b96ad3d9a5..b7b16adb0615 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1254,7 +1254,7 @@ bool kfd_dev_is_large_bar(struct kfd_dev *dev) return true; } - if (dev->device_info->needs_iommu_device) + if (dev->use_iommu_v2) return false; amdgpu_amdkfd_get_local_mem_info(dev->kgd, &mem_info); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 6a250f8fcfb8..3fac06b281ce 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -742,6 +742,22 @@ static int kfd_fill_gpu_cache_info(struct kfd_dev *kdev, return 0; } +static bool kfd_ignore_crat(void) +{ + bool ret; + + if (ignore_crat) + return true; + +#ifndef KFD_SUPPORT_IOMMU_V2 + ret = true; +#else + ret = false; +#endif + + return ret; +} + /* * kfd_create_crat_image_acpi - Allocates memory for CRAT image and * copies CRAT from ACPI (if available). @@ -776,7 +792,7 @@ int kfd_create_crat_image_acpi(void **crat_image, size_t *size) return -EINVAL; } - if (ignore_crat) { + if (kfd_ignore_crat()) { pr_info("CRAT table disabled by module option\n"); return -ENODATA; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 4bfedaab183f..0e71a0543f98 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -29,6 +29,7 @@ #include "cwsr_trap_handler.h" #include "kfd_iommu.h" #include "amdgpu_amdkfd.h" +#include "kfd_smi_events.h" #define MQD_SIZE_ALIGNED 768 @@ -115,6 +116,7 @@ static const struct kfd_device_info carrizo_device_info = { .num_xgmi_sdma_engines = 0, .num_sdma_queues_per_engine = 2, }; +#endif static const struct kfd_device_info raven_device_info = { .asic_family = CHIP_RAVEN, @@ -133,7 +135,6 @@ static const struct kfd_device_info raven_device_info = { .num_xgmi_sdma_engines = 0, .num_sdma_queues_per_engine = 2, }; -#endif static const struct kfd_device_info hawaii_device_info = { .asic_family = CHIP_HAWAII, @@ -711,11 +712,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto kfd_doorbell_error; } - if (kfd->kfd2kgd->get_hive_id) - kfd->hive_id = kfd->kfd2kgd->get_hive_id(kfd->kgd); + kfd->hive_id = amdgpu_amdkfd_get_hive_id(kfd->kgd); - if (kfd->kfd2kgd->get_unique_id) - kfd->unique_id = kfd->kfd2kgd->get_unique_id(kfd->kgd); + kfd->unique_id = amdgpu_amdkfd_get_unique_id(kfd->kgd); if (kfd_interrupt_init(kfd)) { dev_err(kfd_device, "Error initializing interrupts\n"); @@ -737,6 +736,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto gws_error; } + /* If CRAT is broken, won't set iommu enabled */ + kfd_double_confirm_iommu_support(kfd); + if (kfd_iommu_device_init(kfd)) { dev_err(kfd_device, "Error initializing iommuv2\n"); goto device_iommu_error; @@ -810,6 +812,8 @@ int kgd2kfd_pre_reset(struct kfd_dev *kfd) if (!kfd->init_complete) return 0; + kfd_smi_event_update_gpu_reset(kfd, false); + kfd->dqm->ops.pre_reset(kfd->dqm); kgd2kfd_suspend(kfd, false); @@ -838,6 +842,8 @@ int kgd2kfd_post_reset(struct kfd_dev *kfd) atomic_set(&kfd->sram_ecc_flag, 0); + kfd_smi_event_update_gpu_reset(kfd, true); + return 0; } @@ -1245,6 +1251,12 @@ void kfd_dec_compute_active(struct kfd_dev *kfd) WARN_ONCE(count < 0, "Compute profile ref. count error"); } +void kgd2kfd_smi_event_throttle(struct kfd_dev *kfd, uint32_t throttle_bitmask) +{ + if (kfd) + kfd_smi_event_update_thermal_throttling(kfd, throttle_bitmask); +} + #if defined(CONFIG_DEBUG_FS) /* This function will send a package to HIQ to hang the HWS diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index e0e60b0d0669..560adc57a050 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -153,30 +153,6 @@ static void decrement_queue_count(struct device_queue_manager *dqm, dqm->active_cp_queue_count--; } -int read_sdma_queue_counter(uint64_t q_rptr, uint64_t *val) -{ - int ret; - uint64_t tmp = 0; - - if (!val) - return -EINVAL; - /* - * SDMA activity counter is stored at queue's RPTR + 0x8 location. - */ - if (!access_ok((const void __user *)(q_rptr + - sizeof(uint64_t)), sizeof(uint64_t))) { - pr_err("Can't access sdma queue activity counter\n"); - return -EFAULT; - } - - ret = get_user(tmp, (uint64_t *)(q_rptr + sizeof(uint64_t))); - if (!ret) { - *val = tmp; - } - - return ret; -} - static int allocate_doorbell(struct qcm_process_device *qpd, struct queue *q) { struct kfd_dev *dev = qpd->dqm->dev; @@ -552,7 +528,7 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, /* Get the SDMA queue stats */ if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) || (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) { - retval = read_sdma_queue_counter((uint64_t)q->properties.read_ptr, + retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr, &sdma_val); if (retval) pr_err("Failed to read SDMA queue counter for queue: %d\n", @@ -1473,7 +1449,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, /* Get the SDMA queue stats */ if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) || (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) { - retval = read_sdma_queue_counter((uint64_t)q->properties.read_ptr, + retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr, &sdma_val); if (retval) pr_err("Failed to read SDMA queue counter for queue: %d\n", diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 49d8e324c636..16262e5d93f5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -251,5 +251,11 @@ static inline void dqm_unlock(struct device_queue_manager *dqm) mutex_unlock(&dqm->lock_hidden); } -int read_sdma_queue_counter(uint64_t q_rptr, uint64_t *val); +static inline int read_sdma_queue_counter(uint64_t __user *q_rptr, uint64_t *val) +{ + /* + * SDMA activity counter is stored at queue's RPTR + 0x8 location. + */ + return get_user(*val, q_rptr + 1); +} #endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c index 95a82ac455f2..309f63a0b34a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c @@ -62,7 +62,7 @@ static int update_qpd_v9(struct device_queue_manager *dqm, SH_MEM_ALIGNMENT_MODE_UNALIGNED << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT; if (amdgpu_noretry && - !dqm->dev->device_info->needs_iommu_device) + !dqm->dev->use_iommu_v2) qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c index c1166c40ac15..3c22909470f2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c @@ -321,7 +321,7 @@ static void kfd_init_apertures_vi(struct kfd_process_device *pdd, uint8_t id) pdd->lds_base = MAKE_LDS_APP_BASE_VI(); pdd->lds_limit = MAKE_LDS_APP_LIMIT(pdd->lds_base); - if (!pdd->dev->device_info->needs_iommu_device) { + if (!pdd->dev->use_iommu_v2) { /* dGPUs: SVM aperture starting at 0 * with small reserved space for kernel. * Set them to CANONICAL addresses. @@ -425,7 +425,7 @@ int kfd_init_apertures(struct kfd_process *process) return -EINVAL; } - if (!dev->device_info->needs_iommu_device) { + if (!dev->use_iommu_v2) { /* dGPUs: the reserved space for kernel * before SVM */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c index 7c8786b9eb0a..5a64915abaf7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c @@ -41,7 +41,7 @@ int kfd_iommu_check_device(struct kfd_dev *kfd) struct amd_iommu_device_info iommu_info; int err; - if (!kfd->device_info->needs_iommu_device) + if (!kfd->use_iommu_v2) return -ENODEV; iommu_info.flags = 0; @@ -63,7 +63,7 @@ int kfd_iommu_device_init(struct kfd_dev *kfd) unsigned int pasid_limit; int err; - if (!kfd->device_info->needs_iommu_device) + if (!kfd->use_iommu_v2) return 0; iommu_info.flags = 0; @@ -109,7 +109,7 @@ int kfd_iommu_bind_process_to_device(struct kfd_process_device *pdd) struct kfd_process *p = pdd->process; int err; - if (!dev->device_info->needs_iommu_device || pdd->bound == PDD_BOUND) + if (!dev->use_iommu_v2 || pdd->bound == PDD_BOUND) return 0; if (unlikely(pdd->bound == PDD_BOUND_SUSPENDED)) { @@ -284,7 +284,7 @@ static void kfd_unbind_processes_from_device(struct kfd_dev *kfd) */ void kfd_iommu_suspend(struct kfd_dev *kfd) { - if (!kfd->device_info->needs_iommu_device) + if (!kfd->use_iommu_v2) return; kfd_unbind_processes_from_device(kfd); @@ -304,7 +304,7 @@ int kfd_iommu_resume(struct kfd_dev *kfd) unsigned int pasid_limit; int err; - if (!kfd->device_info->needs_iommu_device) + if (!kfd->use_iommu_v2) return 0; pasid_limit = kfd_get_pasid_limit(); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 6727e9de5b8b..023629f28495 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -297,6 +297,9 @@ struct kfd_dev { bool pci_atomic_requested; + /* Use IOMMU v2 flag */ + bool use_iommu_v2; + /* SRAM ECC flag */ atomic_t sram_ecc_flag; @@ -309,6 +312,8 @@ struct kfd_dev { /* Clients watching SMI events */ struct list_head smi_clients; spinlock_t smi_lock; + + uint32_t reset_seq_num; }; enum kfd_mempool { @@ -892,6 +897,7 @@ struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev); struct kfd_dev *kfd_device_by_kgd(const struct kgd_dev *kgd); int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_dev **kdev); int kfd_numa_node_to_apic_id(int numa_node_id); +void kfd_double_confirm_iommu_support(struct kfd_dev *gpu); /* Interrupts */ int kfd_interrupt_init(struct kfd_dev *dev); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 40695d52e9a8..a0e12a79ab7d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -87,7 +87,7 @@ struct kfd_sdma_activity_handler_workarea { }; struct temp_sdma_queue_list { - uint64_t rptr; + uint64_t __user *rptr; uint64_t sdma_val; unsigned int queue_id; struct list_head list; @@ -159,7 +159,7 @@ static void kfd_sdma_activity_worker(struct work_struct *work) } INIT_LIST_HEAD(&sdma_q->list); - sdma_q->rptr = (uint64_t)q->properties.read_ptr; + sdma_q->rptr = (uint64_t __user *)q->properties.read_ptr; sdma_q->queue_id = q->properties.queue_id; list_add_tail(&sdma_q->list, &sdma_q_list.list); } @@ -218,7 +218,7 @@ static void kfd_sdma_activity_worker(struct work_struct *work) continue; list_for_each_entry_safe(sdma_q, next, &sdma_q_list.list, list) { - if (((uint64_t)q->properties.read_ptr == sdma_q->rptr) && + if (((uint64_t __user *)q->properties.read_ptr == sdma_q->rptr) && (sdma_q->queue_id == q->properties.queue_id)) { list_del(&sdma_q->list); kfree(sdma_q); @@ -270,6 +270,7 @@ static ssize_t kfd_procfs_show(struct kobject *kobj, struct attribute *attr, kfd_sdma_activity_worker); sdma_activity_work_handler.pdd = pdd; + sdma_activity_work_handler.sdma_activity_counter = 0; schedule_work(&sdma_activity_work_handler.sdma_activity_work); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c index 7b348bf9df21..17d1736367ea 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c @@ -24,6 +24,7 @@ #include <linux/wait.h> #include <linux/anon_inodes.h> #include <uapi/linux/kfd_ioctl.h> +#include "amdgpu.h" #include "amdgpu_vm.h" #include "kfd_priv.h" #include "kfd_smi_events.h" @@ -148,15 +149,94 @@ static int kfd_smi_ev_release(struct inode *inode, struct file *filep) return 0; } +static void add_event_to_kfifo(struct kfd_dev *dev, unsigned int smi_event, + char *event_msg, int len) +{ + struct kfd_smi_client *client; + + rcu_read_lock(); + + list_for_each_entry_rcu(client, &dev->smi_clients, list) { + if (!(READ_ONCE(client->events) & + KFD_SMI_EVENT_MASK_FROM_INDEX(smi_event))) + continue; + spin_lock(&client->lock); + if (kfifo_avail(&client->fifo) >= len) { + kfifo_in(&client->fifo, event_msg, len); + wake_up_all(&client->wait_queue); + } else { + pr_debug("smi_event(EventID: %u): no space left\n", + smi_event); + } + spin_unlock(&client->lock); + } + + rcu_read_unlock(); +} + +void kfd_smi_event_update_gpu_reset(struct kfd_dev *dev, bool post_reset) +{ + /* + * GpuReset msg = Reset seq number (incremented for + * every reset message sent before GPU reset). + * 1 byte event + 1 byte space + 8 bytes seq num + + * 1 byte \n + 1 byte \0 = 12 + */ + char fifo_in[12]; + int len; + unsigned int event; + + if (list_empty(&dev->smi_clients)) + return; + + memset(fifo_in, 0x0, sizeof(fifo_in)); + + if (post_reset) { + event = KFD_SMI_EVENT_GPU_POST_RESET; + } else { + event = KFD_SMI_EVENT_GPU_PRE_RESET; + ++(dev->reset_seq_num); + } + + len = snprintf(fifo_in, sizeof(fifo_in), "%x %x\n", event, + dev->reset_seq_num); + + add_event_to_kfifo(dev, event, fifo_in, len); +} + +void kfd_smi_event_update_thermal_throttling(struct kfd_dev *dev, + uint32_t throttle_bitmask) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)dev->kgd; + /* + * ThermalThrottle msg = throttle_bitmask(8): + * thermal_interrupt_count(16): + * 1 byte event + 1 byte space + 8 byte throttle_bitmask + + * 1 byte : + 16 byte thermal_interupt_counter + 1 byte \n + + * 1 byte \0 = 29 + */ + char fifo_in[29]; + int len; + + if (list_empty(&dev->smi_clients)) + return; + + len = snprintf(fifo_in, sizeof(fifo_in), "%x %x:%llx\n", + KFD_SMI_EVENT_THERMAL_THROTTLE, throttle_bitmask, + atomic64_read(&adev->smu.throttle_int_counter)); + + add_event_to_kfifo(dev, KFD_SMI_EVENT_THERMAL_THROTTLE, fifo_in, len); +} + void kfd_smi_event_update_vmfault(struct kfd_dev *dev, uint16_t pasid) { struct amdgpu_device *adev = (struct amdgpu_device *)dev->kgd; struct amdgpu_task_info task_info; /* VmFault msg = (hex)uint32_pid(8) + :(1) + task name(16) = 25 */ - /* 16 bytes event + 1 byte space + 25 bytes msg + 1 byte \n = 43 + /* 1 byte event + 1 byte space + 25 bytes msg + 1 byte \n + + * 1 byte \0 = 29 */ - char fifo_in[43]; - struct kfd_smi_client *client; + char fifo_in[29]; int len; if (list_empty(&dev->smi_clients)) @@ -168,25 +248,10 @@ void kfd_smi_event_update_vmfault(struct kfd_dev *dev, uint16_t pasid) if (!task_info.pid) return; - len = snprintf(fifo_in, 43, "%x %x:%s\n", KFD_SMI_EVENT_VMFAULT, + len = snprintf(fifo_in, sizeof(fifo_in), "%x %x:%s\n", KFD_SMI_EVENT_VMFAULT, task_info.pid, task_info.task_name); - rcu_read_lock(); - - list_for_each_entry_rcu(client, &dev->smi_clients, list) { - if (!(READ_ONCE(client->events) & KFD_SMI_EVENT_VMFAULT)) - continue; - spin_lock(&client->lock); - if (kfifo_avail(&client->fifo) >= len) { - kfifo_in(&client->fifo, fifo_in, len); - wake_up_all(&client->wait_queue); - } - else - pr_debug("smi_event(vmfault): no space left\n"); - spin_unlock(&client->lock); - } - - rcu_read_unlock(); + add_event_to_kfifo(dev, KFD_SMI_EVENT_VMFAULT, fifo_in, len); } int kfd_smi_event_open(struct kfd_dev *dev, uint32_t *fd) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h index a9cb218fef96..b9b0438202e2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h @@ -25,5 +25,8 @@ int kfd_smi_event_open(struct kfd_dev *dev, uint32_t *fd); void kfd_smi_event_update_vmfault(struct kfd_dev *dev, uint16_t pasid); +void kfd_smi_event_update_thermal_throttling(struct kfd_dev *dev, + uint32_t throttle_bitmask); +void kfd_smi_event_update_gpu_reset(struct kfd_dev *dev, bool post_reset); #endif diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index f185f6cbc05c..2b31c3066aaa 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -446,7 +446,7 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, sysfs_show_32bit_prop(buffer, offs, "cpu_cores_count", dev->node_props.cpu_cores_count); sysfs_show_32bit_prop(buffer, offs, "simd_count", - dev->node_props.simd_count); + dev->gpu ? dev->node_props.simd_count : 0); sysfs_show_32bit_prop(buffer, offs, "mem_banks_count", dev->node_props.mem_banks_count); sysfs_show_32bit_prop(buffer, offs, "caches_count", @@ -1139,7 +1139,7 @@ static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu) /* Discrete GPUs need their own topology device list * entries. Don't assign them to CPU/APU nodes. */ - if (!gpu->device_info->needs_iommu_device && + if (!gpu->use_iommu_v2 && dev->node_props.cpu_cores_count) continue; @@ -1239,7 +1239,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu) void *crat_image = NULL; size_t image_size = 0; int proximity_domain; - struct amdgpu_ras *ctx; + struct amdgpu_device *adev; INIT_LIST_HEAD(&temp_topology_device_list); @@ -1388,7 +1388,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu) * Overwrite ATS capability according to needs_iommu_device to fix * potential missing corresponding bit in CRAT of BIOS. */ - if (dev->gpu->device_info->needs_iommu_device) + if (dev->gpu->use_iommu_v2) dev->node_props.capability |= HSA_CAP_ATS_PRESENT; else dev->node_props.capability &= ~HSA_CAP_ATS_PRESENT; @@ -1404,19 +1404,17 @@ int kfd_topology_add_device(struct kfd_dev *gpu) dev->node_props.max_waves_per_simd = 10; } - ctx = amdgpu_ras_get_context((struct amdgpu_device *)(dev->gpu->kgd)); - if (ctx) { - /* kfd only concerns sram ecc on GFX/SDMA and HBM ecc on UMC */ - dev->node_props.capability |= - (((ctx->features & BIT(AMDGPU_RAS_BLOCK__SDMA)) != 0) || - ((ctx->features & BIT(AMDGPU_RAS_BLOCK__GFX)) != 0)) ? - HSA_CAP_SRAM_EDCSUPPORTED : 0; - dev->node_props.capability |= ((ctx->features & BIT(AMDGPU_RAS_BLOCK__UMC)) != 0) ? - HSA_CAP_MEM_EDCSUPPORTED : 0; - - dev->node_props.capability |= (ctx->features != 0) ? + adev = (struct amdgpu_device *)(dev->gpu->kgd); + /* kfd only concerns sram ecc on GFX and HBM ecc on UMC */ + dev->node_props.capability |= + ((adev->ras_features & BIT(AMDGPU_RAS_BLOCK__GFX)) != 0) ? + HSA_CAP_SRAM_EDCSUPPORTED : 0; + dev->node_props.capability |= ((adev->ras_features & BIT(AMDGPU_RAS_BLOCK__UMC)) != 0) ? + HSA_CAP_MEM_EDCSUPPORTED : 0; + + if (adev->asic_type != CHIP_VEGA10) + dev->node_props.capability |= (adev->ras_features != 0) ? HSA_CAP_RASEVENTNOTIFY : 0; - } kfd_debug_print_topology(); @@ -1515,6 +1513,29 @@ int kfd_numa_node_to_apic_id(int numa_node_id) return kfd_cpumask_to_apic_id(cpumask_of_node(numa_node_id)); } +void kfd_double_confirm_iommu_support(struct kfd_dev *gpu) +{ + struct kfd_topology_device *dev; + + gpu->use_iommu_v2 = false; + + if (!gpu->device_info->needs_iommu_device) + return; + + down_read(&topology_lock); + + /* Only use IOMMUv2 if there is an APU topology node with no GPU + * assigned yet. This GPU will be assigned to it. + */ + list_for_each_entry(dev, &topology_device_list, list) + if (dev->node_props.cpu_cores_count && + dev->node_props.simd_count && + !dev->gpu) + gpu->use_iommu_v2 = true; + + up_read(&topology_lock); +} + #if defined(CONFIG_DEBUG_FS) int kfd_debugfs_hqds_by_device(struct seq_file *m, void *data) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 34ae4f3a32f4..f24abf428534 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -6,7 +6,7 @@ config DRM_AMD_DC bool "AMD DC - Enable new display engine" default y select SND_HDA_COMPONENT if SND_HDA_CORE - select DRM_AMD_DC_DCN if (X86 || PPC64) && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) + select DRM_AMD_DC_DCN if (X86 || PPC64 || (ARM64 && KERNEL_MODE_NEON)) && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and @@ -31,6 +31,14 @@ config DRM_AMD_DC_HDCP help Choose this option if you want to support HDCP authentication. +config DRM_AMD_DC_SI + bool "AMD DC support for Southern Islands ASICs" + default n + help + Choose this option to enable new AMD DC support for SI asics + by default. This includes Tahiti, Pitcairn, Cape Verde, Oland. + Hainan is not supported by AMD DC and it has no physical DCE6. + config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC 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 b51c527a3f0d..ec29376667df 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -127,6 +127,42 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU); static int amdgpu_dm_init(struct amdgpu_device *adev); static void amdgpu_dm_fini(struct amdgpu_device *adev); +static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link) +{ + switch (link->dpcd_caps.dongle_type) { + case DISPLAY_DONGLE_NONE: + return DRM_MODE_SUBCONNECTOR_Native; + case DISPLAY_DONGLE_DP_VGA_CONVERTER: + return DRM_MODE_SUBCONNECTOR_VGA; + case DISPLAY_DONGLE_DP_DVI_CONVERTER: + case DISPLAY_DONGLE_DP_DVI_DONGLE: + return DRM_MODE_SUBCONNECTOR_DVID; + case DISPLAY_DONGLE_DP_HDMI_CONVERTER: + case DISPLAY_DONGLE_DP_HDMI_DONGLE: + return DRM_MODE_SUBCONNECTOR_HDMIA; + case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE: + default: + return DRM_MODE_SUBCONNECTOR_Unknown; + } +} + +static void update_subconnector_property(struct amdgpu_dm_connector *aconnector) +{ + struct dc_link *link = aconnector->dc_link; + struct drm_connector *connector = &aconnector->base; + enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown; + + if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) + return; + + if (aconnector->dc_sink) + subconnector = get_subconnector_type(link); + + drm_object_property_set_value(&connector->base, + connector->dev->mode_config.dp_subconnector_property, + subconnector); +} + /* * initializes drm_device display related structures, based on the information * provided by DAL. The drm strcutures are: drm_crtc, drm_connector, @@ -171,7 +207,7 @@ static void amdgpu_dm_set_psr_caps(struct dc_link *link); static bool amdgpu_dm_psr_enable(struct dc_stream_state *stream); static bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream); static bool amdgpu_dm_psr_disable(struct dc_stream_state *stream); - +static bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm); /* * dm_vblank_get_counter @@ -268,7 +304,7 @@ static struct amdgpu_crtc * get_crtc_by_otg_inst(struct amdgpu_device *adev, int otg_inst) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_crtc *crtc; struct amdgpu_crtc *amdgpu_crtc; @@ -320,7 +356,7 @@ static void dm_pflip_high_irq(void *interrupt_params) return; } - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){ DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d !=AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p] \n", @@ -328,7 +364,7 @@ static void dm_pflip_high_irq(void *interrupt_params) AMDGPU_FLIP_SUBMITTED, amdgpu_crtc->crtc_id, amdgpu_crtc); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); return; } @@ -380,7 +416,7 @@ static void dm_pflip_high_irq(void *interrupt_params) e->sequence = drm_crtc_vblank_count(&amdgpu_crtc->base); e->pipe = amdgpu_crtc->crtc_id; - list_add_tail(&e->base.link, &adev->ddev->vblank_event_list); + list_add_tail(&e->base.link, &adev_to_drm(adev)->vblank_event_list); e = NULL; } @@ -393,7 +429,7 @@ static void dm_pflip_high_irq(void *interrupt_params) amdgpu_get_vblank_counter_kms(&amdgpu_crtc->base); amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE; - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); DRM_DEBUG_DRIVER("crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n", amdgpu_crtc->crtc_id, amdgpu_crtc, @@ -429,7 +465,7 @@ static void dm_vupdate_high_irq(void *interrupt_params) /* BTR processing for pre-DCE12 ASICs */ if (acrtc_state->stream && adev->family < AMDGPU_FAMILY_AI) { - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); mod_freesync_handle_v_update( adev->dm.freesync_module, acrtc_state->stream, @@ -439,7 +475,7 @@ static void dm_vupdate_high_irq(void *interrupt_params) adev->dm.dc, acrtc_state->stream, &acrtc_state->vrr_params.adjust); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); } } } @@ -489,7 +525,7 @@ static void dm_crtc_high_irq(void *interrupt_params) if (adev->family < AMDGPU_FAMILY_AI) return; - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); if (acrtc_state->stream && acrtc_state->vrr_params.supported && acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) { @@ -522,7 +558,7 @@ static void dm_crtc_high_irq(void *interrupt_params) acrtc->pflip_status = AMDGPU_FLIP_NONE; } - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); } static int dm_set_clockgating_state(void *handle, @@ -544,7 +580,7 @@ static int dm_early_init(void* handle); static void amdgpu_dm_fbc_init(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct dm_comressor_info *compressor = &adev->dm.compressor; struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector); struct drm_display_mode *mode; @@ -586,7 +622,7 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, unsigned char *buf, int max_bytes) { struct drm_device *dev = dev_get_drvdata(kdev); - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct amdgpu_dm_connector *aconnector; @@ -625,7 +661,7 @@ static int amdgpu_dm_audio_component_bind(struct device *kdev, struct device *hda_kdev, void *data) { struct drm_device *dev = dev_get_drvdata(kdev); - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_audio_component *acomp = data; acomp->ops = &amdgpu_dm_audio_component_ops; @@ -639,7 +675,7 @@ static void amdgpu_dm_audio_component_unbind(struct device *kdev, struct device *hda_kdev, void *data) { struct drm_device *dev = dev_get_drvdata(kdev); - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_audio_component *acomp = data; acomp->ops = NULL; @@ -850,7 +886,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) #endif int r; - adev->dm.ddev = adev->ddev; + adev->dm.ddev = adev_to_drm(adev); adev->dm.adev = adev; /* Zero all the fields */ @@ -986,10 +1022,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) /* TODO: Add_display_info? */ /* TODO use dynamic cursor width */ - adev->ddev->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size; - adev->ddev->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size; + adev_to_drm(adev)->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size; + adev_to_drm(adev)->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size; - if (drm_vblank_init(adev->ddev, adev->dm.display_indexes_num)) { + if (drm_vblank_init(adev_to_drm(adev), adev->dm.display_indexes_num)) { DRM_ERROR( "amdgpu: failed to initialize sw for display support.\n"); goto error; @@ -1066,6 +1102,12 @@ static int load_dmcu_fw(struct amdgpu_device *adev) const struct dmcu_firmware_header_v1_0 *hdr; switch(adev->asic_type) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case CHIP_TAHITI: + case CHIP_PITCAIRN: + case CHIP_VERDE: + case CHIP_OLAND: +#endif case CHIP_BONAIRE: case CHIP_HAWAII: case CHIP_KAVERI: @@ -1384,7 +1426,7 @@ static int dm_late_init(void *handle) bool ret = true; if (!adev->dm.fw_dmcu && !adev->dm.dmub_fw) - return detect_mst_link_for_all_connectors(adev->ddev); + return detect_mst_link_for_all_connectors(adev_to_drm(adev)); dmcu = adev->dm.dc->res_pool->dmcu; @@ -1409,12 +1451,12 @@ static int dm_late_init(void *handle) if (dmcu) ret = dmcu_load_iram(dmcu, params); else if (adev->dm.dc->ctx->dmub_srv) - ret = dmub_init_abm_config(adev->dm.dc->res_pool->abm, params); + ret = dmub_init_abm_config(adev->dm.dc->res_pool, params); if (!ret) return -EINVAL; - return detect_mst_link_for_all_connectors(adev->ddev); + return detect_mst_link_for_all_connectors(adev_to_drm(adev)); } static void s3_handle_mst(struct drm_device *dev, bool suspend) @@ -1652,7 +1694,7 @@ static int dm_suspend(void *handle) struct amdgpu_display_manager *dm = &adev->dm; int ret = 0; - if (adev->in_gpu_reset) { + if (amdgpu_in_reset(adev)) { mutex_lock(&dm->dc_lock); dm->cached_dc_state = dc_copy_state(dm->dc->current_state); @@ -1666,9 +1708,9 @@ static int dm_suspend(void *handle) } WARN_ON(adev->dm.cached_state); - adev->dm.cached_state = drm_atomic_helper_suspend(adev->ddev); + adev->dm.cached_state = drm_atomic_helper_suspend(adev_to_drm(adev)); - s3_handle_mst(adev->ddev, true); + s3_handle_mst(adev_to_drm(adev), true); amdgpu_dm_irq_suspend(adev); @@ -1822,7 +1864,7 @@ cleanup: static int dm_resume(void *handle) { struct amdgpu_device *adev = handle; - struct drm_device *ddev = adev->ddev; + struct drm_device *ddev = adev_to_drm(adev); struct amdgpu_display_manager *dm = &adev->dm; struct amdgpu_dm_connector *aconnector; struct drm_connector *connector; @@ -1838,7 +1880,7 @@ static int dm_resume(void *handle) struct dc_state *dc_state; int i, r, j; - if (adev->in_gpu_reset) { + if (amdgpu_in_reset(adev)) { dc_state = dm->cached_dc_state; r = dm_dmub_hw_init(adev); @@ -2044,7 +2086,7 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) return; conn_base = &aconnector->base; - adev = conn_base->dev->dev_private; + adev = drm_to_adev(conn_base->dev); dm = &adev->dm; caps = &dm->backlight_caps; caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; @@ -2095,7 +2137,6 @@ void amdgpu_dm_update_connector_after_detect( if (aconnector->mst_mgr.mst_state == true) return; - sink = aconnector->dc_link->local_sink; if (sink) dc_sink_retain(sink); @@ -2222,6 +2263,8 @@ void amdgpu_dm_update_connector_after_detect( mutex_unlock(&dev->mode_config.mutex); + update_subconnector_property(aconnector); + if (sink) dc_sink_release(sink); } @@ -2233,7 +2276,7 @@ static void handle_hpd_irq(void *param) struct drm_device *dev = connector->dev; enum dc_connection_type new_connection_type = dc_connection_none; #ifdef CONFIG_DRM_AMD_DC_HDCP - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); #endif /* @@ -2366,7 +2409,7 @@ static void handle_hpd_rx_irq(void *param) enum dc_connection_type new_connection_type = dc_connection_none; #ifdef CONFIG_DRM_AMD_DC_HDCP union hpd_irq_data hpd_irq_data; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); #endif @@ -2437,7 +2480,7 @@ static void handle_hpd_rx_irq(void *param) static void register_hpd_handlers(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct amdgpu_dm_connector *aconnector; const struct dc_link *dc_link; @@ -2474,6 +2517,89 @@ static void register_hpd_handlers(struct amdgpu_device *adev) } } +#if defined(CONFIG_DRM_AMD_DC_SI) +/* Register IRQ sources and initialize IRQ callbacks */ +static int dce60_register_irq_handlers(struct amdgpu_device *adev) +{ + struct dc *dc = adev->dm.dc; + struct common_irq_params *c_irq_params; + struct dc_interrupt_params int_params = {0}; + int r; + int i; + unsigned client_id = AMDGPU_IRQ_CLIENTID_LEGACY; + + int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; + int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; + + /* + * Actions of amdgpu_irq_add_id(): + * 1. Register a set() function with base driver. + * Base driver will call set() function to enable/disable an + * interrupt in DC hardware. + * 2. Register amdgpu_dm_irq_handler(). + * Base driver will call amdgpu_dm_irq_handler() for ALL interrupts + * coming from DC hardware. + * amdgpu_dm_irq_handler() will re-direct the interrupt to DC + * for acknowledging and handling. */ + + /* Use VBLANK interrupt */ + for (i = 0; i < adev->mode_info.num_crtc; i++) { + r = amdgpu_irq_add_id(adev, client_id, i+1 , &adev->crtc_irq); + if (r) { + DRM_ERROR("Failed to add crtc irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, i+1 , 0); + + c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_crtc_high_irq, c_irq_params); + } + + /* Use GRPH_PFLIP interrupt */ + for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP; + i <= VISLANDS30_IV_SRCID_D6_GRPH_PFLIP; i += 2) { + r = amdgpu_irq_add_id(adev, client_id, i, &adev->pageflip_irq); + if (r) { + DRM_ERROR("Failed to add page flip irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, i, 0); + + c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_pflip_high_irq, c_irq_params); + + } + + /* HPD */ + r = amdgpu_irq_add_id(adev, client_id, + VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq); + if (r) { + DRM_ERROR("Failed to add hpd irq id!\n"); + return r; + } + + register_hpd_handlers(adev); + + return 0; +} +#endif + /* Register IRQ sources and initialize IRQ callbacks */ static int dce110_register_irq_handlers(struct amdgpu_device *adev) { @@ -2704,7 +2830,7 @@ static int dm_atomic_get_state(struct drm_atomic_state *state, struct dm_atomic_state **dm_state) { struct drm_device *dev = state->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_display_manager *dm = &adev->dm; struct drm_private_state *priv_state; @@ -2724,7 +2850,7 @@ static struct dm_atomic_state * dm_atomic_get_new_state(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_display_manager *dm = &adev->dm; struct drm_private_obj *obj; struct drm_private_state *new_obj_state; @@ -2738,24 +2864,6 @@ dm_atomic_get_new_state(struct drm_atomic_state *state) return NULL; } -static struct dm_atomic_state * -dm_atomic_get_old_state(struct drm_atomic_state *state) -{ - struct drm_device *dev = state->dev; - struct amdgpu_device *adev = dev->dev_private; - struct amdgpu_display_manager *dm = &adev->dm; - struct drm_private_obj *obj; - struct drm_private_state *old_obj_state; - int i; - - for_each_old_private_obj_in_state(state, obj, old_obj_state, i) { - if (obj->funcs == dm->atomic_obj.funcs) - return to_dm_atomic_state(old_obj_state); - } - - return NULL; -} - static struct drm_private_state * dm_atomic_duplicate_state(struct drm_private_obj *obj) { @@ -2803,18 +2911,18 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) adev->mode_info.mode_config_initialized = true; - adev->ddev->mode_config.funcs = (void *)&amdgpu_dm_mode_funcs; - adev->ddev->mode_config.helper_private = &amdgpu_dm_mode_config_helperfuncs; + adev_to_drm(adev)->mode_config.funcs = (void *)&amdgpu_dm_mode_funcs; + adev_to_drm(adev)->mode_config.helper_private = &amdgpu_dm_mode_config_helperfuncs; - adev->ddev->mode_config.max_width = 16384; - adev->ddev->mode_config.max_height = 16384; + adev_to_drm(adev)->mode_config.max_width = 16384; + adev_to_drm(adev)->mode_config.max_height = 16384; - adev->ddev->mode_config.preferred_depth = 24; - adev->ddev->mode_config.prefer_shadow = 1; + adev_to_drm(adev)->mode_config.preferred_depth = 24; + adev_to_drm(adev)->mode_config.prefer_shadow = 1; /* indicates support for immediate flip */ - adev->ddev->mode_config.async_page_flip = true; + adev_to_drm(adev)->mode_config.async_page_flip = true; - adev->ddev->mode_config.fb_base = adev->gmc.aper_base; + adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) @@ -2828,7 +2936,7 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) dc_resource_state_copy_construct_current(adev->dm.dc, state->context); - drm_atomic_private_obj_init(adev->ddev, + drm_atomic_private_obj_init(adev_to_drm(adev), &adev->dm.atomic_obj, &state->base, &dm_atomic_state_funcs); @@ -3000,13 +3108,13 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) props.type = BACKLIGHT_RAW; snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d", - dm->adev->ddev->primary->index); + adev_to_drm(dm->adev)->primary->index); dm->backlight_dev = backlight_device_register(bl_name, - dm->adev->ddev->dev, - dm, - &amdgpu_dm_backlight_ops, - &props); + adev_to_drm(dm->adev)->dev, + dm, + &amdgpu_dm_backlight_ops, + &props); if (IS_ERR(dm->backlight_dev)) DRM_ERROR("DM: Backlight registration failed!\n"); @@ -3212,6 +3320,17 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) /* Software is initialized. Now we can register interrupt handlers. */ switch (adev->asic_type) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case CHIP_TAHITI: + case CHIP_PITCAIRN: + case CHIP_VERDE: + case CHIP_OLAND: + if (dce60_register_irq_handlers(dm->adev)) { + DRM_ERROR("DM: Failed to initialize IRQ\n"); + goto fail; + } + break; +#endif case CHIP_BONAIRE: case CHIP_HAWAII: case CHIP_KAVERI: @@ -3312,14 +3431,14 @@ static ssize_t s3_debug_store(struct device *device, int ret; int s3_state; struct drm_device *drm_dev = dev_get_drvdata(device); - struct amdgpu_device *adev = drm_dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(drm_dev); ret = kstrtoint(buf, 0, &s3_state); if (ret == 0) { if (s3_state) { dm_resume(adev); - drm_kms_helper_hotplug_event(adev->ddev); + drm_kms_helper_hotplug_event(adev_to_drm(adev)); } else dm_suspend(adev); } @@ -3336,6 +3455,20 @@ static int dm_early_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; switch (adev->asic_type) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case CHIP_TAHITI: + case CHIP_PITCAIRN: + case CHIP_VERDE: + adev->mode_info.num_crtc = 6; + adev->mode_info.num_hpd = 6; + adev->mode_info.num_dig = 6; + break; + case CHIP_OLAND: + adev->mode_info.num_crtc = 2; + adev->mode_info.num_hpd = 2; + adev->mode_info.num_dig = 2; + break; +#endif case CHIP_BONAIRE: case CHIP_HAWAII: adev->mode_info.num_crtc = 6; @@ -3432,7 +3565,7 @@ static int dm_early_init(void *handle) */ #if defined(CONFIG_DEBUG_KERNEL_DC) device_create_file( - adev->ddev->dev, + adev_to_drm(adev)->dev, &dev_attr_s3_debug); #endif @@ -3443,21 +3576,12 @@ static bool modeset_required(struct drm_crtc_state *crtc_state, struct dc_stream_state *new_stream, struct dc_stream_state *old_stream) { - if (!drm_atomic_crtc_needs_modeset(crtc_state)) - return false; - - if (!crtc_state->enable) - return false; - - return crtc_state->active; + return crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state); } static bool modereset_required(struct drm_crtc_state *crtc_state) { - if (!drm_atomic_crtc_needs_modeset(crtc_state)) - return false; - - return !crtc_state->enable || !crtc_state->active; + return !crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state); } static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder) @@ -3530,8 +3654,17 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state, static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb, uint64_t *tiling_flags, bool *tmz_surface) { - struct amdgpu_bo *rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]); - int r = amdgpu_bo_reserve(rbo, false); + struct amdgpu_bo *rbo; + int r; + + if (!amdgpu_fb) { + *tiling_flags = 0; + *tmz_surface = false; + return 0; + } + + rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]); + r = amdgpu_bo_reserve(rbo, false); if (unlikely(r)) { /* Don't show error message when returning -ERESTARTSYS */ @@ -3954,13 +4087,10 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, struct drm_crtc_state *crtc_state) { struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); - const struct amdgpu_framebuffer *amdgpu_fb = - to_amdgpu_framebuffer(plane_state->fb); + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); struct dc_scaling_info scaling_info; struct dc_plane_info plane_info; - uint64_t tiling_flags; int ret; - bool tmz_surface = false; bool force_disable_dcc = false; ret = fill_dc_scaling_info(plane_state, &scaling_info); @@ -3972,15 +4102,12 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, dc_plane_state->clip_rect = scaling_info.clip_rect; dc_plane_state->scaling_quality = scaling_info.scaling_quality; - ret = get_fb_info(amdgpu_fb, &tiling_flags, &tmz_surface); - if (ret) - return ret; - force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend; - ret = fill_dc_plane_info_and_addr(adev, plane_state, tiling_flags, + ret = fill_dc_plane_info_and_addr(adev, plane_state, + dm_plane_state->tiling_flags, &plane_info, &dc_plane_state->address, - tmz_surface, + dm_plane_state->tmz_surface, force_disable_dcc); if (ret) return ret; @@ -4562,7 +4689,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, dc_link_get_link_cap(aconnector->dc_link)); #if defined(CONFIG_DRM_AMD_DC_DCN) - if (dsc_caps.is_dsc_supported) + if (dsc_caps.is_dsc_supported) { + /* Set DSC policy according to dsc_clock_en */ + dc_dsc_policy_set_enable_dsc_when_not_needed(aconnector->dsc_settings.dsc_clock_en); + if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], &dsc_caps, aconnector->dc_link->ctx->dc->debug.dsc_min_slice_height_override, @@ -4570,6 +4700,21 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, &stream->timing, &stream->timing.dsc_cfg)) stream->timing.flags.DSC = 1; + /* Overwrite the stream flag if DSC is enabled through debugfs */ + if (aconnector->dsc_settings.dsc_clock_en) + stream->timing.flags.DSC = 1; + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_slice_width) + stream->timing.dsc_cfg.num_slices_h = DIV_ROUND_UP(stream->timing.h_addressable, + aconnector->dsc_settings.dsc_slice_width); + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_slice_height) + stream->timing.dsc_cfg.num_slices_v = DIV_ROUND_UP(stream->timing.v_addressable, + aconnector->dsc_settings.dsc_slice_height); + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel) + stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel; + } #endif } @@ -4583,7 +4728,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, update_stream_signal(stream, sink); if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) - mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false); + mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket); + if (stream->link->psr_settings.psr_feature_enabled) { // // should decide stream support vsc sdp colorimetry capability @@ -4681,7 +4827,7 @@ static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable) { enum dc_irq_source irq_source; struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); int rc; irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst; @@ -4697,7 +4843,7 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) { enum dc_irq_source irq_source; struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state); int rc = 0; @@ -4764,6 +4910,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force) else connected = (aconnector->base.force == DRM_FORCE_ON); + update_subconnector_property(aconnector); + return (connected ? connector_status_connected : connector_status_disconnected); } @@ -4774,7 +4922,7 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, uint64_t val) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct dm_connector_state *dm_old_state = to_dm_connector_state(connector->state); struct dm_connector_state *dm_new_state = @@ -4829,7 +4977,7 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, uint64_t *val) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct dm_connector_state *dm_state = to_dm_connector_state(state); int ret = -EINVAL; @@ -4879,9 +5027,10 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector) { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); const struct dc_link *link = aconnector->dc_link; - struct amdgpu_device *adev = connector->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(connector->dev); struct amdgpu_display_manager *dm = &adev->dm; + drm_atomic_private_obj_fini(&aconnector->mst_mgr.base); #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\ defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) @@ -5064,7 +5213,7 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, const struct dc_stream_state *old_stream) { struct drm_connector *connector = &aconnector->base; - struct amdgpu_device *adev = connector->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(connector->dev); struct dc_stream_state *stream; const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL; int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8; @@ -5341,7 +5490,7 @@ static void dm_update_crtc_active_planes(struct drm_crtc *crtc, static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dc *dc = adev->dm.dc; struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state); int ret = -EINVAL; @@ -5561,6 +5710,10 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) dc_plane_state_retain(dm_plane_state->dc_state); } + /* Framebuffer hasn't been updated yet, so retain old flags. */ + dm_plane_state->tiling_flags = old_dm_plane_state->tiling_flags; + dm_plane_state->tmz_surface = old_dm_plane_state->tmz_surface; + return &dm_plane_state->base; } @@ -5595,14 +5748,8 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, struct list_head list; struct ttm_validate_buffer tv; struct ww_acquire_ctx ticket; - uint64_t tiling_flags; uint32_t domain; int r; - bool tmz_surface = false; - bool force_disable_dcc = false; - - dm_plane_state_old = to_dm_plane_state(plane->state); - dm_plane_state_new = to_dm_plane_state(new_state); if (!new_state->fb) { DRM_DEBUG_DRIVER("No FB bound\n"); @@ -5646,27 +5793,35 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, return r; } - amdgpu_bo_get_tiling_flags(rbo, &tiling_flags); - - tmz_surface = amdgpu_bo_encrypted(rbo); - ttm_eu_backoff_reservation(&ticket, &list); afb->address = amdgpu_bo_gpu_offset(rbo); amdgpu_bo_ref(rbo); + /** + * We don't do surface updates on planes that have been newly created, + * but we also don't have the afb->address during atomic check. + * + * Fill in buffer attributes depending on the address here, but only on + * newly created planes since they're not being used by DC yet and this + * won't modify global state. + */ + dm_plane_state_old = to_dm_plane_state(plane->state); + dm_plane_state_new = to_dm_plane_state(new_state); + if (dm_plane_state_new->dc_state && - dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) { - struct dc_plane_state *plane_state = dm_plane_state_new->dc_state; + dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) { + struct dc_plane_state *plane_state = + dm_plane_state_new->dc_state; + bool force_disable_dcc = !plane_state->dcc.enable; - force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend; fill_plane_buffer_attributes( adev, afb, plane_state->format, plane_state->rotation, - tiling_flags, &plane_state->tiling_info, - &plane_state->plane_size, &plane_state->dcc, - &plane_state->address, tmz_surface, - force_disable_dcc); + dm_plane_state_new->tiling_flags, + &plane_state->tiling_info, &plane_state->plane_size, + &plane_state->dcc, &plane_state->address, + dm_plane_state_new->tmz_surface, force_disable_dcc); } return 0; @@ -5707,7 +5862,7 @@ static int dm_plane_helper_check_state(struct drm_plane_state *state, static int dm_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { - struct amdgpu_device *adev = plane->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(plane->dev); struct dc *dc = adev->dm.dc; struct dm_plane_state *dm_plane_state; struct dc_scaling_info scaling_info; @@ -5876,7 +6031,7 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, num_formats = get_plane_formats(plane, plane_cap, formats, ARRAY_SIZE(formats)); - res = drm_universal_plane_init(dm->adev->ddev, plane, possible_crtcs, + res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs, &dm_plane_funcs, formats, num_formats, NULL, plane->type, NULL); if (res) @@ -5910,8 +6065,9 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; - drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, - supported_rotations); + if (dm->adev->asic_type >= CHIP_BONAIRE) + drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, + supported_rotations); drm_plane_helper_add(plane, &dm_plane_helper_funcs); @@ -6181,7 +6337,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, struct dc_link *link, int link_index) { - struct amdgpu_device *adev = dm->ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dm->ddev); /* * Some of the properties below require access to state, like bpc. @@ -6432,7 +6588,7 @@ static int amdgpu_dm_encoder_init(struct drm_device *dev, struct amdgpu_encoder *aencoder, uint32_t link_index) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int res = drm_encoder_init(dev, &aencoder->base, @@ -6617,7 +6773,7 @@ static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc, static void handle_cursor_update(struct drm_plane *plane, struct drm_plane_state *old_plane_state) { - struct amdgpu_device *adev = plane->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(plane->dev); struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb); struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc; struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL; @@ -6719,7 +6875,7 @@ static void update_freesync_state_on_stream( if (!new_stream->timing.h_total || !new_stream->timing.v_total) return; - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); vrr_params = new_crtc_state->vrr_params; if (surface) { @@ -6772,7 +6928,7 @@ static void update_freesync_state_on_stream( (int)new_crtc_state->base.vrr_enabled, (int)vrr_params.state); - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); } static void pre_update_freesync_state_on_stream( @@ -6795,7 +6951,7 @@ static void pre_update_freesync_state_on_stream( if (!new_stream->timing.h_total || !new_stream->timing.v_total) return; - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); vrr_params = new_crtc_state->vrr_params; if (new_crtc_state->vrr_supported && @@ -6818,7 +6974,7 @@ static void pre_update_freesync_state_on_stream( sizeof(vrr_params.adjust)) != 0); new_crtc_state->vrr_params = vrr_params; - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); } static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state, @@ -6888,8 +7044,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, long r; unsigned long flags; struct amdgpu_bo *abo; - uint64_t tiling_flags; - bool tmz_surface = false; uint32_t target_vblank, last_flip_vblank; bool vrr_active = amdgpu_dm_vrr_active(acrtc_state); bool pflip_present = false; @@ -6973,28 +7127,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, if (unlikely(r <= 0)) DRM_ERROR("Waiting for fences timed out!"); - /* - * TODO This might fail and hence better not used, wait - * explicitly on fences instead - * and in general should be called for - * blocking commit to as per framework helpers - */ - r = amdgpu_bo_reserve(abo, true); - if (unlikely(r != 0)) - DRM_ERROR("failed to reserve buffer before flip\n"); - - amdgpu_bo_get_tiling_flags(abo, &tiling_flags); - - tmz_surface = amdgpu_bo_encrypted(abo); - - amdgpu_bo_unreserve(abo); - fill_dc_plane_info_and_addr( - dm->adev, new_plane_state, tiling_flags, + dm->adev, new_plane_state, + dm_new_plane_state->tiling_flags, &bundle->plane_infos[planes_count], &bundle->flip_addrs[planes_count].address, - tmz_surface, - false); + dm_new_plane_state->tmz_surface, false); DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n", new_plane_state->plane->index, @@ -7172,9 +7310,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, * on some ASICs). */ if (dm_old_crtc_state->active_planes != acrtc_state->active_planes) - dm_update_pflip_irq_state( - (struct amdgpu_device *)dev->dev_private, - acrtc_attach); + 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 && @@ -7204,7 +7341,7 @@ cleanup: static void amdgpu_dm_commit_audio(struct drm_device *dev, struct drm_atomic_state *state) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_dm_connector *aconnector; struct drm_connector *connector; struct drm_connector_state *old_con_state, *new_con_state; @@ -7296,7 +7433,7 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev, { struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); int i; /* @@ -7343,7 +7480,7 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev, static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_display_manager *dm = &adev->dm; struct dm_atomic_state *dm_state; struct dc_state *dc_state = NULL, *dc_state_temp = NULL; @@ -7356,6 +7493,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct drm_connector_state *old_con_state, *new_con_state; struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; int crtc_disable_count = 0; + bool mode_set_reset_required = false; drm_atomic_helper_update_legacy_modeset_state(dev, state); @@ -7432,19 +7570,21 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) acrtc->enabled = true; acrtc->hw_mode = new_crtc_state->mode; crtc->hwmode = new_crtc_state->mode; + mode_set_reset_required = true; } else if (modereset_required(new_crtc_state)) { DRM_DEBUG_DRIVER("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc); /* i.e. reset mode */ - if (dm_old_crtc_state->stream) { - if (dm_old_crtc_state->stream->link->psr_settings.psr_allow_active) - amdgpu_dm_psr_disable(dm_old_crtc_state->stream); - + if (dm_old_crtc_state->stream) remove_stream(adev, acrtc, dm_old_crtc_state->stream); - } + mode_set_reset_required = true; } } /* for_each_crtc_in_state() */ if (dc_state) { + /* if there mode set or reset, disable eDP PSR */ + if (mode_set_reset_required) + amdgpu_dm_psr_disable_all(dm); + dm_enable_per_frame_crtc_master_sync(dc_state); mutex_lock(&dm->dc_lock); WARN_ON(!dc_commit_state(dm->dc, dc_state)); @@ -7646,7 +7786,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) * send vblank event on all events not handled in flip and * mark consumed event for drm_atomic_helper_commit_hw_done */ - spin_lock_irqsave(&adev->ddev->event_lock, flags); + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { if (new_crtc_state->event) @@ -7654,7 +7794,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) new_crtc_state->event = NULL; } - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); /* Signal HW programming completion */ drm_atomic_helper_commit_hw_done(state); @@ -7926,6 +8066,13 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, goto fail; } + /* + * TODO: Check VSDB bits to decide whether this should + * be enabled or not. + */ + new_stream->triggered_crtc_reset.enabled = + dm->force_timing_sync; + dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level; ret = fill_hdr_info_packet(drm_new_conn_state, @@ -8045,8 +8192,7 @@ skip_modeset: * We want to do dc stream updates that do not require a * full modeset below. */ - if (!(enable && aconnector && new_crtc_state->enable && - new_crtc_state->active)) + if (!(enable && aconnector && new_crtc_state->active)) return 0; /* * Given above conditions, the dc state cannot be NULL because: @@ -8137,6 +8283,8 @@ static bool should_reset_plane(struct drm_atomic_state *state, * TODO: Come up with a more elegant solution for this. */ for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) { + struct dm_plane_state *old_dm_plane_state, *new_dm_plane_state; + if (other->type == DRM_PLANE_TYPE_CURSOR) continue; @@ -8147,9 +8295,45 @@ static bool should_reset_plane(struct drm_atomic_state *state, if (old_other_state->crtc != new_other_state->crtc) return true; - /* TODO: Remove this once we can handle fast format changes. */ - if (old_other_state->fb && new_other_state->fb && - old_other_state->fb->format != new_other_state->fb->format) + /* Src/dst size and scaling updates. */ + if (old_other_state->src_w != new_other_state->src_w || + old_other_state->src_h != new_other_state->src_h || + old_other_state->crtc_w != new_other_state->crtc_w || + old_other_state->crtc_h != new_other_state->crtc_h) + return true; + + /* Rotation / mirroring updates. */ + if (old_other_state->rotation != new_other_state->rotation) + return true; + + /* Blending updates. */ + if (old_other_state->pixel_blend_mode != + new_other_state->pixel_blend_mode) + return true; + + /* Alpha updates. */ + if (old_other_state->alpha != new_other_state->alpha) + return true; + + /* Colorspace changes. */ + if (old_other_state->color_range != new_other_state->color_range || + old_other_state->color_encoding != new_other_state->color_encoding) + return true; + + /* Framebuffer checks fall at the end. */ + if (!old_other_state->fb || !new_other_state->fb) + continue; + + /* Pixel format changes can require bandwidth updates. */ + if (old_other_state->fb->format != new_other_state->fb->format) + return true; + + old_dm_plane_state = to_dm_plane_state(old_other_state); + new_dm_plane_state = to_dm_plane_state(new_other_state); + + /* Tiling and DCC changes also require bandwidth updates. */ + if (old_dm_plane_state->tiling_flags != + new_dm_plane_state->tiling_flags) return true; } @@ -8229,8 +8413,7 @@ static int dm_update_plane_state(struct dc *dc, dm_old_plane_state->dc_state, dm_state->context)) { - ret = EINVAL; - return ret; + return -EINVAL; } @@ -8271,7 +8454,7 @@ static int dm_update_plane_state(struct dc *dc, plane->base.id, new_plane_crtc->base.id); ret = fill_dc_plane_attributes( - new_plane_crtc->dev->dev_private, + drm_to_adev(new_plane_crtc->dev), dc_new_plane_state, new_plane_state, new_crtc_state); @@ -8317,169 +8500,6 @@ static int dm_update_plane_state(struct dc *dc, return ret; } -static int -dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, - struct drm_atomic_state *state, - enum surface_update_type *out_type) -{ - struct dc *dc = dm->dc; - struct dm_atomic_state *dm_state = NULL, *old_dm_state = NULL; - int i, j, num_plane, ret = 0; - struct drm_plane_state *old_plane_state, *new_plane_state; - struct dm_plane_state *new_dm_plane_state, *old_dm_plane_state; - struct drm_crtc *new_plane_crtc; - struct drm_plane *plane; - - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state, *old_crtc_state; - struct dm_crtc_state *new_dm_crtc_state, *old_dm_crtc_state; - struct dc_stream_status *status = NULL; - enum surface_update_type update_type = UPDATE_TYPE_FAST; - struct surface_info_bundle { - struct dc_surface_update surface_updates[MAX_SURFACES]; - struct dc_plane_info plane_infos[MAX_SURFACES]; - struct dc_scaling_info scaling_infos[MAX_SURFACES]; - struct dc_flip_addrs flip_addrs[MAX_SURFACES]; - struct dc_stream_update stream_update; - } *bundle; - - bundle = kzalloc(sizeof(*bundle), GFP_KERNEL); - - if (!bundle) { - DRM_ERROR("Failed to allocate update bundle\n"); - /* Set type to FULL to avoid crashing in DC*/ - update_type = UPDATE_TYPE_FULL; - goto cleanup; - } - - for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - - memset(bundle, 0, sizeof(struct surface_info_bundle)); - - new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); - old_dm_crtc_state = to_dm_crtc_state(old_crtc_state); - num_plane = 0; - - if (new_dm_crtc_state->stream != old_dm_crtc_state->stream) { - update_type = UPDATE_TYPE_FULL; - goto cleanup; - } - - if (!new_dm_crtc_state->stream) - continue; - - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { - const struct amdgpu_framebuffer *amdgpu_fb = - to_amdgpu_framebuffer(new_plane_state->fb); - struct dc_plane_info *plane_info = &bundle->plane_infos[num_plane]; - struct dc_flip_addrs *flip_addr = &bundle->flip_addrs[num_plane]; - struct dc_scaling_info *scaling_info = &bundle->scaling_infos[num_plane]; - uint64_t tiling_flags; - bool tmz_surface = false; - - new_plane_crtc = new_plane_state->crtc; - new_dm_plane_state = to_dm_plane_state(new_plane_state); - old_dm_plane_state = to_dm_plane_state(old_plane_state); - - if (plane->type == DRM_PLANE_TYPE_CURSOR) - continue; - - if (new_dm_plane_state->dc_state != old_dm_plane_state->dc_state) { - update_type = UPDATE_TYPE_FULL; - goto cleanup; - } - - if (crtc != new_plane_crtc) - continue; - - bundle->surface_updates[num_plane].surface = - new_dm_plane_state->dc_state; - - if (new_crtc_state->mode_changed) { - bundle->stream_update.dst = new_dm_crtc_state->stream->dst; - bundle->stream_update.src = new_dm_crtc_state->stream->src; - } - - if (new_crtc_state->color_mgmt_changed) { - bundle->surface_updates[num_plane].gamma = - new_dm_plane_state->dc_state->gamma_correction; - bundle->surface_updates[num_plane].in_transfer_func = - new_dm_plane_state->dc_state->in_transfer_func; - bundle->surface_updates[num_plane].gamut_remap_matrix = - &new_dm_plane_state->dc_state->gamut_remap_matrix; - bundle->stream_update.gamut_remap = - &new_dm_crtc_state->stream->gamut_remap_matrix; - bundle->stream_update.output_csc_transform = - &new_dm_crtc_state->stream->csc_color_matrix; - bundle->stream_update.out_transfer_func = - new_dm_crtc_state->stream->out_transfer_func; - } - - ret = fill_dc_scaling_info(new_plane_state, - scaling_info); - if (ret) - goto cleanup; - - bundle->surface_updates[num_plane].scaling_info = scaling_info; - - if (amdgpu_fb) { - ret = get_fb_info(amdgpu_fb, &tiling_flags, &tmz_surface); - if (ret) - goto cleanup; - - ret = fill_dc_plane_info_and_addr( - dm->adev, new_plane_state, tiling_flags, - plane_info, - &flip_addr->address, tmz_surface, - false); - if (ret) - goto cleanup; - - bundle->surface_updates[num_plane].plane_info = plane_info; - bundle->surface_updates[num_plane].flip_addr = flip_addr; - } - - num_plane++; - } - - if (num_plane == 0) - continue; - - ret = dm_atomic_get_state(state, &dm_state); - if (ret) - goto cleanup; - - old_dm_state = dm_atomic_get_old_state(state); - if (!old_dm_state) { - ret = -EINVAL; - goto cleanup; - } - - status = dc_stream_get_status_from_state(old_dm_state->context, - new_dm_crtc_state->stream); - bundle->stream_update.stream = new_dm_crtc_state->stream; - /* - * TODO: DC modifies the surface during this call so we need - * to lock here - find a way to do this without locking. - */ - mutex_lock(&dm->dc_lock); - update_type = dc_check_update_surfaces_for_stream( - dc, bundle->surface_updates, num_plane, - &bundle->stream_update, status); - mutex_unlock(&dm->dc_lock); - - if (update_type > UPDATE_TYPE_MED) { - update_type = UPDATE_TYPE_FULL; - goto cleanup; - } - } - -cleanup: - kfree(bundle); - - *out_type = update_type; - return ret; -} #if defined(CONFIG_DRM_AMD_DC_DCN) static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc) { @@ -8520,8 +8540,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm * acquired. For full updates case which removes/adds/updates streams on one * CRTC while flipping on another CRTC, acquiring global lock will guarantee * that any such full update commit will wait for completion of any outstanding - * flip using DRMs synchronization events. See - * dm_determine_update_type_for_commit() + * flip using DRMs synchronization events. * * Note that DM adds the affected connectors for all CRTCs in state, when that * might not seem necessary. This is because DC stream creation requires the @@ -8533,7 +8552,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm static int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct dm_atomic_state *dm_state = NULL; struct dc *dc = adev->dm.dc; struct drm_connector *connector; @@ -8542,15 +8561,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct drm_plane *plane; struct drm_plane_state *old_plane_state, *new_plane_state; - enum surface_update_type update_type = UPDATE_TYPE_FAST; - enum surface_update_type overall_update_type = UPDATE_TYPE_FAST; enum dc_status status; int ret, i; - - /* - * This bool will be set for true for any modeset/reset - * or plane update which implies non fast surface update. - */ bool lock_and_validation_needed = false; ret = drm_atomic_helper_check_modeset(dev, state); @@ -8645,6 +8657,17 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, } } + /* Prepass for updating tiling flags on new planes. */ + for_each_new_plane_in_state(state, plane, new_plane_state, i) { + struct dm_plane_state *new_dm_plane_state = to_dm_plane_state(new_plane_state); + struct amdgpu_framebuffer *new_afb = to_amdgpu_framebuffer(new_plane_state->fb); + + ret = get_fb_info(new_afb, &new_dm_plane_state->tiling_flags, + &new_dm_plane_state->tmz_surface); + if (ret) + goto fail; + } + /* Remove exiting planes if they are modified */ for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { ret = dm_update_plane_state(dc, state, plane, @@ -8733,27 +8756,23 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state)) continue; - overall_update_type = UPDATE_TYPE_FULL; lock_and_validation_needed = true; } - ret = dm_determine_update_type_for_commit(&adev->dm, state, &update_type); - if (ret) - goto fail; - - if (overall_update_type < update_type) - overall_update_type = update_type; - - /* - * lock_and_validation_needed was an old way to determine if we need to set - * the global lock. Leaving it in to check if we broke any corner cases - * lock_and_validation_needed true = UPDATE_TYPE_FULL or UPDATE_TYPE_MED - * lock_and_validation_needed false = UPDATE_TYPE_FAST + /** + * Streams and planes are reset when there are changes that affect + * bandwidth. Anything that affects bandwidth needs to go through + * DC global validation to ensure that the configuration can be applied + * to hardware. + * + * We have to currently stall out here in atomic_check for outstanding + * commits to finish in this case because our IRQ handlers reference + * DRM state directly - we can end up disabling interrupts too early + * if we don't. + * + * TODO: Remove this stall and drop DM state private objects. */ - if (lock_and_validation_needed && overall_update_type <= UPDATE_TYPE_FAST) - WARN(1, "Global lock should be Set, overall_update_type should be UPDATE_TYPE_MED or UPDATE_TYPE_FULL"); - - if (overall_update_type > UPDATE_TYPE_FAST) { + if (lock_and_validation_needed) { ret = dm_atomic_get_state(state, &dm_state); if (ret) goto fail; @@ -8835,7 +8854,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); - dm_new_crtc_state->update_type = (int)overall_update_type; + dm_new_crtc_state->update_type = lock_and_validation_needed ? + UPDATE_TYPE_FULL : + UPDATE_TYPE_FAST; } /* Must be success */ @@ -8884,7 +8905,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, struct dm_connector_state *dm_con_state = NULL; struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); bool freesync_capable = false; if (!connector->state) { @@ -9083,3 +9104,34 @@ static bool amdgpu_dm_psr_disable(struct dc_stream_state *stream) return dc_link_set_psr_allow_active(stream->link, false, true); } + +/* + * amdgpu_dm_psr_disable() - disable psr f/w + * if psr is enabled on any stream + * + * Return: true if success + */ +static bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm) +{ + DRM_DEBUG_DRIVER("Disabling psr if psr is enabled on any stream\n"); + return dc_set_psr_allow_active(dm->dc, false); +} + +void amdgpu_dm_trigger_timing_sync(struct drm_device *dev) +{ + struct amdgpu_device *adev = drm_to_adev(dev); + struct dc *dc = adev->dm.dc; + int i; + + mutex_lock(&adev->dm.dc_lock); + if (dc->current_state) { + for (i = 0; i < dc->current_state->stream_count; ++i) + dc->current_state->streams[i] + ->triggered_crtc_reset.enabled = + adev->dm.force_timing_sync; + + dm_enable_per_frame_crtc_master_sync(dc->current_state); + dc_trigger_sync(dc, dc->current_state); + } + mutex_unlock(&adev->dm.dc_lock); +} 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 dd1559c743c2..a7856ae2e5f5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -340,6 +340,14 @@ struct amdgpu_display_manager { * fake encoders used for DP MST. */ struct amdgpu_encoder mst_encoders[AMDGPU_DM_MAX_CRTC]; + bool force_timing_sync; +}; + +struct dsc_preferred_settings { + bool dsc_clock_en; + uint32_t dsc_slice_width; + uint32_t dsc_slice_height; + uint32_t dsc_bits_per_pixel; }; struct amdgpu_dm_connector { @@ -389,6 +397,7 @@ struct amdgpu_dm_connector { uint32_t debugfs_dpcd_size; #endif bool force_yuv420_output; + struct dsc_preferred_settings dsc_settings; }; #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base) @@ -403,6 +412,8 @@ struct dc_plane_state; struct dm_plane_state { struct drm_plane_state base; struct dc_plane_state *dc_state; + uint64_t tiling_flags; + bool tmz_surface; }; struct dm_crtc_state { @@ -485,6 +496,8 @@ void dm_restore_drm_connector_state(struct drm_device *dev, void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, struct edid *edid); +void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); + #define MAX_COLOR_LUT_ENTRIES 4096 /* Legacy gamm LUT users such as X doesn't like large LUT sizes */ #define MAX_COLOR_LEGACY_LUT_ENTRIES 256 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index b321ff654df4..5df05f0d18bc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -308,8 +308,7 @@ static int __set_input_tf(struct dc_transfer_func *func, int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) { struct dc_stream_state *stream = crtc->stream; - struct amdgpu_device *adev = - (struct amdgpu_device *)crtc->base.state->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev); bool has_rom = adev->asic_type <= CHIP_RAVEN; struct drm_color_ctm *ctm = NULL; const struct drm_color_lut *degamma_lut, *regamma_lut; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index eaad9099bc0b..d0699e98db92 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -101,7 +101,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, struct dm_crtc_state *dm_crtc_state, enum amdgpu_dm_pipe_crc_source source) { - struct amdgpu_device *adev = crtc->dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dc_stream_state *stream_state = dm_crtc_state->stream; bool enable = amdgpu_dm_is_valid_crc_source(source); int ret = 0; 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 e5a6d9115949..94fcb086154c 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 @@ -49,6 +49,10 @@ struct dmub_debugfs_trace_entry { uint32_t param1; }; +static inline const char *yesno(bool v) +{ + return v ? "yes" : "no"; +} /* parse_write_buffer_into_params - Helper function to parse debugfs write buffer into an array * @@ -980,6 +984,161 @@ static ssize_t dp_dpcd_data_read(struct file *f, char __user *buf, return read_size - r; } +/* function: Read link's DSC & FEC capabilities + * + * + * Access it with the following command (you need to specify + * connector like DP-1): + * + * cat /sys/kernel/debug/dri/0/DP-X/dp_dsc_fec_support + * + */ +static int dp_dsc_fec_support_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + struct drm_modeset_acquire_ctx ctx; + struct drm_device *dev = connector->dev; + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + int ret = 0; + bool try_again = false; + bool is_fec_supported = false; + bool is_dsc_supported = false; + struct dpcd_caps dpcd_caps; + + drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); + do { + try_again = false; + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx); + if (ret) { + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) { + try_again = true; + continue; + } + } + break; + } + if (connector->status != connector_status_connected) { + ret = -ENODEV; + break; + } + dpcd_caps = aconnector->dc_link->dpcd_caps; + if (aconnector->port) { + /* aconnector sets dsc_aux during get_modes call + * if MST connector has it means it can either + * enable DSC on the sink device or on MST branch + * its connected to. + */ + if (aconnector->dsc_aux) { + is_fec_supported = true; + is_dsc_supported = true; + } + } else { + is_fec_supported = dpcd_caps.fec_cap.raw & 0x1; + is_dsc_supported = dpcd_caps.dsc_caps.dsc_basic_caps.raw[0] & 0x1; + } + } while (try_again); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + seq_printf(m, "FEC_Sink_Support: %s\n", yesno(is_fec_supported)); + seq_printf(m, "DSC_Sink_Support: %s\n", yesno(is_dsc_supported)); + + return ret; +} + +/* function: Trigger virtual HPD redetection on connector + * + * This function will perform link rediscovery, link disable + * and enable, and dm connector state update. + * + * Retrigger HPD on an existing connector by echoing 1 into + * its respectful "trigger_hotplug" debugfs entry: + * + * echo 1 > /sys/kernel/debug/dri/0/DP-X/trigger_hotplug + * + */ +static ssize_t dp_trigger_hotplug(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + struct drm_connector *connector = &aconnector->base; + struct drm_device *dev = connector->dev; + enum dc_connection_type new_connection_type = dc_connection_none; + char *wr_buf = NULL; + uint32_t wr_buf_size = 42; + int max_param_num = 1; + long param[1] = {0}; + uint8_t param_nums = 0; + + if (!aconnector || !aconnector->dc_link) + return -EINVAL; + + if (size == 0) + return -EINVAL; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + + if (!wr_buf) { + DRM_DEBUG_DRIVER("no memory to allocate write buffer\n"); + return -ENOSPC; + } + + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) + return -EINVAL; + + if (param_nums <= 0) { + DRM_DEBUG_DRIVER("user data not be read\n"); + kfree(wr_buf); + return -EINVAL; + } + + if (param[0] == 1) { + mutex_lock(&aconnector->hpd_lock); + + if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type) && + new_connection_type != dc_connection_none) + goto unlock; + + if (!dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) + goto unlock; + + amdgpu_dm_update_connector_after_detect(aconnector); + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + drm_kms_helper_hotplug_event(dev); + +unlock: + mutex_unlock(&aconnector->hpd_lock); + } + + kfree(wr_buf); + return size; +} + +/* function: read DSC status on the connector + * + * The read function: dp_dsc_clock_en_read + * returns current status of DSC clock on the connector. + * The return is a boolean flag: 1 or 0. + * + * Access it with the following command (you need to specify + * connector like DP-1): + * + * cat /sys/kernel/debug/dri/0/DP-X/dsc_clock_en + * + * Expected output: + * 1 - means that DSC is currently enabled + * 0 - means that DSC is disabled + */ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { @@ -1037,6 +1196,95 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, return result; } +/* function: write force DSC on the connector + * + * The write function: dp_dsc_clock_en_write + * enables to force DSC on the connector. + * User can write to either force enable DSC + * on the next modeset or set it to driver default + * + * Writing DSC settings is done with the following command: + * - To force enable DSC (you need to specify + * connector like DP-1): + * + * echo 0x1 > /sys/kernel/debug/dri/0/DP-X/dsc_clock_en + * + * - To return to default state set the flag to zero and + * let driver deal with DSC automatically + * (you need to specify connector like DP-1): + * + * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_clock_en + * + */ +static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + struct pipe_ctx *pipe_ctx; + int i; + char *wr_buf = NULL; + uint32_t wr_buf_size = 42; + int max_param_num = 1; + long param[1] = {0}; + uint8_t param_nums = 0; + + if (size == 0) + return -EINVAL; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + + if (!wr_buf) { + DRM_DEBUG_DRIVER("no memory to allocate write buffer\n"); + return -ENOSPC; + } + + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) { + kfree(wr_buf); + return -EINVAL; + } + + if (param_nums <= 0) { + DRM_DEBUG_DRIVER("user data not be read\n"); + kfree(wr_buf); + return -EINVAL; + } + + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx && pipe_ctx->stream && + pipe_ctx->stream->link == aconnector->dc_link) + break; + } + + if (!pipe_ctx || !pipe_ctx->stream) + goto done; + + aconnector->dsc_settings.dsc_clock_en = param[0]; + +done: + kfree(wr_buf); + return size; +} + +/* function: read DSC slice width parameter on the connector + * + * The read function: dp_dsc_slice_width_read + * returns dsc slice width used in the current configuration + * The return is an integer: 0 or other positive number + * + * Access the status with the following command: + * + * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_width + * + * 0 - means that DSC is disabled + * + * Any other number more than zero represents the + * slice width currently used by DSC in pixels + * + */ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { @@ -1094,6 +1342,98 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf, return result; } +/* function: write DSC slice width parameter + * + * The write function: dp_dsc_slice_width_write + * overwrites automatically generated DSC configuration + * of slice width. + * + * The user has to write the slice width divisible by the + * picture width. + * + * Also the user has to write width in hexidecimal + * rather than in decimal. + * + * Writing DSC settings is done with the following command: + * - To force overwrite slice width: (example sets to 1920 pixels) + * + * echo 0x780 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_width + * + * - To stop overwriting and let driver find the optimal size, + * set the width to zero: + * + * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_width + * + */ +static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + struct pipe_ctx *pipe_ctx; + int i; + char *wr_buf = NULL; + uint32_t wr_buf_size = 42; + int max_param_num = 1; + long param[1] = {0}; + uint8_t param_nums = 0; + + if (size == 0) + return -EINVAL; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + + if (!wr_buf) { + DRM_DEBUG_DRIVER("no memory to allocate write buffer\n"); + return -ENOSPC; + } + + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) { + kfree(wr_buf); + return -EINVAL; + } + + if (param_nums <= 0) { + DRM_DEBUG_DRIVER("user data not be read\n"); + kfree(wr_buf); + return -EINVAL; + } + + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx && pipe_ctx->stream && + pipe_ctx->stream->link == aconnector->dc_link) + break; + } + + if (!pipe_ctx || !pipe_ctx->stream) + goto done; + + aconnector->dsc_settings.dsc_slice_width = param[0]; + +done: + kfree(wr_buf); + return size; +} + +/* function: read DSC slice height parameter on the connector + * + * The read function: dp_dsc_slice_height_read + * returns dsc slice height used in the current configuration + * The return is an integer: 0 or other positive number + * + * Access the status with the following command: + * + * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_height + * + * 0 - means that DSC is disabled + * + * Any other number more than zero represents the + * slice height currently used by DSC in pixels + * + */ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { @@ -1151,6 +1491,94 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf, return result; } +/* function: write DSC slice height parameter + * + * The write function: dp_dsc_slice_height_write + * overwrites automatically generated DSC configuration + * of slice height. + * + * The user has to write the slice height divisible by the + * picture height. + * + * Also the user has to write height in hexidecimal + * rather than in decimal. + * + * Writing DSC settings is done with the following command: + * - To force overwrite slice height (example sets to 128 pixels): + * + * echo 0x80 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_height + * + * - To stop overwriting and let driver find the optimal size, + * set the height to zero: + * + * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_slice_height + * + */ +static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + struct pipe_ctx *pipe_ctx; + int i; + char *wr_buf = NULL; + uint32_t wr_buf_size = 42; + int max_param_num = 1; + uint8_t param_nums = 0; + long param[1] = {0}; + + if (size == 0) + return -EINVAL; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + + if (!wr_buf) { + DRM_DEBUG_DRIVER("no memory to allocate write buffer\n"); + return -ENOSPC; + } + + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) { + kfree(wr_buf); + return -EINVAL; + } + + if (param_nums <= 0) { + DRM_DEBUG_DRIVER("user data not be read\n"); + kfree(wr_buf); + return -EINVAL; + } + + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx && pipe_ctx->stream && + pipe_ctx->stream->link == aconnector->dc_link) + break; + } + + if (!pipe_ctx || !pipe_ctx->stream) + goto done; + + aconnector->dsc_settings.dsc_slice_height = param[0]; + +done: + kfree(wr_buf); + return size; +} + +/* function: read DSC target rate on the connector in bits per pixel + * + * The read function: dp_dsc_bits_per_pixel_read + * returns target rate of compression in bits per pixel + * The return is an integer: 0 or other positive integer + * + * Access it with the following command: + * + * cat /sys/kernel/debug/dri/0/DP-X/dsc_bits_per_pixel + * + * 0 - means that DSC is disabled + */ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { @@ -1208,6 +1636,94 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf, return result; } +/* function: write DSC target rate in bits per pixel + * + * The write function: dp_dsc_bits_per_pixel_write + * overwrites automatically generated DSC configuration + * of DSC target bit rate. + * + * Also the user has to write bpp in hexidecimal + * rather than in decimal. + * + * Writing DSC settings is done with the following command: + * - To force overwrite rate (example sets to 256 bpp x 1/16): + * + * echo 0x100 > /sys/kernel/debug/dri/0/DP-X/dsc_bits_per_pixel + * + * - To stop overwriting and let driver find the optimal rate, + * set the rate to zero: + * + * echo 0x0 > /sys/kernel/debug/dri/0/DP-X/dsc_bits_per_pixel + * + */ +static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + struct pipe_ctx *pipe_ctx; + int i; + char *wr_buf = NULL; + uint32_t wr_buf_size = 42; + int max_param_num = 1; + uint8_t param_nums = 0; + long param[1] = {0}; + + if (size == 0) + return -EINVAL; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + + if (!wr_buf) { + DRM_DEBUG_DRIVER("no memory to allocate write buffer\n"); + return -ENOSPC; + } + + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) { + kfree(wr_buf); + return -EINVAL; + } + + if (param_nums <= 0) { + DRM_DEBUG_DRIVER("user data not be read\n"); + kfree(wr_buf); + return -EINVAL; + } + + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx && pipe_ctx->stream && + pipe_ctx->stream->link == aconnector->dc_link) + break; + } + + if (!pipe_ctx || !pipe_ctx->stream) + goto done; + + aconnector->dsc_settings.dsc_bits_per_pixel = param[0]; + +done: + kfree(wr_buf); + return size; +} + +/* function: read DSC picture width parameter on the connector + * + * The read function: dp_dsc_pic_width_read + * returns dsc picture width used in the current configuration + * It is the same as h_addressable of the current + * display's timing + * The return is an integer: 0 or other positive integer + * If 0 then DSC is disabled. + * + * Access it with the following command: + * + * cat /sys/kernel/debug/dri/0/DP-X/dsc_pic_width + * + * 0 - means that DSC is disabled + */ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { @@ -1322,6 +1838,21 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf, return result; } +/* function: read DSC chunk size parameter on the connector + * + * The read function: dp_dsc_chunk_size_read + * returns dsc chunk size set in the current configuration + * The value is calculated automatically by DSC code + * and depends on slice parameters and bpp target rate + * The return is an integer: 0 or other positive integer + * If 0 then DSC is disabled. + * + * Access it with the following command: + * + * cat /sys/kernel/debug/dri/0/DP-X/dsc_chunk_size + * + * 0 - means that DSC is disabled + */ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { @@ -1379,6 +1910,21 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf, return result; } +/* function: read DSC slice bpg offset on the connector + * + * The read function: dp_dsc_slice_bpg_offset_read + * returns dsc bpg slice offset set in the current configuration + * The value is calculated automatically by DSC code + * and depends on slice parameters and bpp target rate + * The return is an integer: 0 or other positive integer + * If 0 then DSC is disabled. + * + * Access it with the following command: + * + * cat /sys/kernel/debug/dri/0/DP-X/dsc_slice_bpg_offset + * + * 0 - means that DSC is disabled + */ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { @@ -1436,6 +1982,7 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf, return result; } +DEFINE_SHOW_ATTRIBUTE(dp_dsc_fec_support); DEFINE_SHOW_ATTRIBUTE(dmub_fw_state); DEFINE_SHOW_ATTRIBUTE(dmub_tracebuffer); DEFINE_SHOW_ATTRIBUTE(output_bpc); @@ -1446,24 +1993,28 @@ DEFINE_SHOW_ATTRIBUTE(hdcp_sink_capability); static const struct file_operations dp_dsc_clock_en_debugfs_fops = { .owner = THIS_MODULE, .read = dp_dsc_clock_en_read, + .write = dp_dsc_clock_en_write, .llseek = default_llseek }; static const struct file_operations dp_dsc_slice_width_debugfs_fops = { .owner = THIS_MODULE, .read = dp_dsc_slice_width_read, + .write = dp_dsc_slice_width_write, .llseek = default_llseek }; static const struct file_operations dp_dsc_slice_height_debugfs_fops = { .owner = THIS_MODULE, .read = dp_dsc_slice_height_read, + .write = dp_dsc_slice_height_write, .llseek = default_llseek }; static const struct file_operations dp_dsc_bits_per_pixel_debugfs_fops = { .owner = THIS_MODULE, .read = dp_dsc_bits_per_pixel_read, + .write = dp_dsc_bits_per_pixel_write, .llseek = default_llseek }; @@ -1491,6 +2042,12 @@ static const struct file_operations dp_dsc_slice_bpg_offset_debugfs_fops = { .llseek = default_llseek }; +static const struct file_operations dp_trigger_hotplug_debugfs_fops = { + .owner = THIS_MODULE, + .write = dp_trigger_hotplug, + .llseek = default_llseek +}; + static const struct file_operations dp_link_settings_debugfs_fops = { .owner = THIS_MODULE, .read = dp_link_settings_read, @@ -1557,7 +2114,8 @@ static const struct { {"dsc_pic_width", &dp_dsc_pic_width_debugfs_fops}, {"dsc_pic_height", &dp_dsc_pic_height_debugfs_fops}, {"dsc_chunk_size", &dp_dsc_chunk_size_debugfs_fops}, - {"dsc_slice_bpg", &dp_dsc_slice_bpg_offset_debugfs_fops} + {"dsc_slice_bpg", &dp_dsc_slice_bpg_offset_debugfs_fops}, + {"dp_dsc_fec_support", &dp_dsc_fec_support_fops} }; #ifdef CONFIG_DRM_AMD_DC_HDCP @@ -1721,7 +2279,7 @@ static int current_backlight_read(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_display_manager *dm = &adev->dm; unsigned int backlight = dc_link_get_backlight_level(dm->backlight_link); @@ -1739,7 +2297,7 @@ static int target_backlight_read(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_display_manager *dm = &adev->dm; unsigned int backlight = dc_link_get_target_backlight_pwm(dm->backlight_link); @@ -1778,6 +2336,38 @@ static const struct drm_info_list amdgpu_dm_debugfs_list[] = { }; /* + * Sets the force_timing_sync debug optino from the given string. + * All connected displays will be force synchronized immediately. + * Usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_force_timing_sync + */ +static int force_timing_sync_set(void *data, u64 val) +{ + struct amdgpu_device *adev = data; + + adev->dm.force_timing_sync = (bool)val; + + amdgpu_dm_trigger_timing_sync(adev_to_drm(adev)); + + return 0; +} + +/* + * Gets the force_timing_sync debug option value into the given buffer. + * Usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_force_timing_sync + */ +static int force_timing_sync_get(void *data, u64 *val) +{ + struct amdgpu_device *adev = data; + + *val = adev->dm.force_timing_sync; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(force_timing_sync_ops, force_timing_sync_get, + force_timing_sync_set, "%llu\n"); + +/* * Sets the DC visual confirm debug option from the given string. * Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_visual_confirm */ @@ -1815,7 +2405,7 @@ int dtn_debugfs_init(struct amdgpu_device *adev) .llseek = default_llseek }; - struct drm_minor *minor = adev->ddev->primary; + struct drm_minor *minor = adev_to_drm(adev)->primary; struct dentry *root = minor->debugfs_root; int ret; @@ -1836,5 +2426,8 @@ int dtn_debugfs_init(struct amdgpu_device *adev) debugfs_create_file_unsafe("amdgpu_dm_dmub_fw_state", 0644, root, adev, &dmub_fw_state_fops); + debugfs_create_file_unsafe("amdgpu_dm_force_timing_sync", 0644, root, + adev, &force_timing_sync_ops); + return 0; } 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 cbcf504f73a5..357778556b06 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 @@ -719,7 +719,7 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev) */ void amdgpu_dm_hpd_init(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; @@ -755,7 +755,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev) */ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_connector *connector; struct drm_connector_list_iter iter; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 336aaa09be46..adbb44822e94 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -26,6 +26,7 @@ #include <linux/version.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_dp_mst_helper.h> +#include <drm/drm_dp_helper.h> #include "dm_services.h" #include "amdgpu.h" #include "amdgpu_dm.h" @@ -241,7 +242,7 @@ dm_mst_atomic_best_encoder(struct drm_connector *connector, struct drm_connector_state *connector_state) { struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(connector_state->crtc); return &adev->dm.mst_encoders[acrtc->crtc_id].base; @@ -310,7 +311,7 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = { void dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); int i; for (i = 0; i < adev->dm.display_indexes_num; i++) { @@ -337,7 +338,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, { struct amdgpu_dm_connector *master = container_of(mgr, struct amdgpu_dm_connector, mst_mgr); struct drm_device *dev = master->base.dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_dm_connector *aconnector; struct drm_connector *connector; int i; @@ -426,11 +427,13 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, aconnector->mst_mgr.cbs = &dm_mst_cbs; drm_dp_mst_topology_mgr_init( &aconnector->mst_mgr, - dm->adev->ddev, + adev_to_drm(dm->adev), &aconnector->dm_dp_aux.aux, 16, 4, aconnector->connector_id); + + drm_connector_attach_dp_subconnector_property(&aconnector->base); } int dm_mst_get_pbn_divider(struct dc_link *link) @@ -450,6 +453,10 @@ struct dsc_mst_fairness_params { struct dc_dsc_bw_range bw_range; bool compression_possible; struct drm_dp_mst_port *port; + bool clock_overwrite; + uint32_t slice_width_overwrite; + uint32_t slice_height_overwrite; + uint32_t bpp_overwrite; }; struct dsc_mst_fairness_vars { @@ -483,7 +490,21 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p params[i].timing, ¶ms[i].timing->dsc_cfg)) { params[i].timing->flags.DSC = 1; - params[i].timing->dsc_cfg.bits_per_pixel = vars[i].bpp_x16; + + if (params[i].bpp_overwrite) + params[i].timing->dsc_cfg.bits_per_pixel = params[i].bpp_overwrite; + else + params[i].timing->dsc_cfg.bits_per_pixel = vars[i].bpp_x16; + + if (params[i].slice_width_overwrite) + params[i].timing->dsc_cfg.num_slices_h = DIV_ROUND_UP( + params[i].timing->h_addressable, + params[i].slice_width_overwrite); + + if (params[i].slice_height_overwrite) + params[i].timing->dsc_cfg.num_slices_v = DIV_ROUND_UP( + params[i].timing->v_addressable, + params[i].slice_height_overwrite); } else { params[i].timing->flags.DSC = 0; } @@ -615,7 +636,9 @@ static void try_disable_dsc(struct drm_atomic_state *state, int remaining_to_try = 0; for (i = 0; i < count; i++) { - if (vars[i].dsc_enabled && vars[i].bpp_x16 == params[i].bw_range.max_target_bpp_x16) { + if (vars[i].dsc_enabled + && vars[i].bpp_x16 == params[i].bw_range.max_target_bpp_x16 + && !params[i].clock_overwrite) { kbps_increase[i] = params[i].bw_range.stream_kbps - params[i].bw_range.max_kbps; tried[i] = false; remaining_to_try += 1; @@ -676,6 +699,7 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, struct dsc_mst_fairness_vars vars[MAX_PIPES]; struct amdgpu_dm_connector *aconnector; int count = 0; + bool debugfs_overwrite = false; memset(params, 0, sizeof(params)); @@ -694,6 +718,12 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, params[count].sink = stream->sink; aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; params[count].port = aconnector->port; + params[count].clock_overwrite = aconnector->dsc_settings.dsc_clock_en; + if (params[count].clock_overwrite) + debugfs_overwrite = true; + params[count].slice_width_overwrite = aconnector->dsc_settings.dsc_slice_width; + params[count].slice_height_overwrite = aconnector->dsc_settings.dsc_slice_height; + params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel; params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported; dc_dsc_get_policy_for_timing(params[count].timing, &dsc_policy); if (!dc_dsc_compute_bandwidth_range( @@ -719,7 +749,7 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, dm_mst_get_pbn_divider(dc_link)) < 0) return false; } - if (!drm_dp_mst_atomic_check(state)) { + if (!drm_dp_mst_atomic_check(state) && !debugfs_overwrite) { set_dsc_configs_from_fairness_vars(params, vars, count); return true; } diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index e0f4f1be1618..047b1e2dd8f1 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -43,6 +43,10 @@ DC_LIBS += dce110 DC_LIBS += dce100 DC_LIBS += dce80 +ifdef CONFIG_DRM_AMD_DC_SI +DC_LIBS += dce60 +endif + ifdef CONFIG_DRM_AMD_DC_HDCP DC_LIBS += hdcp endif diff --git a/drivers/gpu/drm/amd/display/dc/bios/Makefile b/drivers/gpu/drm/amd/display/dc/bios/Makefile index 239e86bbec5a..ed6b5e9763f6 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/Makefile +++ b/drivers/gpu/drm/amd/display/dc/bios/Makefile @@ -32,6 +32,15 @@ AMD_DAL_BIOS = $(addprefix $(AMDDALPATH)/dc/bios/,$(BIOS)) AMD_DISPLAY_FILES += $(AMD_DAL_BIOS) ############################################################################### +# DCE 6x +############################################################################### +# All DCE6.x are derived from DCE6.0, so 6.0 MUST be defined if ANY of +# DCE6.x is compiled. +ifdef CONFIG_DRM_AMD_DC_SI +AMD_DISPLAY_FILES += $(AMDDALPATH)/dc/bios/dce60/command_table_helper_dce60.o +endif + +############################################################################### # DCE 8x ############################################################################### # All DCE8.x are derived from DCE8.0, so 8.0 MUST be defined if ANY of 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 5815983caaf8..070459e3e407 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c @@ -1877,9 +1877,7 @@ static enum bp_result set_crtc_using_dtd_timing_v3( * but it is 4 either from Edid data (spec CEA 861) * or CEA timing table. */ - params.usV_SyncOffset = - cpu_to_le16(le16_to_cpu(params.usV_SyncOffset) + 1); - + le16_add_cpu(¶ms.usV_SyncOffset, 1); } } 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 eb3ae5c3677c..25bdf1c38e0a 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -569,10 +569,7 @@ static enum bp_result set_crtc_using_dtd_timing_v3( * but it is 4 either from Edid data (spec CEA 861) * or CEA timing table. */ - params.v_syncoffset = - cpu_to_le16(le16_to_cpu(params.v_syncoffset) + - 1); - + le16_add_cpu(¶ms.v_syncoffset, 1); } } @@ -923,11 +920,39 @@ static void init_enable_lvtma_control(struct bios_parser *bp) } +static void enable_lvtma_control_dmcub( + struct dc_dmub_srv *dmcub, + uint8_t uc_pwr_on) +{ + + union dmub_rb_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + + cmd.cmd_common.header.type = DMUB_CMD__VBIOS; + cmd.cmd_common.header.sub_type = + DMUB_CMD__VBIOS_LVTMA_CONTROL; + cmd.cmd_common.cmd_buffer[0] = + uc_pwr_on; + + dc_dmub_srv_cmd_queue(dmcub, &cmd); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); + +} + static enum bp_result enable_lvtma_control( struct bios_parser *bp, uint8_t uc_pwr_on) { enum bp_result result = BP_RESULT_FAILURE; + + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + enable_lvtma_control_dmcub(bp->base.ctx->dmub_srv, + uc_pwr_on); + return BP_RESULT_OK; + } return result; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c index 253bbb1eea60..48b4ef03fc8f 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c @@ -36,6 +36,14 @@ bool dal_bios_parser_init_cmd_tbl_helper( enum dce_version dce) { switch (dce) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case DCE_VERSION_6_0: + case DCE_VERSION_6_1: + case DCE_VERSION_6_4: + *h = dal_cmd_tbl_helper_dce60_get_table(); + return true; +#endif + case DCE_VERSION_8_0: case DCE_VERSION_8_1: case DCE_VERSION_8_3: diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h index 4c3789df253d..dfd30aaf4032 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h @@ -26,6 +26,9 @@ #ifndef __DAL_COMMAND_TABLE_HELPER_H__ #define __DAL_COMMAND_TABLE_HELPER_H__ +#if defined(CONFIG_DRM_AMD_DC_SI) +#include "dce60/command_table_helper_dce60.h" +#endif #include "dce80/command_table_helper_dce80.h" #include "dce110/command_table_helper_dce110.h" #include "dce112/command_table_helper_dce112.h" diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c index 21ff6b686f5f..74c498b6774d 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c @@ -37,6 +37,14 @@ bool dal_bios_parser_init_cmd_tbl_helper2( enum dce_version dce) { switch (dce) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case DCE_VERSION_6_0: + case DCE_VERSION_6_1: + case DCE_VERSION_6_4: + *h = dal_cmd_tbl_helper_dce60_get_table(); + return true; +#endif + case DCE_VERSION_8_0: case DCE_VERSION_8_1: case DCE_VERSION_8_3: diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h index 785fcb20a1b9..66e0a3e73768 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h @@ -26,6 +26,9 @@ #ifndef __DAL_COMMAND_TABLE_HELPER2_H__ #define __DAL_COMMAND_TABLE_HELPER2_H__ +#if defined(CONFIG_DRM_AMD_DC_SI) +#include "dce60/command_table_helper_dce60.h" +#endif #include "dce80/command_table_helper_dce80.h" #include "dce110/command_table_helper_dce110.h" #include "dce112/command_table_helper2_dce112.h" diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce60/command_table_helper_dce60.c b/drivers/gpu/drm/amd/display/dc/bios/dce60/command_table_helper_dce60.c new file mode 100644 index 000000000000..710221b4f5c5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bios/dce60/command_table_helper_dce60.c @@ -0,0 +1,354 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#include "dm_services.h" + +#include "atom.h" + +#include "include/grph_object_id.h" +#include "include/grph_object_defs.h" +#include "include/bios_parser_types.h" + +#include "../command_table_helper.h" + +static uint8_t encoder_action_to_atom(enum bp_encoder_control_action action) +{ + uint8_t atom_action = 0; + + switch (action) { + case ENCODER_CONTROL_ENABLE: + atom_action = ATOM_ENABLE; + break; + case ENCODER_CONTROL_DISABLE: + atom_action = ATOM_DISABLE; + break; + case ENCODER_CONTROL_SETUP: + atom_action = ATOM_ENCODER_CMD_SETUP; + break; + case ENCODER_CONTROL_INIT: + atom_action = ATOM_ENCODER_INIT; + break; + default: + BREAK_TO_DEBUGGER(); /* Unhandle action in driver.!! */ + break; + } + + return atom_action; +} + +static bool engine_bp_to_atom(enum engine_id id, uint32_t *atom_engine_id) +{ + bool result = false; + + if (atom_engine_id != NULL) + switch (id) { + case ENGINE_ID_DIGA: + *atom_engine_id = ASIC_INT_DIG1_ENCODER_ID; + result = true; + break; + case ENGINE_ID_DIGB: + *atom_engine_id = ASIC_INT_DIG2_ENCODER_ID; + result = true; + break; + case ENGINE_ID_DIGC: + *atom_engine_id = ASIC_INT_DIG3_ENCODER_ID; + result = true; + break; + case ENGINE_ID_DIGD: + *atom_engine_id = ASIC_INT_DIG4_ENCODER_ID; + result = true; + break; + case ENGINE_ID_DIGE: + *atom_engine_id = ASIC_INT_DIG5_ENCODER_ID; + result = true; + break; + case ENGINE_ID_DIGF: + *atom_engine_id = ASIC_INT_DIG6_ENCODER_ID; + result = true; + break; + case ENGINE_ID_DIGG: + *atom_engine_id = ASIC_INT_DIG7_ENCODER_ID; + result = true; + break; + case ENGINE_ID_DACA: + *atom_engine_id = ASIC_INT_DAC1_ENCODER_ID; + result = true; + break; + default: + break; + } + + return result; +} + +static bool clock_source_id_to_atom( + enum clock_source_id id, + uint32_t *atom_pll_id) +{ + bool result = true; + + if (atom_pll_id != NULL) + switch (id) { + case CLOCK_SOURCE_ID_PLL0: + *atom_pll_id = ATOM_PPLL0; + break; + case CLOCK_SOURCE_ID_PLL1: + *atom_pll_id = ATOM_PPLL1; + break; + case CLOCK_SOURCE_ID_PLL2: + *atom_pll_id = ATOM_PPLL2; + break; + case CLOCK_SOURCE_ID_EXTERNAL: + *atom_pll_id = ATOM_PPLL_INVALID; + break; + case CLOCK_SOURCE_ID_DFS: + *atom_pll_id = ATOM_EXT_PLL1; + break; + case CLOCK_SOURCE_ID_VCE: + /* for VCE encoding, + * we need to pass in ATOM_PPLL_INVALID + */ + *atom_pll_id = ATOM_PPLL_INVALID; + break; + case CLOCK_SOURCE_ID_DP_DTO: + /* When programming DP DTO PLL ID should be invalid */ + *atom_pll_id = ATOM_PPLL_INVALID; + break; + case CLOCK_SOURCE_ID_UNDEFINED: + BREAK_TO_DEBUGGER(); /* check when this will happen! */ + *atom_pll_id = ATOM_PPLL_INVALID; + result = false; + break; + default: + result = false; + break; + } + + return result; +} + +static uint8_t clock_source_id_to_atom_phy_clk_src_id( + enum clock_source_id id) +{ + uint8_t atom_phy_clk_src_id = 0; + + switch (id) { + case CLOCK_SOURCE_ID_PLL0: + atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P0PLL; + break; + case CLOCK_SOURCE_ID_PLL1: + atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL; + break; + case CLOCK_SOURCE_ID_PLL2: + atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P2PLL; + break; + case CLOCK_SOURCE_ID_EXTERNAL: + atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SRC_EXT; + break; + default: + atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL; + break; + } + + return atom_phy_clk_src_id >> 2; +} + +static uint8_t signal_type_to_atom_dig_mode(enum signal_type s) +{ + uint8_t atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP; + + switch (s) { + case SIGNAL_TYPE_DISPLAY_PORT: + case SIGNAL_TYPE_EDP: + atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP; + break; + case SIGNAL_TYPE_LVDS: + atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_LVDS; + break; + case SIGNAL_TYPE_DVI_SINGLE_LINK: + case SIGNAL_TYPE_DVI_DUAL_LINK: + atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI; + break; + case SIGNAL_TYPE_HDMI_TYPE_A: + atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_HDMI; + break; + case SIGNAL_TYPE_DISPLAY_PORT_MST: + atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP_MST; + break; + default: + atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI; + break; + } + + return atom_dig_mode; +} + +static uint8_t hpd_sel_to_atom(enum hpd_source_id id) +{ + uint8_t atom_hpd_sel = 0; + + switch (id) { + case HPD_SOURCEID1: + atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD1_SEL; + break; + case HPD_SOURCEID2: + atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD2_SEL; + break; + case HPD_SOURCEID3: + atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD3_SEL; + break; + case HPD_SOURCEID4: + atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD4_SEL; + break; + case HPD_SOURCEID5: + atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD5_SEL; + break; + case HPD_SOURCEID6: + atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD6_SEL; + break; + case HPD_SOURCEID_UNKNOWN: + default: + atom_hpd_sel = 0; + break; + } + return atom_hpd_sel >> 4; +} + +static uint8_t dig_encoder_sel_to_atom(enum engine_id id) +{ + uint8_t atom_dig_encoder_sel = 0; + + switch (id) { + case ENGINE_ID_DIGA: + atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGA_SEL; + break; + case ENGINE_ID_DIGB: + atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGB_SEL; + break; + case ENGINE_ID_DIGC: + atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGC_SEL; + break; + case ENGINE_ID_DIGD: + atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGD_SEL; + break; + case ENGINE_ID_DIGE: + atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGE_SEL; + break; + case ENGINE_ID_DIGF: + atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGF_SEL; + break; + case ENGINE_ID_DIGG: + atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGG_SEL; + break; + default: + atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGA_SEL; + break; + } + + return atom_dig_encoder_sel; +} + +static uint8_t phy_id_to_atom(enum transmitter t) +{ + uint8_t atom_phy_id; + + switch (t) { + case TRANSMITTER_UNIPHY_A: + atom_phy_id = ATOM_PHY_ID_UNIPHYA; + break; + case TRANSMITTER_UNIPHY_B: + atom_phy_id = ATOM_PHY_ID_UNIPHYB; + break; + case TRANSMITTER_UNIPHY_C: + atom_phy_id = ATOM_PHY_ID_UNIPHYC; + break; + case TRANSMITTER_UNIPHY_D: + atom_phy_id = ATOM_PHY_ID_UNIPHYD; + break; + case TRANSMITTER_UNIPHY_E: + atom_phy_id = ATOM_PHY_ID_UNIPHYE; + break; + case TRANSMITTER_UNIPHY_F: + atom_phy_id = ATOM_PHY_ID_UNIPHYF; + break; + case TRANSMITTER_UNIPHY_G: + atom_phy_id = ATOM_PHY_ID_UNIPHYG; + break; + default: + atom_phy_id = ATOM_PHY_ID_UNIPHYA; + break; + } + return atom_phy_id; +} + +static uint8_t disp_power_gating_action_to_atom( + enum bp_pipe_control_action action) +{ + uint8_t atom_pipe_action = 0; + + switch (action) { + case ASIC_PIPE_DISABLE: + atom_pipe_action = ATOM_DISABLE; + break; + case ASIC_PIPE_ENABLE: + atom_pipe_action = ATOM_ENABLE; + break; + case ASIC_PIPE_INIT: + atom_pipe_action = ATOM_INIT; + break; + default: + BREAK_TO_DEBUGGER(); /* Unhandle action in driver! */ + break; + } + + return atom_pipe_action; +} + +static const struct command_table_helper command_table_helper_funcs = { + .controller_id_to_atom = dal_cmd_table_helper_controller_id_to_atom, + .encoder_action_to_atom = encoder_action_to_atom, + .engine_bp_to_atom = engine_bp_to_atom, + .clock_source_id_to_atom = clock_source_id_to_atom, + .clock_source_id_to_atom_phy_clk_src_id = + clock_source_id_to_atom_phy_clk_src_id, + .signal_type_to_atom_dig_mode = signal_type_to_atom_dig_mode, + .hpd_sel_to_atom = hpd_sel_to_atom, + .dig_encoder_sel_to_atom = dig_encoder_sel_to_atom, + .phy_id_to_atom = phy_id_to_atom, + .disp_power_gating_action_to_atom = disp_power_gating_action_to_atom, + .assign_control_parameter = + dal_cmd_table_helper_assign_control_parameter, + .clock_source_id_to_ref_clk_src = + dal_cmd_table_helper_clock_source_id_to_ref_clk_src, + .transmitter_bp_to_atom = dal_cmd_table_helper_transmitter_bp_to_atom, + .encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom, + .encoder_mode_bp_to_atom = + dal_cmd_table_helper_encoder_mode_bp_to_atom, +}; + +const struct command_table_helper *dal_cmd_tbl_helper_dce60_get_table(void) +{ + return &command_table_helper_funcs; +} diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce60/command_table_helper_dce60.h b/drivers/gpu/drm/amd/display/dc/bios/dce60/command_table_helper_dce60.h new file mode 100644 index 000000000000..f733be553d5a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bios/dce60/command_table_helper_dce60.h @@ -0,0 +1,33 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#ifndef __DAL_COMMAND_TABLE_HELPER_DCE60_H__ +#define __DAL_COMMAND_TABLE_HELPER_DCE60_H__ + +struct command_table_helper; + +const struct command_table_helper *dal_cmd_tbl_helper_dce60_get_table(void); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 4674aca8f206..64f515d74410 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -33,6 +33,10 @@ ifdef CONFIG_PPC64 calcs_ccflags := -mhard-float -maltivec endif +ifdef CONFIG_ARM64 +calcs_rcflags := -mgeneral-regs-only +endif + ifdef CONFIG_CC_IS_GCC ifeq ($(call cc-ifversion, -lt, 0701, y), y) IS_OLD_GCC = 1 @@ -53,6 +57,9 @@ endif CFLAGS_$(AMDDALPATH)/dc/calcs/dcn_calcs.o := $(calcs_ccflags) CFLAGS_$(AMDDALPATH)/dc/calcs/dcn_calc_auto.o := $(calcs_ccflags) CFLAGS_$(AMDDALPATH)/dc/calcs/dcn_calc_math.o := $(calcs_ccflags) -Wno-tautological-compare +CFLAGS_REMOVE_$(AMDDALPATH)/dc/calcs/dcn_calcs.o := $(calcs_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/calcs/dcn_calc_auto.o := $(calcs_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/calcs/dcn_calc_math.o := $(calcs_rcflags) BW_CALCS = dce_calcs.o bw_fixed.o custom_float.o diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile index 6874276bb2a1..1a495759a034 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile @@ -30,6 +30,17 @@ AMD_DAL_CLK_MGR = $(addprefix $(AMDDALPATH)/dc/clk_mgr/,$(CLK_MGR)) AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR) +ifdef CONFIG_DRM_AMD_DC_SI +############################################################################### +# DCE 60 +############################################################################### +CLK_MGR_DCE60 = dce60_clk_mgr.o + +AMD_DAL_CLK_MGR_DCE60 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dce60/,$(CLK_MGR_DCE60)) + +AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCE60) +endif + ############################################################################### # DCE 100 and DCE8x ############################################################################### @@ -93,6 +104,13 @@ ifdef CONFIG_PPC64 CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn21/rn_clk_mgr.o := $(call cc-option,-mno-gnu-attribute) endif +# prevent build errors: +# ...: '-mgeneral-regs-only' is incompatible with the use of floating-point types +# this file is unused on arm64, just like on ppc64 +ifdef CONFIG_ARM64 +CFLAGS_REMOVE_$(AMDDALPATH)/dc/clk_mgr/dcn21/rn_clk_mgr.o := -mgeneral-regs-only +endif + AMD_DAL_CLK_MGR_DCN21 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn21/,$(CLK_MGR_DCN21)) AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN21) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c index 6a345d43028c..efb909ef7a0f 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c @@ -34,6 +34,7 @@ #include "dce110/dce110_clk_mgr.h" #include "dce112/dce112_clk_mgr.h" #include "dce120/dce120_clk_mgr.h" +#include "dce60/dce60_clk_mgr.h" #include "dcn10/rv1_clk_mgr.h" #include "dcn10/rv2_clk_mgr.h" #include "dcn20/dcn20_clk_mgr.h" @@ -123,6 +124,11 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p } switch (asic_id.chip_family) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case FAMILY_SI: + dce60_clk_mgr_construct(ctx, clk_mgr); + break; +#endif case FAMILY_CI: case FAMILY_KV: dce_clk_mgr_construct(ctx, clk_mgr); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c new file mode 100644 index 000000000000..c11c6b3a787d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.c @@ -0,0 +1,174 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + + +#include "dccg.h" +#include "clk_mgr_internal.h" +#include "dce100/dce_clk_mgr.h" +#include "dce110/dce110_clk_mgr.h" +#include "dce60_clk_mgr.h" +#include "reg_helper.h" +#include "dmcu.h" +#include "core_types.h" +#include "dal_asic_id.h" + +/* + * Currently the register shifts and masks in this file are used for dce60 + * which has no DPREFCLK_CNTL register + * TODO: remove this when DENTIST_DISPCLK_CNTL + * is moved to dccg, where it belongs + */ +#include "dce/dce_6_0_d.h" +#include "dce/dce_6_0_sh_mask.h" + +#define REG(reg) \ + (clk_mgr->regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name + +/* set register offset */ +#define SR(reg_name)\ + .reg_name = mm ## reg_name + +static const struct clk_mgr_registers disp_clk_regs = { + CLK_COMMON_REG_LIST_DCE60_BASE() +}; + +static const struct clk_mgr_shift disp_clk_shift = { + CLK_COMMON_MASK_SH_LIST_DCE60_COMMON_BASE(__SHIFT) +}; + +static const struct clk_mgr_mask disp_clk_mask = { + CLK_COMMON_MASK_SH_LIST_DCE60_COMMON_BASE(_MASK) +}; + + +/* Max clock values for each state indexed by "enum clocks_state": */ +static const struct state_dependent_clocks dce60_max_clks_by_state[] = { +/* ClocksStateInvalid - should not be used */ +{ .display_clk_khz = 0, .pixel_clk_khz = 0 }, +/* ClocksStateUltraLow - not expected to be used for DCE 6.0 */ +{ .display_clk_khz = 0, .pixel_clk_khz = 0 }, +/* ClocksStateLow */ +{ .display_clk_khz = 352000, .pixel_clk_khz = 330000}, +/* ClocksStateNominal */ +{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 }, +/* ClocksStatePerformance */ +{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } }; + +int dce60_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + int dprefclk_wdivider; + int dp_ref_clk_khz; + int target_div; + + /* DCE6 has no DPREFCLK_CNTL to read DP Reference Clock source */ + + /* Read the mmDENTIST_DISPCLK_CNTL to get the currently + * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ + REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider); + + /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ + target_div = dentist_get_divider_from_did(dprefclk_wdivider); + + /* Calculate the current DFS clock, in kHz.*/ + dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_mgr->base.dentist_vco_freq_khz) / target_div; + + return dce_adjust_dp_ref_freq_for_ss(clk_mgr, dp_ref_clk_khz); +} + +static void dce60_pplib_apply_display_requirements( + struct dc *dc, + struct dc_state *context) +{ + struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; + + pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context); + + dce110_fill_display_configs(context, pp_display_cfg); + + if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0) + dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg); +} + +static void dce60_update_clocks(struct clk_mgr *clk_mgr_base, + struct dc_state *context, + bool safe_to_lower) +{ + struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dm_pp_power_level_change_request level_change_req; + int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz; + + /*TODO: W/A for dal3 linux, investigate why this works */ + if (!clk_mgr_dce->dfs_bypass_active) + patched_disp_clk = patched_disp_clk * 115 / 100; + + level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context); + /* get max clock state from PPLIB */ + if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower) + || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) { + if (dm_pp_apply_power_level_change_request(clk_mgr_base->ctx, &level_change_req)) + clk_mgr_dce->cur_min_clks_state = level_change_req.power_level; + } + + if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr_base->clks.dispclk_khz)) { + patched_disp_clk = dce_set_clock(clk_mgr_base, patched_disp_clk); + clk_mgr_base->clks.dispclk_khz = patched_disp_clk; + } + dce60_pplib_apply_display_requirements(clk_mgr_base->ctx->dc, context); +} + + + + + + + + +static struct clk_mgr_funcs dce60_funcs = { + .get_dp_ref_clk_frequency = dce60_get_dp_ref_freq_khz, + .update_clocks = dce60_update_clocks +}; + +void dce60_clk_mgr_construct( + struct dc_context *ctx, + struct clk_mgr_internal *clk_mgr) +{ + dce_clk_mgr_construct(ctx, clk_mgr); + + memcpy(clk_mgr->max_clks_by_state, + dce60_max_clks_by_state, + sizeof(dce60_max_clks_by_state)); + + clk_mgr->regs = &disp_clk_regs; + clk_mgr->clk_mgr_shift = &disp_clk_shift; + clk_mgr->clk_mgr_mask = &disp_clk_mask; + clk_mgr->base.funcs = &dce60_funcs; +} + diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.h new file mode 100644 index 000000000000..eca3e5168089 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce60/dce60_clk_mgr.h @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + + +#ifndef DAL_DC_DCE_DCE60_CLK_MGR_H_ +#define DAL_DC_DCE_DCE60_CLK_MGR_H_ + +#include "dc.h" + +void dce60_clk_mgr_construct( + struct dc_context *ctx, + struct clk_mgr_internal *clk_mgr_dce); + +#endif /* DAL_DC_DCE_DCE60_CLK_MGR_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c index 9133646f6d5f..b0e9b0509568 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c @@ -554,8 +554,7 @@ void dcn3_clk_mgr_construct( void dcn3_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr) { - if (clk_mgr->base.bw_params) - kfree(clk_mgr->base.bw_params); + kfree(clk_mgr->base.bw_params); if (clk_mgr->wm_range_table) dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 92eb1ca1634f..dc463d99ef50 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1238,6 +1238,14 @@ bool dc_enable_stereo( return ret; } +void dc_trigger_sync(struct dc *dc, struct dc_state *context) +{ + if (context->stream_count > 1 && !dc->debug.disable_timing_sync) { + enable_timing_multisync(dc, context); + program_timing_sync(dc, context); + } +} + /* * Applies given context to HW and copy it into current context. * It's up to the user to release the src context afterwards. @@ -1297,10 +1305,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c if (result != DC_OK) return result; - if (context->stream_count > 1 && !dc->debug.disable_timing_sync) { - enable_timing_multisync(dc, context); - program_timing_sync(dc, context); - } + dc_trigger_sync(dc, context); /* Program all planes within new context*/ if (dc->hwss.program_front_end_for_ctx) { @@ -2295,6 +2300,7 @@ static void commit_planes_for_stream(struct dc *dc, enum surface_update_type update_type, struct dc_state *context) { + bool mpcc_disconnected = false; int i, j; struct pipe_ctx *top_pipe_to_program = NULL; @@ -2325,6 +2331,15 @@ static void commit_planes_for_stream(struct dc *dc, context_clock_trace(dc, context); } + if (update_type != UPDATE_TYPE_FAST && dc->hwss.interdependent_update_lock && + dc->hwss.disconnect_pipes && dc->hwss.wait_for_pending_cleared){ + dc->hwss.interdependent_update_lock(dc, context, true); + mpcc_disconnected = dc->hwss.disconnect_pipes(dc, context); + dc->hwss.interdependent_update_lock(dc, context, false); + if (mpcc_disconnected) + dc->hwss.wait_for_pending_cleared(dc, context); + } + for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; @@ -2621,7 +2636,7 @@ void dc_commit_updates_for_stream(struct dc *dc, copy_stream_update_to_stream(dc, context, stream, stream_update); - if (update_type > UPDATE_TYPE_FAST) { + if (update_type >= UPDATE_TYPE_FULL) { if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) { DC_ERROR("Mode validation failed for stream update!\n"); dc_release_state(context); @@ -2933,6 +2948,30 @@ void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_ dc->hwss.get_clock(dc, clock_type, clock_cfg); } +/* enable/disable eDP PSR without specify stream for eDP */ +bool dc_set_psr_allow_active(struct dc *dc, bool enable) +{ + int i; + + for (i = 0; i < dc->current_state->stream_count ; i++) { + struct dc_link *link; + struct dc_stream_state *stream = dc->current_state->streams[i]; + + link = stream->link; + if (!link) + continue; + + if (link->psr_settings.psr_feature_enabled) { + if (enable && !link->psr_settings.psr_allow_active) + return dc_link_set_psr_allow_active(link, true, false); + else if (!enable && link->psr_settings.psr_allow_active) + return dc_link_set_psr_allow_active(link, false, false); + } + } + + return true; +} + #if defined(CONFIG_DRM_AMD_DC_DCN3_0) void dc_allow_idle_optimizations(struct dc *dc, bool allow) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index b2be6ad5101d..d1d95d3e248a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -2431,6 +2431,12 @@ static bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settin return false; } +static bool decide_mst_link_settings(const struct dc_link *link, struct dc_link_settings *link_setting) +{ + *link_setting = link->verified_link_cap; + return true; +} + void decide_link_settings(struct dc_stream_state *stream, struct dc_link_settings *link_setting) { @@ -2456,11 +2462,9 @@ void decide_link_settings(struct dc_stream_state *stream, * TODO: add MST specific link training routine */ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - *link_setting = link->verified_link_cap; - return; - } - - if (link->connector_signal == SIGNAL_TYPE_EDP) { + if (decide_mst_link_settings(link, link_setting)) + return; + } else if (link->connector_signal == SIGNAL_TYPE_EDP) { if (decide_edp_link_settings(link, link_setting, req_bw)) return; } else if (decide_dp_link_settings(link, link_setting, req_bw)) 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 7b5f90ebb133..c6b737dd8425 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -42,6 +42,9 @@ #include "virtual/virtual_stream_encoder.h" #include "dpcd_defs.h" +#if defined(CONFIG_DRM_AMD_DC_SI) +#include "dce60/dce60_resource.h" +#endif #include "dce80/dce80_resource.h" #include "dce100/dce100_resource.h" #include "dce110/dce110_resource.h" @@ -63,6 +66,18 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) enum dce_version dc_version = DCE_VERSION_UNKNOWN; switch (asic_id.chip_family) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case FAMILY_SI: + if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) || + ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) || + ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev)) + dc_version = DCE_VERSION_6_0; + else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev)) + dc_version = DCE_VERSION_6_4; + else + dc_version = DCE_VERSION_6_1; + break; +#endif case FAMILY_CI: dc_version = DCE_VERSION_8_0; break; @@ -129,6 +144,20 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc, struct resource_pool *res_pool = NULL; switch (dc_version) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case DCE_VERSION_6_0: + res_pool = dce60_create_resource_pool( + init_data->num_virtual_links, dc); + break; + case DCE_VERSION_6_1: + res_pool = dce61_create_resource_pool( + init_data->num_virtual_links, dc); + break; + case DCE_VERSION_6_4: + res_pool = dce64_create_resource_pool( + init_data->num_virtual_links, dc); + break; +#endif case DCE_VERSION_8_0: res_pool = dce80_create_resource_pool( init_data->num_virtual_links, dc); 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 0257a900fe2b..f42a17d765e3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -708,3 +708,4 @@ void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream) "\tlink: %d\n", stream->link->link_index); } + diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index f50ef4255020..1d9c8e09c08b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -42,7 +42,7 @@ #include "inc/hw/dmcu.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.95" +#define DC_VER "3.2.99" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -1265,6 +1265,9 @@ void dc_unlock_memory_clock_frequency(struct dc *dc); void dc_lock_memory_clock_frequency(struct dc *dc); #endif + +bool dc_set_psr_allow_active(struct dc *dc, bool enable); + /******************************************************************************* * DSC Interfaces ******************************************************************************/ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dsc.h b/drivers/gpu/drm/amd/display/dc/dc_dsc.h index 3800340a5b4f..768ab38d41cf 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dsc.h @@ -51,6 +51,7 @@ struct dc_dsc_policy { int min_slice_height; // Must not be less than 8 uint32_t max_target_bpp; uint32_t min_target_bpp; + bool enable_dsc_when_not_needed; }; bool dc_dsc_parse_dsc_dpcd(const struct dc *dc, @@ -80,4 +81,6 @@ void dc_dsc_get_policy_for_timing(const struct dc_crtc_timing *timing, void dc_dsc_policy_set_max_target_bpp_limit(uint32_t limit); +void dc_dsc_policy_set_enable_dsc_when_not_needed(bool enable); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index d9888f316da6..c246af7c584b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -397,6 +397,8 @@ bool dc_enable_stereo( struct dc_stream_state *streams[], uint8_t stream_count); +/* Triggers multi-stream synchronization. */ +void dc_trigger_sync(struct dc *dc, struct dc_state *context); enum surface_update_type dc_check_update_surfaces_for_stream( struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 946ba929c6f6..aa8e0955db48 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -233,6 +233,7 @@ struct dc_panel_patch { unsigned int skip_scdc_overwrite; unsigned int delay_ignore_msa; unsigned int disable_fec; + unsigned int extra_t3_ms; }; struct dc_edid_caps { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h index a44effcda49f..e84d21605854 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h @@ -46,6 +46,8 @@ SR(BL1_PWM_USER_LEVEL), \ SR(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES), \ SR(DC_ABM1_HGLS_REG_READ_PROGRESS), \ + SR(DC_ABM1_ACE_OFFSET_SLOPE_0), \ + SR(DC_ABM1_ACE_THRES_12), \ SR(BIOS_SCRATCH_2) #define ABM_DCN10_REG_LIST(id)\ @@ -60,6 +62,8 @@ SRI(BL1_PWM_USER_LEVEL, ABM, id), \ SRI(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, ABM, id), \ SRI(DC_ABM1_HGLS_REG_READ_PROGRESS, ABM, id), \ + SRI(DC_ABM1_ACE_OFFSET_SLOPE_0, ABM, id), \ + SRI(DC_ABM1_ACE_THRES_12, ABM, id), \ NBIO_SR(BIOS_SCRATCH_2) #define ABM_DCN20_REG_LIST() \ @@ -74,10 +78,12 @@ SR(BL1_PWM_USER_LEVEL), \ SR(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES), \ SR(DC_ABM1_HGLS_REG_READ_PROGRESS), \ + SR(DC_ABM1_ACE_OFFSET_SLOPE_0), \ + SR(DC_ABM1_ACE_THRES_12), \ NBIO_SR(BIOS_SCRATCH_2) #if defined(CONFIG_DRM_AMD_DC_DCN3_0) -#define ABM_DCN301_REG_LIST(id)\ +#define ABM_DCN30_REG_LIST(id)\ ABM_COMMON_REG_LIST_DCE_BASE(), \ SRI(DC_ABM1_HG_SAMPLE_RATE, ABM, id), \ SRI(DC_ABM1_LS_SAMPLE_RATE, ABM, id), \ @@ -89,6 +95,8 @@ SRI(BL1_PWM_USER_LEVEL, ABM, id), \ SRI(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, ABM, id), \ SRI(DC_ABM1_HGLS_REG_READ_PROGRESS, ABM, id), \ + SRI(DC_ABM1_ACE_OFFSET_SLOPE_0, ABM, id), \ + SRI(DC_ABM1_ACE_THRES_12, ABM, id), \ NBIO_SR(BIOS_SCRATCH_2) #endif @@ -208,6 +216,8 @@ struct dce_abm_registers { uint32_t BL1_PWM_USER_LEVEL; uint32_t DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES; uint32_t DC_ABM1_HGLS_REG_READ_PROGRESS; + uint32_t DC_ABM1_ACE_OFFSET_SLOPE_0; + uint32_t DC_ABM1_ACE_THRES_12; uint32_t MASTER_COMM_CNTL_REG; uint32_t MASTER_COMM_CMD_REG; uint32_t MASTER_COMM_DATA_REG1; 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 408046579712..2a2a0fdb9253 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -867,6 +867,98 @@ void dce_aud_wall_dto_setup( } } +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_aud_wall_dto_setup( + struct audio *audio, + enum signal_type signal, + const struct audio_crtc_info *crtc_info, + const struct audio_pll_info *pll_info) +{ + struct dce_audio *aud = DCE_AUD(audio); + + struct azalia_clock_info clock_info = { 0 }; + + if (dc_is_hdmi_signal(signal)) { + uint32_t src_sel; + + /*DTO0 Programming goal: + -generate 24MHz, 128*Fs from 24MHz + -use DTO0 when an active HDMI port is connected + (optionally a DP is connected) */ + + /* calculate DTO settings */ + get_azalia_clock_info_hdmi( + crtc_info->requested_pixel_clock_100Hz, + crtc_info->calculated_pixel_clock_100Hz, + &clock_info); + + DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock_100Hz = %d"\ + "calculated_pixel_clock_100Hz =%d\n"\ + "audio_dto_module = %d audio_dto_phase =%d \n\n", __func__,\ + crtc_info->requested_pixel_clock_100Hz,\ + crtc_info->calculated_pixel_clock_100Hz,\ + clock_info.audio_dto_module,\ + clock_info.audio_dto_phase); + + /* On TN/SI, Program DTO source select and DTO select before + programming DTO modulo and DTO phase. These bits must be + programmed first, otherwise there will be no HDMI audio at boot + up. This is a HW sequence change (different from old ASICs). + Caution when changing this programming sequence. + + HDMI enabled, using DTO0 + program master CRTC for DTO0 */ + src_sel = pll_info->dto_source - DTO_SOURCE_ID0; + REG_UPDATE_2(DCCG_AUDIO_DTO_SOURCE, + DCCG_AUDIO_DTO0_SOURCE_SEL, src_sel, + DCCG_AUDIO_DTO_SEL, 0); + + /* module */ + REG_UPDATE(DCCG_AUDIO_DTO0_MODULE, + DCCG_AUDIO_DTO0_MODULE, clock_info.audio_dto_module); + + /* phase */ + REG_UPDATE(DCCG_AUDIO_DTO0_PHASE, + DCCG_AUDIO_DTO0_PHASE, clock_info.audio_dto_phase); + } else { + /*DTO1 Programming goal: + -generate 24MHz, 128*Fs from 24MHz (DCE6 does not support 512*Fs) + -default is to used DTO1, and switch to DTO0 when an audio + master HDMI port is connected + -use as default for DP + + calculate DTO settings */ + get_azalia_clock_info_dp( + crtc_info->requested_pixel_clock_100Hz, + pll_info, + &clock_info); + + /* Program DTO select before programming DTO modulo and DTO + phase. default to use DTO1 */ + + REG_UPDATE(DCCG_AUDIO_DTO_SOURCE, + DCCG_AUDIO_DTO_SEL, 1); + + /* DCCG_AUDIO_DTO2_USE_512FBR_DTO, 1) + * Cannot select 512fs for DP + * + * DCE6 has no DCCG_AUDIO_DTO2_USE_512FBR_DTO mask + */ + + /* module */ + REG_UPDATE(DCCG_AUDIO_DTO1_MODULE, + DCCG_AUDIO_DTO1_MODULE, clock_info.audio_dto_module); + + /* phase */ + REG_UPDATE(DCCG_AUDIO_DTO1_PHASE, + DCCG_AUDIO_DTO1_PHASE, clock_info.audio_dto_phase); + + /* DCE6 has no DCCG_AUDIO_DTO2_USE_512FBR_DTO mask in DCCG_AUDIO_DTO_SOURCE reg */ + + } +} +#endif + static bool dce_aud_endpoint_valid(struct audio *audio) { uint32_t value; @@ -926,6 +1018,19 @@ static const struct audio_funcs funcs = { .az_configure = dce_aud_az_configure, .destroy = dce_aud_destroy, }; + +#if defined(CONFIG_DRM_AMD_DC_SI) +static const struct audio_funcs dce60_funcs = { + .endpoint_valid = dce_aud_endpoint_valid, + .hw_init = dce_aud_hw_init, + .wall_dto_setup = dce60_aud_wall_dto_setup, + .az_enable = dce_aud_az_enable, + .az_disable = dce_aud_az_disable, + .az_configure = dce_aud_az_configure, + .destroy = dce_aud_destroy, +}; +#endif + void dce_aud_destroy(struct audio **audio) { struct dce_audio *aud = DCE_AUD(*audio); @@ -959,3 +1064,29 @@ struct audio *dce_audio_create( return &audio->base; } +#if defined(CONFIG_DRM_AMD_DC_SI) +struct audio *dce60_audio_create( + struct dc_context *ctx, + unsigned int inst, + const struct dce_audio_registers *reg, + const struct dce_audio_shift *shifts, + const struct dce_audio_mask *masks + ) +{ + struct dce_audio *audio = kzalloc(sizeof(*audio), GFP_KERNEL); + + if (audio == NULL) { + ASSERT_CRITICAL(audio); + return NULL; + } + + audio->base.ctx = ctx; + audio->base.inst = inst; + audio->base.funcs = &dce60_funcs; + + audio->regs = reg; + audio->shifts = shifts; + audio->masks = masks; + return &audio->base; +} +#endif 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 1392fab0860b..5622d5e32d81 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h @@ -64,6 +64,20 @@ SF(AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ SF(AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define AUD_DCE60_MASK_SH_LIST(mask_sh)\ + SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL, mask_sh),\ + SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, mask_sh),\ + SF(DCCG_AUDIO_DTO0_MODULE, DCCG_AUDIO_DTO0_MODULE, mask_sh),\ + SF(DCCG_AUDIO_DTO0_PHASE, DCCG_AUDIO_DTO0_PHASE, mask_sh),\ + SF(DCCG_AUDIO_DTO1_MODULE, DCCG_AUDIO_DTO1_MODULE, mask_sh),\ + SF(DCCG_AUDIO_DTO1_PHASE, DCCG_AUDIO_DTO1_PHASE, mask_sh),\ + SF(AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES, AUDIO_RATE_CAPABILITIES, mask_sh),\ + SF(AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES, CLKSTOP, mask_sh),\ + SF(AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES, EPSS, mask_sh), \ + SF(AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh) +#endif struct dce_audio_registers { uint32_t AZALIA_F0_CODEC_ENDPOINT_INDEX; @@ -135,6 +149,15 @@ struct audio *dce_audio_create( const struct dce_audio_shift *shifts, const struct dce_audio_mask *masks); +#if defined(CONFIG_DRM_AMD_DC_SI) +struct audio *dce60_audio_create( + struct dc_context *ctx, + unsigned int inst, + const struct dce_audio_registers *reg, + const struct dce_audio_shift *shifts, + const struct dce_audio_mask *masks); +#endif + void dce_aud_destroy(struct audio **audio); void dce_aud_hw_init(struct audio *audio); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h index 5e044c2d3d6d..93e7f34d4775 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h @@ -46,6 +46,24 @@ SR(SMU_INTERRUPT_CONTROL), \ SR(DC_DMCU_SCRATCH) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define DMCU_DCE60_REG_LIST() \ + SR(DMCU_CTRL), \ + SR(DMCU_STATUS), \ + SR(DMCU_RAM_ACCESS_CTRL), \ + SR(DMCU_IRAM_WR_CTRL), \ + SR(DMCU_IRAM_WR_DATA), \ + SR(MASTER_COMM_DATA_REG1), \ + SR(MASTER_COMM_DATA_REG2), \ + SR(MASTER_COMM_DATA_REG3), \ + SR(MASTER_COMM_CMD_REG), \ + SR(MASTER_COMM_CNTL_REG), \ + SR(DMCU_IRAM_RD_CTRL), \ + SR(DMCU_IRAM_RD_DATA), \ + SR(DMCU_INTERRUPT_TO_UC_EN_MASK), \ + SR(DC_DMCU_SCRATCH) +#endif + #define DMCU_DCE80_REG_LIST() \ SR(DMCU_CTRL), \ SR(DMCU_STATUS), \ @@ -104,6 +122,25 @@ STATIC_SCREEN4_INT_TO_UC_EN, mask_sh), \ DMCU_SF(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define DMCU_MASK_SH_LIST_DCE60(mask_sh) \ + DMCU_SF(DMCU_CTRL, \ + DMCU_ENABLE, mask_sh), \ + DMCU_SF(DMCU_STATUS, \ + UC_IN_STOP_MODE, mask_sh), \ + DMCU_SF(DMCU_STATUS, \ + UC_IN_RESET, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_HOST_ACCESS_EN, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_WR_ADDR_AUTO_INC, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_RD_ADDR_AUTO_INC, mask_sh), \ + DMCU_SF(MASTER_COMM_CMD_REG, \ + MASTER_COMM_CMD_REG_BYTE0, mask_sh), \ + DMCU_SF(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, mask_sh) +#endif + #define DMCU_MASK_SH_LIST_DCE80(mask_sh) \ DMCU_SF(DMCU_CTRL, \ DMCU_ENABLE, mask_sh), \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c index e1c5839a80dc..4202fadb2c0e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c @@ -85,6 +85,15 @@ void dce_pipe_control_lock(struct dc *dc, } } +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_pipe_control_lock(struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + /* DCE6 has no BLND_V_UPDATE_LOCK register */ +} +#endif + void dce_set_blender_mode(struct dce_hwseq *hws, unsigned int blnd_inst, enum blnd_mode mode) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 66b88d6ba398..70bbc1311327 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -110,6 +110,12 @@ SR(BLNDV_CONTROL),\ HWSEQ_PIXEL_RATE_REG_LIST(CRTC) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define HWSEQ_DCE6_REG_LIST() \ + HWSEQ_DCEF_REG_LIST_DCE8(), \ + HWSEQ_PIXEL_RATE_REG_LIST(CRTC) +#endif + #define HWSEQ_DCE8_REG_LIST() \ HWSEQ_DCEF_REG_LIST_DCE8(), \ HWSEQ_BLND_REG_LIST(), \ @@ -488,6 +494,12 @@ struct dce_hwseq_registers { HWS_SF1(blk, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh),\ HWS_SF1(blk, PHYPLL_PIXEL_RATE_CNTL, PIXEL_RATE_PLL_SOURCE, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define HWSEQ_DCE6_MASK_SH_LIST(mask_sh)\ + .DCFE_CLOCK_ENABLE = CRTC_DCFE_CLOCK_CONTROL__CRTC_DCFE_CLOCK_ENABLE ## mask_sh, \ + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) +#endif + #define HWSEQ_DCE8_MASK_SH_LIST(mask_sh)\ .DCFE_CLOCK_ENABLE = CRTC_DCFE_CLOCK_CONTROL__CRTC_DCFE_CLOCK_ENABLE ## mask_sh, \ HWS_SF(BLND_, V_UPDATE_LOCK, BLND_DCP_GRPH_V_UPDATE_LOCK, mask_sh),\ @@ -836,6 +848,12 @@ void dce_pipe_control_lock(struct dc *dc, void dce_set_blender_mode(struct dce_hwseq *hws, unsigned int blnd_inst, enum blnd_mode mode); +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_pipe_control_lock(struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +#endif + void dce_clock_gating_power_up(struct dce_hwseq *hws, bool enable); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c b/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c index ce30dbf579d4..80569a2734eb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c @@ -231,6 +231,22 @@ static void dce_ipp_set_degamma( CURSOR2_DEGAMMA_MODE, degamma_type); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_ipp_set_degamma( + struct input_pixel_processor *ipp, + enum ipp_degamma_mode mode) +{ + struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp); + uint32_t degamma_type = (mode == IPP_DEGAMMA_MODE_HW_sRGB) ? 1 : 0; + + ASSERT(mode == IPP_DEGAMMA_MODE_BYPASS || mode == IPP_DEGAMMA_MODE_HW_sRGB); + /* DCE6 does not have CURSOR2_DEGAMMA_MODE bit in DEGAMMA_CONTROL reg */ + REG_SET_2(DEGAMMA_CONTROL, 0, + GRPH_DEGAMMA_MODE, degamma_type, + CURSOR_DEGAMMA_MODE, degamma_type); +} +#endif + static const struct ipp_funcs dce_ipp_funcs = { .ipp_cursor_set_attributes = dce_ipp_cursor_set_attributes, .ipp_cursor_set_position = dce_ipp_cursor_set_position, @@ -239,6 +255,17 @@ static const struct ipp_funcs dce_ipp_funcs = { .ipp_set_degamma = dce_ipp_set_degamma }; +#if defined(CONFIG_DRM_AMD_DC_SI) +static const struct ipp_funcs dce60_ipp_funcs = { + .ipp_cursor_set_attributes = dce_ipp_cursor_set_attributes, + .ipp_cursor_set_position = dce_ipp_cursor_set_position, + .ipp_program_prescale = dce_ipp_program_prescale, + .ipp_program_input_lut = dce_ipp_program_input_lut, + .ipp_set_degamma = dce60_ipp_set_degamma +}; +#endif + + /*****************************************/ /* Constructor, Destructor */ /*****************************************/ @@ -260,6 +287,25 @@ void dce_ipp_construct( ipp_dce->ipp_mask = ipp_mask; } +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_ipp_construct( + struct dce_ipp *ipp_dce, + struct dc_context *ctx, + int inst, + const struct dce_ipp_registers *regs, + const struct dce_ipp_shift *ipp_shift, + const struct dce_ipp_mask *ipp_mask) +{ + ipp_dce->base.ctx = ctx; + ipp_dce->base.inst = inst; + ipp_dce->base.funcs = &dce60_ipp_funcs; + + ipp_dce->regs = regs; + ipp_dce->ipp_shift = ipp_shift; + ipp_dce->ipp_mask = ipp_mask; +} +#endif + void dce_ipp_destroy(struct input_pixel_processor **ipp) { kfree(TO_DCE_IPP(*ipp)); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.h b/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.h index ca04e97d44c3..0028d4bdd81b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.h @@ -147,6 +147,46 @@ IPP_SF(DCP0_DEGAMMA_CONTROL, CURSOR_DEGAMMA_MODE, mask_sh), \ IPP_SF(DCP0_DEGAMMA_CONTROL, CURSOR2_DEGAMMA_MODE, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define IPP_DCE60_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh) \ + IPP_SF(CUR_UPDATE, CURSOR_UPDATE_LOCK, mask_sh), \ + IPP_SF(CUR_CONTROL, CURSOR_EN, mask_sh), \ + IPP_SF(CUR_CONTROL, CURSOR_MODE, mask_sh), \ + IPP_SF(CUR_CONTROL, CURSOR_2X_MAGNIFY, mask_sh), \ + IPP_SF(CUR_CONTROL, CUR_INV_TRANS_CLAMP, mask_sh), \ + IPP_SF(CUR_POSITION, CURSOR_X_POSITION, mask_sh), \ + IPP_SF(CUR_POSITION, CURSOR_Y_POSITION, mask_sh), \ + IPP_SF(CUR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ + IPP_SF(CUR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ + IPP_SF(CUR_COLOR1, CUR_COLOR1_BLUE, mask_sh), \ + IPP_SF(CUR_COLOR1, CUR_COLOR1_GREEN, mask_sh), \ + IPP_SF(CUR_COLOR1, CUR_COLOR1_RED, mask_sh), \ + IPP_SF(CUR_COLOR2, CUR_COLOR2_BLUE, mask_sh), \ + IPP_SF(CUR_COLOR2, CUR_COLOR2_GREEN, mask_sh), \ + IPP_SF(CUR_COLOR2, CUR_COLOR2_RED, mask_sh), \ + IPP_SF(CUR_SIZE, CURSOR_WIDTH, mask_sh), \ + IPP_SF(CUR_SIZE, CURSOR_HEIGHT, mask_sh), \ + IPP_SF(CUR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, mask_sh), \ + IPP_SF(CUR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, mask_sh), \ + IPP_SF(PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_BYPASS, mask_sh), \ + IPP_SF(PRESCALE_VALUES_GRPH_R, GRPH_PRESCALE_SCALE_R, mask_sh), \ + IPP_SF(PRESCALE_VALUES_GRPH_R, GRPH_PRESCALE_BIAS_R, mask_sh), \ + IPP_SF(PRESCALE_VALUES_GRPH_G, GRPH_PRESCALE_SCALE_G, mask_sh), \ + IPP_SF(PRESCALE_VALUES_GRPH_G, GRPH_PRESCALE_BIAS_G, mask_sh), \ + IPP_SF(PRESCALE_VALUES_GRPH_B, GRPH_PRESCALE_SCALE_B, mask_sh), \ + IPP_SF(PRESCALE_VALUES_GRPH_B, GRPH_PRESCALE_BIAS_B, mask_sh), \ + IPP_SF(INPUT_GAMMA_CONTROL, GRPH_INPUT_GAMMA_MODE, mask_sh), \ + IPP_SF(DC_LUT_WRITE_EN_MASK, DC_LUT_WRITE_EN_MASK, mask_sh), \ + IPP_SF(DC_LUT_RW_MODE, DC_LUT_RW_MODE, mask_sh), \ + IPP_SF(DC_LUT_CONTROL, DC_LUT_DATA_R_FORMAT, mask_sh), \ + IPP_SF(DC_LUT_CONTROL, DC_LUT_DATA_G_FORMAT, mask_sh), \ + IPP_SF(DC_LUT_CONTROL, DC_LUT_DATA_B_FORMAT, mask_sh), \ + IPP_SF(DC_LUT_RW_INDEX, DC_LUT_RW_INDEX, mask_sh), \ + IPP_SF(DC_LUT_SEQ_COLOR, DC_LUT_SEQ_COLOR, mask_sh), \ + IPP_SF(DEGAMMA_CONTROL, GRPH_DEGAMMA_MODE, mask_sh), \ + IPP_SF(DEGAMMA_CONTROL, CURSOR_DEGAMMA_MODE, mask_sh) +#endif + #define IPP_REG_FIELD_LIST(type) \ type CURSOR_UPDATE_LOCK; \ type CURSOR_EN; \ @@ -233,6 +273,15 @@ void dce_ipp_construct(struct dce_ipp *ipp_dce, const struct dce_ipp_shift *ipp_shift, const struct dce_ipp_mask *ipp_mask); +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_ipp_construct(struct dce_ipp *ipp_dce, + struct dc_context *ctx, + int inst, + const struct dce_ipp_registers *regs, + const struct dce_ipp_shift *ipp_shift, + const struct dce_ipp_mask *ipp_mask); +#endif + void dce_ipp_destroy(struct input_pixel_processor **ipp); #endif /* _DCE_IPP_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 8d8c84c81b34..b409f6b2bfd8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -425,6 +425,59 @@ static void set_dp_phy_pattern_hbr2_compliance_cp2520_2( enable_phy_bypass_mode(enc110, false); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_set_dp_phy_pattern_hbr2_compliance_cp2520_2( + struct dce110_link_encoder *enc110, + unsigned int cp2520_pattern) +{ + + /* previously there is a register DP_HBR2_EYE_PATTERN + * that is enabled to get the pattern. + * But it does not work with the latest spec change, + * so we are programming the following registers manually. + * + * The following settings have been confirmed + * by Nick Chorney and Sandra Liu */ + + /* Disable PHY Bypass mode to setup the test pattern */ + + enable_phy_bypass_mode(enc110, false); + + /* Setup DIG encoder in DP SST mode */ + enc110->base.funcs->setup(&enc110->base, SIGNAL_TYPE_DISPLAY_PORT); + + /* ensure normal panel mode. */ + setup_panel_mode(enc110, DP_PANEL_MODE_DEFAULT); + + /* no vbid after BS (SR) + * DP_LINK_FRAMING_CNTL changed history Sandra Liu + * 11000260 / 11000104 / 110000FC */ + REG_UPDATE_3(DP_LINK_FRAMING_CNTL, + DP_IDLE_BS_INTERVAL, 0xFC, + DP_VBID_DISABLE, 1, + DP_VID_ENHANCED_FRAME_MODE, 1); + + /* DCE6 has no DP_DPHY_SCRAM_CNTL register, skip swap BS with SR */ + + /* select cp2520 patterns */ + if (REG(DP_DPHY_HBR2_PATTERN_CONTROL)) + REG_UPDATE(DP_DPHY_HBR2_PATTERN_CONTROL, + DP_DPHY_HBR2_PATTERN_CONTROL, cp2520_pattern); + else + /* pre-DCE11 can only generate CP2520 pattern 2 */ + ASSERT(cp2520_pattern == 2); + + /* set link training complete */ + set_link_training_complete(enc110, true); + + /* disable video stream */ + REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0); + + /* Disable PHY Bypass mode to setup the test pattern */ + enable_phy_bypass_mode(enc110, false); +} +#endif + static void set_dp_phy_pattern_passthrough_mode( struct dce110_link_encoder *enc110, enum dp_panel_mode panel_mode) @@ -452,6 +505,35 @@ static void set_dp_phy_pattern_passthrough_mode( disable_prbs_mode(enc110); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_set_dp_phy_pattern_passthrough_mode( + struct dce110_link_encoder *enc110, + enum dp_panel_mode panel_mode) +{ + /* program correct panel mode */ + setup_panel_mode(enc110, panel_mode); + + /* restore LINK_FRAMING_CNTL + * in case we were doing HBR2 compliance pattern before + */ + REG_UPDATE_3(DP_LINK_FRAMING_CNTL, + DP_IDLE_BS_INTERVAL, 0x2000, + DP_VBID_DISABLE, 0, + DP_VID_ENHANCED_FRAME_MODE, 1); + + /* DCE6 has no DP_DPHY_SCRAM_CNTL register, skip DPHY_SCRAMBLER_BS_COUNT restore */ + + /* set link training complete */ + set_link_training_complete(enc110, true); + + /* Disable PHY Bypass mode to setup the test pattern */ + enable_phy_bypass_mode(enc110, false); + + /* Disable PRBS mode */ + disable_prbs_mode(enc110); +} +#endif + /* return value is bit-vector */ static uint8_t get_frontend_source( enum engine_id engine) @@ -490,6 +572,20 @@ static void configure_encoder( REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_ADVANCE, 1); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_configure_encoder( + struct dce110_link_encoder *enc110, + const struct dc_link_settings *link_settings) +{ + /* set number of lanes */ + + REG_SET(DP_CONFIG, 0, + DP_UDI_LANES, link_settings->lane_count - LANE_COUNT_ONE); + + /* DCE6 has no DP_DPHY_SCRAM_CNTL register, skip setup scrambler */ +} +#endif + static void aux_initialize( struct dce110_link_encoder *enc110) { @@ -1059,6 +1155,87 @@ void dce110_link_encoder_enable_dp_mst_output( BREAK_TO_DEBUGGER(); } } + +#if defined(CONFIG_DRM_AMD_DC_SI) +/* enables DP PHY output */ +void dce60_link_encoder_enable_dp_output( + struct link_encoder *enc, + const struct dc_link_settings *link_settings, + enum clock_source_id clock_source) +{ + struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); + struct bp_transmitter_control cntl = { 0 }; + enum bp_result result; + + /* Enable the PHY */ + + /* number_of_lanes is used for pixel clock adjust, + * but it's not passed to asic_control. + * We need to set number of lanes manually. + */ + dce60_configure_encoder(enc110, link_settings); + cntl.connector_obj_id = enc110->base.connector; + cntl.action = TRANSMITTER_CONTROL_ENABLE; + cntl.engine_id = enc->preferred_engine; + cntl.transmitter = enc110->base.transmitter; + cntl.pll_id = clock_source; + cntl.signal = SIGNAL_TYPE_DISPLAY_PORT; + cntl.lanes_number = link_settings->lane_count; + cntl.hpd_sel = enc110->base.hpd_source; + cntl.pixel_clock = link_settings->link_rate + * LINK_RATE_REF_FREQ_IN_KHZ; + /* TODO: check if undefined works */ + cntl.color_depth = COLOR_DEPTH_UNDEFINED; + + result = link_transmitter_control(enc110, &cntl); + + if (result != BP_RESULT_OK) { + DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n", + __func__); + BREAK_TO_DEBUGGER(); + } +} + +/* enables DP PHY output in MST mode */ +void dce60_link_encoder_enable_dp_mst_output( + struct link_encoder *enc, + const struct dc_link_settings *link_settings, + enum clock_source_id clock_source) +{ + struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); + struct bp_transmitter_control cntl = { 0 }; + enum bp_result result; + + /* Enable the PHY */ + + /* number_of_lanes is used for pixel clock adjust, + * but it's not passed to asic_control. + * We need to set number of lanes manually. + */ + dce60_configure_encoder(enc110, link_settings); + + cntl.action = TRANSMITTER_CONTROL_ENABLE; + cntl.engine_id = ENGINE_ID_UNKNOWN; + cntl.transmitter = enc110->base.transmitter; + cntl.pll_id = clock_source; + cntl.signal = SIGNAL_TYPE_DISPLAY_PORT_MST; + cntl.lanes_number = link_settings->lane_count; + cntl.hpd_sel = enc110->base.hpd_source; + cntl.pixel_clock = link_settings->link_rate + * LINK_RATE_REF_FREQ_IN_KHZ; + /* TODO: check if undefined works */ + cntl.color_depth = COLOR_DEPTH_UNDEFINED; + + result = link_transmitter_control(enc110, &cntl); + + if (result != BP_RESULT_OK) { + DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n", + __func__); + BREAK_TO_DEBUGGER(); + } +} +#endif + /* * @brief * Disable transmitter and its encoder @@ -1208,6 +1385,63 @@ void dce110_link_encoder_dp_set_phy_pattern( } } +#if defined(CONFIG_DRM_AMD_DC_SI) +/* set DP PHY test and training patterns */ +void dce60_link_encoder_dp_set_phy_pattern( + struct link_encoder *enc, + const struct encoder_set_dp_phy_pattern_param *param) +{ + struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); + + switch (param->dp_phy_pattern) { + case DP_TEST_PATTERN_TRAINING_PATTERN1: + dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 0); + break; + case DP_TEST_PATTERN_TRAINING_PATTERN2: + dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 1); + break; + case DP_TEST_PATTERN_TRAINING_PATTERN3: + dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 2); + break; + case DP_TEST_PATTERN_TRAINING_PATTERN4: + dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 3); + break; + case DP_TEST_PATTERN_D102: + set_dp_phy_pattern_d102(enc110); + break; + case DP_TEST_PATTERN_SYMBOL_ERROR: + set_dp_phy_pattern_symbol_error(enc110); + break; + case DP_TEST_PATTERN_PRBS7: + set_dp_phy_pattern_prbs7(enc110); + break; + case DP_TEST_PATTERN_80BIT_CUSTOM: + set_dp_phy_pattern_80bit_custom( + enc110, param->custom_pattern); + break; + case DP_TEST_PATTERN_CP2520_1: + dce60_set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 1); + break; + case DP_TEST_PATTERN_CP2520_2: + dce60_set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 2); + break; + case DP_TEST_PATTERN_CP2520_3: + dce60_set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 3); + break; + case DP_TEST_PATTERN_VIDEO_MODE: { + dce60_set_dp_phy_pattern_passthrough_mode( + enc110, param->dp_panel_mode); + break; + } + + default: + /* invalid phy pattern */ + ASSERT_CRITICAL(false); + break; + } +} +#endif + static void fill_stream_allocation_row_info( const struct link_mst_stream_allocation *stream_allocation, uint32_t *src, @@ -1407,3 +1641,138 @@ void dce110_link_encoder_get_max_link_cap(struct link_encoder *enc, *link_settings = max_link_cap; } + +#if defined(CONFIG_DRM_AMD_DC_SI) +static const struct link_encoder_funcs dce60_lnk_enc_funcs = { + .validate_output_with_stream = + dce110_link_encoder_validate_output_with_stream, + .hw_init = dce110_link_encoder_hw_init, + .setup = dce110_link_encoder_setup, + .enable_tmds_output = dce110_link_encoder_enable_tmds_output, + .enable_dp_output = dce60_link_encoder_enable_dp_output, + .enable_dp_mst_output = dce60_link_encoder_enable_dp_mst_output, + .enable_lvds_output = dce110_link_encoder_enable_lvds_output, + .disable_output = dce110_link_encoder_disable_output, + .dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings, + .dp_set_phy_pattern = dce60_link_encoder_dp_set_phy_pattern, + .update_mst_stream_allocation_table = + dce110_link_encoder_update_mst_stream_allocation_table, + .psr_program_dp_dphy_fast_training = + dce110_psr_program_dp_dphy_fast_training, + .psr_program_secondary_packet = dce110_psr_program_secondary_packet, + .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe, + .enable_hpd = dce110_link_encoder_enable_hpd, + .disable_hpd = dce110_link_encoder_disable_hpd, + .is_dig_enabled = dce110_is_dig_enabled, + .destroy = dce110_link_encoder_destroy, + .get_max_link_cap = dce110_link_encoder_get_max_link_cap +}; + +void dce60_link_encoder_construct( + struct dce110_link_encoder *enc110, + const struct encoder_init_data *init_data, + const struct encoder_feature_support *enc_features, + const struct dce110_link_enc_registers *link_regs, + const struct dce110_link_enc_aux_registers *aux_regs, + const struct dce110_link_enc_hpd_registers *hpd_regs) +{ + struct bp_encoder_cap_info bp_cap_info = {0}; + const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; + enum bp_result result = BP_RESULT_OK; + + enc110->base.funcs = &dce60_lnk_enc_funcs; + enc110->base.ctx = init_data->ctx; + enc110->base.id = init_data->encoder; + + enc110->base.hpd_source = init_data->hpd_source; + enc110->base.connector = init_data->connector; + + enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; + + enc110->base.features = *enc_features; + + enc110->base.transmitter = init_data->transmitter; + + /* set the flag to indicate whether driver poll the I2C data pin + * while doing the DP sink detect + */ + +/* if (dal_adapter_service_is_feature_supported(as, + FEATURE_DP_SINK_DETECT_POLL_DATA_PIN)) + enc110->base.features.flags.bits. + DP_SINK_DETECT_POLL_DATA_PIN = true;*/ + + enc110->base.output_signals = + SIGNAL_TYPE_DVI_SINGLE_LINK | + SIGNAL_TYPE_DVI_DUAL_LINK | + SIGNAL_TYPE_LVDS | + SIGNAL_TYPE_DISPLAY_PORT | + SIGNAL_TYPE_DISPLAY_PORT_MST | + SIGNAL_TYPE_EDP | + SIGNAL_TYPE_HDMI_TYPE_A; + + /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE. + * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY. + * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer + * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS. + * Prefer DIG assignment is decided by board design. + * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design + * and VBIOS will filter out 7 UNIPHY for DCE 8.0. + * By this, adding DIGG should not hurt DCE 8.0. + * This will let DCE 8.1 share DCE 8.0 as much as possible + */ + + enc110->link_regs = link_regs; + enc110->aux_regs = aux_regs; + enc110->hpd_regs = hpd_regs; + + switch (enc110->base.transmitter) { + case TRANSMITTER_UNIPHY_A: + enc110->base.preferred_engine = ENGINE_ID_DIGA; + break; + case TRANSMITTER_UNIPHY_B: + enc110->base.preferred_engine = ENGINE_ID_DIGB; + break; + case TRANSMITTER_UNIPHY_C: + enc110->base.preferred_engine = ENGINE_ID_DIGC; + break; + case TRANSMITTER_UNIPHY_D: + enc110->base.preferred_engine = ENGINE_ID_DIGD; + break; + case TRANSMITTER_UNIPHY_E: + enc110->base.preferred_engine = ENGINE_ID_DIGE; + break; + case TRANSMITTER_UNIPHY_F: + enc110->base.preferred_engine = ENGINE_ID_DIGF; + break; + case TRANSMITTER_UNIPHY_G: + enc110->base.preferred_engine = ENGINE_ID_DIGG; + break; + default: + ASSERT_CRITICAL(false); + enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; + } + + /* default to one to mirror Windows behavior */ + enc110->base.features.flags.bits.HDMI_6GB_EN = 1; + + result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios, + enc110->base.id, &bp_cap_info); + + /* Override features with DCE-specific values */ + if (BP_RESULT_OK == result) { + enc110->base.features.flags.bits.IS_HBR2_CAPABLE = + bp_cap_info.DP_HBR2_EN; + enc110->base.features.flags.bits.IS_HBR3_CAPABLE = + bp_cap_info.DP_HBR3_EN; + enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; + } else { + DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", + __func__, + result); + } + if (enc110->base.ctx->dc->debug.hdmi20_disable) { + enc110->base.features.flags.bits.HDMI_6GB_EN = 0; + } +} +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h index 66027d496778..cb714a48b171 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h @@ -76,6 +76,34 @@ SRI(DP_DPHY_INTERNAL_CTRL, DP, id), \ SR(DCI_MEM_PWR_STATUS) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define LE_DCE60_REG_LIST(id)\ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id), \ + SR(DMCU_RAM_ACCESS_CTRL), \ + SR(DMCU_IRAM_RD_CTRL), \ + SR(DMCU_IRAM_RD_DATA), \ + SR(DMCU_INTERRUPT_TO_UC_EN_MASK), \ + SRI(DIG_BE_CNTL, DIG, id), \ + SRI(DIG_BE_EN_CNTL, DIG, id), \ + SRI(DP_CONFIG, DP, id), \ + SRI(DP_DPHY_CNTL, DP, id), \ + SRI(DP_DPHY_PRBS_CNTL, DP, id), \ + SRI(DP_DPHY_SYM0, DP, id), \ + SRI(DP_DPHY_SYM1, DP, id), \ + SRI(DP_DPHY_SYM2, DP, id), \ + SRI(DP_DPHY_TRAINING_PATTERN_SEL, DP, id), \ + SRI(DP_LINK_CNTL, DP, id), \ + SRI(DP_LINK_FRAMING_CNTL, DP, id), \ + SRI(DP_MSE_SAT0, DP, id), \ + SRI(DP_MSE_SAT1, DP, id), \ + SRI(DP_MSE_SAT2, DP, id), \ + SRI(DP_MSE_SAT_UPDATE, DP, id), \ + SRI(DP_SEC_CNTL, DP, id), \ + SRI(DP_VID_STREAM_CNTL, DP, id), \ + SRI(DP_DPHY_FAST_TRAINING, DP, id), \ + SRI(DP_SEC_CNTL1, DP, id) +#endif + #define LE_DCE80_REG_LIST(id)\ SRI(DP_DPHY_INTERNAL_CTRL, DP, id), \ LE_COMMON_REG_LIST_BASE(id) @@ -171,6 +199,16 @@ void dce110_link_encoder_construct( const struct dce110_link_enc_aux_registers *aux_regs, const struct dce110_link_enc_hpd_registers *hpd_regs); +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_link_encoder_construct( + struct dce110_link_encoder *enc110, + const struct encoder_init_data *init_data, + const struct encoder_feature_support *enc_features, + const struct dce110_link_enc_registers *link_regs, + const struct dce110_link_enc_aux_registers *aux_regs, + const struct dce110_link_enc_hpd_registers *hpd_regs); +#endif + bool dce110_link_encoder_validate_dvi_output( const struct dce110_link_encoder *enc110, enum signal_type connector_signal, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c index 51481e922eb9..79a6f261a0da 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c @@ -174,6 +174,22 @@ static void program_urgency_watermark( URGENCY_HIGH_WATERMARK, urgency_high_wm); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_program_urgency_watermark( + struct dce_mem_input *dce_mi, + uint32_t wm_select, + uint32_t urgency_low_wm, + uint32_t urgency_high_wm) +{ + REG_UPDATE(DPG_PIPE_ARBITRATION_CONTROL3, + URGENCY_WATERMARK_MASK, wm_select); + + REG_SET_2(DPG_PIPE_URGENCY_CONTROL, 0, + URGENCY_LOW_WATERMARK, urgency_low_wm, + URGENCY_HIGH_WATERMARK, urgency_high_wm); +} +#endif + static void dce120_program_urgency_watermark( struct dce_mem_input *dce_mi, uint32_t wm_select, @@ -193,6 +209,25 @@ static void dce120_program_urgency_watermark( } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_program_nbp_watermark( + struct dce_mem_input *dce_mi, + uint32_t wm_select, + uint32_t nbp_wm) +{ + REG_UPDATE(DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, + NB_PSTATE_CHANGE_WATERMARK_MASK, wm_select); + + REG_UPDATE_3(DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, + NB_PSTATE_CHANGE_ENABLE, 1, + NB_PSTATE_CHANGE_URGENT_DURING_REQUEST, 1, + NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST, 1); + + REG_UPDATE(DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, + NB_PSTATE_CHANGE_WATERMARK, nbp_wm); +} +#endif + static void program_nbp_watermark( struct dce_mem_input *dce_mi, uint32_t wm_select, @@ -225,6 +260,20 @@ static void program_nbp_watermark( } } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_program_stutter_watermark( + struct dce_mem_input *dce_mi, + uint32_t wm_select, + uint32_t stutter_mark) +{ + REG_UPDATE(DPG_PIPE_STUTTER_CONTROL, + STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK, wm_select); + + REG_UPDATE(DPG_PIPE_STUTTER_CONTROL, + STUTTER_EXIT_SELF_REFRESH_WATERMARK, stutter_mark); +} +#endif + static void dce120_program_stutter_watermark( struct dce_mem_input *dce_mi, uint32_t wm_select, @@ -286,6 +335,34 @@ static void dce_mi_program_display_marks( program_stutter_watermark(dce_mi, 1, stutter_exit.d_mark); /* set d */ } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_mi_program_display_marks( + struct mem_input *mi, + struct dce_watermarks nbp, + struct dce_watermarks stutter_exit, + struct dce_watermarks stutter_enter, + struct dce_watermarks urgent, + uint32_t total_dest_line_time_ns) +{ + struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi); + uint32_t stutter_en = mi->ctx->dc->debug.disable_stutter ? 0 : 1; + + dce60_program_urgency_watermark(dce_mi, 2, /* set a */ + urgent.a_mark, total_dest_line_time_ns); + dce60_program_urgency_watermark(dce_mi, 1, /* set d */ + urgent.d_mark, total_dest_line_time_ns); + + REG_UPDATE_2(DPG_PIPE_STUTTER_CONTROL, + STUTTER_ENABLE, stutter_en, + STUTTER_IGNORE_FBC, 1); + dce60_program_nbp_watermark(dce_mi, 2, nbp.a_mark); /* set a */ + dce60_program_nbp_watermark(dce_mi, 1, nbp.d_mark); /* set d */ + + dce60_program_stutter_watermark(dce_mi, 2, stutter_exit.a_mark); /* set a */ + dce60_program_stutter_watermark(dce_mi, 1, stutter_exit.d_mark); /* set d */ +} +#endif + static void dce112_mi_program_display_marks(struct mem_input *mi, struct dce_watermarks nbp, struct dce_watermarks stutter_exit, @@ -369,7 +446,7 @@ static void program_tiling( */ } - if (dce_mi->masks->GRPH_ARRAY_MODE) { /* GFX8 */ + if (dce_mi->masks->GRPH_MICRO_TILE_MODE) { /* GFX8 */ REG_UPDATE_9(GRPH_CONTROL, GRPH_NUM_BANKS, info->gfx8.num_banks, GRPH_BANK_WIDTH, info->gfx8.bank_width, @@ -385,6 +462,23 @@ static void program_tiling( GRPH_Z, 0); */ } + + if (dce_mi->masks->GRPH_ARRAY_MODE) { /* GFX6 but reuses gfx8 struct */ + REG_UPDATE_8(GRPH_CONTROL, + GRPH_NUM_BANKS, info->gfx8.num_banks, + GRPH_BANK_WIDTH, info->gfx8.bank_width, + GRPH_BANK_HEIGHT, info->gfx8.bank_height, + GRPH_MACRO_TILE_ASPECT, info->gfx8.tile_aspect, + GRPH_TILE_SPLIT, info->gfx8.tile_split, + /* DCE6 has no GRPH_MICRO_TILE_MODE mask */ + GRPH_PIPE_CONFIG, info->gfx8.pipe_config, + GRPH_ARRAY_MODE, info->gfx8.array_mode, + GRPH_COLOR_EXPANSION_MODE, 1); + /* 01 - DCP_GRPH_COLOR_EXPANSION_MODE_ZEXP: zero expansion for YCbCr */ + /* + GRPH_Z, 0); + */ + } } @@ -429,6 +523,36 @@ static void program_size_and_rotation( GRPH_ROTATION_ANGLE, rotation_angles[rotation]); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_program_size( + struct dce_mem_input *dce_mi, + enum dc_rotation_angle rotation, /* not used in DCE6 */ + const struct plane_size *plane_size) +{ + struct rect hw_rect = plane_size->surface_size; + /* DCE6 has no HW rotation, skip rotation_angles declaration */ + + /* DCE6 has no HW rotation, skip ROTATION_ANGLE_* processing */ + + REG_SET(GRPH_X_START, 0, + GRPH_X_START, hw_rect.x); + + REG_SET(GRPH_Y_START, 0, + GRPH_Y_START, hw_rect.y); + + REG_SET(GRPH_X_END, 0, + GRPH_X_END, hw_rect.width); + + REG_SET(GRPH_Y_END, 0, + GRPH_Y_END, hw_rect.height); + + REG_SET(GRPH_PITCH, 0, + GRPH_PITCH, plane_size->surface_pitch); + + /* DCE6 has no HW_ROTATION register, skip setting rotation_angles */ +} +#endif + static void program_grph_pixel_format( struct dce_mem_input *dce_mi, enum surface_pixel_format format) @@ -521,6 +645,28 @@ static void dce_mi_program_surface_config( program_grph_pixel_format(dce_mi, format); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_mi_program_surface_config( + struct mem_input *mi, + enum surface_pixel_format format, + union dc_tiling_info *tiling_info, + struct plane_size *plane_size, + enum dc_rotation_angle rotation, /* not used in DCE6 */ + struct dc_plane_dcc_param *dcc, + bool horizontal_mirror) +{ + struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi); + REG_UPDATE(GRPH_ENABLE, GRPH_ENABLE, 1); + + program_tiling(dce_mi, tiling_info); + dce60_program_size(dce_mi, rotation, plane_size); + + if (format >= SURFACE_PIXEL_FORMAT_GRPH_BEGIN && + format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) + program_grph_pixel_format(dce_mi, format); +} +#endif + static uint32_t get_dmif_switch_time_us( uint32_t h_total, uint32_t v_total, @@ -741,6 +887,20 @@ static const struct mem_input_funcs dce_mi_funcs = { .mem_input_is_flip_pending = dce_mi_is_flip_pending }; +#if defined(CONFIG_DRM_AMD_DC_SI) +static const struct mem_input_funcs dce60_mi_funcs = { + .mem_input_program_display_marks = dce60_mi_program_display_marks, + .allocate_mem_input = dce_mi_allocate_dmif, + .free_mem_input = dce_mi_free_dmif, + .mem_input_program_surface_flip_and_addr = + dce_mi_program_surface_flip_and_addr, + .mem_input_program_pte_vm = dce_mi_program_pte_vm, + .mem_input_program_surface_config = + dce60_mi_program_surface_config, + .mem_input_is_flip_pending = dce_mi_is_flip_pending +}; +#endif + static const struct mem_input_funcs dce112_mi_funcs = { .mem_input_program_display_marks = dce112_mi_program_display_marks, .allocate_mem_input = dce_mi_allocate_dmif, @@ -783,6 +943,20 @@ void dce_mem_input_construct( dce_mi->masks = mi_mask; } +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_mem_input_construct( + struct dce_mem_input *dce_mi, + struct dc_context *ctx, + int inst, + const struct dce_mem_input_registers *regs, + const struct dce_mem_input_shift *mi_shift, + const struct dce_mem_input_mask *mi_mask) +{ + dce_mem_input_construct(dce_mi, ctx, inst, regs, mi_shift, mi_mask); + dce_mi->base.funcs = &dce60_mi_funcs; +} +#endif + void dce112_mem_input_construct( struct dce_mem_input *dce_mi, struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h index d15b0d7f47fc..23db5c72f07e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h @@ -58,6 +58,31 @@ SRI(DVMM_PTE_CONTROL, DCP, id),\ SRI(DVMM_PTE_ARB_CONTROL, DCP, id) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define MI_DCE6_REG_LIST(id)\ + SRI(GRPH_ENABLE, DCP, id),\ + SRI(GRPH_CONTROL, DCP, id),\ + SRI(GRPH_X_START, DCP, id),\ + SRI(GRPH_Y_START, DCP, id),\ + SRI(GRPH_X_END, DCP, id),\ + SRI(GRPH_Y_END, DCP, id),\ + SRI(GRPH_PITCH, DCP, id),\ + SRI(GRPH_SWAP_CNTL, DCP, id),\ + SRI(PRESCALE_GRPH_CONTROL, DCP, id),\ + SRI(GRPH_UPDATE, DCP, id),\ + SRI(GRPH_FLIP_CONTROL, DCP, id),\ + SRI(GRPH_PRIMARY_SURFACE_ADDRESS, DCP, id),\ + SRI(GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, DCP, id),\ + SRI(GRPH_SECONDARY_SURFACE_ADDRESS, DCP, id),\ + SRI(GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, DCP, id),\ + SRI(DPG_PIPE_ARBITRATION_CONTROL1, DMIF_PG, id),\ + SRI(DPG_PIPE_ARBITRATION_CONTROL3, DMIF_PG, id),\ + SRI(DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, DMIF_PG, id),\ + SRI(DPG_PIPE_URGENCY_CONTROL, DMIF_PG, id),\ + SRI(DPG_PIPE_STUTTER_CONTROL, DMIF_PG, id),\ + SRI(DMIF_BUFFER_CONTROL, PIPE, id) +#endif + #define MI_DCE8_REG_LIST(id)\ MI_DCE_BASE_REG_LIST(id),\ SRI(DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, DMIF_PG, id) @@ -104,6 +129,9 @@ struct dce_mem_input_registers { uint32_t GRPH_SECONDARY_SURFACE_ADDRESS_HIGH; /* DMIF_PG */ uint32_t DPG_PIPE_ARBITRATION_CONTROL1; +#if defined(CONFIG_DRM_AMD_DC_SI) + uint32_t DPG_PIPE_ARBITRATION_CONTROL3; +#endif uint32_t DPG_WATERMARK_MASK_CONTROL; uint32_t DPG_PIPE_URGENCY_CONTROL; uint32_t DPG_PIPE_URGENT_LEVEL_CONTROL; @@ -126,6 +154,18 @@ struct dce_mem_input_registers { #define SFB(blk_name, reg_name, field_name, post_fix)\ .field_name = blk_name ## reg_name ## __ ## field_name ## post_fix +#if defined(CONFIG_DRM_AMD_DC_SI) +#define MI_GFX6_TILE_MASK_SH_LIST(mask_sh, blk)\ + SFB(blk, GRPH_CONTROL, GRPH_NUM_BANKS, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_BANK_WIDTH, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_BANK_HEIGHT, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_MACRO_TILE_ASPECT, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_TILE_SPLIT, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_PIPE_CONFIG, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_ARRAY_MODE, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_COLOR_EXPANSION_MODE, mask_sh) +#endif + #define MI_GFX8_TILE_MASK_SH_LIST(mask_sh, blk)\ SFB(blk, GRPH_CONTROL, GRPH_NUM_BANKS, mask_sh),\ SFB(blk, GRPH_CONTROL, GRPH_BANK_WIDTH, mask_sh),\ @@ -162,6 +202,32 @@ struct dce_mem_input_registers { SFB(blk, GRPH_UPDATE, GRPH_UPDATE_LOCK, mask_sh),\ SFB(blk, GRPH_FLIP_CONTROL, GRPH_SURFACE_UPDATE_H_RETRACE_EN, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define MI_DCP_MASK_SH_LIST_DCE6(mask_sh, blk)\ + SFB(blk, GRPH_ENABLE, GRPH_ENABLE, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_DEPTH, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_FORMAT, mask_sh),\ + SFB(blk, GRPH_CONTROL, GRPH_NUM_BANKS, mask_sh),\ + SFB(blk, GRPH_X_START, GRPH_X_START, mask_sh),\ + SFB(blk, GRPH_Y_START, GRPH_Y_START, mask_sh),\ + SFB(blk, GRPH_X_END, GRPH_X_END, mask_sh),\ + SFB(blk, GRPH_Y_END, GRPH_Y_END, mask_sh),\ + SFB(blk, GRPH_PITCH, GRPH_PITCH, mask_sh),\ + SFB(blk, GRPH_SWAP_CNTL, GRPH_RED_CROSSBAR, mask_sh),\ + SFB(blk, GRPH_SWAP_CNTL, GRPH_BLUE_CROSSBAR, mask_sh),\ + SFB(blk, PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_SELECT, mask_sh),\ + SFB(blk, PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_R_SIGN, mask_sh),\ + SFB(blk, PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_G_SIGN, mask_sh),\ + SFB(blk, PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_B_SIGN, mask_sh),\ + SFB(blk, GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, mask_sh),\ + SFB(blk, GRPH_SECONDARY_SURFACE_ADDRESS, GRPH_SECONDARY_SURFACE_ADDRESS, mask_sh),\ + SFB(blk, GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, mask_sh),\ + SFB(blk, GRPH_PRIMARY_SURFACE_ADDRESS, GRPH_PRIMARY_SURFACE_ADDRESS, mask_sh),\ + SFB(blk, GRPH_UPDATE, GRPH_SURFACE_UPDATE_PENDING, mask_sh),\ + SFB(blk, GRPH_UPDATE, GRPH_UPDATE_LOCK, mask_sh),\ + SFB(blk, GRPH_FLIP_CONTROL, GRPH_SURFACE_UPDATE_H_RETRACE_EN, mask_sh) +#endif + #define MI_DCP_DCE11_MASK_SH_LIST(mask_sh, blk)\ SFB(blk, GRPH_PIPE_OUTSTANDING_REQUEST_LIMIT, GRPH_PIPE_OUTSTANDING_REQUEST_LIMIT, mask_sh) @@ -172,6 +238,33 @@ struct dce_mem_input_registers { SFB(blk, DVMM_PTE_ARB_CONTROL, DVMM_PTE_REQ_PER_CHUNK, mask_sh),\ SFB(blk, DVMM_PTE_ARB_CONTROL, DVMM_MAX_PTE_REQ_OUTSTANDING, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define MI_DMIF_PG_MASK_SH_LIST_DCE6(mask_sh, blk)\ + SFB(blk, DPG_PIPE_ARBITRATION_CONTROL1, PIXEL_DURATION, mask_sh),\ + SFB(blk, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, mask_sh),\ + SFB(blk, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, mask_sh),\ + SFB(blk, DPG_PIPE_STUTTER_CONTROL, STUTTER_ENABLE, mask_sh),\ + SFB(blk, DPG_PIPE_STUTTER_CONTROL, STUTTER_IGNORE_FBC, mask_sh),\ + SF(PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED, mask_sh),\ + SF(PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATION_COMPLETED, mask_sh) + +#define MI_DMIF_PG_MASK_SH_DCE6(mask_sh, blk)\ + SFB(blk, DPG_PIPE_ARBITRATION_CONTROL3, URGENCY_WATERMARK_MASK, mask_sh),\ + SFB(blk, DPG_PIPE_STUTTER_CONTROL, STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK, mask_sh),\ + SFB(blk, DPG_PIPE_STUTTER_CONTROL, STUTTER_EXIT_SELF_REFRESH_WATERMARK, mask_sh),\ + SFB(blk, DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, NB_PSTATE_CHANGE_WATERMARK_MASK, mask_sh),\ + SFB(blk, DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, NB_PSTATE_CHANGE_ENABLE, mask_sh),\ + SFB(blk, DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, NB_PSTATE_CHANGE_URGENT_DURING_REQUEST, mask_sh),\ + SFB(blk, DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST, mask_sh),\ + SFB(blk, DPG_PIPE_NB_PSTATE_CHANGE_CONTROL, NB_PSTATE_CHANGE_WATERMARK, mask_sh) + +#define MI_DCE6_MASK_SH_LIST(mask_sh)\ + MI_DCP_MASK_SH_LIST_DCE6(mask_sh, ),\ + MI_DMIF_PG_MASK_SH_LIST_DCE6(mask_sh, ),\ + MI_DMIF_PG_MASK_SH_DCE6(mask_sh, ),\ + MI_GFX6_TILE_MASK_SH_LIST(mask_sh, ) +#endif + #define MI_DMIF_PG_MASK_SH_LIST(mask_sh, blk)\ SFB(blk, DPG_PIPE_ARBITRATION_CONTROL1, PIXEL_DURATION, mask_sh),\ SFB(blk, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, mask_sh),\ @@ -345,6 +438,16 @@ void dce_mem_input_construct( const struct dce_mem_input_shift *mi_shift, const struct dce_mem_input_mask *mi_mask); +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_mem_input_construct( + struct dce_mem_input *dce_mi, + struct dc_context *ctx, + int inst, + const struct dce_mem_input_registers *regs, + const struct dce_mem_input_shift *mi_shift, + const struct dce_mem_input_mask *mi_mask); +#endif + void dce112_mem_input_construct( struct dce_mem_input *dce_mi, struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c b/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c index 51081d9ae3fb..e459ae65aaf7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c @@ -141,6 +141,47 @@ static void set_truncation( params->flags.TRUNCATE_MODE); } +#if defined(CONFIG_DRM_AMD_DC_SI) +/** + * dce60_set_truncation + * 1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp + * 2) enable truncation + * 3) HW remove 12bit FMT support for DCE11 power saving reason. + */ +static void dce60_set_truncation( + struct dce110_opp *opp110, + const struct bit_depth_reduction_params *params) +{ + /* DCE6 has no FMT_TRUNCATE_MODE bit in FMT_BIT_DEPTH_CONTROL reg */ + + /*Disable truncation*/ + REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL, + FMT_TRUNCATE_EN, 0, + FMT_TRUNCATE_DEPTH, 0); + + if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) { + /* 8bpc trunc on YCbCr422*/ + if (params->flags.TRUNCATE_DEPTH == 1) + REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL, + FMT_TRUNCATE_EN, 1, + FMT_TRUNCATE_DEPTH, 1); + else if (params->flags.TRUNCATE_DEPTH == 2) + /* 10bpc trunc on YCbCr422*/ + REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL, + FMT_TRUNCATE_EN, 1, + FMT_TRUNCATE_DEPTH, 2); + return; + } + /* on other format-to do */ + if (params->flags.TRUNCATE_ENABLED == 0) + return; + /*Set truncation depth and Enable truncation*/ + REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL, + FMT_TRUNCATE_EN, 1, + FMT_TRUNCATE_DEPTH, + params->flags.TRUNCATE_DEPTH); +} +#endif /** * set_spatial_dither @@ -373,6 +414,57 @@ void dce110_opp_set_clamping( } } +#if defined(CONFIG_DRM_AMD_DC_SI) +/** + * Set Clamping for DCE6 parts + * 1) Set clamping format based on bpc - 0 for 6bpc (No clamping) + * 1 for 8 bpc + * 2 for 10 bpc + * 3 for 12 bpc + * 7 for programable + * 2) Enable clamp if Limited range requested + */ +void dce60_opp_set_clamping( + struct dce110_opp *opp110, + const struct clamping_and_pixel_encoding_params *params) +{ + REG_SET_2(FMT_CLAMP_CNTL, 0, + FMT_CLAMP_DATA_EN, 0, + FMT_CLAMP_COLOR_FORMAT, 0); + + switch (params->clamping_level) { + case CLAMPING_FULL_RANGE: + break; + case CLAMPING_LIMITED_RANGE_8BPC: + REG_SET_2(FMT_CLAMP_CNTL, 0, + FMT_CLAMP_DATA_EN, 1, + FMT_CLAMP_COLOR_FORMAT, 1); + break; + case CLAMPING_LIMITED_RANGE_10BPC: + REG_SET_2(FMT_CLAMP_CNTL, 0, + FMT_CLAMP_DATA_EN, 1, + FMT_CLAMP_COLOR_FORMAT, 2); + break; + case CLAMPING_LIMITED_RANGE_12BPC: + REG_SET_2(FMT_CLAMP_CNTL, 0, + FMT_CLAMP_DATA_EN, 1, + FMT_CLAMP_COLOR_FORMAT, 3); + break; + case CLAMPING_LIMITED_RANGE_PROGRAMMABLE: + /*Set clamp control*/ + REG_SET_2(FMT_CLAMP_CNTL, 0, + FMT_CLAMP_DATA_EN, 1, + FMT_CLAMP_COLOR_FORMAT, 7); + + /* DCE6 does have FMT_CLAMP_COMPONENT_{R,G,B} registers */ + + break; + default: + break; + } +} +#endif + /** * set_pixel_encoding * @@ -408,6 +500,39 @@ static void set_pixel_encoding( } +#if defined(CONFIG_DRM_AMD_DC_SI) +/** + * dce60_set_pixel_encoding + * DCE6 has no FMT_SUBSAMPLING_{MODE,ORDER} bits in FMT_CONTROL reg + * Set Pixel Encoding + * 0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly + * 1: YCbCr 4:2:2 + */ +static void dce60_set_pixel_encoding( + struct dce110_opp *opp110, + const struct clamping_and_pixel_encoding_params *params) +{ + if (opp110->opp_mask->FMT_CBCR_BIT_REDUCTION_BYPASS) + REG_UPDATE_2(FMT_CONTROL, + FMT_PIXEL_ENCODING, 0, + FMT_CBCR_BIT_REDUCTION_BYPASS, 0); + else + REG_UPDATE(FMT_CONTROL, + FMT_PIXEL_ENCODING, 0); + + if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) { + REG_UPDATE(FMT_CONTROL, + FMT_PIXEL_ENCODING, 1); + } + if (params->pixel_encoding == PIXEL_ENCODING_YCBCR420) { + REG_UPDATE_2(FMT_CONTROL, + FMT_PIXEL_ENCODING, 2, + FMT_CBCR_BIT_REDUCTION_BYPASS, 1); + } + +} +#endif + void dce110_opp_program_bit_depth_reduction( struct output_pixel_processor *opp, const struct bit_depth_reduction_params *params) @@ -419,6 +544,19 @@ void dce110_opp_program_bit_depth_reduction( set_temporal_dither(opp110, params); } +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_opp_program_bit_depth_reduction( + struct output_pixel_processor *opp, + const struct bit_depth_reduction_params *params) +{ + struct dce110_opp *opp110 = TO_DCE110_OPP(opp); + + dce60_set_truncation(opp110, params); + set_spatial_dither(opp110, params); + set_temporal_dither(opp110, params); +} +#endif + void dce110_opp_program_clamping_and_pixel_encoding( struct output_pixel_processor *opp, const struct clamping_and_pixel_encoding_params *params) @@ -429,6 +567,19 @@ void dce110_opp_program_clamping_and_pixel_encoding( set_pixel_encoding(opp110, params); } +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_opp_program_clamping_and_pixel_encoding( + struct output_pixel_processor *opp, + const struct clamping_and_pixel_encoding_params *params) +{ + struct dce110_opp *opp110 = TO_DCE110_OPP(opp); + + dce60_opp_set_clamping(opp110, params); + dce60_set_pixel_encoding(opp110, params); +} +#endif + + static void program_formatter_420_memory(struct output_pixel_processor *opp) { struct dce110_opp *opp110 = TO_DCE110_OPP(opp); @@ -526,7 +677,32 @@ void dce110_opp_program_fmt( return; } +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_opp_program_fmt( + struct output_pixel_processor *opp, + struct bit_depth_reduction_params *fmt_bit_depth, + struct clamping_and_pixel_encoding_params *clamping) +{ + /* dithering is affected by <CrtcSourceSelect>, hence should be + * programmed afterwards */ + + if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420) + program_formatter_420_memory(opp); + + dce60_opp_program_bit_depth_reduction( + opp, + fmt_bit_depth); + + dce60_opp_program_clamping_and_pixel_encoding( + opp, + clamping); + + if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420) + program_formatter_reset_dig_resync_fifo(opp); + return; +} +#endif @@ -541,6 +717,15 @@ static const struct opp_funcs funcs = { .opp_program_bit_depth_reduction = dce110_opp_program_bit_depth_reduction }; +#if defined(CONFIG_DRM_AMD_DC_SI) +static const struct opp_funcs dce60_opp_funcs = { + .opp_set_dyn_expansion = dce110_opp_set_dyn_expansion, + .opp_destroy = dce110_opp_destroy, + .opp_program_fmt = dce60_opp_program_fmt, + .opp_program_bit_depth_reduction = dce60_opp_program_bit_depth_reduction +}; +#endif + void dce110_opp_construct(struct dce110_opp *opp110, struct dc_context *ctx, uint32_t inst, @@ -559,6 +744,26 @@ void dce110_opp_construct(struct dce110_opp *opp110, opp110->opp_mask = opp_mask; } +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_opp_construct(struct dce110_opp *opp110, + struct dc_context *ctx, + uint32_t inst, + const struct dce_opp_registers *regs, + const struct dce_opp_shift *opp_shift, + const struct dce_opp_mask *opp_mask) +{ + opp110->base.funcs = &dce60_opp_funcs; + + opp110->base.ctx = ctx; + + opp110->base.inst = inst; + + opp110->regs = regs; + opp110->opp_shift = opp_shift; + opp110->opp_mask = opp_mask; +} +#endif + void dce110_opp_destroy(struct output_pixel_processor **opp) { if (*opp) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_opp.h b/drivers/gpu/drm/amd/display/dc/dce/dce_opp.h index 2ab0147cbd9d..4d484ef60f35 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_opp.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_opp.h @@ -81,6 +81,17 @@ enum dce110_opp_reg_type { OPP_COMMON_REG_LIST_BASE(id), \ SRI(CONTROL, FMT_MEMORY, id) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define OPP_DCE_60_REG_LIST(id) \ + SRI(FMT_DYNAMIC_EXP_CNTL, FMT, id), \ + SRI(FMT_BIT_DEPTH_CONTROL, FMT, id), \ + SRI(FMT_CONTROL, FMT, id), \ + SRI(FMT_DITHER_RAND_R_SEED, FMT, id), \ + SRI(FMT_DITHER_RAND_G_SEED, FMT, id), \ + SRI(FMT_DITHER_RAND_B_SEED, FMT, id), \ + SRI(FMT_CLAMP_CNTL, FMT, id) +#endif + #define OPP_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -192,6 +203,35 @@ enum dce110_opp_reg_type { OPP_SF(FMT0_FMT_CONTROL, FMT_SUBSAMPLING_ORDER, mask_sh),\ OPP_SF(FMT0_FMT_CONTROL, FMT_CBCR_BIT_REDUCTION_BYPASS, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define OPP_COMMON_MASK_SH_LIST_DCE_60(mask_sh)\ + OPP_SF(FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN, mask_sh),\ + OPP_SF(FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_MODE, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_EN, mask_sh),\ + OPP_SF(FMT_DITHER_RAND_R_SEED, FMT_RAND_R_SEED, mask_sh),\ + OPP_SF(FMT_DITHER_RAND_G_SEED, FMT_RAND_G_SEED, mask_sh),\ + OPP_SF(FMT_DITHER_RAND_B_SEED, FMT_RAND_B_SEED, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_EN, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_RESET, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_OFFSET, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_DEPTH, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_LEVEL, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_25FRC_SEL, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_50FRC_SEL, mask_sh),\ + OPP_SF(FMT_BIT_DEPTH_CONTROL, FMT_75FRC_SEL, mask_sh),\ + OPP_SF(FMT_CLAMP_CNTL, FMT_CLAMP_DATA_EN, mask_sh),\ + OPP_SF(FMT_CLAMP_CNTL, FMT_CLAMP_COLOR_FORMAT, mask_sh),\ + OPP_SF(FMT_CONTROL, FMT_PIXEL_ENCODING, mask_sh) +#endif + #define OPP_REG_FIELD_LIST(type) \ type FMT_DYNAMIC_EXP_EN; \ type FMT_DYNAMIC_EXP_MODE; \ @@ -279,6 +319,15 @@ void dce110_opp_construct(struct dce110_opp *opp110, const struct dce_opp_shift *opp_shift, const struct dce_opp_mask *opp_mask); +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_opp_construct(struct dce110_opp *opp110, + struct dc_context *ctx, + uint32_t inst, + const struct dce_opp_registers *regs, + const struct dce_opp_shift *opp_shift, + const struct dce_opp_mask *opp_mask); +#endif + void dce110_opp_destroy(struct output_pixel_processor **opp); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c index 43781e77be43..df7f826eebd8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c @@ -46,13 +46,14 @@ #define FN(reg_name, field_name) \ dce_panel_cntl->shift->field_name, dce_panel_cntl->mask->field_name -static unsigned int calculate_16_bit_backlight_from_pwm(struct dce_panel_cntl *dce_panel_cntl) +static unsigned int dce_get_16_bit_backlight_from_pwm(struct panel_cntl *panel_cntl) { uint64_t current_backlight; uint32_t round_result; uint32_t pwm_period_cntl, bl_period, bl_int_count; uint32_t bl_pwm_cntl, bl_pwm, fractional_duty_cycle_en; uint32_t bl_period_mask, bl_pwm_mask; + struct dce_panel_cntl *dce_panel_cntl = TO_DCE_PANEL_CNTL(panel_cntl); pwm_period_cntl = REG_READ(BL_PWM_PERIOD_CNTL); REG_GET(BL_PWM_PERIOD_CNTL, BL_PWM_PERIOD, &bl_period); @@ -75,7 +76,7 @@ static unsigned int calculate_16_bit_backlight_from_pwm(struct dce_panel_cntl *d else bl_pwm &= 0xFFFF; - current_backlight = bl_pwm << (1 + bl_int_count); + current_backlight = (uint64_t)bl_pwm << (1 + bl_int_count); if (bl_period == 0) bl_period = 0xFFFF; @@ -150,7 +151,7 @@ static uint32_t dce_panel_cntl_hw_init(struct panel_cntl *panel_cntl) REG_UPDATE(BL_PWM_GRP1_REG_LOCK, BL_PWM_GRP1_REG_LOCK, 0); - current_backlight = calculate_16_bit_backlight_from_pwm(dce_panel_cntl); + current_backlight = dce_get_16_bit_backlight_from_pwm(panel_cntl); return current_backlight; } @@ -273,6 +274,7 @@ static const struct panel_cntl_funcs dce_link_panel_cntl_funcs = { .is_panel_powered_on = dce_is_panel_powered_on, .store_backlight_level = dce_store_backlight_level, .driver_set_backlight = dce_driver_set_backlight, + .get_current_backlight = dce_get_16_bit_backlight_from_pwm, }; void dce_panel_cntl_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index ab63d0d0304c..2a32b66959ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -146,6 +146,33 @@ static bool setup_scaling_configuration( return true; } +#if defined(CONFIG_DRM_AMD_DC_SI) +static bool dce60_setup_scaling_configuration( + struct dce_transform *xfm_dce, + const struct scaler_data *data) +{ + REG_SET(SCL_BYPASS_CONTROL, 0, SCL_BYPASS_MODE, 0); + + if (data->taps.h_taps + data->taps.v_taps <= 2) { + /* Set bypass */ + + /* DCE6 has no SCL_MODE register, skip scale mode programming */ + + return false; + } + + REG_SET_2(SCL_TAP_CONTROL, 0, + SCL_H_NUM_OF_TAPS, data->taps.h_taps - 1, + SCL_V_NUM_OF_TAPS, data->taps.v_taps - 1); + + /* DCE6 has no SCL_MODE register, skip scale mode programming */ + + /* DCE6 has no SCL_BOUNDARY_MODE bit, skip replace out of bound pixels */ + + return true; +} +#endif + static void program_overscan( struct dce_transform *xfm_dce, const struct scaler_data *data) @@ -279,6 +306,36 @@ static void calculate_inits( inits->v_init.fraction = dc_fixpt_u0d19(v_init) << 5; } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_calculate_inits( + struct dce_transform *xfm_dce, + const struct scaler_data *data, + struct sclh_ratios_inits *inits) +{ + struct fixed31_32 v_init; + + inits->h_int_scale_ratio = + dc_fixpt_u2d19(data->ratios.horz) << 5; + inits->v_int_scale_ratio = + dc_fixpt_u2d19(data->ratios.vert) << 5; + + /* DCE6 h_init_luma setting inspired by DCE110 */ + inits->h_init_luma.integer = 1; + + /* DCE6 h_init_chroma setting inspired by DCE110 */ + inits->h_init_chroma.integer = 1; + + v_init = + dc_fixpt_div_int( + dc_fixpt_add( + data->ratios.vert, + dc_fixpt_from_int(data->taps.v_taps + 1)), + 2); + inits->v_init.integer = dc_fixpt_floor(v_init); + inits->v_init.fraction = dc_fixpt_u0d19(v_init) << 5; +} +#endif + static void program_scl_ratios_inits( struct dce_transform *xfm_dce, struct scl_ratios_inits *inits) @@ -301,6 +358,36 @@ static void program_scl_ratios_inits( REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_program_scl_ratios_inits( + struct dce_transform *xfm_dce, + struct sclh_ratios_inits *inits) +{ + + REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0, + SCL_H_SCALE_RATIO, inits->h_int_scale_ratio); + + REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0, + SCL_V_SCALE_RATIO, inits->v_int_scale_ratio); + + /* DCE6 has SCL_HORZ_FILTER_INIT_RGB_LUMA register */ + REG_SET_2(SCL_HORZ_FILTER_INIT_RGB_LUMA, 0, + SCL_H_INIT_INT_RGB_Y, inits->h_init_luma.integer, + SCL_H_INIT_FRAC_RGB_Y, inits->h_init_luma.fraction); + + /* DCE6 has SCL_HORZ_FILTER_INIT_CHROMA register */ + REG_SET_2(SCL_HORZ_FILTER_INIT_CHROMA, 0, + SCL_H_INIT_INT_CBCR, inits->h_init_chroma.integer, + SCL_H_INIT_FRAC_CBCR, inits->h_init_chroma.fraction); + + REG_SET_2(SCL_VERT_FILTER_INIT, 0, + SCL_V_INIT_INT, inits->v_init.integer, + SCL_V_INIT_FRAC, inits->v_init.fraction); + + REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0); +} +#endif + static const uint16_t *get_filter_coeffs_16p(int taps, struct fixed31_32 ratio) { if (taps == 4) @@ -399,6 +486,91 @@ static void dce_transform_set_scaler( REG_UPDATE(LB_DATA_FORMAT, ALPHA_EN, data->lb_params.alpha_en); } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_transform_set_scaler( + struct transform *xfm, + const struct scaler_data *data) +{ + struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); + bool is_scaling_required; + bool filter_updated = false; + const uint16_t *coeffs_v, *coeffs_h; + + /*Use whole line buffer memory always*/ + REG_SET(DC_LB_MEMORY_SPLIT, 0, + DC_LB_MEMORY_CONFIG, 0); + + REG_SET(DC_LB_MEM_SIZE, 0, + DC_LB_MEM_SIZE, xfm_dce->lb_memory_size); + + /* Clear SCL_F_SHARP_CONTROL value to 0 */ + REG_WRITE(SCL_F_SHARP_CONTROL, 0); + + /* 1. Program overscan */ + program_overscan(xfm_dce, data); + + /* 2. Program taps and configuration */ + is_scaling_required = dce60_setup_scaling_configuration(xfm_dce, data); + + if (is_scaling_required) { + /* 3. Calculate and program ratio, DCE6 filter initialization */ + struct sclh_ratios_inits inits = { 0 }; + + /* DCE6 has specific calculate_inits() function */ + dce60_calculate_inits(xfm_dce, data, &inits); + + /* DCE6 has specific program_scl_ratios_inits() function */ + dce60_program_scl_ratios_inits(xfm_dce, &inits); + + coeffs_v = get_filter_coeffs_16p(data->taps.v_taps, data->ratios.vert); + coeffs_h = get_filter_coeffs_16p(data->taps.h_taps, data->ratios.horz); + + if (coeffs_v != xfm_dce->filter_v || coeffs_h != xfm_dce->filter_h) { + /* 4. Program vertical filters */ + if (xfm_dce->filter_v == NULL) + REG_SET(SCL_VERT_FILTER_CONTROL, 0, + SCL_V_2TAP_HARDCODE_COEF_EN, 0); + program_multi_taps_filter( + xfm_dce, + data->taps.v_taps, + coeffs_v, + FILTER_TYPE_RGB_Y_VERTICAL); + program_multi_taps_filter( + xfm_dce, + data->taps.v_taps, + coeffs_v, + FILTER_TYPE_ALPHA_VERTICAL); + + /* 5. Program horizontal filters */ + if (xfm_dce->filter_h == NULL) + REG_SET(SCL_HORZ_FILTER_CONTROL, 0, + SCL_H_2TAP_HARDCODE_COEF_EN, 0); + program_multi_taps_filter( + xfm_dce, + data->taps.h_taps, + coeffs_h, + FILTER_TYPE_RGB_Y_HORIZONTAL); + program_multi_taps_filter( + xfm_dce, + data->taps.h_taps, + coeffs_h, + FILTER_TYPE_ALPHA_HORIZONTAL); + + xfm_dce->filter_v = coeffs_v; + xfm_dce->filter_h = coeffs_h; + filter_updated = true; + } + } + + /* 6. Program the viewport */ + program_viewport(xfm_dce, &data->viewport); + + /* DCE6 has no SCL_COEF_UPDATE_COMPLETE bit to flip to new coefficient memory */ + + /* DCE6 DATA_FORMAT register does not support ALPHA_EN */ +} +#endif + /***************************************************************************** * set_clamp * @@ -664,6 +836,67 @@ static void program_bit_depth_reduction( bit_depth_params->flags.HIGHPASS_RANDOM); } +#if defined(CONFIG_DRM_AMD_DC_SI) +/***************************************************************************** + * dce60_transform_bit_depth_reduction program + * + * @brief + * Programs the DCP bit depth reduction registers (Clamp, Round/Truncate, + * Dither) for dce + * + * @param depth : bit depth to set the clamp to (should match denorm) + * + ******************************************************************************/ +static void dce60_program_bit_depth_reduction( + struct dce_transform *xfm_dce, + enum dc_color_depth depth, + const struct bit_depth_reduction_params *bit_depth_params) +{ + enum dcp_out_trunc_round_depth trunc_round_depth; + enum dcp_out_trunc_round_mode trunc_mode; + bool spatial_dither_enable; + + ASSERT(depth < COLOR_DEPTH_121212); /* Invalid clamp bit depth */ + + spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED; + /* Default to 12 bit truncation without rounding */ + trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT; + trunc_mode = DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE; + + if (bit_depth_params->flags.TRUNCATE_ENABLED) { + /* Don't enable dithering if truncation is enabled */ + spatial_dither_enable = false; + trunc_mode = bit_depth_params->flags.TRUNCATE_MODE ? + DCP_OUT_TRUNC_ROUND_MODE_ROUND : + DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE; + + if (bit_depth_params->flags.TRUNCATE_DEPTH == 0 || + bit_depth_params->flags.TRUNCATE_DEPTH == 1) + trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_8BIT; + else if (bit_depth_params->flags.TRUNCATE_DEPTH == 2) + trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_10BIT; + else { + /* + * Invalid truncate/round depth. Setting here to 12bit + * to prevent use-before-initialize errors. + */ + trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT; + BREAK_TO_DEBUGGER(); + } + } + + /* DCE6 has no OUT_CLAMP_CONTROL_* registers - set_clamp() is skipped */ + set_round(xfm_dce, trunc_mode, trunc_round_depth); + set_dither(xfm_dce, + spatial_dither_enable, + DCP_SPATIAL_DITHER_MODE_A_AA_A, + DCP_SPATIAL_DITHER_DEPTH_30BPP, + bit_depth_params->flags.FRAME_RANDOM, + bit_depth_params->flags.RGB_RANDOM, + bit_depth_params->flags.HIGHPASS_RANDOM); +} +#endif + static int dce_transform_get_max_num_of_supported_lines( struct dce_transform *xfm_dce, enum lb_pixel_depth depth, @@ -797,6 +1030,59 @@ static void dce_transform_set_pixel_storage_depth( } } +#if defined(CONFIG_DRM_AMD_DC_SI) +static void dce60_transform_set_pixel_storage_depth( + struct transform *xfm, + enum lb_pixel_depth depth, + const struct bit_depth_reduction_params *bit_depth_params) +{ + struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); + int pixel_depth, expan_mode; + enum dc_color_depth color_depth; + + switch (depth) { + case LB_PIXEL_DEPTH_18BPP: + color_depth = COLOR_DEPTH_666; + pixel_depth = 2; + expan_mode = 1; + break; + case LB_PIXEL_DEPTH_24BPP: + color_depth = COLOR_DEPTH_888; + pixel_depth = 1; + expan_mode = 1; + break; + case LB_PIXEL_DEPTH_30BPP: + color_depth = COLOR_DEPTH_101010; + pixel_depth = 0; + expan_mode = 1; + break; + case LB_PIXEL_DEPTH_36BPP: + color_depth = COLOR_DEPTH_121212; + pixel_depth = 3; + expan_mode = 0; + break; + default: + color_depth = COLOR_DEPTH_101010; + pixel_depth = 0; + expan_mode = 1; + BREAK_TO_DEBUGGER(); + break; + } + + set_denormalization(xfm_dce, color_depth); + dce60_program_bit_depth_reduction(xfm_dce, color_depth, bit_depth_params); + + /* DATA_FORMAT in DCE6 does not have PIXEL_DEPTH and PIXEL_EXPAN_MODE masks */ + + if (!(xfm_dce->lb_pixel_depth_supported & depth)) { + /*we should use unsupported capabilities + * unless it is required by w/a*/ + DC_LOG_WARNING("%s: Capability not supported", + __func__); + } +} +#endif + static void program_gamut_remap( struct dce_transform *xfm_dce, const uint16_t *reg_val) @@ -1335,6 +1621,21 @@ static const struct transform_funcs dce_transform_funcs = { .transform_get_optimal_number_of_taps = dce_transform_get_optimal_number_of_taps }; +#if defined(CONFIG_DRM_AMD_DC_SI) +static const struct transform_funcs dce60_transform_funcs = { + .transform_reset = dce_transform_reset, + .transform_set_scaler = dce60_transform_set_scaler, + .transform_set_gamut_remap = dce_transform_set_gamut_remap, + .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment, + .opp_set_csc_default = dce110_opp_set_csc_default, + .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut, + .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl, + .opp_set_regamma_mode = dce110_opp_set_regamma_mode, + .transform_set_pixel_storage_depth = dce60_transform_set_pixel_storage_depth, + .transform_get_optimal_number_of_taps = dce_transform_get_optimal_number_of_taps +}; +#endif + /*****************************************/ /* Constructor, Destructor */ /*****************************************/ @@ -1365,3 +1666,32 @@ void dce_transform_construct( xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY; xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/ } + +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_transform_construct( + struct dce_transform *xfm_dce, + struct dc_context *ctx, + uint32_t inst, + const struct dce_transform_registers *regs, + const struct dce_transform_shift *xfm_shift, + const struct dce_transform_mask *xfm_mask) +{ + xfm_dce->base.ctx = ctx; + + xfm_dce->base.inst = inst; + xfm_dce->base.funcs = &dce60_transform_funcs; + + xfm_dce->regs = regs; + xfm_dce->xfm_shift = xfm_shift; + xfm_dce->xfm_mask = xfm_mask; + + xfm_dce->prescaler_on = true; + xfm_dce->lb_pixel_depth_supported = + LB_PIXEL_DEPTH_18BPP | + LB_PIXEL_DEPTH_24BPP | + LB_PIXEL_DEPTH_30BPP; + + xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY; + xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/ +} +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.h b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.h index 948281d8b6af..cbce194ec7b8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.h @@ -108,6 +108,68 @@ SRI(DCFE_MEM_PWR_CTRL, DCFE, id), \ SRI(DCFE_MEM_PWR_STATUS, DCFE, id) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define XFM_COMMON_REG_LIST_DCE60_BASE(id) \ + SRI(DATA_FORMAT, LB, id), \ + SRI(GAMUT_REMAP_CONTROL, DCP, id), \ + SRI(GAMUT_REMAP_C11_C12, DCP, id), \ + SRI(GAMUT_REMAP_C13_C14, DCP, id), \ + SRI(GAMUT_REMAP_C21_C22, DCP, id), \ + SRI(GAMUT_REMAP_C23_C24, DCP, id), \ + SRI(GAMUT_REMAP_C31_C32, DCP, id), \ + SRI(GAMUT_REMAP_C33_C34, DCP, id), \ + SRI(OUTPUT_CSC_C11_C12, DCP, id), \ + SRI(OUTPUT_CSC_C13_C14, DCP, id), \ + SRI(OUTPUT_CSC_C21_C22, DCP, id), \ + SRI(OUTPUT_CSC_C23_C24, DCP, id), \ + SRI(OUTPUT_CSC_C31_C32, DCP, id), \ + SRI(OUTPUT_CSC_C33_C34, DCP, id), \ + SRI(OUTPUT_CSC_CONTROL, DCP, id), \ + SRI(REGAMMA_CNTLA_START_CNTL, DCP, id), \ + SRI(REGAMMA_CNTLA_SLOPE_CNTL, DCP, id), \ + SRI(REGAMMA_CNTLA_END_CNTL1, DCP, id), \ + SRI(REGAMMA_CNTLA_END_CNTL2, DCP, id), \ + SRI(REGAMMA_CNTLA_REGION_0_1, DCP, id), \ + SRI(REGAMMA_CNTLA_REGION_2_3, DCP, id), \ + SRI(REGAMMA_CNTLA_REGION_4_5, DCP, id), \ + SRI(REGAMMA_CNTLA_REGION_6_7, DCP, id), \ + SRI(REGAMMA_CNTLA_REGION_8_9, DCP, id), \ + SRI(REGAMMA_CNTLA_REGION_10_11, DCP, id), \ + SRI(REGAMMA_CNTLA_REGION_12_13, DCP, id), \ + SRI(REGAMMA_CNTLA_REGION_14_15, DCP, id), \ + SRI(REGAMMA_LUT_WRITE_EN_MASK, DCP, id), \ + SRI(REGAMMA_LUT_INDEX, DCP, id), \ + SRI(REGAMMA_LUT_DATA, DCP, id), \ + SRI(REGAMMA_CONTROL, DCP, id), \ + SRI(DENORM_CONTROL, DCP, id), \ + SRI(DCP_SPATIAL_DITHER_CNTL, DCP, id), \ + SRI(OUT_ROUND_CONTROL, DCP, id), \ + SRI(SCL_TAP_CONTROL, SCL, id), \ + SRI(SCL_CONTROL, SCL, id), \ + SRI(SCL_BYPASS_CONTROL, SCL, id), \ + SRI(EXT_OVERSCAN_LEFT_RIGHT, SCL, id), \ + SRI(EXT_OVERSCAN_TOP_BOTTOM, SCL, id), \ + SRI(SCL_VERT_FILTER_CONTROL, SCL, id), \ + SRI(SCL_HORZ_FILTER_CONTROL, SCL, id), \ + SRI(SCL_COEF_RAM_SELECT, SCL, id), \ + SRI(SCL_COEF_RAM_TAP_DATA, SCL, id), \ + SRI(VIEWPORT_START, SCL, id), \ + SRI(VIEWPORT_SIZE, SCL, id), \ + SRI(SCL_HORZ_FILTER_SCALE_RATIO, SCL, id), \ + SRI(SCL_VERT_FILTER_SCALE_RATIO, SCL, id), \ + SRI(SCL_VERT_FILTER_INIT, SCL, id), \ + SRI(SCL_AUTOMATIC_MODE_CONTROL, SCL, id), \ + SRI(DC_LB_MEMORY_SPLIT, LB, id), \ + SRI(DC_LB_MEM_SIZE, LB, id), \ + SRI(DCFE_MEM_LIGHT_SLEEP_CNTL, CRTC, id), \ + SRI(SCL_UPDATE, SCL, id), \ + SRI(SCL_F_SHARP_CONTROL, SCL, id) + +#define XFM_COMMON_REG_LIST_DCE60(id) \ + XFM_COMMON_REG_LIST_DCE60_BASE(id), \ + SRI(DCFE_MEM_LIGHT_SLEEP_CNTL, CRTC, id) +#endif + #define XFM_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -204,6 +266,83 @@ XFM_SF(DCFE_MEM_PWR_STATUS, DCP_REGAMMA_MEM_PWR_STATE, mask_sh),\ XFM_SF(SCL_MODE, SCL_PSCL_EN, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define XFM_COMMON_MASK_SH_LIST_DCE60(mask_sh) \ + XFM_COMMON_MASK_SH_LIST_DCE60_COMMON_BASE(mask_sh), \ + OPP_SF(DCFE_MEM_LIGHT_SLEEP_CNTL, REGAMMA_LUT_LIGHT_SLEEP_DIS, mask_sh),\ + OPP_SF(DCFE_MEM_LIGHT_SLEEP_CNTL, DCP_LUT_LIGHT_SLEEP_DIS, mask_sh),\ + OPP_SF(DCFE_MEM_LIGHT_SLEEP_CNTL, REGAMMA_LUT_MEM_PWR_STATE, mask_sh) + +#define XFM_COMMON_MASK_SH_LIST_DCE60_COMMON_BASE(mask_sh) \ + XFM_SF(OUT_ROUND_CONTROL, OUT_ROUND_TRUNC_MODE, mask_sh), \ + XFM_SF(DCP_SPATIAL_DITHER_CNTL, DCP_SPATIAL_DITHER_EN, mask_sh), \ + XFM_SF(DCP_SPATIAL_DITHER_CNTL, DCP_SPATIAL_DITHER_MODE, mask_sh), \ + XFM_SF(DCP_SPATIAL_DITHER_CNTL, DCP_SPATIAL_DITHER_DEPTH, mask_sh), \ + XFM_SF(DCP_SPATIAL_DITHER_CNTL, DCP_FRAME_RANDOM_ENABLE, mask_sh), \ + XFM_SF(DCP_SPATIAL_DITHER_CNTL, DCP_RGB_RANDOM_ENABLE, mask_sh), \ + XFM_SF(DCP_SPATIAL_DITHER_CNTL, DCP_HIGHPASS_RANDOM_ENABLE, mask_sh), \ + XFM_SF(DENORM_CONTROL, DENORM_MODE, mask_sh), \ + XFM_SF(DATA_FORMAT, INTERLEAVE_EN, mask_sh), \ + XFM_SF(GAMUT_REMAP_C11_C12, GAMUT_REMAP_C11, mask_sh), \ + XFM_SF(GAMUT_REMAP_C11_C12, GAMUT_REMAP_C12, mask_sh), \ + XFM_SF(GAMUT_REMAP_C13_C14, GAMUT_REMAP_C13, mask_sh), \ + XFM_SF(GAMUT_REMAP_C13_C14, GAMUT_REMAP_C14, mask_sh), \ + XFM_SF(GAMUT_REMAP_C21_C22, GAMUT_REMAP_C21, mask_sh), \ + XFM_SF(GAMUT_REMAP_C21_C22, GAMUT_REMAP_C22, mask_sh), \ + XFM_SF(GAMUT_REMAP_C23_C24, GAMUT_REMAP_C23, mask_sh), \ + XFM_SF(GAMUT_REMAP_C23_C24, GAMUT_REMAP_C24, mask_sh), \ + XFM_SF(GAMUT_REMAP_C31_C32, GAMUT_REMAP_C31, mask_sh), \ + XFM_SF(GAMUT_REMAP_C31_C32, GAMUT_REMAP_C32, mask_sh), \ + XFM_SF(GAMUT_REMAP_C33_C34, GAMUT_REMAP_C33, mask_sh), \ + XFM_SF(GAMUT_REMAP_C33_C34, GAMUT_REMAP_C34, mask_sh), \ + XFM_SF(GAMUT_REMAP_CONTROL, GRPH_GAMUT_REMAP_MODE, mask_sh), \ + XFM_SF(OUTPUT_CSC_C11_C12, OUTPUT_CSC_C11, mask_sh),\ + XFM_SF(OUTPUT_CSC_C11_C12, OUTPUT_CSC_C12, mask_sh),\ + XFM_SF(OUTPUT_CSC_CONTROL, OUTPUT_CSC_GRPH_MODE, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_START_CNTL, REGAMMA_CNTLA_EXP_REGION_START, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_START_CNTL, REGAMMA_CNTLA_EXP_REGION_START_SEGMENT, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_SLOPE_CNTL, REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_END_CNTL1, REGAMMA_CNTLA_EXP_REGION_END, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_END_CNTL2, REGAMMA_CNTLA_EXP_REGION_END_BASE, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_END_CNTL2, REGAMMA_CNTLA_EXP_REGION_END_SLOPE, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_REGION_0_1, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_REGION_0_1, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_REGION_0_1, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, mask_sh),\ + XFM_SF(REGAMMA_CNTLA_REGION_0_1, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\ + XFM_SF(REGAMMA_LUT_WRITE_EN_MASK, REGAMMA_LUT_WRITE_EN_MASK, mask_sh),\ + XFM_SF(REGAMMA_CONTROL, GRPH_REGAMMA_MODE, mask_sh),\ + XFM_SF(SCL_TAP_CONTROL, SCL_H_NUM_OF_TAPS, mask_sh), \ + XFM_SF(SCL_TAP_CONTROL, SCL_V_NUM_OF_TAPS, mask_sh), \ + XFM_SF(SCL_BYPASS_CONTROL, SCL_BYPASS_MODE, mask_sh), \ + XFM_SF(EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT, mask_sh), \ + XFM_SF(EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT, mask_sh), \ + XFM_SF(EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP, mask_sh), \ + XFM_SF(EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM, mask_sh), \ + XFM_SF(SCL_COEF_RAM_SELECT, SCL_C_RAM_FILTER_TYPE, mask_sh), \ + XFM_SF(SCL_COEF_RAM_SELECT, SCL_C_RAM_PHASE, mask_sh), \ + XFM_SF(SCL_COEF_RAM_SELECT, SCL_C_RAM_TAP_PAIR_IDX, mask_sh), \ + XFM_SF(SCL_COEF_RAM_TAP_DATA, SCL_C_RAM_EVEN_TAP_COEF_EN, mask_sh), \ + XFM_SF(SCL_COEF_RAM_TAP_DATA, SCL_C_RAM_EVEN_TAP_COEF, mask_sh), \ + XFM_SF(SCL_COEF_RAM_TAP_DATA, SCL_C_RAM_ODD_TAP_COEF_EN, mask_sh), \ + XFM_SF(SCL_COEF_RAM_TAP_DATA, SCL_C_RAM_ODD_TAP_COEF, mask_sh), \ + XFM_SF(VIEWPORT_START, VIEWPORT_X_START, mask_sh), \ + XFM_SF(VIEWPORT_START, VIEWPORT_Y_START, mask_sh), \ + XFM_SF(VIEWPORT_SIZE, VIEWPORT_HEIGHT, mask_sh), \ + XFM_SF(VIEWPORT_SIZE, VIEWPORT_WIDTH, mask_sh), \ + XFM_SF(SCL_HORZ_FILTER_SCALE_RATIO, SCL_H_SCALE_RATIO, mask_sh), \ + XFM_SF(SCL_VERT_FILTER_SCALE_RATIO, SCL_V_SCALE_RATIO, mask_sh), \ + XFM_SF(SCL_HORZ_FILTER_INIT_RGB_LUMA, SCL_H_INIT_INT_RGB_Y, mask_sh), \ + XFM_SF(SCL_HORZ_FILTER_INIT_RGB_LUMA, SCL_H_INIT_FRAC_RGB_Y, mask_sh), \ + XFM_SF(SCL_HORZ_FILTER_INIT_CHROMA, SCL_H_INIT_INT_CBCR, mask_sh), \ + XFM_SF(SCL_HORZ_FILTER_INIT_CHROMA, SCL_H_INIT_FRAC_CBCR, mask_sh), \ + XFM_SF(SCL_VERT_FILTER_INIT, SCL_V_INIT_INT, mask_sh), \ + XFM_SF(SCL_VERT_FILTER_INIT, SCL_V_INIT_FRAC, mask_sh), \ + XFM_SF(SCL_HORZ_FILTER_CONTROL, SCL_H_FILTER_PICK_NEAREST, mask_sh), \ + XFM_SF(SCL_VERT_FILTER_CONTROL, SCL_V_FILTER_PICK_NEAREST, mask_sh), \ + XFM_SF(DC_LB_MEMORY_SPLIT, DC_LB_MEMORY_CONFIG, mask_sh), \ + XFM_SF(DC_LB_MEM_SIZE, DC_LB_MEM_SIZE, mask_sh) +#endif + #define XFM_COMMON_MASK_SH_LIST_SOC_BASE(mask_sh) \ XFM_SF(DCP0_OUT_CLAMP_CONTROL_B_CB, OUT_CLAMP_MIN_B_CB, mask_sh), \ XFM_SF(DCP0_OUT_CLAMP_CONTROL_B_CB, OUT_CLAMP_MAX_B_CB, mask_sh), \ @@ -302,6 +441,7 @@ type DCP_RGB_RANDOM_ENABLE; \ type DCP_HIGHPASS_RANDOM_ENABLE; \ type DENORM_MODE; \ + type INTERLEAVE_EN; \ type PIXEL_DEPTH; \ type PIXEL_EXPAN_MODE; \ type GAMUT_REMAP_C11; \ @@ -365,12 +505,20 @@ type SCL_V_SCALE_RATIO; \ type SCL_H_INIT_INT; \ type SCL_H_INIT_FRAC; \ + type SCL_H_INIT_INT_RGB_Y; \ + type SCL_H_INIT_FRAC_RGB_Y; \ + type SCL_H_INIT_INT_CBCR; \ + type SCL_H_INIT_FRAC_CBCR; \ type SCL_V_INIT_INT; \ type SCL_V_INIT_FRAC; \ + type DC_LB_MEMORY_CONFIG; \ + type DC_LB_MEM_SIZE; \ type LB_MEMORY_CONFIG; \ type LB_MEMORY_SIZE; \ type SCL_V_2TAP_HARDCODE_COEF_EN; \ type SCL_H_2TAP_HARDCODE_COEF_EN; \ + type SCL_V_FILTER_PICK_NEAREST; \ + type SCL_H_FILTER_PICK_NEAREST; \ type SCL_COEF_UPDATE_COMPLETE; \ type ALPHA_EN @@ -383,6 +531,9 @@ struct dce_transform_mask { }; struct dce_transform_registers { +#if defined(CONFIG_DRM_AMD_DC_SI) + uint32_t DATA_FORMAT; +#endif uint32_t LB_DATA_FORMAT; uint32_t GAMUT_REMAP_CONTROL; uint32_t GAMUT_REMAP_C11_C12; @@ -438,8 +589,16 @@ struct dce_transform_registers { uint32_t SCL_HORZ_FILTER_SCALE_RATIO; uint32_t SCL_VERT_FILTER_SCALE_RATIO; uint32_t SCL_HORZ_FILTER_INIT; +#if defined(CONFIG_DRM_AMD_DC_SI) + uint32_t SCL_HORZ_FILTER_INIT_RGB_LUMA; + uint32_t SCL_HORZ_FILTER_INIT_CHROMA; +#endif uint32_t SCL_VERT_FILTER_INIT; uint32_t SCL_AUTOMATIC_MODE_CONTROL; +#if defined(CONFIG_DRM_AMD_DC_SI) + uint32_t DC_LB_MEMORY_SPLIT; + uint32_t DC_LB_MEM_SIZE; +#endif uint32_t LB_MEMORY_CTRL; uint32_t SCL_UPDATE; uint32_t SCL_F_SHARP_CONTROL; @@ -457,6 +616,16 @@ struct scl_ratios_inits { struct init_int_and_frac v_init; }; +#if defined(CONFIG_DRM_AMD_DC_SI) +struct sclh_ratios_inits { + uint32_t h_int_scale_ratio; + uint32_t v_int_scale_ratio; + struct init_int_and_frac h_init_luma; + struct init_int_and_frac h_init_chroma; + struct init_int_and_frac v_init; +}; +#endif + enum ram_filter_type { FILTER_TYPE_RGB_Y_VERTICAL = 0, /* 0 - RGB/Y Vertical filter */ FILTER_TYPE_CBCR_VERTICAL = 1, /* 1 - CbCr Vertical filter */ @@ -489,6 +658,15 @@ void dce_transform_construct(struct dce_transform *xfm_dce, const struct dce_transform_shift *xfm_shift, const struct dce_transform_mask *xfm_mask); +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_transform_construct(struct dce_transform *xfm_dce, + struct dc_context *ctx, + uint32_t inst, + const struct dce_transform_registers *regs, + const struct dce_transform_shift *xfm_shift, + const struct dce_transform_mask *xfm_mask); +#endif + bool dce_transform_get_optimal_number_of_taps( struct transform *xfm, struct scaler_data *scl_data, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 45c9e9027886..0603ddca7bd0 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -720,6 +720,7 @@ void dce110_edp_wait_for_hpd_ready( struct dc_context *ctx = link->ctx; struct graphics_object_id connector = link->link_enc->connector; struct gpio *hpd; + struct dc_sink *sink = link->local_sink; bool edp_hpd_high = false; uint32_t time_elapsed = 0; uint32_t timeout = power_up ? @@ -752,6 +753,14 @@ void dce110_edp_wait_for_hpd_ready( return; } + if (sink != NULL) { + if (sink->edid_caps.panel_patch.extra_t3_ms > 0) { + int extra_t3_in_ms = sink->edid_caps.panel_patch.extra_t3_ms; + + msleep(extra_t3_in_ms); + } + } + dal_gpio_open(hpd, GPIO_MODE_INTERRUPT); /* wait until timeout or panel detected */ diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 5d83e8174005..0853bc9917c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -1017,7 +1017,7 @@ enum dc_status dce112_add_stream_to_ctx( struct dc_state *new_ctx, struct dc_stream_state *dc_stream) { - enum dc_status result = DC_ERROR_UNEXPECTED; + enum dc_status result; result = resource_map_pool_resources(dc, new_ctx, dc_stream); diff --git a/drivers/gpu/drm/amd/display/dc/dce60/Makefile b/drivers/gpu/drm/amd/display/dc/dce60/Makefile new file mode 100644 index 000000000000..7036c3bd0f87 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce60/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2020 Mauro Rossi <[email protected]> +# +# 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. +# +# +# Makefile for the 'controller' sub-component of DAL. +# It provides the control and status of HW CRTC block. + +DCE60 = dce60_timing_generator.o dce60_hw_sequencer.o \ + dce60_resource.o + +AMD_DAL_DCE60 = $(addprefix $(AMDDALPATH)/dc/dce60/,$(DCE60)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DCE60) + + + diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.c new file mode 100644 index 000000000000..920c7ae29d53 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.c @@ -0,0 +1,432 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dc.h" +#include "core_types.h" +#include "dce60_hw_sequencer.h" + +#include "dce/dce_hwseq.h" +#include "dce110/dce110_hw_sequencer.h" +#include "dce100/dce100_hw_sequencer.h" + +/* include DCE6 register header files */ +#include "dce/dce_6_0_d.h" +#include "dce/dce_6_0_sh_mask.h" + +#define DC_LOGGER_INIT() + +/******************************************************************************* + * Private definitions + ******************************************************************************/ + +/***************************PIPE_CONTROL***********************************/ + +/* + * Check if FBC can be enabled + */ +static bool dce60_should_enable_fbc(struct dc *dc, + struct dc_state *context, + uint32_t *pipe_idx) +{ + uint32_t i; + struct pipe_ctx *pipe_ctx = NULL; + struct resource_context *res_ctx = &context->res_ctx; + unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; + + + ASSERT(dc->fbc_compressor); + + /* FBC memory should be allocated */ + if (!dc->ctx->fbc_gpu_addr) + return false; + + /* Only supports single display */ + if (context->stream_count != 1) + return false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (res_ctx->pipe_ctx[i].stream) { + + pipe_ctx = &res_ctx->pipe_ctx[i]; + + if (!pipe_ctx) + continue; + + /* fbc not applicable on underlay pipe */ + if (pipe_ctx->pipe_idx != underlay_idx) { + *pipe_idx = i; + break; + } + } + } + + if (i == dc->res_pool->pipe_count) + return false; + + if (!pipe_ctx->stream->link) + return false; + + /* Only supports eDP */ + if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP) + return false; + + /* PSR should not be enabled */ + if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled) + return false; + + /* Nothing to compress */ + if (!pipe_ctx->plane_state) + return false; + + /* Only for non-linear tiling */ + if (pipe_ctx->plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL) + return false; + + return true; +} + +/* + * Enable FBC + */ +static void dce60_enable_fbc( + struct dc *dc, + struct dc_state *context) +{ + uint32_t pipe_idx = 0; + + if (dce60_should_enable_fbc(dc, context, &pipe_idx)) { + /* Program GRPH COMPRESSED ADDRESS and PITCH */ + struct compr_addr_and_pitch_params params = {0, 0, 0}; + struct compressor *compr = dc->fbc_compressor; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; + + params.source_view_width = pipe_ctx->stream->timing.h_addressable; + params.source_view_height = pipe_ctx->stream->timing.v_addressable; + params.inst = pipe_ctx->stream_res.tg->inst; + compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr; + + compr->funcs->surface_address_and_pitch(compr, ¶ms); + compr->funcs->set_fbc_invalidation_triggers(compr, 1); + + compr->funcs->enable_fbc(compr, ¶ms); + } +} + + +/******************************************************************************* + * Front End programming + ******************************************************************************/ + +static void dce60_set_default_colors(struct pipe_ctx *pipe_ctx) +{ + struct default_adjustment default_adjust = { 0 }; + + default_adjust.force_hw_default = false; + default_adjust.in_color_space = pipe_ctx->plane_state->color_space; + default_adjust.out_color_space = pipe_ctx->stream->output_color_space; + default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW; + default_adjust.surface_pixel_format = pipe_ctx->plane_res.scl_data.format; + + /* display color depth */ + default_adjust.color_depth = + pipe_ctx->stream->timing.display_color_depth; + + /* Lb color depth */ + default_adjust.lb_color_depth = pipe_ctx->plane_res.scl_data.lb_params.depth; + + pipe_ctx->plane_res.xfm->funcs->opp_set_csc_default( + pipe_ctx->plane_res.xfm, &default_adjust); +} + +/******************************************************************************* + * In order to turn on surface we will program + * CRTC + * + * DCE6 has no bottom_pipe and no Blender HW + * We need to set 'blank_target' to false in order to turn on the display + * + * |-----------|------------|---------| + * |curr pipe | set_blank | | + * |Surface |blank_target| CRCT | + * |visibility | argument | | + * |-----------|------------|---------| + * | off | true | blank | + * | on | false | unblank | + * |-----------|------------|---------| + * + ******************************************************************************/ +static void dce60_program_surface_visibility(const struct dc *dc, + struct pipe_ctx *pipe_ctx) +{ + bool blank_target = false; + + /* DCE6 has no bottom_pipe and no Blender HW */ + + if (!pipe_ctx->plane_state->visible) + blank_target = true; + + /* DCE6 skip dce_set_blender_mode() but then proceed to 'unblank' CRTC */ + pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, blank_target); + +} + + +static void dce60_get_surface_visual_confirm_color(const struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->stream_res.tg->inst) / 4; + + switch (pipe_ctx->plane_res.scl_data.format) { + case PIXEL_FORMAT_ARGB8888: + /* set boarder color to red */ + color->color_r_cr = color_value; + break; + + case PIXEL_FORMAT_ARGB2101010: + /* set boarder color to blue */ + color->color_b_cb = color_value; + break; + case PIXEL_FORMAT_420BPP8: + /* set boarder color to green */ + color->color_g_y = color_value; + break; + case PIXEL_FORMAT_420BPP10: + /* set boarder color to yellow */ + color->color_g_y = color_value; + color->color_r_cr = color_value; + break; + case PIXEL_FORMAT_FP16: + /* set boarder color to white */ + color->color_r_cr = color_value; + color->color_b_cb = color_value; + color->color_g_y = color_value; + break; + default: + break; + } +} + +static void dce60_program_scaler(const struct dc *dc, + const struct pipe_ctx *pipe_ctx) +{ + struct tg_color color = {0}; + + /* DCE6 skips DCN TOFPGA check for transform_set_pixel_storage_depth == NULL */ + + if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) + dce60_get_surface_visual_confirm_color(pipe_ctx, &color); + else + color_space_to_black_color(dc, + pipe_ctx->stream->output_color_space, + &color); + + pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth( + pipe_ctx->plane_res.xfm, + pipe_ctx->plane_res.scl_data.lb_params.depth, + &pipe_ctx->stream->bit_depth_params); + + if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) { + /* + * The way 420 is packed, 2 channels carry Y component, 1 channel + * alternate between Cb and Cr, so both channels need the pixel + * value for Y + */ + if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + color.color_r_cr = color.color_g_y; + + pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color( + pipe_ctx->stream_res.tg, + &color); + } + + pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(pipe_ctx->plane_res.xfm, + &pipe_ctx->plane_res.scl_data); +} + +static void +dce60_program_front_end_for_pipe( + struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct mem_input *mi = pipe_ctx->plane_res.mi; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct xfm_grph_csc_adjustment adjust; + struct out_csc_color_matrix tbl_entry; + unsigned int i; + struct dce_hwseq *hws = dc->hwseq; + + DC_LOGGER_INIT(); + memset(&tbl_entry, 0, sizeof(tbl_entry)); + + memset(&adjust, 0, sizeof(adjust)); + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + dce_enable_fe_clock(dc->hwseq, mi->inst, true); + + dce60_set_default_colors(pipe_ctx); + if (pipe_ctx->stream->csc_color_matrix.enable_adjustment + == true) { + tbl_entry.color_space = + pipe_ctx->stream->output_color_space; + + for (i = 0; i < 12; i++) + tbl_entry.regval[i] = + pipe_ctx->stream->csc_color_matrix.matrix[i]; + + pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment + (pipe_ctx->plane_res.xfm, &tbl_entry); + } + + if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; + } + + pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); + + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0; + + dce60_program_scaler(dc, pipe_ctx); + + mi->funcs->mem_input_program_surface_config( + mi, + plane_state->format, + &plane_state->tiling_info, + &plane_state->plane_size, + plane_state->rotation, + NULL, + false); + if (mi->funcs->set_blank) + mi->funcs->set_blank(mi, pipe_ctx->plane_state->visible); + + if (dc->config.gpu_vm_support) + mi->funcs->mem_input_program_pte_vm( + pipe_ctx->plane_res.mi, + plane_state->format, + &plane_state->tiling_info, + plane_state->rotation); + + /* Moved programming gamma from dc to hwss */ + if (pipe_ctx->plane_state->update_flags.bits.full_update || + pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || + pipe_ctx->plane_state->update_flags.bits.gamma_change) + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); + + if (pipe_ctx->plane_state->update_flags.bits.full_update) + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); + + DC_LOG_SURFACE( + "Pipe:%d %p: addr hi:0x%x, " + "addr low:0x%x, " + "src: %d, %d, %d," + " %d; dst: %d, %d, %d, %d;" + "clip: %d, %d, %d, %d\n", + pipe_ctx->pipe_idx, + (void *) pipe_ctx->plane_state, + pipe_ctx->plane_state->address.grph.addr.high_part, + pipe_ctx->plane_state->address.grph.addr.low_part, + pipe_ctx->plane_state->src_rect.x, + pipe_ctx->plane_state->src_rect.y, + pipe_ctx->plane_state->src_rect.width, + pipe_ctx->plane_state->src_rect.height, + pipe_ctx->plane_state->dst_rect.x, + pipe_ctx->plane_state->dst_rect.y, + pipe_ctx->plane_state->dst_rect.width, + pipe_ctx->plane_state->dst_rect.height, + pipe_ctx->plane_state->clip_rect.x, + pipe_ctx->plane_state->clip_rect.y, + pipe_ctx->plane_state->clip_rect.width, + pipe_ctx->plane_state->clip_rect.height); + + DC_LOG_SURFACE( + "Pipe %d: width, height, x, y\n" + "viewport:%d, %d, %d, %d\n" + "recout: %d, %d, %d, %d\n", + pipe_ctx->pipe_idx, + pipe_ctx->plane_res.scl_data.viewport.width, + pipe_ctx->plane_res.scl_data.viewport.height, + pipe_ctx->plane_res.scl_data.viewport.x, + pipe_ctx->plane_res.scl_data.viewport.y, + pipe_ctx->plane_res.scl_data.recout.width, + pipe_ctx->plane_res.scl_data.recout.height, + pipe_ctx->plane_res.scl_data.recout.x, + pipe_ctx->plane_res.scl_data.recout.y); +} + +static void dce60_apply_ctx_for_surface( + struct dc *dc, + const struct dc_stream_state *stream, + int num_planes, + struct dc_state *context) +{ + int i; + + if (num_planes == 0) + return; + + if (dc->fbc_compressor) + dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream != stream) + continue; + + /* Need to allocate mem before program front end for Fiji */ + pipe_ctx->plane_res.mi->funcs->allocate_mem_input( + pipe_ctx->plane_res.mi, + pipe_ctx->stream->timing.h_total, + pipe_ctx->stream->timing.v_total, + pipe_ctx->stream->timing.pix_clk_100hz / 10, + context->stream_count); + + dce60_program_front_end_for_pipe(dc, pipe_ctx); + + dc->hwss.update_plane_addr(dc, pipe_ctx); + + dce60_program_surface_visibility(dc, pipe_ctx); + + } + + if (dc->fbc_compressor) + dce60_enable_fbc(dc, context); +} + +void dce60_hw_sequencer_construct(struct dc *dc) +{ + dce110_hw_sequencer_construct(dc); + + dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating; + dc->hwss.apply_ctx_for_surface = dce60_apply_ctx_for_surface; + dc->hwss.cursor_lock = dce60_pipe_control_lock; + dc->hwss.pipe_control_lock = dce60_pipe_control_lock; + dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth; + dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.h new file mode 100644 index 000000000000..f3b2d8b60d5b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCE60_H__ +#define __DC_HWSS_DCE60_H__ + +#include "core_types.h" +#include "hw_sequencer_private.h" + +struct dc; + +void dce60_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_HWSS_DCE60_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c new file mode 100644 index 000000000000..5a5a9cb77acb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c @@ -0,0 +1,1527 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#include <linux/slab.h> + +#include "dce/dce_6_0_d.h" +#include "dce/dce_6_0_sh_mask.h" + +#include "dm_services.h" + +#include "link_encoder.h" +#include "stream_encoder.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "irq/dce60/irq_service_dce60.h" +#include "dce110/dce110_timing_generator.h" +#include "dce110/dce110_resource.h" +#include "dce60/dce60_timing_generator.h" +#include "dce/dce_mem_input.h" +#include "dce/dce_link_encoder.h" +#include "dce/dce_stream_encoder.h" +#include "dce/dce_ipp.h" +#include "dce/dce_transform.h" +#include "dce/dce_opp.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "dce60/dce60_hw_sequencer.h" +#include "dce100/dce100_resource.h" +#include "dce/dce_panel_cntl.h" + +#include "reg_helper.h" + +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_abm.h" +#include "dce/dce_i2c.h" +/* TODO remove this include */ + +#ifndef mmMC_HUB_RDREQ_DMIF_LIMIT +#include "gmc/gmc_6_0_d.h" +#include "gmc/gmc_6_0_sh_mask.h" +#endif + +#ifndef mmDP_DPHY_INTERNAL_CTRL +#define mmDP_DPHY_INTERNAL_CTRL 0x1CDE +#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x1CDE +#define mmDP1_DP_DPHY_INTERNAL_CTRL 0x1FDE +#define mmDP2_DP_DPHY_INTERNAL_CTRL 0x42DE +#define mmDP3_DP_DPHY_INTERNAL_CTRL 0x45DE +#define mmDP4_DP_DPHY_INTERNAL_CTRL 0x48DE +#define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4BDE +#endif + + +#ifndef mmBIOS_SCRATCH_2 + #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC + #define mmBIOS_SCRATCH_6 0x05CF +#endif + +#ifndef mmDP_DPHY_FAST_TRAINING + #define mmDP_DPHY_FAST_TRAINING 0x1CCE + #define mmDP0_DP_DPHY_FAST_TRAINING 0x1CCE + #define mmDP1_DP_DPHY_FAST_TRAINING 0x1FCE + #define mmDP2_DP_DPHY_FAST_TRAINING 0x42CE + #define mmDP3_DP_DPHY_FAST_TRAINING 0x45CE + #define mmDP4_DP_DPHY_FAST_TRAINING 0x48CE + #define mmDP5_DP_DPHY_FAST_TRAINING 0x4BCE +#endif + + +#ifndef mmHPD_DC_HPD_CONTROL + #define mmHPD_DC_HPD_CONTROL 0x189A + #define mmHPD0_DC_HPD_CONTROL 0x189A + #define mmHPD1_DC_HPD_CONTROL 0x18A2 + #define mmHPD2_DC_HPD_CONTROL 0x18AA + #define mmHPD3_DC_HPD_CONTROL 0x18B2 + #define mmHPD4_DC_HPD_CONTROL 0x18BA + #define mmHPD5_DC_HPD_CONTROL 0x18C2 +#endif + +#define DCE11_DIG_FE_CNTL 0x4a00 +#define DCE11_DIG_BE_CNTL 0x4a47 +#define DCE11_DP_SEC 0x4ac3 + +static const struct dce110_timing_generator_offsets dce60_tg_offsets[] = { + { + .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmGRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG0_DPG_PIPE_ARBITRATION_CONTROL3 + - mmDPG_PIPE_ARBITRATION_CONTROL3), + }, + { + .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG1_DPG_PIPE_ARBITRATION_CONTROL3 + - mmDPG_PIPE_ARBITRATION_CONTROL3), + }, + { + .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG2_DPG_PIPE_ARBITRATION_CONTROL3 + - mmDPG_PIPE_ARBITRATION_CONTROL3), + }, + { + .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG3_DPG_PIPE_ARBITRATION_CONTROL3 + - mmDPG_PIPE_ARBITRATION_CONTROL3), + }, + { + .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG4_DPG_PIPE_ARBITRATION_CONTROL3 + - mmDPG_PIPE_ARBITRATION_CONTROL3), + }, + { + .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG5_DPG_PIPE_ARBITRATION_CONTROL3 + - mmDPG_PIPE_ARBITRATION_CONTROL3), + } +}; + +/* set register offset */ +#define SR(reg_name)\ + .reg_name = mm ## reg_name + +/* set register offset with instance */ +#define SRI(reg_name, block, id)\ + .reg_name = mm ## block ## id ## _ ## reg_name + +#define ipp_regs(id)\ +[id] = {\ + IPP_COMMON_REG_LIST_DCE_BASE(id)\ +} + +static const struct dce_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), + ipp_regs(4), + ipp_regs(5) +}; + +static const struct dce_ipp_shift ipp_shift = { + IPP_DCE60_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce_ipp_mask ipp_mask = { + IPP_DCE60_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +#define transform_regs(id)\ +[id] = {\ + XFM_COMMON_REG_LIST_DCE60(id)\ +} + +static const struct dce_transform_registers xfm_regs[] = { + transform_regs(0), + transform_regs(1), + transform_regs(2), + transform_regs(3), + transform_regs(4), + transform_regs(5) +}; + +static const struct dce_transform_shift xfm_shift = { + XFM_COMMON_MASK_SH_LIST_DCE60(__SHIFT) +}; + +static const struct dce_transform_mask xfm_mask = { + XFM_COMMON_MASK_SH_LIST_DCE60(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + AUX_REG_LIST(id)\ +} + +static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id)\ +[id] = {\ + LE_DCE60_REG_LIST(id)\ +} + +static const struct dce110_link_enc_registers link_enc_regs[] = { + link_regs(0), + link_regs(1), + link_regs(2), + link_regs(3), + link_regs(4), + link_regs(5) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_COMMON_REG_LIST_DCE_BASE(id),\ + .AFMT_CNTL = 0,\ +} + +static const struct dce110_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), + stream_enc_regs(5) +}; + +static const struct dce_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCE80_100(__SHIFT) +}; + +static const struct dce_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCE80_100(_MASK) +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCE_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_DCE_60_REG_LIST(id),\ +} + +static const struct dce_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5) +}; + +static const struct dce_opp_shift opp_shift = { + OPP_COMMON_MASK_SH_LIST_DCE_60(__SHIFT) +}; + +static const struct dce_opp_mask opp_mask = { + OPP_COMMON_MASK_SH_LIST_DCE_60(_MASK) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCE10_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCE10_AUX_MASK_SH_LIST(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), +}; + +static const struct dce_audio_shift audio_shift = { + AUD_DCE60_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + AUD_DCE60_MASK_SH_LIST(_MASK) +}; + +#define clk_src_regs(id)\ +[id] = {\ + CS_COMMON_REG_LIST_DCE_80(id),\ +} + + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0), + clk_src_regs(1), + clk_src_regs(2) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, + .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 +}; + +static const struct resource_caps res_cap = { + .num_timing_generator = 6, + .num_audio = 6, + .num_stream_encoder = 6, + .num_pll = 2, + .num_ddc = 6, +}; + +static const struct resource_caps res_cap_61 = { + .num_timing_generator = 4, + .num_audio = 6, + .num_stream_encoder = 6, + .num_pll = 3, + .num_ddc = 6, +}; + +static const struct resource_caps res_cap_64 = { + .num_timing_generator = 2, + .num_audio = 2, + .num_stream_encoder = 2, + .num_pll = 2, + .num_ddc = 2, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCE_RGB, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = false, + .fp16 = false + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 1, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 1, + .fp16 = 1 + } +}; + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE60_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE60(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE60(_MASK) +}; +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; + +#define CTX ctx +#define REG(reg) mm ## reg + +#ifndef mmCC_DC_HDMI_STRAPS +#define mmCC_DC_HDMI_STRAPS 0x1918 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 +#endif + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + break; + case TRANSMITTER_UNIPHY_B: + return 1; + break; + case TRANSMITTER_UNIPHY_C: + return 2; + break; + case TRANSMITTER_UNIPHY_D: + return 3; + break; + case TRANSMITTER_UNIPHY_E: + return 4; + break; + case TRANSMITTER_UNIPHY_F: + return 5; + break; + case TRANSMITTER_UNIPHY_G: + return 6; + break; + default: + ASSERT(0); + return 0; + } +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + REG_GET_2(CC_DC_HDMI_STRAPS, + HDMI_DISABLE, &straps->hdmi_disable, + AUDIO_STREAM_NUMBER, &straps->audio_stream_number); + + REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); +} + +static struct audio *create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce60_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct timing_generator *dce60_timing_generator_create( + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets) +{ + struct dce110_timing_generator *tg110 = + kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); + + if (!tg110) + return NULL; + + dce60_timing_generator_construct(tg110, ctx, instance, offsets); + return &tg110->base; +} + +static struct output_pixel_processor *dce60_opp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce110_opp *opp = + kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); + + if (!opp) + return NULL; + + dce60_opp_construct(opp, + ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +struct dce_aux *dce60_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +struct dce_i2c_hw *dce60_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dce_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +struct dce_i2c_sw *dce60_i2c_sw_create( + struct dc_context *ctx) +{ + struct dce_i2c_sw *dce_i2c_sw = + kzalloc(sizeof(struct dce_i2c_sw), GFP_KERNEL); + + if (!dce_i2c_sw) + return NULL; + + dce_i2c_sw_construct(dce_i2c_sw, ctx); + + return dce_i2c_sw; +} +static struct stream_encoder *dce60_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dce110_stream_encoder *enc110 = + kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); + + if (!enc110) + return NULL; + + dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + return &enc110->base; +} + +#define SRII(reg_name, block, id)\ + .reg_name[id] = mm ## block ## id ## _ ## reg_name + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCE6_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCE6_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCE6_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dce60_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dce60_stream_encoder_create, + .create_hwseq = dce60_hwseq_create, +}; + +#define mi_inst_regs(id) { \ + MI_DCE6_REG_LIST(id), \ + .MC_HUB_RDREQ_DMIF_LIMIT = mmMC_HUB_RDREQ_DMIF_LIMIT \ +} +static const struct dce_mem_input_registers mi_regs[] = { + mi_inst_regs(0), + mi_inst_regs(1), + mi_inst_regs(2), + mi_inst_regs(3), + mi_inst_regs(4), + mi_inst_regs(5), +}; + +static const struct dce_mem_input_shift mi_shifts = { + MI_DCE6_MASK_SH_LIST(__SHIFT), + .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE__SHIFT +}; + +static const struct dce_mem_input_mask mi_masks = { + MI_DCE6_MASK_SH_LIST(_MASK), + .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE_MASK +}; + +static struct mem_input *dce60_mem_input_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), + GFP_KERNEL); + + if (!dce_mi) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce60_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); + dce_mi->wa.single_head_rdreq_dmif_limit = 2; + return &dce_mi->base; +} + +static void dce60_transform_destroy(struct transform **xfm) +{ + kfree(TO_DCE_TRANSFORM(*xfm)); + *xfm = NULL; +} + +static struct transform *dce60_transform_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_transform *transform = + kzalloc(sizeof(struct dce_transform), GFP_KERNEL); + + if (!transform) + return NULL; + + dce60_transform_construct(transform, ctx, inst, + &xfm_regs[inst], &xfm_shift, &xfm_mask); + transform->prescaler_on = false; + return &transform->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 297000, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true +}; + +struct link_encoder *dce60_link_encoder_create( + const struct encoder_init_data *enc_init_data) +{ + struct dce110_link_encoder *enc110 = + kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc110) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dce60_link_encoder_construct(enc110, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +} + +static struct panel_cntl *dce60_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +struct clock_source *dce60_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dce110_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +void dce60_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + +static struct input_pixel_processor *dce60_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce60_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + +static void dce60_resource_destruct(struct dce110_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.opps[i] != NULL) + dce110_opp_destroy(&pool->base.opps[i]); + + if (pool->base.transforms[i] != NULL) + dce60_transform_destroy(&pool->base.transforms[i]); + + if (pool->base.ipps[i] != NULL) + dce_ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.mis[i] != NULL) { + kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); + pool->base.mis[i] = NULL; + } + + if (pool->base.timing_generators[i] != NULL) { + kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) + kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dce60_clock_source_destroy(&pool->base.clock_sources[i]); + } + } + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.dp_clock_source != NULL) + dce60_clock_source_destroy(&pool->base.dp_clock_source); + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i] != NULL) { + dce_aud_destroy(&pool->base.audios[i]); + } + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } +} + +bool dce60_validate_bandwidth( + struct dc *dc, + struct dc_state *context, + bool fast_validate) +{ + int i; + bool at_least_one_pipe = false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].stream) + at_least_one_pipe = true; + } + + if (at_least_one_pipe) { + /* TODO implement when needed but for now hardcode max value*/ + context->bw_ctx.bw.dce.dispclk_khz = 681000; + context->bw_ctx.bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ; + } else { + context->bw_ctx.bw.dce.dispclk_khz = 0; + context->bw_ctx.bw.dce.yclk_khz = 0; + } + + return true; +} + +static bool dce60_validate_surface_sets( + struct dc_state *context) +{ + int i; + + for (i = 0; i < context->stream_count; i++) { + if (context->stream_status[i].plane_count == 0) + continue; + + if (context->stream_status[i].plane_count > 1) + return false; + + if (context->stream_status[i].plane_states[0]->format + >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) + return false; + } + + return true; +} + +enum dc_status dce60_validate_global( + struct dc *dc, + struct dc_state *context) +{ + if (!dce60_validate_surface_sets(context)) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +static void dce60_destroy_resource_pool(struct resource_pool **pool) +{ + struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); + + dce60_resource_destruct(dce110_pool); + kfree(dce110_pool); + *pool = NULL; +} + +static const struct resource_funcs dce60_res_pool_funcs = { + .destroy = dce60_destroy_resource_pool, + .link_enc_create = dce60_link_encoder_create, + .panel_cntl_create = dce60_panel_cntl_create, + .validate_bandwidth = dce60_validate_bandwidth, + .validate_plane = dce100_validate_plane, + .add_stream_to_ctx = dce100_add_stream_to_ctx, + .validate_global = dce60_validate_global, + .find_first_free_match_stream_enc_for_link = dce100_find_first_free_match_stream_enc_for_link +}; + +static bool dce60_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + struct dc_bios *bp; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap; + pool->base.funcs = &dce60_res_pool_funcs; + + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = res_cap.num_timing_generator; + pool->base.timing_generator_count = res_cap.num_timing_generator; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 64; + dc->caps.dual_link_dvi = true; + dc->caps.extended_aux_timeout_support = false; + + /************************************************* + * Create resources * + *************************************************/ + + bp = ctx->dc_bios; + + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { + pool->base.dp_clock_source = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); + + pool->base.clock_sources[0] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false); + pool->base.clock_sources[1] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clk_src_count = 2; + + } else { + pool->base.dp_clock_source = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true); + + pool->base.clock_sources[0] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clk_src_count = 1; + } + + if (pool->base.dp_clock_source == NULL) { + dm_error("DC: failed to create dp clock source!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce60_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = dce60_timing_generator_create( + ctx, i, &dce60_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce60_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce60_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce60_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce60_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce60_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce60_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = dce60_i2c_sw_create(ctx); + if (pool->base.sw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create sw i2c!!\n"); + goto res_create_fail; + } + } + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->caps.disable_dp_clk_share = true; + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + dce60_hw_sequencer_construct(dc); + + return true; + +res_create_fail: + dce60_resource_destruct(pool); + return false; +} + +struct resource_pool *dce60_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce60_construct(num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool dce61_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + struct dc_bios *bp; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_61; + pool->base.funcs = &dce60_res_pool_funcs; + + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = res_cap_61.num_timing_generator; + pool->base.timing_generator_count = res_cap_61.num_timing_generator; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 64; + dc->caps.is_apu = true; + + /************************************************* + * Create resources * + *************************************************/ + + bp = ctx->dc_bios; + + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { + pool->base.dp_clock_source = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); + + pool->base.clock_sources[0] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false); + pool->base.clock_sources[1] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clock_sources[2] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); + pool->base.clk_src_count = 3; + + } else { + pool->base.dp_clock_source = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true); + + pool->base.clock_sources[0] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clock_sources[1] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); + pool->base.clk_src_count = 2; + } + + if (pool->base.dp_clock_source == NULL) { + dm_error("DC: failed to create dp clock source!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce60_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = dce60_timing_generator_create( + ctx, i, &dce60_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce60_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce60_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce60_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce60_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce60_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce60_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = dce60_i2c_sw_create(ctx); + if (pool->base.sw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create sw i2c!!\n"); + goto res_create_fail; + } + } + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->caps.disable_dp_clk_share = true; + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + dce60_hw_sequencer_construct(dc); + + return true; + +res_create_fail: + dce60_resource_destruct(pool); + return false; +} + +struct resource_pool *dce61_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce61_construct(num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool dce64_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + struct dc_bios *bp; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_64; + pool->base.funcs = &dce60_res_pool_funcs; + + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = res_cap_64.num_timing_generator; + pool->base.timing_generator_count = res_cap_64.num_timing_generator; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 64; + dc->caps.is_apu = true; + + /************************************************* + * Create resources * + *************************************************/ + + bp = ctx->dc_bios; + + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { + pool->base.dp_clock_source = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); + + pool->base.clock_sources[0] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[0], false); + pool->base.clock_sources[1] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[1], false); + pool->base.clk_src_count = 2; + + } else { + pool->base.dp_clock_source = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[0], true); + + pool->base.clock_sources[0] = + dce60_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[1], false); + pool->base.clk_src_count = 1; + } + + if (pool->base.dp_clock_source == NULL) { + dm_error("DC: failed to create dp clock source!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce60_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = dce60_timing_generator_create( + ctx, i, &dce60_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce60_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce60_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce60_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce60_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce60_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce60_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = dce60_i2c_sw_create(ctx); + if (pool->base.sw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create sw i2c!!\n"); + goto res_create_fail; + } + } + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->caps.disable_dp_clk_share = true; + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + dce60_hw_sequencer_construct(dc); + + return true; + +res_create_fail: + dce60_resource_destruct(pool); + return false; +} + +struct resource_pool *dce64_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce64_construct(num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.h b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.h new file mode 100644 index 000000000000..5d653a76b0b0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.h @@ -0,0 +1,47 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#ifndef __DC_RESOURCE_DCE60_H__ +#define __DC_RESOURCE_DCE60_H__ + +#include "core_types.h" + +struct dc; +struct resource_pool; + +struct resource_pool *dce60_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +struct resource_pool *dce61_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +struct resource_pool *dce64_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +#endif /* __DC_RESOURCE_DCE60_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce60/dce60_timing_generator.c new file mode 100644 index 000000000000..fc1af0ff0ca4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_timing_generator.c @@ -0,0 +1,266 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#include "dm_services.h" + +/* include DCE6 register header files */ +#include "dce/dce_6_0_d.h" +#include "dce/dce_6_0_sh_mask.h" + +#include "dc_types.h" + +#include "include/grph_object_id.h" +#include "include/logger_interface.h" +#include "../dce110/dce110_timing_generator.h" +#include "dce60_timing_generator.h" + +#include "timing_generator.h" + +enum black_color_format { + BLACK_COLOR_FORMAT_RGB_FULLRANGE = 0, /* used as index in array */ + BLACK_COLOR_FORMAT_RGB_LIMITED, + BLACK_COLOR_FORMAT_YUV_TV, + BLACK_COLOR_FORMAT_YUV_CV, + BLACK_COLOR_FORMAT_YUV_SUPER_AA, + + BLACK_COLOR_FORMAT_COUNT +}; + +static const struct dce110_timing_generator_offsets reg_offsets[] = { +{ + .crtc = (mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), + .dcp = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), +}, +{ + .crtc = (mmCRTC1_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), + .dcp = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), +}, +{ + .crtc = (mmCRTC2_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), + .dcp = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), +}, +{ + .crtc = (mmCRTC3_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), + .dcp = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), +}, +{ + .crtc = (mmCRTC4_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), + .dcp = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), +}, +{ + .crtc = (mmCRTC5_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), + .dcp = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), +} +}; + +#define NUMBER_OF_FRAME_TO_WAIT_ON_TRIGGERED_RESET 10 + +#define MAX_H_TOTAL (CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1) +#define MAX_V_TOTAL (CRTC_V_TOTAL__CRTC_V_TOTAL_MASKhw + 1) + +#define CRTC_REG(reg) (reg + tg110->offsets.crtc) +#define DCP_REG(reg) (reg + tg110->offsets.dcp) +#define DMIF_REG(reg) (reg + tg110->offsets.dmif) + +static void program_pix_dur(struct timing_generator *tg, uint32_t pix_clk_100hz) +{ + uint64_t pix_dur; + uint32_t addr = mmDMIF_PG0_DPG_PIPE_ARBITRATION_CONTROL1 + + DCE110TG_FROM_TG(tg)->offsets.dmif; + uint32_t value = dm_read_reg(tg->ctx, addr); + + if (pix_clk_100hz == 0) + return; + + pix_dur = div_u64(10000000000ull, pix_clk_100hz); + + set_reg_field_value( + value, + pix_dur, + DPG_PIPE_ARBITRATION_CONTROL1, + PIXEL_DURATION); + + dm_write_reg(tg->ctx, addr, value); +} + +static void program_timing(struct timing_generator *tg, + const struct dc_crtc_timing *timing, + int vready_offset, + int vstartup_start, + int vupdate_offset, + int vupdate_width, + const enum signal_type signal, + bool use_vbios) +{ + if (!use_vbios) + program_pix_dur(tg, timing->pix_clk_100hz); + + dce110_tg_program_timing(tg, timing, 0, 0, 0, 0, 0, use_vbios); +} + +static void dce60_timing_generator_enable_advanced_request( + struct timing_generator *tg, + bool enable, + const struct dc_crtc_timing *timing) +{ + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = CRTC_REG(mmCRTC_START_LINE_CONTROL); + uint32_t value = dm_read_reg(tg->ctx, addr); + /* DCE6 has CRTC_PREFETCH_EN bit in CRTC_CONTROL register */ + uint32_t addr2 = CRTC_REG(mmCRTC_CONTROL); + uint32_t value2 = dm_read_reg(tg->ctx, addr2); + + /* DCE6 does not support CRTC_LEGACY_REQUESTOR_EN bit + so here is not possible to set bit based on enable argument */ + + if ((timing->v_sync_width + timing->v_front_porch) <= 3) { + set_reg_field_value( + value, + 3, + CRTC_START_LINE_CONTROL, + CRTC_ADVANCED_START_LINE_POSITION); + set_reg_field_value( + value2, + 0, + CRTC_CONTROL, + CRTC_PREFETCH_EN); + } else { + set_reg_field_value( + value, + 4, + CRTC_START_LINE_CONTROL, + CRTC_ADVANCED_START_LINE_POSITION); + set_reg_field_value( + value2, + 1, + CRTC_CONTROL, + CRTC_PREFETCH_EN); + } + + set_reg_field_value( + value, + 1, + CRTC_START_LINE_CONTROL, + CRTC_PROGRESSIVE_START_LINE_EARLY); + + set_reg_field_value( + value, + 1, + CRTC_START_LINE_CONTROL, + CRTC_INTERLACE_START_LINE_EARLY); + + dm_write_reg(tg->ctx, addr, value); + dm_write_reg(tg->ctx, addr2, value2); +} + +static bool dce60_is_tg_enabled(struct timing_generator *tg) +{ + uint32_t addr = 0; + uint32_t value = 0; + uint32_t field = 0; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + addr = CRTC_REG(mmCRTC_CONTROL); + value = dm_read_reg(tg->ctx, addr); + field = get_reg_field_value(value, CRTC_CONTROL, + CRTC_CURRENT_MASTER_EN_STATE); + return field == 1; +} + +bool dce60_configure_crc(struct timing_generator *tg, + const struct crc_params *params) +{ + /* Cannot configure crc on a CRTC that is disabled */ + if (!dce60_is_tg_enabled(tg)) + return false; + + /* DCE6 has no CRTC_CRC_CNTL register, nothing to do */ + + return true; +} + +static const struct timing_generator_funcs dce60_tg_funcs = { + .validate_timing = dce110_tg_validate_timing, + .program_timing = program_timing, + .enable_crtc = dce110_timing_generator_enable_crtc, + .disable_crtc = dce110_timing_generator_disable_crtc, + .is_counter_moving = dce110_timing_generator_is_counter_moving, + .get_position = dce110_timing_generator_get_position, + .get_frame_count = dce110_timing_generator_get_vblank_counter, + .get_scanoutpos = dce110_timing_generator_get_crtc_scanoutpos, + .set_early_control = dce110_timing_generator_set_early_control, + .wait_for_state = dce110_tg_wait_for_state, + .set_blank = dce110_tg_set_blank, + .is_blanked = dce110_tg_is_blanked, + .set_colors = dce110_tg_set_colors, + .set_overscan_blank_color = + dce110_timing_generator_set_overscan_color_black, + .set_blank_color = dce110_timing_generator_program_blank_color, + .disable_vga = dce110_timing_generator_disable_vga, + .did_triggered_reset_occur = + dce110_timing_generator_did_triggered_reset_occur, + .setup_global_swap_lock = + dce110_timing_generator_setup_global_swap_lock, + .enable_reset_trigger = dce110_timing_generator_enable_reset_trigger, + .disable_reset_trigger = dce110_timing_generator_disable_reset_trigger, + .tear_down_global_swap_lock = + dce110_timing_generator_tear_down_global_swap_lock, + .set_drr = dce110_timing_generator_set_drr, + .set_static_screen_control = + dce110_timing_generator_set_static_screen_control, + .set_test_pattern = dce110_timing_generator_set_test_pattern, + .arm_vert_intr = dce110_arm_vert_intr, + + /* DCE6.0 overrides */ + .enable_advanced_request = + dce60_timing_generator_enable_advanced_request, + .configure_crc = dce60_configure_crc, + .get_crc = dce110_get_crc, +}; + +void dce60_timing_generator_construct( + struct dce110_timing_generator *tg110, + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets) +{ + tg110->controller_id = CONTROLLER_ID_D0 + instance; + tg110->base.inst = instance; + tg110->offsets = *offsets; + tg110->derived_offsets = reg_offsets[instance]; + + tg110->base.funcs = &dce60_tg_funcs; + + tg110->base.ctx = ctx; + tg110->base.bp = ctx->dc_bios; + + tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; + tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; + + tg110->min_h_blank = 56; + tg110->min_h_front_porch = 4; + tg110->min_h_back_porch = 4; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dce60/dce60_timing_generator.h new file mode 100644 index 000000000000..81d831233cc5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_timing_generator.h @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#ifndef __DC_TIMING_GENERATOR_DCE60_H__ +#define __DC_TIMING_GENERATOR_DCE60_H__ + +#include "timing_generator.h" +#include "../include/grph_object_id.h" + +/* DCE6.0 implementation inherits from DCE11.0 */ +void dce60_timing_generator_construct( + struct dce110_timing_generator *tg, + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets); + +#endif /* __DC_TIMING_GENERATOR_DCE60_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index 62ad1a11bff9..733e6e6e43bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -31,4 +31,11 @@ DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \ AMD_DAL_DCN10 = $(addprefix $(AMDDALPATH)/dc/dcn10/,$(DCN10)) +# fix: +# ...: '-mgeneral-regs-only' is incompatible with the use of floating-point types +# aarch64 does not support soft-float, so use hard-float and handle this in code +ifdef CONFIG_ARM64 +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn10/dcn10_resource.o := -mgeneral-regs-only +endif + AMD_DISPLAY_FILES += $(AMD_DAL_DCN10) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index fa643ec5a876..8ca94f506195 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2377,14 +2377,6 @@ void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) &blnd_cfg.black_color); } - /* - * The way 420 is packed, 2 channels carry Y component, 1 channel - * alternate between Cb and Cr, so both channels need the pixel - * value for Y - */ - if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - blnd_cfg.black_color.color_r_cr = blnd_cfg.black_color.color_g_y; - if (per_pixel_alpha) blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; else @@ -2769,6 +2761,152 @@ static struct pipe_ctx *dcn10_find_top_pipe_for_stream( return NULL; } +bool dcn10_disconnect_pipes( + struct dc *dc, + struct dc_state *context) +{ + bool found_stream = false; + int i, j; + struct dce_hwseq *hws = dc->hwseq; + struct dc_state *old_ctx = dc->current_state; + bool mpcc_disconnected = false; + struct pipe_ctx *old_pipe; + struct pipe_ctx *new_pipe; + DC_LOGGER_INIT(dc->ctx->logger); + + /* Set pipe update flags and lock pipes */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + new_pipe = &context->res_ctx.pipe_ctx[i]; + new_pipe->update_flags.raw = 0; + + if (!old_pipe->plane_state && !new_pipe->plane_state) + continue; + + if (old_pipe->plane_state && !new_pipe->plane_state) + new_pipe->update_flags.bits.disable = 1; + + /* Check for scl update */ + if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data))) + new_pipe->update_flags.bits.scaler = 1; + + /* Check for vp update */ + if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect)) + || memcmp(&old_pipe->plane_res.scl_data.viewport_c, + &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect))) + new_pipe->update_flags.bits.viewport = 1; + + } + + if (!IS_DIAG_DC(dc->ctx->dce_environment)) { + /* Disconnect mpcc here only if losing pipe split*/ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && + old_ctx->res_ctx.pipe_ctx[i].top_pipe) { + + /* Find the top pipe in the new ctx for the bottom pipe that we + * want to remove by comparing the streams. If both pipes are being + * disabled then do it in the regular pipe programming sequence + */ + for (j = 0; j < dc->res_pool->pipe_count; j++) { + if (old_ctx->res_ctx.pipe_ctx[i].top_pipe->stream == context->res_ctx.pipe_ctx[j].stream && + !context->res_ctx.pipe_ctx[j].top_pipe && + !context->res_ctx.pipe_ctx[j].update_flags.bits.disable) { + found_stream = true; + break; + } + } + + // Disconnect if the top pipe lost it's pipe split + if (found_stream && !context->res_ctx.pipe_ctx[j].bottom_pipe) { + hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); + mpcc_disconnected = true; + } + } + found_stream = false; + } + } + + if (mpcc_disconnected) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + + if (!pipe_ctx || !plane_state || !pipe_ctx->stream) + continue; + + // Only update scaler and viewport here if we lose a pipe split. + // This is to prevent half the screen from being black when we + // unlock after disconnecting MPCC. + if (!(old_pipe && !pipe_ctx->top_pipe && + !pipe_ctx->bottom_pipe && old_pipe->bottom_pipe)) + continue; + + if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw) { + if (pipe_ctx->update_flags.bits.scaler || + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.position_change || + plane_state->update_flags.bits.per_pixel_alpha_change || + pipe_ctx->stream->update_flags.bits.scaling) { + + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; + ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_30BPP); + /* scaler configuration */ + pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( + pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); + } + + if (pipe_ctx->update_flags.bits.viewport || + (context == dc->current_state && plane_state->update_flags.bits.position_change) || + (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || + (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { + + hubp->funcs->mem_program_viewport( + hubp, + &pipe_ctx->plane_res.scl_data.viewport, + &pipe_ctx->plane_res.scl_data.viewport_c); + } + } + } + } + return mpcc_disconnected; +} + +void dcn10_wait_for_pending_cleared(struct dc *dc, + struct dc_state *context) +{ + struct pipe_ctx *pipe_ctx; + struct timing_generator *tg; + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe_ctx = &context->res_ctx.pipe_ctx[i]; + tg = pipe_ctx->stream_res.tg; + + /* + * Only wait for top pipe's tg penindg bit + * Also skip if pipe is disabled. + */ + if (pipe_ctx->top_pipe || + !pipe_ctx->stream || !pipe_ctx->plane_state || + !tg->funcs->is_tg_enabled(tg)) + continue; + + /* + * Wait for VBLANK then VACTIVE to ensure we get VUPDATE. + * For some reason waiting for OTG_UPDATE_PENDING cleared + * seems to not trigger the update right away, and if we + * lock again before VUPDATE then we don't get a separated + * operation. + */ + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); + } +} + void dcn10_apply_ctx_for_surface( struct dc *dc, const struct dc_stream_state *stream, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 6d891166da8a..e5691e499023 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -194,6 +194,12 @@ void dcn10_get_surface_visual_confirm_color( void dcn10_get_hdr_visual_confirm_color( struct pipe_ctx *pipe_ctx, struct tg_color *color); +bool dcn10_disconnect_pipes( + struct dc *dc, + struct dc_state *context); + +void dcn10_wait_for_pending_cleared(struct dc *dc, + struct dc_state *context); void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx); void dcn10_verify_allow_pstate_change_high(struct dc *dc); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c index 5c98b71c1d47..a1d1559bb5d7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -34,6 +34,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, .post_unlock_program_front_end = dcn10_post_unlock_program_front_end, + .disconnect_pipes = dcn10_disconnect_pipes, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, .update_plane_addr = dcn10_update_plane_addr, .update_dchub = dcn10_update_dchub, .update_pending_status = dcn10_update_pending_status, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 8939541ad7af..1abd81e17f09 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1339,6 +1339,47 @@ static uint32_t read_pipe_fuses(struct dc_context *ctx) return value; } +/* + * Some architectures don't support soft-float (e.g. aarch64), on those + * this function has to be called with hardfloat enabled, make sure not + * to inline it so whatever fp stuff is done stays inside + */ +static noinline void dcn10_resource_construct_fp( + struct dc *dc) +{ + if (dc->ctx->dce_version == DCN_VERSION_1_01) { + struct dcn_soc_bounding_box *dcn_soc = dc->dcn_soc; + struct dcn_ip_params *dcn_ip = dc->dcn_ip; + struct display_mode_lib *dml = &dc->dml; + + dml->ip.max_num_dpp = 3; + /* TODO how to handle 23.84? */ + dcn_soc->dram_clock_change_latency = 23; + dcn_ip->max_num_dpp = 3; + } + if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { + dc->dcn_soc->urgent_latency = 3; + dc->debug.disable_dmcu = true; + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 41.60f; + } + + + dc->dcn_soc->number_of_channels = dc->ctx->asic_id.vram_width / ddr4_dram_width; + ASSERT(dc->dcn_soc->number_of_channels < 3); + if (dc->dcn_soc->number_of_channels == 0)/*old sbios bug*/ + dc->dcn_soc->number_of_channels = 2; + + if (dc->dcn_soc->number_of_channels == 1) { + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 19.2f; + dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 = 17.066f; + dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 = 14.933f; + dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = 12.8f; + if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 20.80f; + } + } +} + static bool dcn10_resource_construct( uint8_t num_virtual_links, struct dc *dc, @@ -1490,37 +1531,15 @@ static bool dcn10_resource_construct( memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults)); memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_defaults)); - if (dc->ctx->dce_version == DCN_VERSION_1_01) { - struct dcn_soc_bounding_box *dcn_soc = dc->dcn_soc; - struct dcn_ip_params *dcn_ip = dc->dcn_ip; - struct display_mode_lib *dml = &dc->dml; - - dml->ip.max_num_dpp = 3; - /* TODO how to handle 23.84? */ - dcn_soc->dram_clock_change_latency = 23; - dcn_ip->max_num_dpp = 3; - } - if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { - dc->dcn_soc->urgent_latency = 3; - dc->debug.disable_dmcu = true; - dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 41.60f; - } - - - dc->dcn_soc->number_of_channels = dc->ctx->asic_id.vram_width / ddr4_dram_width; - ASSERT(dc->dcn_soc->number_of_channels < 3); - if (dc->dcn_soc->number_of_channels == 0)/*old sbios bug*/ - dc->dcn_soc->number_of_channels = 2; - - if (dc->dcn_soc->number_of_channels == 1) { - dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 19.2f; - dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 = 17.066f; - dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 = 14.933f; - dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = 12.8f; - if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { - dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 20.80f; - } - } +#if defined(CONFIG_ARM64) + /* Aarch64 does not support -msoft-float/-mfloat-abi=soft */ + DC_FP_START(); + dcn10_resource_construct_fp(dc); + DC_FP_END(); +#else + /* Other architectures we build for build this with soft-float */ + dcn10_resource_construct_fp(dc); +#endif pool->base.pp_smu = dcn10_pp_smu_create(ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index 5fcaf78334ff..624cb1341ef1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -17,6 +17,10 @@ ifdef CONFIG_PPC64 CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mhard-float -maltivec endif +ifdef CONFIG_ARM64 +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mgeneral-regs-only +endif + ifdef CONFIG_CC_IS_GCC ifeq ($(call cc-ifversion, -lt, 0701, y), y) IS_OLD_GCC = 1 diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h index 667640c4b288..1118e33aaa2c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h @@ -94,6 +94,7 @@ DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_CLOCK_EN, mask_sh), \ DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DISPCLK_R_GATE_DIS, mask_sh), \ DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DSCCLK_R_GATE_DIS, mask_sh), \ + DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_DBG_EN, mask_sh), \ DSC_SF(DSCC0_DSCC_CONFIG0, ICH_RESET_AT_END_OF_LINE, mask_sh), \ DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_PER_LINE, mask_sh), \ DSC_SF(DSCC0_DSCC_CONFIG0, ALTERNATE_ICH_ENCODING_EN, mask_sh), \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c index 3dde6f26de47..966e1790b9bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c @@ -34,6 +34,8 @@ static const struct hw_sequencer_funcs dcn20_funcs = { .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = NULL, .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .disconnect_pipes = dcn10_disconnect_pipes, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, .update_plane_addr = dcn20_update_plane_addr, .update_dchub = dcn10_update_dchub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h index dcbf28dd72d4..864acd695cbb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h @@ -231,8 +231,6 @@ SRI(RDPCSTX_PHY_FUSE3, RDPCSTX, id), \ SRI(DPCSTX_TX_CLOCK_CNTL, DPCSTX, id), \ SRI(DPCSTX_TX_CNTL, DPCSTX, id), \ - SRI(DPCSTX_DEBUG_CONFIG, DPCSTX, id), \ - SRI(RDPCSTX_DEBUG_CONFIG, RDPCSTX, id), \ SR(RDPCSTX0_RDPCSTX_SCRATCH) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 9140b3fc767a..1b9874445134 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -3209,6 +3209,9 @@ static noinline bool dcn20_validate_bandwidth_fp(struct dc *dc, context->bw_ctx.dml.soc.allow_dram_clock_one_display_vactive = dc->debug.enable_dram_clock_change_one_display_vactive; + /*Unsafe due to current pipe merge and split logic*/ + ASSERT(context != dc->current_state); + if (fast_validate) { return dcn20_validate_bandwidth_internal(dc, context, true); } @@ -3320,7 +3323,7 @@ enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_stat return DC_OK; } -static struct resource_funcs dcn20_res_pool_funcs = { +static const struct resource_funcs dcn20_res_pool_funcs = { .destroy = dcn20_destroy_resource_pool, .link_enc_create = dcn20_link_encoder_create, .panel_cntl_create = dcn20_panel_cntl_create, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h index 2c1959845c29..cdd39ee9761d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h @@ -95,7 +95,6 @@ struct display_stream_compressor *dcn20_dsc_create( struct dc_context *ctx, uint32_t inst); void dcn20_dsc_destroy(struct display_stream_compressor **dsc); -void dcn20_patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb); void dcn20_cap_soc_clocks( struct _vcs_dpi_soc_bounding_box_st *bb, struct pp_smu_nv_clock_table max_clocks); diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile index 07684d3e375a..51a2f3d4c194 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile @@ -13,6 +13,10 @@ ifdef CONFIG_PPC64 CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mhard-float -maltivec endif +ifdef CONFIG_ARM64 +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mgeneral-regs-only +endif + ifdef CONFIG_CC_IS_GCC ifeq ($(call cc-ifversion, -lt, 0701, y), y) IS_OLD_GCC = 1 diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c index b187f71afa65..2ba880c3943c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c @@ -35,6 +35,8 @@ static const struct hw_sequencer_funcs dcn21_funcs = { .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = NULL, .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .disconnect_pipes = dcn10_disconnect_pipes, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, .update_plane_addr = dcn20_update_plane_addr, .update_dchub = dcn10_update_dchub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index 88d41a385add..78743ae37851 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -1184,6 +1184,9 @@ bool dcn21_validate_bandwidth(struct dc *dc, struct dc_state *context, BW_VAL_TRACE_COUNT(); + /*Unsafe due to current pipe merge and split logic*/ + ASSERT(context != dc->current_state); + out = dcn20_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel); if (pipe_cnt == 0) @@ -1754,7 +1757,7 @@ enum dc_status dcn21_patch_unknown_plane_state(struct dc_plane_state *plane_stat return result; } -static struct resource_funcs dcn21_res_pool_funcs = { +static const struct resource_funcs dcn21_res_pool_funcs = { .destroy = dcn21_destroy_resource_pool, .link_enc_create = dcn21_link_encoder_create, .panel_cntl_create = dcn21_panel_cntl_create, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c index 9afee7160490..19daa456e3bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c @@ -35,6 +35,8 @@ static const struct hw_sequencer_funcs dcn30_funcs = { .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = NULL, .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .disconnect_pipes = dcn10_disconnect_pipes, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, .update_plane_addr = dcn20_update_plane_addr, .update_dchub = dcn10_update_dchub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index ebe0cc5b833b..8be4f21169d0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -340,7 +340,7 @@ static const struct dce110_clk_src_mask cs_mask = { #define abm_regs(id)\ [id] = {\ - ABM_DCN301_REG_LIST(id)\ + ABM_DCN30_REG_LIST(id)\ } static const struct dce_abm_registers abm_regs[] = { @@ -491,6 +491,7 @@ static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { [id] = {\ LE_DCN3_REG_LIST(id), \ UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN2_REG_LIST(id), \ SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ } @@ -872,7 +873,7 @@ void dcn30_dpp_destroy(struct dpp **dpp) *dpp = NULL; } -struct dpp *dcn30_dpp_create( +static struct dpp *dcn30_dpp_create( struct dc_context *ctx, uint32_t inst) { @@ -890,7 +891,8 @@ struct dpp *dcn30_dpp_create( kfree(dpp); return NULL; } -struct output_pixel_processor *dcn30_opp_create( + +static struct output_pixel_processor *dcn30_opp_create( struct dc_context *ctx, uint32_t inst) { struct dcn20_opp *opp = @@ -906,7 +908,7 @@ struct output_pixel_processor *dcn30_opp_create( return &opp->base; } -struct dce_aux *dcn30_aux_engine_create( +static struct dce_aux *dcn30_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -925,6 +927,7 @@ struct dce_aux *dcn30_aux_engine_create( return &aux_engine->base; } + #define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } static const struct dce_i2c_registers i2c_hw_regs[] = { @@ -944,7 +947,7 @@ static const struct dce_i2c_mask i2c_masks = { I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) }; -struct dce_i2c_hw *dcn30_i2c_hw_create( +static struct dce_i2c_hw *dcn30_i2c_hw_create( struct dc_context *ctx, uint32_t inst) { @@ -959,6 +962,7 @@ struct dce_i2c_hw *dcn30_i2c_hw_create( return dce_i2c_hw; } + static struct mpc *dcn30_mpc_create( struct dc_context *ctx, int num_mpcc, @@ -1009,7 +1013,7 @@ struct hubbub *dcn30_hubbub_create(struct dc_context *ctx) return &hubbub3->base; } -struct timing_generator *dcn30_timing_generator_create( +static struct timing_generator *dcn30_timing_generator_create( struct dc_context *ctx, uint32_t instance) { @@ -1043,7 +1047,7 @@ static const struct encoder_feature_support link_enc_feature = { .flags.bits.IS_TPS4_CAPABLE = true }; -struct link_encoder *dcn30_link_encoder_create( +static struct link_encoder *dcn30_link_encoder_create( const struct encoder_init_data *enc_init_data) { struct dcn20_link_encoder *enc20 = @@ -1064,7 +1068,7 @@ struct link_encoder *dcn30_link_encoder_create( return &enc20->enc10.base; } -struct panel_cntl *dcn30_panel_cntl_create(const struct panel_cntl_init_data *init_data) +static struct panel_cntl *dcn30_panel_cntl_create(const struct panel_cntl_init_data *init_data) { struct dce_panel_cntl *panel_cntl = kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); @@ -1312,7 +1316,7 @@ static void dcn30_resource_destruct(struct dcn30_resource_pool *pool) dcn_dccg_destroy(&pool->base.dccg); } -struct hubp *dcn30_hubp_create( +static struct hubp *dcn30_hubp_create( struct dc_context *ctx, uint32_t inst) { @@ -1331,7 +1335,7 @@ struct hubp *dcn30_hubp_create( return NULL; } -bool dcn30_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +static bool dcn30_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) { int i; uint32_t pipe_count = pool->res_cap->num_dwb; @@ -1356,7 +1360,7 @@ bool dcn30_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) return true; } -bool dcn30_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +static bool dcn30_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) { int i; uint32_t pipe_count = pool->res_cap->num_dwb; @@ -2293,7 +2297,7 @@ static void get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts, (dcn3_0_soc.return_bus_width_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100)); } -static void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) { unsigned int i, j; unsigned int num_states = 0; @@ -2413,7 +2417,7 @@ static void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30); } -static struct resource_funcs dcn30_res_pool_funcs = { +static const struct resource_funcs dcn30_res_pool_funcs = { .destroy = dcn30_destroy_resource_pool, .link_enc_create = dcn30_link_encoder_create, .panel_cntl_create = dcn30_panel_cntl_create, @@ -2421,6 +2425,7 @@ static struct resource_funcs dcn30_res_pool_funcs = { .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer, .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, .set_mcif_arb_params = dcn30_set_mcif_arb_params, @@ -2684,7 +2689,7 @@ static bool dcn30_resource_construct( if (!resource_construct(num_virtual_links, dc, &pool->base, (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) ? &res_create_funcs : &res_create_maximus_funcs))) - goto create_fail; + goto create_fail; /* HW Sequencer and Plane caps */ dcn30_hw_sequencer_construct(dc); diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h index 4b4a4d81c1e3..c9d5f94092a0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h @@ -79,4 +79,7 @@ enum dc_status dcn30_add_stream_to_ctx( struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); + +void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); + #endif /* _DCN30_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 417331438c30..dbc7e2abe379 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -33,6 +33,10 @@ ifdef CONFIG_PPC64 dml_ccflags := -mhard-float -maltivec endif +ifdef CONFIG_ARM64 +dml_rcflags := -mgeneral-regs-only +endif + ifdef CONFIG_CC_IS_GCC ifeq ($(call cc-ifversion, -lt, 0701, y), y) IS_OLD_GCC = 1 @@ -60,6 +64,13 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) 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_rq_dlg_calc_21.o := $(dml_ccflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20v2.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn21/display_rq_dlg_calc_21.o := $(dml_rcflags) endif ifdef CONFIG_DRM_AMD_DC_DCN3_0 CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) -Wframe-larger-than=2048 @@ -67,6 +78,8 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) endif CFLAGS_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/display_rq_dlg_helpers.o := $(dml_ccflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_rq_dlg_helpers.o := $(dml_rcflags) DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c index afdd4f0d9d71..b32093136089 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c @@ -467,7 +467,7 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) mode_lib->vba.AudioSampleLayout[mode_lib->vba.NumberOfActivePlanes] = 1; mode_lib->vba.DRAMClockChangeLatencyOverride = 0.0; - mode_lib->vba.DSCEnabled[mode_lib->vba.NumberOfActivePlanes] = dout->dsc_enable;; + mode_lib->vba.DSCEnabled[mode_lib->vba.NumberOfActivePlanes] = dout->dsc_enable; mode_lib->vba.DSCEnable[mode_lib->vba.NumberOfActivePlanes] = dout->dsc_enable; mode_lib->vba.NumberOfDSCSlices[mode_lib->vba.NumberOfActivePlanes] = dout->dsc_slices; diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile index ea29cf95d470..f2624a1156e5 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile @@ -10,6 +10,10 @@ ifdef CONFIG_PPC64 dsc_ccflags := -mhard-float -maltivec endif +ifdef CONFIG_ARM64 +dsc_rcflags := -mgeneral-regs-only +endif + ifdef CONFIG_CC_IS_GCC ifeq ($(call cc-ifversion, -lt, 0701, y), y) IS_OLD_GCC = 1 @@ -28,6 +32,7 @@ endif endif CFLAGS_$(AMDDALPATH)/dc/dsc/rc_calc.o := $(dsc_ccflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/dsc/rc_calc.o := $(dsc_rcflags) DSC = dc_dsc.o rc_calc.o rc_calc_dpi.o 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 8cdaa6eef5d3..4c844cfaa956 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -34,6 +34,9 @@ /* default DSC policy target bitrate limit is 16bpp */ static uint32_t dsc_policy_max_target_bpp_limit = 16; +/* default DSC policy enables DSC only when needed */ +static bool dsc_policy_enable_dsc_when_not_needed; + static uint32_t dc_dsc_bandwidth_in_kbps_from_timing( const struct dc_crtc_timing *timing) { @@ -189,8 +192,10 @@ static bool dsc_throughput_from_dpcd(int dpcd_throughput, int *throughput) } -static bool dsc_bpp_increment_div_from_dpcd(int bpp_increment_dpcd, uint32_t *bpp_increment_div) +static bool dsc_bpp_increment_div_from_dpcd(uint8_t bpp_increment_dpcd, uint32_t *bpp_increment_div) { + // Mask bpp increment dpcd field to avoid reading other fields + bpp_increment_dpcd &= 0x7; switch (bpp_increment_dpcd) { case 0: @@ -360,7 +365,7 @@ static bool decide_dsc_target_bpp_x16( get_dsc_bandwidth_range(policy->min_target_bpp, policy->max_target_bpp, dsc_common_caps, timing, &range); - if (target_bandwidth_kbps >= range.stream_kbps) { + if (!policy->enable_dsc_when_not_needed && target_bandwidth_kbps >= range.stream_kbps) { /* enough bandwidth without dsc */ *target_bpp_x16 = 0; should_use_dsc = false; @@ -961,9 +966,20 @@ void dc_dsc_get_policy_for_timing(const struct dc_crtc_timing *timing, struct dc /* internal upper limit, default 16 bpp */ if (policy->max_target_bpp > dsc_policy_max_target_bpp_limit) policy->max_target_bpp = dsc_policy_max_target_bpp_limit; + + /* enable DSC when not needed, default false */ + if (dsc_policy_enable_dsc_when_not_needed) + policy->enable_dsc_when_not_needed = dsc_policy_enable_dsc_when_not_needed; + else + policy->enable_dsc_when_not_needed = false; } void dc_dsc_policy_set_max_target_bpp_limit(uint32_t limit) { dsc_policy_max_target_bpp_limit = limit; } + +void dc_dsc_policy_set_enable_dsc_when_not_needed(bool enable) +{ + dsc_policy_enable_dsc_when_not_needed = enable; +} diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile index 0f2f4508e564..74c0943ed644 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile @@ -31,6 +31,18 @@ AMD_DAL_GPIO = $(addprefix $(AMDDALPATH)/dc/gpio/,$(GPIO)) AMD_DISPLAY_FILES += $(AMD_DAL_GPIO) ############################################################################### +# DCE 6x +############################################################################### +# all DCE6.x are derived from DCE6.0 +ifdef CONFIG_DRM_AMD_DC_SI +GPIO_DCE60 = hw_translate_dce60.o hw_factory_dce60.o + +AMD_DAL_GPIO_DCE60 = $(addprefix $(AMDDALPATH)/dc/gpio/dce60/,$(GPIO_DCE60)) + +AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCE60) +endif + +############################################################################### # DCE 8x ############################################################################### # all DCE8.x are derived from DCE8.0 diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_factory_dce60.c b/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_factory_dce60.c new file mode 100644 index 000000000000..cc69acd8ada7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_factory_dce60.c @@ -0,0 +1,175 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "include/gpio_types.h" +#include "../hw_factory.h" + +#include "hw_factory_dce60.h" + +#include "../hw_gpio.h" +#include "../hw_ddc.h" +#include "../hw_hpd.h" +#include "../hw_generic.h" + +#include "dce/dce_6_0_d.h" +#include "dce/dce_6_0_sh_mask.h" + + +#define REG(reg_name)\ + mm ## reg_name + +#include "reg_helper.h" +#include "../hpd_regs.h" + +#define HPD_REG_LIST_DCE6(id) \ + HPD_GPIO_REG_LIST(id), \ + .int_status = mmDC_HPD ## id ## _INT_STATUS,\ + .toggle_filt_cntl = mmDC_HPD ## id ## _TOGGLE_FILT_CNTL + +#define HPD_MASK_SH_LIST_DCE6(mask_sh) \ + .DC_HPD_SENSE_DELAYED = DC_HPD1_INT_STATUS__DC_HPD1_SENSE_DELAYED ## mask_sh,\ + .DC_HPD_SENSE = DC_HPD1_INT_STATUS__DC_HPD1_SENSE ## mask_sh,\ + .DC_HPD_CONNECT_INT_DELAY = DC_HPD1_TOGGLE_FILT_CNTL__DC_HPD1_CONNECT_INT_DELAY ## mask_sh,\ + .DC_HPD_DISCONNECT_INT_DELAY = DC_HPD1_TOGGLE_FILT_CNTL__DC_HPD1_DISCONNECT_INT_DELAY ## mask_sh + +#define hpd_regs(id) \ +{\ + HPD_REG_LIST_DCE6(id)\ +} + +static const struct hpd_registers hpd_regs[] = { + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5), + hpd_regs(6) +}; + +static const struct hpd_sh_mask hpd_shift = { + HPD_MASK_SH_LIST_DCE6(__SHIFT) +}; + +static const struct hpd_sh_mask hpd_mask = { + HPD_MASK_SH_LIST_DCE6(_MASK) +}; + +#include "../ddc_regs.h" + + /* set field name */ +#define SF_DDC(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +static const struct ddc_registers ddc_data_regs[] = { + ddc_data_regs(1), + ddc_data_regs(2), + ddc_data_regs(3), + ddc_data_regs(4), + ddc_data_regs(5), + ddc_data_regs(6), + ddc_vga_data_regs, + ddc_i2c_data_regs +}; + +static const struct ddc_registers ddc_clk_regs[] = { + ddc_clk_regs(1), + ddc_clk_regs(2), + ddc_clk_regs(3), + ddc_clk_regs(4), + ddc_clk_regs(5), + ddc_clk_regs(6), + ddc_vga_clk_regs, + ddc_i2c_clk_regs +}; + +static const struct ddc_sh_mask ddc_shift = { + DDC_MASK_SH_LIST(__SHIFT) +}; + +static const struct ddc_sh_mask ddc_mask = { + DDC_MASK_SH_LIST(_MASK) +}; + +static void define_ddc_registers( + struct hw_gpio_pin *pin, + uint32_t en) +{ + struct hw_ddc *ddc = HW_DDC_FROM_BASE(pin); + + switch (pin->id) { + case GPIO_ID_DDC_DATA: + ddc->regs = &ddc_data_regs[en]; + ddc->base.regs = &ddc_data_regs[en].gpio; + break; + case GPIO_ID_DDC_CLOCK: + ddc->regs = &ddc_clk_regs[en]; + ddc->base.regs = &ddc_clk_regs[en].gpio; + break; + default: + ASSERT_CRITICAL(false); + return; + } + + ddc->shifts = &ddc_shift; + ddc->masks = &ddc_mask; + +} + +static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en) +{ + struct hw_hpd *hpd = HW_HPD_FROM_BASE(pin); + + hpd->regs = &hpd_regs[en]; + hpd->shifts = &hpd_shift; + hpd->masks = &hpd_mask; + hpd->base.regs = &hpd_regs[en].gpio; +} + +static const struct hw_factory_funcs funcs = { + .init_ddc_data = dal_hw_ddc_init, + .init_generic = NULL, + .init_hpd = dal_hw_hpd_init, + .get_ddc_pin = dal_hw_ddc_get_pin, + .get_hpd_pin = dal_hw_hpd_get_pin, + .get_generic_pin = NULL, + .define_hpd_registers = define_hpd_registers, + .define_ddc_registers = define_ddc_registers +}; + +void dal_hw_factory_dce60_init( + struct hw_factory *factory) +{ + factory->number_of_pins[GPIO_ID_DDC_DATA] = 8; + factory->number_of_pins[GPIO_ID_DDC_CLOCK] = 8; + factory->number_of_pins[GPIO_ID_GENERIC] = 7; + factory->number_of_pins[GPIO_ID_HPD] = 6; + factory->number_of_pins[GPIO_ID_GPIO_PAD] = 31; + factory->number_of_pins[GPIO_ID_VIP_PAD] = 0; + factory->number_of_pins[GPIO_ID_SYNC] = 2; + factory->number_of_pins[GPIO_ID_GSL] = 4; + + factory->funcs = &funcs; +} diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_factory_dce60.h b/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_factory_dce60.h new file mode 100644 index 000000000000..1fd54ff8979c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_factory_dce60.h @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#ifndef __DAL_HW_FACTORY_DCE60_H__ +#define __DAL_HW_FACTORY_DCE60_H__ + +void dal_hw_factory_dce60_init( + struct hw_factory *factory); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_translate_dce60.c b/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_translate_dce60.c new file mode 100644 index 000000000000..255df31ec577 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_translate_dce60.c @@ -0,0 +1,411 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#include "dm_services.h" + +/* + * Pre-requisites: headers required by header of this unit + */ +#include "include/gpio_types.h" +#include "../hw_translate.h" + +#include "hw_translate_dce60.h" + +#include "dce/dce_6_0_d.h" +#include "dce/dce_6_0_sh_mask.h" +#include "smu/smu_6_0_d.h" + +/* + * @brief + * Returns index of first bit (starting with LSB) which is set + */ +static uint32_t index_from_vector( + uint32_t vector) +{ + uint32_t result = 0; + uint32_t mask = 1; + + do { + if (vector == mask) + return result; + + ++result; + mask <<= 1; + } while (mask); + + BREAK_TO_DEBUGGER(); + + return GPIO_ENUM_UNKNOWN; +} + +static bool offset_to_id( + uint32_t offset, + uint32_t mask, + enum gpio_id *id, + uint32_t *en) +{ + switch (offset) { + /* GENERIC */ + case mmDC_GPIO_GENERIC_A: + *id = GPIO_ID_GENERIC; + switch (mask) { + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: + *en = GPIO_GENERIC_A; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: + *en = GPIO_GENERIC_B; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: + *en = GPIO_GENERIC_C; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: + *en = GPIO_GENERIC_D; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: + *en = GPIO_GENERIC_E; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: + *en = GPIO_GENERIC_F; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK: + *en = GPIO_GENERIC_G; + return true; + default: + BREAK_TO_DEBUGGER(); + return false; + } + break; + /* HPD */ + case mmDC_GPIO_HPD_A: + *id = GPIO_ID_HPD; + switch (mask) { + case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: + *en = GPIO_HPD_1; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: + *en = GPIO_HPD_2; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: + *en = GPIO_HPD_3; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: + *en = GPIO_HPD_4; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: + *en = GPIO_HPD_5; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK: + *en = GPIO_HPD_6; + return true; + default: + BREAK_TO_DEBUGGER(); + return false; + } + break; + /* SYNCA */ + case mmDC_GPIO_SYNCA_A: + *id = GPIO_ID_SYNC; + switch (mask) { + case DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK: + *en = GPIO_SYNC_HSYNC_A; + return true; + case DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK: + *en = GPIO_SYNC_VSYNC_A; + return true; + default: + BREAK_TO_DEBUGGER(); + return false; + } + break; + /* mmDC_GPIO_GENLK_MASK */ + case mmDC_GPIO_GENLK_A: + *id = GPIO_ID_GSL; + switch (mask) { + case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: + *en = GPIO_GSL_GENLOCK_CLOCK; + return true; + case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: + *en = GPIO_GSL_GENLOCK_VSYNC; + return true; + case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: + *en = GPIO_GSL_SWAPLOCK_A; + return true; + case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: + *en = GPIO_GSL_SWAPLOCK_B; + return true; + default: + BREAK_TO_DEBUGGER(); + return false; + } + break; + /* GPIOPAD */ + case mmGPIOPAD_A: + *id = GPIO_ID_GPIO_PAD; + *en = index_from_vector(mask); + return (*en <= GPIO_GPIO_PAD_MAX); + /* DDC */ + /* we don't care about the GPIO_ID for DDC + * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK + * directly in the create method */ + case mmDC_GPIO_DDC1_A: + *en = GPIO_DDC_LINE_DDC1; + return true; + case mmDC_GPIO_DDC2_A: + *en = GPIO_DDC_LINE_DDC2; + return true; + case mmDC_GPIO_DDC3_A: + *en = GPIO_DDC_LINE_DDC3; + return true; + case mmDC_GPIO_DDC4_A: + *en = GPIO_DDC_LINE_DDC4; + return true; + case mmDC_GPIO_DDC5_A: + *en = GPIO_DDC_LINE_DDC5; + return true; + case mmDC_GPIO_DDC6_A: + *en = GPIO_DDC_LINE_DDC6; + return true; + case mmDC_GPIO_DDCVGA_A: + *en = GPIO_DDC_LINE_DDC_VGA; + return true; + /* GPIO_I2CPAD */ + case mmDC_GPIO_I2CPAD_A: + *en = GPIO_DDC_LINE_I2C_PAD; + return true; + /* Not implemented */ + case mmDC_GPIO_PWRSEQ_A: + case mmDC_GPIO_PAD_STRENGTH_1: + case mmDC_GPIO_PAD_STRENGTH_2: + case mmDC_GPIO_DEBUG: + return false; + /* UNEXPECTED */ + default: + BREAK_TO_DEBUGGER(); + return false; + } +} + +static bool id_to_offset( + enum gpio_id id, + uint32_t en, + struct gpio_pin_info *info) +{ + bool result = true; + + switch (id) { + case GPIO_ID_DDC_DATA: + info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK; + switch (en) { + case GPIO_DDC_LINE_DDC1: + info->offset = mmDC_GPIO_DDC1_A; + break; + case GPIO_DDC_LINE_DDC2: + info->offset = mmDC_GPIO_DDC2_A; + break; + case GPIO_DDC_LINE_DDC3: + info->offset = mmDC_GPIO_DDC3_A; + break; + case GPIO_DDC_LINE_DDC4: + info->offset = mmDC_GPIO_DDC4_A; + break; + case GPIO_DDC_LINE_DDC5: + info->offset = mmDC_GPIO_DDC5_A; + break; + case GPIO_DDC_LINE_DDC6: + info->offset = mmDC_GPIO_DDC6_A; + break; + case GPIO_DDC_LINE_DDC_VGA: + info->offset = mmDC_GPIO_DDCVGA_A; + break; + case GPIO_DDC_LINE_I2C_PAD: + info->offset = mmDC_GPIO_I2CPAD_A; + break; + default: + BREAK_TO_DEBUGGER(); + result = false; + } + break; + case GPIO_ID_DDC_CLOCK: + info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK; + switch (en) { + case GPIO_DDC_LINE_DDC1: + info->offset = mmDC_GPIO_DDC1_A; + break; + case GPIO_DDC_LINE_DDC2: + info->offset = mmDC_GPIO_DDC2_A; + break; + case GPIO_DDC_LINE_DDC3: + info->offset = mmDC_GPIO_DDC3_A; + break; + case GPIO_DDC_LINE_DDC4: + info->offset = mmDC_GPIO_DDC4_A; + break; + case GPIO_DDC_LINE_DDC5: + info->offset = mmDC_GPIO_DDC5_A; + break; + case GPIO_DDC_LINE_DDC6: + info->offset = mmDC_GPIO_DDC6_A; + break; + case GPIO_DDC_LINE_DDC_VGA: + info->offset = mmDC_GPIO_DDCVGA_A; + break; + case GPIO_DDC_LINE_I2C_PAD: + info->offset = mmDC_GPIO_I2CPAD_A; + break; + default: + BREAK_TO_DEBUGGER(); + result = false; + } + break; + case GPIO_ID_GENERIC: + info->offset = mmDC_GPIO_GENERIC_A; + switch (en) { + case GPIO_GENERIC_A: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; + break; + case GPIO_GENERIC_B: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; + break; + case GPIO_GENERIC_C: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; + break; + case GPIO_GENERIC_D: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; + break; + case GPIO_GENERIC_E: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; + break; + case GPIO_GENERIC_F: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; + break; + case GPIO_GENERIC_G: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK; + break; + default: + BREAK_TO_DEBUGGER(); + result = false; + } + break; + case GPIO_ID_HPD: + info->offset = mmDC_GPIO_HPD_A; + switch (en) { + case GPIO_HPD_1: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; + break; + case GPIO_HPD_2: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; + break; + case GPIO_HPD_3: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; + break; + case GPIO_HPD_4: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; + break; + case GPIO_HPD_5: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; + break; + case GPIO_HPD_6: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK; + break; + default: + BREAK_TO_DEBUGGER(); + result = false; + } + break; + case GPIO_ID_SYNC: + switch (en) { + case GPIO_SYNC_HSYNC_A: + info->offset = mmDC_GPIO_SYNCA_A; + info->mask = DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK; + break; + case GPIO_SYNC_VSYNC_A: + info->offset = mmDC_GPIO_SYNCA_A; + info->mask = DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK; + break; + case GPIO_SYNC_HSYNC_B: + case GPIO_SYNC_VSYNC_B: + default: + BREAK_TO_DEBUGGER(); + result = false; + } + break; + case GPIO_ID_GSL: + switch (en) { + case GPIO_GSL_GENLOCK_CLOCK: + info->offset = mmDC_GPIO_GENLK_A; + info->mask = DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK; + break; + case GPIO_GSL_GENLOCK_VSYNC: + info->offset = mmDC_GPIO_GENLK_A; + info->mask = + DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK; + break; + case GPIO_GSL_SWAPLOCK_A: + info->offset = mmDC_GPIO_GENLK_A; + info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK; + break; + case GPIO_GSL_SWAPLOCK_B: + info->offset = mmDC_GPIO_GENLK_A; + info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK; + break; + default: + BREAK_TO_DEBUGGER(); + result = false; + } + break; + case GPIO_ID_GPIO_PAD: + info->offset = mmGPIOPAD_A; + info->mask = (1 << en); + result = (info->mask <= GPIO_GPIO_PAD_MAX); + break; + case GPIO_ID_VIP_PAD: + default: + BREAK_TO_DEBUGGER(); + result = false; + } + + if (result) { + info->offset_y = info->offset + 2; + info->offset_en = info->offset + 1; + info->offset_mask = info->offset - 1; + + info->mask_y = info->mask; + info->mask_en = info->mask; + info->mask_mask = info->mask; + } + + return result; +} + +static const struct hw_translate_funcs funcs = { + .offset_to_id = offset_to_id, + .id_to_offset = id_to_offset, +}; + +void dal_hw_translate_dce60_init( + struct hw_translate *translate) +{ + translate->funcs = &funcs; +} diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_translate_dce60.h b/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_translate_dce60.h new file mode 100644 index 000000000000..1e811f35cec7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce60/hw_translate_dce60.h @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#ifndef __DAL_HW_TRANSLATE_DCE60_H__ +#define __DAL_HW_TRANSLATE_DCE60_H__ + +void dal_hw_translate_dce60_init( + struct hw_translate *tr); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c index e5cfe28bc7bf..6fc8a6e9dc15 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -42,6 +42,9 @@ * Post-requisites: headers required by this unit */ +#if defined(CONFIG_DRM_AMD_DC_SI) +#include "dce60/hw_factory_dce60.h" +#endif #include "dce80/hw_factory_dce80.h" #include "dce110/hw_factory_dce110.h" #include "dce120/hw_factory_dce120.h" @@ -71,6 +74,13 @@ bool dal_hw_factory_init( } switch (dce_version) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case DCE_VERSION_6_0: + case DCE_VERSION_6_1: + case DCE_VERSION_6_4: + dal_hw_factory_dce60_init(factory); + return true; +#endif case DCE_VERSION_8_0: case DCE_VERSION_8_1: case DCE_VERSION_8_3: diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index efea7cb0f17c..3a93c945e57d 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -40,6 +40,9 @@ * Post-requisites: headers required by this unit */ +#if defined(CONFIG_DRM_AMD_DC_SI) +#include "dce60/hw_translate_dce60.h" +#endif #include "dce80/hw_translate_dce80.h" #include "dce110/hw_translate_dce110.h" #include "dce120/hw_translate_dce120.h" @@ -69,6 +72,13 @@ bool dal_hw_translate_init( } switch (dce_version) { +#if defined(CONFIG_DRM_AMD_DC_SI) + case DCE_VERSION_6_0: + case DCE_VERSION_6_1: + case DCE_VERSION_6_4: + dal_hw_translate_dce60_init(translate); + return true; +#endif case DCE_VERSION_8_0: case DCE_VERSION_8_1: case DCE_VERSION_8_3: 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 72743058836d..949b61351ede 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 @@ -89,6 +89,11 @@ enum dentist_divider_range { .DPREFCLK_CNTL = mmDPREFCLK_CNTL, \ .DENTIST_DISPCLK_CNTL = mmDENTIST_DISPCLK_CNTL +#if defined(CONFIG_DRM_AMD_DC_SI) +#define CLK_COMMON_REG_LIST_DCE60_BASE() \ + SR(DENTIST_DISPCLK_CNTL) +#endif + #define CLK_COMMON_REG_LIST_DCN_BASE() \ SR(DENTIST_DISPCLK_CNTL) @@ -115,6 +120,12 @@ enum dentist_divider_range { CLK_SF(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, mask_sh), \ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_SI) +#define CLK_COMMON_MASK_SH_LIST_DCE60_COMMON_BASE(mask_sh) \ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh) +#endif + #define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh) diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h index f9ab5abb6462..48eac622c6a0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h @@ -49,6 +49,7 @@ struct panel_cntl_funcs { void (*store_backlight_level)(struct panel_cntl *panel_cntl); void (*driver_set_backlight)(struct panel_cntl *panel_cntl, uint32_t backlight_pwm_u16_16); + uint32_t (*get_current_backlight)(struct panel_cntl *panel_cntl); }; struct panel_cntl_init_data { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index 3c986717dcd5..64c1be818b0e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -67,6 +67,10 @@ struct hw_sequencer_funcs { int num_planes, struct dc_state *context); void (*program_front_end_for_ctx)(struct dc *dc, struct dc_state *context); + bool (*disconnect_pipes)(struct dc *dc, + struct dc_state *context); + void (*wait_for_pending_cleared)(struct dc *dc, + struct dc_state *context); void (*post_unlock_program_front_end)(struct dc *dc, struct dc_state *context); void (*update_plane_addr)(const struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index 3352b79fb1cb..405c25322607 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -31,6 +31,17 @@ AMD_DAL_IRQ = $(addprefix $(AMDDALPATH)/dc/irq/,$(IRQ)) AMD_DISPLAY_FILES += $(AMD_DAL_IRQ) ############################################################################### +# DCE 6x +############################################################################### +ifdef CONFIG_DRM_AMD_DC_SI +IRQ_DCE60 = irq_service_dce60.o + +AMD_DAL_IRQ_DCE60 = $(addprefix $(AMDDALPATH)/dc/irq/dce60/,$(IRQ_DCE60)) + +AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCE60) +endif + +############################################################################### # DCE 8x ############################################################################### IRQ_DCE80 = irq_service_dce80.o diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce60/irq_service_dce60.c b/drivers/gpu/drm/amd/display/dc/irq/dce60/irq_service_dce60.c new file mode 100644 index 000000000000..524481885fd0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/irq/dce60/irq_service_dce60.c @@ -0,0 +1,395 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#include <linux/slab.h> + +#include "dm_services.h" + +#include "include/logger_interface.h" + +#include "irq_service_dce60.h" +#include "../dce110/irq_service_dce110.h" + +#include "dce/dce_6_0_d.h" +#include "dce/dce_6_0_sh_mask.h" + +#include "ivsrcid/ivsrcid_vislands30.h" + +#define VISLANDS30_IV_SRCID_D1_VBLANK 1 +#define VISLANDS30_IV_SRCID_D2_VBLANK 2 +#define VISLANDS30_IV_SRCID_D3_VBLANK 3 +#define VISLANDS30_IV_SRCID_D4_VBLANK 4 +#define VISLANDS30_IV_SRCID_D5_VBLANK 5 +#define VISLANDS30_IV_SRCID_D6_VBLANK 6 + +#include "dc_types.h" + +static bool hpd_ack( + struct irq_service *irq_service, + const struct irq_source_info *info) +{ + uint32_t addr = info->status_reg; + uint32_t value = dm_read_reg(irq_service->ctx, addr); + uint32_t current_status = + get_reg_field_value( + value, + DC_HPD1_INT_STATUS, + DC_HPD1_SENSE_DELAYED); + + dal_irq_service_ack_generic(irq_service, info); + + value = dm_read_reg(irq_service->ctx, info->enable_reg); + + set_reg_field_value( + value, + current_status ? 0 : 1, + DC_HPD1_INT_CONTROL, + DC_HPD1_INT_POLARITY); + + dm_write_reg(irq_service->ctx, info->enable_reg, value); + + return true; +} + +static const struct irq_source_info_funcs hpd_irq_info_funcs = { + .set = NULL, + .ack = hpd_ack +}; + +static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs pflip_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs vblank_irq_info_funcs = { + .set = dce110_vblank_set, + .ack = NULL +}; + +static const struct irq_source_info_funcs vblank_irq_info_funcs_dce60 = { + .set = NULL, + .ack = NULL +}; + +#define hpd_int_entry(reg_num)\ + [DC_IRQ_SOURCE_INVALID + reg_num] = {\ + .enable_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\ + .enable_mask = DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK,\ + .enable_value = {\ + DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK,\ + ~DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK\ + },\ + .ack_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\ + .ack_mask = DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK,\ + .ack_value = DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK,\ + .status_reg = mmDC_HPD ## reg_num ## _INT_STATUS,\ + .funcs = &hpd_irq_info_funcs\ + } + +#define hpd_rx_int_entry(reg_num)\ + [DC_IRQ_SOURCE_HPD6 + reg_num] = {\ + .enable_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\ + .enable_mask = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK,\ + .enable_value = {\ + DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK,\ + ~DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK },\ + .ack_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\ + .ack_mask = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_ACK_MASK,\ + .ack_value = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_ACK_MASK,\ + .status_reg = mmDC_HPD ## reg_num ## _INT_STATUS,\ + .funcs = &hpd_rx_irq_info_funcs\ + } + +#define pflip_int_entry(reg_num)\ + [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\ + .enable_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_CONTROL,\ + .enable_mask =\ + GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ + .enable_value = {\ + GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ + ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\ + .ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\ + .ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ + .ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ + .status_reg = mmDCP ## reg_num ##_GRPH_INTERRUPT_STATUS,\ + .funcs = &pflip_irq_info_funcs\ + } + +#define vupdate_int_entry(reg_num)\ + [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ + .enable_reg = mmCRTC ## reg_num ## _CRTC_INTERRUPT_CONTROL,\ + .enable_mask =\ + CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ + .enable_value = {\ + CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ + ~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\ + .ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\ + .ack_mask =\ + CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\ + .ack_value =\ + CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\ + .funcs = &vblank_irq_info_funcs\ + } + +#define vblank_int_entry(reg_num)\ + [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ + .enable_reg = mmLB ## reg_num ## _INT_MASK,\ + .enable_mask =\ + INT_MASK__VBLANK_INT_MASK,\ + .enable_value = {\ + INT_MASK__VBLANK_INT_MASK,\ + ~INT_MASK__VBLANK_INT_MASK},\ + .ack_reg = mmLB ## reg_num ## _VBLANK_STATUS,\ + .ack_mask =\ + VBLANK_STATUS__VBLANK_ACK_MASK,\ + .ack_value =\ + VBLANK_STATUS__VBLANK_ACK_MASK,\ + .funcs = &vblank_irq_info_funcs_dce60\ + } + +#define dummy_irq_entry() \ + {\ + .funcs = &dummy_irq_info_funcs\ + } + +#define i2c_int_entry(reg_num) \ + [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry() + +#define dp_sink_int_entry(reg_num) \ + [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry() + +#define gpio_pad_int_entry(reg_num) \ + [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry() + +#define dc_underflow_int_entry(reg_num) \ + [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry() + + +static const struct irq_source_info_funcs dummy_irq_info_funcs = { + .set = dal_irq_service_dummy_set, + .ack = dal_irq_service_dummy_ack +}; + +static const struct irq_source_info +irq_source_info_dce60[DAL_IRQ_SOURCES_NUMBER] = { + [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(), + hpd_int_entry(1), + hpd_int_entry(2), + hpd_int_entry(3), + hpd_int_entry(4), + hpd_int_entry(5), + hpd_int_entry(6), + hpd_rx_int_entry(1), + hpd_rx_int_entry(2), + hpd_rx_int_entry(3), + hpd_rx_int_entry(4), + hpd_rx_int_entry(5), + hpd_rx_int_entry(6), + i2c_int_entry(1), + i2c_int_entry(2), + i2c_int_entry(3), + i2c_int_entry(4), + i2c_int_entry(5), + i2c_int_entry(6), + dp_sink_int_entry(1), + dp_sink_int_entry(2), + dp_sink_int_entry(3), + dp_sink_int_entry(4), + dp_sink_int_entry(5), + dp_sink_int_entry(6), + [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(), + pflip_int_entry(0), + pflip_int_entry(1), + pflip_int_entry(2), + pflip_int_entry(3), + pflip_int_entry(4), + pflip_int_entry(5), + [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(), + gpio_pad_int_entry(0), + gpio_pad_int_entry(1), + gpio_pad_int_entry(2), + gpio_pad_int_entry(3), + gpio_pad_int_entry(4), + gpio_pad_int_entry(5), + gpio_pad_int_entry(6), + gpio_pad_int_entry(7), + gpio_pad_int_entry(8), + gpio_pad_int_entry(9), + gpio_pad_int_entry(10), + gpio_pad_int_entry(11), + gpio_pad_int_entry(12), + gpio_pad_int_entry(13), + gpio_pad_int_entry(14), + gpio_pad_int_entry(15), + gpio_pad_int_entry(16), + gpio_pad_int_entry(17), + gpio_pad_int_entry(18), + gpio_pad_int_entry(19), + gpio_pad_int_entry(20), + gpio_pad_int_entry(21), + gpio_pad_int_entry(22), + gpio_pad_int_entry(23), + gpio_pad_int_entry(24), + gpio_pad_int_entry(25), + gpio_pad_int_entry(26), + gpio_pad_int_entry(27), + gpio_pad_int_entry(28), + gpio_pad_int_entry(29), + gpio_pad_int_entry(30), + dc_underflow_int_entry(1), + dc_underflow_int_entry(2), + dc_underflow_int_entry(3), + dc_underflow_int_entry(4), + dc_underflow_int_entry(5), + dc_underflow_int_entry(6), + [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), + [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), + vupdate_int_entry(0), + vupdate_int_entry(1), + vupdate_int_entry(2), + vupdate_int_entry(3), + vupdate_int_entry(4), + vupdate_int_entry(5), + vblank_int_entry(0), + vblank_int_entry(1), + vblank_int_entry(2), + vblank_int_entry(3), + vblank_int_entry(4), + vblank_int_entry(5), +}; + +enum dc_irq_source to_dal_irq_source_dce60( + struct irq_service *irq_service, + uint32_t src_id, + uint32_t ext_id) +{ + switch (src_id) { + case VISLANDS30_IV_SRCID_D1_VBLANK: + return DC_IRQ_SOURCE_VBLANK1; + case VISLANDS30_IV_SRCID_D2_VBLANK: + return DC_IRQ_SOURCE_VBLANK2; + case VISLANDS30_IV_SRCID_D3_VBLANK: + return DC_IRQ_SOURCE_VBLANK3; + case VISLANDS30_IV_SRCID_D4_VBLANK: + return DC_IRQ_SOURCE_VBLANK4; + case VISLANDS30_IV_SRCID_D5_VBLANK: + return DC_IRQ_SOURCE_VBLANK5; + case VISLANDS30_IV_SRCID_D6_VBLANK: + return DC_IRQ_SOURCE_VBLANK6; + case VISLANDS30_IV_SRCID_D1_V_UPDATE_INT: + return DC_IRQ_SOURCE_VUPDATE1; + case VISLANDS30_IV_SRCID_D2_V_UPDATE_INT: + return DC_IRQ_SOURCE_VUPDATE2; + case VISLANDS30_IV_SRCID_D3_V_UPDATE_INT: + return DC_IRQ_SOURCE_VUPDATE3; + case VISLANDS30_IV_SRCID_D4_V_UPDATE_INT: + return DC_IRQ_SOURCE_VUPDATE4; + case VISLANDS30_IV_SRCID_D5_V_UPDATE_INT: + return DC_IRQ_SOURCE_VUPDATE5; + case VISLANDS30_IV_SRCID_D6_V_UPDATE_INT: + return DC_IRQ_SOURCE_VUPDATE6; + case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP: + return DC_IRQ_SOURCE_PFLIP1; + case VISLANDS30_IV_SRCID_D2_GRPH_PFLIP: + return DC_IRQ_SOURCE_PFLIP2; + case VISLANDS30_IV_SRCID_D3_GRPH_PFLIP: + return DC_IRQ_SOURCE_PFLIP3; + case VISLANDS30_IV_SRCID_D4_GRPH_PFLIP: + return DC_IRQ_SOURCE_PFLIP4; + case VISLANDS30_IV_SRCID_D5_GRPH_PFLIP: + return DC_IRQ_SOURCE_PFLIP5; + case VISLANDS30_IV_SRCID_D6_GRPH_PFLIP: + return DC_IRQ_SOURCE_PFLIP6; + + case VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A: + /* generic src_id for all HPD and HPDRX interrupts */ + switch (ext_id) { + case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_A: + return DC_IRQ_SOURCE_HPD1; + case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_B: + return DC_IRQ_SOURCE_HPD2; + case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_C: + return DC_IRQ_SOURCE_HPD3; + case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_D: + return DC_IRQ_SOURCE_HPD4; + case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_E: + return DC_IRQ_SOURCE_HPD5; + case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_F: + return DC_IRQ_SOURCE_HPD6; + case VISLANDS30_IV_EXTID_HPD_RX_A: + return DC_IRQ_SOURCE_HPD1RX; + case VISLANDS30_IV_EXTID_HPD_RX_B: + return DC_IRQ_SOURCE_HPD2RX; + case VISLANDS30_IV_EXTID_HPD_RX_C: + return DC_IRQ_SOURCE_HPD3RX; + case VISLANDS30_IV_EXTID_HPD_RX_D: + return DC_IRQ_SOURCE_HPD4RX; + case VISLANDS30_IV_EXTID_HPD_RX_E: + return DC_IRQ_SOURCE_HPD5RX; + case VISLANDS30_IV_EXTID_HPD_RX_F: + return DC_IRQ_SOURCE_HPD6RX; + default: + return DC_IRQ_SOURCE_INVALID; + } + break; + + default: + return DC_IRQ_SOURCE_INVALID; + } +} + +static const struct irq_service_funcs irq_service_funcs_dce60 = { + .to_dal_irq_source = to_dal_irq_source_dce60 +}; + +static void dce60_irq_construct( + struct irq_service *irq_service, + struct irq_service_init_data *init_data) +{ + dal_irq_service_construct(irq_service, init_data); + + irq_service->info = irq_source_info_dce60; + irq_service->funcs = &irq_service_funcs_dce60; +} + +struct irq_service *dal_irq_service_dce60_create( + struct irq_service_init_data *init_data) +{ + struct irq_service *irq_service = kzalloc(sizeof(*irq_service), + GFP_KERNEL); + + if (!irq_service) + return NULL; + + dce60_irq_construct(irq_service, init_data); + return irq_service; +} + + diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce60/irq_service_dce60.h b/drivers/gpu/drm/amd/display/dc/irq/dce60/irq_service_dce60.h new file mode 100644 index 000000000000..294db29e8115 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/irq/dce60/irq_service_dce60.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Mauro Rossi <[email protected]> + * + * 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. + * + * Authors: AMD + * + */ + +#ifndef __DAL_IRQ_SERVICE_DCE60_H__ +#define __DAL_IRQ_SERVICE_DCE60_H__ + +#include "../irq_service.h" + +enum dc_irq_source to_dal_irq_source_dce60( + struct irq_service *irq_service, + uint32_t src_id, + uint32_t ext_id); + +struct irq_service *dal_irq_service_dce60_create( + struct irq_service_init_data *init_data); + +#endif + diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index 33053b9fe6bd..6bf27bde8724 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -32,6 +32,9 @@ #include "dce110/irq_service_dce110.h" +#if defined(CONFIG_DRM_AMD_DC_SI) +#include "dce60/irq_service_dce60.h" +#endif #include "dce80/irq_service_dce80.h" diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index c3bbfe397e8d..330acaaed79a 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -55,6 +55,10 @@ #include <asm/fpu/api.h> #define DC_FP_START() kernel_fpu_begin() #define DC_FP_END() kernel_fpu_end() +#elif defined(CONFIG_ARM64) +#include <asm/neon.h> +#define DC_FP_START() kernel_neon_begin() +#define DC_FP_END() kernel_neon_end() #elif defined(CONFIG_PPC64) #include <asm/switch_to.h> #include <asm/cputable.h> diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c index b8040da94b9d..944c0327763c 100644 --- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c @@ -87,6 +87,17 @@ static void virtual_enc_dp_set_odm_combine( bool odm_combine) {} +static void virtual_dig_connect_to_otg( + struct stream_encoder *enc, + int tg_inst) +{} + +static void virtual_setup_stereo_sync( + struct stream_encoder *enc, + int tg_inst, + bool enable) +{} + static const struct stream_encoder_funcs virtual_str_enc_funcs = { .dp_set_odm_combine = virtual_enc_dp_set_odm_combine, @@ -114,6 +125,8 @@ static const struct stream_encoder_funcs virtual_str_enc_funcs = { .audio_mute_control = virtual_audio_mute_control, .set_avmute = virtual_stream_encoder_set_avmute, .hdmi_reset_stream_attribute = virtual_stream_encoder_reset_hdmi_stream_attribute, + .dig_connect_to_otg = virtual_dig_connect_to_otg, + .setup_stereo_sync = virtual_setup_stereo_sync, }; bool virtual_stream_encoder_construct( 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 e013875b89ed..d7e7f2eda92f 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -36,11 +36,20 @@ /* Firmware versioning. */ #ifdef DMUB_EXPOSE_VERSION -#define DMUB_FW_VERSION_GIT_HASH 0xe6d590b09 +#define DMUB_FW_VERSION_GIT_HASH 0x4e5b2f46f #define DMUB_FW_VERSION_MAJOR 0 #define DMUB_FW_VERSION_MINOR 0 -#define DMUB_FW_VERSION_REVISION 25 -#define DMUB_FW_VERSION_UCODE ((DMUB_FW_VERSION_MAJOR << 24) | (DMUB_FW_VERSION_MINOR << 16) | DMUB_FW_VERSION_REVISION) +#define DMUB_FW_VERSION_REVISION 29 +#define DMUB_FW_VERSION_TEST 0 +#define DMUB_FW_VERSION_VBIOS 0 +#define DMUB_FW_VERSION_HOTFIX 0 +#define DMUB_FW_VERSION_UCODE (((DMUB_FW_VERSION_MAJOR & 0xFF) << 24) | \ + ((DMUB_FW_VERSION_MINOR & 0xFF) << 16) | \ + ((DMUB_FW_VERSION_REVISION & 0xFF) << 8) | \ + ((DMUB_FW_VERSION_TEST & 0x1) << 7) | \ + ((DMUB_FW_VERSION_VBIOS & 0x1) << 6) | \ + (DMUB_FW_VERSION_HOTFIX & 0x3F)) + #endif //<DMUB_TYPES>================================================================== @@ -204,6 +213,7 @@ enum dmub_cmd_vbios_type { DMUB_CMD__VBIOS_DIG1_TRANSMITTER_CONTROL = 1, DMUB_CMD__VBIOS_SET_PIXEL_CLOCK = 2, DMUB_CMD__VBIOS_ENABLE_DISP_POWER_GATING = 3, + DMUB_CMD__VBIOS_LVTMA_CONTROL = 15, }; //============================================================================== diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h index abeb58d544b1..b267987aed06 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -30,6 +30,34 @@ * ASIC internal revision ID */ +/* DCE60 (based on si_id.h in GPUOpen-Tools CodeXL) */ +#define SI_TAHITI_P_A0 0x01 +#define SI_TAHITI_P_B0 0x05 +#define SI_TAHITI_P_B1 0x06 +#define SI_PITCAIRN_PM_A0 0x14 +#define SI_PITCAIRN_PM_A1 0x15 +#define SI_CAPEVERDE_M_A0 0x28 +#define SI_CAPEVERDE_M_A1 0x29 +#define SI_OLAND_M_A0 0x3C +#define SI_HAINAN_V_A0 0x46 + +#define SI_UNKNOWN 0xFF + +#define ASIC_REV_IS_TAHITI_P(rev) \ + ((rev >= SI_TAHITI_P_A0) && (rev < SI_PITCAIRN_PM_A0)) + +#define ASIC_REV_IS_PITCAIRN_PM(rev) \ + ((rev >= SI_PITCAIRN_PM_A0) && (rev < SI_CAPEVERDE_M_A0)) + +#define ASIC_REV_IS_CAPEVERDE_M(rev) \ + ((rev >= SI_CAPEVERDE_M_A0) && (rev < SI_OLAND_M_A0)) + +#define ASIC_REV_IS_OLAND_M(rev) \ + ((rev >= SI_OLAND_M_A0) && (rev < SI_HAINAN_V_A0)) + +#define ASIC_REV_IS_HAINAN_V(rev) \ + ((rev >= SI_HAINAN_V_A0) && (rev < SI_UNKNOWN)) + /* DCE80 (based on ci_id.h in Perforce) */ #define CI_BONAIRE_M_A0 0x14 #define CI_BONAIRE_M_A1 0x15 @@ -181,6 +209,17 @@ enum { /* * ASIC chip ID */ + +/* DCE60 */ +#define DEVICE_ID_SI_TAHITI_P_6780 0x6780 +#define DEVICE_ID_SI_PITCAIRN_PM_6800 0x6800 +#define DEVICE_ID_SI_PITCAIRN_PM_6808 0x6808 +#define DEVICE_ID_SI_CAPEVERDE_M_6820 0x6820 +#define DEVICE_ID_SI_CAPEVERDE_M_6828 0x6828 +#define DEVICE_ID_SI_OLAND_M_6600 0x6600 +#define DEVICE_ID_SI_OLAND_M_6608 0x6608 +#define DEVICE_ID_SI_HAINAN_V_6660 0x6660 + /* DCE80 */ #define DEVICE_ID_KALINDI_9834 0x9834 #define DEVICE_ID_TEMASH_9839 0x9839 @@ -190,6 +229,7 @@ enum { #define DEVICE_ID_RENOIR_1636 0x1636 /* Asic Family IDs for different asic family. */ +#define FAMILY_SI 110 /* Southern Islands: Tahiti (P), Pitcairn (PM), Cape Verde (M), Oland (M), Hainan (V) */ #define FAMILY_CI 120 /* Sea Islands: Hawaii (P), Bonaire (M) */ #define FAMILY_KV 125 /* Fusion => Kaveri: Spectre, Spooky; Kabini: Kalindi */ #define FAMILY_VI 130 /* Volcanic Islands: Iceland (V), Tonga (M) */ diff --git a/drivers/gpu/drm/amd/display/include/dal_types.h b/drivers/gpu/drm/amd/display/include/dal_types.h index b67c9fa6b9cd..8aaa3af69202 100644 --- a/drivers/gpu/drm/amd/display/include/dal_types.h +++ b/drivers/gpu/drm/amd/display/include/dal_types.h @@ -34,6 +34,9 @@ struct dc_bios; enum dce_version { DCE_VERSION_UNKNOWN = (-1), + DCE_VERSION_6_0, + DCE_VERSION_6_1, + DCE_VERSION_6_4, DCE_VERSION_8_0, DCE_VERSION_8_1, DCE_VERSION_8_3, diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h index 13c57ff2abdc..1ab813b4fd14 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h @@ -37,6 +37,6 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream, struct dc_info_packet *info_packet); void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, - struct dc_info_packet *info_packet, int ALLMEnabled, int ALLMValue); + struct dc_info_packet *info_packet); #endif diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c index 7cd8a43d1889..0fdf7a3e96de 100644 --- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c @@ -421,15 +421,13 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream, ***************************************************************************** */ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, - struct dc_info_packet *info_packet, int ALLMEnabled, int ALLMValue) + struct dc_info_packet *info_packet) { unsigned int length = 5; bool hdmi_vic_mode = false; uint8_t checksum = 0; uint32_t i = 0; enum dc_timing_3d_format format; - bool bALLM = (bool)ALLMEnabled; - bool bALLMVal = (bool)ALLMValue; info_packet->valid = false; format = stream->timing.timing_3d_format; @@ -442,20 +440,13 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, && format == TIMING_3D_FORMAT_NONE) hdmi_vic_mode = true; - if ((format == TIMING_3D_FORMAT_NONE) && !hdmi_vic_mode && !bALLM) + if ((format == TIMING_3D_FORMAT_NONE) && !hdmi_vic_mode) return; info_packet->sb[1] = 0x03; info_packet->sb[2] = 0x0C; info_packet->sb[3] = 0x00; - if (bALLM) { - info_packet->sb[1] = 0xD8; - info_packet->sb[2] = 0x5D; - info_packet->sb[3] = 0xC4; - info_packet->sb[4] = HF_VSIF_VERSION; - } - if (format != TIMING_3D_FORMAT_NONE) info_packet->sb[4] = (2 << 5); @@ -490,9 +481,6 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, info_packet->hb1 = 0x01; info_packet->hb2 = (uint8_t) (length); - if (bALLM) - info_packet->sb[5] = (info_packet->sb[5] & ~0x02) | (bALLMVal << 1); - checksum += info_packet->hb0; checksum += info_packet->hb1; checksum += info_packet->hb2; 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 859724771a75..61497954e67e 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -657,7 +657,7 @@ void fill_iram_v_2_3(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parame params, ram_table, big_endian); } -bool dmub_init_abm_config(struct abm *abm, +bool dmub_init_abm_config(struct resource_pool *res_pool, struct dmcu_iram_parameters params) { struct iram_table_v_2_2 ram_table; @@ -665,8 +665,13 @@ bool dmub_init_abm_config(struct abm *abm, bool result = false; uint32_t i, j = 0; - if (abm == NULL) +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) + if (res_pool->abm == NULL && res_pool->multiple_abms[0] == NULL) return false; +#else + if (res_pool->abm == NULL) + return false; +#endif memset(&ram_table, 0, sizeof(ram_table)); memset(&config, 0, sizeof(config)); @@ -707,8 +712,14 @@ bool dmub_init_abm_config(struct abm *abm, config.min_abm_backlight = ram_table.min_abm_backlight; - result = abm->funcs->init_abm_config( - abm, (char *)(&config), sizeof(struct abm_config_table)); +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) + if (res_pool->multiple_abms[0]) { + result = res_pool->multiple_abms[0]->funcs->init_abm_config( + res_pool->multiple_abms[0], (char *)(&config), sizeof(struct abm_config_table)); + } else +#endif + result = res_pool->abm->funcs->init_abm_config( + res_pool->abm, (char *)(&config), sizeof(struct abm_config_table)); return result; } 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 46fbca2e2cd1..fa4728d88092 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h @@ -28,6 +28,8 @@ #include "dc/inc/hw/dmcu.h" #include "dc/inc/hw/abm.h" +struct resource_pool; + enum abm_defines { abm_defines_max_level = 4, @@ -45,7 +47,7 @@ struct dmcu_iram_parameters { bool dmcu_load_iram(struct dmcu *dmcu, struct dmcu_iram_parameters params); -bool dmub_init_abm_config(struct abm *abm, +bool dmub_init_abm_config(struct resource_pool *res_pool, struct dmcu_iram_parameters params); #endif /* MODULES_POWER_POWER_HELPERS_H_ */ diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_12_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_12_0_offset.h index 27bb8c1ab858..b6f74bf4af02 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_12_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_12_0_offset.h @@ -7376,8 +7376,6 @@ #define mmCRTC4_CRTC_DRR_CONTROL 0x0f3e #define mmCRTC4_CRTC_DRR_CONTROL_BASE_IDX 2 -#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0 0x395d -#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0_BASE_IDX 2 // addressBlock: dce_dc_fmt4_dispdec // base address: 0x2000 diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_d.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_d.h index ae798f768853..9de01ae574c0 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_d.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_d.h @@ -4444,14 +4444,90 @@ /* Registers that spilled out of sid.h */ #define mmDATA_FORMAT 0x1AC0 +#define mmLB0_DATA_FORMAT 0x1AC0 +#define mmLB1_DATA_FORMAT 0x1DC0 +#define mmLB2_DATA_FORMAT 0x40C0 +#define mmLB3_DATA_FORMAT 0x43C0 +#define mmLB4_DATA_FORMAT 0x46C0 +#define mmLB5_DATA_FORMAT 0x49C0 #define mmDESKTOP_HEIGHT 0x1AC1 +#define mmLB0_DESKTOP_HEIGHT 0x1AC1 +#define mmLB1_DESKTOP_HEIGHT 0x1DC1 +#define mmLB2_DESKTOP_HEIGHT 0x40C1 +#define mmLB3_DESKTOP_HEIGHT 0x43C1 +#define mmLB4_DESKTOP_HEIGHT 0x46C1 +#define mmLB5_DESKTOP_HEIGHT 0x49C1 #define mmDC_LB_MEMORY_SPLIT 0x1AC3 +#define mmLB0_DC_LB_MEMORY_SPLIT 0x1AC3 +#define mmLB1_DC_LB_MEMORY_SPLIT 0x1DC3 +#define mmLB2_DC_LB_MEMORY_SPLIT 0x40C3 +#define mmLB3_DC_LB_MEMORY_SPLIT 0x43C3 +#define mmLB4_DC_LB_MEMORY_SPLIT 0x46C3 +#define mmLB5_DC_LB_MEMORY_SPLIT 0x49C3 +#define mmDC_LB_MEM_SIZE 0x1AC4 +#define mmLB0_DC_LB_MEM_SIZE 0x1AC4 +#define mmLB1_DC_LB_MEM_SIZE 0x1DC4 +#define mmLB2_DC_LB_MEM_SIZE 0x40C4 +#define mmLB3_DC_LB_MEM_SIZE 0x43C4 +#define mmLB4_DC_LB_MEM_SIZE 0x46C4 +#define mmLB5_DC_LB_MEM_SIZE 0x49C4 #define mmPRIORITY_A_CNT 0x1AC6 +#define mmLB0_PRIORITY_A_CNT 0x1AC6 +#define mmLB1_PRIORITY_A_CNT 0x1DC6 +#define mmLB2_PRIORITY_A_CNT 0x40C6 +#define mmLB3_PRIORITY_A_CNT 0x43C6 +#define mmLB4_PRIORITY_A_CNT 0x46C6 +#define mmLB5_PRIORITY_A_CNT 0x49C6 #define mmPRIORITY_B_CNT 0x1AC7 +#define mmLB0_PRIORITY_B_CNT 0x1AC7 +#define mmLB1_PRIORITY_B_CNT 0x1DC7 +#define mmLB2_PRIORITY_B_CNT 0x40C7 +#define mmLB3_PRIORITY_B_CNT 0x43C7 +#define mmLB4_PRIORITY_B_CNT 0x46C7 +#define mmLB5_PRIORITY_B_CNT 0x49C7 #define mmDPG_PIPE_ARBITRATION_CONTROL3 0x1B32 +#define mmDMIF_PG0_DPG_PIPE_ARBITRATION_CONTROL3 0x1B32 +#define mmDMIF_PG1_DPG_PIPE_ARBITRATION_CONTROL3 0x1E32 +#define mmDMIF_PG2_DPG_PIPE_ARBITRATION_CONTROL3 0x4132 +#define mmDMIF_PG3_DPG_PIPE_ARBITRATION_CONTROL3 0x4432 +#define mmDMIF_PG4_DPG_PIPE_ARBITRATION_CONTROL3 0x4732 +#define mmDMIF_PG5_DPG_PIPE_ARBITRATION_CONTROL3 0x4A32 #define mmINT_MASK 0x1AD0 +#define mmLB0_INT_MASK 0x1AD0 +#define mmLB1_INT_MASK 0x1DD0 +#define mmLB2_INT_MASK 0x40D0 +#define mmLB3_INT_MASK 0x43D0 +#define mmLB4_INT_MASK 0x46D0 +#define mmLB5_INT_MASK 0x49D0 #define mmVLINE_STATUS 0x1AEE +#define mmLB0_VLINE_STATUS 0x1AEE +#define mmLB1_VLINE_STATUS 0x1DEE +#define mmLB2_VLINE_STATUS 0x40EE +#define mmLB3_VLINE_STATUS 0x43EE +#define mmLB4_VLINE_STATUS 0x46EE +#define mmLB5_VLINE_STATUS 0x49EE #define mmVBLANK_STATUS 0x1AEF +#define mmLB0_VBLANK_STATUS 0x1AEF +#define mmLB1_VBLANK_STATUS 0x1DEF +#define mmLB2_VBLANK_STATUS 0x40EF +#define mmLB3_VBLANK_STATUS 0x43EF +#define mmLB4_VBLANK_STATUS 0x46EF +#define mmLB5_VBLANK_STATUS 0x49EF +#define mmSCL_HORZ_FILTER_INIT_RGB_LUMA 0x1B4C +#define mmSCL0_SCL_HORZ_FILTER_INIT_RGB_LUMA 0x1B4C +#define mmSCL1_SCL_HORZ_FILTER_INIT_RGB_LUMA 0x1E4C +#define mmSCL2_SCL_HORZ_FILTER_INIT_RGB_LUMA 0x414C +#define mmSCL3_SCL_HORZ_FILTER_INIT_RGB_LUMA 0x444C +#define mmSCL4_SCL_HORZ_FILTER_INIT_RGB_LUMA 0x474C +#define mmSCL5_SCL_HORZ_FILTER_INIT_RGB_LUMA 0x4A4C + +#define mmSCL_HORZ_FILTER_INIT_CHROMA 0x1B4D +#define mmSCL0_SCL_HORZ_FILTER_INIT_CHROMA 0x1B4D +#define mmSCL1_SCL_HORZ_FILTER_INIT_CHROMA 0x1E4D +#define mmSCL2_SCL_HORZ_FILTER_INIT_CHROMA 0x414D +#define mmSCL3_SCL_HORZ_FILTER_INIT_CHROMA 0x444D +#define mmSCL4_SCL_HORZ_FILTER_INIT_CHROMA 0x474D +#define mmSCL5_SCL_HORZ_FILTER_INIT_CHROMA 0x4A4D #endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h index abe05bc80752..41c4a46ce357 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dce/dce_6_0_sh_mask.h @@ -2076,6 +2076,8 @@ #define CRTC_CONTROL__CRTC_START_POINT_CNTL__SHIFT 0x0000000c #define CRTC_CONTROL__CRTC_SYNC_RESET_SEL_MASK 0x00000010L #define CRTC_CONTROL__CRTC_SYNC_RESET_SEL__SHIFT 0x00000004 +#define CRTC_CONTROL__CRTC_PREFETCH_EN_MASK 0x10000000L +#define CRTC_CONTROL__CRTC_PREFETCH_EN__SHIFT 0x0000001c #define CRTC_COUNT_CONTROL__CRTC_HORZ_COUNT_BY2_EN_MASK 0x00000001L #define CRTC_COUNT_CONTROL__CRTC_HORZ_COUNT_BY2_EN__SHIFT 0x00000000 #define CRTC_COUNT_CONTROL__CRTC_HORZ_REPETITION_COUNT_MASK 0x0000001eL @@ -6364,6 +6366,8 @@ #define DPG_PIPE_ARBITRATION_CONTROL2__TIME_WEIGHT__SHIFT 0x00000000 #define DPG_PIPE_ARBITRATION_CONTROL2__URGENCY_WEIGHT_MASK 0xffff0000L #define DPG_PIPE_ARBITRATION_CONTROL2__URGENCY_WEIGHT__SHIFT 0x00000010 +#define DPG_PIPE_ARBITRATION_CONTROL3__URGENCY_WATERMARK_MASK_MASK 0x00030000L +#define DPG_PIPE_ARBITRATION_CONTROL3__URGENCY_WATERMARK_MASK__SHIFT 0x00000010 #define DPG_PIPE_DPM_CONTROL__DPM_ENABLE_MASK 0x00000001L #define DPG_PIPE_DPM_CONTROL__DPM_ENABLE__SHIFT 0x00000000 #define DPG_PIPE_DPM_CONTROL__MCLK_CHANGE_ENABLE_MASK 0x00000010L @@ -6384,6 +6388,8 @@ #define DPG_PIPE_NB_PSTATE_CHANGE_CONTROL__NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST__SHIFT 0x00000008 #define DPG_PIPE_NB_PSTATE_CHANGE_CONTROL__NB_PSTATE_CHANGE_URGENT_DURING_REQUEST_MASK 0x00000010L #define DPG_PIPE_NB_PSTATE_CHANGE_CONTROL__NB_PSTATE_CHANGE_URGENT_DURING_REQUEST__SHIFT 0x00000004 +#define DPG_PIPE_NB_PSTATE_CHANGE_CONTROL__NB_PSTATE_CHANGE_WATERMARK_MASK_MASK 0x00003000L +#define DPG_PIPE_NB_PSTATE_CHANGE_CONTROL__NB_PSTATE_CHANGE_WATERMARK_MASK__SHIFT 0x0000000c #define DPG_PIPE_NB_PSTATE_CHANGE_CONTROL__NB_PSTATE_CHANGE_WATERMARK_MASK 0xffff0000L #define DPG_PIPE_NB_PSTATE_CHANGE_CONTROL__NB_PSTATE_CHANGE_WATERMARK__SHIFT 0x00000010 #define DPG_PIPE_STUTTER_CONTROL_NONLPTCH__STUTTER_ENABLE_NONLPTCH_MASK 0x00000001L @@ -6406,6 +6412,8 @@ #define DPG_PIPE_STUTTER_CONTROL_NONLPTCH__STUTTER_WM_HIGH_FORCE_ON_NONLPTCH__SHIFT 0x00000008 #define DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE_MASK 0x00000001L #define DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE__SHIFT 0x00000000 +#define DPG_PIPE_STUTTER_CONTROL__STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK_MASK 0x00003000L +#define DPG_PIPE_STUTTER_CONTROL__STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK__SHIFT 0x0000000c #define DPG_PIPE_STUTTER_CONTROL__STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK 0xffff0000L #define DPG_PIPE_STUTTER_CONTROL__STUTTER_EXIT_SELF_REFRESH_WATERMARK__SHIFT 0x00000010 #define DPG_PIPE_STUTTER_CONTROL__STUTTER_IGNORE_CURSOR_MASK 0x00000010L @@ -7256,6 +7264,8 @@ #define GRPH_CONTROL__GRPH_FORMAT__SHIFT 0x00000008 #define GRPH_CONTROL__GRPH_MACRO_TILE_ASPECT_MASK 0x000c0000L #define GRPH_CONTROL__GRPH_MACRO_TILE_ASPECT__SHIFT 0x00000012 +#define GRPH_CONTROL__GRPH_ARRAY_MODE_MASK 0x00f00000L +#define GRPH_CONTROL__GRPH_ARRAY_MODE__SHIFT 0x00000014 #define GRPH_CONTROL__GRPH_NUM_BANKS_MASK 0x0000000cL #define GRPH_CONTROL__GRPH_NUM_BANKS__SHIFT 0x00000002 #define GRPH_CONTROL__GRPH_PIPE_CONFIG_MASK 0x1f000000L @@ -9835,4 +9845,98 @@ #define XDMA_TEST_DEBUG_INDEX__XDMA_TEST_DEBUG_WRITE_EN_MASK 0x00000100L #define XDMA_TEST_DEBUG_INDEX__XDMA_TEST_DEBUG_WRITE_EN__SHIFT 0x00000008 +// DATA_FORMAT +#define DATA_FORMAT__INTERLEAVE_EN_MASK 0x00000001L +#define DATA_FORMAT__INTERLEAVE_EN__SHIFT 0x00000000 +#define DATA_FORMAT__RESET_REQ_AT_EOL_MASK 0x00000010L +#define DATA_FORMAT__RESET_REQ_AT_EOL__SHIFT 0x00000004 +#define DATA_FORMAT__PREFETCH_MASK 0x00001000L +#define DATA_FORMAT__PREFETCH__SHIFT 0x0000000c +#define DATA_FORMAT__SOF_READ_PT_MASK 0x001f0000L +#define DATA_FORMAT__SOF_READ_PT__SHIFT 0x00000010 +#define DATA_FORMAT__REQUEST_MODE_MASK 0x03000000L +#define DATA_FORMAT__REQUEST_MODE__SHIFT 0x00000018 +#define DATA_FORMAT__ALLOW_REQ_MODE_1_2_MASK 0x10000000L +#define DATA_FORMAT__ALLOW_REQ_MODE_1_2__SHIFT 0x0000001c + + +// DC_LB_MEMORY_SPLIT +#define DC_LB_MEMORY_SPLIT__LB_NUM_PARTITIONS_MASK 0x000f0000L +#define DC_LB_MEMORY_SPLIT__LB_NUM_PARTITIONS__SHIFT 0x00000010 +#define DC_LB_MEMORY_SPLIT__DC_LB_MEMORY_CONFIG_MASK 0x00300000L +#define DC_LB_MEMORY_SPLIT__DC_LB_MEMORY_CONFIG__SHIFT 0x00000014 + +// DC_LB_MEM_SIZE +#define DC_LB_MEM_SIZE__DC_LB_MEM_SIZE_MASK 0x000007ffL +#define DC_LB_MEM_SIZE__DC_LB_MEM_SIZE__SHIFT 0x00000000 + +// SCL_TAP_CONTROL +#define SCL_TAP_CONTROL__SCL_V_NUM_OF_TAPS_MASK 0x00000007L +#define SCL_TAP_CONTROL__SCL_V_NUM_OF_TAPS__SHIFT 0x00000000 +#define SCL_TAP_CONTROL__SCL_H_NUM_OF_TAPS_MASK 0x00000f00L +#define SCL_TAP_CONTROL__SCL_H_NUM_OF_TAPS__SHIFT 0x00000008 + +// INT_MASK +#define INT_MASK__VBLANK_INT_MASK 0x00000001L +#define INT_MASK__VBLANK_INT__SHIFT 0x00000000 +#define INT_MASK__VLINE_INT_MASK 0x00000010L +#define INT_MASK__VLINE_INT__SHIFT 0x00000004 + +// PRIORITY_A_CNT +#define PRIORITY_A_CNT__PRIORITY_MARK_A_MASK 0x00007fffL +#define PRIORITY_A_CNT__PRIORITY_MARK_A__SHIFT 0x00000000 +#define PRIORITY_A_CNT__PRIORITY_A_OFF_MASK 0x00010000L +#define PRIORITY_A_CNT__PRIORITY_A_OFF__SHIFT 0x00000010 +#define PRIORITY_A_CNT__PRIORITY_A_ALWAYS_ON_MASK 0x00100000L +#define PRIORITY_A_CNT__PRIORITY_A_ALWAYS_ON__SHIFT 0x00000014 +#define PRIORITY_A_CNT__PRIORITY_A_FORCE_MASK_MASK 0x01000000L +#define PRIORITY_A_CNT__PRIORITY_A_FORCE_MASK__SHIFT 0x00000018 + +// PRIORITY_B_CNT +#define PRIORITY_B_CNT__PRIORITY_MARK_B_MASK 0x00007fffL +#define PRIORITY_B_CNT__PRIORITY_MARK_B__SHIFT 0x00000000 +#define PRIORITY_B_CNT__PRIORITY_B_OFF_MASK 0x00010000L +#define PRIORITY_B_CNT__PRIORITY_B_OFF__SHIFT 0x00000010 +#define PRIORITY_B_CNT__PRIORITY_B_ALWAYS_ON_MASK 0x00100000L +#define PRIORITY_B_CNT__PRIORITY_B_ALWAYS_ON__SHIFT 0x00000014 +#define PRIORITY_B_CNT__PRIORITY_B_FORCE_MASK_MASK 0x01000000L +#define PRIORITY_B_CNT__PRIORITY_B_FORCE_MASK__SHIFT 0x00000018 + +// VLINE_STATUS +#define VLINE_STATUS__VLINE_OCCURRED_MASK 0x00000001L +#define VLINE_STATUS__VLINE_OCCURRED__SHIFT 0x00000000 +#define VLINE_STATUS__VLINE_ACK_MASK 0x00000010L +#define VLINE_STATUS__VLINE_ACK__SHIFT 0x00000004 +#define VLINE_STATUS__VLINE_STAT_MASK 0x00001000L +#define VLINE_STATUS__VLINE_STAT__SHIFT 0x0000000c +#define VLINE_STATUS__VLINE_INTERRUPT_MASK 0x00010000L +#define VLINE_STATUS__VLINE_INTERRUPT__SHIFT 0x00000010 +#define VLINE_STATUS__VLINE_INTERRUPT_TYPE_MASK 0x00020000L +#define VLINE_STATUS__VLINE_INTERRUPT_TYPE__SHIFT 0x00000011 + +// VBLANK_STATUS +#define VBLANK_STATUS__VBLANK_OCCURRED_MASK 0x00000001L +#define VBLANK_STATUS__VBLANK_OCCURRED__SHIFT 0x00000000 +#define VBLANK_STATUS__VBLANK_ACK_MASK 0x00000010L +#define VBLANK_STATUS__VBLANK_ACK__SHIFT 0x00000004 +#define VBLANK_STATUS__VBLANK_STAT_MASK 0x00001000L +#define VBLANK_STATUS__VBLANK_STAT__SHIFT 0x0000000c +#define VBLANK_STATUS__VBLANK_INTERRUPT_MASK 0x00010000L +#define VBLANK_STATUS__VBLANK_INTERRUPT__SHIFT 0x00000010 +#define VBLANK_STATUS__VBLANK_INTERRUPT_TYPE_MASK 0x00020000L +#define VBLANK_STATUS__VBLANK_INTERRUPT_TYPE__SHIFT 0x00000011 + +// SCL_HORZ_FILTER_INIT_RGB_LUMA +#define SCL_HORZ_FILTER_INIT_RGB_LUMA__SCL_H_INIT_FRAC_RGB_Y_MASK 0x0000ffffL +#define SCL_HORZ_FILTER_INIT_RGB_LUMA__SCL_H_INIT_FRAC_RGB_Y__SHIFT 0x00000000 +#define SCL_HORZ_FILTER_INIT_RGB_LUMA__SCL_H_INIT_INT_RGB_Y_MASK 0x000f0000L +#define SCL_HORZ_FILTER_INIT_RGB_LUMA__SCL_H_INIT_INT_RGB_Y__SHIFT 0x00000010 + +// SCL_HORZ_FILTER_INIT_CHROMA +#define SCL_HORZ_FILTER_INIT_CHROMA__SCL_H_INIT_FRAC_CBCR_MASK 0x0000ffffL +#define SCL_HORZ_FILTER_INIT_CHROMA__SCL_H_INIT_FRAC_CBCR__SHIFT 0x00000000 +#define SCL_HORZ_FILTER_INIT_CHROMA__SCL_H_INIT_INT_CBCR_MASK 0x00070000L +#define SCL_HORZ_FILTER_INIT_CHROMA__SCL_H_INIT_INT_CBCR__SHIFT 0x00000010 + + #endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h index cf166b591bc5..cf166b591bc5 100755..100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_offset.h diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h index 0e0319e98c07..ea683f452bb3 100755..100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_0_0_sh_mask.h @@ -50271,6 +50271,10 @@ #define DSC_TOP0_DSC_TOP_CONTROL__DSC_CLOCK_EN_MASK 0x00000001L #define DSC_TOP0_DSC_TOP_CONTROL__DSC_DISPCLK_R_GATE_DIS_MASK 0x00000010L #define DSC_TOP0_DSC_TOP_CONTROL__DSC_DSCCLK_R_GATE_DIS_MASK 0x00000100L +//DSC_TOP0_DSC_DEBUG_CONTROL +#define DSC_TOP0_DSC_DEBUG_CONTROL__DSC_DBG_EN__SHIFT 0x0 +#define DSC_TOP0_DSC_DEBUG_CONTROL__DSC_DBG_EN_MASK 0x00000001L + // addressBlock: dce_dc_dsc0_dispdec_dsccif_dispdec //DSCCIF0_DSCCIF_CONFIG0 @@ -50789,6 +50793,9 @@ #define DSC_TOP1_DSC_TOP_CONTROL__DSC_CLOCK_EN_MASK 0x00000001L #define DSC_TOP1_DSC_TOP_CONTROL__DSC_DISPCLK_R_GATE_DIS_MASK 0x00000010L #define DSC_TOP1_DSC_TOP_CONTROL__DSC_DSCCLK_R_GATE_DIS_MASK 0x00000100L +//DSC_TOP1_DSC_DEBUG_CONTROL +#define DSC_TOP1_DSC_DEBUG_CONTROL__DSC_DBG_EN__SHIFT 0x0 +#define DSC_TOP1_DSC_DEBUG_CONTROL__DSC_DBG_EN_MASK 0x00000001L // addressBlock: dce_dc_dsc1_dispdec_dsccif_dispdec @@ -51308,6 +51315,10 @@ #define DSC_TOP2_DSC_TOP_CONTROL__DSC_CLOCK_EN_MASK 0x00000001L #define DSC_TOP2_DSC_TOP_CONTROL__DSC_DISPCLK_R_GATE_DIS_MASK 0x00000010L #define DSC_TOP2_DSC_TOP_CONTROL__DSC_DSCCLK_R_GATE_DIS_MASK 0x00000100L +//DSC_TOP2_DSC_DEBUG_CONTROL +#define DSC_TOP2_DSC_DEBUG_CONTROL__DSC_DBG_EN__SHIFT 0x0 +#define DSC_TOP2_DSC_DEBUG_CONTROL__DSC_DBG_EN_MASK 0x00000001L + // addressBlock: dce_dc_dsc2_dispdec_dsccif_dispdec //DSCCIF2_DSCCIF_CONFIG0 @@ -51826,6 +51837,9 @@ #define DSC_TOP3_DSC_TOP_CONTROL__DSC_CLOCK_EN_MASK 0x00000001L #define DSC_TOP3_DSC_TOP_CONTROL__DSC_DISPCLK_R_GATE_DIS_MASK 0x00000010L #define DSC_TOP3_DSC_TOP_CONTROL__DSC_DSCCLK_R_GATE_DIS_MASK 0x00000100L +//DSC_TOP3_DSC_DEBUG_CONTROL +#define DSC_TOP3_DSC_DEBUG_CONTROL__DSC_DBG_EN__SHIFT 0x0 +#define DSC_TOP3_DSC_DEBUG_CONTROL__DSC_DBG_EN_MASK 0x00000001L // addressBlock: dce_dc_dsc3_dispdec_dsccif_dispdec @@ -52346,6 +52360,10 @@ #define DSC_TOP4_DSC_TOP_CONTROL__DSC_CLOCK_EN_MASK 0x00000001L #define DSC_TOP4_DSC_TOP_CONTROL__DSC_DISPCLK_R_GATE_DIS_MASK 0x00000010L #define DSC_TOP4_DSC_TOP_CONTROL__DSC_DSCCLK_R_GATE_DIS_MASK 0x00000100L +//DSC_TOP4_DSC_DEBUG_CONTROL +#define DSC_TOP4_DSC_DEBUG_CONTROL__DSC_DBG_EN__SHIFT 0x0 +#define DSC_TOP4_DSC_DEBUG_CONTROL__DSC_DBG_EN_MASK 0x00000001L + // addressBlock: dce_dc_dsc4_dispdec_dsccif_dispdec //DSCCIF4_DSCCIF_CONFIG0 @@ -52864,6 +52882,10 @@ #define DSC_TOP5_DSC_TOP_CONTROL__DSC_CLOCK_EN_MASK 0x00000001L #define DSC_TOP5_DSC_TOP_CONTROL__DSC_DISPCLK_R_GATE_DIS_MASK 0x00000010L #define DSC_TOP5_DSC_TOP_CONTROL__DSC_DSCCLK_R_GATE_DIS_MASK 0x00000100L +//DSC_TOP5_DSC_DEBUG_CONTROL +#define DSC_TOP5_DSC_DEBUG_CONTROL__DSC_DBG_EN__SHIFT 0x0 +#define DSC_TOP5_DSC_DEBUG_CONTROL__DSC_DBG_EN_MASK 0x00000001L + // addressBlock: dce_dc_dsc5_dispdec_dsccif_dispdec //DSCCIF5_DSCCIF_CONFIG0 diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dpcs_3_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dpcs_3_0_0_offset.h index 67faaf68e9d7..67faaf68e9d7 100755..100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dpcs_3_0_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dpcs_3_0_0_offset.h diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dpcs_3_0_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dpcs_3_0_0_sh_mask.h index b4ef50a72868..b4ef50a72868 100755..100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dpcs_3_0_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dpcs_3_0_0_sh_mask.h diff --git a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_offset.h index 05d1b0a5f6d2..cbaad7d83194 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_offset.h @@ -9180,6 +9180,8 @@ #define mmRLC_GPM_THREAD_ENABLE_BASE_IDX 1 #define mmRLC_RLCG_DOORBELL_RANGE 0x4c47 #define mmRLC_RLCG_DOORBELL_RANGE_BASE_IDX 1 +#define mmRLC_CGTT_MGCG_OVERRIDE 0x4c48 +#define mmRLC_CGTT_MGCG_OVERRIDE_BASE_IDX 1 #define mmRLC_CGCG_CGLS_CTRL 0x4c49 #define mmRLC_CGCG_CGLS_CTRL_BASE_IDX 1 #define mmRLC_CGCG_RAMP_CTRL 0x4c4a diff --git a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_sh_mask.h index aac57f714cf1..c2d035ef3e94 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_sh_mask.h @@ -32315,6 +32315,31 @@ #define RLC_RLCG_DOORBELL_CNTL__DOORBELL_3_MODE_MASK 0x000000C0L #define RLC_RLCG_DOORBELL_CNTL__DOORBELL_ID_MASK 0x001F0000L #define RLC_RLCG_DOORBELL_CNTL__DOORBELL_ID_EN_MASK 0x00200000L +//RLC_CGTT_MGCG_OVERRIDE +#define RLC_CGTT_MGCG_OVERRIDE__RESERVED_0__SHIFT 0x0 +#define RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE__SHIFT 0x1 +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE__SHIFT 0x2 +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGCG_OVERRIDE__SHIFT 0x3 +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGLS_OVERRIDE__SHIFT 0x4 +#define RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE__SHIFT 0x5 +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE__SHIFT 0x6 +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_GFX3D_CG_OVERRIDE__SHIFT 0x7 +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_FGCG_OVERRIDE__SHIFT 0x8 +#define RLC_CGTT_MGCG_OVERRIDE__RESERVED_15_9__SHIFT 0x9 +#define RLC_CGTT_MGCG_OVERRIDE__ENABLE_CGTS_LEGACY__SHIFT 0x10 +#define RLC_CGTT_MGCG_OVERRIDE__RESERVED_31_17__SHIFT 0x11 +#define RLC_CGTT_MGCG_OVERRIDE__RESERVED_0_MASK 0x00000001L +#define RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK 0x00000002L +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK 0x00000004L +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGCG_OVERRIDE_MASK 0x00000008L +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGLS_OVERRIDE_MASK 0x00000010L +#define RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK 0x00000020L +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK 0x00000040L +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_GFX3D_CG_OVERRIDE_MASK 0x00000080L +#define RLC_CGTT_MGCG_OVERRIDE__GFXIP_FGCG_OVERRIDE_MASK 0x00000100L +#define RLC_CGTT_MGCG_OVERRIDE__RESERVED_15_9_MASK 0x0000FE00L +#define RLC_CGTT_MGCG_OVERRIDE__ENABLE_CGTS_LEGACY_MASK 0x00010000L +#define RLC_CGTT_MGCG_OVERRIDE__RESERVED_31_17_MASK 0xFFFE0000L //RLC_RLCG_DOORBELL_STAT #define RLC_RLCG_DOORBELL_STAT__DOORBELL_0_VALID__SHIFT 0x0 #define RLC_RLCG_DOORBELL_STAT__DOORBELL_1_VALID__SHIFT 0x1 diff --git a/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_offset.h new file mode 100644 index 000000000000..3685766c4d56 --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_offset.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 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) 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 _umc_8_7_0_OFFSET_HEADER +#define _umc_8_7_0_OFFSET_HEADER + +#define mmUMCCH0_0_GeccErrCntSel 0x0328 +#define mmUMCCH0_0_GeccErrCntSel_BASE_IDX 0 +#define mmUMCCH0_0_GeccErrCnt 0x0329 +#define mmUMCCH0_0_GeccErrCnt_BASE_IDX 0 +#define mmMCA_UMC_UMC0_MCUMC_STATUST0 0x03c2 +#define mmMCA_UMC_UMC0_MCUMC_STATUST0_BASE_IDX 0 +#define mmMCA_UMC_UMC0_MCUMC_ADDRT0 0x03c4 +#define mmMCA_UMC_UMC0_MCUMC_ADDRT0_BASE_IDX 0 + +#endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_sh_mask.h new file mode 100644 index 000000000000..4c5097fa0c09 --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_sh_mask.h @@ -0,0 +1,79 @@ +#ifndef _umc_8_7_0_SH_MASK_HEADER
+#define _umc_8_7_0_SH_MASK_HEADER
+
+//UMCCH0_0_GeccErrCntSel
+#define UMCCH0_0_GeccErrCntSel__GeccErrCntCsSel__SHIFT 0x0
+#define UMCCH0_0_GeccErrCntSel__GeccErrInt__SHIFT 0xc
+#define UMCCH0_0_GeccErrCntSel__GeccErrCntEn__SHIFT 0xf
+#define UMCCH0_0_GeccErrCntSel__PoisonCntEn__SHIFT 0x10
+#define UMCCH0_0_GeccErrCntSel__GeccErrCntCsSel_MASK 0x0000000FL
+#define UMCCH0_0_GeccErrCntSel__GeccErrInt_MASK 0x00003000L
+#define UMCCH0_0_GeccErrCntSel__GeccErrCntEn_MASK 0x00008000L
+#define UMCCH0_0_GeccErrCntSel__PoisonCntEn_MASK 0x00030000L
+//UMCCH0_0_GeccErrCnt
+#define UMCCH0_0_GeccErrCnt__GeccErrCnt__SHIFT 0x0
+#define UMCCH0_0_GeccErrCnt__GeccUnCorrErrCnt__SHIFT 0x10
+#define UMCCH0_0_GeccErrCnt__GeccErrCnt_MASK 0x0000FFFFL
+#define UMCCH0_0_GeccErrCnt__GeccUnCorrErrCnt_MASK 0xFFFF0000L
+//MCA_UMC_UMC0_MCUMC_STATUST0
+#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCode__SHIFT 0x0
+#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCodeExt__SHIFT 0x10
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV22__SHIFT 0x16
+#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrLsb__SHIFT 0x18
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV30__SHIFT 0x1e
+#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreId__SHIFT 0x20
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV38__SHIFT 0x26
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Scrub__SHIFT 0x28
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV41__SHIFT 0x29
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Poison__SHIFT 0x2b
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Deferred__SHIFT 0x2c
+#define MCA_UMC_UMC0_MCUMC_STATUST0__UECC__SHIFT 0x2d
+#define MCA_UMC_UMC0_MCUMC_STATUST0__CECC__SHIFT 0x2e
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV47__SHIFT 0x2f
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Transparent__SHIFT 0x34
+#define MCA_UMC_UMC0_MCUMC_STATUST0__SyndV__SHIFT 0x35
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV54__SHIFT 0x36
+#define MCA_UMC_UMC0_MCUMC_STATUST0__TCC__SHIFT 0x37
+#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreIdVal__SHIFT 0x38
+#define MCA_UMC_UMC0_MCUMC_STATUST0__PCC__SHIFT 0x39
+#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrV__SHIFT 0x3a
+#define MCA_UMC_UMC0_MCUMC_STATUST0__MiscV__SHIFT 0x3b
+#define MCA_UMC_UMC0_MCUMC_STATUST0__En__SHIFT 0x3c
+#define MCA_UMC_UMC0_MCUMC_STATUST0__UC__SHIFT 0x3d
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Overflow__SHIFT 0x3e
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Val__SHIFT 0x3f
+#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCode_MASK 0x000000000000FFFFL
+#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCodeExt_MASK 0x00000000003F0000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV22_MASK 0x0000000000C00000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrLsb_MASK 0x000000003F000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV30_MASK 0x00000000C0000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreId_MASK 0x0000003F00000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV38_MASK 0x000000C000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Scrub_MASK 0x0000010000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV41_MASK 0x0000060000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Poison_MASK 0x0000080000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Deferred_MASK 0x0000100000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__UECC_MASK 0x0000200000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__CECC_MASK 0x0000400000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV47_MASK 0x000F800000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Transparent_MASK 0x0010000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__SyndV_MASK 0x0020000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV54_MASK 0x0040000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__TCC_MASK 0x0080000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreIdVal_MASK 0x0100000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__PCC_MASK 0x0200000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrV_MASK 0x0400000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__MiscV_MASK 0x0800000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__En_MASK 0x1000000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__UC_MASK 0x2000000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Overflow_MASK 0x4000000000000000L
+#define MCA_UMC_UMC0_MCUMC_STATUST0__Val_MASK 0x8000000000000000L
+//MCA_UMC_UMC0_MCUMC_ADDRT0
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__ErrorAddr__SHIFT 0x0
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__LSB__SHIFT 0x38
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__Reserved__SHIFT 0x3e
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__ErrorAddr_MASK 0x00FFFFFFFFFFFFFFL
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__LSB_MASK 0x3F00000000000000L
+#define MCA_UMC_UMC0_MCUMC_ADDRT0__Reserved_MASK 0xC000000000000000L
+
+#endif
diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index a3c238c39ef5..fc592f60e6a0 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -212,10 +212,6 @@ struct tile_config { * IH ring entry. This function allows the KFD ISR to get the VMID * from the fault status register as early as possible. * - * @get_hive_id: Returns hive id of current device, 0 if xgmi is not enabled - * - * @get_unique_id: Returns uuid id of current device - * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -290,9 +286,6 @@ struct kfd2kgd_calls { void (*set_vm_context_page_table_base)(struct kgd_dev *kgd, uint32_t vmid, uint64_t page_table_base); uint32_t (*read_vmid_from_vmfault_reg)(struct kgd_dev *kgd); - uint64_t (*get_hive_id)(struct kgd_dev *kgd); - uint64_t (*get_unique_id)(struct kgd_dev *kgd); - }; #endif /* KGD_KFD_INTERFACE_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index a7f92d0b3a90..0aec28fda058 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -322,6 +322,115 @@ struct amd_pm_funcs { int (*asic_reset_mode_2)(void *handle); int (*set_df_cstate)(void *handle, enum pp_df_cstate state); int (*set_xgmi_pstate)(void *handle, uint32_t pstate); + ssize_t (*get_gpu_metrics)(void *handle, void **table); +}; + +struct metrics_table_header { + uint16_t structure_size; + uint8_t format_revision; + uint8_t content_revision; +}; + +struct gpu_metrics_v1_0 { + struct metrics_table_header common_header; + + /* Driver attached timestamp (in ns) */ + uint64_t system_clock_counter; + + /* Temperature */ + uint16_t temperature_edge; + uint16_t temperature_hotspot; + uint16_t temperature_mem; + uint16_t temperature_vrgfx; + uint16_t temperature_vrsoc; + uint16_t temperature_vrmem; + + /* Utilization */ + uint16_t average_gfx_activity; + uint16_t average_umc_activity; // memory controller + uint16_t average_mm_activity; // UVD or VCN + + /* Power/Energy */ + uint16_t average_socket_power; + uint32_t energy_accumulator; + + /* Average clocks */ + uint16_t average_gfxclk_frequency; + uint16_t average_socclk_frequency; + uint16_t average_uclk_frequency; + uint16_t average_vclk0_frequency; + uint16_t average_dclk0_frequency; + uint16_t average_vclk1_frequency; + uint16_t average_dclk1_frequency; + + /* Current clocks */ + uint16_t current_gfxclk; + uint16_t current_socclk; + uint16_t current_uclk; + uint16_t current_vclk0; + uint16_t current_dclk0; + uint16_t current_vclk1; + uint16_t current_dclk1; + + /* Throttle status */ + uint32_t throttle_status; + + /* Fans */ + uint16_t current_fan_speed; + + /* Link width/speed */ + uint8_t pcie_link_width; + uint8_t pcie_link_speed; // in 0.1 GT/s +}; + +struct gpu_metrics_v2_0 { + struct metrics_table_header common_header; + + /* Driver attached timestamp (in ns) */ + uint64_t system_clock_counter; + + /* Temperature */ + uint16_t temperature_gfx; // gfx temperature on APUs + uint16_t temperature_soc; // soc temperature on APUs + uint16_t temperature_core[8]; // CPU core temperature on APUs + uint16_t temperature_l3[2]; + + /* Utilization */ + uint16_t average_gfx_activity; + uint16_t average_mm_activity; // UVD or VCN + + /* Power/Energy */ + uint16_t average_socket_power; // dGPU + APU power on A + A platform + uint16_t average_cpu_power; + uint16_t average_soc_power; + uint16_t average_gfx_power; + uint16_t average_core_power[8]; // CPU core power on APUs + + /* Average clocks */ + uint16_t average_gfxclk_frequency; + uint16_t average_socclk_frequency; + uint16_t average_uclk_frequency; + uint16_t average_fclk_frequency; + uint16_t average_vclk_frequency; + uint16_t average_dclk_frequency; + + /* Current clocks */ + uint16_t current_gfxclk; + uint16_t current_socclk; + uint16_t current_uclk; + uint16_t current_fclk; + uint16_t current_vclk; + uint16_t current_dclk; + uint16_t current_coreclk[8]; // CPU core clocks + uint16_t current_l3clk[2]; + + /* Throttle status */ + uint32_t throttle_status; + + /* Fans */ + uint16_t fan_pwm; + + uint16_t padding; }; #endif diff --git a/drivers/gpu/drm/amd/pm/Makefile b/drivers/gpu/drm/amd/pm/Makefile new file mode 100644 index 000000000000..f01e86030cd1 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/Makefile @@ -0,0 +1,46 @@ +# +# Copyright 2017 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. +# + +subdir-ccflags-y += \ + -I$(FULL_AMD_PATH)/pm/inc/ \ + -I$(FULL_AMD_PATH)/include/asic_reg \ + -I$(FULL_AMD_PATH)/include \ + -I$(FULL_AMD_PATH)/pm/swsmu \ + -I$(FULL_AMD_PATH)/pm/swsmu/smu11 \ + -I$(FULL_AMD_PATH)/pm/swsmu/smu12 \ + -I$(FULL_AMD_PATH)/pm/powerplay \ + -I$(FULL_AMD_PATH)/pm/powerplay/smumgr\ + -I$(FULL_AMD_PATH)/pm/powerplay/hwmgr + +AMD_PM_PATH = ../pm + +PM_LIBS = swsmu powerplay + +AMD_PM = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/pm/,$(PM_LIBS))) + +include $(AMD_PM) + +PM_MGR = amdgpu_dpm.o amdgpu_pm.o + +AMD_PM_POWER = $(addprefix $(AMD_PM_PATH)/,$(PM_MGR)) + +AMD_POWERPLAY_FILES += $(AMD_PM_POWER) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 2082c0acd216..17a45baff638 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -28,6 +28,11 @@ #include "amdgpu_dpm.h" #include "atom.h" #include "amd_pcie.h" +#include "amdgpu_display.h" +#include "hwmgr.h" +#include <linux/power_supply.h> + +#define WIDTH_4K 3840 void amdgpu_dpm_print_class_info(u32 class, u32 class2) { @@ -117,7 +122,7 @@ void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev, void amdgpu_dpm_get_active_displays(struct amdgpu_device *adev) { - struct drm_device *ddev = adev->ddev; + struct drm_device *ddev = adev_to_drm(adev); struct drm_crtc *crtc; struct amdgpu_crtc *amdgpu_crtc; @@ -138,7 +143,7 @@ void amdgpu_dpm_get_active_displays(struct amdgpu_device *adev) u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_crtc *crtc; struct amdgpu_crtc *amdgpu_crtc; u32 vblank_in_pixels; @@ -165,7 +170,7 @@ u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev) u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev) { - struct drm_device *dev = adev->ddev; + struct drm_device *dev = adev_to_drm(adev); struct drm_crtc *crtc; struct amdgpu_crtc *amdgpu_crtc; u32 vrefresh = 0; @@ -1110,8 +1115,6 @@ int amdgpu_dpm_baco_reset(struct amdgpu_device *adev) struct smu_context *smu = &adev->smu; int ret = 0; - dev_info(adev->dev, "GPU BACO reset\n"); - if (is_support_sw_smu(adev)) { ret = smu_baco_enter(smu); if (ret) @@ -1216,3 +1219,469 @@ int amdgpu_dpm_allow_xgmi_power_down(struct amdgpu_device *adev, bool en) return 0; } + +int amdgpu_dpm_enable_mgpu_fan_boost(struct amdgpu_device *adev) +{ + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = + adev->powerplay.pp_funcs; + struct smu_context *smu = &adev->smu; + int ret = 0; + + if (is_support_sw_smu(adev)) + ret = smu_enable_mgpu_fan_boost(smu); + else if (pp_funcs && pp_funcs->enable_mgpu_fan_boost) + ret = pp_funcs->enable_mgpu_fan_boost(pp_handle); + + return ret; +} + +int amdgpu_dpm_set_clockgating_by_smu(struct amdgpu_device *adev, + uint32_t msg_id) +{ + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = + adev->powerplay.pp_funcs; + int ret = 0; + + if (pp_funcs && pp_funcs->set_clockgating_by_smu) + ret = pp_funcs->set_clockgating_by_smu(pp_handle, + msg_id); + + return ret; +} + +int amdgpu_dpm_smu_i2c_bus_access(struct amdgpu_device *adev, + bool acquire) +{ + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = + adev->powerplay.pp_funcs; + int ret = -EOPNOTSUPP; + + if (pp_funcs && pp_funcs->smu_i2c_bus_access) + ret = pp_funcs->smu_i2c_bus_access(pp_handle, + acquire); + + return ret; +} + +void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) +{ + if (adev->pm.dpm_enabled) { + mutex_lock(&adev->pm.mutex); + if (power_supply_is_system_supplied() > 0) + adev->pm.ac_power = true; + else + adev->pm.ac_power = false; + if (adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->enable_bapm) + amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power); + mutex_unlock(&adev->pm.mutex); + + if (is_support_sw_smu(adev)) + smu_set_ac_dc(&adev->smu); + } +} + +int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + if (!data || !size) + return -EINVAL; + + if (is_support_sw_smu(adev)) + ret = smu_read_sensor(&adev->smu, sensor, data, size); + else { + if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->read_sensor) + ret = adev->powerplay.pp_funcs->read_sensor((adev)->powerplay.pp_handle, + sensor, data, size); + else + ret = -EINVAL; + } + + return ret; +} + +void amdgpu_dpm_thermal_work_handler(struct work_struct *work) +{ + struct amdgpu_device *adev = + container_of(work, struct amdgpu_device, + pm.dpm.thermal.work); + /* switch to the thermal state */ + enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL; + int temp, size = sizeof(temp); + + if (!adev->pm.dpm_enabled) + return; + + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, + (void *)&temp, &size)) { + if (temp < adev->pm.dpm.thermal.min_temp) + /* switch back the user state */ + dpm_state = adev->pm.dpm.user_state; + } else { + if (adev->pm.dpm.thermal.high_to_low) + /* switch back the user state */ + dpm_state = adev->pm.dpm.user_state; + } + mutex_lock(&adev->pm.mutex); + if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL) + adev->pm.dpm.thermal_active = true; + else + adev->pm.dpm.thermal_active = false; + adev->pm.dpm.state = dpm_state; + mutex_unlock(&adev->pm.mutex); + + amdgpu_pm_compute_clocks(adev); +} + +static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev, + enum amd_pm_state_type dpm_state) +{ + int i; + struct amdgpu_ps *ps; + u32 ui_class; + bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ? + true : false; + + /* check if the vblank period is too short to adjust the mclk */ + if (single_display && adev->powerplay.pp_funcs->vblank_too_short) { + if (amdgpu_dpm_vblank_too_short(adev)) + single_display = false; + } + + /* certain older asics have a separare 3D performance state, + * so try that first if the user selected performance + */ + if (dpm_state == POWER_STATE_TYPE_PERFORMANCE) + dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; + /* balanced states don't exist at the moment */ + if (dpm_state == POWER_STATE_TYPE_BALANCED) + dpm_state = POWER_STATE_TYPE_PERFORMANCE; + +restart_search: + /* Pick the best power state based on current conditions */ + for (i = 0; i < adev->pm.dpm.num_ps; i++) { + ps = &adev->pm.dpm.ps[i]; + ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK; + switch (dpm_state) { + /* user states */ + case POWER_STATE_TYPE_BATTERY: + if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) { + if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { + if (single_display) + return ps; + } else + return ps; + } + break; + case POWER_STATE_TYPE_BALANCED: + if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) { + if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { + if (single_display) + return ps; + } else + return ps; + } + break; + case POWER_STATE_TYPE_PERFORMANCE: + if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { + if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { + if (single_display) + return ps; + } else + return ps; + } + break; + /* internal states */ + case POWER_STATE_TYPE_INTERNAL_UVD: + if (adev->pm.dpm.uvd_ps) + return adev->pm.dpm.uvd_ps; + else + break; + case POWER_STATE_TYPE_INTERNAL_UVD_SD: + if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) + return ps; + break; + case POWER_STATE_TYPE_INTERNAL_UVD_HD: + if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) + return ps; + break; + case POWER_STATE_TYPE_INTERNAL_UVD_HD2: + if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) + return ps; + break; + case POWER_STATE_TYPE_INTERNAL_UVD_MVC: + if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) + return ps; + break; + case POWER_STATE_TYPE_INTERNAL_BOOT: + return adev->pm.dpm.boot_ps; + case POWER_STATE_TYPE_INTERNAL_THERMAL: + if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) + return ps; + break; + case POWER_STATE_TYPE_INTERNAL_ACPI: + if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) + return ps; + break; + case POWER_STATE_TYPE_INTERNAL_ULV: + if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) + return ps; + break; + case POWER_STATE_TYPE_INTERNAL_3DPERF: + if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) + return ps; + break; + default: + break; + } + } + /* use a fallback state if we didn't match */ + switch (dpm_state) { + case POWER_STATE_TYPE_INTERNAL_UVD_SD: + dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; + goto restart_search; + case POWER_STATE_TYPE_INTERNAL_UVD_HD: + case POWER_STATE_TYPE_INTERNAL_UVD_HD2: + case POWER_STATE_TYPE_INTERNAL_UVD_MVC: + if (adev->pm.dpm.uvd_ps) { + return adev->pm.dpm.uvd_ps; + } else { + dpm_state = POWER_STATE_TYPE_PERFORMANCE; + goto restart_search; + } + case POWER_STATE_TYPE_INTERNAL_THERMAL: + dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI; + goto restart_search; + case POWER_STATE_TYPE_INTERNAL_ACPI: + dpm_state = POWER_STATE_TYPE_BATTERY; + goto restart_search; + case POWER_STATE_TYPE_BATTERY: + case POWER_STATE_TYPE_BALANCED: + case POWER_STATE_TYPE_INTERNAL_3DPERF: + dpm_state = POWER_STATE_TYPE_PERFORMANCE; + goto restart_search; + default: + break; + } + + return NULL; +} + +static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev) +{ + struct amdgpu_ps *ps; + enum amd_pm_state_type dpm_state; + int ret; + bool equal = false; + + /* if dpm init failed */ + if (!adev->pm.dpm_enabled) + return; + + if (adev->pm.dpm.user_state != adev->pm.dpm.state) { + /* add other state override checks here */ + if ((!adev->pm.dpm.thermal_active) && + (!adev->pm.dpm.uvd_active)) + adev->pm.dpm.state = adev->pm.dpm.user_state; + } + dpm_state = adev->pm.dpm.state; + + ps = amdgpu_dpm_pick_power_state(adev, dpm_state); + if (ps) + adev->pm.dpm.requested_ps = ps; + else + return; + + if (amdgpu_dpm == 1 && adev->powerplay.pp_funcs->print_power_state) { + printk("switching from power state:\n"); + amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps); + printk("switching to power state:\n"); + amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps); + } + + /* update whether vce is active */ + ps->vce_active = adev->pm.dpm.vce_active; + if (adev->powerplay.pp_funcs->display_configuration_changed) + amdgpu_dpm_display_configuration_changed(adev); + + ret = amdgpu_dpm_pre_set_power_state(adev); + if (ret) + return; + + if (adev->powerplay.pp_funcs->check_state_equal) { + if (0 != amdgpu_dpm_check_state_equal(adev, adev->pm.dpm.current_ps, adev->pm.dpm.requested_ps, &equal)) + equal = false; + } + + if (equal) + return; + + amdgpu_dpm_set_power_state(adev); + amdgpu_dpm_post_set_power_state(adev); + + adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs; + adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count; + + if (adev->powerplay.pp_funcs->force_performance_level) { + if (adev->pm.dpm.thermal_active) { + enum amd_dpm_forced_level level = adev->pm.dpm.forced_level; + /* force low perf level for thermal */ + amdgpu_dpm_force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW); + /* save the user's level */ + adev->pm.dpm.forced_level = level; + } else { + /* otherwise, user selected level */ + amdgpu_dpm_force_performance_level(adev, adev->pm.dpm.forced_level); + } + } +} + +void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) +{ + int i = 0; + + if (!adev->pm.dpm_enabled) + return; + + if (adev->mode_info.num_crtc) + amdgpu_display_bandwidth_update(adev); + + for (i = 0; i < AMDGPU_MAX_RINGS; i++) { + struct amdgpu_ring *ring = adev->rings[i]; + if (ring && ring->sched.ready) + amdgpu_fence_wait_empty(ring); + } + + if (is_support_sw_smu(adev)) { + struct smu_dpm_context *smu_dpm = &adev->smu.smu_dpm; + smu_handle_task(&adev->smu, + smu_dpm->dpm_level, + AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, + true); + } else { + if (adev->powerplay.pp_funcs->dispatch_tasks) { + if (!amdgpu_device_has_dc_support(adev)) { + mutex_lock(&adev->pm.mutex); + amdgpu_dpm_get_active_displays(adev); + adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; + adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); + adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); + /* we have issues with mclk switching with refresh rates over 120 hz on the non-DC code. */ + if (adev->pm.pm_display_cfg.vrefresh > 120) + adev->pm.pm_display_cfg.min_vblank_time = 0; + if (adev->powerplay.pp_funcs->display_configuration_change) + adev->powerplay.pp_funcs->display_configuration_change( + adev->powerplay.pp_handle, + &adev->pm.pm_display_cfg); + mutex_unlock(&adev->pm.mutex); + } + amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, NULL); + } else { + mutex_lock(&adev->pm.mutex); + amdgpu_dpm_get_active_displays(adev); + amdgpu_dpm_change_power_state_locked(adev); + mutex_unlock(&adev->pm.mutex); + } + } +} + +void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) +{ + int ret = 0; + + if (adev->family == AMDGPU_FAMILY_SI) { + mutex_lock(&adev->pm.mutex); + if (enable) { + adev->pm.dpm.uvd_active = true; + adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD; + } else { + adev->pm.dpm.uvd_active = false; + } + mutex_unlock(&adev->pm.mutex); + + amdgpu_pm_compute_clocks(adev); + } else { + ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable); + if (ret) + DRM_ERROR("Dpm %s uvd failed, ret = %d. \n", + enable ? "enable" : "disable", ret); + + /* enable/disable Low Memory PState for UVD (4k videos) */ + if (adev->asic_type == CHIP_STONEY && + adev->uvd.decode_image_width >= WIDTH_4K) { + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + + if (hwmgr && hwmgr->hwmgr_func && + hwmgr->hwmgr_func->update_nbdpm_pstate) + hwmgr->hwmgr_func->update_nbdpm_pstate(hwmgr, + !enable, + true); + } + } +} + +void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) +{ + int ret = 0; + + if (adev->family == AMDGPU_FAMILY_SI) { + mutex_lock(&adev->pm.mutex); + if (enable) { + adev->pm.dpm.vce_active = true; + /* XXX select vce level based on ring/task */ + adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL; + } else { + adev->pm.dpm.vce_active = false; + } + mutex_unlock(&adev->pm.mutex); + + amdgpu_pm_compute_clocks(adev); + } else { + ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable); + if (ret) + DRM_ERROR("Dpm %s vce failed, ret = %d. \n", + enable ? "enable" : "disable", ret); + } +} + +void amdgpu_pm_print_power_states(struct amdgpu_device *adev) +{ + int i; + + if (adev->powerplay.pp_funcs->print_power_state == NULL) + return; + + for (i = 0; i < adev->pm.dpm.num_ps; i++) + amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]); + +} + +void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable) +{ + int ret = 0; + + ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_JPEG, !enable); + if (ret) + DRM_ERROR("Dpm %s jpeg failed, ret = %d. \n", + enable ? "enable" : "disable", ret); +} + +int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version) +{ + int r; + + if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->load_firmware) { + r = adev->powerplay.pp_funcs->load_firmware(adev->powerplay.pp_handle); + if (r) { + pr_err("smu firmware loading failed\n"); + return r; + } + *smu_version = adev->pm.fw_version; + } + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index e4dbf14320b6..2d924e88a215 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -29,17 +29,14 @@ #include "amdgpu_drv.h" #include "amdgpu_pm.h" #include "amdgpu_dpm.h" -#include "amdgpu_display.h" #include "amdgpu_smu.h" #include "atom.h" -#include <linux/power_supply.h> #include <linux/pci.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/nospec.h> #include <linux/pm_runtime.h> #include "hwmgr.h" -#define WIDTH_4K 3840 static const struct cg_flag_name clocks[] = { {AMD_CG_SUPPORT_GFX_MGCG, "Graphics Medium Grain Clock Gating"}, @@ -81,45 +78,6 @@ static const struct hwmon_temp_label { {PP_TEMP_MEM, "mem"}, }; -void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) -{ - if (adev->pm.dpm_enabled) { - mutex_lock(&adev->pm.mutex); - if (power_supply_is_system_supplied() > 0) - adev->pm.ac_power = true; - else - adev->pm.ac_power = false; - if (adev->powerplay.pp_funcs && - adev->powerplay.pp_funcs->enable_bapm) - amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power); - mutex_unlock(&adev->pm.mutex); - - if (is_support_sw_smu(adev)) - smu_set_ac_dc(&adev->smu); - } -} - -int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor, - void *data, uint32_t *size) -{ - int ret = 0; - - if (!data || !size) - return -EINVAL; - - if (is_support_sw_smu(adev)) - ret = smu_read_sensor(&adev->smu, sensor, data, size); - else { - if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->read_sensor) - ret = adev->powerplay.pp_funcs->read_sensor((adev)->powerplay.pp_handle, - sensor, data, size); - else - ret = -EINVAL; - } - - return ret; -} - /** * DOC: power_dpm_state * @@ -159,11 +117,11 @@ static ssize_t amdgpu_get_power_dpm_state(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); enum amd_pm_state_type pm; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -197,11 +155,11 @@ static ssize_t amdgpu_set_power_dpm_state(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); enum amd_pm_state_type state; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (strncmp("battery", buf, strlen("battery")) == 0) @@ -303,11 +261,11 @@ static ssize_t amdgpu_get_power_dpm_force_performance_level(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); enum amd_dpm_forced_level level = 0xff; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -344,12 +302,12 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); enum amd_dpm_forced_level level; enum amd_dpm_forced_level current_level = 0xff; int ret = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (strncmp("low", buf, strlen("low")) == 0) { @@ -449,11 +407,11 @@ static ssize_t amdgpu_get_pp_num_states(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); struct pp_states_info data; int i, buf_len, ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -491,13 +449,13 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); struct pp_states_info data; struct smu_context *smu = &adev->smu; enum amd_pm_state_type pm = 0; int i = 0, ret = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -536,9 +494,9 @@ static ssize_t amdgpu_get_pp_force_state(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (adev->pp_force_state_enabled) @@ -553,12 +511,12 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); enum amd_pm_state_type state = 0; unsigned long idx; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (strlen(buf) == 1) @@ -614,11 +572,11 @@ static ssize_t amdgpu_get_pp_table(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); char *table = NULL; int size, ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -659,10 +617,10 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -694,6 +652,52 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, * in each power level within a power state. The pp_od_clk_voltage is used for * this. * + * Note that the actual memory controller clock rate are exposed, not + * the effective memory clock of the DRAMs. To translate it, use the + * following formula: + * + * Clock conversion (Mhz): + * + * HBM: effective_memory_clock = memory_controller_clock * 1 + * + * G5: effective_memory_clock = memory_controller_clock * 1 + * + * G6: effective_memory_clock = memory_controller_clock * 2 + * + * DRAM data rate (MT/s): + * + * HBM: effective_memory_clock * 2 = data_rate + * + * G5: effective_memory_clock * 4 = data_rate + * + * G6: effective_memory_clock * 8 = data_rate + * + * Bandwidth (MB/s): + * + * data_rate * vram_bit_width / 8 = memory_bandwidth + * + * Some examples: + * + * G5 on RX460: + * + * memory_controller_clock = 1750 Mhz + * + * effective_memory_clock = 1750 Mhz * 1 = 1750 Mhz + * + * data rate = 1750 * 4 = 7000 MT/s + * + * memory_bandwidth = 7000 * 128 bits / 8 = 112000 MB/s + * + * G6 on RX5700: + * + * memory_controller_clock = 875 Mhz + * + * effective_memory_clock = 875 Mhz * 2 = 1750 Mhz + * + * data rate = 1750 * 8 = 14000 MT/s + * + * memory_bandwidth = 14000 * 256 bits / 8 = 448000 MB/s + * * < For Vega10 and previous ASICs > * * Reading the file will display: @@ -759,7 +763,7 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret; uint32_t parameter_size = 0; long parameter[64]; @@ -769,7 +773,7 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, const char delimiter[3] = {' ', '\n', '\0'}; uint32_t type; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (count > 127) @@ -796,7 +800,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, tmp_str++; while (isspace(*++tmp_str)); - while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { + while (tmp_str[0]) { + sub_str = strsep(&tmp_str, delimiter); ret = kstrtol(sub_str, 0, ¶meter[parameter_size]); if (ret) return -EINVAL; @@ -858,11 +863,11 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -912,11 +917,11 @@ static ssize_t amdgpu_set_pp_features(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint64_t featuremask; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = kstrtou64(buf, 0, &featuremask); @@ -957,11 +962,11 @@ static ssize_t amdgpu_get_pp_features(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1018,11 +1023,11 @@ static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1066,7 +1071,8 @@ static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask) memcpy(buf_cpy, buf, bytes); buf_cpy[bytes] = '\0'; tmp = buf_cpy; - while ((sub_str = strsep(&tmp, delimiter)) != NULL) { + while (tmp[0]) { + sub_str = strsep(&tmp, delimiter); if (strlen(sub_str)) { ret = kstrtol(sub_str, 0, &level); if (ret) @@ -1085,11 +1091,11 @@ static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret; uint32_t mask = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = amdgpu_read_mask(buf, count, &mask); @@ -1121,11 +1127,11 @@ static ssize_t amdgpu_get_pp_dpm_mclk(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1153,11 +1159,11 @@ static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint32_t mask = 0; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = amdgpu_read_mask(buf, count, &mask); @@ -1189,11 +1195,11 @@ static ssize_t amdgpu_get_pp_dpm_socclk(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1221,11 +1227,11 @@ static ssize_t amdgpu_set_pp_dpm_socclk(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret; uint32_t mask = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = amdgpu_read_mask(buf, count, &mask); @@ -1259,11 +1265,11 @@ static ssize_t amdgpu_get_pp_dpm_fclk(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1291,11 +1297,11 @@ static ssize_t amdgpu_set_pp_dpm_fclk(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret; uint32_t mask = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = amdgpu_read_mask(buf, count, &mask); @@ -1329,11 +1335,11 @@ static ssize_t amdgpu_get_pp_dpm_dcefclk(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1361,11 +1367,11 @@ static ssize_t amdgpu_set_pp_dpm_dcefclk(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret; uint32_t mask = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = amdgpu_read_mask(buf, count, &mask); @@ -1399,11 +1405,11 @@ static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1431,11 +1437,11 @@ static ssize_t amdgpu_set_pp_dpm_pcie(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret; uint32_t mask = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = amdgpu_read_mask(buf, count, &mask); @@ -1469,11 +1475,11 @@ static ssize_t amdgpu_get_pp_sclk_od(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint32_t value = 0; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1499,11 +1505,11 @@ static ssize_t amdgpu_set_pp_sclk_od(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret; long int value; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = kstrtol(buf, 0, &value); @@ -1542,11 +1548,11 @@ static ssize_t amdgpu_get_pp_mclk_od(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint32_t value = 0; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1572,11 +1578,11 @@ static ssize_t amdgpu_set_pp_mclk_od(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int ret; long int value; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = kstrtol(buf, 0, &value); @@ -1635,11 +1641,11 @@ static ssize_t amdgpu_get_pp_power_profile_mode(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); ssize_t size; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; ret = pm_runtime_get_sync(ddev->dev); @@ -1669,7 +1675,7 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, { int ret; struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint32_t parameter_size = 0; long parameter[64]; char *sub_str, buf_cpy[128]; @@ -1679,7 +1685,7 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, long int profile_mode = 0; const char delimiter[3] = {' ', '\n', '\0'}; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; tmp[0] = *(buf); @@ -1695,7 +1701,8 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, i++; memcpy(buf_cpy, buf, count-i); tmp_str = buf_cpy; - while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { + while (tmp_str[0]) { + sub_str = strsep(&tmp_str, delimiter); ret = kstrtol(sub_str, 0, ¶meter[parameter_size]); if (ret) return -EINVAL; @@ -1739,10 +1746,10 @@ static ssize_t amdgpu_get_gpu_busy_percent(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int r, value, size = sizeof(value); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; r = pm_runtime_get_sync(ddev->dev); @@ -1777,10 +1784,10 @@ static ssize_t amdgpu_get_mem_busy_percent(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); int r, value, size = sizeof(value); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; r = pm_runtime_get_sync(ddev->dev); @@ -1819,11 +1826,11 @@ static ssize_t amdgpu_get_pcie_bw(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); uint64_t count0 = 0, count1 = 0; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (adev->flags & AMD_IS_APU) @@ -1862,9 +1869,9 @@ static ssize_t amdgpu_get_unique_id(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (adev->unique_id) @@ -1893,10 +1900,10 @@ static ssize_t amdgpu_get_thermal_throttling_logging(struct device *dev, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); return snprintf(buf, PAGE_SIZE, "%s: thermal throttling logging %s, with interval %d seconds\n", - adev->ddev->unique, + adev_to_drm(adev)->unique, atomic_read(&adev->throttling_logging_enabled) ? "enabled" : "disabled", adev->throttling_logging_rs.interval / HZ + 1); } @@ -1907,7 +1914,7 @@ static ssize_t amdgpu_set_thermal_throttling_logging(struct device *dev, size_t count) { struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; + struct amdgpu_device *adev = drm_to_adev(ddev); long throttling_logging_interval; unsigned long flags; int ret = 0; @@ -1940,6 +1947,57 @@ static ssize_t amdgpu_set_thermal_throttling_logging(struct device *dev, return count; } +/** + * DOC: gpu_metrics + * + * The amdgpu driver provides a sysfs API for retrieving current gpu + * metrics data. The file gpu_metrics is used for this. Reading the + * file will dump all the current gpu metrics data. + * + * These data include temperature, frequency, engines utilization, + * power consume, throttler status, fan speed and cpu core statistics( + * available for APU only). That's it will give a snapshot of all sensors + * at the same time. + */ +static ssize_t amdgpu_get_gpu_metrics(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + void *gpu_metrics; + ssize_t size = 0; + int ret; + + if (amdgpu_in_reset(adev)) + return -EPERM; + + ret = pm_runtime_get_sync(ddev->dev); + if (ret < 0) { + pm_runtime_put_autosuspend(ddev->dev); + return ret; + } + + if (is_support_sw_smu(adev)) + size = smu_sys_get_gpu_metrics(&adev->smu, &gpu_metrics); + else if (adev->powerplay.pp_funcs->get_gpu_metrics) + size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics); + + if (size <= 0) + goto out; + + if (size >= PAGE_SIZE) + size = PAGE_SIZE - 1; + + memcpy(buf, gpu_metrics, size); + +out: + pm_runtime_mark_last_busy(ddev->dev); + pm_runtime_put_autosuspend(ddev->dev); + + return size; +} + static struct amdgpu_device_attr amdgpu_device_attrs[] = { AMDGPU_DEVICE_ATTR_RW(power_dpm_state, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), AMDGPU_DEVICE_ATTR_RW(power_dpm_force_performance_level, ATTR_FLAG_BASIC), @@ -1963,6 +2021,7 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = { AMDGPU_DEVICE_ATTR_RW(pp_features, ATTR_FLAG_BASIC), AMDGPU_DEVICE_ATTR_RO(unique_id, ATTR_FLAG_BASIC), AMDGPU_DEVICE_ATTR_RW(thermal_throttling_logging, ATTR_FLAG_BASIC), + AMDGPU_DEVICE_ATTR_RO(gpu_metrics, ATTR_FLAG_BASIC), }; static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr, @@ -2012,6 +2071,9 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ } else if (DEVICE_ATTR_IS(pp_features)) { if (adev->flags & AMD_IS_APU || asic_type < CHIP_VEGA10) *states = ATTR_STATE_UNSUPPORTED; + } else if (DEVICE_ATTR_IS(gpu_metrics)) { + if (asic_type < CHIP_VEGA12) + *states = ATTR_STATE_UNSUPPORTED; } if (asic_type == CHIP_ARCTURUS) { @@ -2131,15 +2193,15 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev, int channel = to_sensor_dev_attr(attr)->index; int r, temp = 0, size = sizeof(temp); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (channel >= PP_TEMP_MAX) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -2164,8 +2226,8 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev, break; } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) return r; @@ -2267,12 +2329,12 @@ static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev, u32 pwm_mode = 0; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - ret = pm_runtime_get_sync(adev->ddev->dev); + ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (ret < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return ret; } @@ -2280,16 +2342,16 @@ static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev, pwm_mode = smu_get_fan_control_mode(&adev->smu); } else { if (!adev->powerplay.pp_funcs->get_fan_control_mode) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return -EINVAL; } pwm_mode = amdgpu_dpm_get_fan_control_mode(adev); } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return sprintf(buf, "%i\n", pwm_mode); } @@ -2303,16 +2365,16 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev, int err, ret; int value; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; err = kstrtoint(buf, 10, &value); if (err) return err; - ret = pm_runtime_get_sync(adev->ddev->dev); + ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (ret < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return ret; } @@ -2320,16 +2382,16 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev, smu_set_fan_control_mode(&adev->smu, value); } else { if (!adev->powerplay.pp_funcs->set_fan_control_mode) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return -EINVAL; } amdgpu_dpm_set_fan_control_mode(adev, value); } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return count; } @@ -2357,12 +2419,12 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev, u32 value; u32 pwm_mode; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - err = pm_runtime_get_sync(adev->ddev->dev); + err = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (err < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2373,15 +2435,15 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev, if (pwm_mode != AMD_FAN_CTRL_MANUAL) { pr_info("manual fan speed control should be enabled first\n"); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return -EINVAL; } err = kstrtou32(buf, 10, &value); if (err) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2394,8 +2456,8 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev, else err = -EINVAL; - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) return err; @@ -2411,12 +2473,12 @@ static ssize_t amdgpu_hwmon_get_pwm1(struct device *dev, int err; u32 speed = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - err = pm_runtime_get_sync(adev->ddev->dev); + err = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (err < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2427,8 +2489,8 @@ static ssize_t amdgpu_hwmon_get_pwm1(struct device *dev, else err = -EINVAL; - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) return err; @@ -2446,12 +2508,12 @@ static ssize_t amdgpu_hwmon_get_fan1_input(struct device *dev, int err; u32 speed = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - err = pm_runtime_get_sync(adev->ddev->dev); + err = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (err < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2462,8 +2524,8 @@ static ssize_t amdgpu_hwmon_get_fan1_input(struct device *dev, else err = -EINVAL; - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) return err; @@ -2480,20 +2542,20 @@ static ssize_t amdgpu_hwmon_get_fan1_min(struct device *dev, u32 size = sizeof(min_rpm); int r; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_MIN_FAN_RPM, (void *)&min_rpm, &size); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) return r; @@ -2510,20 +2572,20 @@ static ssize_t amdgpu_hwmon_get_fan1_max(struct device *dev, u32 size = sizeof(max_rpm); int r; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_MAX_FAN_RPM, (void *)&max_rpm, &size); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) return r; @@ -2539,12 +2601,12 @@ static ssize_t amdgpu_hwmon_get_fan1_target(struct device *dev, int err; u32 rpm = 0; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - err = pm_runtime_get_sync(adev->ddev->dev); + err = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (err < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2555,8 +2617,8 @@ static ssize_t amdgpu_hwmon_get_fan1_target(struct device *dev, else err = -EINVAL; - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) return err; @@ -2573,12 +2635,12 @@ static ssize_t amdgpu_hwmon_set_fan1_target(struct device *dev, u32 value; u32 pwm_mode; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - err = pm_runtime_get_sync(adev->ddev->dev); + err = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (err < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2588,15 +2650,15 @@ static ssize_t amdgpu_hwmon_set_fan1_target(struct device *dev, pwm_mode = amdgpu_dpm_get_fan_control_mode(adev); if (pwm_mode != AMD_FAN_CTRL_MANUAL) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return -ENODATA; } err = kstrtou32(buf, 10, &value); if (err) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2607,8 +2669,8 @@ static ssize_t amdgpu_hwmon_set_fan1_target(struct device *dev, else err = -EINVAL; - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) return err; @@ -2624,12 +2686,12 @@ static ssize_t amdgpu_hwmon_get_fan1_enable(struct device *dev, u32 pwm_mode = 0; int ret; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - ret = pm_runtime_get_sync(adev->ddev->dev); + ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (ret < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return ret; } @@ -2637,16 +2699,16 @@ static ssize_t amdgpu_hwmon_get_fan1_enable(struct device *dev, pwm_mode = smu_get_fan_control_mode(&adev->smu); } else { if (!adev->powerplay.pp_funcs->get_fan_control_mode) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return -EINVAL; } pwm_mode = amdgpu_dpm_get_fan_control_mode(adev); } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return sprintf(buf, "%i\n", pwm_mode == AMD_FAN_CTRL_AUTO ? 0 : 1); } @@ -2661,7 +2723,7 @@ static ssize_t amdgpu_hwmon_set_fan1_enable(struct device *dev, int value; u32 pwm_mode; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; err = kstrtoint(buf, 10, &value); @@ -2675,9 +2737,9 @@ static ssize_t amdgpu_hwmon_set_fan1_enable(struct device *dev, else return -EINVAL; - err = pm_runtime_get_sync(adev->ddev->dev); + err = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (err < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2685,15 +2747,15 @@ static ssize_t amdgpu_hwmon_set_fan1_enable(struct device *dev, smu_set_fan_control_mode(&adev->smu, pwm_mode); } else { if (!adev->powerplay.pp_funcs->set_fan_control_mode) { - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return -EINVAL; } amdgpu_dpm_set_fan_control_mode(adev, pwm_mode); } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return count; } @@ -2706,12 +2768,12 @@ static ssize_t amdgpu_hwmon_show_vddgfx(struct device *dev, u32 vddgfx; int r, size = sizeof(vddgfx); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -2719,8 +2781,8 @@ static ssize_t amdgpu_hwmon_show_vddgfx(struct device *dev, r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX, (void *)&vddgfx, &size); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) return r; @@ -2743,16 +2805,16 @@ static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev, u32 vddnb; int r, size = sizeof(vddnb); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; /* only APUs have vddnb */ if (!(adev->flags & AMD_IS_APU)) return -EINVAL; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -2760,8 +2822,8 @@ static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev, r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *)&vddnb, &size); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) return r; @@ -2785,12 +2847,12 @@ static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, int r, size = sizeof(u32); unsigned uw; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -2798,8 +2860,8 @@ static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_POWER, (void *)&query, &size); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) return r; @@ -2826,12 +2888,12 @@ static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev, ssize_t size; int r; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -2845,8 +2907,8 @@ static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev, size = snprintf(buf, PAGE_SIZE, "\n"); } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return size; } @@ -2860,12 +2922,12 @@ static ssize_t amdgpu_hwmon_show_power_cap(struct device *dev, ssize_t size; int r; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -2879,8 +2941,8 @@ static ssize_t amdgpu_hwmon_show_power_cap(struct device *dev, size = snprintf(buf, PAGE_SIZE, "\n"); } - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return size; } @@ -2895,7 +2957,7 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, int err; u32 value; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; if (amdgpu_sriov_vf(adev)) @@ -2908,9 +2970,9 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, value = value / 1000000; /* convert to Watt */ - err = pm_runtime_get_sync(adev->ddev->dev); + err = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (err < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return err; } @@ -2921,8 +2983,8 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, else err = -EINVAL; - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) return err; @@ -2938,12 +3000,12 @@ static ssize_t amdgpu_hwmon_show_sclk(struct device *dev, uint32_t sclk; int r, size = sizeof(sclk); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -2951,8 +3013,8 @@ static ssize_t amdgpu_hwmon_show_sclk(struct device *dev, r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK, (void *)&sclk, &size); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) return r; @@ -2975,12 +3037,12 @@ static ssize_t amdgpu_hwmon_show_mclk(struct device *dev, uint32_t mclk; int r, size = sizeof(mclk); - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; - r = pm_runtime_get_sync(adev->ddev->dev); + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } @@ -2988,8 +3050,8 @@ static ssize_t amdgpu_hwmon_show_mclk(struct device *dev, r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK, (void *)&mclk, &size); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (r) return r; @@ -3249,14 +3311,18 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, } if (((adev->flags & AMD_IS_APU) || - adev->family == AMDGPU_FAMILY_SI || /* not implemented yet */ - adev->family == AMDGPU_FAMILY_KV) && /* not implemented yet */ - (attr == &sensor_dev_attr_power1_average.dev_attr.attr || - attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr || + adev->family == AMDGPU_FAMILY_SI) && /* not implemented yet */ + (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr || attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr|| attr == &sensor_dev_attr_power1_cap.dev_attr.attr)) return 0; + if (((adev->family == AMDGPU_FAMILY_SI) || + ((adev->flags & AMD_IS_APU) && + (adev->asic_type < CHIP_RENOIR))) && /* not implemented yet */ + (attr == &sensor_dev_attr_power1_average.dev_attr.attr)) + return 0; + if (!is_support_sw_smu(adev)) { /* hide max/min values if we can't both query and manage the fan */ if ((!adev->powerplay.pp_funcs->set_fan_speed_percent && @@ -3321,338 +3387,6 @@ static const struct attribute_group *hwmon_groups[] = { NULL }; -void amdgpu_dpm_thermal_work_handler(struct work_struct *work) -{ - struct amdgpu_device *adev = - container_of(work, struct amdgpu_device, - pm.dpm.thermal.work); - /* switch to the thermal state */ - enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL; - int temp, size = sizeof(temp); - - if (!adev->pm.dpm_enabled) - return; - - if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, - (void *)&temp, &size)) { - if (temp < adev->pm.dpm.thermal.min_temp) - /* switch back the user state */ - dpm_state = adev->pm.dpm.user_state; - } else { - if (adev->pm.dpm.thermal.high_to_low) - /* switch back the user state */ - dpm_state = adev->pm.dpm.user_state; - } - mutex_lock(&adev->pm.mutex); - if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL) - adev->pm.dpm.thermal_active = true; - else - adev->pm.dpm.thermal_active = false; - adev->pm.dpm.state = dpm_state; - mutex_unlock(&adev->pm.mutex); - - amdgpu_pm_compute_clocks(adev); -} - -static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev, - enum amd_pm_state_type dpm_state) -{ - int i; - struct amdgpu_ps *ps; - u32 ui_class; - bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ? - true : false; - - /* check if the vblank period is too short to adjust the mclk */ - if (single_display && adev->powerplay.pp_funcs->vblank_too_short) { - if (amdgpu_dpm_vblank_too_short(adev)) - single_display = false; - } - - /* certain older asics have a separare 3D performance state, - * so try that first if the user selected performance - */ - if (dpm_state == POWER_STATE_TYPE_PERFORMANCE) - dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; - /* balanced states don't exist at the moment */ - if (dpm_state == POWER_STATE_TYPE_BALANCED) - dpm_state = POWER_STATE_TYPE_PERFORMANCE; - -restart_search: - /* Pick the best power state based on current conditions */ - for (i = 0; i < adev->pm.dpm.num_ps; i++) { - ps = &adev->pm.dpm.ps[i]; - ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK; - switch (dpm_state) { - /* user states */ - case POWER_STATE_TYPE_BATTERY: - if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) { - if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { - if (single_display) - return ps; - } else - return ps; - } - break; - case POWER_STATE_TYPE_BALANCED: - if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) { - if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { - if (single_display) - return ps; - } else - return ps; - } - break; - case POWER_STATE_TYPE_PERFORMANCE: - if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { - if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) { - if (single_display) - return ps; - } else - return ps; - } - break; - /* internal states */ - case POWER_STATE_TYPE_INTERNAL_UVD: - if (adev->pm.dpm.uvd_ps) - return adev->pm.dpm.uvd_ps; - else - break; - case POWER_STATE_TYPE_INTERNAL_UVD_SD: - if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) - return ps; - break; - case POWER_STATE_TYPE_INTERNAL_UVD_HD: - if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) - return ps; - break; - case POWER_STATE_TYPE_INTERNAL_UVD_HD2: - if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) - return ps; - break; - case POWER_STATE_TYPE_INTERNAL_UVD_MVC: - if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) - return ps; - break; - case POWER_STATE_TYPE_INTERNAL_BOOT: - return adev->pm.dpm.boot_ps; - case POWER_STATE_TYPE_INTERNAL_THERMAL: - if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) - return ps; - break; - case POWER_STATE_TYPE_INTERNAL_ACPI: - if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) - return ps; - break; - case POWER_STATE_TYPE_INTERNAL_ULV: - if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) - return ps; - break; - case POWER_STATE_TYPE_INTERNAL_3DPERF: - if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) - return ps; - break; - default: - break; - } - } - /* use a fallback state if we didn't match */ - switch (dpm_state) { - case POWER_STATE_TYPE_INTERNAL_UVD_SD: - dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD; - goto restart_search; - case POWER_STATE_TYPE_INTERNAL_UVD_HD: - case POWER_STATE_TYPE_INTERNAL_UVD_HD2: - case POWER_STATE_TYPE_INTERNAL_UVD_MVC: - if (adev->pm.dpm.uvd_ps) { - return adev->pm.dpm.uvd_ps; - } else { - dpm_state = POWER_STATE_TYPE_PERFORMANCE; - goto restart_search; - } - case POWER_STATE_TYPE_INTERNAL_THERMAL: - dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI; - goto restart_search; - case POWER_STATE_TYPE_INTERNAL_ACPI: - dpm_state = POWER_STATE_TYPE_BATTERY; - goto restart_search; - case POWER_STATE_TYPE_BATTERY: - case POWER_STATE_TYPE_BALANCED: - case POWER_STATE_TYPE_INTERNAL_3DPERF: - dpm_state = POWER_STATE_TYPE_PERFORMANCE; - goto restart_search; - default: - break; - } - - return NULL; -} - -static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev) -{ - struct amdgpu_ps *ps; - enum amd_pm_state_type dpm_state; - int ret; - bool equal = false; - - /* if dpm init failed */ - if (!adev->pm.dpm_enabled) - return; - - if (adev->pm.dpm.user_state != adev->pm.dpm.state) { - /* add other state override checks here */ - if ((!adev->pm.dpm.thermal_active) && - (!adev->pm.dpm.uvd_active)) - adev->pm.dpm.state = adev->pm.dpm.user_state; - } - dpm_state = adev->pm.dpm.state; - - ps = amdgpu_dpm_pick_power_state(adev, dpm_state); - if (ps) - adev->pm.dpm.requested_ps = ps; - else - return; - - if (amdgpu_dpm == 1 && adev->powerplay.pp_funcs->print_power_state) { - printk("switching from power state:\n"); - amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps); - printk("switching to power state:\n"); - amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps); - } - - /* update whether vce is active */ - ps->vce_active = adev->pm.dpm.vce_active; - if (adev->powerplay.pp_funcs->display_configuration_changed) - amdgpu_dpm_display_configuration_changed(adev); - - ret = amdgpu_dpm_pre_set_power_state(adev); - if (ret) - return; - - if (adev->powerplay.pp_funcs->check_state_equal) { - if (0 != amdgpu_dpm_check_state_equal(adev, adev->pm.dpm.current_ps, adev->pm.dpm.requested_ps, &equal)) - equal = false; - } - - if (equal) - return; - - amdgpu_dpm_set_power_state(adev); - amdgpu_dpm_post_set_power_state(adev); - - adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs; - adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count; - - if (adev->powerplay.pp_funcs->force_performance_level) { - if (adev->pm.dpm.thermal_active) { - enum amd_dpm_forced_level level = adev->pm.dpm.forced_level; - /* force low perf level for thermal */ - amdgpu_dpm_force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW); - /* save the user's level */ - adev->pm.dpm.forced_level = level; - } else { - /* otherwise, user selected level */ - amdgpu_dpm_force_performance_level(adev, adev->pm.dpm.forced_level); - } - } -} - -void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) -{ - int ret = 0; - - if (adev->family == AMDGPU_FAMILY_SI) { - mutex_lock(&adev->pm.mutex); - if (enable) { - adev->pm.dpm.uvd_active = true; - adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD; - } else { - adev->pm.dpm.uvd_active = false; - } - mutex_unlock(&adev->pm.mutex); - - amdgpu_pm_compute_clocks(adev); - } else { - ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable); - if (ret) - DRM_ERROR("Dpm %s uvd failed, ret = %d. \n", - enable ? "enable" : "disable", ret); - - /* enable/disable Low Memory PState for UVD (4k videos) */ - if (adev->asic_type == CHIP_STONEY && - adev->uvd.decode_image_width >= WIDTH_4K) { - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - - if (hwmgr && hwmgr->hwmgr_func && - hwmgr->hwmgr_func->update_nbdpm_pstate) - hwmgr->hwmgr_func->update_nbdpm_pstate(hwmgr, - !enable, - true); - } - } -} - -void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) -{ - int ret = 0; - - if (adev->family == AMDGPU_FAMILY_SI) { - mutex_lock(&adev->pm.mutex); - if (enable) { - adev->pm.dpm.vce_active = true; - /* XXX select vce level based on ring/task */ - adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL; - } else { - adev->pm.dpm.vce_active = false; - } - mutex_unlock(&adev->pm.mutex); - - amdgpu_pm_compute_clocks(adev); - } else { - ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable); - if (ret) - DRM_ERROR("Dpm %s vce failed, ret = %d. \n", - enable ? "enable" : "disable", ret); - } -} - -void amdgpu_pm_print_power_states(struct amdgpu_device *adev) -{ - int i; - - if (adev->powerplay.pp_funcs->print_power_state == NULL) - return; - - for (i = 0; i < adev->pm.dpm.num_ps; i++) - amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]); - -} - -void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable) -{ - int ret = 0; - - ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_JPEG, !enable); - if (ret) - DRM_ERROR("Dpm %s jpeg failed, ret = %d. \n", - enable ? "enable" : "disable", ret); -} - -int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version) -{ - int r; - - if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->load_firmware) { - r = adev->powerplay.pp_funcs->load_firmware(adev->powerplay.pp_handle); - if (r) { - pr_err("smu firmware loading failed\n"); - return r; - } - *smu_version = adev->pm.fw_version; - } - return 0; -} - int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) { int ret; @@ -3713,55 +3447,6 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) amdgpu_device_attr_remove_groups(adev, &adev->pm.pm_attr_list); } -void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) -{ - int i = 0; - - if (!adev->pm.dpm_enabled) - return; - - if (adev->mode_info.num_crtc) - amdgpu_display_bandwidth_update(adev); - - for (i = 0; i < AMDGPU_MAX_RINGS; i++) { - struct amdgpu_ring *ring = adev->rings[i]; - if (ring && ring->sched.ready) - amdgpu_fence_wait_empty(ring); - } - - if (is_support_sw_smu(adev)) { - struct smu_dpm_context *smu_dpm = &adev->smu.smu_dpm; - smu_handle_task(&adev->smu, - smu_dpm->dpm_level, - AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, - true); - } else { - if (adev->powerplay.pp_funcs->dispatch_tasks) { - if (!amdgpu_device_has_dc_support(adev)) { - mutex_lock(&adev->pm.mutex); - amdgpu_dpm_get_active_displays(adev); - adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; - adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); - adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); - /* we have issues with mclk switching with refresh rates over 120 hz on the non-DC code. */ - if (adev->pm.pm_display_cfg.vrefresh > 120) - adev->pm.pm_display_cfg.min_vblank_time = 0; - if (adev->powerplay.pp_funcs->display_configuration_change) - adev->powerplay.pp_funcs->display_configuration_change( - adev->powerplay.pp_handle, - &adev->pm.pm_display_cfg); - mutex_unlock(&adev->pm.mutex); - } - amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, NULL); - } else { - mutex_lock(&adev->pm.mutex); - amdgpu_dpm_get_active_displays(adev); - amdgpu_dpm_change_power_state_locked(adev); - mutex_unlock(&adev->pm.mutex); - } - } -} - /* * Debugfs info */ @@ -3869,11 +3554,11 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_device *adev = drm_to_adev(dev); u32 flags = 0; int r; - if (adev->in_gpu_reset) + if (amdgpu_in_reset(adev)) return -EPERM; r = pm_runtime_get_sync(dev->dev); @@ -3882,11 +3567,6 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data) return r; } - amdgpu_device_ip_get_clockgating_state(adev, &flags); - seq_printf(m, "Clock Gating Flags Mask: 0x%x\n", flags); - amdgpu_parse_cg_state(m, flags); - seq_printf(m, "\n"); - if (!adev->pm.dpm_enabled) { seq_printf(m, "dpm not enabled\n"); pm_runtime_mark_last_busy(dev->dev); @@ -3906,7 +3586,16 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data) } else { r = amdgpu_debugfs_pm_info_pp(m, adev); } + if (r) + goto out; + + amdgpu_device_ip_get_clockgating_state(adev, &flags); + + seq_printf(m, "Clock Gating Flags Mask: 0x%x\n", flags); + amdgpu_parse_cg_state(m, flags); + seq_printf(m, "\n"); +out: pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); diff --git a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h b/drivers/gpu/drm/amd/pm/inc/amd_powerplay.h index fe3665965416..fe3665965416 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h +++ b/drivers/gpu/drm/amd/pm/inc/amd_powerplay.h diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index aa27fe65cdfa..dff4a5f99bb0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -341,10 +341,6 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->reset_power_profile_state(\ (adev)->powerplay.pp_handle, request)) -#define amdgpu_dpm_set_clockgating_by_smu(adev, msg_id) \ - ((adev)->powerplay.pp_funcs->set_clockgating_by_smu(\ - (adev)->powerplay.pp_handle, msg_id)) - #define amdgpu_dpm_get_power_profile_mode(adev, buf) \ ((adev)->powerplay.pp_funcs->get_power_profile_mode(\ (adev)->powerplay.pp_handle, buf)) @@ -357,10 +353,6 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->odn_edit_dpm_table(\ (adev)->powerplay.pp_handle, type, parameter, size)) -#define amdgpu_dpm_enable_mgpu_fan_boost(adev) \ - ((adev)->powerplay.pp_funcs->enable_mgpu_fan_boost(\ - (adev)->powerplay.pp_handle)) - #define amdgpu_dpm_get_ppfeature_status(adev, buf) \ ((adev)->powerplay.pp_funcs->get_ppfeature_status(\ (adev)->powerplay.pp_handle, (buf))) @@ -369,6 +361,9 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->set_ppfeature_status(\ (adev)->powerplay.pp_handle, (ppfeatures))) +#define amdgpu_dpm_get_gpu_metrics(adev, table) \ + ((adev)->powerplay.pp_funcs->get_gpu_metrics((adev)->powerplay.pp_handle, table)) + struct amdgpu_dpm { struct amdgpu_ps *ps; /* number of valid power states */ @@ -545,4 +540,26 @@ int amdgpu_dpm_set_df_cstate(struct amdgpu_device *adev, int amdgpu_dpm_allow_xgmi_power_down(struct amdgpu_device *adev, bool en); +int amdgpu_dpm_enable_mgpu_fan_boost(struct amdgpu_device *adev); + +int amdgpu_dpm_set_clockgating_by_smu(struct amdgpu_device *adev, + uint32_t msg_id); + +int amdgpu_dpm_smu_i2c_bus_access(struct amdgpu_device *adev, + bool acquire); + +void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev); + +int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor, + void *data, uint32_t *size); + +void amdgpu_dpm_thermal_work_handler(struct work_struct *work); + +void amdgpu_pm_compute_clocks(struct amdgpu_device *adev); +void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable); +void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable); +void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable); +void amdgpu_pm_print_power_states(struct amdgpu_device *adev); +int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_pm.h index d9ae2b49a402..45a22e101d15 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_pm.h @@ -79,18 +79,10 @@ struct amdgpu_device_attr_entry { amdgpu_get_##_name, NULL, \ _flags, ##__VA_ARGS__) -void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev); int amdgpu_pm_sysfs_init(struct amdgpu_device *adev); int amdgpu_pm_virt_sysfs_init(struct amdgpu_device *adev); void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev); void amdgpu_pm_virt_sysfs_fini(struct amdgpu_device *adev); -void amdgpu_pm_print_power_states(struct amdgpu_device *adev); -int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version); -void amdgpu_pm_compute_clocks(struct amdgpu_device *adev); -void amdgpu_dpm_thermal_work_handler(struct work_struct *work); -void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable); -void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable); -void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable); int amdgpu_debugfs_pm_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h index 074458eb5407..d22a759b6b43 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h @@ -274,6 +274,9 @@ struct smu_table_context void *overdrive_table; void *boot_overdrive_table; + + uint32_t gpu_metrics_table_size; + void *gpu_metrics_table; }; struct smu_dpm_context { @@ -448,6 +451,10 @@ struct smu_context bool dc_controlled_by_gpio; struct work_struct throttling_logging_work; + atomic64_t throttle_int_counter; + + unsigned fan_max_rpm; + unsigned manual_fan_speed_rpm; }; struct i2c_adapter; @@ -491,7 +498,6 @@ struct pptable_funcs { int (*notify_smc_display_config)(struct smu_context *smu); int (*set_cpu_power_state)(struct smu_context *smu); bool (*is_dpm_running)(struct smu_context *smu); - int (*get_fan_speed_percent)(struct smu_context *smu, uint32_t *speed); int (*get_fan_speed_rpm)(struct smu_context *smu, uint32_t *speed); int (*set_watermarks_table)(struct smu_context *smu, struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges); @@ -567,7 +573,6 @@ struct pptable_funcs { int (*conv_power_profile_to_pplib_workload)(int power_profile); uint32_t (*get_fan_control_mode)(struct smu_context *smu); int (*set_fan_control_mode)(struct smu_context *smu, uint32_t mode); - int (*set_fan_speed_percent)(struct smu_context *smu, uint32_t speed); int (*set_fan_speed_rpm)(struct smu_context *smu, uint32_t speed); int (*set_xgmi_pstate)(struct smu_context *smu, uint32_t pstate); int (*gfx_off_control)(struct smu_context *smu, bool enable); @@ -590,6 +595,11 @@ struct pptable_funcs { void (*log_thermal_throttling_event)(struct smu_context *smu); size_t (*get_pp_feature_mask)(struct smu_context *smu, char *buf); int (*set_pp_feature_mask)(struct smu_context *smu, uint64_t new_mask); + ssize_t (*get_gpu_metrics)(struct smu_context *smu, void **table); + int (*enable_mgpu_fan_boost)(struct smu_context *smu); + int (*gfx_ulv_control)(struct smu_context *smu, bool enablement); + int (*deep_sleep_control)(struct smu_context *smu, bool enablement); + int (*get_fan_parameters)(struct smu_context *smu); }; typedef enum { @@ -792,5 +802,9 @@ int smu_get_dpm_clock_table(struct smu_context *smu, int smu_get_status_gfxoff(struct amdgpu_device *adev, uint32_t *value); +ssize_t smu_sys_get_gpu_metrics(struct smu_context *smu, void **table); + +int smu_enable_mgpu_fan_boost(struct smu_context *smu); + #endif #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/arcturus_ppsmc.h index 79afb132164e..79afb132164e 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/arcturus_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/cz_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/cz_ppsmc.h index 9b698780aed8..9b698780aed8 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/cz_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/cz_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/fiji_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/fiji_ppsmc.h index 7ae494569a60..7ae494569a60 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/fiji_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/fiji_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/pm/inc/hardwaremanager.h index 6e0be6027705..6e0be6027705 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h +++ b/drivers/gpu/drm/amd/pm/inc/hardwaremanager.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/inc/hwmgr.h index 15ed6cbdf366..1b3529efc91e 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/inc/hwmgr.h @@ -359,6 +359,7 @@ struct pp_hwmgr_func { int (*set_xgmi_pstate)(struct pp_hwmgr *hwmgr, uint32_t pstate); int (*disable_power_features_for_compute_performance)(struct pp_hwmgr *hwmgr, bool disable); + ssize_t (*get_gpu_metrics)(struct pp_hwmgr *hwmgr, void **table); }; struct pp_table_func { diff --git a/drivers/gpu/drm/amd/powerplay/inc/polaris10_pwrvirus.h b/drivers/gpu/drm/amd/pm/inc/polaris10_pwrvirus.h index 6a53b7e74ccd..6a53b7e74ccd 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/polaris10_pwrvirus.h +++ b/drivers/gpu/drm/amd/pm/inc/polaris10_pwrvirus.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/power_state.h b/drivers/gpu/drm/amd/pm/inc/power_state.h index a5f2227a3971..a5f2227a3971 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/power_state.h +++ b/drivers/gpu/drm/amd/pm/inc/power_state.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h b/drivers/gpu/drm/amd/pm/inc/pp_debug.h index cea65093b6ad..cea65093b6ad 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_debug.h +++ b/drivers/gpu/drm/amd/pm/inc/pp_debug.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_endian.h b/drivers/gpu/drm/amd/pm/inc/pp_endian.h index f49d1963fe85..f49d1963fe85 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_endian.h +++ b/drivers/gpu/drm/amd/pm/inc/pp_endian.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_thermal.h b/drivers/gpu/drm/amd/pm/inc/pp_thermal.h index 3e30768f9e1c..3e30768f9e1c 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_thermal.h +++ b/drivers/gpu/drm/amd/pm/inc/pp_thermal.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/ppinterrupt.h b/drivers/gpu/drm/amd/pm/inc/ppinterrupt.h index c067e0925b6b..c067e0925b6b 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/ppinterrupt.h +++ b/drivers/gpu/drm/amd/pm/inc/ppinterrupt.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/rv_ppsmc.h index df4677da736c..df4677da736c 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/rv_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu10.h b/drivers/gpu/drm/amd/pm/inc/smu10.h index b96520528240..b96520528240 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu10.h +++ b/drivers/gpu/drm/amd/pm/inc/smu10.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu10_driver_if.h b/drivers/gpu/drm/amd/pm/inc/smu10_driver_if.h index dea8fe93da63..dea8fe93da63 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu10_driver_if.h +++ b/drivers/gpu/drm/amd/pm/inc/smu10_driver_if.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if.h b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if.h index fdc6b7a57bc9..fdc6b7a57bc9 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if.h +++ b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_arcturus.h b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_arcturus.h index 43d43d6addc0..43d43d6addc0 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_arcturus.h +++ b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_arcturus.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_navi10.h b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_navi10.h index 4b2da98afcd2..246d3951a78a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_navi10.h +++ b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_navi10.h @@ -885,6 +885,45 @@ typedef struct { } SmuMetrics_t; typedef struct { + uint16_t CurrClock[PPCLK_COUNT]; + uint16_t AverageGfxclkFrequency; + uint16_t AverageSocclkFrequency; + uint16_t AverageUclkFrequency ; + uint16_t AverageGfxActivity ; + uint16_t AverageUclkActivity ; + uint8_t CurrSocVoltageOffset ; + uint8_t CurrGfxVoltageOffset ; + uint8_t CurrMemVidOffset ; + uint8_t Padding8 ; + uint16_t AverageSocketPower ; + uint16_t TemperatureEdge ; + uint16_t TemperatureHotspot ; + uint16_t TemperatureMem ; + uint16_t TemperatureVrGfx ; + uint16_t TemperatureVrMem0 ; + uint16_t TemperatureVrMem1 ; + uint16_t TemperatureVrSoc ; + uint16_t TemperatureLiquid0 ; + uint16_t TemperatureLiquid1 ; + uint16_t TemperaturePlx ; + uint16_t Padding16 ; + uint32_t ThrottlerStatus ; + + uint8_t LinkDpmLevel; + uint8_t Padding8_2; + uint16_t CurrFanSpeed; + + uint32_t EnergyAccumulator; + uint16_t AverageVclkFrequency ; + uint16_t AverageDclkFrequency ; + uint16_t VcnActivityPercentage ; + uint16_t padding16_2; + + // Padding - ignore + uint32_t MmHubPadding[8]; // SMU internal use +} SmuMetrics_NV12_t; + +typedef struct { uint16_t MinClock; // This is either DCEFCLK or SOCCLK (in MHz) uint16_t MaxClock; // This is either DCEFCLK or SOCCLK (in MHz) uint16_t MinUclk; diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_sienna_cichlid.h b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_sienna_cichlid.h index aa2708fccb6d..5ef9c92f57c4 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_sienna_cichlid.h +++ b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_sienna_cichlid.h @@ -27,7 +27,7 @@ // *** IMPORTANT *** // SMU TEAM: Always increment the interface version if // any structure is changed in this file -#define SMU11_DRIVER_IF_VERSION 0x34 +#define SMU11_DRIVER_IF_VERSION 0x35 #define PPTABLE_Sienna_Cichlid_SMU_VERSION 5 @@ -127,7 +127,7 @@ #define FEATURE_DF_CSTATE_BIT 45 #define FEATURE_2_STEP_PSTATE_BIT 46 #define FEATURE_SMNCLK_DPM_BIT 47 -#define FEATURE_SPARE_48_BIT 48 +#define FEATURE_PERLINK_GMIDOWN_BIT 48 #define FEATURE_GFX_EDC_BIT 49 #define FEATURE_SPARE_50_BIT 50 #define FEATURE_SPARE_51_BIT 51 @@ -169,7 +169,7 @@ typedef enum { #define DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN 0x00000200 #define DPM_OVERRIDE_DISABLE_MEMORY_TEMPERATURE_READ 0x00000400 #define DPM_OVERRIDE_DISABLE_VOLT_LINK_VCN_DCEFCLK 0x00000800 -#define DPM_OVERRIDE_DISABLE_FAST_FCLK_TIMER 0x00001000 +#define DPM_OVERRIDE_ENABLE_FAST_FCLK_TIMER 0x00001000 #define DPM_OVERRIDE_DISABLE_VCN_PG 0x00002000 #define DPM_OVERRIDE_DISABLE_FMAX_VMAX 0x00004000 diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu12_driver_if.h b/drivers/gpu/drm/amd/pm/inc/smu12_driver_if.h index e9315eb5b48e..e9315eb5b48e 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu12_driver_if.h +++ b/drivers/gpu/drm/amd/pm/inc/smu12_driver_if.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7.h b/drivers/gpu/drm/amd/pm/inc/smu7.h index e14072d45918..e14072d45918 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu7.h +++ b/drivers/gpu/drm/amd/pm/inc/smu7.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu71.h b/drivers/gpu/drm/amd/pm/inc/smu71.h index 71c9b2d28640..71c9b2d28640 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu71.h +++ b/drivers/gpu/drm/amd/pm/inc/smu71.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu71_discrete.h b/drivers/gpu/drm/amd/pm/inc/smu71_discrete.h index c0e3936d5c2e..c0e3936d5c2e 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu71_discrete.h +++ b/drivers/gpu/drm/amd/pm/inc/smu71_discrete.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu72.h b/drivers/gpu/drm/amd/pm/inc/smu72.h index 9ad1cefff79f..9ad1cefff79f 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu72.h +++ b/drivers/gpu/drm/amd/pm/inc/smu72.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h b/drivers/gpu/drm/amd/pm/inc/smu72_discrete.h index 2aefbb85f620..2aefbb85f620 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h +++ b/drivers/gpu/drm/amd/pm/inc/smu72_discrete.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu73.h b/drivers/gpu/drm/amd/pm/inc/smu73.h index c6b12a4c00db..c6b12a4c00db 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu73.h +++ b/drivers/gpu/drm/amd/pm/inc/smu73.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu73_discrete.h b/drivers/gpu/drm/amd/pm/inc/smu73_discrete.h index 5916be08a7fe..5916be08a7fe 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu73_discrete.h +++ b/drivers/gpu/drm/amd/pm/inc/smu73_discrete.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu74.h b/drivers/gpu/drm/amd/pm/inc/smu74.h index fd10a9fa843d..fd10a9fa843d 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu74.h +++ b/drivers/gpu/drm/amd/pm/inc/smu74.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu74_discrete.h b/drivers/gpu/drm/amd/pm/inc/smu74_discrete.h index 899d6d8108c2..899d6d8108c2 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu74_discrete.h +++ b/drivers/gpu/drm/amd/pm/inc/smu74_discrete.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu75.h b/drivers/gpu/drm/amd/pm/inc/smu75.h index 771523001533..771523001533 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu75.h +++ b/drivers/gpu/drm/amd/pm/inc/smu75.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu75_discrete.h b/drivers/gpu/drm/amd/pm/inc/smu75_discrete.h index b64e58a22ddf..b64e58a22ddf 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu75_discrete.h +++ b/drivers/gpu/drm/amd/pm/inc/smu75_discrete.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7_common.h b/drivers/gpu/drm/amd/pm/inc/smu7_common.h index 94bf7b649c20..94bf7b649c20 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu7_common.h +++ b/drivers/gpu/drm/amd/pm/inc/smu7_common.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7_discrete.h b/drivers/gpu/drm/amd/pm/inc/smu7_discrete.h index ee876745dd12..ee876745dd12 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu7_discrete.h +++ b/drivers/gpu/drm/amd/pm/inc/smu7_discrete.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7_fusion.h b/drivers/gpu/drm/amd/pm/inc/smu7_fusion.h index 78ada9ffd508..78ada9ffd508 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu7_fusion.h +++ b/drivers/gpu/drm/amd/pm/inc/smu7_fusion.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/smu7_ppsmc.h index 6e19f4c7cf8f..6e19f4c7cf8f 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu7_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/smu7_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu8.h b/drivers/gpu/drm/amd/pm/inc/smu8.h index d758d07b6a31..d758d07b6a31 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu8.h +++ b/drivers/gpu/drm/amd/pm/inc/smu8.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu8_fusion.h b/drivers/gpu/drm/amd/pm/inc/smu8_fusion.h index 0c37c94e9414..0c37c94e9414 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu8_fusion.h +++ b/drivers/gpu/drm/amd/pm/inc/smu8_fusion.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu9.h b/drivers/gpu/drm/amd/pm/inc/smu9.h index 70ac4d477be2..70ac4d477be2 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu9.h +++ b/drivers/gpu/drm/amd/pm/inc/smu9.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu9_driver_if.h b/drivers/gpu/drm/amd/pm/inc/smu9_driver_if.h index 2818c98ff5ca..2818c98ff5ca 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu9_driver_if.h +++ b/drivers/gpu/drm/amd/pm/inc/smu9_driver_if.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_types.h b/drivers/gpu/drm/amd/pm/inc/smu_types.h index 7b585e205a5a..7b585e205a5a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_types.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_cz.h b/drivers/gpu/drm/amd/pm/inc/smu_ucode_xfer_cz.h index eb0f79f9c876..eb0f79f9c876 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_cz.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_ucode_xfer_cz.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_vi.h b/drivers/gpu/drm/amd/pm/inc/smu_ucode_xfer_vi.h index 880152c0f775..880152c0f775 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_vi.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_ucode_xfer_vi.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h index 6a42331aba8a..1f9575a4dfe7 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h @@ -28,10 +28,10 @@ #define SMU11_DRIVER_IF_VERSION_INV 0xFFFFFFFF #define SMU11_DRIVER_IF_VERSION_ARCT 0x17 #define SMU11_DRIVER_IF_VERSION_NV10 0x36 -#define SMU11_DRIVER_IF_VERSION_NV12 0x33 +#define SMU11_DRIVER_IF_VERSION_NV12 0x36 #define SMU11_DRIVER_IF_VERSION_NV14 0x36 -#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x34 -#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0x3 +#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x35 +#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0x4 /* MP Apertures */ #define MP0_Public 0x03800000 @@ -200,12 +200,12 @@ int smu_v11_0_set_fan_control_mode(struct smu_context *smu, uint32_t mode); -int -smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed); - int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed); +int smu_v11_0_get_fan_speed_rpm(struct smu_context *smu, + uint32_t *speed); + int smu_v11_0_set_xgmi_pstate(struct smu_context *smu, uint32_t pstate); @@ -264,5 +264,21 @@ int smu_v11_0_get_dpm_level_range(struct smu_context *smu, uint32_t *min_value, uint32_t *max_value); +int smu_v11_0_get_current_pcie_link_width_level(struct smu_context *smu); + +int smu_v11_0_get_current_pcie_link_width(struct smu_context *smu); + +int smu_v11_0_get_current_pcie_link_speed_level(struct smu_context *smu); + +int smu_v11_0_get_current_pcie_link_speed(struct smu_context *smu); + +void smu_v11_0_init_gpu_metrics_v1_0(struct gpu_metrics_v1_0 *gpu_metrics); + +int smu_v11_0_gfx_ulv_control(struct smu_context *smu, + bool enablement); + +int smu_v11_0_deep_sleep_control(struct smu_context *smu, + bool enablement); + #endif #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_0_7_ppsmc.h index 35dd6072cc45..35dd6072cc45 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_0_7_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_pptable.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_0_7_pptable.h index 247c6e9632ba..247c6e9632ba 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_pptable.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_0_7_pptable.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_0_ppsmc.h index 406bfd187ce8..fa0174dc7e0e 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_0_ppsmc.h @@ -123,7 +123,9 @@ #define PPSMC_MSG_DALDisableDummyPstateChange 0x49 #define PPSMC_MSG_DALEnableDummyPstateChange 0x4A -#define PPSMC_Message_Count 0x4B +#define PPSMC_MSG_SetMGpuFanBoostLimitRpm 0x4C + +#define PPSMC_Message_Count 0x4D typedef uint32_t PPSMC_Result; typedef uint32_t PPSMC_Msg; diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_pptable.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_0_pptable.h index 7a63cf8e85ed..7a63cf8e85ed 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_pptable.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_0_pptable.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h b/drivers/gpu/drm/amd/pm/inc/smu_v12_0.h index 02de3b6199e5..fa2e8cb07967 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v12_0.h @@ -60,5 +60,7 @@ int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_ int smu_v12_0_set_driver_table_location(struct smu_context *smu); +void smu_v12_0_init_gpu_metrics_v2_0(struct gpu_metrics_v2_0 *gpu_metrics); + #endif #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/smu_v12_0_ppsmc.h index 9ac9f3bd3664..9ac9f3bd3664 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v12_0_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/pm/inc/smumgr.h index ad100b533d04..ad100b533d04 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h +++ b/drivers/gpu/drm/amd/pm/inc/smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/tonga_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/tonga_ppsmc.h index 63631296d751..63631296d751 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/tonga_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/tonga_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega10_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/vega10_ppsmc.h index 715b5a168831..715b5a168831 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega10_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/vega10_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h b/drivers/gpu/drm/amd/pm/inc/vega12/smu9_driver_if.h index b6ffd08784e7..b6ffd08784e7 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h +++ b/drivers/gpu/drm/amd/pm/inc/vega12/smu9_driver_if.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega12_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/vega12_ppsmc.h index f985c78d746a..f985c78d746a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega12_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/vega12_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/vega20_ppsmc.h index 0c66f0fe1aaf..0c66f0fe1aaf 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/vega20_ppsmc.h diff --git a/drivers/gpu/drm/amd/powerplay/Makefile b/drivers/gpu/drm/amd/pm/powerplay/Makefile index e9c48f99f71b..0fb114adc79f 100644 --- a/drivers/gpu/drm/amd/powerplay/Makefile +++ b/drivers/gpu/drm/amd/pm/powerplay/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2017 Advanced Micro Devices, Inc. +# Copyright 2020 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"), @@ -20,25 +20,20 @@ # OTHER DEALINGS IN THE SOFTWARE. # -subdir-ccflags-y += \ - -I$(FULL_AMD_PATH)/powerplay/inc/ \ - -I$(FULL_AMD_PATH)/include/asic_reg \ - -I$(FULL_AMD_PATH)/include \ - -I$(FULL_AMD_PATH)/powerplay/smumgr\ - -I$(FULL_AMD_PATH)/powerplay/hwmgr - -AMD_PP_PATH = ../powerplay +AMD_PP_PATH = ../pm/powerplay PP_LIBS = smumgr hwmgr -AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/powerplay/,$(PP_LIBS))) +AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/pm/powerplay/,$(PP_LIBS))) include $(AMD_POWERPLAY) -POWER_MGR = amd_powerplay.o amdgpu_smu.o smu_v11_0.o \ - smu_v12_0.o arcturus_ppt.o navi10_ppt.o \ - renoir_ppt.o sienna_cichlid_ppt.o smu_cmn.o +POWER_MGR-y = amd_powerplay.o + +POWER_MGR-$(CONFIG_DRM_AMDGPU_CIK)+= kv_dpm.o kv_smc.o + +POWER_MGR-$(CONFIG_DRM_AMDGPU_SI)+= si_dpm.o si_smc.o -AMD_PP_POWER = $(addprefix $(AMD_PP_PATH)/,$(POWER_MGR)) +AMD_PP_POWER = $(addprefix $(AMD_PP_PATH)/,$(POWER_MGR-y)) AMD_POWERPLAY_FILES += $(AMD_PP_POWER) diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 7e6dcdf7df73..a6321f2063c1 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -1598,6 +1598,24 @@ static int pp_set_xgmi_pstate(void *handle, uint32_t pstate) return 0; } +static ssize_t pp_get_gpu_metrics(void *handle, void **table) +{ + struct pp_hwmgr *hwmgr = handle; + ssize_t size; + + if (!hwmgr) + return -EINVAL; + + if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_gpu_metrics) + return -EOPNOTSUPP; + + mutex_lock(&hwmgr->smu_lock); + size = hwmgr->hwmgr_func->get_gpu_metrics(hwmgr, table); + mutex_unlock(&hwmgr->smu_lock); + + return size; +} + static const struct amd_pm_funcs pp_dpm_funcs = { .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, @@ -1658,4 +1676,5 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .smu_i2c_bus_access = pp_smu_i2c_bus_access, .set_df_cstate = pp_set_df_cstate, .set_xgmi_pstate = pp_set_xgmi_pstate, + .get_gpu_metrics = pp_get_gpu_metrics, }; diff --git a/drivers/gpu/drm/amd/amdgpu/cik_dpm.h b/drivers/gpu/drm/amd/pm/powerplay/cik_dpm.h index 2fcc4b60153c..2fcc4b60153c 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_dpm.h +++ b/drivers/gpu/drm/amd/pm/powerplay/cik_dpm.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/Makefile index 2773966ae434..2773966ae434 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/Makefile diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ci_baco.c index 3be40114e63d..3be40114e63d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ci_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ci_baco.h index 17041f187020..17041f187020 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ci_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/common_baco.c index 1c73776bd606..1c73776bd606 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/common_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/common_baco.h index 8393eb62706d..8393eb62706d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/common_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/fiji_baco.c index c0368f2dfb21..c0368f2dfb21 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/fiji_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/fiji_baco.h index 47f402900bdb..47f402900bdb 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/fiji_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c index 9454ab50f9a1..1f9b9facdf1f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c @@ -271,7 +271,10 @@ int phm_start_thermal_controller(struct pp_hwmgr *hwmgr) bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr) { - PHM_FUNC_CHECK(hwmgr); + if (hwmgr == NULL || + hwmgr->hwmgr_func == NULL) + return false; + if (hwmgr->pp_one_vf) return false; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c index f48fdc7f0382..f48fdc7f0382 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr_ppt.h index c0193e09d58a..c0193e09d58a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr_ppt.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr_ppt.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/polaris_baco.c index 8f8e296f2fe9..8f8e296f2fe9 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/polaris_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/polaris_baco.h index 87a5fa0a157a..87a5fa0a157a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/polaris_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_overdriver.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_overdriver.c index 8de384bf9a8f..8de384bf9a8f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_overdriver.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_overdriver.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_overdriver.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_overdriver.h index 4112a9398163..4112a9398163 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_overdriver.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_overdriver.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c index 31a32a79cfc2..31a32a79cfc2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.h index b62d55f1f289..b62d55f1f289 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c index 01dc46dc9c8a..01dc46dc9c8a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.h index 3ee54f182943..76ed2e413594 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.h @@ -26,15 +26,6 @@ #include "hwmgr.h" -#define MEM_TYPE_GDDR5 0x50 -#define MEM_TYPE_GDDR4 0x40 -#define MEM_TYPE_GDDR3 0x30 -#define MEM_TYPE_DDR2 0x20 -#define MEM_TYPE_GDDR1 0x10 -#define MEM_TYPE_DDR3 0xb0 -#define MEM_TYPE_MASK 0xF0 - - /* As returned from PowerConnectorDetectionTable. */ #define PP_ATOM_POWER_BUDGET_DISABLE_OVERDRIVE 0x80 #define PP_ATOM_POWER_BUDGET_SHOW_WARNING 0x40 diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c index 615cf2c09e54..615cf2c09e54 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h index b7e2651b570b..b7e2651b570b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppevvmath.h index 8f50a038396c..8f50a038396c 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppevvmath.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pppcielanes.c index 186496a34cbe..186496a34cbe 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pppcielanes.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pppcielanes.h index 70b163b35570..70b163b35570 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pppcielanes.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pppcielanes.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pptable_v1_0.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h index 1e870f58dd12..1e870f58dd12 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pptable_v1_0.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c index b760f95e7fa7..b760f95e7fa7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.h index b9710abdff01..b9710abdff01 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c index 719597c5d27d..719597c5d27d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.h index baddaa75693b..baddaa75693b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c index 9ee8cf8267c8..9ee8cf8267c8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h index 0f969de10fab..0f969de10fab 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_inc.h index edb68e302f6f..edb68e302f6f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_inc.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c index 044cda005aed..044cda005aed 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h index be0d98abb536..be0d98abb536 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c index f2bda3bcbbde..f2bda3bcbbde 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h index fc8f8a6acc72..fc8f8a6acc72 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_dyn_defaults.h index 3477d4dfff70..3477d4dfff70 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_dyn_defaults.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c index 4a3b64aa21ce..4a3b64aa21ce 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h index 69d361f8dfca..69d361f8dfca 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_powertune.c index 5d4971576111..5d4971576111 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_powertune.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_powertune.h index 22f86b6bf1be..22f86b6bf1be 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_powertune.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c index 0b30f73649a8..0b30f73649a8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.h index 42c1ba0fad78..42c1ba0fad78 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c index 35ed47ebaf09..35ed47ebaf09 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.h index 05a06083e1b8..05a06083e1b8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu9_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c index de0a37f7c632..de0a37f7c632 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu9_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu9_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h index 84e90f801ac3..84e90f801ac3 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu9_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c index 60b5ca974356..60b5ca974356 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h index ad33983a8064..ad33983a8064 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/tonga_baco.c index ea743bea8e29..ea743bea8e29 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/tonga_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/tonga_baco.h index 5dc16cc8a295..5dc16cc8a295 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/tonga_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_baco.c index 46bb16c29cf6..46bb16c29cf6 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_baco.h index 96d793f026a5..96d793f026a5 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c index c378a000c934..c378a000c934 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.h index f752b4ad0c8a..f752b4ad0c8a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_inc.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_inc.h index faf7ac044348..faf7ac044348 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_inc.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_inc.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_powertune.c index 9757d47dd6b8..9757d47dd6b8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_powertune.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_powertune.h index b95771ab89cd..b95771ab89cd 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_powertune.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_pptable.h index c934e9612c1b..c934e9612c1b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_pptable.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_pptable.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c index f29af5ca0aa0..f29af5ca0aa0 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.h index da5fbec9b0cd..da5fbec9b0cd 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c index 952cd3d7240e..952cd3d7240e 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.h index 4a0ede7c1f07..4a0ede7c1f07 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_baco.c index bc53cce4f32d..bc53cce4f32d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_baco.h index 57b72e5a95ae..57b72e5a95ae 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c index a678a67f1c0d..f0680dd58508 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c @@ -47,6 +47,13 @@ #include "pp_thermal.h" #include "vega12_baco.h" +#define smnPCIE_LC_SPEED_CNTL 0x11140290 +#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 + +#define LINK_WIDTH_MAX 6 +#define LINK_SPEED_MAX 3 +static int link_width[] = {0, 1, 2, 4, 8, 12, 16}; +static int link_speed[] = {25, 50, 80, 160}; static int vega12_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask); @@ -1255,22 +1262,29 @@ static uint32_t vega12_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) return (mem_clk * 100); } -static int vega12_get_metrics_table(struct pp_hwmgr *hwmgr, SmuMetrics_t *metrics_table) +static int vega12_get_metrics_table(struct pp_hwmgr *hwmgr, + SmuMetrics_t *metrics_table, + bool bypass_cache) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); int ret = 0; - if (!data->metrics_time || time_after(jiffies, data->metrics_time + HZ / 2)) { - ret = smum_smc_table_manager(hwmgr, (uint8_t *)metrics_table, - TABLE_SMU_METRICS, true); + if (bypass_cache || + !data->metrics_time || + time_after(jiffies, data->metrics_time + msecs_to_jiffies(1))) { + ret = smum_smc_table_manager(hwmgr, + (uint8_t *)(&data->metrics_table), + TABLE_SMU_METRICS, + true); if (ret) { pr_info("Failed to export SMU metrics table!\n"); return ret; } - memcpy(&data->metrics_table, metrics_table, sizeof(SmuMetrics_t)); data->metrics_time = jiffies; - } else + } + + if (metrics_table) memcpy(metrics_table, &data->metrics_table, sizeof(SmuMetrics_t)); return ret; @@ -1281,7 +1295,7 @@ static int vega12_get_gpu_power(struct pp_hwmgr *hwmgr, uint32_t *query) SmuMetrics_t metrics_table; int ret = 0; - ret = vega12_get_metrics_table(hwmgr, &metrics_table); + ret = vega12_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -1332,7 +1346,7 @@ static int vega12_get_current_activity_percent( SmuMetrics_t metrics_table; int ret = 0; - ret = vega12_get_metrics_table(hwmgr, &metrics_table); + ret = vega12_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -1380,7 +1394,7 @@ static int vega12_read_sensor(struct pp_hwmgr *hwmgr, int idx, *size = 4; break; case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: - ret = vega12_get_metrics_table(hwmgr, &metrics_table); + ret = vega12_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -1389,7 +1403,7 @@ static int vega12_read_sensor(struct pp_hwmgr *hwmgr, int idx, *size = 4; break; case AMDGPU_PP_SENSOR_MEM_TEMP: - ret = vega12_get_metrics_table(hwmgr, &metrics_table); + ret = vega12_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -2095,6 +2109,46 @@ static int vega12_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfe return 0; } +static int vega12_get_current_pcie_link_width_level(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + + return (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & + PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) + >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; +} + +static int vega12_get_current_pcie_link_width(struct pp_hwmgr *hwmgr) +{ + uint32_t width_level; + + width_level = vega12_get_current_pcie_link_width_level(hwmgr); + if (width_level > LINK_WIDTH_MAX) + width_level = 0; + + return link_width[width_level]; +} + +static int vega12_get_current_pcie_link_speed_level(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + + return (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & + PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) + >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; +} + +static int vega12_get_current_pcie_link_speed(struct pp_hwmgr *hwmgr) +{ + uint32_t speed_level; + + speed_level = vega12_get_current_pcie_link_speed_level(hwmgr); + if (speed_level > LINK_SPEED_MAX) + speed_level = 0; + + return link_speed[speed_level]; +} + static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf) { @@ -2682,6 +2736,69 @@ static int vega12_set_mp1_state(struct pp_hwmgr *hwmgr, return 0; } +static void vega12_init_gpu_metrics_v1_0(struct gpu_metrics_v1_0 *gpu_metrics) +{ + memset(gpu_metrics, 0xFF, sizeof(struct gpu_metrics_v1_0)); + + gpu_metrics->common_header.structure_size = + sizeof(struct gpu_metrics_v1_0); + gpu_metrics->common_header.format_revision = 1; + gpu_metrics->common_header.content_revision = 0; + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); +} + +static ssize_t vega12_get_gpu_metrics(struct pp_hwmgr *hwmgr, + void **table) +{ + struct vega12_hwmgr *data = + (struct vega12_hwmgr *)(hwmgr->backend); + struct gpu_metrics_v1_0 *gpu_metrics = + &data->gpu_metrics_table; + SmuMetrics_t metrics; + uint32_t fan_speed_rpm; + int ret; + + ret = vega12_get_metrics_table(hwmgr, &metrics, true); + if (ret) + return ret; + + vega12_init_gpu_metrics_v1_0(gpu_metrics); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureHBM; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + vega12_fan_ctrl_get_fan_speed_rpm(hwmgr, &fan_speed_rpm); + gpu_metrics->current_fan_speed = (uint16_t)fan_speed_rpm; + + gpu_metrics->pcie_link_width = + vega12_get_current_pcie_link_width(hwmgr); + gpu_metrics->pcie_link_speed = + vega12_get_current_pcie_link_speed(hwmgr); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); +} + static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .backend_init = vega12_hwmgr_backend_init, .backend_fini = vega12_hwmgr_backend_fini, @@ -2739,6 +2856,7 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .get_ppfeature_status = vega12_get_ppfeature_status, .set_ppfeature_status = vega12_set_ppfeature_status, .set_mp1_state = vega12_set_mp1_state, + .get_gpu_metrics = vega12_get_gpu_metrics, }; int vega12_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.h index 73875399666a..aa63ae41942d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.h @@ -399,6 +399,7 @@ struct vega12_hwmgr { unsigned long metrics_time; SmuMetrics_t metrics_table; + struct gpu_metrics_v1_0 gpu_metrics_table; }; #define VEGA12_DPM2_NEAR_TDP_DEC 10 diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_inc.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_inc.h index e6d9e84059e1..0d08c57d3bca 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_inc.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_inc.h @@ -35,7 +35,6 @@ #include "asic_reg/gc/gc_9_2_1_sh_mask.h" #include "asic_reg/nbio/nbio_6_1_offset.h" -#include "asic_reg/nbio/nbio_6_1_offset.h" #include "asic_reg/nbio/nbio_6_1_sh_mask.h" #endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_pptable.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_pptable.h index bf4f5095b80d..bf4f5095b80d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_pptable.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_pptable.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c index 195d8539fbb4..740e2fc7a034 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c @@ -252,7 +252,7 @@ static int init_powerplay_table_information( phm_copy_clock_limits_array(hwmgr, &pptable_information->power_saving_clock_max, powerplay_table->PowerSavingClockMax, ATOM_VEGA12_PPCLOCK_COUNT); phm_copy_clock_limits_array(hwmgr, &pptable_information->power_saving_clock_min, powerplay_table->PowerSavingClockMin, ATOM_VEGA12_PPCLOCK_COUNT); - pptable_information->smc_pptable = (PPTable_t *)kmalloc(sizeof(PPTable_t), GFP_KERNEL); + pptable_information->smc_pptable = kmalloc(sizeof(PPTable_t), GFP_KERNEL); if (pptable_information->smc_pptable == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.h index 65652ae65929..65652ae65929 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_thermal.c index 7ace439dcde7..7ace439dcde7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_thermal.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_thermal.h index 0d8ed039ab12..0d8ed039ab12 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_thermal.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c index 2a28c9df15a0..2a28c9df15a0 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h index f06471e712dc..f06471e712dc 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c index ea70d736f6a8..da84012b7fd5 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c @@ -55,6 +55,11 @@ #define smnPCIE_LC_SPEED_CNTL 0x11140290 #define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 +#define LINK_WIDTH_MAX 6 +#define LINK_SPEED_MAX 3 +static int link_width[] = {0, 1, 2, 4, 8, 12, 16}; +static int link_speed[] = {25, 50, 80, 160}; + static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr) { struct vega20_hwmgr *data = @@ -484,7 +489,7 @@ static int vega20_setup_asic_task(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); int ret = 0; - bool use_baco = (adev->in_gpu_reset && + bool use_baco = (amdgpu_in_reset(adev) && (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) || (adev->in_runpm && amdgpu_asic_supports_baco(adev)); @@ -2067,22 +2072,29 @@ static uint32_t vega20_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) return (mem_clk * 100); } -static int vega20_get_metrics_table(struct pp_hwmgr *hwmgr, SmuMetrics_t *metrics_table) +static int vega20_get_metrics_table(struct pp_hwmgr *hwmgr, + SmuMetrics_t *metrics_table, + bool bypass_cache) { struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend); int ret = 0; - if (!data->metrics_time || time_after(jiffies, data->metrics_time + HZ / 2)) { - ret = smum_smc_table_manager(hwmgr, (uint8_t *)metrics_table, - TABLE_SMU_METRICS, true); + if (bypass_cache || + !data->metrics_time || + time_after(jiffies, data->metrics_time + msecs_to_jiffies(1))) { + ret = smum_smc_table_manager(hwmgr, + (uint8_t *)(&data->metrics_table), + TABLE_SMU_METRICS, + true); if (ret) { pr_info("Failed to export SMU metrics table!\n"); return ret; } - memcpy(&data->metrics_table, metrics_table, sizeof(SmuMetrics_t)); data->metrics_time = jiffies; - } else + } + + if (metrics_table) memcpy(metrics_table, &data->metrics_table, sizeof(SmuMetrics_t)); return ret; @@ -2094,7 +2106,7 @@ static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, int ret = 0; SmuMetrics_t metrics_table; - ret = vega20_get_metrics_table(hwmgr, &metrics_table); + ret = vega20_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -2132,7 +2144,7 @@ static int vega20_get_current_activity_percent(struct pp_hwmgr *hwmgr, int ret = 0; SmuMetrics_t metrics_table; - ret = vega20_get_metrics_table(hwmgr, &metrics_table); + ret = vega20_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -2162,7 +2174,7 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx, switch (idx) { case AMDGPU_PP_SENSOR_GFX_SCLK: - ret = vega20_get_metrics_table(hwmgr, &metrics_table); + ret = vega20_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -2187,7 +2199,7 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx, *size = 4; break; case AMDGPU_PP_SENSOR_EDGE_TEMP: - ret = vega20_get_metrics_table(hwmgr, &metrics_table); + ret = vega20_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -2196,7 +2208,7 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx, *size = 4; break; case AMDGPU_PP_SENSOR_MEM_TEMP: - ret = vega20_get_metrics_table(hwmgr, &metrics_table); + ret = vega20_get_metrics_table(hwmgr, &metrics_table, false); if (ret) return ret; @@ -3259,6 +3271,46 @@ static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfe return 0; } +static int vega20_get_current_pcie_link_width_level(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + + return (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & + PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) + >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; +} + +static int vega20_get_current_pcie_link_width(struct pp_hwmgr *hwmgr) +{ + uint32_t width_level; + + width_level = vega20_get_current_pcie_link_width_level(hwmgr); + if (width_level > LINK_WIDTH_MAX) + width_level = 0; + + return link_width[width_level]; +} + +static int vega20_get_current_pcie_link_speed_level(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + + return (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & + PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) + >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; +} + +static int vega20_get_current_pcie_link_speed(struct pp_hwmgr *hwmgr) +{ + uint32_t speed_level; + + speed_level = vega20_get_current_pcie_link_speed_level(hwmgr); + if (speed_level > LINK_SPEED_MAX) + speed_level = 0; + + return link_speed[speed_level]; +} + static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf) { @@ -3271,7 +3323,6 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, struct phm_ppt_v3_information *pptable_information = (struct phm_ppt_v3_information *)hwmgr->pptable; PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable; - struct amdgpu_device *adev = hwmgr->adev; struct pp_clock_levels_with_latency clocks; struct vega20_single_dpm_table *fclk_dpm_table = &(data->dpm_table.fclk_table); @@ -3365,12 +3416,10 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, break; case PP_PCIE: - current_gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & - PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) - >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; - current_lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & - PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) - >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; + current_gen_speed = + vega20_get_current_pcie_link_speed_level(hwmgr); + current_lane_width = + vega20_get_current_pcie_link_width_level(hwmgr); for (i = 0; i < NUM_LINK_LEVELS; i++) { if (i == 1 && data->pcie_parameters_override) { gen_speed = data->pcie_gen_level1; @@ -4212,6 +4261,72 @@ static int vega20_set_xgmi_pstate(struct pp_hwmgr *hwmgr, return ret; } +static void vega20_init_gpu_metrics_v1_0(struct gpu_metrics_v1_0 *gpu_metrics) +{ + memset(gpu_metrics, 0xFF, sizeof(struct gpu_metrics_v1_0)); + + gpu_metrics->common_header.structure_size = + sizeof(struct gpu_metrics_v1_0); + gpu_metrics->common_header.format_revision = 1; + gpu_metrics->common_header.content_revision = 0; + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); +} + +static ssize_t vega20_get_gpu_metrics(struct pp_hwmgr *hwmgr, + void **table) +{ + struct vega20_hwmgr *data = + (struct vega20_hwmgr *)(hwmgr->backend); + struct gpu_metrics_v1_0 *gpu_metrics = + &data->gpu_metrics_table; + SmuMetrics_t metrics; + uint32_t fan_speed_rpm; + int ret; + + ret = vega20_get_metrics_table(hwmgr, &metrics, true); + if (ret) + return ret; + + vega20_init_gpu_metrics_v1_0(gpu_metrics); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureHBM; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + + gpu_metrics->average_socket_power = metrics.AverageSocketPower; + + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + vega20_fan_ctrl_get_fan_speed_rpm(hwmgr, &fan_speed_rpm); + gpu_metrics->current_fan_speed = (uint16_t)fan_speed_rpm; + + gpu_metrics->pcie_link_width = + vega20_get_current_pcie_link_width(hwmgr); + gpu_metrics->pcie_link_speed = + vega20_get_current_pcie_link_speed(hwmgr); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); +} + static const struct pp_hwmgr_func vega20_hwmgr_funcs = { /* init/fini related */ .backend_init = vega20_hwmgr_backend_init, @@ -4282,6 +4397,7 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = { .smu_i2c_bus_access = vega20_smu_i2c_bus_access, .set_df_cstate = vega20_set_df_cstate, .set_xgmi_pstate = vega20_set_xgmi_pstate, + .get_gpu_metrics = vega20_get_gpu_metrics, }; int vega20_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.h index 2c3125f82b24..075c0094da9c 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.h @@ -527,6 +527,7 @@ struct vega20_hwmgr { unsigned long metrics_time; SmuMetrics_t metrics_table; + struct gpu_metrics_v1_0 gpu_metrics_table; bool pcie_parameters_override; uint32_t pcie_gen_level1; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_inc.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_inc.h index 613cb1989b3d..613cb1989b3d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_inc.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_inc.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_powertune.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_powertune.c index d7cc3d2d9e17..d7cc3d2d9e17 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_powertune.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_powertune.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_powertune.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_powertune.h index d68c734c0f4e..d68c734c0f4e 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_powertune.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_powertune.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_pptable.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_pptable.h index 2222e29405c6..2222e29405c6 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_pptable.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_pptable.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c index 7a7f15d0c53a..1f9082539457 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c @@ -890,14 +890,12 @@ static int init_powerplay_table_information( power_saving_clock_count); } - pptable_information->smc_pptable = (PPTable_t *)kmalloc(sizeof(PPTable_t), GFP_KERNEL); + pptable_information->smc_pptable = kmemdup(&(powerplay_table->smcPPTable), + sizeof(PPTable_t), + GFP_KERNEL); if (pptable_information->smc_pptable == NULL) return -ENOMEM; - memcpy(pptable_information->smc_pptable, - &(powerplay_table->smcPPTable), - sizeof(PPTable_t)); - result = append_vbios_pptable(hwmgr, (pptable_information->smc_pptable)); if (result) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_processpptables.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.h index 846c2cb40b35..846c2cb40b35 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_processpptables.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c index 364162ddaa9c..364162ddaa9c 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_thermal.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.h index 2d1769bbd24e..2d1769bbd24e 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_thermal.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.h diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/pm/powerplay/kv_dpm.c index 4b3faaccecb9..4b3faaccecb9 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/pm/powerplay/kv_dpm.c diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.h b/drivers/gpu/drm/amd/pm/powerplay/kv_dpm.h index 6df0ed41317c..6df0ed41317c 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.h +++ b/drivers/gpu/drm/amd/pm/powerplay/kv_dpm.h diff --git a/drivers/gpu/drm/amd/amdgpu/kv_smc.c b/drivers/gpu/drm/amd/pm/powerplay/kv_smc.c index 2d9ab6b8be66..2d9ab6b8be66 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_smc.c +++ b/drivers/gpu/drm/amd/pm/powerplay/kv_smc.c diff --git a/drivers/gpu/drm/amd/amdgpu/ppsmc.h b/drivers/gpu/drm/amd/pm/powerplay/ppsmc.h index 8463245f424f..8463245f424f 100644 --- a/drivers/gpu/drm/amd/amdgpu/ppsmc.h +++ b/drivers/gpu/drm/amd/pm/powerplay/ppsmc.h diff --git a/drivers/gpu/drm/amd/amdgpu/r600_dpm.h b/drivers/gpu/drm/amd/pm/powerplay/r600_dpm.h index 055321f61ca7..055321f61ca7 100644 --- a/drivers/gpu/drm/amd/amdgpu/r600_dpm.h +++ b/drivers/gpu/drm/amd/pm/powerplay/r600_dpm.h diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/pm/powerplay/si_dpm.c index b5986d19dc08..b5986d19dc08 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/powerplay/si_dpm.c diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.h b/drivers/gpu/drm/amd/pm/powerplay/si_dpm.h index bc0be6818e21..bc0be6818e21 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.h +++ b/drivers/gpu/drm/amd/pm/powerplay/si_dpm.h diff --git a/drivers/gpu/drm/amd/amdgpu/si_smc.c b/drivers/gpu/drm/amd/pm/powerplay/si_smc.c index 8f994ffa9cd1..8f994ffa9cd1 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_smc.c +++ b/drivers/gpu/drm/amd/pm/powerplay/si_smc.c diff --git a/drivers/gpu/drm/amd/amdgpu/sislands_smc.h b/drivers/gpu/drm/amd/pm/powerplay/sislands_smc.h index d2930eceaf3c..d2930eceaf3c 100644 --- a/drivers/gpu/drm/amd/amdgpu/sislands_smc.h +++ b/drivers/gpu/drm/amd/pm/powerplay/sislands_smc.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/pm/powerplay/smumgr/Makefile index 6c59c61a0d81..6c59c61a0d81 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/Makefile diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c index e4d1f3d66ef4..e4d1f3d66ef4 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.h index a8282705c569..a8282705c569 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c index ecb9ee46d6b3..ecb9ee46d6b3 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.h index 6d3746268ccf..6d3746268ccf 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c index 431ad2fd38df..431ad2fd38df 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.h index f32c506779c9..f32c506779c9 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c index c3d2e6dcf62a..c3d2e6dcf62a 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.h index 1ec425df9eda..1ec425df9eda 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c index ea2279bb8cbf..ea2279bb8cbf 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.h index 9c2be74a2b2f..9c2be74a2b2f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c index aae25243eb10..aae25243eb10 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h index e7303dc8c260..e7303dc8c260 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c index 76d4f12ceedf..76d4f12ceedf 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.h index c7b61222d258..c7b61222d258 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu9_smumgr.c index adfbcbe5d113..adfbcbe5d113 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu9_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu9_smumgr.h index 1462279ca128..1462279ca128 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu9_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smumgr.c index b6fb48066841..b6fb48066841 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c index 4bfadb49521b..4bfadb49521b 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.h index d664fedd3d85..d664fedd3d85 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c index 1e222c5d91a4..1e222c5d91a4 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.h index bad760f22624..bad760f22624 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c index f54df76537e4..f54df76537e4 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.h index aeec965ce81f..aeec965ce81f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c index cf43629d29d2..cf43629d29d2 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.h index 62ebbfd6068f..62ebbfd6068f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c index 0ecc18b55ffb..0ecc18b55ffb 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.h index 2b6558238500..2b6558238500 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.h diff --git a/drivers/gpu/drm/amd/pm/swsmu/Makefile b/drivers/gpu/drm/amd/pm/swsmu/Makefile new file mode 100644 index 000000000000..6f281990b7b4 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/Makefile @@ -0,0 +1,36 @@ +# +# Copyright 2020 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. +# + +AMD_SWSMU_PATH = ../pm/swsmu + +SWSMU_LIBS = smu11 smu12 + +AMD_SWSMU = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/pm/swsmu/,$(SWSMU_LIBS))) + +include $(AMD_SWSMU) + +SWSMU_MGR = amdgpu_smu.o \ + smu_cmn.o \ + +AMD_SWSMU_POWER = $(addprefix $(AMD_SWSMU_PATH)/,$(SWSMU_MGR)) + +AMD_POWERPLAY_FILES += $(AMD_SWSMU_POWER) diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 0826625573dc..7a55ece1f124 100644 --- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -504,6 +504,8 @@ static int smu_late_init(void *handle) smu_get_unique_id(smu); + smu_get_fan_parameters(smu); + smu_handle_task(&adev->smu, smu->smu_dpm.dpm_level, AMD_PP_TASK_COMPLETE_INIT, @@ -756,6 +758,7 @@ static int smu_sw_init(void *handle) mutex_init(&smu->message_lock); INIT_WORK(&smu->throttling_logging_work, smu_throttling_logging_work_fn); + atomic64_set(&smu->throttle_int_counter, 0); smu->watermarks_bitmap = 0; smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; @@ -1109,7 +1112,7 @@ static int smu_disable_dpms(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; int ret = 0; bool use_baco = !smu->is_apu && - ((adev->in_gpu_reset && + ((amdgpu_in_reset(adev) && (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) || ((adev->in_runpm || adev->in_hibernate) && amdgpu_asic_supports_baco(adev))); @@ -1439,6 +1442,8 @@ static int smu_enable_umd_pstate(void *handle, amdgpu_device_ip_set_clockgating_state(smu->adev, AMD_IP_BLOCK_TYPE_GFX, AMD_CG_STATE_UNGATE); + smu_gfx_ulv_control(smu, false); + smu_deep_sleep_control(smu, false); } } else { /* exit umd pstate, restore level, enable gfx cg*/ @@ -1446,6 +1451,8 @@ static int smu_enable_umd_pstate(void *handle, if (*level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT) *level = smu_dpm_ctx->saved_dpm_level; smu_dpm_ctx->enable_umd_pstate = false; + smu_deep_sleep_control(smu, true); + smu_gfx_ulv_control(smu, true); amdgpu_device_ip_set_clockgating_state(smu->adev, AMD_IP_BLOCK_TYPE_GFX, AMD_CG_STATE_GATE); @@ -2185,31 +2192,44 @@ int smu_set_fan_control_mode(struct smu_context *smu, int value) int smu_get_fan_speed_percent(struct smu_context *smu, uint32_t *speed) { int ret = 0; + uint32_t percent; + uint32_t current_rpm; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->get_fan_speed_percent) - ret = smu->ppt_funcs->get_fan_speed_percent(smu, speed); + if (smu->ppt_funcs->get_fan_speed_rpm) { + ret = smu->ppt_funcs->get_fan_speed_rpm(smu, ¤t_rpm); + if (!ret) { + percent = current_rpm * 100 / smu->fan_max_rpm; + *speed = percent > 100 ? 100 : percent; + } + } mutex_unlock(&smu->mutex); + return ret; } int smu_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) { int ret = 0; + uint32_t rpm; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->set_fan_speed_percent) - ret = smu->ppt_funcs->set_fan_speed_percent(smu, speed); + if (smu->ppt_funcs->set_fan_speed_rpm) { + if (speed > 100) + speed = 100; + rpm = speed * smu->fan_max_rpm / 100; + ret = smu->ppt_funcs->set_fan_speed_rpm(smu, rpm); + } mutex_unlock(&smu->mutex); @@ -2631,3 +2651,40 @@ int smu_get_dpm_clock_table(struct smu_context *smu, return ret; } + +ssize_t smu_sys_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + ssize_t size; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (!smu->ppt_funcs->get_gpu_metrics) + return -EOPNOTSUPP; + + mutex_lock(&smu->mutex); + + size = smu->ppt_funcs->get_gpu_metrics(smu, table); + + mutex_unlock(&smu->mutex); + + return size; +} + +int smu_enable_mgpu_fan_boost(struct smu_context *smu) +{ + int ret = 0; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->enable_mgpu_fan_boost) + ret = smu->ppt_funcs->enable_mgpu_fan_boost(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu11/Makefile new file mode 100644 index 000000000000..f98d97192635 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/Makefile @@ -0,0 +1,33 @@ +# +# Copyright 2020 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. +# +# +# Makefile for the 'smu manager' sub-component of powerplay. +# It provides the smu management services for the driver. + +SMU11_MGR = arcturus_ppt.o \ + navi10_ppt.o \ + sienna_cichlid_ppt.o \ + smu_v11_0.o + +AMD_SWSMU_SMU11MGR = $(addprefix $(AMD_SWSMU_PATH)/smu11/,$(SMU11_MGR)) + +AMD_POWERPLAY_FILES += $(AMD_SWSMU_SMU11MGR) diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 9582b38162f0..2ce6ad9c6609 100644 --- a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -79,6 +79,8 @@ /* possible frequency drift (1Mhz) */ #define EPSILON 1 +#define smnPCIE_ESM_CTRL 0x111003D0 + static const struct cmn2asic_msg_mapping arcturus_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -234,6 +236,13 @@ static int arcturus_tables_init(struct smu_context *smu) return -ENOMEM; smu_table->metrics_time = 0; + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0); + smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); + if (!smu_table->gpu_metrics_table) { + kfree(smu_table->metrics_table); + return -ENOMEM; + } + return 0; } @@ -542,19 +551,12 @@ static int arcturus_get_smu_metrics_data(struct smu_context *smu, mutex_lock(&smu->metrics_lock); - if (!smu_table->metrics_time || - time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) { - ret = smu_cmn_update_table(smu, - SMU_TABLE_SMU_METRICS, - 0, - smu_table->metrics_table, - false); - if (ret) { - dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n"); - mutex_unlock(&smu->metrics_lock); - return ret; - } - smu_table->metrics_time = jiffies; + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + false); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; } switch (member) { @@ -897,9 +899,10 @@ static int arcturus_force_clk_levels(struct smu_context *smu, return ret; } - if (smu_version >= 0x361200) { + if ((smu_version >= 0x361200) && + (smu_version <= 0x361a00)) { dev_err(smu->adev->dev, "Forcing clock level is not supported with " - "54.18 and onwards SMU firmwares\n"); + "54.18 - 54.26(included) SMU firmwares\n"); return -EOPNOTSUPP; } @@ -1120,29 +1123,23 @@ static int arcturus_get_fan_speed_rpm(struct smu_context *smu, if (!speed) return -EINVAL; - return arcturus_get_smu_metrics_data(smu, - METRICS_CURR_FANSPEED, - speed); + switch (smu_v11_0_get_fan_control_mode(smu)) { + case AMD_FAN_CTRL_AUTO: + return arcturus_get_smu_metrics_data(smu, + METRICS_CURR_FANSPEED, + speed); + default: + return smu_v11_0_get_fan_speed_rpm(smu, speed); + } } -static int arcturus_get_fan_speed_percent(struct smu_context *smu, - uint32_t *speed) +static int arcturus_get_fan_parameters(struct smu_context *smu) { PPTable_t *pptable = smu->smu_table.driver_pptable; - uint32_t percent, current_rpm; - int ret = 0; - - if (!speed) - return -EINVAL; - - ret = arcturus_get_fan_speed_rpm(smu, ¤t_rpm); - if (ret) - return ret; - percent = current_rpm * 100 / pptable->FanMaximumRpm; - *speed = percent > 100 ? 100 : percent; + smu->fan_max_rpm = pptable->FanMaximumRpm; - return ret; + return 0; } static int arcturus_get_power_limit(struct smu_context *smu) @@ -1392,9 +1389,10 @@ static int arcturus_set_performance_level(struct smu_context *smu, case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: - if (smu_version >= 0x361200) { + if ((smu_version >= 0x361200) && + (smu_version <= 0x361a00)) { dev_err(smu->adev->dev, "Forcing clock level is not supported with " - "54.18 and onwards SMU firmwares\n"); + "54.18 - 54.26(included) SMU firmwares\n"); return -EOPNOTSUPP; } break; @@ -2240,6 +2238,77 @@ static void arcturus_log_thermal_throttling_event(struct smu_context *smu) dev_warn(adev->dev, "WARN: GPU thermal throttling temperature reached, expect performance decrease. %s.\n", log_buf); + kgd2kfd_smi_event_throttle(smu->adev->kfd.dev, throttler_status); +} + +static int arcturus_get_current_pcie_link_speed(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t esm_ctrl; + + /* TODO: confirm this on real target */ + esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); + if ((esm_ctrl >> 15) & 0x1FFFF) + return (((esm_ctrl >> 8) & 0x3F) + 128); + + return smu_v11_0_get_current_pcie_link_speed(smu); +} + +static ssize_t arcturus_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct gpu_metrics_v1_0 *gpu_metrics = + (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + SmuMetrics_t metrics; + int ret = 0; + + ret = smu_cmn_get_metrics_table(smu, + &metrics, + true); + if (ret) + return ret; + + smu_v11_0_init_gpu_metrics_v1_0(gpu_metrics); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureHBM; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + gpu_metrics->average_mm_activity = metrics.VcnActivityPercentage; + + gpu_metrics->average_socket_power = metrics.AverageSocketPower; + gpu_metrics->energy_accumulator = metrics.EnergyAccumulator; + + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; + gpu_metrics->average_vclk0_frequency = metrics.AverageVclkFrequency; + gpu_metrics->average_dclk0_frequency = metrics.AverageDclkFrequency; + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; + + gpu_metrics->pcie_link_width = + smu_v11_0_get_current_pcie_link_width(smu); + gpu_metrics->pcie_link_speed = + arcturus_get_current_pcie_link_speed(smu); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); } static const struct pptable_funcs arcturus_ppt_funcs = { @@ -2254,7 +2323,6 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .print_clk_levels = arcturus_print_clk_levels, .force_clk_levels = arcturus_force_clk_levels, .read_sensor = arcturus_read_sensor, - .get_fan_speed_percent = arcturus_get_fan_speed_percent, .get_fan_speed_rpm = arcturus_get_fan_speed_rpm, .get_power_profile_mode = arcturus_get_power_profile_mode, .set_power_profile_mode = arcturus_set_power_profile_mode, @@ -2300,7 +2368,6 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, .get_fan_control_mode = smu_v11_0_get_fan_control_mode, .set_fan_control_mode = smu_v11_0_set_fan_control_mode, - .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent, .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm, .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, .gfx_off_control = smu_v11_0_gfx_off_control, @@ -2319,6 +2386,10 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .log_thermal_throttling_event = arcturus_log_thermal_throttling_event, .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, + .get_gpu_metrics = arcturus_get_gpu_metrics, + .gfx_ulv_control = smu_v11_0_gfx_ulv_control, + .deep_sleep_control = smu_v11_0_deep_sleep_control, + .get_fan_parameters = arcturus_get_fan_parameters, }; void arcturus_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.h index d756b16924b8..d756b16924b8 100644 --- a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.h diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 3d5eae956a23..42d53cca7360 100644 --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -138,6 +138,7 @@ static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALEnableDummyPstateChange, 0), MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm, 0), MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive, 0), + MSG_MAP(SetMGpuFanBoostLimitRpm, PPSMC_MSG_SetMGpuFanBoostLimitRpm, 0), }; static struct cmn2asic_mapping navi10_clk_map[SMU_CLK_COUNT] = { @@ -456,13 +457,18 @@ static int navi10_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; + struct amdgpu_device *adev = smu->adev; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + if (adev->asic_type == CHIP_NAVI12) + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_NV12_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + else + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t), @@ -473,16 +479,30 @@ static int navi10_tables_init(struct smu_context *smu) sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc(adev->asic_type == CHIP_NAVI12 ? + sizeof(SmuMetrics_NV12_t) : + sizeof(SmuMetrics_t), GFP_KERNEL); if (!smu_table->metrics_table) - return -ENOMEM; + goto err0_out; smu_table->metrics_time = 0; + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0); + smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); + if (!smu_table->gpu_metrics_table) + goto err1_out; + smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); if (!smu_table->watermarks_table) - return -ENOMEM; + goto err2_out; return 0; + +err2_out: + kfree(smu_table->gpu_metrics_table); +err1_out: + kfree(smu_table->metrics_table); +err0_out: + return -ENOMEM; } static int navi10_get_smu_metrics_data(struct smu_context *smu, @@ -490,23 +510,22 @@ static int navi10_get_smu_metrics_data(struct smu_context *smu, uint32_t *value) { struct smu_table_context *smu_table= &smu->smu_table; + /* + * This works for NV12 also. As although NV12 uses a different + * SmuMetrics structure from other NV1X ASICs, they share the + * same offsets for the heading parts(those members used here). + */ SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; int ret = 0; mutex_lock(&smu->metrics_lock); - if (!smu_table->metrics_time || - time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) { - ret = smu_cmn_update_table(smu, - SMU_TABLE_SMU_METRICS, - 0, - smu_table->metrics_table, - false); - if (ret) { - dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n"); - mutex_unlock(&smu->metrics_lock); - return ret; - } - smu_table->metrics_time = jiffies; + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + false); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; } switch (member) { @@ -909,7 +928,6 @@ static int navi10_print_clk_levels(struct smu_context *smu, uint32_t gen_speed, lane_width; struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; - struct amdgpu_device *adev = smu->adev; PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; OverDriveTable_t *od_table = (OverDriveTable_t *)table_context->overdrive_table; @@ -963,12 +981,8 @@ static int navi10_print_clk_levels(struct smu_context *smu, } break; case SMU_PCIE: - gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & - PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) - >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; - lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & - PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) - >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; + gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu); + lane_width = smu_v11_0_get_current_pcie_link_width_level(smu); for (i = 0; i < NUM_LINK_LEVELS; i++) size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i, (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," : @@ -1348,27 +1362,23 @@ static int navi10_get_fan_speed_rpm(struct smu_context *smu, if (!speed) return -EINVAL; - return navi10_get_smu_metrics_data(smu, - METRICS_CURR_FANSPEED, - speed); + switch (smu_v11_0_get_fan_control_mode(smu)) { + case AMD_FAN_CTRL_AUTO: + return navi10_get_smu_metrics_data(smu, + METRICS_CURR_FANSPEED, + speed); + default: + return smu_v11_0_get_fan_speed_rpm(smu, speed); + } } -static int navi10_get_fan_speed_percent(struct smu_context *smu, - uint32_t *speed) +static int navi10_get_fan_parameters(struct smu_context *smu) { - int ret = 0; - uint32_t percent = 0; - uint32_t current_rpm; PPTable_t *pptable = smu->smu_table.driver_pptable; - ret = navi10_get_fan_speed_rpm(smu, ¤t_rpm); - if (ret) - return ret; - - percent = current_rpm * 100 / pptable->FanMaximumRpm; - *speed = percent > 100 ? 100 : percent; + smu->fan_max_rpm = pptable->FanMaximumRpm; - return ret; + return 0; } static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf) @@ -2476,6 +2486,97 @@ static void navi10_i2c_control_fini(struct smu_context *smu, struct i2c_adapter i2c_del_adapter(control); } +static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct gpu_metrics_v1_0 *gpu_metrics = + (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + struct amdgpu_device *adev = smu->adev; + SmuMetrics_NV12_t nv12_metrics = { 0 }; + SmuMetrics_t metrics; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + true); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; + } + + memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_t)); + if (adev->asic_type == CHIP_NAVI12) + memcpy(&nv12_metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_t)); + + mutex_unlock(&smu->metrics_lock); + + smu_v11_0_init_gpu_metrics_v1_0(gpu_metrics); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureMem; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + + gpu_metrics->average_socket_power = metrics.AverageSocketPower; + + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; + + if (adev->asic_type == CHIP_NAVI12) { + gpu_metrics->energy_accumulator = nv12_metrics.EnergyAccumulator; + gpu_metrics->average_vclk0_frequency = nv12_metrics.AverageVclkFrequency; + gpu_metrics->average_dclk0_frequency = nv12_metrics.AverageDclkFrequency; + gpu_metrics->average_mm_activity = nv12_metrics.VcnActivityPercentage; + } + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; + + gpu_metrics->pcie_link_width = + smu_v11_0_get_current_pcie_link_width(smu); + gpu_metrics->pcie_link_speed = + smu_v11_0_get_current_pcie_link_speed(smu); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); +} + +static int navi10_enable_mgpu_fan_boost(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t param = 0; + + /* Navi12 does not support this */ + if (adev->asic_type == CHIP_NAVI12) + return 0; + + /* Workaround for WS SKU */ + if (adev->pdev->device == 0x7312 && + adev->pdev->revision == 0) + param = 0xD188; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetMGpuFanBoostLimitRpm, + param, + NULL); +} static const struct pptable_funcs navi10_ppt_funcs = { .get_allowed_feature_mask = navi10_get_allowed_feature_mask, @@ -2492,7 +2593,6 @@ static const struct pptable_funcs navi10_ppt_funcs = { .display_config_changed = navi10_display_config_changed, .notify_smc_display_config = navi10_notify_smc_display_config, .is_dpm_running = navi10_is_dpm_running, - .get_fan_speed_percent = navi10_get_fan_speed_percent, .get_fan_speed_rpm = navi10_get_fan_speed_rpm, .get_power_profile_mode = navi10_get_power_profile_mode, .set_power_profile_mode = navi10_set_power_profile_mode, @@ -2536,7 +2636,6 @@ static const struct pptable_funcs navi10_ppt_funcs = { .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, .get_fan_control_mode = smu_v11_0_get_fan_control_mode, .set_fan_control_mode = smu_v11_0_set_fan_control_mode, - .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent, .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm, .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, .gfx_off_control = smu_v11_0_gfx_off_control, @@ -2557,6 +2656,11 @@ static const struct pptable_funcs navi10_ppt_funcs = { .set_power_source = smu_v11_0_set_power_source, .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, + .get_gpu_metrics = navi10_get_gpu_metrics, + .enable_mgpu_fan_boost = navi10_enable_mgpu_fan_boost, + .gfx_ulv_control = smu_v11_0_gfx_ulv_control, + .deep_sleep_control = smu_v11_0_deep_sleep_control, + .get_fan_parameters = navi10_get_fan_parameters, }; void navi10_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.h index 2abb4ba01db1..84dc5a1b6830 100644 --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.h @@ -49,9 +49,6 @@ #define NAVI10_VOLTAGE_SCALE (4) -#define smnPCIE_LC_SPEED_CNTL 0x11140290 -#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 - extern void navi10_set_ppt_funcs(struct smu_context *smu); #endif diff --git a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 61f4ddae262d..5c22611d5878 100644 --- a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -126,6 +126,7 @@ static struct cmn2asic_msg_mapping sienna_cichlid_message_map[SMU_MSG_MAX_COUNT] MSG_MAP(BacoAudioD3PME, PPSMC_MSG_BacoAudioD3PME, 0), MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0), MSG_MAP(Mode1Reset, PPSMC_MSG_Mode1Reset, 0), + MSG_MAP(SetMGpuFanBoostLimitRpm, PPSMC_MSG_SetMGpuFanBoostLimitRpm, 0), }; static struct cmn2asic_mapping sienna_cichlid_clk_map[SMU_CLK_COUNT] = { @@ -388,14 +389,26 @@ static int sienna_cichlid_tables_init(struct smu_context *smu) smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); if (!smu_table->metrics_table) - return -ENOMEM; + goto err0_out; smu_table->metrics_time = 0; + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0); + smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); + if (!smu_table->gpu_metrics_table) + goto err1_out; + smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); if (!smu_table->watermarks_table) - return -ENOMEM; + goto err2_out; return 0; + +err2_out: + kfree(smu_table->gpu_metrics_table); +err1_out: + kfree(smu_table->metrics_table); +err0_out: + return -ENOMEM; } static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu, @@ -407,19 +420,13 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu, int ret = 0; mutex_lock(&smu->metrics_lock); - if (!smu_table->metrics_time || - time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) { - ret = smu_cmn_update_table(smu, - SMU_TABLE_SMU_METRICS, - 0, - smu_table->metrics_table, - false); - if (ret) { - dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n"); - mutex_unlock(&smu->metrics_lock); - return ret; - } - smu_table->metrics_time = jiffies; + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + false); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; } switch (member) { @@ -954,12 +961,8 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu, } break; case SMU_PCIE: - gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & - PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) - >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; - lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & - PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) - >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; + gen_speed = smu_v11_0_get_current_pcie_link_speed(smu); + lane_width = smu_v11_0_get_current_pcie_link_width(smu); for (i = 0; i < NUM_LINK_LEVELS; i++) size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i, (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," : @@ -1166,27 +1169,23 @@ static int sienna_cichlid_get_fan_speed_rpm(struct smu_context *smu, if (!speed) return -EINVAL; - return sienna_cichlid_get_smu_metrics_data(smu, - METRICS_CURR_FANSPEED, - speed); + switch (smu_v11_0_get_fan_control_mode(smu)) { + case AMD_FAN_CTRL_AUTO: + return sienna_cichlid_get_smu_metrics_data(smu, + METRICS_CURR_FANSPEED, + speed); + default: + return smu_v11_0_get_fan_speed_rpm(smu, speed); + } } -static int sienna_cichlid_get_fan_speed_percent(struct smu_context *smu, - uint32_t *speed) +static int sienna_cichlid_get_fan_parameters(struct smu_context *smu) { - int ret = 0; - uint32_t percent = 0; - uint32_t current_rpm; PPTable_t *pptable = smu->smu_table.driver_pptable; - ret = sienna_cichlid_get_fan_speed_rpm(smu, ¤t_rpm); - if (ret) - return ret; - - percent = current_rpm * 100 / pptable->FanMaximumRpm; - *speed = percent > 100 ? 100 : percent; + smu->fan_max_rpm = pptable->FanMaximumRpm; - return ret; + return 0; } static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *buf) @@ -2656,6 +2655,76 @@ static void sienna_cichlid_i2c_control_fini(struct smu_context *smu, struct i2c_ i2c_del_adapter(control); } +static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct gpu_metrics_v1_0 *gpu_metrics = + (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + SmuMetrics_t metrics; + int ret = 0; + + ret = smu_cmn_get_metrics_table(smu, + &metrics, + true); + if (ret) + return ret; + + smu_v11_0_init_gpu_metrics_v1_0(gpu_metrics); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureMem; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + gpu_metrics->average_mm_activity = metrics.VcnActivityPercentage; + + gpu_metrics->average_socket_power = metrics.AverageSocketPower; + gpu_metrics->energy_accumulator = metrics.EnergyAccumulator; + + if (metrics.AverageGfxActivity <= SMU_11_0_7_GFX_BUSY_THRESHOLD) + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPostDs; + else + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPreDs; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequencyPostDs; + gpu_metrics->average_vclk0_frequency = metrics.AverageVclk0Frequency; + gpu_metrics->average_dclk0_frequency = metrics.AverageDclk0Frequency; + gpu_metrics->average_vclk1_frequency = metrics.AverageVclk1Frequency; + gpu_metrics->average_dclk1_frequency = metrics.AverageDclk1Frequency; + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK_0]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK_0]; + gpu_metrics->current_vclk1 = metrics.CurrClock[PPCLK_VCLK_1]; + gpu_metrics->current_dclk1 = metrics.CurrClock[PPCLK_DCLK_1]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; + + gpu_metrics->pcie_link_width = + smu_v11_0_get_current_pcie_link_width(smu); + gpu_metrics->pcie_link_speed = + smu_v11_0_get_current_pcie_link_speed(smu); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); +} + +static int sienna_cichlid_enable_mgpu_fan_boost(struct smu_context *smu) +{ + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetMGpuFanBoostLimitRpm, + 0, + NULL); +} static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .get_allowed_feature_mask = sienna_cichlid_get_allowed_feature_mask, @@ -2671,7 +2740,6 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .display_config_changed = sienna_cichlid_display_config_changed, .notify_smc_display_config = sienna_cichlid_notify_smc_display_config, .is_dpm_running = sienna_cichlid_is_dpm_running, - .get_fan_speed_percent = sienna_cichlid_get_fan_speed_percent, .get_fan_speed_rpm = sienna_cichlid_get_fan_speed_rpm, .get_power_profile_mode = sienna_cichlid_get_power_profile_mode, .set_power_profile_mode = sienna_cichlid_set_power_profile_mode, @@ -2715,7 +2783,6 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, .get_fan_control_mode = smu_v11_0_get_fan_control_mode, .set_fan_control_mode = smu_v11_0_set_fan_control_mode, - .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent, .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm, .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, .gfx_off_control = smu_v11_0_gfx_off_control, @@ -2734,6 +2801,11 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .run_btc = sienna_cichlid_run_btc, .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, + .get_gpu_metrics = sienna_cichlid_get_gpu_metrics, + .enable_mgpu_fan_boost = sienna_cichlid_enable_mgpu_fan_boost, + .gfx_ulv_control = smu_v11_0_gfx_ulv_control, + .deep_sleep_control = smu_v11_0_deep_sleep_control, + .get_fan_parameters = sienna_cichlid_get_fan_parameters, }; void sienna_cichlid_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.h index 8078886e4cbc..57e120c440ea 100644 --- a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.h @@ -31,7 +31,4 @@ typedef enum { extern void sienna_cichlid_set_ppt_funcs(struct smu_context *smu); -#define smnPCIE_LC_SPEED_CNTL 0x11140290 -#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 - #endif diff --git a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 7b950a582a28..f5aeb0b5cf97 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -67,6 +67,19 @@ MODULE_FIRMWARE("amdgpu/navy_flounder_smc.bin"); #define SMU11_MODE1_RESET_WAIT_TIME_IN_MS 500 //500ms +#define LINK_WIDTH_MAX 6 +#define LINK_SPEED_MAX 3 + +#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 +#define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK 0x00000070L +#define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT 0x4 +#define smnPCIE_LC_SPEED_CNTL 0x11140290 +#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xC000 +#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0xE + +static int link_width[] = {0, 1, 2, 4, 8, 12, 16}; +static int link_speed[] = {25, 50, 80, 160}; + int smu_v11_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -404,10 +417,12 @@ int smu_v11_0_fini_smc_tables(struct smu_context *smu) struct smu_table_context *smu_table = &smu->smu_table; struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + kfree(smu_table->gpu_metrics_table); kfree(smu_table->boot_overdrive_table); kfree(smu_table->overdrive_table); kfree(smu_table->max_sustainable_clocks); kfree(smu_table->driver_pptable); + smu_table->gpu_metrics_table = NULL; smu_table->boot_overdrive_table = NULL; smu_table->overdrive_table = NULL; smu_table->max_sustainable_clocks = NULL; @@ -1085,35 +1100,6 @@ smu_v11_0_set_fan_static_mode(struct smu_context *smu, uint32_t mode) } int -smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t duty100, duty; - uint64_t tmp64; - - if (speed > 100) - speed = 100; - - if (smu_v11_0_auto_fan_control(smu, 0)) - return -EINVAL; - - duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1), - CG_FDO_CTRL1, FMAX_DUTY100); - if (!duty100) - return -EINVAL; - - tmp64 = (uint64_t)speed * duty100; - do_div(tmp64, 100); - duty = (uint32_t)tmp64; - - WREG32_SOC15(THM, 0, mmCG_FDO_CTRL0, - REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL0), - CG_FDO_CTRL0, FDO_STATIC_DUTY, duty)); - - return smu_v11_0_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC); -} - -int smu_v11_0_set_fan_control_mode(struct smu_context *smu, uint32_t mode) { @@ -1121,7 +1107,7 @@ smu_v11_0_set_fan_control_mode(struct smu_context *smu, switch (mode) { case AMD_FAN_CTRL_NONE: - ret = smu_v11_0_set_fan_speed_percent(smu, 100); + ret = smu_v11_0_set_fan_speed_rpm(smu, smu->fan_max_rpm); break; case AMD_FAN_CTRL_MANUAL: ret = smu_v11_0_auto_fan_control(smu, 0); @@ -1167,6 +1153,27 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu, return ret; } +int smu_v11_0_get_fan_speed_rpm(struct smu_context *smu, + uint32_t *speed) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t tach_period, crystal_clock_freq; + uint64_t tmp64; + + tach_period = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL), + CG_TACH_CTRL, TARGET_PERIOD); + if (!tach_period) + return -EINVAL; + + crystal_clock_freq = amdgpu_asic_get_xclk(adev); + + tmp64 = (uint64_t)crystal_clock_freq * 60 * 10000; + do_div(tmp64, (tach_period * 8)); + *speed = (uint32_t)tmp64; + + return 0; +} + int smu_v11_0_set_xgmi_pstate(struct smu_context *smu, uint32_t pstate) { @@ -1312,6 +1319,11 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, smu_v11_0_ack_ac_dc_interrupt(&adev->smu); break; case 0x7: + /* + * Increment the throttle interrupt counter + */ + atomic64_inc(&smu->throttle_int_counter); + if (!atomic_read(&adev->throttling_logging_enabled)) return 0; @@ -1913,3 +1925,99 @@ int smu_v11_0_get_dpm_level_range(struct smu_context *smu, return ret; } + +int smu_v11_0_get_current_pcie_link_width_level(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + return (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & + PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) + >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; +} + +int smu_v11_0_get_current_pcie_link_width(struct smu_context *smu) +{ + uint32_t width_level; + + width_level = smu_v11_0_get_current_pcie_link_width_level(smu); + if (width_level > LINK_WIDTH_MAX) + width_level = 0; + + return link_width[width_level]; +} + +int smu_v11_0_get_current_pcie_link_speed_level(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + return (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & + PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) + >> PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; +} + +int smu_v11_0_get_current_pcie_link_speed(struct smu_context *smu) +{ + uint32_t speed_level; + + speed_level = smu_v11_0_get_current_pcie_link_speed_level(smu); + if (speed_level > LINK_SPEED_MAX) + speed_level = 0; + + return link_speed[speed_level]; +} + +void smu_v11_0_init_gpu_metrics_v1_0(struct gpu_metrics_v1_0 *gpu_metrics) +{ + memset(gpu_metrics, 0xFF, sizeof(struct gpu_metrics_v1_0)); + + gpu_metrics->common_header.structure_size = + sizeof(struct gpu_metrics_v1_0); + gpu_metrics->common_header.format_revision = 1; + gpu_metrics->common_header.content_revision = 0; + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); +} + +int smu_v11_0_gfx_ulv_control(struct smu_context *smu, + bool enablement) +{ + int ret = 0; + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_GFX_ULV_BIT)) + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_GFX_ULV_BIT, enablement); + + return ret; +} + +int smu_v11_0_deep_sleep_control(struct smu_context *smu, + bool enablement) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_GFXCLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_GFXCLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s GFXCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_SOCCLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_SOCCLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s SOCCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_LCLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_LCLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s LCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + return ret; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu12/Makefile new file mode 100644 index 000000000000..67e53f7da3ce --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/Makefile @@ -0,0 +1,31 @@ +# +# Copyright 2020 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. +# +# +# Makefile for the 'smu manager' sub-component of powerplay. +# It provides the smu management services for the driver. + +SMU12_MGR = renoir_ppt.o \ + smu_v12_0.o + +AMD_SWSMU_SMU12MGR = $(addprefix $(AMD_SWSMU_PATH)/smu12/,$(SMU12_MGR)) + +AMD_POWERPLAY_FILES += $(AMD_SWSMU_SMU12MGR) diff --git a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index dbb676c482fd..3b9ac72c7571 100644 --- a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -128,30 +128,6 @@ static struct cmn2asic_mapping renoir_workload_map[PP_SMC_POWER_PROFILE_COUNT] = WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), }; -static int renoir_get_metrics_table(struct smu_context *smu, - SmuMetrics_t *metrics_table) -{ - struct smu_table_context *smu_table= &smu->smu_table; - int ret = 0; - - mutex_lock(&smu->metrics_lock); - if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) { - ret = smu_cmn_update_table(smu, SMU_TABLE_SMU_METRICS, 0, - (void *)smu_table->metrics_table, false); - if (ret) { - dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n"); - mutex_unlock(&smu->metrics_lock); - return ret; - } - smu_table->metrics_time = jiffies; - } - - memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t)); - mutex_unlock(&smu->metrics_lock); - - return ret; -} - static int renoir_init_smc_tables(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; @@ -166,18 +142,32 @@ static int renoir_init_smc_tables(struct smu_context *smu) smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); if (!smu_table->clocks_table) - return -ENOMEM; + goto err0_out; smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); if (!smu_table->metrics_table) - return -ENOMEM; + goto err1_out; smu_table->metrics_time = 0; smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); if (!smu_table->watermarks_table) - return -ENOMEM; + goto err2_out; + + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_0); + smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); + if (!smu_table->gpu_metrics_table) + goto err3_out; return 0; + +err3_out: + kfree(smu_table->watermarks_table); +err2_out: + kfree(smu_table->metrics_table); +err1_out: + kfree(smu_table->clocks_table); +err0_out: + return -ENOMEM; } /** @@ -361,7 +351,7 @@ static int renoir_print_clk_levels(struct smu_context *smu, memset(&metrics, 0, sizeof(metrics)); - ret = renoir_get_metrics_table(smu, &metrics); + ret = smu_cmn_get_metrics_table(smu, &metrics, false); if (ret) return ret; @@ -507,7 +497,7 @@ static int renoir_get_current_clk_freq_by_table(struct smu_context *smu, int ret = 0, clk_id = 0; SmuMetrics_t metrics; - ret = renoir_get_metrics_table(smu, &metrics); + ret = smu_cmn_get_metrics_table(smu, &metrics, false); if (ret) return ret; @@ -590,7 +580,7 @@ static int renoir_get_gpu_temperature(struct smu_context *smu, uint32_t *value) if (!value) return -EINVAL; - ret = renoir_get_metrics_table(smu, &metrics); + ret = smu_cmn_get_metrics_table(smu, &metrics, false); if (ret) return ret; @@ -610,7 +600,7 @@ static int renoir_get_current_activity_percent(struct smu_context *smu, if (!value) return -EINVAL; - ret = renoir_get_metrics_table(smu, &metrics); + ret = smu_cmn_get_metrics_table(smu, &metrics, false); if (ret) return ret; @@ -626,6 +616,44 @@ static int renoir_get_current_activity_percent(struct smu_context *smu, return 0; } +static int renoir_get_vddc(struct smu_context *smu, uint32_t *value, + unsigned int index) +{ + int ret = 0; + SmuMetrics_t metrics; + + if (index >= 2) + return -EINVAL; + + if (!value) + return -EINVAL; + + ret = smu_cmn_get_metrics_table(smu, &metrics, false); + if (ret) + return ret; + + *value = metrics.Voltage[index]; + + return 0; +} + +static int renoir_get_power(struct smu_context *smu, uint32_t *value) +{ + int ret = 0; + SmuMetrics_t metrics; + + if (!value) + return -EINVAL; + + ret = smu_cmn_get_metrics_table(smu, &metrics, false); + if (ret) + return ret; + + *value = metrics.CurrentSocketPower << 8; + + return 0; +} + /** * This interface get dpm clock table for dc */ @@ -962,6 +990,18 @@ static int renoir_read_sensor(struct smu_context *smu, *(uint32_t *)data *= 100; *size = 4; break; + case AMDGPU_PP_SENSOR_VDDGFX: + ret = renoir_get_vddc(smu, (uint32_t *)data, 0); + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDNB: + ret = renoir_get_vddc(smu, (uint32_t *)data, 1); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_POWER: + ret = renoir_get_power(smu, (uint32_t *)data); + *size = 4; + break; default: ret = -EOPNOTSUPP; break; @@ -987,6 +1027,65 @@ static bool renoir_is_dpm_running(struct smu_context *smu) } +static ssize_t renoir_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct gpu_metrics_v2_0 *gpu_metrics = + (struct gpu_metrics_v2_0 *)smu_table->gpu_metrics_table; + SmuMetrics_t metrics; + int ret = 0; + + ret = smu_cmn_get_metrics_table(smu, &metrics, true); + if (ret) + return ret; + + smu_v12_0_init_gpu_metrics_v2_0(gpu_metrics); + + gpu_metrics->temperature_gfx = metrics.GfxTemperature; + gpu_metrics->temperature_soc = metrics.SocTemperature; + memcpy(&gpu_metrics->temperature_core[0], + &metrics.CoreTemperature[0], + sizeof(uint16_t) * 8); + gpu_metrics->temperature_l3[0] = metrics.L3Temperature[0]; + gpu_metrics->temperature_l3[1] = metrics.L3Temperature[1]; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_mm_activity = metrics.AverageUvdActivity; + + gpu_metrics->average_socket_power = metrics.CurrentSocketPower; + gpu_metrics->average_cpu_power = metrics.Power[0]; + gpu_metrics->average_soc_power = metrics.Power[1]; + memcpy(&gpu_metrics->average_core_power[0], + &metrics.CorePower[0], + sizeof(uint16_t) * 8); + + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_fclk_frequency = metrics.AverageFclkFrequency; + gpu_metrics->average_vclk_frequency = metrics.AverageVclkFrequency; + + gpu_metrics->current_gfxclk = metrics.ClockFrequency[CLOCK_GFXCLK]; + gpu_metrics->current_socclk = metrics.ClockFrequency[CLOCK_SOCCLK]; + gpu_metrics->current_uclk = metrics.ClockFrequency[CLOCK_UMCCLK]; + gpu_metrics->current_fclk = metrics.ClockFrequency[CLOCK_FCLK]; + gpu_metrics->current_vclk = metrics.ClockFrequency[CLOCK_VCLK]; + gpu_metrics->current_dclk = metrics.ClockFrequency[CLOCK_DCLK]; + memcpy(&gpu_metrics->current_coreclk[0], + &metrics.CoreFrequency[0], + sizeof(uint16_t) * 8); + gpu_metrics->current_l3clk[0] = metrics.L3Frequency[0]; + gpu_metrics->current_l3clk[1] = metrics.L3Frequency[1]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + gpu_metrics->fan_pwm = metrics.FanPwm; + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v2_0); +} + static const struct pptable_funcs renoir_ppt_funcs = { .set_power_state = NULL, .print_clk_levels = renoir_print_clk_levels, @@ -1021,6 +1120,7 @@ static const struct pptable_funcs renoir_ppt_funcs = { .is_dpm_running = renoir_is_dpm_running, .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, + .get_gpu_metrics = renoir_get_gpu_metrics, }; void renoir_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/powerplay/renoir_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.h index 8c3f004cdf8d..8c3f004cdf8d 100644 --- a/drivers/gpu/drm/amd/powerplay/renoir_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.h diff --git a/drivers/gpu/drm/amd/powerplay/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index 31456437bb18..660f403d5770 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -274,3 +274,15 @@ int smu_v12_0_set_driver_table_location(struct smu_context *smu) return ret; } + +void smu_v12_0_init_gpu_metrics_v2_0(struct gpu_metrics_v2_0 *gpu_metrics) +{ + memset(gpu_metrics, 0xFF, sizeof(struct gpu_metrics_v2_0)); + + gpu_metrics->common_header.structure_size = + sizeof(struct gpu_metrics_v2_0); + gpu_metrics->common_header.format_revision = 2; + gpu_metrics->common_header.content_revision = 0; + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); +} diff --git a/drivers/gpu/drm/amd/powerplay/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 5c23c44c33bd..a58ea08cd115 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -604,7 +604,7 @@ int smu_cmn_update_table(struct smu_context *smu, memcpy(table_data, table->cpu_addr, table_size); } - return ret; + return 0; } int smu_cmn_write_watermarks_table(struct smu_context *smu) @@ -631,3 +631,48 @@ int smu_cmn_write_pptable(struct smu_context *smu) pptable, true); } + +int smu_cmn_get_metrics_table_locked(struct smu_context *smu, + void *metrics_table, + bool bypass_cache) +{ + struct smu_table_context *smu_table= &smu->smu_table; + uint32_t table_size = + smu_table->tables[SMU_TABLE_SMU_METRICS].size; + int ret = 0; + + if (bypass_cache || + !smu_table->metrics_time || + time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) { + ret = smu_cmn_update_table(smu, + SMU_TABLE_SMU_METRICS, + 0, + smu_table->metrics_table, + false); + if (ret) { + dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n"); + return ret; + } + smu_table->metrics_time = jiffies; + } + + if (metrics_table) + memcpy(metrics_table, smu_table->metrics_table, table_size); + + return 0; +} + +int smu_cmn_get_metrics_table(struct smu_context *smu, + void *metrics_table, + bool bypass_cache) +{ + int ret = 0; + + mutex_lock(&smu->metrics_lock); + ret = smu_cmn_get_metrics_table_locked(smu, + metrics_table, + bypass_cache); + mutex_unlock(&smu->metrics_lock); + + return ret; +} diff --git a/drivers/gpu/drm/amd/powerplay/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 98face8c5fd6..6d00ad740c27 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -79,5 +79,13 @@ int smu_cmn_write_watermarks_table(struct smu_context *smu); int smu_cmn_write_pptable(struct smu_context *smu); +int smu_cmn_get_metrics_table_locked(struct smu_context *smu, + void *metrics_table, + bool bypass_cache); + +int smu_cmn_get_metrics_table(struct smu_context *smu, + void *metrics_table, + bool bypass_cache); + #endif #endif diff --git a/drivers/gpu/drm/amd/powerplay/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h index 264073d4e263..38c10177ed21 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_internal.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h @@ -92,6 +92,9 @@ #define smu_get_asic_power_limits(smu) smu_ppt_funcs(get_power_limit, 0, smu) #define smu_get_pp_feature_mask(smu, buf) smu_ppt_funcs(get_pp_feature_mask, 0, smu, buf) #define smu_set_pp_feature_mask(smu, new_mask) smu_ppt_funcs(set_pp_feature_mask, 0, smu, new_mask) +#define smu_gfx_ulv_control(smu, enablement) smu_ppt_funcs(gfx_ulv_control, 0, smu, enablement) +#define smu_deep_sleep_control(smu, enablement) smu_ppt_funcs(deep_sleep_control, 0, smu, enablement) +#define smu_get_fan_parameters(smu) smu_ppt_funcs(get_fan_parameters, 0, smu) #endif #endif diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index ab45ac445045..351a85088d0e 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -346,7 +346,7 @@ static bool malidp_check_pages_threshold(struct malidp_plane_state *ms, if (cma_obj->sgt) sgt = cma_obj->sgt; else - sgt = obj->dev->driver->gem_prime_get_sg_table(obj); + sgt = obj->funcs->get_sg_table(obj); if (!sgt) return false; diff --git a/drivers/gpu/drm/ast/ast_cursor.c b/drivers/gpu/drm/ast/ast_cursor.c index acf0d23514e8..e0f4613918ad 100644 --- a/drivers/gpu/drm/ast/ast_cursor.c +++ b/drivers/gpu/drm/ast/ast_cursor.c @@ -47,7 +47,7 @@ static void ast_cursor_fini(struct ast_private *ast) static void ast_cursor_release(struct drm_device *dev, void *ptr) { - struct ast_private *ast = dev->dev_private; + struct ast_private *ast = to_ast_private(dev); ast_cursor_fini(ast); } @@ -57,7 +57,7 @@ static void ast_cursor_release(struct drm_device *dev, void *ptr) */ int ast_cursor_init(struct ast_private *ast) { - struct drm_device *dev = ast->dev; + struct drm_device *dev = &ast->base; size_t size, i; struct drm_gem_vram_object *gbo; void __iomem *vaddr; @@ -168,7 +168,7 @@ static void update_cursor_image(u8 __iomem *dst, const u8 *src, int width, int h int ast_cursor_blit(struct ast_private *ast, struct drm_framebuffer *fb) { - struct drm_device *dev = ast->dev; + struct drm_device *dev = &ast->base; struct drm_gem_vram_object *gbo; int ret; void *src; @@ -217,7 +217,7 @@ static void ast_cursor_set_base(struct ast_private *ast, u64 address) void ast_cursor_page_flip(struct ast_private *ast) { - struct drm_device *dev = ast->dev; + struct drm_device *dev = &ast->base; struct drm_gem_vram_object *gbo; s64 off; @@ -253,7 +253,8 @@ void ast_cursor_show(struct ast_private *ast, int x, int y, unsigned int offset_x, unsigned int offset_y) { u8 x_offset, y_offset; - u8 __iomem *dst, __iomem *sig; + u8 __iomem *dst; + u8 __iomem *sig; u8 jreg; dst = ast->cursor.vaddr[ast->cursor.next_index]; diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index 4b85a504825a..88121c0e0d05 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -8,11 +8,24 @@ MODULE_FIRMWARE("ast_dp501_fw.bin"); +static void ast_release_firmware(void *data) +{ + struct ast_private *ast = data; + + release_firmware(ast->dp501_fw); + ast->dp501_fw = NULL; +} + static int ast_load_dp501_microcode(struct drm_device *dev) { struct ast_private *ast = to_ast_private(dev); + int ret; + + ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev); + if (ret) + return ret; - return request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev); + return devm_add_action_or_reset(dev->dev, ast_release_firmware, ast); } static void send_ack(struct ast_private *ast) @@ -435,11 +448,3 @@ void ast_init_3rdtx(struct drm_device *dev) } } } - -void ast_release_firmware(struct drm_device *dev) -{ - struct ast_private *ast = to_ast_private(dev); - - release_firmware(ast->dp501_fw); - ast->dp501_fw = NULL; -} diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 0b58f7aee6b0..f0b4af1c390a 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -43,9 +43,33 @@ int ast_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, ast_modeset, int, 0400); -#define PCI_VENDOR_ASPEED 0x1a03 +/* + * DRM driver + */ + +DEFINE_DRM_GEM_FOPS(ast_fops); + +static struct drm_driver ast_driver = { + .driver_features = DRIVER_ATOMIC | + DRIVER_GEM | + DRIVER_MODESET, + + .fops = &ast_fops, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, + + DRM_GEM_VRAM_DRIVER +}; + +/* + * PCI driver + */ -static struct drm_driver driver; +#define PCI_VENDOR_ASPEED 0x1a03 #define AST_VGA_DEVICE(id, info) { \ .class = PCI_BASE_CLASS_DISPLAY << 16, \ @@ -56,13 +80,13 @@ static struct drm_driver driver; .subdevice = PCI_ANY_ID, \ .driver_data = (unsigned long) info } -static const struct pci_device_id pciidlist[] = { +static const struct pci_device_id ast_pciidlist[] = { AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL), AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL), {0, 0, 0}, }; -MODULE_DEVICE_TABLE(pci, pciidlist); +MODULE_DEVICE_TABLE(pci, ast_pciidlist); static void ast_kick_out_firmware_fb(struct pci_dev *pdev) { @@ -85,6 +109,7 @@ static void ast_kick_out_firmware_fb(struct pci_dev *pdev) static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct ast_private *ast; struct drm_device *dev; int ret; @@ -94,41 +119,25 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - dev = drm_dev_alloc(&driver, &pdev->dev); - if (IS_ERR(dev)) - return PTR_ERR(dev); - - dev->pdev = pdev; - pci_set_drvdata(pdev, dev); - - ret = ast_driver_load(dev, ent->driver_data); - if (ret) - goto err_drm_dev_put; + ast = ast_device_create(&ast_driver, pdev, ent->driver_data); + if (IS_ERR(ast)) + return PTR_ERR(ast); + dev = &ast->base; ret = drm_dev_register(dev, ent->driver_data); if (ret) - goto err_ast_driver_unload; + return ret; drm_fbdev_generic_setup(dev, 32); return 0; - -err_ast_driver_unload: - ast_driver_unload(dev); -err_drm_dev_put: - drm_dev_put(dev); - return ret; - } -static void -ast_pci_remove(struct pci_dev *pdev) +static void ast_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); drm_dev_unregister(dev); - ast_driver_unload(dev); - drm_dev_put(dev); } static int ast_drm_freeze(struct drm_device *dev) @@ -217,30 +226,12 @@ static const struct dev_pm_ops ast_pm_ops = { static struct pci_driver ast_pci_driver = { .name = DRIVER_NAME, - .id_table = pciidlist, + .id_table = ast_pciidlist, .probe = ast_pci_probe, .remove = ast_pci_remove, .driver.pm = &ast_pm_ops, }; -DEFINE_DRM_GEM_FOPS(ast_fops); - -static struct drm_driver driver = { - .driver_features = DRIVER_ATOMIC | - DRIVER_GEM | - DRIVER_MODESET, - - .fops = &ast_fops, - .name = DRIVER_NAME, - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, - .patchlevel = DRIVER_PATCHLEVEL, - - DRM_GEM_VRAM_DRIVER -}; - static int __init ast_init(void) { if (vgacon_text_force() && ast_modeset == -1) @@ -261,4 +252,3 @@ module_exit(ast_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL and additional rights"); - diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index e3a264ac7ee2..c1af6b725933 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -98,9 +98,25 @@ enum ast_tx_chip { #define AST_HWC_SIGNATURE_HOTSPOTX 0x14 #define AST_HWC_SIGNATURE_HOTSPOTY 0x18 +struct ast_i2c_chan { + struct i2c_adapter adapter; + struct drm_device *dev; + struct i2c_algo_bit_data bit; +}; + +struct ast_connector { + struct drm_connector base; + struct ast_i2c_chan *i2c; +}; + +static inline struct ast_connector * +to_ast_connector(struct drm_connector *connector) +{ + return container_of(connector, struct ast_connector, base); +} struct ast_private { - struct drm_device *dev; + struct drm_device base; void __iomem *regs; void __iomem *ioregs; @@ -119,9 +135,11 @@ struct ast_private { unsigned int next_index; } cursor; - struct drm_encoder encoder; struct drm_plane primary_plane; struct drm_plane cursor_plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct ast_connector connector; bool support_wide_screen; enum { @@ -138,11 +156,12 @@ struct ast_private { static inline struct ast_private *to_ast_private(struct drm_device *dev) { - return dev->dev_private; + return container_of(dev, struct ast_private, base); } -int ast_driver_load(struct drm_device *dev, unsigned long flags); -void ast_driver_unload(struct drm_device *dev); +struct ast_private *ast_device_create(struct drm_driver *drv, + struct pci_dev *pdev, + unsigned long flags); #define AST_IO_AR_PORT_WRITE (0x40) #define AST_IO_MISC_PORT_WRITE (0x42) @@ -226,19 +245,6 @@ static inline void ast_open_key(struct ast_private *ast) #define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M -struct ast_i2c_chan { - struct i2c_adapter adapter; - struct drm_device *dev; - struct i2c_algo_bit_data bit; -}; - -struct ast_connector { - struct drm_connector base; - struct ast_i2c_chan *i2c; -}; - -#define to_ast_connector(x) container_of(x, struct ast_connector, base) - struct ast_vbios_stdtable { u8 misc; u8 seq[4]; @@ -305,7 +311,6 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata); u8 ast_get_dp501_max_clk(struct drm_device *dev); void ast_init_3rdtx(struct drm_device *dev); -void ast_release_firmware(struct drm_device *dev); /* ast_cursor.c */ int ast_cursor_init(struct ast_private *ast); diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 6a9fba051d13..77066bca8793 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -30,8 +30,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_gem.h> #include <drm/drm_gem_vram_helper.h> +#include <drm/drm_managed.h> #include "ast_drv.h" @@ -230,11 +232,11 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) ast->tx_chip_type = AST_TX_SIL164; break; case 0x08: - ast->dp501_fw_addr = kzalloc(32*1024, GFP_KERNEL); + ast->dp501_fw_addr = drmm_kzalloc(dev, 32*1024, GFP_KERNEL); if (ast->dp501_fw_addr) { /* backup firmware */ if (ast_backup_fw(dev, ast->dp501_fw_addr, 32*1024)) { - kfree(ast->dp501_fw_addr); + drmm_kfree(dev, ast->dp501_fw_addr); ast->dp501_fw_addr = NULL; } } @@ -378,24 +380,38 @@ static int ast_get_dram_info(struct drm_device *dev) return 0; } -int ast_driver_load(struct drm_device *dev, unsigned long flags) +/* + * Run this function as part of the HW device cleanup; not + * when the DRM device gets released. + */ +static void ast_device_release(void *data) { + struct ast_private *ast = data; + + /* enable standard VGA decode */ + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04); +} + +struct ast_private *ast_device_create(struct drm_driver *drv, + struct pci_dev *pdev, + unsigned long flags) +{ + struct drm_device *dev; struct ast_private *ast; bool need_post; int ret = 0; - ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL); - if (!ast) - return -ENOMEM; + ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_private, base); + if (IS_ERR(ast)) + return ast; + dev = &ast->base; - dev->dev_private = ast; - ast->dev = dev; + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); ast->regs = pci_iomap(dev->pdev, 1, 0); - if (!ast->regs) { - ret = -EIO; - goto out_free; - } + if (!ast->regs) + return ERR_PTR(-EIO); /* * If we don't have IO space at all, use MMIO now and @@ -410,17 +426,16 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) /* "map" IO regs if the above hasn't done so already */ if (!ast->ioregs) { ast->ioregs = pci_iomap(dev->pdev, 2, 0); - if (!ast->ioregs) { - ret = -EIO; - goto out_free; - } + if (!ast->ioregs) + return ERR_PTR(-EIO); } ast_detect_chip(dev, &need_post); ret = ast_get_dram_info(dev); if (ret) - goto out_free; + return ERR_PTR(ret); + drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n", ast->mclk, ast->dram_type, ast->dram_bus_width); @@ -429,28 +444,15 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) ret = ast_mm_init(ast); if (ret) - goto out_free; + return ERR_PTR(ret); ret = ast_mode_config_init(ast); if (ret) - goto out_free; + return ERR_PTR(ret); - return 0; -out_free: - kfree(ast); - dev->dev_private = NULL; - return ret; -} - -void ast_driver_unload(struct drm_device *dev) -{ - struct ast_private *ast = to_ast_private(dev); - - /* enable standard VGA decode */ - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04); - - ast_release_firmware(dev); - kfree(ast->dp501_fw_addr); + ret = devm_add_action_or_reset(dev->dev, ast_device_release, ast); + if (ret) + return ERR_PTR(ret); - kfree(ast); + return ast; } diff --git a/drivers/gpu/drm/ast/ast_mm.c b/drivers/gpu/drm/ast/ast_mm.c index 9186ec3ebbe0..8392ebde504b 100644 --- a/drivers/gpu/drm/ast/ast_mm.c +++ b/drivers/gpu/drm/ast/ast_mm.c @@ -85,9 +85,9 @@ static void ast_mm_release(struct drm_device *dev, void *ptr) int ast_mm_init(struct ast_private *ast) { + struct drm_device *dev = &ast->base; u32 vram_size; int ret; - struct drm_device *dev = ast->dev; vram_size = ast_get_vram_size(ast); diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 154cd877d9d1..62fe682a7de6 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -663,7 +663,7 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; - struct ast_private *ast = plane->dev->dev_private; + struct ast_private *ast = to_ast_private(plane->dev); unsigned int offset_x, offset_y; offset_x = AST_MAX_HWC_WIDTH - fb->width; @@ -831,12 +831,6 @@ static void ast_crtc_reset(struct drm_crtc *crtc) __drm_atomic_helper_crtc_reset(crtc, &ast_state->base); } -static void ast_crtc_destroy(struct drm_crtc *crtc) -{ - drm_crtc_cleanup(crtc); - kfree(crtc); -} - static struct drm_crtc_state * ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc) { @@ -872,7 +866,7 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc, static const struct drm_crtc_funcs ast_crtc_funcs = { .reset = ast_crtc_reset, .gamma_set = drm_atomic_helper_legacy_gamma_set, - .destroy = ast_crtc_destroy, + .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .atomic_duplicate_state = ast_crtc_atomic_duplicate_state, @@ -882,27 +876,19 @@ static const struct drm_crtc_funcs ast_crtc_funcs = { static int ast_crtc_init(struct drm_device *dev) { struct ast_private *ast = to_ast_private(dev); - struct drm_crtc *crtc; + struct drm_crtc *crtc = &ast->crtc; int ret; - crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); - if (!crtc) - return -ENOMEM; - ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane, &ast->cursor_plane, &ast_crtc_funcs, NULL); if (ret) - goto err_kfree; + return ret; drm_mode_crtc_set_gamma_size(crtc, 256); drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs); return 0; - -err_kfree: - kfree(crtc); - return ret; } /* @@ -1021,7 +1007,6 @@ static void ast_connector_destroy(struct drm_connector *connector) struct ast_connector *ast_connector = to_ast_connector(connector); ast_i2c_destroy(ast_connector->i2c); drm_connector_cleanup(connector); - kfree(connector); } static const struct drm_connector_helper_funcs ast_connector_helper_funcs = { @@ -1039,15 +1024,11 @@ static const struct drm_connector_funcs ast_connector_funcs = { static int ast_connector_init(struct drm_device *dev) { - struct ast_connector *ast_connector; - struct drm_connector *connector; - struct drm_encoder *encoder; - - ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL); - if (!ast_connector) - return -ENOMEM; + struct ast_private *ast = to_ast_private(dev); + struct ast_connector *ast_connector = &ast->connector; + struct drm_connector *connector = &ast_connector->base; + struct drm_encoder *encoder = &ast->encoder; - connector = &ast_connector->base; ast_connector->i2c = ast_i2c_create(dev); if (!ast_connector->i2c) drm_err(dev, "failed to add ddc bus for connector\n"); @@ -1064,7 +1045,6 @@ static int ast_connector_init(struct drm_device *dev) connector->polled = DRM_CONNECTOR_POLL_CONNECT; - encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head); drm_connector_attach_encoder(connector, encoder); return 0; @@ -1083,7 +1063,7 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = { int ast_mode_config_init(struct ast_private *ast) { - struct drm_device *dev = ast->dev; + struct drm_device *dev = &ast->base; int ret; ret = ast_cursor_init(ast); @@ -1099,7 +1079,7 @@ int ast_mode_config_init(struct ast_private *ast) dev->mode_config.min_height = 0; dev->mode_config.preferred_depth = 24; dev->mode_config.prefer_shadow = 1; - dev->mode_config.fb_base = pci_resource_start(ast->dev->pdev, 0); + dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); if (ast->chip == AST2100 || ast->chip == AST2200 || diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index c043fe717553..8902c2f84bf9 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -365,12 +365,12 @@ static void ast_init_dram_reg(struct drm_device *dev) void ast_post_gpu(struct drm_device *dev) { - u32 reg; struct ast_private *ast = to_ast_private(dev); + u32 reg; - pci_read_config_dword(ast->dev->pdev, 0x04, ®); + pci_read_config_dword(dev->pdev, 0x04, ®); reg |= 0x3; - pci_write_config_dword(ast->dev->pdev, 0x04, reg); + pci_write_config_dword(dev->pdev, 0x04, reg); ast_enable_vga(dev); ast_open_key(ast); diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 43271c21d3fc..3e11af4e9f63 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -48,6 +48,19 @@ config DRM_DISPLAY_CONNECTOR on ARM-based platforms. Saying Y here when this driver is not needed will not cause any issue. +config DRM_LONTIUM_LT9611 + tristate "Lontium LT9611 DSI/HDMI bridge" + select SND_SOC_HDMI_CODEC if SND_SOC + depends on OF + select DRM_PANEL_BRIDGE + select DRM_KMS_HELPER + select REGMAP_I2C + help + Driver for Lontium LT9611 DSI to HDMI bridge + chip driver that converts dual DSI and I2S to + HDMI signals + Please say Y if you have such hardware. + config DRM_LVDS_CODEC tristate "Transparent LVDS encoders and decoders support" depends on OF @@ -153,6 +166,14 @@ config DRM_THINE_THC63LVD1024 help Thine THC63LVD1024 LVDS/parallel converter driver. +config DRM_TOSHIBA_TC358762 + tristate "TC358762 DSI/DPI bridge" + depends on OF + select DRM_MIPI_DSI + select DRM_PANEL_BRIDGE + help + Toshiba TC358762 DSI/DPI bridge driver. + config DRM_TOSHIBA_TC358764 tristate "TC358764 DSI/LVDS bridge" depends on OF @@ -181,6 +202,16 @@ config DRM_TOSHIBA_TC358768 help Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver. +config DRM_TOSHIBA_TC358775 + tristate "Toshiba TC358775 DSI/LVDS bridge" + depends on OF + select DRM_KMS_HELPER + select REGMAP_I2C + select DRM_PANEL + select DRM_MIPI_DSI + help + Toshiba TC358775 DSI/LVDS bridge chip driver. + config DRM_TI_TFP410 tristate "TI TFP410 DVI/HDMI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index d63d4b7e4347..c589a6a7cbe1 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o +obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o @@ -12,9 +13,11 @@ obj-$(CONFIG_DRM_SII902X) += sii902x.o obj-$(CONFIG_DRM_SII9234) += sii9234.o obj-$(CONFIG_DRM_SIMPLE_BRIDGE) += simple-bridge.o obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o +obj-$(CONFIG_DRM_TOSHIBA_TC358762) += tc358762.o obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o +obj-$(CONFIG_DRM_TOSHIBA_TC358775) += tc358775.o obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index f082b4ed4878..d9164fab044d 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -507,10 +507,6 @@ static const struct drm_connector_helper_funcs anx6345_connector_helper_funcs = static void anx6345_connector_destroy(struct drm_connector *connector) { - struct anx6345 *anx6345 = connector_to_anx6345(connector); - - if (anx6345->panel) - drm_panel_detach(anx6345->panel); drm_connector_cleanup(connector); } @@ -575,14 +571,6 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge, return err; } - if (anx6345->panel) { - err = drm_panel_attach(anx6345->panel, &anx6345->connector); - if (err) { - DRM_ERROR("Failed to attach panel: %d\n", err); - return err; - } - } - return 0; } diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 76736fb8ed94..aa1bb86293fd 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1265,14 +1265,6 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge, } } - if (dp->plat_data->panel) { - ret = drm_panel_attach(dp->plat_data->panel, &dp->connector); - if (ret) { - DRM_ERROR("Failed to attach panel\n"); - return ret; - } - } - return 0; } @@ -1803,7 +1795,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp) if (dp->plat_data->panel) { if (drm_panel_unprepare(dp->plat_data->panel)) DRM_ERROR("failed to turnoff the panel\n"); - drm_panel_detach(dp->plat_data->panel); } drm_dp_aux_unregister(&dp->aux); diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c new file mode 100644 index 000000000000..1009fc4ed4ed --- /dev/null +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -0,0 +1,1230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020. Linaro Limited. + */ + +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#include <sound/hdmi-codec.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_print.h> +#include <drm/drm_probe_helper.h> + +#define EDID_SEG_SIZE 256 +#define EDID_LEN 32 +#define EDID_LOOP 8 +#define KEY_DDC_ACCS_DONE 0x02 +#define DDC_NO_ACK 0x50 + +#define LT9611_4LANES 0 + +struct lt9611 { + struct device *dev; + struct drm_bridge bridge; + struct drm_connector connector; + + struct regmap *regmap; + + struct device_node *dsi0_node; + struct device_node *dsi1_node; + struct mipi_dsi_device *dsi0; + struct mipi_dsi_device *dsi1; + struct platform_device *audio_pdev; + + bool ac_mode; + + struct gpio_desc *reset_gpio; + struct gpio_desc *enable_gpio; + + bool power_on; + bool sleep; + + struct regulator_bulk_data supplies[2]; + + struct i2c_client *client; + + enum drm_connector_status status; + + u8 edid_buf[EDID_SEG_SIZE]; + u32 vic; +}; + +#define LT9611_PAGE_CONTROL 0xff + +static const struct regmap_range_cfg lt9611_ranges[] = { + { + .name = "register_range", + .range_min = 0, + .range_max = 0x85ff, + .selector_reg = LT9611_PAGE_CONTROL, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, + }, +}; + +static const struct regmap_config lt9611_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xffff, + .ranges = lt9611_ranges, + .num_ranges = ARRAY_SIZE(lt9611_ranges), +}; + +struct lt9611_mode { + u16 hdisplay; + u16 vdisplay; + u8 vrefresh; + u8 lanes; + u8 intfs; +}; + +static struct lt9611_mode lt9611_modes[] = { + { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */ + { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */ + { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */ + { 1920, 1080, 24, 3, 1 }, + { 720, 480, 60, 4, 1 }, + { 720, 576, 50, 2, 1 }, + { 640, 480, 60, 2, 1 }, +}; + +static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge) +{ + return container_of(bridge, struct lt9611, bridge); +} + +static struct lt9611 *connector_to_lt9611(struct drm_connector *connector) +{ + return container_of(connector, struct lt9611, connector); +} + +static int lt9611_mipi_input_analog(struct lt9611 *lt9611) +{ + const struct reg_sequence reg_cfg[] = { + { 0x8106, 0x40 }, /* port A rx current */ + { 0x810a, 0xfe }, /* port A ldo voltage set */ + { 0x810b, 0xbf }, /* enable port A lprx */ + { 0x8111, 0x40 }, /* port B rx current */ + { 0x8115, 0xfe }, /* port B ldo voltage set */ + { 0x8116, 0xbf }, /* enable port B lprx */ + + { 0x811c, 0x03 }, /* PortA clk lane no-LP mode */ + { 0x8120, 0x03 }, /* PortB clk lane with-LP mode */ + }; + + return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); +} + +static int lt9611_mipi_input_digital(struct lt9611 *lt9611, + const struct drm_display_mode *mode) +{ + struct reg_sequence reg_cfg[] = { + { 0x8300, LT9611_4LANES }, + { 0x830a, 0x00 }, + { 0x824f, 0x80 }, + { 0x8250, 0x10 }, + { 0x8302, 0x0a }, + { 0x8306, 0x0a }, + }; + + if (mode->hdisplay == 3840) + reg_cfg[1].def = 0x03; + + return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); +} + +static void lt9611_mipi_video_setup(struct lt9611 *lt9611, + const struct drm_display_mode *mode) +{ + u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch; + u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch; + + h_total = mode->htotal; + v_total = mode->vtotal; + + hactive = mode->hdisplay; + hsync_len = mode->hsync_end - mode->hsync_start; + hfront_porch = mode->hsync_start - mode->hdisplay; + hsync_porch = hsync_len + mode->htotal - mode->hsync_end; + + vactive = mode->vdisplay; + vsync_len = mode->vsync_end - mode->vsync_start; + vfront_porch = mode->vsync_start - mode->vdisplay; + vsync_porch = vsync_len + mode->vtotal - mode->vsync_end; + + regmap_write(lt9611->regmap, 0x830d, (u8)(v_total / 256)); + regmap_write(lt9611->regmap, 0x830e, (u8)(v_total % 256)); + + regmap_write(lt9611->regmap, 0x830f, (u8)(vactive / 256)); + regmap_write(lt9611->regmap, 0x8310, (u8)(vactive % 256)); + + regmap_write(lt9611->regmap, 0x8311, (u8)(h_total / 256)); + regmap_write(lt9611->regmap, 0x8312, (u8)(h_total % 256)); + + regmap_write(lt9611->regmap, 0x8313, (u8)(hactive / 256)); + regmap_write(lt9611->regmap, 0x8314, (u8)(hactive % 256)); + + regmap_write(lt9611->regmap, 0x8315, (u8)(vsync_len % 256)); + regmap_write(lt9611->regmap, 0x8316, (u8)(hsync_len % 256)); + + regmap_write(lt9611->regmap, 0x8317, (u8)(vfront_porch % 256)); + + regmap_write(lt9611->regmap, 0x8318, (u8)(vsync_porch % 256)); + + regmap_write(lt9611->regmap, 0x8319, (u8)(hfront_porch % 256)); + + regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256)); + regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256)); +} + +static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode) +{ + const struct reg_sequence reg_cfg[] = { + { 0x830b, 0x01 }, + { 0x830c, 0x10 }, + { 0x8348, 0x00 }, + { 0x8349, 0x81 }, + + /* stage 1 */ + { 0x8321, 0x4a }, + { 0x8324, 0x71 }, + { 0x8325, 0x30 }, + { 0x832a, 0x01 }, + + /* stage 2 */ + { 0x834a, 0x40 }, + { 0x831d, 0x10 }, + + /* MK limit */ + { 0x832d, 0x38 }, + { 0x8331, 0x08 }, + }; + const struct reg_sequence reg_cfg2[] = { + { 0x830b, 0x03 }, + { 0x830c, 0xd0 }, + { 0x8348, 0x03 }, + { 0x8349, 0xe0 }, + { 0x8324, 0x72 }, + { 0x8325, 0x00 }, + { 0x832a, 0x01 }, + { 0x834a, 0x10 }, + { 0x831d, 0x10 }, + { 0x8326, 0x37 }, + }; + + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); + + switch (mode->hdisplay) { + case 640: + regmap_write(lt9611->regmap, 0x8326, 0x14); + break; + case 1920: + regmap_write(lt9611->regmap, 0x8326, 0x37); + break; + case 3840: + regmap_multi_reg_write(lt9611->regmap, reg_cfg2, ARRAY_SIZE(reg_cfg2)); + break; + } + + /* pcr rst */ + regmap_write(lt9611->regmap, 0x8011, 0x5a); + regmap_write(lt9611->regmap, 0x8011, 0xfa); +} + +static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode) +{ + unsigned int pclk = mode->clock; + const struct reg_sequence reg_cfg[] = { + /* txpll init */ + { 0x8123, 0x40 }, + { 0x8124, 0x64 }, + { 0x8125, 0x80 }, + { 0x8126, 0x55 }, + { 0x812c, 0x37 }, + { 0x812f, 0x01 }, + { 0x8126, 0x55 }, + { 0x8127, 0x66 }, + { 0x8128, 0x88 }, + }; + + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); + + if (pclk > 150000) + regmap_write(lt9611->regmap, 0x812d, 0x88); + else if (pclk > 70000) + regmap_write(lt9611->regmap, 0x812d, 0x99); + else + regmap_write(lt9611->regmap, 0x812d, 0xaa); + + /* + * first divide pclk by 2 first + * - write divide by 64k to 19:16 bits which means shift by 17 + * - write divide by 256 to 15:8 bits which means shift by 9 + * - write remainder to 7:0 bits, which means shift by 1 + */ + regmap_write(lt9611->regmap, 0x82e3, pclk >> 17); /* pclk[19:16] */ + regmap_write(lt9611->regmap, 0x82e4, pclk >> 9); /* pclk[15:8] */ + regmap_write(lt9611->regmap, 0x82e5, pclk >> 1); /* pclk[7:0] */ + + regmap_write(lt9611->regmap, 0x82de, 0x20); + regmap_write(lt9611->regmap, 0x82de, 0xe0); + + regmap_write(lt9611->regmap, 0x8016, 0xf1); + regmap_write(lt9611->regmap, 0x8016, 0xf3); + + return 0; +} + +static int lt9611_read_video_check(struct lt9611 *lt9611, unsigned int reg) +{ + unsigned int temp, temp2; + int ret; + + ret = regmap_read(lt9611->regmap, reg, &temp); + if (ret) + return ret; + temp <<= 8; + ret = regmap_read(lt9611->regmap, reg + 1, &temp2); + if (ret) + return ret; + + return (temp + temp2); +} + +static int lt9611_video_check(struct lt9611 *lt9611) +{ + u32 v_total, vactive, hactive_a, hactive_b, h_total_sysclk; + int temp; + + /* top module video check */ + + /* vactive */ + temp = lt9611_read_video_check(lt9611, 0x8282); + if (temp < 0) + goto end; + vactive = temp; + + /* v_total */ + temp = lt9611_read_video_check(lt9611, 0x826c); + if (temp < 0) + goto end; + v_total = temp; + + /* h_total_sysclk */ + temp = lt9611_read_video_check(lt9611, 0x8286); + if (temp < 0) + goto end; + h_total_sysclk = temp; + + /* hactive_a */ + temp = lt9611_read_video_check(lt9611, 0x8382); + if (temp < 0) + goto end; + hactive_a = temp / 3; + + /* hactive_b */ + temp = lt9611_read_video_check(lt9611, 0x8386); + if (temp < 0) + goto end; + hactive_b = temp / 3; + + dev_info(lt9611->dev, + "video check: hactive_a=%d, hactive_b=%d, vactive=%d, v_total=%d, h_total_sysclk=%d\n", + hactive_a, hactive_b, vactive, v_total, h_total_sysclk); + + return 0; + +end: + dev_err(lt9611->dev, "read video check error\n"); + return temp; +} + +static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611) +{ + regmap_write(lt9611->regmap, 0x8443, 0x46 - lt9611->vic); + regmap_write(lt9611->regmap, 0x8447, lt9611->vic); + regmap_write(lt9611->regmap, 0x843d, 0x0a); /* UD1 infoframe */ + + regmap_write(lt9611->regmap, 0x82d6, 0x8c); + regmap_write(lt9611->regmap, 0x82d7, 0x04); +} + +static void lt9611_hdmi_tx_phy(struct lt9611 *lt9611) +{ + struct reg_sequence reg_cfg[] = { + { 0x8130, 0x6a }, + { 0x8131, 0x44 }, /* HDMI DC mode */ + { 0x8132, 0x4a }, + { 0x8133, 0x0b }, + { 0x8134, 0x00 }, + { 0x8135, 0x00 }, + { 0x8136, 0x00 }, + { 0x8137, 0x44 }, + { 0x813f, 0x0f }, + { 0x8140, 0xa0 }, + { 0x8141, 0xa0 }, + { 0x8142, 0xa0 }, + { 0x8143, 0xa0 }, + { 0x8144, 0x0a }, + }; + + /* HDMI AC mode */ + if (lt9611->ac_mode) + reg_cfg[2].def = 0x73; + + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); +} + +static irqreturn_t lt9611_irq_thread_handler(int irq, void *dev_id) +{ + struct lt9611 *lt9611 = dev_id; + unsigned int irq_flag0 = 0; + unsigned int irq_flag3 = 0; + + regmap_read(lt9611->regmap, 0x820f, &irq_flag3); + regmap_read(lt9611->regmap, 0x820c, &irq_flag0); + + /* hpd changed low */ + if (irq_flag3 & 0x80) { + dev_info(lt9611->dev, "hdmi cable disconnected\n"); + + regmap_write(lt9611->regmap, 0x8207, 0xbf); + regmap_write(lt9611->regmap, 0x8207, 0x3f); + } + + /* hpd changed high */ + if (irq_flag3 & 0x40) { + dev_info(lt9611->dev, "hdmi cable connected\n"); + + regmap_write(lt9611->regmap, 0x8207, 0x7f); + regmap_write(lt9611->regmap, 0x8207, 0x3f); + } + + if (irq_flag3 & 0xc0 && lt9611->bridge.dev) + drm_kms_helper_hotplug_event(lt9611->bridge.dev); + + /* video input changed */ + if (irq_flag0 & 0x01) { + dev_info(lt9611->dev, "video input changed\n"); + regmap_write(lt9611->regmap, 0x829e, 0xff); + regmap_write(lt9611->regmap, 0x829e, 0xf7); + regmap_write(lt9611->regmap, 0x8204, 0xff); + regmap_write(lt9611->regmap, 0x8204, 0xfe); + } + + return IRQ_HANDLED; +} + +static void lt9611_enable_hpd_interrupts(struct lt9611 *lt9611) +{ + unsigned int val; + + regmap_read(lt9611->regmap, 0x8203, &val); + + val &= ~0xc0; + regmap_write(lt9611->regmap, 0x8203, val); + regmap_write(lt9611->regmap, 0x8207, 0xff); /* clear */ + regmap_write(lt9611->regmap, 0x8207, 0x3f); +} + +static void lt9611_sleep_setup(struct lt9611 *lt9611) +{ + const struct reg_sequence sleep_setup[] = { + { 0x8024, 0x76 }, + { 0x8023, 0x01 }, + { 0x8157, 0x03 }, /* set addr pin as output */ + { 0x8149, 0x0b }, + { 0x8151, 0x30 }, /* disable IRQ */ + { 0x8102, 0x48 }, /* MIPI Rx power down */ + { 0x8123, 0x80 }, + { 0x8130, 0x00 }, + { 0x8100, 0x01 }, /* bandgap power down */ + { 0x8101, 0x00 }, /* system clk power down */ + }; + + regmap_multi_reg_write(lt9611->regmap, + sleep_setup, ARRAY_SIZE(sleep_setup)); + lt9611->sleep = true; +} + +static int lt9611_power_on(struct lt9611 *lt9611) +{ + int ret; + const struct reg_sequence seq[] = { + /* LT9611_System_Init */ + { 0x8101, 0x18 }, /* sel xtal clock */ + + /* timer for frequency meter */ + { 0x821b, 0x69 }, /* timer 2 */ + { 0x821c, 0x78 }, + { 0x82cb, 0x69 }, /* timer 1 */ + { 0x82cc, 0x78 }, + + /* irq init */ + { 0x8251, 0x01 }, + { 0x8258, 0x0a }, /* hpd irq */ + { 0x8259, 0x80 }, /* hpd debounce width */ + { 0x829e, 0xf7 }, /* video check irq */ + + /* power consumption for work */ + { 0x8004, 0xf0 }, + { 0x8006, 0xf0 }, + { 0x800a, 0x80 }, + { 0x800b, 0x40 }, + { 0x800d, 0xef }, + { 0x8011, 0xfa }, + }; + + if (lt9611->power_on) + return 0; + + ret = regmap_multi_reg_write(lt9611->regmap, seq, ARRAY_SIZE(seq)); + if (!ret) + lt9611->power_on = true; + + return ret; +} + +static int lt9611_power_off(struct lt9611 *lt9611) +{ + int ret; + + ret = regmap_write(lt9611->regmap, 0x8130, 0x6a); + if (!ret) + lt9611->power_on = false; + + return ret; +} + +static void lt9611_reset(struct lt9611 *lt9611) +{ + gpiod_set_value_cansleep(lt9611->reset_gpio, 1); + msleep(20); + + gpiod_set_value_cansleep(lt9611->reset_gpio, 0); + msleep(20); + + gpiod_set_value_cansleep(lt9611->reset_gpio, 1); + msleep(100); +} + +static void lt9611_assert_5v(struct lt9611 *lt9611) +{ + if (!lt9611->enable_gpio) + return; + + gpiod_set_value_cansleep(lt9611->enable_gpio, 1); + msleep(20); +} + +static int lt9611_regulator_init(struct lt9611 *lt9611) +{ + int ret; + + lt9611->supplies[0].supply = "vdd"; + lt9611->supplies[1].supply = "vcc"; + + ret = devm_regulator_bulk_get(lt9611->dev, 2, lt9611->supplies); + if (ret < 0) + return ret; + + return regulator_set_load(lt9611->supplies[0].consumer, 300000); +} + +static int lt9611_regulator_enable(struct lt9611 *lt9611) +{ + int ret; + + ret = regulator_enable(lt9611->supplies[0].consumer); + if (ret < 0) + return ret; + + usleep_range(1000, 10000); + + ret = regulator_enable(lt9611->supplies[1].consumer); + if (ret < 0) { + regulator_disable(lt9611->supplies[0].consumer); + return ret; + } + + return 0; +} + +static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lt9611_modes); i++) { + if (lt9611_modes[i].hdisplay == mode->hdisplay && + lt9611_modes[i].vdisplay == mode->vdisplay && + lt9611_modes[i].vrefresh == drm_mode_vrefresh(mode)) { + return <9611_modes[i]; + } + } + + return NULL; +} + +/* connector funcs */ +static enum drm_connector_status +lt9611_connector_detect(struct drm_connector *connector, bool force) +{ + struct lt9611 *lt9611 = connector_to_lt9611(connector); + unsigned int reg_val = 0; + int connected = 0; + + regmap_read(lt9611->regmap, 0x825e, ®_val); + connected = (reg_val & BIT(2)); + + lt9611->status = connected ? connector_status_connected : + connector_status_disconnected; + + return lt9611->status; +} + +static int lt9611_read_edid(struct lt9611 *lt9611) +{ + unsigned int temp; + int ret = 0; + int i, j; + + /* memset to clear old buffer, if any */ + memset(lt9611->edid_buf, 0, sizeof(lt9611->edid_buf)); + + regmap_write(lt9611->regmap, 0x8503, 0xc9); + + /* 0xA0 is EDID device address */ + regmap_write(lt9611->regmap, 0x8504, 0xa0); + /* 0x00 is EDID offset address */ + regmap_write(lt9611->regmap, 0x8505, 0x00); + + /* length for read */ + regmap_write(lt9611->regmap, 0x8506, EDID_LEN); + regmap_write(lt9611->regmap, 0x8514, 0x7f); + + for (i = 0; i < EDID_LOOP; i++) { + /* offset address */ + regmap_write(lt9611->regmap, 0x8505, i * EDID_LEN); + regmap_write(lt9611->regmap, 0x8507, 0x36); + regmap_write(lt9611->regmap, 0x8507, 0x31); + regmap_write(lt9611->regmap, 0x8507, 0x37); + usleep_range(5000, 10000); + + regmap_read(lt9611->regmap, 0x8540, &temp); + + if (temp & KEY_DDC_ACCS_DONE) { + for (j = 0; j < EDID_LEN; j++) { + regmap_read(lt9611->regmap, 0x8583, &temp); + lt9611->edid_buf[i * EDID_LEN + j] = temp; + } + + } else if (temp & DDC_NO_ACK) { /* DDC No Ack or Abitration lost */ + dev_err(lt9611->dev, "read edid failed: no ack\n"); + ret = -EIO; + goto end; + + } else { + dev_err(lt9611->dev, "read edid failed: access not done\n"); + ret = -EIO; + goto end; + } + } + +end: + regmap_write(lt9611->regmap, 0x8507, 0x1f); + return ret; +} + +static int +lt9611_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) +{ + struct lt9611 *lt9611 = data; + int ret; + + if (len > 128) + return -EINVAL; + + /* supports up to 1 extension block */ + /* TODO: add support for more extension blocks */ + if (block > 1) + return -EINVAL; + + if (block == 0) { + ret = lt9611_read_edid(lt9611); + if (ret) { + dev_err(lt9611->dev, "edid read failed\n"); + return ret; + } + } + + block %= 2; + memcpy(buf, lt9611->edid_buf + (block * 128), len); + + return 0; +} + +static int lt9611_connector_get_modes(struct drm_connector *connector) +{ + struct lt9611 *lt9611 = connector_to_lt9611(connector); + unsigned int count; + struct edid *edid; + + lt9611_power_on(lt9611); + edid = drm_do_get_edid(connector, lt9611_get_edid_block, lt9611); + drm_connector_update_edid_property(connector, edid); + count = drm_add_edid_modes(connector, edid); + kfree(edid); + + return count; +} + +static enum drm_mode_status +lt9611_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode); + + return lt9611_mode ? MODE_OK : MODE_BAD; +} + +/* bridge funcs */ +static void lt9611_bridge_enable(struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + + if (lt9611_power_on(lt9611)) { + dev_err(lt9611->dev, "power on failed\n"); + return; + } + + lt9611_mipi_input_analog(lt9611); + lt9611_hdmi_tx_digital(lt9611); + lt9611_hdmi_tx_phy(lt9611); + + msleep(500); + + lt9611_video_check(lt9611); + + /* Enable HDMI output */ + regmap_write(lt9611->regmap, 0x8130, 0xea); +} + +static void lt9611_bridge_disable(struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + int ret; + + /* Disable HDMI output */ + ret = regmap_write(lt9611->regmap, 0x8130, 0x6a); + if (ret) { + dev_err(lt9611->dev, "video on failed\n"); + return; + } + + if (lt9611_power_off(lt9611)) { + dev_err(lt9611->dev, "power on failed\n"); + return; + } +} + +static struct +drm_connector_helper_funcs lt9611_bridge_connector_helper_funcs = { + .get_modes = lt9611_connector_get_modes, + .mode_valid = lt9611_connector_mode_valid, +}; + +static const struct drm_connector_funcs lt9611_bridge_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = lt9611_connector_detect, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, + struct device_node *dsi_node) +{ + const struct mipi_dsi_device_info info = { "lt9611", 0, NULL }; + struct mipi_dsi_device *dsi; + struct mipi_dsi_host *host; + int ret; + + host = of_find_mipi_dsi_host_by_node(dsi_node); + if (!host) { + dev_err(lt9611->dev, "failed to find dsi host\n"); + return ERR_PTR(-EPROBE_DEFER); + } + + dsi = mipi_dsi_device_register_full(host, &info); + if (IS_ERR(dsi)) { + dev_err(lt9611->dev, "failed to create dsi device\n"); + return dsi; + } + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_VIDEO_HSE; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(lt9611->dev, "failed to attach dsi to host\n"); + mipi_dsi_device_unregister(dsi); + return ERR_PTR(ret); + } + + return dsi; +} + +static void lt9611_bridge_detach(struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + + if (lt9611->dsi1) { + mipi_dsi_detach(lt9611->dsi1); + mipi_dsi_device_unregister(lt9611->dsi1); + } + + mipi_dsi_detach(lt9611->dsi0); + mipi_dsi_device_unregister(lt9611->dsi0); +} + +static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt9611) +{ + int ret; + + ret = drm_connector_init(bridge->dev, <9611->connector, + <9611_bridge_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + if (ret) { + DRM_ERROR("Failed to initialize connector with drm\n"); + return ret; + } + + drm_connector_helper_add(<9611->connector, + <9611_bridge_connector_helper_funcs); + drm_connector_attach_encoder(<9611->connector, bridge->encoder); + + if (!bridge->encoder) { + DRM_ERROR("Parent encoder object not found"); + return -ENODEV; + } + + return 0; +} + +static int lt9611_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + int ret; + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { + ret = lt9611_connector_init(bridge, lt9611); + if (ret < 0) + return ret; + } + + /* Attach primary DSI */ + lt9611->dsi0 = lt9611_attach_dsi(lt9611, lt9611->dsi0_node); + if (IS_ERR(lt9611->dsi0)) + return PTR_ERR(lt9611->dsi0); + + /* Attach secondary DSI, if specified */ + if (lt9611->dsi1_node) { + lt9611->dsi1 = lt9611_attach_dsi(lt9611, lt9611->dsi1_node); + if (IS_ERR(lt9611->dsi1)) { + ret = PTR_ERR(lt9611->dsi1); + goto err_unregister_dsi0; + } + } + + return 0; + +err_unregister_dsi0: + lt9611_bridge_detach(bridge); + drm_connector_cleanup(<9611->connector); + mipi_dsi_device_unregister(lt9611->dsi0); + + return ret; +} + +static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode); + + return lt9611_mode ? MODE_OK : MODE_BAD; +} + +static void lt9611_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + + if (!lt9611->sleep) + return; + + lt9611_reset(lt9611); + regmap_write(lt9611->regmap, 0x80ee, 0x01); + + lt9611->sleep = false; +} + +static void lt9611_bridge_post_disable(struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + + lt9611_sleep_setup(lt9611); +} + +static void lt9611_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adj_mode) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + struct hdmi_avi_infoframe avi_frame; + int ret; + + lt9611_bridge_pre_enable(bridge); + + lt9611_mipi_input_digital(lt9611, mode); + lt9611_pll_setup(lt9611, mode); + lt9611_mipi_video_setup(lt9611, mode); + lt9611_pcr_setup(lt9611, mode); + + ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, + <9611->connector, + mode); + if (!ret) + lt9611->vic = avi_frame.video_code; +} + +static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + unsigned int reg_val = 0; + int connected; + + regmap_read(lt9611->regmap, 0x825e, ®_val); + connected = reg_val & BIT(2); + + lt9611->status = connected ? connector_status_connected : + connector_status_disconnected; + + return lt9611->status; +} + +static struct edid *lt9611_bridge_get_edid(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); +} + +static void lt9611_bridge_hpd_enable(struct drm_bridge *bridge) +{ + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + + lt9611_enable_hpd_interrupts(lt9611); +} + +static const struct drm_bridge_funcs lt9611_bridge_funcs = { + .attach = lt9611_bridge_attach, + .detach = lt9611_bridge_detach, + .mode_valid = lt9611_bridge_mode_valid, + .enable = lt9611_bridge_enable, + .disable = lt9611_bridge_disable, + .post_disable = lt9611_bridge_post_disable, + .mode_set = lt9611_bridge_mode_set, + .detect = lt9611_bridge_detect, + .get_edid = lt9611_bridge_get_edid, + .hpd_enable = lt9611_bridge_hpd_enable, +}; + +static int lt9611_parse_dt(struct device *dev, + struct lt9611 *lt9611) +{ + lt9611->dsi0_node = of_graph_get_remote_node(dev->of_node, 1, -1); + if (!lt9611->dsi0_node) { + dev_err(lt9611->dev, "failed to get remote node for primary dsi\n"); + return -ENODEV; + } + + lt9611->dsi1_node = of_graph_get_remote_node(dev->of_node, 2, -1); + + lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode"); + + return 0; +} + +static int lt9611_gpio_init(struct lt9611 *lt9611) +{ + struct device *dev = lt9611->dev; + + lt9611->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(lt9611->reset_gpio)) { + dev_err(dev, "failed to acquire reset gpio\n"); + return PTR_ERR(lt9611->reset_gpio); + } + + lt9611->enable_gpio = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(lt9611->enable_gpio)) { + dev_err(dev, "failed to acquire enable gpio\n"); + return PTR_ERR(lt9611->enable_gpio); + } + + return 0; +} + +static int lt9611_read_device_rev(struct lt9611 *lt9611) +{ + unsigned int rev; + int ret; + + regmap_write(lt9611->regmap, 0x80ee, 0x01); + ret = regmap_read(lt9611->regmap, 0x8002, &rev); + if (ret) + dev_err(lt9611->dev, "failed to read revision: %d\n", ret); + else + dev_info(lt9611->dev, "LT9611 revision: 0x%x\n", rev); + + return ret; +} + +static int lt9611_hdmi_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms) +{ + struct lt9611 *lt9611 = data; + + if (hparms->sample_rate == 48000) + regmap_write(lt9611->regmap, 0x840f, 0x2b); + else if (hparms->sample_rate == 96000) + regmap_write(lt9611->regmap, 0x840f, 0xab); + else + return -EINVAL; + + regmap_write(lt9611->regmap, 0x8435, 0x00); + regmap_write(lt9611->regmap, 0x8436, 0x18); + regmap_write(lt9611->regmap, 0x8437, 0x00); + + return 0; +} + +static int lt9611_audio_startup(struct device *dev, void *data) +{ + struct lt9611 *lt9611 = data; + + regmap_write(lt9611->regmap, 0x82d6, 0x8c); + regmap_write(lt9611->regmap, 0x82d7, 0x04); + + regmap_write(lt9611->regmap, 0x8406, 0x08); + regmap_write(lt9611->regmap, 0x8407, 0x10); + + regmap_write(lt9611->regmap, 0x8434, 0xd5); + + return 0; +} + +static void lt9611_audio_shutdown(struct device *dev, void *data) +{ + struct lt9611 *lt9611 = data; + + regmap_write(lt9611->regmap, 0x8406, 0x00); + regmap_write(lt9611->regmap, 0x8407, 0x00); +} + +static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component, + struct device_node *endpoint) +{ + struct of_endpoint of_ep; + int ret; + + ret = of_graph_parse_endpoint(endpoint, &of_ep); + if (ret < 0) + return ret; + + /* + * HDMI sound should be located as reg = <2> + * Then, it is sound port 0 + */ + if (of_ep.port == 2) + return 0; + + return -EINVAL; +} + +static const struct hdmi_codec_ops lt9611_codec_ops = { + .hw_params = lt9611_hdmi_hw_params, + .audio_shutdown = lt9611_audio_shutdown, + .audio_startup = lt9611_audio_startup, + .get_dai_id = lt9611_hdmi_i2s_get_dai_id, +}; + +static struct hdmi_codec_pdata codec_data = { + .ops = <9611_codec_ops, + .max_i2s_channels = 8, + .i2s = 1, +}; + +static int lt9611_audio_init(struct device *dev, struct lt9611 *lt9611) +{ + codec_data.data = lt9611; + lt9611->audio_pdev = + platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, + &codec_data, sizeof(codec_data)); + + return PTR_ERR_OR_ZERO(lt9611->audio_pdev); +} + +static void lt9611_audio_exit(struct lt9611 *lt9611) +{ + if (lt9611->audio_pdev) { + platform_device_unregister(lt9611->audio_pdev); + lt9611->audio_pdev = NULL; + } +} + +static int lt9611_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lt9611 *lt9611; + struct device *dev = &client->dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(dev, "device doesn't support I2C\n"); + return -ENODEV; + } + + lt9611 = devm_kzalloc(dev, sizeof(*lt9611), GFP_KERNEL); + if (!lt9611) + return -ENOMEM; + + lt9611->dev = &client->dev; + lt9611->client = client; + lt9611->sleep = false; + + lt9611->regmap = devm_regmap_init_i2c(client, <9611_regmap_config); + if (IS_ERR(lt9611->regmap)) { + dev_err(lt9611->dev, "regmap i2c init failed\n"); + return PTR_ERR(lt9611->regmap); + } + + ret = lt9611_parse_dt(&client->dev, lt9611); + if (ret) { + dev_err(dev, "failed to parse device tree\n"); + return ret; + } + + ret = lt9611_gpio_init(lt9611); + if (ret < 0) + goto err_of_put; + + ret = lt9611_regulator_init(lt9611); + if (ret < 0) + goto err_of_put; + + lt9611_assert_5v(lt9611); + + ret = lt9611_regulator_enable(lt9611); + if (ret) + goto err_of_put; + + lt9611_reset(lt9611); + + ret = lt9611_read_device_rev(lt9611); + if (ret) { + dev_err(dev, "failed to read chip rev\n"); + goto err_disable_regulators; + } + + ret = devm_request_threaded_irq(dev, client->irq, NULL, + lt9611_irq_thread_handler, + IRQF_ONESHOT, "lt9611", lt9611); + if (ret) { + dev_err(dev, "failed to request irq\n"); + goto err_disable_regulators; + } + + i2c_set_clientdata(client, lt9611); + + lt9611->bridge.funcs = <9611_bridge_funcs; + lt9611->bridge.of_node = client->dev.of_node; + lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | + DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES; + lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA; + + drm_bridge_add(<9611->bridge); + + lt9611_enable_hpd_interrupts(lt9611); + + return lt9611_audio_init(dev, lt9611); + +err_disable_regulators: + regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies); + +err_of_put: + of_node_put(lt9611->dsi1_node); + of_node_put(lt9611->dsi0_node); + + return ret; +} + +static int lt9611_remove(struct i2c_client *client) +{ + struct lt9611 *lt9611 = i2c_get_clientdata(client); + + disable_irq(client->irq); + lt9611_audio_exit(lt9611); + drm_bridge_remove(<9611->bridge); + + regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies); + + of_node_put(lt9611->dsi1_node); + of_node_put(lt9611->dsi0_node); + + return 0; +} + +static struct i2c_device_id lt9611_id[] = { + { "lontium,lt9611", 0 }, + {} +}; + +static const struct of_device_id lt9611_match_table[] = { + { .compatible = "lontium,lt9611" }, + { } +}; +MODULE_DEVICE_TABLE(of, lt9611_match_table); + +static struct i2c_driver lt9611_driver = { + .driver = { + .name = "lt9611", + .of_match_table = lt9611_match_table, + }, + .probe = lt9611_probe, + .remove = lt9611_remove, + .id_table = lt9611_id, +}; +module_i2c_driver(lt9611_driver); + +MODULE_LICENSE("GPL v2"); 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 6200f12a37e6..d2808c4a6fb1 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -61,7 +61,6 @@ struct ge_b850v3_lvds { struct drm_bridge bridge; struct i2c_client *stdp4028_i2c; struct i2c_client *stdp2690_i2c; - struct edid *edid; }; static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr; @@ -131,22 +130,26 @@ err: return NULL; } -static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) +static struct edid *ge_b850v3_lvds_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) { struct i2c_client *client; - int num_modes = 0; client = ge_b850v3_lvds_ptr->stdp2690_i2c; - kfree(ge_b850v3_lvds_ptr->edid); - ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client); + return (struct edid *)stdp2690_get_edid(client); +} - if (ge_b850v3_lvds_ptr->edid) { - drm_connector_update_edid_property(connector, - ge_b850v3_lvds_ptr->edid); - num_modes = drm_add_edid_modes(connector, - ge_b850v3_lvds_ptr->edid); - } +static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) +{ + struct edid *edid; + int num_modes; + + edid = ge_b850v3_lvds_get_edid(&ge_b850v3_lvds_ptr->bridge, connector); + + drm_connector_update_edid_property(connector, edid); + num_modes = drm_add_edid_modes(connector, edid); + kfree(edid); return num_modes; } @@ -163,8 +166,7 @@ drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = { .mode_valid = ge_b850v3_lvds_mode_valid, }; -static enum drm_connector_status ge_b850v3_lvds_detect( - struct drm_connector *connector, bool force) +static enum drm_connector_status ge_b850v3_lvds_bridge_detect(struct drm_bridge *bridge) { struct i2c_client *stdp4028_i2c = ge_b850v3_lvds_ptr->stdp4028_i2c; @@ -182,6 +184,12 @@ static enum drm_connector_status ge_b850v3_lvds_detect( return connector_status_unknown; } +static enum drm_connector_status ge_b850v3_lvds_detect(struct drm_connector *connector, + bool force) +{ + return ge_b850v3_lvds_bridge_detect(&ge_b850v3_lvds_ptr->bridge); +} + static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = ge_b850v3_lvds_detect, @@ -191,34 +199,11 @@ static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id) -{ - struct i2c_client *stdp4028_i2c - = ge_b850v3_lvds_ptr->stdp4028_i2c; - - i2c_smbus_write_word_data(stdp4028_i2c, - STDP4028_DPTX_IRQ_STS_REG, - STDP4028_DPTX_IRQ_CLEAR); - - if (ge_b850v3_lvds_ptr->connector.dev) - drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->connector.dev); - - return IRQ_HANDLED; -} - -static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) +static int ge_b850v3_lvds_create_connector(struct drm_bridge *bridge) { struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector; - struct i2c_client *stdp4028_i2c - = ge_b850v3_lvds_ptr->stdp4028_i2c; int ret; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } - if (!bridge->encoder) { DRM_ERROR("Parent encoder object not found"); return -ENODEV; @@ -237,9 +222,29 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, return ret; } - ret = drm_connector_attach_encoder(connector, bridge->encoder); - if (ret) - return ret; + return drm_connector_attach_encoder(connector, bridge->encoder); +} + +static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id) +{ + struct i2c_client *stdp4028_i2c + = ge_b850v3_lvds_ptr->stdp4028_i2c; + + i2c_smbus_write_word_data(stdp4028_i2c, + STDP4028_DPTX_IRQ_STS_REG, + STDP4028_DPTX_IRQ_CLEAR); + + if (ge_b850v3_lvds_ptr->bridge.dev) + drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->bridge.dev); + + return IRQ_HANDLED; +} + +static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct i2c_client *stdp4028_i2c + = ge_b850v3_lvds_ptr->stdp4028_i2c; /* Configures the bridge to re-enable interrupts after each ack. */ i2c_smbus_write_word_data(stdp4028_i2c, @@ -251,11 +256,16 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, STDP4028_DPTX_IRQ_EN_REG, STDP4028_DPTX_IRQ_CONFIG); - return 0; + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; + + return ge_b850v3_lvds_create_connector(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, }; static int ge_b850v3_lvds_init(struct device *dev) @@ -291,8 +301,6 @@ static void ge_b850v3_lvds_remove(void) drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge); - kfree(ge_b850v3_lvds_ptr->edid); - ge_b850v3_lvds_ptr = NULL; out: mutex_unlock(&ge_b850v3_lvds_dev_mutex); @@ -302,14 +310,21 @@ static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c, const struct i2c_device_id *id) { struct device *dev = &stdp4028_i2c->dev; + int ret; + + ret = ge_b850v3_lvds_init(dev); - ge_b850v3_lvds_init(dev); + if (ret) + return ret; ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c; i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr); /* drm bridge initialization */ ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; + ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_EDID; + ge_b850v3_lvds_ptr->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; drm_bridge_add(&ge_b850v3_lvds_ptr->bridge); @@ -361,8 +376,12 @@ static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c, const struct i2c_device_id *id) { struct device *dev = &stdp2690_i2c->dev; + int ret; + + ret = ge_b850v3_lvds_init(dev); - ge_b850v3_lvds_init(dev); + if (ret) + return ret; ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c; i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr); diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 438e566ce0a4..e941c1132598 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -29,8 +29,7 @@ struct ptn3460_bridge { struct drm_connector connector; struct i2c_client *client; struct drm_bridge bridge; - struct edid *edid; - struct drm_panel *panel; + struct drm_bridge *panel_bridge; struct gpio_desc *gpio_pd_n; struct gpio_desc *gpio_rst_n; u32 edid_emulation; @@ -127,11 +126,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge) usleep_range(10, 20); gpiod_set_value(ptn_bridge->gpio_rst_n, 1); - if (drm_panel_prepare(ptn_bridge->panel)) { - DRM_ERROR("failed to prepare panel\n"); - return; - } - /* * There's a bug in the PTN chip where it falsely asserts hotplug before * it is fully functional. We're forced to wait for the maximum start up @@ -146,16 +140,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge) ptn_bridge->enabled = true; } -static void ptn3460_enable(struct drm_bridge *bridge) -{ - struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); - - if (drm_panel_enable(ptn_bridge->panel)) { - DRM_ERROR("failed to enable panel\n"); - return; - } -} - static void ptn3460_disable(struct drm_bridge *bridge) { struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); @@ -165,36 +149,18 @@ static void ptn3460_disable(struct drm_bridge *bridge) ptn_bridge->enabled = false; - if (drm_panel_disable(ptn_bridge->panel)) { - DRM_ERROR("failed to disable panel\n"); - return; - } - gpiod_set_value(ptn_bridge->gpio_rst_n, 1); gpiod_set_value(ptn_bridge->gpio_pd_n, 0); } -static void ptn3460_post_disable(struct drm_bridge *bridge) -{ - struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); - if (drm_panel_unprepare(ptn_bridge->panel)) { - DRM_ERROR("failed to unprepare panel\n"); - return; - } -} - -static int ptn3460_get_modes(struct drm_connector *connector) +static struct edid *ptn3460_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) { - struct ptn3460_bridge *ptn_bridge; - u8 *edid; - int ret, num_modes = 0; + struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); bool power_off; - - ptn_bridge = connector_to_ptn3460(connector); - - if (ptn_bridge->edid) - return drm_add_edid_modes(connector, ptn_bridge->edid); + u8 *edid; + int ret; power_off = !ptn_bridge->enabled; ptn3460_pre_enable(&ptn_bridge->bridge); @@ -202,30 +168,40 @@ static int ptn3460_get_modes(struct drm_connector *connector) edid = kmalloc(EDID_LENGTH, GFP_KERNEL); if (!edid) { DRM_ERROR("Failed to allocate EDID\n"); - return 0; + goto out; } ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, - EDID_LENGTH); + EDID_LENGTH); if (ret) { kfree(edid); + edid = NULL; goto out; } - ptn_bridge->edid = (struct edid *)edid; - drm_connector_update_edid_property(connector, ptn_bridge->edid); - - num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); - out: if (power_off) ptn3460_disable(&ptn_bridge->bridge); + return (struct edid *)edid; +} + +static int ptn3460_connector_get_modes(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector); + struct edid *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); + return num_modes; } static const struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { - .get_modes = ptn3460_get_modes, + .get_modes = ptn3460_connector_get_modes, }; static const struct drm_connector_funcs ptn3460_connector_funcs = { @@ -242,10 +218,14 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); int ret; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } + /* Let this driver create connector if requested */ + ret = drm_bridge_attach(bridge->encoder, ptn_bridge->panel_bridge, + bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) + return ret; + + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; if (!bridge->encoder) { DRM_ERROR("Parent encoder object not found"); @@ -265,9 +245,6 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, drm_connector_attach_encoder(&ptn_bridge->connector, bridge->encoder); - if (ptn_bridge->panel) - drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector); - drm_helper_hpd_irq_event(ptn_bridge->connector.dev); return ret; @@ -275,10 +252,9 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, static const struct drm_bridge_funcs ptn3460_bridge_funcs = { .pre_enable = ptn3460_pre_enable, - .enable = ptn3460_enable, .disable = ptn3460_disable, - .post_disable = ptn3460_post_disable, .attach = ptn3460_bridge_attach, + .get_edid = ptn3460_get_edid, }; static int ptn3460_probe(struct i2c_client *client, @@ -286,6 +262,8 @@ static int ptn3460_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct ptn3460_bridge *ptn_bridge; + struct drm_bridge *panel_bridge; + struct drm_panel *panel; int ret; ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL); @@ -293,10 +271,15 @@ static int ptn3460_probe(struct i2c_client *client, return -ENOMEM; } - ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ptn_bridge->panel, NULL); + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL); if (ret) return ret; + panel_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(panel_bridge)) + return PTR_ERR(panel_bridge); + + ptn_bridge->panel_bridge = panel_bridge; ptn_bridge->client = client; ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown", @@ -327,6 +310,8 @@ static int ptn3460_probe(struct i2c_client *client, } ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; + ptn_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; + ptn_bridge->bridge.type = DRM_MODE_CONNECTOR_LVDS; ptn_bridge->bridge.of_node = dev->of_node; drm_bridge_add(&ptn_bridge->bridge); diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 1e63ed6b18aa..0ddc37551194 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -82,18 +82,11 @@ static int panel_bridge_attach(struct drm_bridge *bridge, drm_connector_attach_encoder(&panel_bridge->connector, bridge->encoder); - ret = drm_panel_attach(panel_bridge->panel, &panel_bridge->connector); - if (ret < 0) - return ret; - return 0; } static void panel_bridge_detach(struct drm_bridge *bridge) { - struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); - - drm_panel_detach(panel_bridge->panel); } static void panel_bridge_pre_enable(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index d789ea2a7fb9..614b19f0f1b7 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -42,10 +42,9 @@ #endif struct ps8622_bridge { - struct drm_connector connector; struct i2c_client *client; struct drm_bridge bridge; - struct drm_panel *panel; + struct drm_bridge *panel_bridge; struct regulator *v12; struct backlight_device *bl; @@ -64,12 +63,6 @@ static inline struct ps8622_bridge * return container_of(bridge, struct ps8622_bridge, bridge); } -static inline struct ps8622_bridge * - connector_to_ps8622(struct drm_connector *connector) -{ - return container_of(connector, struct ps8622_bridge, connector); -} - static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val) { int ret; @@ -365,11 +358,6 @@ static void ps8622_pre_enable(struct drm_bridge *bridge) DRM_ERROR("fails to enable ps8622->v12"); } - if (drm_panel_prepare(ps8622->panel)) { - DRM_ERROR("failed to prepare panel\n"); - return; - } - gpiod_set_value(ps8622->gpio_slp, 1); /* @@ -399,24 +387,9 @@ static void ps8622_pre_enable(struct drm_bridge *bridge) ps8622->enabled = true; } -static void ps8622_enable(struct drm_bridge *bridge) -{ - struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); - - if (drm_panel_enable(ps8622->panel)) { - DRM_ERROR("failed to enable panel\n"); - return; - } -} - static void ps8622_disable(struct drm_bridge *bridge) { - struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); - - if (drm_panel_disable(ps8622->panel)) { - DRM_ERROR("failed to disable panel\n"); - return; - } + /* Delay after panel is disabled */ msleep(PS8622_PWMO_END_T12_MS); } @@ -436,11 +409,6 @@ static void ps8622_post_disable(struct drm_bridge *bridge) */ gpiod_set_value(ps8622->gpio_slp, 0); - if (drm_panel_unprepare(ps8622->panel)) { - DRM_ERROR("failed to unprepare panel\n"); - return; - } - if (ps8622->v12) regulator_disable(ps8622->v12); @@ -455,67 +423,17 @@ static void ps8622_post_disable(struct drm_bridge *bridge) msleep(PS8622_POWER_OFF_T17_MS); } -static int ps8622_get_modes(struct drm_connector *connector) -{ - struct ps8622_bridge *ps8622; - - ps8622 = connector_to_ps8622(connector); - - return drm_panel_get_modes(ps8622->panel, connector); -} - -static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = { - .get_modes = ps8622_get_modes, -}; - -static const struct drm_connector_funcs ps8622_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - static int ps8622_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); - int ret; - - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } - if (!bridge->encoder) { - DRM_ERROR("Parent encoder object not found"); - return -ENODEV; - } - - ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD; - ret = drm_connector_init(bridge->dev, &ps8622->connector, - &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - if (ret) { - DRM_ERROR("Failed to initialize connector with drm\n"); - return ret; - } - drm_connector_helper_add(&ps8622->connector, - &ps8622_connector_helper_funcs); - drm_connector_register(&ps8622->connector); - drm_connector_attach_encoder(&ps8622->connector, - bridge->encoder); - - if (ps8622->panel) - drm_panel_attach(ps8622->panel, &ps8622->connector); - - drm_helper_hpd_irq_event(ps8622->connector.dev); - - return ret; + return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge, + &ps8622->bridge, flags); } static const struct drm_bridge_funcs ps8622_bridge_funcs = { .pre_enable = ps8622_pre_enable, - .enable = ps8622_enable, .disable = ps8622_disable, .post_disable = ps8622_post_disable, .attach = ps8622_attach, @@ -533,16 +451,23 @@ static int ps8622_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct ps8622_bridge *ps8622; + struct drm_bridge *panel_bridge; + struct drm_panel *panel; int ret; ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL); if (!ps8622) return -ENOMEM; - ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ps8622->panel, NULL); + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL); if (ret) return ret; + panel_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(panel_bridge)) + return PTR_ERR(panel_bridge); + + ps8622->panel_bridge = panel_bridge; ps8622->client = client; ps8622->v12 = devm_regulator_get(dev, "vdd12"); @@ -595,6 +520,7 @@ static int ps8622_probe(struct i2c_client *client, } ps8622->bridge.funcs = &ps8622_bridge_funcs; + ps8622->bridge.type = DRM_MODE_CONNECTOR_LVDS; ps8622->bridge.of_node = dev->of_node; drm_bridge_add(&ps8622->bridge); diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 4b099196afeb..9f7b7a9c53c5 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -82,8 +82,11 @@ static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge, ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD, sizeof(vdo_ctrl_buf), vdo_ctrl_buf); - if (ret < 0) + if (ret < 0) { + DRM_ERROR("failed to %sable VDO: %d\n", + ctrl == ENABLE ? "en" : "dis", ret); return ret; + } return 0; } @@ -150,10 +153,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge) } ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE); - if (ret) { - DRM_ERROR("failed to enable VDO: %d\n", ret); + if (ret) goto err_regulators_disable; - } /* Switch access edp panel's edid through i2c */ ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS, @@ -175,9 +176,7 @@ static void ps8640_post_disable(struct drm_bridge *bridge) struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); int ret; - ret = ps8640_bridge_vdo_control(ps_bridge, DISABLE); - if (ret < 0) - DRM_ERROR("failed to disable VDO: %d\n", ret); + ps8640_bridge_vdo_control(ps_bridge, DISABLE); gpiod_set_value(ps_bridge->gpio_reset, 1); gpiod_set_value(ps_bridge->gpio_powerdown, 1); @@ -200,6 +199,10 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, .channel = 0, .node = NULL, }; + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + /* port@0 is ps8640 dsi input port */ in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); if (!in_ep) @@ -242,8 +245,18 @@ err_dsi_attach: return ret; } +static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); + + return drm_get_edid(connector, + ps_bridge->page[PAGE0_DP_CNTL]->adapter); +} + static const struct drm_bridge_funcs ps8640_bridge_funcs = { .attach = ps8640_bridge_attach, + .get_edid = ps8640_bridge_get_edid, .post_disable = ps8640_post_disable, .pre_enable = ps8640_pre_enable, }; @@ -294,6 +307,8 @@ static int ps8640_probe(struct i2c_client *client) ps_bridge->bridge.funcs = &ps8640_bridge_funcs; ps_bridge->bridge.of_node = dev->of_node; + ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; + ps_bridge->bridge.type = DRM_MODE_CONNECTOR_eDP; ps_bridge->page[PAGE0_DP_CNTL] = client; diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c new file mode 100644 index 000000000000..1bfdfc6affaf --- /dev/null +++ b/drivers/gpu/drm/bridge/tc358762.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Marek Vasut <[email protected]> + * + * Based on tc358764.c by + * Andrzej Hajda <[email protected]> + * Maciej Purski <[email protected]> + * + * Based on rpi_touchscreen.c by + * Eric Anholt <[email protected]> + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/of_graph.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_of.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> +#include <drm/drm_probe_helper.h> + +/* PPI layer registers */ +#define PPI_STARTPPI 0x0104 /* START control bit */ +#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */ +#define PPI_D0S_ATMR 0x0144 +#define PPI_D1S_ATMR 0x0148 +#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* Assertion timer for Lane 0 */ +#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* Assertion timer for Lane 1 */ +#define PPI_START_FUNCTION 1 + +/* DSI layer registers */ +#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */ +#define DSI_LANEENABLE 0x0210 /* Enables each lane */ +#define DSI_RX_START 1 + +/* LCDC/DPI Host Registers */ +#define LCDCTRL 0x0420 + +/* SPI Master Registers */ +#define SPICMR 0x0450 +#define SPITCR 0x0454 + +/* System Controller Registers */ +#define SYSCTRL 0x0464 + +/* System registers */ +#define LPX_PERIOD 3 + +/* Lane enable PPI and DSI register bits */ +#define LANEENABLE_CLEN BIT(0) +#define LANEENABLE_L0EN BIT(1) +#define LANEENABLE_L1EN BIT(2) + +struct tc358762 { + struct device *dev; + struct drm_bridge bridge; + struct drm_connector connector; + struct regulator *regulator; + struct drm_bridge *panel_bridge; + bool pre_enabled; + int error; +}; + +static int tc358762_clear_error(struct tc358762 *ctx) +{ + int ret = ctx->error; + + ctx->error = 0; + return ret; +} + +static void tc358762_write(struct tc358762 *ctx, u16 addr, u32 val) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + ssize_t ret; + u8 data[6]; + + if (ctx->error) + return; + + data[0] = addr; + data[1] = addr >> 8; + data[2] = val; + data[3] = val >> 8; + data[4] = val >> 16; + data[5] = val >> 24; + + ret = mipi_dsi_generic_write(dsi, data, sizeof(data)); + if (ret < 0) + ctx->error = ret; +} + +static inline struct tc358762 *bridge_to_tc358762(struct drm_bridge *bridge) +{ + return container_of(bridge, struct tc358762, bridge); +} + +static int tc358762_init(struct tc358762 *ctx) +{ + tc358762_write(ctx, DSI_LANEENABLE, + LANEENABLE_L0EN | LANEENABLE_CLEN); + tc358762_write(ctx, PPI_D0S_CLRSIPOCOUNT, 5); + tc358762_write(ctx, PPI_D1S_CLRSIPOCOUNT, 5); + tc358762_write(ctx, PPI_D0S_ATMR, 0); + tc358762_write(ctx, PPI_D1S_ATMR, 0); + tc358762_write(ctx, PPI_LPTXTIMECNT, LPX_PERIOD); + + tc358762_write(ctx, SPICMR, 0x00); + tc358762_write(ctx, LCDCTRL, 0x00100150); + tc358762_write(ctx, SYSCTRL, 0x040f); + msleep(100); + + tc358762_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION); + tc358762_write(ctx, DSI_STARTDSI, DSI_RX_START); + + msleep(100); + + return tc358762_clear_error(ctx); +} + +static void tc358762_post_disable(struct drm_bridge *bridge) +{ + struct tc358762 *ctx = bridge_to_tc358762(bridge); + int ret; + + /* + * The post_disable hook might be called multiple times. + * We want to avoid regulator imbalance below. + */ + if (!ctx->pre_enabled) + return; + + ctx->pre_enabled = false; + + ret = regulator_disable(ctx->regulator); + if (ret < 0) + dev_err(ctx->dev, "error disabling regulators (%d)\n", ret); +} + +static void tc358762_pre_enable(struct drm_bridge *bridge) +{ + struct tc358762 *ctx = bridge_to_tc358762(bridge); + int ret; + + ret = regulator_enable(ctx->regulator); + if (ret < 0) + dev_err(ctx->dev, "error enabling regulators (%d)\n", ret); + + ret = tc358762_init(ctx); + if (ret < 0) + dev_err(ctx->dev, "error initializing bridge (%d)\n", ret); + + ctx->pre_enabled = true; +} + +static int tc358762_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct tc358762 *ctx = bridge_to_tc358762(bridge); + + return drm_bridge_attach(bridge->encoder, ctx->panel_bridge, + bridge, flags); +} + +static const struct drm_bridge_funcs tc358762_bridge_funcs = { + .post_disable = tc358762_post_disable, + .pre_enable = tc358762_pre_enable, + .attach = tc358762_attach, +}; + +static int tc358762_parse_dt(struct tc358762 *ctx) +{ + struct drm_bridge *panel_bridge; + struct device *dev = ctx->dev; + struct drm_panel *panel; + int ret; + + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); + if (ret) + return ret; + + panel_bridge = devm_drm_panel_bridge_add(dev, panel); + + if (IS_ERR(panel_bridge)) + return PTR_ERR(panel_bridge); + + ctx->panel_bridge = panel_bridge; + + return 0; +} + +static int tc358762_configure_regulators(struct tc358762 *ctx) +{ + ctx->regulator = devm_regulator_get(ctx->dev, "vddc"); + if (IS_ERR(ctx->regulator)) + return PTR_ERR(ctx->regulator); + + return 0; +} + +static int tc358762_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct tc358762 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(struct tc358762), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mipi_dsi_set_drvdata(dsi, ctx); + + ctx->dev = dev; + ctx->pre_enabled = false; + + /* TODO: Find out how to get dual-lane mode working */ + dsi->lanes = 1; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM; + + ret = tc358762_parse_dt(ctx); + if (ret < 0) + return ret; + + ret = tc358762_configure_regulators(ctx); + if (ret < 0) + return ret; + + ctx->bridge.funcs = &tc358762_bridge_funcs; + ctx->bridge.type = DRM_MODE_CONNECTOR_DPI; + ctx->bridge.of_node = dev->of_node; + + drm_bridge_add(&ctx->bridge); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_bridge_remove(&ctx->bridge); + dev_err(dev, "failed to attach dsi\n"); + } + + return ret; +} + +static int tc358762_remove(struct mipi_dsi_device *dsi) +{ + struct tc358762 *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_bridge_remove(&ctx->bridge); + + return 0; +} + +static const struct of_device_id tc358762_of_match[] = { + { .compatible = "toshiba,tc358762" }, + { } +}; +MODULE_DEVICE_TABLE(of, tc358762_of_match); + +static struct mipi_dsi_driver tc358762_driver = { + .probe = tc358762_probe, + .remove = tc358762_remove, + .driver = { + .name = "tc358762", + .of_match_table = tc358762_of_match, + }, +}; +module_mipi_dsi_driver(tc358762_driver); + +MODULE_AUTHOR("Marek Vasut <[email protected]>"); +MODULE_DESCRIPTION("MIPI-DSI based Driver for TC358762 DSI/DPI Bridge"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index 5ac1430fab04..d89394bc5aa4 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -153,10 +153,9 @@ static const char * const tc358764_supplies[] = { struct tc358764 { struct device *dev; struct drm_bridge bridge; - struct drm_connector connector; struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)]; struct gpio_desc *gpio_reset; - struct drm_panel *panel; + struct drm_bridge *panel_bridge; int error; }; @@ -210,12 +209,6 @@ static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge) return container_of(bridge, struct tc358764, bridge); } -static inline -struct tc358764 *connector_to_tc358764(struct drm_connector *connector) -{ - return container_of(connector, struct tc358764, connector); -} - static int tc358764_init(struct tc358764 *ctx) { u32 v = 0; @@ -278,43 +271,11 @@ static void tc358764_reset(struct tc358764 *ctx) usleep_range(1000, 2000); } -static int tc358764_get_modes(struct drm_connector *connector) -{ - struct tc358764 *ctx = connector_to_tc358764(connector); - - return drm_panel_get_modes(ctx->panel, connector); -} - -static const -struct drm_connector_helper_funcs tc358764_connector_helper_funcs = { - .get_modes = tc358764_get_modes, -}; - -static const struct drm_connector_funcs tc358764_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static void tc358764_disable(struct drm_bridge *bridge) -{ - struct tc358764 *ctx = bridge_to_tc358764(bridge); - int ret = drm_panel_disable(bridge_to_tc358764(bridge)->panel); - - if (ret < 0) - dev_err(ctx->dev, "error disabling panel (%d)\n", ret); -} - static void tc358764_post_disable(struct drm_bridge *bridge) { struct tc358764 *ctx = bridge_to_tc358764(bridge); int ret; - ret = drm_panel_unprepare(ctx->panel); - if (ret < 0) - dev_err(ctx->dev, "error unpreparing panel (%d)\n", ret); tc358764_reset(ctx); usleep_range(10000, 15000); ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); @@ -335,73 +296,28 @@ static void tc358764_pre_enable(struct drm_bridge *bridge) ret = tc358764_init(ctx); if (ret < 0) dev_err(ctx->dev, "error initializing bridge (%d)\n", ret); - ret = drm_panel_prepare(ctx->panel); - if (ret < 0) - dev_err(ctx->dev, "error preparing panel (%d)\n", ret); -} - -static void tc358764_enable(struct drm_bridge *bridge) -{ - struct tc358764 *ctx = bridge_to_tc358764(bridge); - int ret = drm_panel_enable(ctx->panel); - - if (ret < 0) - dev_err(ctx->dev, "error enabling panel (%d)\n", ret); } static int tc358764_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct tc358764 *ctx = bridge_to_tc358764(bridge); - struct drm_device *drm = bridge->dev; - int ret; - - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } - - ctx->connector.polled = DRM_CONNECTOR_POLL_HPD; - ret = drm_connector_init(drm, &ctx->connector, - &tc358764_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); - if (ret) { - DRM_ERROR("Failed to initialize connector\n"); - return ret; - } - - drm_connector_helper_add(&ctx->connector, - &tc358764_connector_helper_funcs); - drm_connector_attach_encoder(&ctx->connector, bridge->encoder); - drm_panel_attach(ctx->panel, &ctx->connector); - ctx->connector.funcs->reset(&ctx->connector); - drm_connector_register(&ctx->connector); - - return 0; -} - -static void tc358764_detach(struct drm_bridge *bridge) -{ - struct tc358764 *ctx = bridge_to_tc358764(bridge); - drm_connector_unregister(&ctx->connector); - drm_panel_detach(ctx->panel); - ctx->panel = NULL; - drm_connector_put(&ctx->connector); + return drm_bridge_attach(bridge->encoder, ctx->panel_bridge, + bridge, flags); } static const struct drm_bridge_funcs tc358764_bridge_funcs = { - .disable = tc358764_disable, .post_disable = tc358764_post_disable, - .enable = tc358764_enable, .pre_enable = tc358764_pre_enable, .attach = tc358764_attach, - .detach = tc358764_detach, }; static int tc358764_parse_dt(struct tc358764 *ctx) { + struct drm_bridge *panel_bridge; struct device *dev = ctx->dev; + struct drm_panel *panel; int ret; ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); @@ -410,12 +326,16 @@ static int tc358764_parse_dt(struct tc358764 *ctx) return PTR_ERR(ctx->gpio_reset); } - ret = drm_of_find_panel_or_bridge(ctx->dev->of_node, 1, 0, &ctx->panel, - NULL); - if (ret && ret != -EPROBE_DEFER) - dev_err(dev, "cannot find panel (%d)\n", ret); + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); + if (ret) + return ret; - return ret; + panel_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(panel_bridge)) + return PTR_ERR(panel_bridge); + + ctx->panel_bridge = panel_bridge; + return 0; } static int tc358764_configure_regulators(struct tc358764 *ctx) @@ -461,6 +381,7 @@ static int tc358764_probe(struct mipi_dsi_device *dsi) return ret; ctx->bridge.funcs = &tc358764_bridge_funcs; + ctx->bridge.type = DRM_MODE_CONNECTOR_LVDS; ctx->bridge.of_node = dev->of_node; drm_bridge_add(&ctx->bridge); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index c2777b226c75..34a3e4e9f717 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -244,14 +244,12 @@ struct tc_data { struct drm_dp_aux aux; struct drm_bridge bridge; + struct drm_bridge *panel_bridge; struct drm_connector connector; - struct drm_panel *panel; /* link settings */ struct tc_edp_link link; - /* display edid */ - struct edid *edid; /* current mode */ struct drm_display_mode mode; @@ -1236,13 +1234,6 @@ static int tc_stream_disable(struct tc_data *tc) return 0; } -static void tc_bridge_pre_enable(struct drm_bridge *bridge) -{ - struct tc_data *tc = bridge_to_tc(bridge); - - drm_panel_prepare(tc->panel); -} - static void tc_bridge_enable(struct drm_bridge *bridge) { struct tc_data *tc = bridge_to_tc(bridge); @@ -1266,8 +1257,6 @@ static void tc_bridge_enable(struct drm_bridge *bridge) tc_main_link_disable(tc); return; } - - drm_panel_enable(tc->panel); } static void tc_bridge_disable(struct drm_bridge *bridge) @@ -1275,8 +1264,6 @@ static void tc_bridge_disable(struct drm_bridge *bridge) struct tc_data *tc = bridge_to_tc(bridge); int ret; - drm_panel_disable(tc->panel); - ret = tc_stream_disable(tc); if (ret < 0) dev_err(tc->dev, "main link stream stop error: %d\n", ret); @@ -1286,13 +1273,6 @@ static void tc_bridge_disable(struct drm_bridge *bridge) dev_err(tc->dev, "main link disable error: %d\n", ret); } -static void tc_bridge_post_disable(struct drm_bridge *bridge) -{ - struct tc_data *tc = bridge_to_tc(bridge); - - drm_panel_unprepare(tc->panel); -} - static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adj) @@ -1335,11 +1315,19 @@ static void tc_bridge_mode_set(struct drm_bridge *bridge, tc->mode = *mode; } +static struct edid *tc_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct tc_data *tc = bridge_to_tc(bridge); + + return drm_get_edid(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; - int count; int ret; ret = tc_get_display_props(tc); @@ -1348,42 +1336,30 @@ static int tc_connector_get_modes(struct drm_connector *connector) return 0; } - count = drm_panel_get_modes(tc->panel, connector); - if (count > 0) - return count; - - edid = drm_get_edid(connector, &tc->aux.ddc); - - kfree(tc->edid); - tc->edid = edid; - if (!edid) - return 0; + if (tc->panel_bridge) { + num_modes = drm_bridge_get_modes(tc->panel_bridge, connector); + if (num_modes > 0) + return num_modes; + } - drm_connector_update_edid_property(connector, edid); - count = drm_add_edid_modes(connector, edid); + edid = tc_get_edid(&tc->bridge, connector); + num_modes = drm_add_edid_modes(connector, edid); + kfree(edid); - return count; + return num_modes; } static const struct drm_connector_helper_funcs tc_connector_helper_funcs = { .get_modes = tc_connector_get_modes, }; -static enum drm_connector_status tc_connector_detect(struct drm_connector *connector, - bool force) +static enum drm_connector_status tc_bridge_detect(struct drm_bridge *bridge) { - struct tc_data *tc = connector_to_tc(connector); + struct tc_data *tc = bridge_to_tc(bridge); bool conn; u32 val; int ret; - if (tc->hpd_pin < 0) { - if (tc->panel) - return connector_status_connected; - else - return connector_status_unknown; - } - ret = regmap_read(tc->regmap, GPIOI, &val); if (ret) return connector_status_unknown; @@ -1396,6 +1372,20 @@ static enum drm_connector_status tc_connector_detect(struct drm_connector *conne return connector_status_disconnected; } +static enum drm_connector_status +tc_connector_detect(struct drm_connector *connector, bool force) +{ + struct tc_data *tc = connector_to_tc(connector); + + if (tc->hpd_pin >= 0) + return tc_bridge_detect(&tc->bridge); + + if (tc->panel_bridge) + return connector_status_connected; + else + return connector_status_unknown; +} + static const struct drm_connector_funcs tc_connector_funcs = { .detect = tc_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, @@ -1413,16 +1403,20 @@ static int tc_bridge_attach(struct drm_bridge *bridge, struct drm_device *drm = bridge->dev; int ret; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; + if (tc->panel_bridge) { + /* If a connector is required then this driver shall create it */ + ret = drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge, + &tc->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) + return ret; } + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; + /* Create DP/eDP connector */ drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs); - ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, - tc->panel ? DRM_MODE_CONNECTOR_eDP : - DRM_MODE_CONNECTOR_DisplayPort); + ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, tc->bridge.type); if (ret) return ret; @@ -1435,9 +1429,6 @@ static int tc_bridge_attach(struct drm_bridge *bridge, DRM_CONNECTOR_POLL_DISCONNECT; } - if (tc->panel) - drm_panel_attach(tc->panel, &tc->connector); - drm_display_info_set_bus_formats(&tc->connector.display_info, &bus_format, 1); tc->connector.display_info.bus_flags = @@ -1453,11 +1444,11 @@ static const struct drm_bridge_funcs tc_bridge_funcs = { .attach = tc_bridge_attach, .mode_valid = tc_mode_valid, .mode_set = tc_bridge_mode_set, - .pre_enable = tc_bridge_pre_enable, .enable = tc_bridge_enable, .disable = tc_bridge_disable, - .post_disable = tc_bridge_post_disable, .mode_fixup = tc_bridge_mode_fixup, + .detect = tc_bridge_detect, + .get_edid = tc_get_edid, }; static bool tc_readable_reg(struct device *dev, unsigned int reg) @@ -1547,6 +1538,7 @@ static irqreturn_t tc_irq_handler(int irq, void *arg) static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; + struct drm_panel *panel; struct tc_data *tc; int ret; @@ -1557,10 +1549,23 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) tc->dev = dev; /* port@2 is the output port */ - ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &tc->panel, NULL); + ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL); if (ret && ret != -ENODEV) return ret; + if (panel) { + struct drm_bridge *panel_bridge; + + panel_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(panel_bridge)) + return PTR_ERR(panel_bridge); + + tc->panel_bridge = panel_bridge; + tc->bridge.type = DRM_MODE_CONNECTOR_eDP; + } else { + tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; + } + /* Shut down GPIO is optional */ tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); if (IS_ERR(tc->sd_gpio)) @@ -1680,6 +1685,10 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) return ret; tc->bridge.funcs = &tc_bridge_funcs; + if (tc->hpd_pin >= 0) + tc->bridge.ops |= DRM_BRIDGE_OP_DETECT; + tc->bridge.ops |= DRM_BRIDGE_OP_EDID; + tc->bridge.of_node = dev->of_node; drm_bridge_add(&tc->bridge); diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c new file mode 100644 index 000000000000..d951cdc58297 --- /dev/null +++ b/drivers/gpu/drm/bridge/tc358775.c @@ -0,0 +1,749 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TC358775 DSI to LVDS bridge driver + * + * Copyright (C) 2020 SMART Wireless Computing + * Author: Vinay Simha BN <[email protected]> + * + */ +/* #define DEBUG */ +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +#include <asm/unaligned.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_dp_helper.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_of.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +#define FLD_VAL(val, start, end) FIELD_PREP(GENMASK(start, end), val) + +/* Registers */ + +/* DSI D-PHY Layer Registers */ +#define D0W_DPHYCONTTX 0x0004 /* Data Lane 0 DPHY Tx Control */ +#define CLW_DPHYCONTRX 0x0020 /* Clock Lane DPHY Rx Control */ +#define D0W_DPHYCONTRX 0x0024 /* Data Lane 0 DPHY Rx Control */ +#define D1W_DPHYCONTRX 0x0028 /* Data Lane 1 DPHY Rx Control */ +#define D2W_DPHYCONTRX 0x002C /* Data Lane 2 DPHY Rx Control */ +#define D3W_DPHYCONTRX 0x0030 /* Data Lane 3 DPHY Rx Control */ +#define COM_DPHYCONTRX 0x0038 /* DPHY Rx Common Control */ +#define CLW_CNTRL 0x0040 /* Clock Lane Control */ +#define D0W_CNTRL 0x0044 /* Data Lane 0 Control */ +#define D1W_CNTRL 0x0048 /* Data Lane 1 Control */ +#define D2W_CNTRL 0x004C /* Data Lane 2 Control */ +#define D3W_CNTRL 0x0050 /* Data Lane 3 Control */ +#define DFTMODE_CNTRL 0x0054 /* DFT Mode Control */ + +/* DSI PPI Layer Registers */ +#define PPI_STARTPPI 0x0104 /* START control bit of PPI-TX function. */ +#define PPI_START_FUNCTION 1 + +#define PPI_BUSYPPI 0x0108 +#define PPI_LINEINITCNT 0x0110 /* Line Initialization Wait Counter */ +#define PPI_LPTXTIMECNT 0x0114 +#define PPI_LANEENABLE 0x0134 /* Enables each lane at the PPI layer. */ +#define PPI_TX_RX_TA 0x013C /* DSI Bus Turn Around timing parameters */ + +/* Analog timer function enable */ +#define PPI_CLS_ATMR 0x0140 /* Delay for Clock Lane in LPRX */ +#define PPI_D0S_ATMR 0x0144 /* Delay for Data Lane 0 in LPRX */ +#define PPI_D1S_ATMR 0x0148 /* Delay for Data Lane 1 in LPRX */ +#define PPI_D2S_ATMR 0x014C /* Delay for Data Lane 2 in LPRX */ +#define PPI_D3S_ATMR 0x0150 /* Delay for Data Lane 3 in LPRX */ + +#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* For lane 0 */ +#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* For lane 1 */ +#define PPI_D2S_CLRSIPOCOUNT 0x016C /* For lane 2 */ +#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* For lane 3 */ + +#define CLS_PRE 0x0180 /* Digital Counter inside of PHY IO */ +#define D0S_PRE 0x0184 /* Digital Counter inside of PHY IO */ +#define D1S_PRE 0x0188 /* Digital Counter inside of PHY IO */ +#define D2S_PRE 0x018C /* Digital Counter inside of PHY IO */ +#define D3S_PRE 0x0190 /* Digital Counter inside of PHY IO */ +#define CLS_PREP 0x01A0 /* Digital Counter inside of PHY IO */ +#define D0S_PREP 0x01A4 /* Digital Counter inside of PHY IO */ +#define D1S_PREP 0x01A8 /* Digital Counter inside of PHY IO */ +#define D2S_PREP 0x01AC /* Digital Counter inside of PHY IO */ +#define D3S_PREP 0x01B0 /* Digital Counter inside of PHY IO */ +#define CLS_ZERO 0x01C0 /* Digital Counter inside of PHY IO */ +#define D0S_ZERO 0x01C4 /* Digital Counter inside of PHY IO */ +#define D1S_ZERO 0x01C8 /* Digital Counter inside of PHY IO */ +#define D2S_ZERO 0x01CC /* Digital Counter inside of PHY IO */ +#define D3S_ZERO 0x01D0 /* Digital Counter inside of PHY IO */ + +#define PPI_CLRFLG 0x01E0 /* PRE Counters has reached set values */ +#define PPI_CLRSIPO 0x01E4 /* Clear SIPO values, Slave mode use only. */ +#define HSTIMEOUT 0x01F0 /* HS Rx Time Out Counter */ +#define HSTIMEOUTENABLE 0x01F4 /* Enable HS Rx Time Out Counter */ +#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX function */ +#define DSI_RX_START 1 + +#define DSI_BUSYDSI 0x0208 +#define DSI_LANEENABLE 0x0210 /* Enables each lane at the Protocol layer. */ +#define DSI_LANESTATUS0 0x0214 /* Displays lane is in HS RX mode. */ +#define DSI_LANESTATUS1 0x0218 /* Displays lane is in ULPS or STOP state */ + +#define DSI_INTSTATUS 0x0220 /* Interrupt Status */ +#define DSI_INTMASK 0x0224 /* Interrupt Mask */ +#define DSI_INTCLR 0x0228 /* Interrupt Clear */ +#define DSI_LPTXTO 0x0230 /* Low Power Tx Time Out Counter */ + +#define DSIERRCNT 0x0300 /* DSI Error Count */ +#define APLCTRL 0x0400 /* Application Layer Control */ +#define RDPKTLN 0x0404 /* Command Read Packet Length */ + +#define VPCTRL 0x0450 /* Video Path Control */ +#define HTIM1 0x0454 /* Horizontal Timing Control 1 */ +#define HTIM2 0x0458 /* Horizontal Timing Control 2 */ +#define VTIM1 0x045C /* Vertical Timing Control 1 */ +#define VTIM2 0x0460 /* Vertical Timing Control 2 */ +#define VFUEN 0x0464 /* Video Frame Timing Update Enable */ +#define VFUEN_EN BIT(0) /* Upload Enable */ + +/* Mux Input Select for LVDS LINK Input */ +#define LV_MX0003 0x0480 /* Bit 0 to 3 */ +#define LV_MX0407 0x0484 /* Bit 4 to 7 */ +#define LV_MX0811 0x0488 /* Bit 8 to 11 */ +#define LV_MX1215 0x048C /* Bit 12 to 15 */ +#define LV_MX1619 0x0490 /* Bit 16 to 19 */ +#define LV_MX2023 0x0494 /* Bit 20 to 23 */ +#define LV_MX2427 0x0498 /* Bit 24 to 27 */ +#define LV_MX(b0, b1, b2, b3) (FLD_VAL(b0, 4, 0) | FLD_VAL(b1, 12, 8) | \ + FLD_VAL(b2, 20, 16) | FLD_VAL(b3, 28, 24)) + +/* Input bit numbers used in mux registers */ +enum { + LVI_R0, + LVI_R1, + LVI_R2, + LVI_R3, + LVI_R4, + LVI_R5, + LVI_R6, + LVI_R7, + LVI_G0, + LVI_G1, + LVI_G2, + LVI_G3, + LVI_G4, + LVI_G5, + LVI_G6, + LVI_G7, + LVI_B0, + LVI_B1, + LVI_B2, + LVI_B3, + LVI_B4, + LVI_B5, + LVI_B6, + LVI_B7, + LVI_HS, + LVI_VS, + LVI_DE, + LVI_L0 +}; + +#define LVCFG 0x049C /* LVDS Configuration */ +#define LVPHY0 0x04A0 /* LVDS PHY 0 */ +#define LV_PHY0_RST(v) FLD_VAL(v, 22, 22) /* PHY reset */ +#define LV_PHY0_IS(v) FLD_VAL(v, 15, 14) +#define LV_PHY0_ND(v) FLD_VAL(v, 4, 0) /* Frequency range select */ +#define LV_PHY0_PRBS_ON(v) FLD_VAL(v, 20, 16) /* Clock/Data Flag pins */ + +#define LVPHY1 0x04A4 /* LVDS PHY 1 */ +#define SYSSTAT 0x0500 /* System Status */ +#define SYSRST 0x0504 /* System Reset */ + +#define SYS_RST_I2CS BIT(0) /* Reset I2C-Slave controller */ +#define SYS_RST_I2CM BIT(1) /* Reset I2C-Master controller */ +#define SYS_RST_LCD BIT(2) /* Reset LCD controller */ +#define SYS_RST_BM BIT(3) /* Reset Bus Management controller */ +#define SYS_RST_DSIRX BIT(4) /* Reset DSI-RX and App controller */ +#define SYS_RST_REG BIT(5) /* Reset Register module */ + +/* GPIO Registers */ +#define GPIOC 0x0520 /* GPIO Control */ +#define GPIOO 0x0524 /* GPIO Output */ +#define GPIOI 0x0528 /* GPIO Input */ + +/* I2C Registers */ +#define I2CTIMCTRL 0x0540 /* I2C IF Timing and Enable Control */ +#define I2CMADDR 0x0544 /* I2C Master Addressing */ +#define WDATAQ 0x0548 /* Write Data Queue */ +#define RDATAQ 0x054C /* Read Data Queue */ + +/* Chip ID and Revision ID Register */ +#define IDREG 0x0580 + +#define LPX_PERIOD 4 +#define TTA_GET 0x40000 +#define TTA_SURE 6 +#define SINGLE_LINK 1 +#define DUAL_LINK 2 + +#define TC358775XBG_ID 0x00007500 + +/* Debug Registers */ +#define DEBUG00 0x05A0 /* Debug */ +#define DEBUG01 0x05A4 /* LVDS Data */ + +#define DSI_CLEN_BIT BIT(0) +#define DIVIDE_BY_3 3 /* PCLK=DCLK/3 */ +#define DIVIDE_BY_6 6 /* PCLK=DCLK/6 */ +#define LVCFG_LVEN_BIT BIT(0) + +#define L0EN BIT(1) + +#define TC358775_VPCTRL_VSDELAY__MASK 0x3FF00000 +#define TC358775_VPCTRL_VSDELAY__SHIFT 20 +static inline u32 TC358775_VPCTRL_VSDELAY(uint32_t val) +{ + return ((val) << TC358775_VPCTRL_VSDELAY__SHIFT) & + TC358775_VPCTRL_VSDELAY__MASK; +} + +#define TC358775_VPCTRL_OPXLFMT__MASK 0x00000100 +#define TC358775_VPCTRL_OPXLFMT__SHIFT 8 +static inline u32 TC358775_VPCTRL_OPXLFMT(uint32_t val) +{ + return ((val) << TC358775_VPCTRL_OPXLFMT__SHIFT) & + TC358775_VPCTRL_OPXLFMT__MASK; +} + +#define TC358775_VPCTRL_MSF__MASK 0x00000001 +#define TC358775_VPCTRL_MSF__SHIFT 0 +static inline u32 TC358775_VPCTRL_MSF(uint32_t val) +{ + return ((val) << TC358775_VPCTRL_MSF__SHIFT) & + TC358775_VPCTRL_MSF__MASK; +} + +#define TC358775_LVCFG_PCLKDIV__MASK 0x000000f0 +#define TC358775_LVCFG_PCLKDIV__SHIFT 4 +static inline u32 TC358775_LVCFG_PCLKDIV(uint32_t val) +{ + return ((val) << TC358775_LVCFG_PCLKDIV__SHIFT) & + TC358775_LVCFG_PCLKDIV__MASK; +} + +#define TC358775_LVCFG_LVDLINK__MASK 0x00000002 +#define TC358775_LVCFG_LVDLINK__SHIFT 0 +static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val) +{ + return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) & + TC358775_LVCFG_LVDLINK__MASK; +} + +enum tc358775_ports { + TC358775_DSI_IN, + TC358775_LVDS_OUT0, + TC358775_LVDS_OUT1, +}; + +struct tc_data { + struct i2c_client *i2c; + struct device *dev; + + struct drm_bridge bridge; + struct drm_bridge *panel_bridge; + + struct device_node *host_node; + struct mipi_dsi_device *dsi; + u8 num_dsi_lanes; + + struct regulator *vdd; + struct regulator *vddio; + struct gpio_desc *reset_gpio; + struct gpio_desc *stby_gpio; + u8 lvds_link; /* single-link or dual-link */ + u8 bpc; +}; + +static inline struct tc_data *bridge_to_tc(struct drm_bridge *b) +{ + return container_of(b, struct tc_data, bridge); +} + +static void tc_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct tc_data *tc = bridge_to_tc(bridge); + struct device *dev = &tc->dsi->dev; + int ret; + + ret = regulator_enable(tc->vddio); + if (ret < 0) + dev_err(dev, "regulator vddio enable failed, %d\n", ret); + usleep_range(10000, 11000); + + ret = regulator_enable(tc->vdd); + if (ret < 0) + dev_err(dev, "regulator vdd enable failed, %d\n", ret); + usleep_range(10000, 11000); + + gpiod_set_value(tc->stby_gpio, 0); + usleep_range(10000, 11000); + + gpiod_set_value(tc->reset_gpio, 0); + usleep_range(10, 20); +} + +static void tc_bridge_post_disable(struct drm_bridge *bridge) +{ + struct tc_data *tc = bridge_to_tc(bridge); + struct device *dev = &tc->dsi->dev; + int ret; + + gpiod_set_value(tc->reset_gpio, 1); + usleep_range(10, 20); + + gpiod_set_value(tc->stby_gpio, 1); + usleep_range(10000, 11000); + + ret = regulator_disable(tc->vdd); + if (ret < 0) + dev_err(dev, "regulator vdd disable failed, %d\n", ret); + usleep_range(10000, 11000); + + ret = regulator_disable(tc->vddio); + if (ret < 0) + dev_err(dev, "regulator vddio disable failed, %d\n", ret); + usleep_range(10000, 11000); +} + +static void d2l_read(struct i2c_client *i2c, u16 addr, u32 *val) +{ + int ret; + u8 buf_addr[2]; + + put_unaligned_be16(addr, buf_addr); + ret = i2c_master_send(i2c, buf_addr, sizeof(buf_addr)); + if (ret < 0) + goto fail; + + ret = i2c_master_recv(i2c, (u8 *)val, sizeof(*val)); + if (ret < 0) + goto fail; + + pr_debug("d2l: I2C : addr:%04x value:%08x\n", addr, *val); + +fail: + dev_err(&i2c->dev, "Error %d reading from subaddress 0x%x\n", + ret, addr); +} + +static void d2l_write(struct i2c_client *i2c, u16 addr, u32 val) +{ + u8 data[6]; + int ret; + + put_unaligned_be16(addr, data); + put_unaligned_le32(val, data + 2); + + ret = i2c_master_send(i2c, data, ARRAY_SIZE(data)); + if (ret < 0) + dev_err(&i2c->dev, "Error %d writing to subaddress 0x%x\n", + ret, addr); +} + +/* helper function to access bus_formats */ +static struct drm_connector *get_connector(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + if (connector->encoder == encoder) + return connector; + + return NULL; +} + +static void tc_bridge_enable(struct drm_bridge *bridge) +{ + struct tc_data *tc = bridge_to_tc(bridge); + u32 hback_porch, hsync_len, hfront_porch, hactive, htime1, htime2; + u32 vback_porch, vsync_len, vfront_porch, vactive, vtime1, vtime2; + u32 val = 0; + u16 dsiclk, clkdiv, byteclk, t1, t2, t3, vsdelay; + struct drm_display_mode *mode; + struct drm_connector *connector = get_connector(bridge->encoder); + + mode = &bridge->encoder->crtc->state->adjusted_mode; + + hback_porch = mode->htotal - mode->hsync_end; + hsync_len = mode->hsync_end - mode->hsync_start; + vback_porch = mode->vtotal - mode->vsync_end; + vsync_len = mode->vsync_end - mode->vsync_start; + + htime1 = (hback_porch << 16) + hsync_len; + vtime1 = (vback_porch << 16) + vsync_len; + + hfront_porch = mode->hsync_start - mode->hdisplay; + hactive = mode->hdisplay; + vfront_porch = mode->vsync_start - mode->vdisplay; + vactive = mode->vdisplay; + + htime2 = (hfront_porch << 16) + hactive; + vtime2 = (vfront_porch << 16) + vactive; + + d2l_read(tc->i2c, IDREG, &val); + + dev_info(tc->dev, "DSI2LVDS Chip ID.%02x Revision ID. %02x **\n", + (val >> 8) & 0xFF, val & 0xFF); + + d2l_write(tc->i2c, SYSRST, SYS_RST_REG | SYS_RST_DSIRX | SYS_RST_BM | + SYS_RST_LCD | SYS_RST_I2CM | SYS_RST_I2CS); + usleep_range(30000, 40000); + + d2l_write(tc->i2c, PPI_TX_RX_TA, TTA_GET | TTA_SURE); + d2l_write(tc->i2c, PPI_LPTXTIMECNT, LPX_PERIOD); + d2l_write(tc->i2c, PPI_D0S_CLRSIPOCOUNT, 3); + d2l_write(tc->i2c, PPI_D1S_CLRSIPOCOUNT, 3); + d2l_write(tc->i2c, PPI_D2S_CLRSIPOCOUNT, 3); + d2l_write(tc->i2c, PPI_D3S_CLRSIPOCOUNT, 3); + + val = ((L0EN << tc->num_dsi_lanes) - L0EN) | DSI_CLEN_BIT; + d2l_write(tc->i2c, PPI_LANEENABLE, val); + d2l_write(tc->i2c, DSI_LANEENABLE, val); + + d2l_write(tc->i2c, PPI_STARTPPI, PPI_START_FUNCTION); + d2l_write(tc->i2c, DSI_STARTDSI, DSI_RX_START); + + if (tc->bpc == 8) + val = TC358775_VPCTRL_OPXLFMT(1); + else /* bpc = 6; */ + val = TC358775_VPCTRL_MSF(1); + + dsiclk = mode->crtc_clock * 3 * tc->bpc / tc->num_dsi_lanes / 1000; + clkdiv = dsiclk / DIVIDE_BY_3 * tc->lvds_link; + byteclk = dsiclk / 4; + t1 = hactive * (tc->bpc * 3 / 8) / tc->num_dsi_lanes; + t2 = ((100000 / clkdiv)) * (hactive + hback_porch + hsync_len + hfront_porch) / 1000; + t3 = ((t2 * byteclk) / 100) - (hactive * (tc->bpc * 3 / 8) / + tc->num_dsi_lanes); + + vsdelay = (clkdiv * (t1 + t3) / byteclk) - hback_porch - hsync_len - hactive; + + val |= TC358775_VPCTRL_VSDELAY(vsdelay); + d2l_write(tc->i2c, VPCTRL, val); + + d2l_write(tc->i2c, HTIM1, htime1); + d2l_write(tc->i2c, VTIM1, vtime1); + d2l_write(tc->i2c, HTIM2, htime2); + d2l_write(tc->i2c, VTIM2, vtime2); + + d2l_write(tc->i2c, VFUEN, VFUEN_EN); + d2l_write(tc->i2c, SYSRST, SYS_RST_LCD); + d2l_write(tc->i2c, LVPHY0, LV_PHY0_PRBS_ON(4) | LV_PHY0_ND(6)); + + dev_dbg(tc->dev, "bus_formats %04x bpc %d\n", + connector->display_info.bus_formats[0], + tc->bpc); + /* + * Default hardware register settings of tc358775 configured + * with MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA jeida-24 format + */ + if (connector->display_info.bus_formats[0] == + MEDIA_BUS_FMT_RGB888_1X7X4_SPWG) { + /* VESA-24 */ + d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3)); + d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_R7, LVI_R5, LVI_G0)); + d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_G6, LVI_G7)); + d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0)); + d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2)); + d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); + d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6)); + } else { /* MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - JEIDA-18 */ + d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3)); + d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_L0, LVI_R5, LVI_G0)); + d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_L0, LVI_L0)); + d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0)); + d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_L0, LVI_L0, LVI_B1, LVI_B2)); + d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); + d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_L0)); + } + + d2l_write(tc->i2c, VFUEN, VFUEN_EN); + + val = LVCFG_LVEN_BIT; + if (tc->lvds_link == DUAL_LINK) { + val |= TC358775_LVCFG_LVDLINK(1); + val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_6); + } else { + val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_3); + }; + d2l_write(tc->i2c, LVCFG, val); +} + +static enum drm_mode_status +tc_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct tc_data *tc = bridge_to_tc(bridge); + + /* + * Maximum pixel clock speed 135MHz for single-link + * 270MHz for dual-link + */ + if ((mode->clock > 135000 && tc->lvds_link == SINGLE_LINK) || + (mode->clock > 270000 && tc->lvds_link == DUAL_LINK)) + return MODE_CLOCK_HIGH; + + switch (info->bus_formats[0]) { + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: + /* RGB888 */ + tc->bpc = 8; + break; + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + /* RGB666 */ + tc->bpc = 6; + break; + default: + dev_warn(tc->dev, + "unsupported LVDS bus format 0x%04x\n", + info->bus_formats[0]); + return MODE_NOMODE; + } + + return MODE_OK; +} + +static int tc358775_parse_dt(struct device_node *np, struct tc_data *tc) +{ + struct device_node *endpoint; + struct device_node *parent; + struct device_node *remote; + struct property *prop; + int len = 0; + + /* + * To get the data-lanes of dsi, we need to access the dsi0_out of port1 + * of dsi0 endpoint from bridge port0 of d2l_in + */ + endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node, + TC358775_DSI_IN, -1); + if (endpoint) { + /* dsi0_out node */ + parent = of_graph_get_remote_port_parent(endpoint); + of_node_put(endpoint); + if (parent) { + /* dsi0 port 1 */ + endpoint = of_graph_get_endpoint_by_regs(parent, 1, -1); + of_node_put(parent); + if (endpoint) { + prop = of_find_property(endpoint, "data-lanes", + &len); + of_node_put(endpoint); + if (!prop) { + dev_err(tc->dev, + "failed to find data lane\n"); + return -EPROBE_DEFER; + } + } + } + } + + tc->num_dsi_lanes = len / sizeof(u32); + + if (tc->num_dsi_lanes < 1 || tc->num_dsi_lanes > 4) + return -EINVAL; + + tc->host_node = of_graph_get_remote_node(np, 0, 0); + if (!tc->host_node) + return -ENODEV; + + of_node_put(tc->host_node); + + tc->lvds_link = SINGLE_LINK; + endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node, + TC358775_LVDS_OUT1, -1); + if (endpoint) { + remote = of_graph_get_remote_port_parent(endpoint); + of_node_put(endpoint); + + if (remote) { + if (of_device_is_available(remote)) + tc->lvds_link = DUAL_LINK; + of_node_put(remote); + } + } + + dev_dbg(tc->dev, "no.of dsi lanes: %d\n", tc->num_dsi_lanes); + dev_dbg(tc->dev, "operating in %d-link mode\n", tc->lvds_link); + + return 0; +} + +static int tc_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct tc_data *tc = bridge_to_tc(bridge); + struct device *dev = &tc->i2c->dev; + struct mipi_dsi_host *host; + struct mipi_dsi_device *dsi; + int ret; + + const struct mipi_dsi_device_info info = { .type = "tc358775", + .channel = 0, + .node = NULL, + }; + + host = of_find_mipi_dsi_host_by_node(tc->host_node); + if (!host) { + dev_err(dev, "failed to find dsi host\n"); + return -EPROBE_DEFER; + } + + dsi = mipi_dsi_device_register_full(host, &info); + if (IS_ERR(dsi)) { + dev_err(dev, "failed to create dsi device\n"); + ret = PTR_ERR(dsi); + goto err_dsi_device; + } + + tc->dsi = dsi; + + dsi->lanes = tc->num_dsi_lanes; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "failed to attach dsi to host\n"); + goto err_dsi_attach; + } + + /* Attach the panel-bridge to the dsi bridge */ + return drm_bridge_attach(bridge->encoder, tc->panel_bridge, + &tc->bridge, flags); +err_dsi_attach: + mipi_dsi_device_unregister(dsi); +err_dsi_device: + return ret; +} + +static const struct drm_bridge_funcs tc_bridge_funcs = { + .attach = tc_bridge_attach, + .pre_enable = tc_bridge_pre_enable, + .enable = tc_bridge_enable, + .mode_valid = tc_mode_valid, + .post_disable = tc_bridge_post_disable, +}; + +static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct drm_panel *panel; + struct tc_data *tc; + int ret; + + tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL); + if (!tc) + return -ENOMEM; + + tc->dev = dev; + tc->i2c = client; + + ret = drm_of_find_panel_or_bridge(dev->of_node, TC358775_LVDS_OUT0, + 0, &panel, NULL); + if (ret < 0) + return ret; + if (!panel) + return -ENODEV; + + tc->panel_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(tc->panel_bridge)) + return PTR_ERR(tc->panel_bridge); + + ret = tc358775_parse_dt(dev->of_node, tc); + if (ret) + return ret; + + tc->vddio = devm_regulator_get(dev, "vddio-supply"); + if (IS_ERR(tc->vddio)) { + ret = PTR_ERR(tc->vddio); + dev_err(dev, "vddio-supply not found\n"); + return ret; + } + + tc->vdd = devm_regulator_get(dev, "vdd-supply"); + if (IS_ERR(tc->vdd)) { + ret = PTR_ERR(tc->vdd); + dev_err(dev, "vdd-supply not found\n"); + return ret; + } + + tc->stby_gpio = devm_gpiod_get(dev, "stby", GPIOD_OUT_HIGH); + if (IS_ERR(tc->stby_gpio)) { + ret = PTR_ERR(tc->stby_gpio); + dev_err(dev, "cannot get stby-gpio %d\n", ret); + return ret; + } + + tc->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(tc->reset_gpio)) { + ret = PTR_ERR(tc->reset_gpio); + dev_err(dev, "cannot get reset-gpios %d\n", ret); + return ret; + } + + tc->bridge.funcs = &tc_bridge_funcs; + tc->bridge.of_node = dev->of_node; + drm_bridge_add(&tc->bridge); + + i2c_set_clientdata(client, tc); + + return 0; +} + +static int tc_remove(struct i2c_client *client) +{ + struct tc_data *tc = i2c_get_clientdata(client); + + drm_bridge_remove(&tc->bridge); + + return 0; +} + +static const struct i2c_device_id tc358775_i2c_ids[] = { + { "tc358775", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tc358775_i2c_ids); + +static const struct of_device_id tc358775_of_ids[] = { + { .compatible = "toshiba,tc358775", }, + { } +}; +MODULE_DEVICE_TABLE(of, tc358775_of_ids); + +static struct i2c_driver tc358775_driver = { + .driver = { + .name = "tc358775", + .of_match_table = tc358775_of_ids, + }, + .id_table = tc358775_i2c_ids, + .probe = tc_probe, + .remove = tc_remove, +}; +module_i2c_driver(tc358775_driver); + +MODULE_AUTHOR("Vinay Simha BN <[email protected]>"); +MODULE_DESCRIPTION("TC358775 DSI/LVDS bridge driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 5b6e19ecbc84..ecdf9b01340f 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -394,9 +394,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, } pdata->dsi = dsi; - /* attach panel to bridge */ - drm_panel_attach(pdata->panel, &pdata->connector); - return 0; err_dsi_attach: diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index c6994fe673f3..a58cbde59c34 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -187,6 +187,7 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force) case DRM_MODE_CONNECTOR_DPI: case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_DSI: + case DRM_MODE_CONNECTOR_eDP: status = connector_status_connected; break; default: diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 00e40a26a800..3d48ad1c3682 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -850,7 +850,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ }; @@ -867,7 +867,7 @@ static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ @@ -876,6 +876,19 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, drm_tv_subconnector_enum_list) +static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = { + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ + { DRM_MODE_SUBCONNECTOR_VGA, "VGA" }, /* DP */ + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DP */ + { DRM_MODE_SUBCONNECTOR_HDMIA, "HDMI" }, /* DP */ + { DRM_MODE_SUBCONNECTOR_DisplayPort, "DP" }, /* DP */ + { DRM_MODE_SUBCONNECTOR_Wireless, "Wireless" }, /* DP */ + { DRM_MODE_SUBCONNECTOR_Native, "Native" }, /* DP */ +}; + +DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name, + drm_dp_subconnector_enum_list) + static const struct drm_prop_enum_list hdmi_colorspaces[] = { /* For Default case, driver will set the colorspace */ { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, @@ -1217,6 +1230,14 @@ static const struct drm_prop_enum_list dp_colorspaces[] = { * can also expose this property to external outputs, in which case they * must support "None", which should be the default (since external screens * have a built-in scaler). + * + * subconnector: + * This property is used by DVI-I, TVout and DisplayPort to indicate different + * connector subtypes. Enum values more or less match with those from main + * connector types. + * For DVI-I and TVout there is also a matching property "select subconnector" + * allowing to switch between signal types. + * DP subconnector corresponds to a downstream port. */ int drm_connector_create_standard_properties(struct drm_device *dev) @@ -1306,6 +1327,30 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev) EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); /** + * drm_connector_attach_dp_subconnector_property - create subconnector property for DP + * @connector: drm_connector to attach property + * + * Called by a driver when DP connector is created. + */ +void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector) +{ + struct drm_mode_config *mode_config = &connector->dev->mode_config; + + if (!mode_config->dp_subconnector_property) + mode_config->dp_subconnector_property = + drm_property_create_enum(connector->dev, + DRM_MODE_PROP_IMMUTABLE, + "subconnector", + drm_dp_subconnector_enum_list, + ARRAY_SIZE(drm_dp_subconnector_enum_list)); + + drm_object_attach_property(&connector->base, + mode_config->dp_subconnector_property, + DRM_MODE_SUBCONNECTOR_Unknown); +} +EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property); + +/** * DOC: HDMI connector properties * * content type (HDMI specific): diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 092c8c985911..ad7c03dac467 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -597,6 +597,77 @@ void drm_dp_downstream_debug(struct seq_file *m, } EXPORT_SYMBOL(drm_dp_downstream_debug); +/** + * drm_dp_subconnector_type() - get DP branch device type + * + */ +enum drm_mode_subconnector +drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]) +{ + int type; + if (!drm_dp_is_branch(dpcd)) + return DRM_MODE_SUBCONNECTOR_Native; + /* DP 1.0 approach */ + if (dpcd[DP_DPCD_REV] == DP_DPCD_REV_10) { + type = dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DWN_STRM_PORT_TYPE_MASK; + + switch (type) { + case DP_DWN_STRM_PORT_TYPE_TMDS: + /* Can be HDMI or DVI-D, DVI-D is a safer option */ + return DRM_MODE_SUBCONNECTOR_DVID; + case DP_DWN_STRM_PORT_TYPE_ANALOG: + /* Can be VGA or DVI-A, VGA is more popular */ + return DRM_MODE_SUBCONNECTOR_VGA; + case DP_DWN_STRM_PORT_TYPE_DP: + return DRM_MODE_SUBCONNECTOR_DisplayPort; + case DP_DWN_STRM_PORT_TYPE_OTHER: + default: + return DRM_MODE_SUBCONNECTOR_Unknown; + } + } + type = port_cap[0] & DP_DS_PORT_TYPE_MASK; + + switch (type) { + case DP_DS_PORT_TYPE_DP: + case DP_DS_PORT_TYPE_DP_DUALMODE: + return DRM_MODE_SUBCONNECTOR_DisplayPort; + case DP_DS_PORT_TYPE_VGA: + return DRM_MODE_SUBCONNECTOR_VGA; + case DP_DS_PORT_TYPE_DVI: + return DRM_MODE_SUBCONNECTOR_DVID; + case DP_DS_PORT_TYPE_HDMI: + return DRM_MODE_SUBCONNECTOR_HDMIA; + case DP_DS_PORT_TYPE_WIRELESS: + return DRM_MODE_SUBCONNECTOR_Wireless; + case DP_DS_PORT_TYPE_NON_EDID: + default: + return DRM_MODE_SUBCONNECTOR_Unknown; + } +} +EXPORT_SYMBOL(drm_dp_subconnector_type); + +/** + * drm_mode_set_dp_subconnector_property - set subconnector for DP connector + * + * Called by a driver on every detect event. + */ +void drm_dp_set_subconnector_property(struct drm_connector *connector, + enum drm_connector_status status, + const u8 *dpcd, + const u8 port_cap[4]) +{ + enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown; + + if (status == connector_status_connected) + subconnector = drm_dp_subconnector_type(dpcd, port_cap); + drm_object_property_set_value(&connector->base, + connector->dev->mode_config.dp_subconnector_property, + subconnector); +} +EXPORT_SYMBOL(drm_dp_set_subconnector_property); + /* * I2C-over-AUX implementation */ diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 3296ed3df358..545a877406f4 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -653,7 +653,7 @@ static void drm_gem_vram_bo_driver_evict_flags(struct drm_gem_vram_object *gbo, static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo, bool evict, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct ttm_bo_kmap_obj *kmap = &gbo->kmap; @@ -1004,28 +1004,6 @@ err_ttm_tt_init: return NULL; } -static int bo_driver_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, - struct ttm_mem_type_manager *man) -{ - switch (type) { - case TTM_PL_SYSTEM: - man->flags = 0; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case TTM_PL_VRAM: - man->func = &ttm_bo_manager_func; - man->flags = TTM_MEMTYPE_FLAG_FIXED; - man->available_caching = TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; - break; - default: - return -EINVAL; - } - return 0; -} - static void bo_driver_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement) { @@ -1042,7 +1020,7 @@ static void bo_driver_evict_flags(struct ttm_buffer_object *bo, static void bo_driver_move_notify(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct drm_gem_vram_object *gbo; @@ -1056,18 +1034,12 @@ static void bo_driver_move_notify(struct ttm_buffer_object *bo, } static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bdev); - mem->bus.addr = NULL; - mem->bus.size = mem->num_pages << PAGE_SHIFT; - switch (mem->mem_type) { case TTM_PL_SYSTEM: /* nothing to do */ - mem->bus.offset = 0; - mem->bus.base = 0; - mem->bus.is_iomem = false; break; case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; @@ -1083,9 +1055,6 @@ static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev, static struct ttm_bo_driver bo_driver = { .ttm_tt_create = bo_driver_ttm_tt_create, - .ttm_tt_populate = ttm_pool_populate, - .ttm_tt_unpopulate = ttm_pool_unpopulate, - .init_mem_type = bo_driver_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = bo_driver_evict_flags, .move_notify = bo_driver_move_notify, @@ -1100,12 +1069,10 @@ static int drm_vram_mm_debugfs(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_vram_mm *vmm = node->minor->dev->vram_mm; - struct drm_mm *mm = vmm->bdev.man[TTM_PL_VRAM].priv; + struct ttm_resource_manager *man = ttm_manager_type(&vmm->bdev, TTM_PL_VRAM); struct drm_printer p = drm_seq_file_printer(m); - spin_lock(&ttm_bo_glob.lru_lock); - drm_mm_print(mm, &p); - spin_unlock(&ttm_bo_glob.lru_lock); + ttm_resource_manager_debug(man, &p); return 0; } @@ -1142,7 +1109,10 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev, if (ret) return ret; - ret = ttm_bo_init_mm(&vmm->bdev, TTM_PL_VRAM, vram_size >> PAGE_SHIFT); + ret = ttm_range_man_init(&vmm->bdev, TTM_PL_VRAM, + TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC, + TTM_PL_FLAG_WC, false, + vram_size >> PAGE_SHIFT); if (ret) return ret; @@ -1151,6 +1121,7 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev, static void drm_vram_mm_cleanup(struct drm_vram_mm *vmm) { + ttm_range_man_fini(&vmm->bdev, TTM_PL_VRAM); ttm_bo_device_release(&vmm->bdev); } diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 8c7bac85a793..f634371c717a 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -70,16 +70,12 @@ EXPORT_SYMBOL(drm_panel_init); * * Add a panel to the global registry so that it can be looked up by display * drivers. - * - * Return: 0 on success or a negative error code on failure. */ -int drm_panel_add(struct drm_panel *panel) +void drm_panel_add(struct drm_panel *panel) { mutex_lock(&panel_lock); list_add_tail(&panel->list, &panel_list); mutex_unlock(&panel_lock); - - return 0; } EXPORT_SYMBOL(drm_panel_add); @@ -98,42 +94,6 @@ void drm_panel_remove(struct drm_panel *panel) EXPORT_SYMBOL(drm_panel_remove); /** - * drm_panel_attach - attach a panel to a connector - * @panel: DRM panel - * @connector: DRM connector - * - * After obtaining a pointer to a DRM panel a display driver calls this - * function to attach a panel to a connector. - * - * An error is returned if the panel is already attached to another connector. - * - * When unloading, the driver should detach from the panel by calling - * drm_panel_detach(). - * - * Return: 0 on success or a negative error code on failure. - */ -int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector) -{ - return 0; -} -EXPORT_SYMBOL(drm_panel_attach); - -/** - * drm_panel_detach - detach a panel from a connector - * @panel: DRM panel - * - * Detaches a panel from the connector it is attached to. If a panel is not - * attached to any connector this is effectively a no-op. - * - * This function should not be called by the panel device itself. It - * is only for the drm device that called drm_panel_attach(). - */ -void drm_panel_detach(struct drm_panel *panel) -{ -} -EXPORT_SYMBOL(drm_panel_detach); - -/** * drm_panel_prepare - power on a panel * @panel: DRM panel * @@ -300,6 +260,49 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) return ERR_PTR(-EPROBE_DEFER); } EXPORT_SYMBOL(of_drm_find_panel); + +/** + * of_drm_get_panel_orientation - look up the orientation of the panel through + * the "rotation" binding from a device tree node + * @np: device tree node of the panel + * @orientation: orientation enum to be filled in + * + * Looks up the rotation of a panel in the device tree. The orientation of the + * panel is expressed as a property name "rotation" in the device tree. The + * rotation in the device tree is counter clockwise. + * + * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the + * rotation property doesn't exist. Return a negative error code on failure. + */ +int of_drm_get_panel_orientation(const struct device_node *np, + enum drm_panel_orientation *orientation) +{ + int rotation, ret; + + ret = of_property_read_u32(np, "rotation", &rotation); + if (ret == -EINVAL) { + /* Don't return an error if there's no rotation property. */ + *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; + return 0; + } + + if (ret < 0) + return ret; + + if (rotation == 0) + *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; + else if (rotation == 90) + *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; + else if (rotation == 180) + *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; + else if (rotation == 270) + *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP; + else + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(of_drm_get_panel_orientation); #endif #if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 3bf73971daf3..6e74e6745eca 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -297,7 +297,7 @@ void drm_syncobj_add_point(struct drm_syncobj *syncobj, prev = drm_syncobj_fence_get(syncobj); /* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */ if (prev && prev->seqno >= point) - DRM_ERROR("You are adding an unorder point to timeline!\n"); + DRM_DEBUG("You are adding an unorder point to timeline!\n"); dma_fence_chain_init(chain, prev, fence, point); rcu_assign_pointer(syncobj->fence, &chain->base); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 7ba5354e7d94..741323a2e6c3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -42,11 +42,6 @@ static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e) static enum drm_connector_status exynos_dpi_detect(struct drm_connector *connector, bool force) { - struct exynos_dpi *ctx = connector_to_dpi(connector); - - if (ctx->panel) - drm_panel_attach(ctx->panel, &ctx->connector); - return connector_status_connected; } @@ -249,8 +244,5 @@ int exynos_dpi_remove(struct drm_encoder *encoder) exynos_dpi_disable(&ctx->encoder); - if (ctx->panel) - drm_panel_detach(ctx->panel); - return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index b38e9b592b8a..1a1a2853a842 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1551,12 +1551,10 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, } dsi->panel = of_drm_find_panel(device->dev.of_node); - if (IS_ERR(dsi->panel)) { + if (IS_ERR(dsi->panel)) dsi->panel = NULL; - } else { - drm_panel_attach(dsi->panel, &dsi->connector); + else dsi->connector.status = connector_status_connected; - } } /* @@ -1596,7 +1594,6 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, if (dsi->panel) { mutex_lock(&drm->mode_config.mutex); exynos_dsi_disable(&dsi->encoder); - drm_panel_detach(dsi->panel); dsi->panel = NULL; dsi->connector.status = connector_status_disconnected; mutex_unlock(&drm->mode_config.mutex); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index 9b0c4736c21a..4d4a715b429d 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -40,10 +40,7 @@ int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev, static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector) { - struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector); - drm_connector_unregister(connector); - drm_panel_detach(fsl_con->panel); drm_connector_cleanup(connector); } @@ -101,12 +98,6 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev, if (ret < 0) goto err_sysfs; - ret = drm_panel_attach(panel, connector); - if (ret) { - dev_err(fsl_dev->dev, "failed to attach panel\n"); - goto err_sysfs; - } - return 0; err_sysfs: diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index f41cbb753bb4..720a767118c9 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -2078,7 +2078,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev intel_dp->dpcd, sizeof(intel_dp->dpcd)); cdv_intel_edp_panel_vdd_off(gma_encoder); - if (ret == 0) { + if (ret <= 0) { /* if this fails, presume the device is a ghost */ DRM_INFO("failed to retrieve link info, disabling eDP\n"); drm_encoder_cleanup(encoder); diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c index b718efccdcf2..be9cf6b1e3b3 100644 --- a/drivers/gpu/drm/gma500/mdfld_device.c +++ b/drivers/gpu/drm/gma500/mdfld_device.c @@ -6,6 +6,7 @@ **************************************************************************/ #include <linux/delay.h> +#include <linux/gpio/machine.h> #include <asm/intel_scu_ipc.h> @@ -505,12 +506,31 @@ static const struct psb_offset mdfld_regmap[3] = { }, }; +/* + * The GPIO lines for resetting DSI pipe 0 and 2 are available in the + * PCI device 0000:00:0c.0 on the Medfield. + */ +static struct gpiod_lookup_table mdfld_dsi_pipe_gpio_table = { + .table = { + GPIO_LOOKUP("0000:00:0c.0", 128, "dsi-pipe0-reset", + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("0000:00:0c.0", 34, "dsi-pipe2-reset", + GPIO_ACTIVE_HIGH), + { }, + }, +}; + static int mdfld_chip_setup(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; if (pci_enable_msi(dev->pdev)) dev_warn(dev->dev, "Enabling MSI failed!\n"); dev_priv->regmap = mdfld_regmap; + + /* Associate the GPIO lines with the DRM device */ + mdfld_dsi_pipe_gpio_table.dev_id = dev_name(dev->dev); + gpiod_add_lookup_table(&mdfld_dsi_pipe_gpio_table); + return mid_chip_setup(dev); } diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c index c976a9dd9240..ae1223f631a7 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c @@ -955,7 +955,7 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, /* panel hard-reset */ if (p_funcs->reset) { - ret = p_funcs->reset(pipe); + ret = p_funcs->reset(dev, pipe); if (ret) { DRM_ERROR("Panel %d hard-reset failed\n", pipe); return NULL; diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c index f350ac1ead18..4aab76613bd9 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include <linux/moduleparam.h> #include <linux/pm_runtime.h> +#include <linux/gpio/consumer.h> #include <asm/intel_scu_ipc.h> @@ -366,7 +367,7 @@ static enum drm_mode_status mdfld_dsi_connector_mode_valid(struct drm_connector /** * FIXME: current DC has no fitting unit, reject any mode setting * request - * Will figure out a way to do up-scaling(pannel fitting) later. + * Will figure out a way to do up-scaling(panel fitting) later. **/ if (fixed_mode) { if (mode->hdisplay != fixed_mode->hdisplay) @@ -432,42 +433,42 @@ static int mdfld_dsi_get_default_config(struct drm_device *dev, return 0; } -int mdfld_dsi_panel_reset(int pipe) +int mdfld_dsi_panel_reset(struct drm_device *ddev, int pipe) { - unsigned gpio; - int ret = 0; - + struct device *dev = ddev->dev; + struct gpio_desc *gpiod; + + /* + * Raise the GPIO reset line for the corresponding pipe to HIGH, + * this is probably because it is active low so this takes the + * respective pipe out of reset. (We have no code to put it back + * into reset in this driver.) + */ switch (pipe) { case 0: - gpio = 128; + gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); break; case 2: - gpio = 34; + gpiod = gpiod_get(dev, "dsi-pipe2-reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); break; default: - DRM_ERROR("Invalid output\n"); + DRM_DEV_ERROR(dev, "Invalid output pipe\n"); return -EINVAL; } + gpiod_put(gpiod); - ret = gpio_request(gpio, "gfx"); - if (ret) { - DRM_ERROR("gpio_rqueset failed\n"); - return ret; - } - - ret = gpio_direction_output(gpio, 1); - if (ret) { - DRM_ERROR("gpio_direction_output failed\n"); - goto gpio_error; - } + /* Flush posted writes on the device */ + gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_ASIS); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + gpiod_get_value(gpiod); + gpiod_put(gpiod); - gpio_get_value(128); - -gpio_error: - if (gpio_is_valid(gpio)) - gpio_free(gpio); - - return ret; + return 0; } /* @@ -531,7 +532,7 @@ void mdfld_dsi_output_init(struct drm_device *dev, dsi_config->connector = dsi_connector; if (!dsi_config->fixed_mode) { - DRM_ERROR("No pannel fixed mode was found\n"); + DRM_ERROR("No panel fixed mode was found\n"); goto dsi_init_err0; } diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.h b/drivers/gpu/drm/gma500/mdfld_dsi_output.h index 0cccfe400a98..5c0db3c2903f 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.h +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.h @@ -372,6 +372,6 @@ extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode, bool hs); -extern int mdfld_dsi_panel_reset(int pipe); +extern int mdfld_dsi_panel_reset(struct drm_device *dev, int pipe); #endif /*__MDFLD_DSI_OUTPUT_H__*/ diff --git a/drivers/gpu/drm/gma500/mdfld_output.h b/drivers/gpu/drm/gma500/mdfld_output.h index 17a944d70add..37a516cc56be 100644 --- a/drivers/gpu/drm/gma500/mdfld_output.h +++ b/drivers/gpu/drm/gma500/mdfld_output.h @@ -54,7 +54,7 @@ struct panel_funcs { const struct drm_encoder_helper_funcs *encoder_helper_funcs; struct drm_display_mode * (*get_config_mode)(struct drm_device *); int (*get_panel_info)(struct drm_device *, int, struct panel_info *); - int (*reset)(int pipe); + int (*reset)(struct drm_device *, int); void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe); }; diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 3dd5718c3e31..5340225d6997 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -13,7 +13,6 @@ #include <drm/drm_encoder.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> -#include <linux/gpio.h> #include "gma_display.h" /* diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 06e44f47e73e..907f966d6f22 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -125,7 +125,7 @@ struct psb_intel_sdvo { bool is_lvds; /** - * This is sdvo fixed pannel mode pointer + * This is sdvo fixed panel mode pointer */ struct drm_display_mode *sdvo_lvds_fixed_mode; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c index cc70e836522f..4d57ec688f82 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c @@ -17,9 +17,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_vram_helper.h> -#include <drm/drm_plane_helper.h> -#include <drm/drm_print.h> -#include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> #include "hibmc_drm_drv.h" @@ -74,12 +71,12 @@ static int hibmc_plane_atomic_check(struct drm_plane *plane, return PTR_ERR(crtc_state); if (src_w != state->crtc_w || src_h != state->crtc_h) { - DRM_DEBUG_ATOMIC("scale not support\n"); + drm_dbg_atomic(plane->dev, "scale not support\n"); return -EINVAL; } if (state->crtc_x < 0 || state->crtc_y < 0) { - DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n"); + drm_dbg_atomic(plane->dev, "crtc_x/y of drm_plane state is invalid\n"); return -EINVAL; } @@ -90,12 +87,12 @@ static int hibmc_plane_atomic_check(struct drm_plane *plane, crtc_state->adjusted_mode.hdisplay || state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay) { - DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n"); + drm_dbg_atomic(plane->dev, "visible portion of plane is invalid\n"); return -EINVAL; } if (state->fb->pitches[0] % 128 != 0) { - DRM_DEBUG_ATOMIC("wrong stride with 128-byte aligned\n"); + drm_dbg_atomic(plane->dev, "wrong stride with 128-byte aligned\n"); return -EINVAL; } return 0; @@ -160,37 +157,6 @@ static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = { .atomic_update = hibmc_plane_atomic_update, }; -static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv) -{ - struct drm_device *dev = priv->dev; - struct drm_plane *plane; - int ret = 0; - - plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL); - if (!plane) { - DRM_ERROR("failed to alloc memory when init plane\n"); - return ERR_PTR(-ENOMEM); - } - /* - * plane init - * TODO: Now only support primary plane, overlay planes - * need to do. - */ - ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs, - channel_formats1, - ARRAY_SIZE(channel_formats1), - NULL, - DRM_PLANE_TYPE_PRIMARY, - NULL); - if (ret) { - DRM_ERROR("failed to init plane: %d\n", ret); - return ERR_PTR(ret); - } - - drm_plane_helper_add(plane, &hibmc_plane_helper_funcs); - return plane; -} - static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms) { struct hibmc_drm_private *priv = crtc->dev->dev_private; @@ -537,32 +503,34 @@ static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = { int hibmc_de_init(struct hibmc_drm_private *priv) { struct drm_device *dev = priv->dev; - struct drm_crtc *crtc; - struct drm_plane *plane; + struct drm_crtc *crtc = &priv->crtc; + struct drm_plane *plane = &priv->primary_plane; int ret; - plane = hibmc_plane_init(priv); - if (IS_ERR(plane)) { - DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane)); - return PTR_ERR(plane); - } + ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs, + channel_formats1, + ARRAY_SIZE(channel_formats1), + NULL, + DRM_PLANE_TYPE_PRIMARY, + NULL); - crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL); - if (!crtc) { - DRM_ERROR("failed to alloc memory when init crtc\n"); - return -ENOMEM; + if (ret) { + drm_err(dev, "failed to init plane: %d\n", ret); + return ret; } + drm_plane_helper_add(plane, &hibmc_plane_helper_funcs); + ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, &hibmc_crtc_funcs, NULL); if (ret) { - DRM_ERROR("failed to init crtc: %d\n", ret); + drm_err(dev, "failed to init crtc: %d\n", ret); return ret; } ret = drm_mode_crtc_set_gamma_size(crtc, 256); if (ret) { - DRM_ERROR("failed to set gamma size: %d\n", ret); + drm_err(dev, "failed to set gamma size: %d\n", ret); return ret; } drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index eea13e60187b..085d1b2fa8c0 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -11,18 +11,14 @@ * Jianhua Li <[email protected]> */ -#include <linux/console.h> #include <linux/module.h> #include <linux/pci.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_helper.h> #include <drm/drm_gem_vram_helper.h> #include <drm/drm_irq.h> #include <drm/drm_managed.h> -#include <drm/drm_print.h> -#include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> #include "hibmc_drm_drv.h" @@ -102,13 +98,13 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv) ret = hibmc_de_init(priv); if (ret) { - DRM_ERROR("failed to init de: %d\n", ret); + drm_err(priv->dev, "failed to init de: %d\n", ret); return ret; } ret = hibmc_vdac_init(priv); if (ret) { - DRM_ERROR("failed to init vdac: %d\n", ret); + drm_err(priv->dev, "failed to init vdac: %d\n", ret); return ret; } @@ -216,7 +212,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) iosize = pci_resource_len(pdev, 1); priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize); if (!priv->mmio) { - DRM_ERROR("Cannot map mmio region\n"); + drm_err(dev, "Cannot map mmio region\n"); return -ENOMEM; } @@ -224,7 +220,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) size = pci_resource_len(pdev, 0); priv->fb_map = devm_ioremap(dev->dev, addr, size); if (!priv->fb_map) { - DRM_ERROR("Cannot map framebuffer\n"); + drm_err(dev, "Cannot map framebuffer\n"); return -ENOMEM; } priv->fb_base = addr; @@ -254,9 +250,8 @@ static int hibmc_unload(struct drm_device *dev) if (dev->irq_enabled) drm_irq_uninstall(dev); - if (priv->msi_enabled) - pci_disable_msi(dev->pdev); + pci_disable_msi(dev->pdev); hibmc_kms_fini(priv); hibmc_mm_fini(priv); dev->dev_private = NULL; @@ -270,7 +265,7 @@ static int hibmc_load(struct drm_device *dev) priv = drmm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) { - DRM_ERROR("no memory to allocate for hibmc_drm_private\n"); + drm_err(dev, "no memory to allocate for hibmc_drm_private\n"); return -ENOMEM; } dev->dev_private = priv; @@ -290,19 +285,17 @@ static int hibmc_load(struct drm_device *dev) ret = drm_vblank_init(dev, dev->mode_config.num_crtc); if (ret) { - DRM_ERROR("failed to initialize vblank: %d\n", ret); + drm_err(dev, "failed to initialize vblank: %d\n", ret); goto err; } - priv->msi_enabled = 0; ret = pci_enable_msi(dev->pdev); if (ret) { - DRM_WARN("enabling MSI failed: %d\n", ret); + drm_warn(dev, "enabling MSI failed: %d\n", ret); } else { - priv->msi_enabled = 1; ret = drm_irq_install(dev, dev->pdev->irq); if (ret) - DRM_WARN("install irq failed: %d\n", ret); + drm_warn(dev, "install irq failed: %d\n", ret); } /* reset all the states of crtc/plane/encoder/connector */ @@ -312,7 +305,7 @@ static int hibmc_load(struct drm_device *dev) err: hibmc_unload(dev); - DRM_ERROR("failed to initialize drm driver: %d\n", ret); + drm_err(dev, "failed to initialize drm driver: %d\n", ret); return ret; } @@ -338,19 +331,19 @@ static int hibmc_pci_probe(struct pci_dev *pdev, ret = pci_enable_device(pdev); if (ret) { - DRM_ERROR("failed to enable pci device: %d\n", ret); + drm_err(dev, "failed to enable pci device: %d\n", ret); goto err_free; } ret = hibmc_load(dev); if (ret) { - DRM_ERROR("failed to load hibmc: %d\n", ret); + drm_err(dev, "failed to load hibmc: %d\n", ret); goto err_disable; } ret = drm_dev_register(dev, 0); if (ret) { - DRM_ERROR("failed to register drv for userspace access: %d\n", + drm_err(dev, "failed to register drv for userspace access: %d\n", ret); goto err_unload; } diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index 609768748de6..197485e2fe0b 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -25,10 +25,11 @@ struct hibmc_drm_private { void __iomem *fb_map; unsigned long fb_base; unsigned long fb_size; - bool msi_enabled; /* drm */ struct drm_device *dev; + struct drm_plane primary_plane; + struct drm_crtc crtc; struct drm_encoder encoder; struct drm_connector connector; bool mode_config_initialized; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index 2ca69c38491a..376a05ddbc2f 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -11,10 +11,8 @@ * Jianhua Li <[email protected]> */ -#include <drm/drm_gem_vram_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_print.h> #include "hibmc_drm_drv.h" @@ -87,7 +85,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL); if (ret) { - DRM_ERROR("failed to init encoder: %d\n", ret); + drm_err(dev, "failed to init encoder: %d\n", ret); return ret; } @@ -96,7 +94,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) ret = drm_connector_init(dev, connector, &hibmc_connector_funcs, DRM_MODE_CONNECTOR_VGA); if (ret) { - DRM_ERROR("failed to init connector: %d\n", ret); + drm_err(dev, "failed to init connector: %d\n", ret); return ret; } drm_connector_helper_add(connector, &hibmc_connector_helper_funcs); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 322bd542e89d..602ece11bb4a 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -32,7 +32,7 @@ int hibmc_mm_init(struct hibmc_drm_private *hibmc) hibmc->fb_size); if (IS_ERR(vmm)) { ret = PTR_ERR(vmm); - DRM_ERROR("Error initializing VRAM MM; %d\n", ret); + drm_err(dev, "Error initializing VRAM MM; %d\n", ret); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 91a8161e7c05..577c4441f32d 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2677,7 +2677,7 @@ void intel_update_cdclk(struct drm_i915_private *dev_priv) */ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) intel_de_write(dev_priv, GMBUSFREQ_VLV, - DIV_ROUND_UP(dev_priv->cdclk.hw.cdclk, 1000)); + DIV_ROUND_UP(dev_priv->cdclk.hw.cdclk, 1000)); } static int cnp_rawclk(struct drm_i915_private *dev_priv) @@ -2903,9 +2903,10 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) dev_priv->display.get_cdclk = i85x_get_cdclk; else if (IS_I845G(dev_priv)) dev_priv->display.get_cdclk = fixed_200mhz_get_cdclk; - else { /* 830 */ - drm_WARN(&dev_priv->drm, !IS_I830(dev_priv), - "Unknown platform. Assuming 133 MHz CDCLK\n"); + else if (IS_I830(dev_priv)) + dev_priv->display.get_cdclk = fixed_133mhz_get_cdclk; + + if (drm_WARN(&dev_priv->drm, !dev_priv->display.get_cdclk, + "Unknown platform. Assuming 133 MHz CDCLK\n")) dev_priv->display.get_cdclk = fixed_133mhz_get_cdclk; - } } diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h index 5731806e4cee..6b31fde4be16 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.h +++ b/drivers/gpu/drm/i915/display/intel_cdclk.h @@ -17,8 +17,8 @@ struct intel_atomic_state; struct intel_crtc_state; struct intel_cdclk_vals { - u16 refclk; u32 cdclk; + u16 refclk; u8 divider; /* CD2X divider * 2 */ u8 ratio; }; diff --git a/drivers/gpu/drm/i915/display/intel_csr.c b/drivers/gpu/drm/i915/display/intel_csr.c index f22a7645c249..d5db16764619 100644 --- a/drivers/gpu/drm/i915/display/intel_csr.c +++ b/drivers/gpu/drm/i915/display/intel_csr.c @@ -40,12 +40,12 @@ #define GEN12_CSR_MAX_FW_SIZE ICL_CSR_MAX_FW_SIZE -#define RKL_CSR_PATH "i915/rkl_dmc_ver2_01.bin" -#define RKL_CSR_VERSION_REQUIRED CSR_VERSION(2, 1) +#define RKL_CSR_PATH "i915/rkl_dmc_ver2_02.bin" +#define RKL_CSR_VERSION_REQUIRED CSR_VERSION(2, 2) MODULE_FIRMWARE(RKL_CSR_PATH); -#define TGL_CSR_PATH "i915/tgl_dmc_ver2_06.bin" -#define TGL_CSR_VERSION_REQUIRED CSR_VERSION(2, 6) +#define TGL_CSR_PATH "i915/tgl_dmc_ver2_08.bin" +#define TGL_CSR_VERSION_REQUIRED CSR_VERSION(2, 8) #define TGL_CSR_MAX_FW_SIZE 0x6000 MODULE_FIRMWARE(TGL_CSR_PATH); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index a49ff3a1a63c..19ac6b2a664c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -706,6 +706,42 @@ static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr2[] = { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ }; +static const struct cnl_ddi_buf_trans tgl_uy_combo_phy_ddi_translations_dp_hbr2[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ + { 0xC, 0x60, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ + { 0xC, 0x7F, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ + { 0xC, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x6F, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ + { 0x6, 0x60, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +/* + * Cloned the HOBL entry to comply with the voltage and pre-emphasis entries + * that DisplayPort specification requires + */ +static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_edp_hbr2_hobl[] = { + /* VS pre-emp */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 1 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 2 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 3 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 1 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 2 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 1 */ +}; + +static bool is_hobl_buf_trans(const struct cnl_ddi_buf_trans *table) +{ + return table == tgl_combo_phy_ddi_translations_edp_hbr2_hobl; +} + static const struct ddi_buf_trans * bdw_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) { @@ -1050,9 +1086,26 @@ static const struct cnl_ddi_buf_trans * tgl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate, int *n_entries) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.hobl) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + if (!intel_dp->hobl_failed && rate <= 540000) { + /* Same table applies to TGL, RKL and DG1 */ + *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl); + return tgl_combo_phy_ddi_translations_edp_hbr2_hobl; + } + } + if (type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_EDP) { return icl_get_combo_buf_trans(encoder, type, rate, n_entries); } else if (rate > 270000) { + if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { + *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2); + return tgl_uy_combo_phy_ddi_translations_dp_hbr2; + } + *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2); return tgl_combo_phy_ddi_translations_dp_hbr2; } @@ -2392,6 +2445,15 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder, level = n_entries - 1; } + if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + val = EDP4K2K_MODE_OVRD_EN | EDP4K2K_MODE_OVRD_OPTIMIZED; + intel_dp->hobl_active = is_hobl_buf_trans(ddi_translations); + intel_de_rmw(dev_priv, ICL_PORT_CL_DW10(phy), val, + intel_dp->hobl_active ? val : 0); + } + /* Set PORT_TX_DW5 */ val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy)); val &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK | @@ -2802,7 +2864,9 @@ hsw_set_signal_levels(struct intel_dp *intel_dp) static u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv, enum phy phy) { - if (intel_phy_is_combo(dev_priv, phy)) { + if (IS_ROCKETLAKE(dev_priv)) { + return RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); + } else if (intel_phy_is_combo(dev_priv, phy)) { return ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); } else if (intel_phy_is_tc(dev_priv, phy)) { enum tc_port tc_port = intel_port_to_tc(dev_priv, @@ -2829,6 +2893,16 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder, (val & icl_dpclka_cfgcr0_clk_off(dev_priv, phy)) == 0); if (intel_phy_is_combo(dev_priv, phy)) { + u32 mask, sel; + + if (IS_ROCKETLAKE(dev_priv)) { + mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + sel = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); + } else { + mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + sel = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); + } + /* * Even though this register references DDIs, note that we * want to pass the PHY rather than the port (DDI). For @@ -2839,8 +2913,8 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder, * Clock Select chooses the PLL for both DDIA and DDID and * drives port A in all cases." */ - val &= ~ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - val |= ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); + val &= ~mask; + val |= sel; intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val); intel_de_posting_read(dev_priv, ICL_DPCLKA_CFGCR0); } @@ -4037,8 +4111,7 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp) intel_wait_ddi_buf_idle(dev_priv, port); } - dp_tp_ctl = DP_TP_CTL_ENABLE | - DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE; + dp_tp_ctl = DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_PAT1; if (intel_dp->link_mst) dp_tp_ctl |= DP_TP_CTL_MODE_MST; else { @@ -4061,16 +4134,10 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp, { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd); - enum port port = dp_to_dig_port(intel_dp)->base.port; u32 temp; temp = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl); - if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE) - temp |= DP_TP_CTL_SCRAMBLE_DISABLE; - else - temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE; - temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; switch (dp_train_pat & train_pat_mask) { case DP_TRAINING_PATTERN_DISABLE: @@ -4091,9 +4158,6 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp, } intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, temp); - - intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP); - intel_de_posting_read(dev_priv, DDI_BUF_CTL(port)); } static void intel_ddi_set_idle_link_train(struct intel_dp *intel_dp) @@ -4878,6 +4942,13 @@ intel_ddi_max_lanes(struct intel_digital_port *dig_port) return max_lanes; } +static bool hti_uses_phy(struct drm_i915_private *i915, enum phy phy) +{ + return i915->hti_state & HDPORT_ENABLED && + (i915->hti_state & HDPORT_PHY_USED_DP(phy) || + i915->hti_state & HDPORT_PHY_USED_HDMI(phy)); +} + void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) { struct intel_digital_port *dig_port; @@ -4885,6 +4956,18 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) bool init_hdmi, init_dp, init_lspcon = false; enum phy phy = intel_port_to_phy(dev_priv, port); + /* + * On platforms with HTI (aka HDPORT), if it's enabled at boot it may + * have taken over some of the PHYs and made them unavailable to the + * driver. In that case we should skip initializing the corresponding + * outputs. + */ + if (hti_uses_phy(dev_priv, phy)) { + drm_dbg_kms(&dev_priv->drm, "PORT %c / PHY %c reserved by HTI\n", + port_name(port), phy_name(phy)); + return; + } + init_hdmi = intel_bios_port_supports_dvi(dev_priv, port) || intel_bios_port_supports_hdmi(dev_priv, port); init_dp = intel_bios_port_supports_dp(dev_priv, port); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 68325678f5ef..d60efb8f4ba3 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -47,6 +47,7 @@ #include "display/intel_ddi.h" #include "display/intel_dp.h" #include "display/intel_dp_mst.h" +#include "display/intel_dpll_mgr.h" #include "display/intel_dsi.h" #include "display/intel_dvo.h" #include "display/intel_gmbus.h" @@ -3761,6 +3762,44 @@ static int glk_max_plane_width(const struct drm_framebuffer *fb, } } +static int icl_min_plane_width(const struct drm_framebuffer *fb) +{ + /* Wa_14011264657, Wa_14011050563: gen11+ */ + switch (fb->format->format) { + case DRM_FORMAT_C8: + return 18; + case DRM_FORMAT_RGB565: + return 10; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XVYU2101010: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + return 6; + case DRM_FORMAT_NV12: + return 20; + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + return 12; + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + return 4; + default: + return 1; + } +} + static int icl_max_plane_width(const struct drm_framebuffer *fb, int color_plane, unsigned int rotation) @@ -3843,29 +3882,31 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state) int y = plane_state->uapi.src.y1 >> 16; int w = drm_rect_width(&plane_state->uapi.src) >> 16; int h = drm_rect_height(&plane_state->uapi.src) >> 16; - int max_width; - int max_height; - u32 alignment; - u32 offset; + int max_width, min_width, max_height; + u32 alignment, offset; int aux_plane = intel_main_to_aux_plane(fb, 0); u32 aux_offset = plane_state->color_plane[aux_plane].offset; - if (INTEL_GEN(dev_priv) >= 11) + if (INTEL_GEN(dev_priv) >= 11) { max_width = icl_max_plane_width(fb, 0, rotation); - else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + min_width = icl_min_plane_width(fb); + } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { max_width = glk_max_plane_width(fb, 0, rotation); - else + min_width = 1; + } else { max_width = skl_max_plane_width(fb, 0, rotation); + min_width = 1; + } if (INTEL_GEN(dev_priv) >= 11) max_height = icl_max_plane_height(); else max_height = skl_max_plane_height(); - if (w > max_width || h > max_height) { + if (w > max_width || w < min_width || h > max_height) { drm_dbg_kms(&dev_priv->drm, - "requested Y/RGB source size %dx%d too big (limit %dx%d)\n", - w, h, max_width, max_height); + "requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n", + w, h, min_width, max_width, max_height); return -EINVAL; } @@ -10802,9 +10843,18 @@ static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, u32 temp; if (intel_phy_is_combo(dev_priv, phy)) { - temp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0) & - ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - id = temp >> ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); + u32 mask, shift; + + if (IS_ROCKETLAKE(dev_priv)) { + mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + shift = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); + } else { + mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + shift = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); + } + + temp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0) & mask; + id = temp >> shift; port_dpll_id = ICL_PORT_DPLL_DEFAULT; } else if (intel_phy_is_tc(dev_priv, phy)) { u32 clk_sel = intel_de_read(dev_priv, DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK; @@ -12760,6 +12810,9 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, } + if (!mode_changed) + intel_psr2_sel_fetch_update(state, crtc); + return 0; } @@ -15136,6 +15189,8 @@ static void commit_pipe_config(struct intel_atomic_state *state, if (new_crtc_state->update_pipe) intel_pipe_fastset(old_crtc_state, new_crtc_state); + + intel_psr2_program_trans_man_trk_ctl(new_crtc_state); } if (dev_priv->display.atomic_update_watermarks) @@ -17894,6 +17949,13 @@ int intel_modeset_init(struct drm_i915_private *i915) if (i915->max_cdclk_freq == 0) intel_update_max_cdclk(i915); + /* + * If the platform has HTI, we need to find out whether it has reserved + * any display resources before we create our display outputs. + */ + if (INTEL_INFO(i915)->display.has_hti) + i915->hti_state = intel_de_read(i915, HDPORT_STATE); + /* Just disable it once at startup */ intel_vga_disable(i915); intel_setup_outputs(i915); diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 5a5cfe25085b..f549381048b3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -417,6 +417,9 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) su_blocks = su_blocks >> PSR2_SU_STATUS_SHIFT(frame); seq_printf(m, "%d\t%d\n", frame, su_blocks); } + + seq_printf(m, "PSR2 selective fetch: %s\n", + enableddisabled(psr->psr2_sel_fetch_enabled)); } unlock: diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index e0fcb89c736b..7946c6af4b1e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -3927,12 +3927,13 @@ tgl_tc_cold_request(struct drm_i915_private *i915, bool block) int ret; while (1) { - u32 low_val = 0, high_val; + u32 low_val; + u32 high_val = 0; if (block) - high_val = TGL_PCODE_EXIT_TCCOLD_DATA_H_BLOCK_REQ; + low_val = TGL_PCODE_EXIT_TCCOLD_DATA_L_BLOCK_REQ; else - high_val = TGL_PCODE_EXIT_TCCOLD_DATA_H_UNBLOCK_REQ; + low_val = TGL_PCODE_EXIT_TCCOLD_DATA_L_UNBLOCK_REQ; /* * Spec states that we should timeout the request after 200us @@ -3951,8 +3952,7 @@ tgl_tc_cold_request(struct drm_i915_private *i915, bool block) if (++tries == 3) break; - if (ret == -EAGAIN) - msleep(1); + msleep(1); } if (ret) @@ -5302,6 +5302,12 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + /* Wa_14011294188:ehl,jsl,tgl,rkl */ + if (INTEL_PCH_TYPE(dev_priv) >= PCH_JSP && + INTEL_PCH_TYPE(dev_priv) < PCH_DG1) + intel_de_rmw(dev_priv, SOUTH_DSPCLK_GATE_D, 0, + PCH_DPMGUNIT_CLOCK_GATE_DISABLE); + /* 1. Enable PCH reset handshake. */ intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv)); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e8f809161c75..9349b15afff6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -931,6 +931,7 @@ struct intel_crtc_state { bool has_psr; bool has_psr2; + bool enable_psr2_sel_fetch; u32 dc3co_exitline; /* @@ -1073,6 +1074,8 @@ struct intel_crtc_state { /* For DSB related info */ struct intel_dsb *dsb; + + u32 psr2_man_track_ctl; }; enum intel_pipe_crc_source { @@ -1375,6 +1378,9 @@ struct intel_dp { /* Display stream compression testing */ bool force_dsc_en; + + bool hobl_failed; + bool hobl_active; }; enum lspcon_vendor { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index d6295eb20b63..79c27f91f42c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -6243,6 +6243,11 @@ out: */ intel_display_power_flush_work(dev_priv); + if (!intel_dp_is_edp(intel_dp)) + drm_dp_set_subconnector_property(connector, + status, + intel_dp->dpcd, + intel_dp->downstream_ports); return status; } @@ -7312,6 +7317,9 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect struct drm_i915_private *dev_priv = to_i915(connector->dev); enum port port = dp_to_dig_port(intel_dp)->base.port; + if (!intel_dp_is_edp(intel_dp)) + drm_connector_attach_dp_subconnector_property(connector); + if (!IS_G4X(dev_priv) && port != PORT_A) intel_attach_force_audio_property(connector); diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index a23ed7290843..f2c8b56be9ea 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -410,10 +410,17 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) intel_connector->base.base.id, intel_connector->base.name, intel_dp->link_rate, intel_dp->lane_count); - if (!intel_dp_get_link_train_fallback_values(intel_dp, - intel_dp->link_rate, - intel_dp->lane_count)) - /* Schedule a Hotplug Uevent to userspace to start modeset */ - schedule_work(&intel_connector->modeset_retry_work); - return; + + if (intel_dp->hobl_active) { + drm_dbg_kms(&dp_to_i915(intel_dp)->drm, + "Link Training failed with HOBL active, not enabling it from now on"); + intel_dp->hobl_failed = true; + } else if (intel_dp_get_link_train_fallback_values(intel_dp, + intel_dp->link_rate, + intel_dp->lane_count)) { + return; + } + + /* Schedule a Hotplug Uevent to userspace to start modeset */ + schedule_work(&intel_connector->modeset_retry_work); } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index afa7a378b31d..c9013f8f766f 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -3475,6 +3475,14 @@ static void icl_update_active_dpll(struct intel_atomic_state *state, icl_set_active_port_dpll(crtc_state, port_dpll_id); } +static u32 intel_get_hti_plls(struct drm_i915_private *i915) +{ + if (!(i915->hti_state & HDPORT_ENABLED)) + return 0; + + return REG_FIELD_GET(HDPORT_DPLL_USED_MASK, i915->hti_state); +} + static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) @@ -3504,13 +3512,22 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state, icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state); - if (IS_ELKHARTLAKE(dev_priv) && port != PORT_A) + if (IS_ROCKETLAKE(dev_priv)) { dpll_mask = BIT(DPLL_ID_EHL_DPLL4) | BIT(DPLL_ID_ICL_DPLL1) | BIT(DPLL_ID_ICL_DPLL0); - else + } else if (IS_ELKHARTLAKE(dev_priv) && port != PORT_A) { + dpll_mask = + BIT(DPLL_ID_EHL_DPLL4) | + BIT(DPLL_ID_ICL_DPLL1) | + BIT(DPLL_ID_ICL_DPLL0); + } else { dpll_mask = BIT(DPLL_ID_ICL_DPLL1) | BIT(DPLL_ID_ICL_DPLL0); + } + + /* Eliminate DPLLs from consideration if reserved by HTI */ + dpll_mask &= ~intel_get_hti_plls(dev_priv); port_dpll->pll = intel_find_shared_dpll(state, crtc, &port_dpll->hw_state, @@ -3791,7 +3808,12 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, if (!(val & PLL_ENABLE)) goto out; - if (INTEL_GEN(dev_priv) >= 12) { + if (IS_ROCKETLAKE(dev_priv)) { + hw_state->cfgcr0 = intel_de_read(dev_priv, + RKL_DPLL_CFGCR0(id)); + hw_state->cfgcr1 = intel_de_read(dev_priv, + RKL_DPLL_CFGCR1(id)); + } else if (INTEL_GEN(dev_priv) >= 12) { hw_state->cfgcr0 = intel_de_read(dev_priv, TGL_DPLL_CFGCR0(id)); hw_state->cfgcr1 = intel_de_read(dev_priv, @@ -3844,7 +3866,10 @@ static void icl_dpll_write(struct drm_i915_private *dev_priv, const enum intel_dpll_id id = pll->info->id; i915_reg_t cfgcr0_reg, cfgcr1_reg; - if (INTEL_GEN(dev_priv) >= 12) { + if (IS_ROCKETLAKE(dev_priv)) { + cfgcr0_reg = RKL_DPLL_CFGCR0(id); + cfgcr1_reg = RKL_DPLL_CFGCR1(id); + } else if (INTEL_GEN(dev_priv) >= 12) { cfgcr0_reg = TGL_DPLL_CFGCR0(id); cfgcr1_reg = TGL_DPLL_CFGCR1(id); } else { @@ -4276,6 +4301,21 @@ static const struct intel_dpll_mgr tgl_pll_mgr = { .dump_hw_state = icl_dump_hw_state, }; +static const struct dpll_info rkl_plls[] = { + { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, + { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, + { "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 }, + { }, +}; + +static const struct intel_dpll_mgr rkl_pll_mgr = { + .dpll_info = rkl_plls, + .get_dplls = icl_get_dplls, + .put_dplls = icl_put_dplls, + .update_ref_clks = icl_update_dpll_ref_clks, + .dump_hw_state = icl_dump_hw_state, +}; + /** * intel_shared_dpll_init - Initialize shared DPLLs * @dev: drm device @@ -4289,7 +4329,9 @@ void intel_shared_dpll_init(struct drm_device *dev) const struct dpll_info *dpll_info; int i; - if (INTEL_GEN(dev_priv) >= 12) + if (IS_ROCKETLAKE(dev_priv)) + dpll_mgr = &rkl_pll_mgr; + else if (INTEL_GEN(dev_priv) >= 12) dpll_mgr = &tgl_pll_mgr; else if (IS_ELKHARTLAKE(dev_priv)) dpll_mgr = &ehl_pll_mgr; diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 24c3a0f212c6..135f5e8a4d70 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -424,6 +424,14 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv, fbc->no_fbc_reason = reason; } +static u64 intel_fbc_cfb_base_max(struct drm_i915_private *i915) +{ + if (INTEL_GEN(i915) >= 5 || IS_G4X(i915)) + return BIT_ULL(28); + else + return BIT_ULL(32); +} + static int find_compression_threshold(struct drm_i915_private *dev_priv, struct drm_mm_node *node, unsigned int size, @@ -442,6 +450,8 @@ static int find_compression_threshold(struct drm_i915_private *dev_priv, else end = U64_MAX; + end = min(end, intel_fbc_cfb_base_max(dev_priv)); + /* HACK: This code depends on what we will do in *_enable_fbc. If that * code changes, this code needs to change as well. * @@ -1416,6 +1426,13 @@ static int intel_sanitize_fbc_option(struct drm_i915_private *dev_priv) if (!HAS_FBC(dev_priv)) return 0; + /* + * Fbc is causing random underruns in CI execution on TGL platforms. + * Disabling the same while the problem is being debugged and analyzed. + */ + if (IS_TIGERLAKE(dev_priv)) + return 0; + if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) return 1; diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index 2979ed2588eb..d898b370d7a4 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -232,6 +232,8 @@ static void frontbuffer_release(struct kref *ref) RCU_INIT_POINTER(obj->frontbuffer, NULL); spin_unlock(&to_i915(obj->base.dev)->fb_tracking.lock); + i915_active_fini(&front->write); + i915_gem_object_put(obj); kfree_rcu(front, rcu); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index bf9e320c547d..2b004ee9619c 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -553,6 +553,22 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) val |= EDP_PSR2_FAST_WAKE(7); } + if (dev_priv->psr.psr2_sel_fetch_enabled) { + /* WA 1408330847 */ + if (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) || + IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0)) + intel_de_rmw(dev_priv, CHICKEN_PAR1_1, + DIS_RAM_BYPASS_PSR2_MAN_TRACK, + DIS_RAM_BYPASS_PSR2_MAN_TRACK); + + intel_de_write(dev_priv, + PSR2_MAN_TRK_CTL(dev_priv->psr.transcoder), + PSR2_MAN_TRK_CTL_ENABLE); + } else if (HAS_PSR2_SEL_FETCH(dev_priv)) { + intel_de_write(dev_priv, + PSR2_MAN_TRK_CTL(dev_priv->psr.transcoder), 0); + } + /* * PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is * recommending keep this bit unset while PSR2 is enabled. @@ -663,6 +679,38 @@ tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp, crtc_state->dc3co_exitline = crtc_vdisplay - exit_scanlines; } +static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state) +{ + struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_plane_state *plane_state; + struct intel_plane *plane; + int i; + + if (!dev_priv->params.enable_psr2_sel_fetch) { + drm_dbg_kms(&dev_priv->drm, + "PSR2 sel fetch not enabled, disabled by parameter\n"); + return false; + } + + if (crtc_state->uapi.async_flip) { + drm_dbg_kms(&dev_priv->drm, + "PSR2 sel fetch not enabled, async flip enabled\n"); + return false; + } + + for_each_new_intel_plane_in_state(state, plane, plane_state, i) { + if (plane_state->uapi.rotation != DRM_MODE_ROTATE_0) { + drm_dbg_kms(&dev_priv->drm, + "PSR2 sel fetch not enabled, plane rotated\n"); + return false; + } + } + + return crtc_state->enable_psr2_sel_fetch = true; +} + static bool intel_psr2_config_valid(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { @@ -732,22 +780,17 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } - /* - * Some platforms lack PSR2 HW tracking and instead require manual - * tracking by software. In this case, the driver is required to track - * the areas that need updates and program hardware to send selective - * updates. - * - * So until the software tracking is implemented, PSR2 needs to be - * disabled for platforms without PSR2 HW tracking. - */ - if (!HAS_PSR_HW_TRACKING(dev_priv)) { - drm_dbg_kms(&dev_priv->drm, - "No PSR2 HW tracking in the platform\n"); - return false; + if (HAS_PSR2_SEL_FETCH(dev_priv)) { + if (!intel_psr2_sel_fetch_config_valid(intel_dp, crtc_state) && + !HAS_PSR_HW_TRACKING(dev_priv)) { + drm_dbg_kms(&dev_priv->drm, + "PSR2 not enabled, selective fetch not valid and no HW tracking available\n"); + return false; + } } - if (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v) { + if (!crtc_state->enable_psr2_sel_fetch && + (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v)) { drm_dbg_kms(&dev_priv->drm, "PSR2 not enabled, resolution %dx%d > max supported %dx%d\n", crtc_hdisplay, crtc_vdisplay, @@ -898,6 +941,11 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, val |= EXITLINE_ENABLE; intel_de_write(dev_priv, EXITLINE(cpu_transcoder), val); } + + if (HAS_PSR_HW_TRACKING(dev_priv)) + intel_de_rmw(dev_priv, CHICKEN_PAR1_1, IGNORE_PSR2_HW_TRACKING, + dev_priv->psr.psr2_sel_fetch_enabled ? + IGNORE_PSR2_HW_TRACKING : 0); } static void intel_psr_enable_locked(struct drm_i915_private *dev_priv, @@ -919,6 +967,7 @@ static void intel_psr_enable_locked(struct drm_i915_private *dev_priv, /* DC5/DC6 requires at least 6 idle frames */ val = usecs_to_jiffies(intel_get_frame_time_us(crtc_state) * 6); dev_priv->psr.dc3co_exit_delay = val; + dev_priv->psr.psr2_sel_fetch_enabled = crtc_state->enable_psr2_sel_fetch; /* * If a PSR error happened and the driver is reloaded, the EDP_PSR_IIR @@ -1058,6 +1107,13 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) psr_status_mask, 2000)) drm_err(&dev_priv->drm, "Timed out waiting PSR idle state\n"); + /* WA 1408330847 */ + if (dev_priv->psr.psr2_sel_fetch_enabled && + (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) || + IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0))) + intel_de_rmw(dev_priv, CHICKEN_PAR1_1, + DIS_RAM_BYPASS_PSR2_MAN_TRACK, 0); + /* Disable PSR on Sink */ drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0); @@ -1115,6 +1171,32 @@ static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv) intel_psr_exit(dev_priv); } +void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct i915_psr *psr = &dev_priv->psr; + + if (!HAS_PSR2_SEL_FETCH(dev_priv) || + !crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(psr->transcoder), + crtc_state->psr2_man_track_ctl); +} + +void intel_psr2_sel_fetch_update(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + crtc_state->psr2_man_track_ctl = PSR2_MAN_TRK_CTL_ENABLE | + PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME; +} + /** * intel_psr_update - Update PSR state * @intel_dp: Intel DP diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index b4515186d5f4..6a83c8e682e6 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -13,6 +13,8 @@ struct drm_connector_state; struct drm_i915_private; struct intel_crtc_state; struct intel_dp; +struct intel_crtc; +struct intel_atomic_state; #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support) void intel_psr_init_dpcd(struct intel_dp *intel_dp); @@ -43,5 +45,8 @@ void intel_psr_atomic_check(struct drm_connector *connector, struct drm_connector_state *old_state, struct drm_connector_state *new_state); void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp); +void intel_psr2_sel_fetch_update(struct intel_atomic_state *state, + struct intel_crtc *crtc); +void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state); #endif /* __INTEL_PSR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index c89f5f7ccb06..6b72223981be 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -2843,8 +2843,9 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane, static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv, enum plane_id plane_id) { - /* Wa_14010477008:tgl[a0..c0] */ - if (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0)) + /* Wa_14010477008:tgl[a0..c0],rkl[all] */ + if (IS_ROCKETLAKE(dev_priv) || + IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0)) return false; return plane_id < PLANE_SPRITE4; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 446e76e95c38..322642fb765f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -26,6 +26,7 @@ #include "i915_gem_ioctls.h" #include "i915_sw_fence_work.h" #include "i915_trace.h" +#include "i915_user_extensions.h" struct eb_vma { struct i915_vma *vma; @@ -229,6 +230,13 @@ enum { * the batchbuffer in trusted mode, otherwise the ioctl is rejected. */ +struct eb_fence { + struct drm_syncobj *syncobj; /* Use with ptr_mask_bits() */ + struct dma_fence *dma_fence; + u64 value; + struct dma_fence_chain *chain_fence; +}; + struct i915_execbuffer { struct drm_i915_private *i915; /** i915 backpointer */ struct drm_file *file; /** per-file lookup tables and limits */ @@ -290,6 +298,9 @@ struct i915_execbuffer { int lut_size; struct hlist_head *buckets; /** ht for relocation handles */ struct eb_vma_array *array; + + struct eb_fence *fences; + unsigned long num_fences; }; static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb) @@ -1894,7 +1905,8 @@ static int i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) return -EINVAL; /* Kernel clipping was a DRI1 misfeature */ - if (!(exec->flags & I915_EXEC_FENCE_ARRAY)) { + if (!(exec->flags & (I915_EXEC_FENCE_ARRAY | + I915_EXEC_USE_EXTENSIONS))) { if (exec->num_cliprects || exec->cliprects_ptr) return -EINVAL; } @@ -2473,107 +2485,241 @@ eb_pin_engine(struct i915_execbuffer *eb, } static void -__free_fence_array(struct drm_syncobj **fences, unsigned int n) +__free_fence_array(struct eb_fence *fences, unsigned int n) { - while (n--) - drm_syncobj_put(ptr_mask_bits(fences[n], 2)); + while (n--) { + drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2)); + dma_fence_put(fences[n].dma_fence); + kfree(fences[n].chain_fence); + } kvfree(fences); } -static struct drm_syncobj ** -get_fence_array(struct drm_i915_gem_execbuffer2 *args, - struct drm_file *file) +static int +add_timeline_fence_array(struct i915_execbuffer *eb, + const struct drm_i915_gem_execbuffer_ext_timeline_fences *timeline_fences) { - const unsigned long nfences = args->num_cliprects; - struct drm_i915_gem_exec_fence __user *user; - struct drm_syncobj **fences; - unsigned long n; - int err; + struct drm_i915_gem_exec_fence __user *user_fences; + u64 __user *user_values; + struct eb_fence *f; + u64 nfences; + int err = 0; - if (!(args->flags & I915_EXEC_FENCE_ARRAY)) - return NULL; + nfences = timeline_fences->fence_count; + if (!nfences) + return 0; /* Check multiplication overflow for access_ok() and kvmalloc_array() */ BUILD_BUG_ON(sizeof(size_t) > sizeof(unsigned long)); if (nfences > min_t(unsigned long, - ULONG_MAX / sizeof(*user), - SIZE_MAX / sizeof(*fences))) - return ERR_PTR(-EINVAL); + ULONG_MAX / sizeof(*user_fences), + SIZE_MAX / sizeof(*f)) - eb->num_fences) + return -EINVAL; - user = u64_to_user_ptr(args->cliprects_ptr); - if (!access_ok(user, nfences * sizeof(*user))) - return ERR_PTR(-EFAULT); + user_fences = u64_to_user_ptr(timeline_fences->handles_ptr); + if (!access_ok(user_fences, nfences * sizeof(*user_fences))) + return -EFAULT; - fences = kvmalloc_array(nfences, sizeof(*fences), - __GFP_NOWARN | GFP_KERNEL); - if (!fences) - return ERR_PTR(-ENOMEM); + user_values = u64_to_user_ptr(timeline_fences->values_ptr); + if (!access_ok(user_values, nfences * sizeof(*user_values))) + return -EFAULT; - for (n = 0; n < nfences; n++) { - struct drm_i915_gem_exec_fence fence; + f = krealloc(eb->fences, + (eb->num_fences + nfences) * sizeof(*f), + __GFP_NOWARN | GFP_KERNEL); + if (!f) + return -ENOMEM; + + eb->fences = f; + f += eb->num_fences; + + BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) & + ~__I915_EXEC_FENCE_UNKNOWN_FLAGS); + + while (nfences--) { + struct drm_i915_gem_exec_fence user_fence; struct drm_syncobj *syncobj; + struct dma_fence *fence = NULL; + u64 point; + + if (__copy_from_user(&user_fence, + user_fences++, + sizeof(user_fence))) + return -EFAULT; - if (__copy_from_user(&fence, user++, sizeof(fence))) { - err = -EFAULT; - goto err; + if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) + return -EINVAL; + + if (__get_user(point, user_values++)) + return -EFAULT; + + syncobj = drm_syncobj_find(eb->file, user_fence.handle); + if (!syncobj) { + DRM_DEBUG("Invalid syncobj handle provided\n"); + return -ENOENT; } - if (fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) { - err = -EINVAL; - goto err; + fence = drm_syncobj_fence_get(syncobj); + + if (!fence && user_fence.flags && + !(user_fence.flags & I915_EXEC_FENCE_SIGNAL)) { + DRM_DEBUG("Syncobj handle has no fence\n"); + drm_syncobj_put(syncobj); + return -EINVAL; } - syncobj = drm_syncobj_find(file, fence.handle); + if (fence) + err = dma_fence_chain_find_seqno(&fence, point); + + if (err && !(user_fence.flags & I915_EXEC_FENCE_SIGNAL)) { + DRM_DEBUG("Syncobj handle missing requested point %llu\n", point); + drm_syncobj_put(syncobj); + return err; + } + + /* + * A point might have been signaled already and + * garbage collected from the timeline. In this case + * just ignore the point and carry on. + */ + if (!fence && !(user_fence.flags & I915_EXEC_FENCE_SIGNAL)) { + drm_syncobj_put(syncobj); + continue; + } + + /* + * For timeline syncobjs we need to preallocate chains for + * later signaling. + */ + if (point != 0 && user_fence.flags & I915_EXEC_FENCE_SIGNAL) { + /* + * Waiting and signaling the same point (when point != + * 0) would break the timeline. + */ + if (user_fence.flags & I915_EXEC_FENCE_WAIT) { + DRM_DEBUG("Trying to wait & signal the same timeline point.\n"); + dma_fence_put(fence); + drm_syncobj_put(syncobj); + return -EINVAL; + } + + f->chain_fence = + kmalloc(sizeof(*f->chain_fence), + GFP_KERNEL); + if (!f->chain_fence) { + drm_syncobj_put(syncobj); + dma_fence_put(fence); + return -ENOMEM; + } + } else { + f->chain_fence = NULL; + } + + f->syncobj = ptr_pack_bits(syncobj, user_fence.flags, 2); + f->dma_fence = fence; + f->value = point; + f++; + eb->num_fences++; + } + + return 0; +} + +static int add_fence_array(struct i915_execbuffer *eb) +{ + struct drm_i915_gem_execbuffer2 *args = eb->args; + struct drm_i915_gem_exec_fence __user *user; + unsigned long num_fences = args->num_cliprects; + struct eb_fence *f; + + if (!(args->flags & I915_EXEC_FENCE_ARRAY)) + return 0; + + if (!num_fences) + return 0; + + /* Check multiplication overflow for access_ok() and kvmalloc_array() */ + BUILD_BUG_ON(sizeof(size_t) > sizeof(unsigned long)); + if (num_fences > min_t(unsigned long, + ULONG_MAX / sizeof(*user), + SIZE_MAX / sizeof(*f) - eb->num_fences)) + return -EINVAL; + + user = u64_to_user_ptr(args->cliprects_ptr); + if (!access_ok(user, num_fences * sizeof(*user))) + return -EFAULT; + + f = krealloc(eb->fences, + (eb->num_fences + num_fences) * sizeof(*f), + __GFP_NOWARN | GFP_KERNEL); + if (!f) + return -ENOMEM; + + eb->fences = f; + f += eb->num_fences; + while (num_fences--) { + struct drm_i915_gem_exec_fence user_fence; + struct drm_syncobj *syncobj; + struct dma_fence *fence = NULL; + + if (__copy_from_user(&user_fence, user++, sizeof(user_fence))) + return -EFAULT; + + if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) + return -EINVAL; + + syncobj = drm_syncobj_find(eb->file, user_fence.handle); if (!syncobj) { DRM_DEBUG("Invalid syncobj handle provided\n"); - err = -ENOENT; - goto err; + return -ENOENT; + } + + if (user_fence.flags & I915_EXEC_FENCE_WAIT) { + fence = drm_syncobj_fence_get(syncobj); + if (!fence) { + DRM_DEBUG("Syncobj handle has no fence\n"); + drm_syncobj_put(syncobj); + return -EINVAL; + } } BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) & ~__I915_EXEC_FENCE_UNKNOWN_FLAGS); - fences[n] = ptr_pack_bits(syncobj, fence.flags, 2); + f->syncobj = ptr_pack_bits(syncobj, user_fence.flags, 2); + f->dma_fence = fence; + f->value = 0; + f->chain_fence = NULL; + f++; + eb->num_fences++; } - return fences; - -err: - __free_fence_array(fences, n); - return ERR_PTR(err); + return 0; } -static void -put_fence_array(struct drm_i915_gem_execbuffer2 *args, - struct drm_syncobj **fences) +static void put_fence_array(struct eb_fence *fences, int num_fences) { if (fences) - __free_fence_array(fences, args->num_cliprects); + __free_fence_array(fences, num_fences); } static int -await_fence_array(struct i915_execbuffer *eb, - struct drm_syncobj **fences) +await_fence_array(struct i915_execbuffer *eb) { - const unsigned int nfences = eb->args->num_cliprects; unsigned int n; int err; - for (n = 0; n < nfences; n++) { + for (n = 0; n < eb->num_fences; n++) { struct drm_syncobj *syncobj; - struct dma_fence *fence; unsigned int flags; - syncobj = ptr_unpack_bits(fences[n], &flags, 2); - if (!(flags & I915_EXEC_FENCE_WAIT)) - continue; + syncobj = ptr_unpack_bits(eb->fences[n].syncobj, &flags, 2); - fence = drm_syncobj_fence_get(syncobj); - if (!fence) - return -EINVAL; + if (!eb->fences[n].dma_fence) + continue; - err = i915_request_await_dma_fence(eb->request, fence); - dma_fence_put(fence); + err = i915_request_await_dma_fence(eb->request, + eb->fences[n].dma_fence); if (err < 0) return err; } @@ -2581,26 +2727,47 @@ await_fence_array(struct i915_execbuffer *eb, return 0; } -static void -signal_fence_array(struct i915_execbuffer *eb, - struct drm_syncobj **fences) +static void signal_fence_array(const struct i915_execbuffer *eb) { - const unsigned int nfences = eb->args->num_cliprects; struct dma_fence * const fence = &eb->request->fence; unsigned int n; - for (n = 0; n < nfences; n++) { + for (n = 0; n < eb->num_fences; n++) { struct drm_syncobj *syncobj; unsigned int flags; - syncobj = ptr_unpack_bits(fences[n], &flags, 2); + syncobj = ptr_unpack_bits(eb->fences[n].syncobj, &flags, 2); if (!(flags & I915_EXEC_FENCE_SIGNAL)) continue; - drm_syncobj_replace_fence(syncobj, fence); + if (eb->fences[n].chain_fence) { + drm_syncobj_add_point(syncobj, + eb->fences[n].chain_fence, + fence, + eb->fences[n].value); + /* + * The chain's ownership is transferred to the + * timeline. + */ + eb->fences[n].chain_fence = NULL; + } else { + drm_syncobj_replace_fence(syncobj, fence); + } } } +static int +parse_timeline_fences(struct i915_user_extension __user *ext, void *data) +{ + struct i915_execbuffer *eb = data; + struct drm_i915_gem_execbuffer_ext_timeline_fences timeline_fences; + + if (copy_from_user(&timeline_fences, ext, sizeof(timeline_fences))) + return -EFAULT; + + return add_timeline_fence_array(eb, &timeline_fences); +} + static void retire_requests(struct intel_timeline *tl, struct i915_request *end) { struct i915_request *rq, *rn; @@ -2642,12 +2809,37 @@ static void eb_request_add(struct i915_execbuffer *eb) mutex_unlock(&tl->mutex); } +static const i915_user_extension_fn execbuf_extensions[] = { + [DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES] = parse_timeline_fences, +}; + +static int +parse_execbuf2_extensions(struct drm_i915_gem_execbuffer2 *args, + struct i915_execbuffer *eb) +{ + if (!(args->flags & I915_EXEC_USE_EXTENSIONS)) + return 0; + + /* The execbuf2 extension mechanism reuses cliprects_ptr. So we cannot + * have another flag also using it at the same time. + */ + if (eb->args->flags & I915_EXEC_FENCE_ARRAY) + return -EINVAL; + + if (args->num_cliprects != 0) + return -EINVAL; + + return i915_user_extensions(u64_to_user_ptr(args->cliprects_ptr), + execbuf_extensions, + ARRAY_SIZE(execbuf_extensions), + eb); +} + static int i915_gem_do_execbuffer(struct drm_device *dev, struct drm_file *file, struct drm_i915_gem_execbuffer2 *args, - struct drm_i915_gem_exec_object2 *exec, - struct drm_syncobj **fences) + struct drm_i915_gem_exec_object2 *exec) { struct drm_i915_private *i915 = to_i915(dev); struct i915_execbuffer eb; @@ -2677,6 +2869,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, eb.batch_len = args->batch_len; eb.trampoline = NULL; + eb.fences = NULL; + eb.num_fences = 0; + eb.batch_flags = 0; if (args->flags & I915_EXEC_SECURE) { if (INTEL_GEN(i915) >= 11) @@ -2694,14 +2889,24 @@ i915_gem_do_execbuffer(struct drm_device *dev, if (args->flags & I915_EXEC_IS_PINNED) eb.batch_flags |= I915_DISPATCH_PINNED; + err = parse_execbuf2_extensions(args, &eb); + if (err) + goto err_ext; + + err = add_fence_array(&eb); + if (err) + goto err_ext; + #define IN_FENCES (I915_EXEC_FENCE_IN | I915_EXEC_FENCE_SUBMIT) if (args->flags & IN_FENCES) { if ((args->flags & IN_FENCES) == IN_FENCES) return -EINVAL; in_fence = sync_file_get_fence(lower_32_bits(args->rsvd2)); - if (!in_fence) - return -EINVAL; + if (!in_fence) { + err = -EINVAL; + goto err_ext; + } } #undef IN_FENCES @@ -2811,8 +3016,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, goto err_request; } - if (fences) { - err = await_fence_array(&eb, fences); + if (eb.fences) { + err = await_fence_array(&eb); if (err) goto err_request; } @@ -2843,8 +3048,8 @@ err_request: i915_request_get(eb.request); eb_request_add(&eb); - if (fences) - signal_fence_array(&eb, fences); + if (eb.fences) + signal_fence_array(&eb); if (out_fence) { if (err == 0) { @@ -2877,6 +3082,8 @@ err_out_fence: put_unused_fd(out_fence_fd); err_in_fence: dma_fence_put(in_fence); +err_ext: + put_fence_array(eb.fences, eb.num_fences); return err; } @@ -2971,7 +3178,7 @@ i915_gem_execbuffer_ioctl(struct drm_device *dev, void *data, exec2_list[i].flags = 0; } - err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list, NULL); + err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list); if (exec2.flags & __EXEC_HAS_RELOC) { struct drm_i915_gem_exec_object __user *user_exec_list = u64_to_user_ptr(args->buffers_ptr); @@ -3003,7 +3210,6 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, struct drm_i915_private *i915 = to_i915(dev); struct drm_i915_gem_execbuffer2 *args = data; struct drm_i915_gem_exec_object2 *exec2_list; - struct drm_syncobj **fences = NULL; const size_t count = args->buffer_count; int err; @@ -3031,15 +3237,7 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, return -EFAULT; } - if (args->flags & I915_EXEC_FENCE_ARRAY) { - fences = get_fence_array(args, file); - if (IS_ERR(fences)) { - kvfree(exec2_list); - return PTR_ERR(fences); - } - } - - err = i915_gem_do_execbuffer(dev, file, args, exec2_list, fences); + err = i915_gem_do_execbuffer(dev, file, args, exec2_list); /* * Now that we have begun execution of the batchbuffer, we ignore @@ -3080,7 +3278,6 @@ end:; } args->flags &= ~__I915_EXEC_UNKNOWN_FLAGS; - put_fence_array(args, fences); kvfree(exec2_list); return err; } diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 24322ef08aa4..d03da2f64a49 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -4555,7 +4555,7 @@ static int gen8_emit_flush_render(struct i915_request *request, vf_flush_wa = true; /* WaForGAMHang:kbl */ - if (IS_KBL_REVID(request->engine->i915, 0, KBL_REVID_B0)) + if (IS_KBL_GT_REVID(request->engine->i915, 0, KBL_REVID_B0)) dc_flush_wa = true; } diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 5726cd0a37e0..be5a4685c991 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -52,6 +52,24 @@ * - Public functions to init or apply the given workaround type. */ +/* + * KBL revision ID ordering is bizarre; higher revision ID's map to lower + * steppings in some cases. So rather than test against the revision ID + * directly, let's map that into our own range of increasing ID's that we + * can test against in a regular manner. + */ + +const struct i915_rev_steppings kbl_revids[] = { + [0] = { .gt_stepping = KBL_REVID_A0, .disp_stepping = KBL_REVID_A0 }, + [1] = { .gt_stepping = KBL_REVID_B0, .disp_stepping = KBL_REVID_B0 }, + [2] = { .gt_stepping = KBL_REVID_C0, .disp_stepping = KBL_REVID_B0 }, + [3] = { .gt_stepping = KBL_REVID_D0, .disp_stepping = KBL_REVID_B0 }, + [4] = { .gt_stepping = KBL_REVID_F0, .disp_stepping = KBL_REVID_C0 }, + [5] = { .gt_stepping = KBL_REVID_C0, .disp_stepping = KBL_REVID_B1 }, + [6] = { .gt_stepping = KBL_REVID_D1, .disp_stepping = KBL_REVID_B1 }, + [7] = { .gt_stepping = KBL_REVID_G0, .disp_stepping = KBL_REVID_C0 }, +}; + static void wa_init_start(struct i915_wa_list *wal, const char *name, const char *engine_name) { wal->name = name; @@ -470,7 +488,7 @@ static void kbl_ctx_workarounds_init(struct intel_engine_cs *engine, gen9_ctx_workarounds_init(engine, wal); /* WaToEnableHwFixForPushConstHWBug:kbl */ - if (IS_KBL_REVID(i915, KBL_REVID_C0, REVID_FOREVER)) + if (IS_KBL_GT_REVID(i915, KBL_REVID_C0, REVID_FOREVER)) WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); @@ -596,8 +614,8 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN11_DIS_PICK_2ND_EU); } -static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine, - struct i915_wa_list *wal) +static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine, + struct i915_wa_list *wal) { /* * Wa_1409142259:tgl @@ -607,12 +625,28 @@ static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine, * Wa_1409207793:tgl * Wa_1409178076:tgl * Wa_1408979724:tgl + * Wa_14010443199:rkl + * Wa_14010698770:rkl */ WA_SET_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3, GEN12_DISABLE_CPS_AWARE_COLOR_PIPE); + /* WaDisableGPGPUMidThreadPreemption:gen12 */ + WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, + GEN9_PREEMPT_GPGPU_LEVEL_MASK, + GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL); +} + +static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine, + struct i915_wa_list *wal) +{ + gen12_ctx_workarounds_init(engine, wal); + /* - * Wa_1604555607:gen12 and Wa_1608008084:gen12 + * Wa_1604555607:tgl,rkl + * + * Note that the implementation of this workaround is further modified + * according to the FF_MODE2 guidance given by Wa_1608008084:gen12. * FF_MODE2 register will return the wrong value when read. The default * value for this register is zero for all fields and there are no bit * masks. So instead of doing a RMW we should just write the GS Timer @@ -623,11 +657,6 @@ static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine, FF_MODE2_GS_TIMER_MASK | FF_MODE2_TDS_TIMER_MASK, FF_MODE2_GS_TIMER_224 | FF_MODE2_TDS_TIMER_128, 0); - - /* WaDisableGPGPUMidThreadPreemption:tgl */ - WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, - GEN9_PREEMPT_GPGPU_LEVEL_MASK, - GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL); } static void @@ -642,8 +671,10 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine, wa_init_start(wal, name, engine->name); - if (IS_GEN(i915, 12)) + if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) tgl_ctx_workarounds_init(engine, wal); + else if (IS_GEN(i915, 12)) + gen12_ctx_workarounds_init(engine, wal); else if (IS_GEN(i915, 11)) icl_ctx_workarounds_init(engine, wal); else if (IS_CANNONLAKE(i915)) @@ -995,7 +1026,7 @@ kbl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) gen9_gt_workarounds_init(i915, wal); /* WaDisableDynamicCreditSharing:kbl */ - if (IS_KBL_REVID(i915, 0, KBL_REVID_B0)) + if (IS_KBL_GT_REVID(i915, 0, KBL_REVID_B0)) wa_write_or(wal, GAMT_CHKN_BIT_REG, GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING); @@ -1176,9 +1207,16 @@ icl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) } static void -tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +gen12_gt_workarounds_init(struct drm_i915_private *i915, + struct i915_wa_list *wal) { wa_init_mcr(i915, wal); +} + +static void +tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) +{ + gen12_gt_workarounds_init(i915, wal); /* Wa_1409420604:tgl */ if (IS_TGL_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) @@ -1196,8 +1234,10 @@ tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) static void gt_init_workarounds(struct drm_i915_private *i915, struct i915_wa_list *wal) { - if (IS_GEN(i915, 12)) + if (IS_TIGERLAKE(i915)) tgl_gt_workarounds_init(i915, wal); + else if (IS_GEN(i915, 12)) + gen12_gt_workarounds_init(i915, wal); else if (IS_GEN(i915, 11)) icl_gt_workarounds_init(i915, wal); else if (IS_CANNONLAKE(i915)) @@ -1630,18 +1670,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN12_DISABLE_POSH_BUSY_FF_DOP_CG); /* - * Wa_1607030317:tgl - * Wa_1607186500:tgl - * Wa_1607297627:tgl there is 3 entries for this WA on BSpec, 2 - * of then says it is fixed on B0 the other one says it is - * permanent - */ - wa_masked_en(wal, - GEN6_RC_SLEEP_PSMI_CONTROL, - GEN12_WAIT_FOR_EVENT_POWER_DOWN_DISABLE | - GEN8_RC_SEMA_IDLE_MSG_DISABLE); - - /* * Wa_1606679103:tgl * (see also Wa_1606682166:icl) */ @@ -1654,22 +1682,17 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) VSUNIT_CLKGATE_DIS_TGL); } - if (IS_TIGERLAKE(i915)) { - /* Wa_1606931601:tgl */ + if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { + /* Wa_1606931601:tgl,rkl */ wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ); - /* Wa_1409804808:tgl */ + /* Wa_1409804808:tgl,rkl */ wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_PUSH_CONST_DEREF_HOLD_DIS); - /* Wa_1606700617:tgl */ - wa_masked_en(wal, - GEN9_CS_DEBUG_MODE1, - FF_DOP_CLOCK_GATE_DISABLE); - /* * Wa_1409085225:tgl - * Wa_14010229206:tgl + * Wa_14010229206:tgl,rkl */ wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH); @@ -1677,9 +1700,29 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) * Wa_1407928979:tgl A* * Wa_18011464164:tgl B0+ * Wa_22010931296:tgl B0+ + * Wa_14010919138:rkl */ wa_write_or(wal, GEN7_FF_THREAD_MODE, GEN12_FF_TESSELATION_DOP_GATE_DISABLE); + + /* + * Wa_1607030317:tgl + * Wa_1607186500:tgl + * Wa_1607297627:tgl,rkl there are multiple entries for this + * WA in the BSpec; some indicate this is an A0-only WA, + * others indicate it applies to all steppings. + */ + wa_masked_en(wal, + GEN6_RC_SLEEP_PSMI_CONTROL, + GEN12_WAIT_FOR_EVENT_POWER_DOWN_DISABLE | + GEN8_RC_SEMA_IDLE_MSG_DISABLE); + } + + if (IS_TIGERLAKE(i915)) { + /* Wa_1606700617:tgl */ + wa_masked_en(wal, + GEN9_CS_DEBUG_MODE1, + FF_DOP_CLOCK_GATE_DISABLE); } if (IS_GEN(i915, 11)) { @@ -1898,7 +1941,7 @@ xcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) struct drm_i915_private *i915 = engine->i915; /* WaKBLVECSSemaphoreWaitPoll:kbl */ - if (IS_KBL_REVID(i915, KBL_REVID_A0, KBL_REVID_E0)) { + if (IS_KBL_GT_REVID(i915, KBL_REVID_A0, KBL_REVID_E0)) { wa_write(wal, RING_SEMA_WAIT_POLL(engine->mmio_base), 1); diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c index 73243ba59c7d..e73854dd2fe0 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c @@ -47,7 +47,10 @@ static int pulse_active(struct i915_active *active) static void pulse_free(struct kref *kref) { - kfree(container_of(kref, struct pulse, kref)); + struct pulse *p = container_of(kref, typeof(*p), kref); + + i915_active_fini(&p->active); + kfree(p); } static void pulse_put(struct pulse *p) diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c index 8624f5d2a1f3..34b403d47840 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rps.c +++ b/drivers/gpu/drm/i915/gt/selftest_rps.c @@ -700,7 +700,7 @@ int live_rps_frequency_cs(void *arg) f = act; /* may skip ahead [pcu granularity] */ } - err = -EINVAL; + err = -EINTR; /* ignore error, continue on with test */ } err_vma: @@ -841,7 +841,7 @@ int live_rps_frequency_srm(void *arg) f = act; /* may skip ahead [pcu granularity] */ } - err = -EINVAL; + err = -EINTR; /* ignore error, continue on with test */ } err_vma: diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c index fb5b7d3498a6..6564c989dbee 100644 --- a/drivers/gpu/drm/i915/gt/selftest_timeline.c +++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c @@ -491,7 +491,7 @@ checked_intel_timeline_create(struct intel_gt *gt) if (IS_ERR(tl)) return tl; - if (*tl->hwsp_seqno != tl->seqno) { + if (READ_ONCE(*tl->hwsp_seqno) != tl->seqno) { pr_err("Timeline created with incorrect breadcrumb, found %x, expected %x\n", *tl->hwsp_seqno, tl->seqno); intel_timeline_put(tl); @@ -561,9 +561,9 @@ static int live_hwsp_engine(void *arg) for (n = 0; n < count; n++) { struct intel_timeline *tl = timelines[n]; - if (!err && *tl->hwsp_seqno != n) { - pr_err("Invalid seqno stored in timeline %lu @ %x, found 0x%x\n", - n, tl->hwsp_offset, *tl->hwsp_seqno); + if (!err && READ_ONCE(*tl->hwsp_seqno) != n) { + GEM_TRACE_ERR("Invalid seqno:%lu stored in timeline %llu @ %x, found 0x%x\n", + n, tl->fence_context, tl->hwsp_offset, *tl->hwsp_seqno); GEM_TRACE_DUMP(); err = -EINVAL; } @@ -633,9 +633,9 @@ out: for (n = 0; n < count; n++) { struct intel_timeline *tl = timelines[n]; - if (!err && *tl->hwsp_seqno != n) { - pr_err("Invalid seqno stored in timeline %lu @ %x, found 0x%x\n", - n, tl->hwsp_offset, *tl->hwsp_seqno); + if (!err && READ_ONCE(*tl->hwsp_seqno) != n) { + GEM_TRACE_ERR("Invalid seqno:%lu stored in timeline %llu @ %x, found 0x%x\n", + n, tl->fence_context, tl->hwsp_offset, *tl->hwsp_seqno); GEM_TRACE_DUMP(); err = -EINVAL; } @@ -733,7 +733,8 @@ static int live_hwsp_wrap(void *arg) goto out; } - if (*hwsp_seqno[0] != seqno[0] || *hwsp_seqno[1] != seqno[1]) { + if (READ_ONCE(*hwsp_seqno[0]) != seqno[0] || + READ_ONCE(*hwsp_seqno[1]) != seqno[1]) { pr_err("Bad timeline values: found (%x, %x), expected (%x, %x)\n", *hwsp_seqno[0], *hwsp_seqno[1], seqno[0], seqno[1]); @@ -966,9 +967,10 @@ static int live_hwsp_recycle(void *arg) break; } - if (*tl->hwsp_seqno != count) { - pr_err("Invalid seqno stored in timeline %lu @ tl->hwsp_offset, found 0x%x\n", - count, *tl->hwsp_seqno); + if (READ_ONCE(*tl->hwsp_seqno) != count) { + GEM_TRACE_ERR("Invalid seqno:%lu stored in timeline %llu @ %x found 0x%x\n", + count, tl->fence_context, + tl->hwsp_offset, *tl->hwsp_seqno); GEM_TRACE_DUMP(); err = -EINVAL; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 59b27aba15c6..80e8b6c3bc8c 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -51,8 +51,8 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, * Note that RKL uses the same firmware as TGL. */ #define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \ - fw_def(ROCKETLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 0, 12)) \ - fw_def(TIGERLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 0, 12)) \ + fw_def(ROCKETLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \ + fw_def(TIGERLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \ fw_def(ELKHARTLAKE, 0, guc_def(ehl, 33, 0, 4), huc_def(ehl, 9, 0, 0)) \ fw_def(ICELAKE, 0, guc_def(icl, 33, 0, 0), huc_def(icl, 9, 0, 0)) \ fw_def(COMETLAKE, 5, guc_def(cml, 33, 0, 0), huc_def(cml, 4, 0, 0)) \ diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c index d960d0be5bd2..1e1253207425 100644 --- a/drivers/gpu/drm/i915/i915_active.c +++ b/drivers/gpu/drm/i915/i915_active.c @@ -758,7 +758,6 @@ int i915_active_acquire_preallocate_barrier(struct i915_active *ref, intel_engine_mask_t tmp, mask = engine->mask; struct llist_node *first = NULL, *last = NULL; struct intel_gt *gt = engine->gt; - int err; GEM_BUG_ON(i915_active_is_idle(ref)); @@ -781,10 +780,8 @@ int i915_active_acquire_preallocate_barrier(struct i915_active *ref, node = reuse_idle_barrier(ref, idx); if (!node) { node = kmem_cache_alloc(global.slab_cache, GFP_KERNEL); - if (!node) { - err = ENOMEM; + if (!node) goto unwind; - } RCU_INIT_POINTER(node->base.fence, NULL); node->base.cb.func = node_retire; @@ -832,7 +829,7 @@ unwind: kmem_cache_free(global.slab_cache, node); } - return err; + return -ENOMEM; } void i915_active_acquire_barrier(struct i915_active *ref) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5fd5af4bc855..e6918c7c0709 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -392,7 +392,7 @@ static void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv) pre |= IS_HSW_EARLY_SDV(dev_priv); pre |= IS_SKL_REVID(dev_priv, 0, SKL_REVID_F0); pre |= IS_BXT_REVID(dev_priv, 0, BXT_REVID_B_LAST); - pre |= IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0); + pre |= IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_A0); pre |= IS_GLK_REVID(dev_priv, 0, GLK_REVID_A2); if (pre) { @@ -1846,7 +1846,8 @@ static struct drm_driver driver = { */ .driver_features = DRIVER_GEM | - DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ, + DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ | + DRIVER_SYNCOBJ_TIMELINE, .release = i915_driver_release, .open = i915_driver_open, .lastclose = i915_driver_lastclose, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e4f7f6518945..1314e0e92c41 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -108,8 +108,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20200715" -#define DRIVER_TIMESTAMP 1594811881 +#define DRIVER_DATE "20200824" +#define DRIVER_TIMESTAMP 1598293597 struct drm_i915_gem_object; @@ -506,6 +506,7 @@ struct i915_psr { bool link_standby; bool colorimetry_support; bool psr2_enabled; + bool psr2_sel_fetch_enabled; u8 sink_sync_latency; ktime_t last_entry_attempt; ktime_t last_exit; @@ -1045,6 +1046,14 @@ struct drm_i915_private { struct intel_l3_parity l3_parity; /* + * HTI (aka HDPORT) state read during initial hw readout. Most + * platforms don't have HTI, so this will just stay 0. Those that do + * will use this later to figure out which PLLs and PHYs are unavailable + * for driver usage. + */ + u32 hti_state; + + /* * edram size in MB. * Cannot be determined by PCIID. You must always read a register. */ @@ -1489,6 +1498,12 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_ICL_WITH_PORT_F(dev_priv) \ IS_SUBPLATFORM(dev_priv, INTEL_ICELAKE, INTEL_SUBPLATFORM_PORTF) +#define IS_TGL_U(dev_priv) \ + IS_SUBPLATFORM(dev_priv, INTEL_TIGERLAKE, INTEL_SUBPLATFORM_ULT) + +#define IS_TGL_Y(dev_priv) \ + IS_SUBPLATFORM(dev_priv, INTEL_TIGERLAKE, INTEL_SUBPLATFORM_ULX) + #define SKL_REVID_A0 0x0 #define SKL_REVID_B0 0x1 #define SKL_REVID_C0 0x2 @@ -1509,14 +1524,34 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_BXT_REVID(dev_priv, since, until) \ (IS_BROXTON(dev_priv) && IS_REVID(dev_priv, since, until)) -#define KBL_REVID_A0 0x0 -#define KBL_REVID_B0 0x1 -#define KBL_REVID_C0 0x2 -#define KBL_REVID_D0 0x3 -#define KBL_REVID_E0 0x4 +enum { + KBL_REVID_A0, + KBL_REVID_B0, + KBL_REVID_B1, + KBL_REVID_C0, + KBL_REVID_D0, + KBL_REVID_D1, + KBL_REVID_E0, + KBL_REVID_F0, + KBL_REVID_G0, +}; + +struct i915_rev_steppings { + u8 gt_stepping; + u8 disp_stepping; +}; + +/* Defined in intel_workarounds.c */ +extern const struct i915_rev_steppings kbl_revids[]; -#define IS_KBL_REVID(dev_priv, since, until) \ - (IS_KABYLAKE(dev_priv) && IS_REVID(dev_priv, since, until)) +#define IS_KBL_GT_REVID(dev_priv, since, until) \ + (IS_KABYLAKE(dev_priv) && \ + kbl_revids[INTEL_REVID(dev_priv)].gt_stepping >= since && \ + kbl_revids[INTEL_REVID(dev_priv)].gt_stepping <= until) +#define IS_KBL_DISP_REVID(dev_priv, since, until) \ + (IS_KABYLAKE(dev_priv) && \ + kbl_revids[INTEL_REVID(dev_priv)].disp_stepping >= since && \ + kbl_revids[INTEL_REVID(dev_priv)].disp_stepping <= until) #define GLK_REVID_A0 0x0 #define GLK_REVID_A1 0x1 @@ -1665,6 +1700,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_PSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_psr) #define HAS_PSR_HW_TRACKING(dev_priv) \ (INTEL_INFO(dev_priv)->display.has_psr_hw_tracking) +#define HAS_PSR2_SEL_FETCH(dev_priv) (INTEL_GEN(dev_priv) >= 12) #define HAS_TRANSCODER(dev_priv, trans) ((INTEL_INFO(dev_priv)->cpu_transcoder_mask & BIT(trans)) != 0) #define HAS_RC6(dev_priv) (INTEL_INFO(dev_priv)->has_rc6) diff --git a/drivers/gpu/drm/i915/i915_getparam.c b/drivers/gpu/drm/i915/i915_getparam.c index 421613219ae9..f96032c60a12 100644 --- a/drivers/gpu/drm/i915/i915_getparam.c +++ b/drivers/gpu/drm/i915/i915_getparam.c @@ -132,6 +132,7 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data, case I915_PARAM_HAS_EXEC_BATCH_FIRST: case I915_PARAM_HAS_EXEC_FENCE_ARRAY: case I915_PARAM_HAS_EXEC_SUBMIT_FENCE: + case I915_PARAM_HAS_EXEC_TIMELINE_FENCES: /* For the time being all of these are always true; * if some supported hardware does not have one of these * features this value needs to be provided from diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 8d8db9ff0a48..7f139ea4a90b 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -102,6 +102,11 @@ i915_param_named(psr_safest_params, bool, 0400, "is helpful to detect if PSR issues are related to bad values set in " " VBT. (0=use VBT parameters, 1=use safest parameters)"); +i915_param_named_unsafe(enable_psr2_sel_fetch, bool, 0400, + "Enable PSR2 selective fetch " + "(0=disabled, 1=enabled) " + "Default: 0"); + i915_param_named_unsafe(force_probe, charp, 0400, "Force probe the driver for specified devices. " "See CONFIG_DRM_I915_FORCE_PROBE for details."); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 53fb5ba8fbed..330c03e2b4f7 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -54,6 +54,7 @@ struct drm_printer; param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ param(bool, psr_safest_params, false, 0600) \ + param(bool, enable_psr2_sel_fetch, false, 0600) \ param(int, disable_power_well, -1, 0400) \ param(int, enable_ips, 1, 0600) \ param(int, invert_brightness, 0, 0600) \ diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 2338f92ce490..366ddfc8df6b 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -890,6 +890,7 @@ static const struct intel_device_info rkl_info = { .cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | BIT(TRANSCODER_C), .require_force_probe = 1, + .display.has_hti = 1, .display.has_psr_hw_tracking = 0, .platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(VECS0) | BIT(VCS0), diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4e796ff4d7d0..ac691927e29d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1898,6 +1898,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define PWR_DOWN_LN_3_1_0 (0xb << 4) #define PWR_DOWN_LN_MASK (0xf << 4) #define PWR_DOWN_LN_SHIFT 4 +#define EDP4K2K_MODE_OVRD_EN (1 << 3) +#define EDP4K2K_MODE_OVRD_OPTIMIZED (1 << 2) #define ICL_PORT_CL_DW12(phy) _MMIO(_ICL_PORT_CL_DW(12, phy)) #define ICL_LANE_ENABLE_AUX (1 << 0) @@ -2919,6 +2921,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define MBUS_BBOX_CTL_S1 _MMIO(0x45040) #define MBUS_BBOX_CTL_S2 _MMIO(0x45044) +#define HDPORT_STATE _MMIO(0x45050) +#define HDPORT_DPLL_USED_MASK REG_GENMASK(14, 12) +#define HDPORT_PHY_USED_DP(phy) REG_BIT(2 * (phy) + 2) +#define HDPORT_PHY_USED_HDMI(phy) REG_BIT(2 * (phy) + 1) +#define HDPORT_ENABLED REG_BIT(0) + /* Make render/texture TLB fetches lower priorty than associated data * fetches. This is not turned on by default */ @@ -7870,6 +7878,7 @@ enum { # define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2) #define CHICKEN_PAR1_1 _MMIO(0x42080) +#define DIS_RAM_BYPASS_PSR2_MAN_TRACK (1 << 16) #define SKL_DE_COMPRESSED_HASH_MODE (1 << 15) #define DPA_MASK_VBLANK_SRD (1 << 15) #define FORCE_ARB_IDLE_PLANES (1 << 14) @@ -8711,6 +8720,7 @@ enum { #define PCH_GMBUSUNIT_CLOCK_GATE_DISABLE (1 << 31) #define PCH_DPLUNIT_CLOCK_GATE_DISABLE (1 << 30) #define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1 << 29) +#define PCH_DPMGUNIT_CLOCK_GATE_DISABLE (1 << 15) #define PCH_CPUNIT_CLOCK_GATE_DISABLE (1 << 14) #define CNP_PWM_CGE_GATING_DISABLE (1 << 13) #define PCH_LP_PARTITION_LEVEL_DISABLE (1 << 12) @@ -9217,8 +9227,8 @@ enum { #define DISPLAY_IPS_CONTROL 0x19 #define TGL_PCODE_TCCOLD 0x26 #define TGL_PCODE_EXIT_TCCOLD_DATA_L_EXIT_FAILED REG_BIT(0) -#define TGL_PCODE_EXIT_TCCOLD_DATA_H_BLOCK_REQ 0 -#define TGL_PCODE_EXIT_TCCOLD_DATA_H_UNBLOCK_REQ REG_BIT(0) +#define TGL_PCODE_EXIT_TCCOLD_DATA_L_BLOCK_REQ 0 +#define TGL_PCODE_EXIT_TCCOLD_DATA_L_UNBLOCK_REQ REG_BIT(0) /* See also IPS_CTL */ #define IPS_PCODE_CONTROL (1 << 30) #define HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL 0x1A @@ -10277,12 +10287,18 @@ enum skl_power_gate { #define ICL_DPCLKA_CFGCR0 _MMIO(0x164280) #define ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) (1 << _PICK(phy, 10, 11, 24)) +#define RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) REG_BIT((phy) + 10) #define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < PORT_TC4 ? \ (tc_port) + 12 : \ (tc_port) - PORT_TC4 + 21)) #define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) ((phy) * 2) #define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (3 << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) #define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) ((pll) << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) +#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) _PICK(phy, 0, 2, 4, 27) +#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) \ + (3 << RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) +#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) \ + ((pll) << RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) /* CNL PLL */ #define DPLL0_ENABLE 0x46010 @@ -10503,19 +10519,21 @@ enum skl_power_gate { #define _TGL_DPLL0_CFGCR0 0x164284 #define _TGL_DPLL1_CFGCR0 0x16428C -/* TODO: add DPLL4 */ #define _TGL_TBTPLL_CFGCR0 0x16429C #define TGL_DPLL_CFGCR0(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR0, \ _TGL_DPLL1_CFGCR0, \ _TGL_TBTPLL_CFGCR0) +#define RKL_DPLL_CFGCR0(pll) _MMIO_PLL(pll, _TGL_DPLL0_CFGCR0, \ + _TGL_DPLL1_CFGCR0) #define _TGL_DPLL0_CFGCR1 0x164288 #define _TGL_DPLL1_CFGCR1 0x164290 -/* TODO: add DPLL4 */ #define _TGL_TBTPLL_CFGCR1 0x1642A0 #define TGL_DPLL_CFGCR1(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR1, \ _TGL_DPLL1_CFGCR1, \ _TGL_TBTPLL_CFGCR1) +#define RKL_DPLL_CFGCR1(pll) _MMIO_PLL(pll, _TGL_DPLL0_CFGCR1, \ + _TGL_DPLL1_CFGCR1) #define _DKL_PHY1_BASE 0x168000 #define _DKL_PHY2_BASE 0x169000 @@ -12336,4 +12354,10 @@ enum skl_power_gate { #define DSB_ENABLE (1 << 31) #define DSB_STATUS (1 << 0) +#define TGL_ROOT_DEVICE_ID 0x9A00 +#define TGL_ROOT_DEVICE_MASK 0xFF00 +#define TGL_ROOT_DEVICE_SKU_MASK 0xF +#define TGL_ROOT_DEVICE_SKU_ULX 0x2 +#define TGL_ROOT_DEVICE_SKU_ULT 0x4 + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 0b2fe55e6194..7a05850ca931 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1783,11 +1783,8 @@ long i915_request_wait(struct i915_request *rq, * but at a cost of spending more power processing the workload * (bad for battery). */ - if (flags & I915_WAIT_PRIORITY) { - if (!i915_request_started(rq) && - INTEL_GEN(rq->engine->i915) >= 6) - intel_rps_boost(rq); - } + if (flags & I915_WAIT_PRIORITY && !i915_request_started(rq)) + intel_rps_boost(rq); wait.tsk = current; if (dma_fence_add_callback(&rq->fence, &wait.cb, request_wait_wake)) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 40c590db3c76..e2aa5bc3a6e0 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -346,6 +346,25 @@ void intel_device_info_subplatform_init(struct drm_i915_private *i915) mask = BIT(INTEL_SUBPLATFORM_PORTF); } + if (IS_TIGERLAKE(i915)) { + struct pci_dev *root, *pdev = i915->drm.pdev; + + root = list_first_entry(&pdev->bus->devices, typeof(*root), bus_list); + + drm_WARN_ON(&i915->drm, mask); + drm_WARN_ON(&i915->drm, (root->device & TGL_ROOT_DEVICE_MASK) != + TGL_ROOT_DEVICE_ID); + + switch (root->device & TGL_ROOT_DEVICE_SKU_MASK) { + case TGL_ROOT_DEVICE_SKU_ULX: + mask = BIT(INTEL_SUBPLATFORM_ULX); + break; + case TGL_ROOT_DEVICE_SKU_ULT: + mask = BIT(INTEL_SUBPLATFORM_ULT); + break; + } + } + GEM_BUG_ON(mask & ~INTEL_SUBPLATFORM_BITS); RUNTIME_INFO(i915)->platform_mask[pi] |= mask; diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index fd2385457ab6..6a3d607218aa 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -146,6 +146,7 @@ enum intel_ppgtt_type { func(has_gmch); \ func(has_hdcp); \ func(has_hotplug); \ + func(has_hti); \ func(has_ipc); \ func(has_modular_fia); \ func(has_overlay); \ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cfabbe0481ab..b4bd19266b8c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -100,12 +100,6 @@ static void gen9_init_clock_gating(struct drm_i915_private *dev_priv) */ I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) | DISP_FBC_MEMORY_WAKE); - - if (IS_SKYLAKE(dev_priv)) { - /* WaDisableDopClockGating */ - I915_WRITE(GEN7_MISCCPCTL, I915_READ(GEN7_MISCCPCTL) - & ~GEN7_DOP_CLOCK_GATE_ENABLE); - } } static void bxt_init_clock_gating(struct drm_i915_private *dev_priv) @@ -7223,12 +7217,12 @@ static void kbl_init_clock_gating(struct drm_i915_private *dev_priv) gen9_init_clock_gating(dev_priv); /* WaDisableSDEUnitClockGating:kbl */ - if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) + if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0)) I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | GEN8_SDEUNIT_CLOCK_GATE_DISABLE); /* WaDisableGamClockGating:kbl */ - if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) + if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0)) I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) | GEN6_GAMUNIT_CLOCK_GATE_DISABLE); @@ -7251,6 +7245,10 @@ static void skl_init_clock_gating(struct drm_i915_private *dev_priv) { gen9_init_clock_gating(dev_priv); + /* WaDisableDopClockGating:skl */ + I915_WRITE(GEN7_MISCCPCTL, I915_READ(GEN7_MISCCPCTL) & + ~GEN7_DOP_CLOCK_GATE_ENABLE); + /* WAC6entrylatency:skl */ I915_WRITE(FBC_LLC_READ_CTRL, I915_READ(FBC_LLC_READ_CTRL) | FBC_LLC_FULLY_OPEN); diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 57dd6f5122ee..c1dcd4b91bda 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -331,7 +331,7 @@ static int __igt_breadcrumbs_smoketest(void *arg) if (!wait) { i915_sw_fence_commit(submit); heap_fence_put(submit); - err = ENOMEM; + err = -ENOMEM; break; } diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 8791d60be92e..af757d1e21fe 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -455,13 +455,6 @@ static int imx_ldb_register(struct drm_device *drm, drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder); } - if (imx_ldb_ch->panel) { - ret = drm_panel_attach(imx_ldb_ch->panel, - &imx_ldb_ch->connector); - if (ret) - return ret; - } - return 0; } @@ -702,9 +695,6 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, for (i = 0; i < 2; i++) { struct imx_ldb_channel *channel = &imx_ldb->channel[i]; - if (channel->panel) - drm_panel_detach(channel->panel); - kfree(channel->edid); i2c_put_adapter(channel->ddc); } diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index a831b5bd1613..8232f512b9ed 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -289,9 +289,6 @@ static int imx_pd_register(struct drm_device *drm, DRM_MODE_CONNECTOR_DPI); } - if (imxpd->panel) - drm_panel_attach(imxpd->panel, &imxpd->connector); - if (imxpd->next_bridge) { ret = drm_bridge_attach(encoder, imxpd->next_bridge, &imxpd->bridge, 0); @@ -357,9 +354,6 @@ static void imx_pd_unbind(struct device *dev, struct device *master, { struct imx_parallel_display *imxpd = dev_get_drvdata(dev); - if (imxpd->panel) - drm_panel_detach(imxpd->panel); - kfree(imxpd->edid); } diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index ada990a7f911..5dab9c3d0a52 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -199,26 +199,20 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc, { struct ingenic_drm *priv = drm_crtc_get_priv(crtc); struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL; - long rate; - - if (!drm_atomic_crtc_needs_modeset(state)) - return 0; - - if (state->mode.hdisplay > priv->soc_info->max_width || - state->mode.vdisplay > priv->soc_info->max_height) - return -EINVAL; - rate = clk_round_rate(priv->pix_clk, - state->adjusted_mode.clock * 1000); - if (rate < 0) - return rate; - - if (priv->soc_info->has_osd) { + if (drm_atomic_crtc_needs_modeset(state) && priv->soc_info->has_osd) { f1_state = drm_atomic_get_plane_state(state->state, &priv->f1); + if (IS_ERR(f1_state)) + return PTR_ERR(f1_state); + f0_state = drm_atomic_get_plane_state(state->state, &priv->f0); + if (IS_ERR(f0_state)) + return PTR_ERR(f0_state); if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) { ipu_state = drm_atomic_get_plane_state(state->state, priv->ipu_plane); + if (IS_ERR(ipu_state)) + return PTR_ERR(ipu_state); /* IPU and F1 planes cannot be enabled at the same time. */ if (f1_state->fb && ipu_state->fb) { @@ -235,6 +229,24 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc, return 0; } +static enum drm_mode_status +ingenic_drm_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) +{ + struct ingenic_drm *priv = drm_crtc_get_priv(crtc); + long rate; + + if (mode->hdisplay > priv->soc_info->max_width) + return MODE_BAD_HVALUE; + if (mode->vdisplay > priv->soc_info->max_height) + return MODE_BAD_VVALUE; + + rate = clk_round_rate(priv->pix_clk, mode->clock * 1000); + if (rate < 0) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + static void ingenic_drm_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *oldstate) { @@ -648,6 +660,7 @@ static const struct drm_crtc_helper_funcs ingenic_drm_crtc_helper_funcs = { .atomic_begin = ingenic_drm_crtc_atomic_begin, .atomic_flush = ingenic_drm_crtc_atomic_flush, .atomic_check = ingenic_drm_crtc_atomic_check, + .mode_valid = ingenic_drm_crtc_mode_valid, }; static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs = { diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c index 7a0a8bd865d3..fc8c6e970ee3 100644 --- a/drivers/gpu/drm/ingenic/ingenic-ipu.c +++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c @@ -35,6 +35,7 @@ struct soc_info { const u32 *formats; size_t num_formats; bool has_bicubic; + bool manual_restart; void (*set_coefs)(struct ingenic_ipu *ipu, unsigned int reg, unsigned int sharpness, bool downscale, @@ -48,6 +49,7 @@ struct ingenic_ipu { struct regmap *map; struct clk *clk; const struct soc_info *soc_info; + bool clk_enabled; unsigned int num_w, num_h, denom_w, denom_h; @@ -287,12 +289,23 @@ static void ingenic_ipu_plane_atomic_update(struct drm_plane *plane, const struct drm_format_info *finfo; u32 ctrl, stride = 0, coef_index = 0, format = 0; bool needs_modeset, upscaling_w, upscaling_h; + int err; if (!state || !state->fb) return; finfo = drm_format_info(state->fb->format->format); + if (!ipu->clk_enabled) { + err = clk_enable(ipu->clk); + if (err) { + dev_err(ipu->dev, "Unable to enable clock: %d\n", err); + return; + } + + ipu->clk_enabled = true; + } + /* Reset all the registers if needed */ needs_modeset = drm_atomic_crtc_needs_modeset(state->crtc->state); if (needs_modeset) { @@ -577,6 +590,11 @@ static void ingenic_ipu_plane_atomic_disable(struct drm_plane *plane, regmap_clear_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_CHIP_EN); ingenic_drm_plane_disable(ipu->master, plane); + + if (ipu->clk_enabled) { + clk_disable(ipu->clk); + ipu->clk_enabled = false; + } } static const struct drm_plane_helper_funcs ingenic_ipu_plane_helper_funcs = { @@ -645,7 +663,8 @@ static irqreturn_t ingenic_ipu_irq_handler(int irq, void *arg) unsigned int dummy; /* dummy read allows CPU to reconfigure IPU */ - regmap_read(ipu->map, JZ_REG_IPU_STATUS, &dummy); + if (ipu->soc_info->manual_restart) + regmap_read(ipu->map, JZ_REG_IPU_STATUS, &dummy); /* ACK interrupt */ regmap_write(ipu->map, JZ_REG_IPU_STATUS, 0); @@ -656,7 +675,8 @@ static irqreturn_t ingenic_ipu_irq_handler(int irq, void *arg) regmap_write(ipu->map, JZ_REG_IPU_V_ADDR, ipu->addr_v); /* Run IPU for the new frame */ - regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RUN); + if (ipu->soc_info->manual_restart) + regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RUN); drm_crtc_handle_vblank(crtc); @@ -758,9 +778,9 @@ static int ingenic_ipu_bind(struct device *dev, struct device *master, void *d) drm_object_attach_property(&plane->base, ipu->sharpness_prop, ipu->sharpness); - err = clk_prepare_enable(ipu->clk); + err = clk_prepare(ipu->clk); if (err) { - dev_err(dev, "Unable to enable clock\n"); + dev_err(dev, "Unable to prepare clock\n"); return err; } @@ -772,7 +792,7 @@ static void ingenic_ipu_unbind(struct device *dev, { struct ingenic_ipu *ipu = dev_get_drvdata(dev); - clk_disable_unprepare(ipu->clk); + clk_unprepare(ipu->clk); } static const struct component_ops ingenic_ipu_ops = { @@ -792,10 +812,16 @@ static int ingenic_ipu_remove(struct platform_device *pdev) } static const u32 jz4725b_ipu_formats[] = { + /* + * While officially supported, packed YUV 4:2:2 formats can cause + * random hardware crashes on JZ4725B under certain circumstances. + * It seems to happen with some specific resize ratios. + * Until a proper workaround or fix is found, disable these formats. DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, + */ DRM_FORMAT_YUV411, DRM_FORMAT_YUV420, DRM_FORMAT_YUV422, @@ -806,6 +832,7 @@ static const struct soc_info jz4725b_soc_info = { .formats = jz4725b_ipu_formats, .num_formats = ARRAY_SIZE(jz4725b_ipu_formats), .has_bicubic = false, + .manual_restart = true, .set_coefs = jz4725b_set_coefs, }; @@ -831,6 +858,7 @@ static const struct soc_info jz4760_soc_info = { .formats = jz4760_ipu_formats, .num_formats = ARRAY_SIZE(jz4760_ipu_formats), .has_bicubic = true, + .manual_restart = false, .set_coefs = jz4760_set_coefs, }; diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index 4d2290f88edb..c271e5bf042e 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -7,6 +7,7 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/dma-buf.h> +#include <linux/regulator/consumer.h> #include <drm/drm_device.h> #include <drm/drm_fb_cma_helper.h> @@ -89,7 +90,7 @@ void mcde_display_irq(struct mcde *mcde) * the update function is called, then we disable the * flow on the channel once we get the TE IRQ. */ - if (mcde->oneshot_mode) { + if (mcde->flow_mode == MCDE_COMMAND_ONESHOT_FLOW) { spin_lock(&mcde->flow_lock); if (--mcde->flow_active == 0) { dev_dbg(mcde->dev, "TE0 IRQ\n"); @@ -333,7 +334,7 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, enum mcde_extsrc src, enum mcde_channel ch, const struct drm_display_mode *mode, - u32 format) + u32 format, int cpp) { u32 val; u32 conf1; @@ -342,6 +343,7 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, u32 ljinc; u32 cr; u32 comp; + u32 pixel_fetcher_watermark; switch (ovl) { case MCDE_OVERLAY_0: @@ -426,8 +428,33 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, format); break; } - /* The default watermark level for overlay 0 is 48 */ - val |= 48 << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT; + + /* + * Pixel fetch watermark level is max 0x1FFF pixels. + * Two basic rules should be followed: + * 1. The value should be at least 256 bits. + * 2. The sum of all active overlays pixelfetch watermark level + * multiplied with bits per pixel, should be lower than the + * size of input_fifo_size in bits. + * 3. The value should be a multiple of a line (256 bits). + */ + switch (cpp) { + case 2: + pixel_fetcher_watermark = 128; + break; + case 3: + pixel_fetcher_watermark = 96; + break; + case 4: + pixel_fetcher_watermark = 48; + break; + default: + pixel_fetcher_watermark = 48; + break; + } + dev_dbg(mcde->dev, "pixel fetcher watermark level %d pixels\n", + pixel_fetcher_watermark); + val |= pixel_fetcher_watermark << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT; writel(val, mcde->regs + conf2); /* Number of bytes to fetch per line */ @@ -498,19 +525,47 @@ static void mcde_configure_channel(struct mcde *mcde, enum mcde_channel ch, } /* Set up channel 0 sync (based on chnl_update_registers()) */ - if (mcde->video_mode || mcde->te_sync) + switch (mcde->flow_mode) { + case MCDE_COMMAND_ONESHOT_FLOW: + /* Oneshot is achieved with software sync */ + val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE + << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; + break; + case MCDE_COMMAND_TE_FLOW: val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; - else - val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE + val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 + << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; + break; + case MCDE_COMMAND_BTA_TE_FLOW: + val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE + << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; + /* + * TODO: + * The vendor driver uses the formatter as sync source + * for BTA TE mode. Test to use TE if you have a panel + * that uses this mode. + */ + val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER + << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; + break; + case MCDE_VIDEO_TE_FLOW: + val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; - - if (mcde->te_sync) val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; - else + break; + case MCDE_VIDEO_FORMATTER_FLOW: + val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE + << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; + break; + default: + dev_err(mcde->dev, "unknown flow mode %d\n", + mcde->flow_mode); + break; + } writel(val, mcde->regs + sync); @@ -825,6 +880,14 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, u32 formatter_frame; u32 pkt_div; u32 val; + int ret; + + /* This powers up the entire MCDE block and the DSI hardware */ + ret = regulator_enable(mcde->epod); + if (ret) { + dev_err(drm->dev, "can't re-enable EPOD regulator\n"); + return; + } dev_info(drm->dev, "enable MCDE, %d x %d format %s\n", mode->hdisplay, mode->vdisplay, @@ -835,6 +898,26 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, return; } + /* Set up the main control, watermark level at 7 */ + val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT; + /* 24 bits DPI: connect LSB Ch B to D[0:7] */ + val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT; + /* TV out: connect LSB Ch B to D[8:15] */ + val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT; + /* Don't care about this muxing */ + val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT; + /* 24 bits DPI: connect MID Ch B to D[24:31] */ + val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT; + /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */ + val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT; + /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */ + writel(val, mcde->regs + MCDE_CONF0); + + /* Clear any pending interrupts */ + mcde_display_disable_irqs(mcde); + writel(0, mcde->regs + MCDE_IMSCERR); + writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); + dev_info(drm->dev, "output in %s mode, format %dbpp\n", (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD", @@ -904,7 +987,7 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, * channel 0 */ mcde_configure_overlay(mcde, MCDE_OVERLAY_0, MCDE_EXTSRC_0, - MCDE_CHANNEL_0, mode, format); + MCDE_CHANNEL_0, mode, format, cpp); /* * Configure pixel-per-line and line-per-frame for channel 0 and then @@ -916,11 +999,25 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0, fifo_wtrmrk); + /* + * This brings up the DSI bridge which is tightly connected + * to the MCDE DSI formatter. + * + * FIXME: if we want to use another formatter, such as DPI, + * we need to be more elaborate here and select the appropriate + * bridge. + */ + mcde_dsi_enable(mcde->bridge); + /* Configure the DSI formatter 0 for the DSI panel output */ mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, formatter_frame, pkt_size); - if (mcde->te_sync) { + switch (mcde->flow_mode) { + case MCDE_COMMAND_TE_FLOW: + case MCDE_COMMAND_BTA_TE_FLOW: + case MCDE_VIDEO_TE_FLOW: + /* We are using TE in some comination */ if (mode->flags & DRM_MODE_FLAG_NVSYNC) val = MCDE_VSCRC_VSPOL; else @@ -930,16 +1027,31 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, val = readl(mcde->regs + MCDE_CRC); val |= MCDE_CRC_SYCEN0; writel(val, mcde->regs + MCDE_CRC); + break; + default: + /* No TE capture */ + break; } drm_crtc_vblank_on(crtc); - if (mcde->video_mode) - /* - * Keep FIFO permanently enabled in video mode, - * otherwise MCDE will stop feeding data to the panel. - */ + /* + * If we're using oneshot mode we don't start the flow + * until each time the display is given an update, and + * then we disable it immediately after. For all other + * modes (command or video) we start the FIFO flow + * right here. This is necessary for the hardware to + * behave right. + */ + if (mcde->flow_mode != MCDE_COMMAND_ONESHOT_FLOW) { mcde_enable_fifo(mcde, MCDE_FIFO_A); + dev_dbg(mcde->dev, "started MCDE video FIFO flow\n"); + } + + /* Enable MCDE with automatic clock gating */ + val = readl(mcde->regs + MCDE_CR); + val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN; + writel(val, mcde->regs + MCDE_CR); dev_info(drm->dev, "MCDE display is enabled\n"); } @@ -950,12 +1062,16 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) struct drm_device *drm = crtc->dev; struct mcde *mcde = to_mcde(drm); struct drm_pending_vblank_event *event; + int ret; drm_crtc_vblank_off(crtc); /* Disable FIFO A flow */ mcde_disable_fifo(mcde, MCDE_FIFO_A, true); + /* This disables the DSI bridge */ + mcde_dsi_disable(mcde->bridge); + event = crtc->state->event; if (event) { crtc->state->event = NULL; @@ -965,43 +1081,47 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) spin_unlock_irq(&crtc->dev->event_lock); } + ret = regulator_disable(mcde->epod); + if (ret) + dev_err(drm->dev, "can't disable EPOD regulator\n"); + /* Make sure we are powered down (before we may power up again) */ + usleep_range(50000, 70000); + dev_info(drm->dev, "MCDE display is disabled\n"); } -static void mcde_display_send_one_frame(struct mcde *mcde) +static void mcde_start_flow(struct mcde *mcde) { - /* Request a TE ACK */ - if (mcde->te_sync) + /* Request a TE ACK only in TE+BTA mode */ + if (mcde->flow_mode == MCDE_COMMAND_BTA_TE_FLOW) mcde_dsi_te_request(mcde->mdsi); /* Enable FIFO A flow */ mcde_enable_fifo(mcde, MCDE_FIFO_A); - if (mcde->te_sync) { + /* + * If oneshot mode is enabled, the flow will be disabled + * when the TE0 IRQ arrives in the interrupt handler. Otherwise + * updates are continuously streamed to the display after this + * point. + */ + + if (mcde->flow_mode == MCDE_COMMAND_ONESHOT_FLOW) { + /* Trigger a software sync out on channel 0 */ + writel(MCDE_CHNLXSYNCHSW_SW_TRIG, + mcde->regs + MCDE_CHNL0SYNCHSW); + /* - * If oneshot mode is enabled, the flow will be disabled - * when the TE0 IRQ arrives in the interrupt handler. Otherwise - * updates are continuously streamed to the display after this - * point. + * Disable FIFO A flow again: since we are using TE sync we + * need to wait for the FIFO to drain before we continue + * so repeated calls to this function will not cause a mess + * in the hardware by pushing updates will updates are going + * on already. */ - dev_dbg(mcde->dev, "sent TE0 framebuffer update\n"); - return; + mcde_disable_fifo(mcde, MCDE_FIFO_A, true); } - /* Trigger a software sync out on channel 0 */ - writel(MCDE_CHNLXSYNCHSW_SW_TRIG, - mcde->regs + MCDE_CHNL0SYNCHSW); - - /* - * Disable FIFO A flow again: since we are using TE sync we - * need to wait for the FIFO to drain before we continue - * so repeated calls to this function will not cause a mess - * in the hardware by pushing updates will updates are going - * on already. - */ - mcde_disable_fifo(mcde, MCDE_FIFO_A, true); - - dev_dbg(mcde->dev, "sent SW framebuffer update\n"); + dev_dbg(mcde->dev, "started MCDE FIFO flow\n"); } static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address) @@ -1060,15 +1180,13 @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe, */ if (fb) { mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0)); - if (!mcde->video_mode) { - /* - * Send a single frame using software sync if the flow - * is not active yet. - */ - if (mcde->flow_active == 0) - mcde_display_send_one_frame(mcde); - } - dev_info_once(mcde->dev, "sent first display update\n"); + dev_info_once(mcde->dev, "first update of display contents\n"); + /* + * Usually the flow is already active, unless we are in + * oneshot mode, then we need to kick the flow right here. + */ + if (mcde->flow_active == 0) + mcde_start_flow(mcde); } else { /* * If an update is receieved before the MCDE is enabled diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h index 679c2c4e6d9d..8253e2f9993e 100644 --- a/drivers/gpu/drm/mcde/mcde_drm.h +++ b/drivers/gpu/drm/mcde/mcde_drm.h @@ -9,6 +9,61 @@ #ifndef _MCDE_DRM_H_ #define _MCDE_DRM_H_ +/* Shared basic registers */ +#define MCDE_CR 0x00000000 +#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_SHIFT 0 +#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_MASK 0x0000003F +#define MCDE_CR_IFIFOCTRLEN BIT(15) +#define MCDE_CR_UFRECOVERY_MODE_V422 BIT(16) +#define MCDE_CR_WRAP_MODE_V422_SHIFT BIT(17) +#define MCDE_CR_AUTOCLKG_EN BIT(30) +#define MCDE_CR_MCDEEN BIT(31) + +#define MCDE_CONF0 0x00000004 +#define MCDE_CONF0_SYNCMUX0 BIT(0) +#define MCDE_CONF0_SYNCMUX1 BIT(1) +#define MCDE_CONF0_SYNCMUX2 BIT(2) +#define MCDE_CONF0_SYNCMUX3 BIT(3) +#define MCDE_CONF0_SYNCMUX4 BIT(4) +#define MCDE_CONF0_SYNCMUX5 BIT(5) +#define MCDE_CONF0_SYNCMUX6 BIT(6) +#define MCDE_CONF0_SYNCMUX7 BIT(7) +#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12 +#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000 +#define MCDE_CONF0_OUTMUX0_SHIFT 16 +#define MCDE_CONF0_OUTMUX0_MASK 0x00070000 +#define MCDE_CONF0_OUTMUX1_SHIFT 19 +#define MCDE_CONF0_OUTMUX1_MASK 0x00380000 +#define MCDE_CONF0_OUTMUX2_SHIFT 22 +#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000 +#define MCDE_CONF0_OUTMUX3_SHIFT 25 +#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000 +#define MCDE_CONF0_OUTMUX4_SHIFT 28 +#define MCDE_CONF0_OUTMUX4_MASK 0x70000000 + +#define MCDE_SSP 0x00000008 +#define MCDE_AIS 0x00000100 +#define MCDE_IMSCERR 0x00000110 +#define MCDE_RISERR 0x00000120 +#define MCDE_MISERR 0x00000130 +#define MCDE_SISERR 0x00000140 + +enum mcde_flow_mode { + /* One-shot mode: flow stops after one frame */ + MCDE_COMMAND_ONESHOT_FLOW, + /* Command mode with tearing effect (TE) IRQ sync */ + MCDE_COMMAND_TE_FLOW, + /* + * Command mode with bus turn-around (BTA) and tearing effect + * (TE) IRQ sync. + */ + MCDE_COMMAND_BTA_TE_FLOW, + /* Video mode with tearing effect (TE) sync IRQ */ + MCDE_VIDEO_TE_FLOW, + /* Video mode with the formatter itself as sync source */ + MCDE_VIDEO_FORMATTER_FLOW, +}; + struct mcde { struct drm_device drm; struct device *dev; @@ -18,9 +73,7 @@ struct mcde { struct drm_simple_display_pipe pipe; struct mipi_dsi_device *mdsi; s16 stride; - bool te_sync; - bool video_mode; - bool oneshot_mode; + enum mcde_flow_mode flow_mode; unsigned int flow_active; spinlock_t flow_lock; /* Locks the channel flow control */ @@ -36,8 +89,16 @@ struct mcde { #define to_mcde(dev) container_of(dev, struct mcde, drm) +static inline bool mcde_flow_is_video(struct mcde *mcde) +{ + return (mcde->flow_mode == MCDE_VIDEO_TE_FLOW || + mcde->flow_mode == MCDE_VIDEO_FORMATTER_FLOW); +} + bool mcde_dsi_irq(struct mipi_dsi_device *mdsi); void mcde_dsi_te_request(struct mipi_dsi_device *mdsi); +void mcde_dsi_enable(struct drm_bridge *bridge); +void mcde_dsi_disable(struct drm_bridge *bridge); extern struct platform_driver mcde_dsi_driver; void mcde_display_irq(struct mcde *mcde); diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index 82137ab76cfc..c592957ed07f 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -63,6 +63,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/delay.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> @@ -82,44 +83,6 @@ #define DRIVER_DESC "DRM module for MCDE" -#define MCDE_CR 0x00000000 -#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_SHIFT 0 -#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_MASK 0x0000003F -#define MCDE_CR_IFIFOCTRLEN BIT(15) -#define MCDE_CR_UFRECOVERY_MODE_V422 BIT(16) -#define MCDE_CR_WRAP_MODE_V422_SHIFT BIT(17) -#define MCDE_CR_AUTOCLKG_EN BIT(30) -#define MCDE_CR_MCDEEN BIT(31) - -#define MCDE_CONF0 0x00000004 -#define MCDE_CONF0_SYNCMUX0 BIT(0) -#define MCDE_CONF0_SYNCMUX1 BIT(1) -#define MCDE_CONF0_SYNCMUX2 BIT(2) -#define MCDE_CONF0_SYNCMUX3 BIT(3) -#define MCDE_CONF0_SYNCMUX4 BIT(4) -#define MCDE_CONF0_SYNCMUX5 BIT(5) -#define MCDE_CONF0_SYNCMUX6 BIT(6) -#define MCDE_CONF0_SYNCMUX7 BIT(7) -#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12 -#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000 -#define MCDE_CONF0_OUTMUX0_SHIFT 16 -#define MCDE_CONF0_OUTMUX0_MASK 0x00070000 -#define MCDE_CONF0_OUTMUX1_SHIFT 19 -#define MCDE_CONF0_OUTMUX1_MASK 0x00380000 -#define MCDE_CONF0_OUTMUX2_SHIFT 22 -#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000 -#define MCDE_CONF0_OUTMUX3_SHIFT 25 -#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000 -#define MCDE_CONF0_OUTMUX4_SHIFT 28 -#define MCDE_CONF0_OUTMUX4_MASK 0x70000000 - -#define MCDE_SSP 0x00000008 -#define MCDE_AIS 0x00000100 -#define MCDE_IMSCERR 0x00000110 -#define MCDE_RISERR 0x00000120 -#define MCDE_MISERR 0x00000130 -#define MCDE_SISERR 0x00000140 - #define MCDE_PID 0x000001FC #define MCDE_PID_METALFIX_VERSION_SHIFT 0 #define MCDE_PID_METALFIX_VERSION_MASK 0x000000FF @@ -293,7 +256,6 @@ static int mcde_probe(struct platform_device *pdev) struct component_match *match = NULL; struct resource *res; u32 pid; - u32 val; int irq; int ret; int i; @@ -305,9 +267,6 @@ static int mcde_probe(struct platform_device *pdev) mcde->dev = dev; platform_set_drvdata(pdev, drm); - /* Enable continuous updates: this is what Linux' framebuffer expects */ - mcde->oneshot_mode = false; - /* First obtain and turn on the main power */ mcde->epod = devm_regulator_get(dev, "epod"); if (IS_ERR(mcde->epod)) { @@ -405,27 +364,7 @@ static int mcde_probe(struct platform_device *pdev) goto clk_disable; } - /* Set up the main control, watermark level at 7 */ - val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT; - /* 24 bits DPI: connect LSB Ch B to D[0:7] */ - val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT; - /* TV out: connect LSB Ch B to D[8:15] */ - val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT; - /* Don't care about this muxing */ - val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT; - /* 24 bits DPI: connect MID Ch B to D[24:31] */ - val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT; - /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */ - val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT; - /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */ - writel(val, mcde->regs + MCDE_CONF0); - - /* Enable automatic clock gating */ - val = readl(mcde->regs + MCDE_CR); - val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN; - writel(val, mcde->regs + MCDE_CR); - - /* Clear any pending interrupts */ + /* Disable and clear any pending interrupts */ mcde_display_disable_irqs(mcde); writel(0, mcde->regs + MCDE_IMSCERR); writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); @@ -455,12 +394,28 @@ static int mcde_probe(struct platform_device *pdev) ret = PTR_ERR(match); goto clk_disable; } + + /* + * Perform an invasive reset of the MCDE and all blocks by + * cutting the power to the subsystem, then bring it back up + * later when we enable the display as a result of + * component_master_add_with_match(). + */ + ret = regulator_disable(mcde->epod); + if (ret) { + dev_err(dev, "can't disable EPOD regulator\n"); + return ret; + } + /* Wait 50 ms so we are sure we cut the power */ + usleep_range(50000, 70000); + ret = component_master_add_with_match(&pdev->dev, &mcde_drm_comp_ops, match); if (ret) { dev_err(dev, "failed to add component master\n"); goto clk_disable; } + return 0; clk_disable: diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c index 981923caa7e6..2314c8122992 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi.c +++ b/drivers/gpu/drm/mcde/mcde_dsi.c @@ -43,6 +43,7 @@ struct mcde_dsi { struct drm_bridge *bridge_out; struct mipi_dsi_host dsi_host; struct mipi_dsi_device *mdsi; + const struct drm_display_mode *mode; struct clk *hs_clk; struct clk *lp_clk; unsigned long hs_freq; @@ -148,9 +149,22 @@ static void mcde_dsi_attach_to_mcde(struct mcde_dsi *d) { d->mcde->mdsi = d->mdsi; - d->mcde->video_mode = !!(d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO); - /* Enable use of the TE signal for all command mode panels */ - d->mcde->te_sync = !d->mcde->video_mode; + /* + * Select the way the DSI data flow is pushing to the display: + * currently we just support video or command mode depending + * on the type of display. Video mode defaults to using the + * formatter itself for synchronization (stateless video panel). + * + * FIXME: add flags to struct mipi_dsi_device .flags to indicate + * displays that require BTA (bus turn around) so we can handle + * such displays as well. Figure out how to properly handle + * single frame on-demand updates with DRM for command mode + * displays (MCDE_COMMAND_ONESHOT_FLOW). + */ + if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) + d->mcde->flow_mode = MCDE_VIDEO_FORMATTER_FLOW; + else + d->mcde->flow_mode = MCDE_COMMAND_TE_FLOW; } static int mcde_dsi_host_attach(struct mipi_dsi_host *host, @@ -194,79 +208,16 @@ static int mcde_dsi_host_detach(struct mipi_dsi_host *host, (type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \ (type == MIPI_DSI_DCS_READ)) -static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, - const struct mipi_dsi_msg *msg) +static int mcde_dsi_execute_transfer(struct mcde_dsi *d, + const struct mipi_dsi_msg *msg) { - struct mcde_dsi *d = host_to_mcde_dsi(host); const u32 loop_delay_us = 10; /* us */ - const u8 *tx = msg->tx_buf; u32 loop_counter; size_t txlen = msg->tx_len; size_t rxlen = msg->rx_len; + int i; u32 val; int ret; - int i; - - if (txlen > 16) { - dev_err(d->dev, - "dunno how to write more than 16 bytes yet\n"); - return -EIO; - } - if (rxlen > 4) { - dev_err(d->dev, - "dunno how to read more than 4 bytes yet\n"); - return -EIO; - } - - dev_dbg(d->dev, - "message to channel %d, write %zd bytes read %zd bytes\n", - msg->channel, txlen, rxlen); - - /* Command "nature" */ - if (MCDE_DSI_HOST_IS_READ(msg->type)) - /* MCTL_MAIN_DATA_CTL already set up */ - val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ; - else - val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE; - /* - * More than 2 bytes will not fit in a single packet, so it's - * time to set the "long not short" bit. One byte is used by - * the MIPI DCS command leaving just one byte for the payload - * in a short package. - */ - if (mipi_dsi_packet_format_is_long(msg->type)) - val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT; - val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT; - val |= txlen << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT; - val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN; - val |= msg->type << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT; - writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS); - - /* MIPI DCS command is part of the data */ - if (txlen > 0) { - val = 0; - for (i = 0; i < 4 && i < txlen; i++) - val |= tx[i] << (i * 8); - } - writel(val, d->regs + DSI_DIRECT_CMD_WRDAT0); - if (txlen > 4) { - val = 0; - for (i = 0; i < 4 && (i + 4) < txlen; i++) - val |= tx[i + 4] << (i * 8); - writel(val, d->regs + DSI_DIRECT_CMD_WRDAT1); - } - if (txlen > 8) { - val = 0; - for (i = 0; i < 4 && (i + 8) < txlen; i++) - val |= tx[i + 8] << (i * 8); - writel(val, d->regs + DSI_DIRECT_CMD_WRDAT2); - } - if (txlen > 12) { - val = 0; - for (i = 0; i < 4 && (i + 12) < txlen; i++) - val |= tx[i + 12] << (i * 8); - writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3); - } writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); @@ -283,6 +234,7 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); if (!loop_counter) { dev_err(d->dev, "DSI read timeout!\n"); + /* Set exit code and retry */ return -ETIME; } } else { @@ -293,6 +245,7 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); if (!loop_counter) { + /* Set exit code and retry */ dev_err(d->dev, "DSI write timeout!\n"); return -ETIME; } @@ -334,6 +287,93 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, ret = rdsz; } + /* Successful transmission */ + return ret; +} + +static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg) +{ + struct mcde_dsi *d = host_to_mcde_dsi(host); + const u8 *tx = msg->tx_buf; + size_t txlen = msg->tx_len; + size_t rxlen = msg->rx_len; + unsigned int retries = 0; + u32 val; + int ret; + int i; + + if (txlen > 16) { + dev_err(d->dev, + "dunno how to write more than 16 bytes yet\n"); + return -EIO; + } + if (rxlen > 4) { + dev_err(d->dev, + "dunno how to read more than 4 bytes yet\n"); + return -EIO; + } + + dev_dbg(d->dev, + "message to channel %d, write %zd bytes read %zd bytes\n", + msg->channel, txlen, rxlen); + + /* Command "nature" */ + if (MCDE_DSI_HOST_IS_READ(msg->type)) + /* MCTL_MAIN_DATA_CTL already set up */ + val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ; + else + val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE; + /* + * More than 2 bytes will not fit in a single packet, so it's + * time to set the "long not short" bit. One byte is used by + * the MIPI DCS command leaving just one byte for the payload + * in a short package. + */ + if (mipi_dsi_packet_format_is_long(msg->type)) + val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT; + val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT; + val |= txlen << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT; + val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN; + val |= msg->type << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT; + writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS); + + /* MIPI DCS command is part of the data */ + if (txlen > 0) { + val = 0; + for (i = 0; i < 4 && i < txlen; i++) + val |= tx[i] << (i * 8); + } + writel(val, d->regs + DSI_DIRECT_CMD_WRDAT0); + if (txlen > 4) { + val = 0; + for (i = 0; i < 4 && (i + 4) < txlen; i++) + val |= tx[i + 4] << (i * 8); + writel(val, d->regs + DSI_DIRECT_CMD_WRDAT1); + } + if (txlen > 8) { + val = 0; + for (i = 0; i < 4 && (i + 8) < txlen; i++) + val |= tx[i + 8] << (i * 8); + writel(val, d->regs + DSI_DIRECT_CMD_WRDAT2); + } + if (txlen > 12) { + val = 0; + for (i = 0; i < 4 && (i + 12) < txlen; i++) + val |= tx[i + 12] << (i * 8); + writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3); + } + + while (retries < 3) { + ret = mcde_dsi_execute_transfer(d, msg); + if (ret >= 0) + break; + retries++; + } + if (ret < 0 && retries) + dev_err(d->dev, "gave up after %d retries\n", retries); + + /* Clear any errors */ writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); @@ -799,10 +839,11 @@ static void mcde_dsi_start(struct mcde_dsi *d) /* Command mode, clear IF1 ID */ val = readl(d->regs + DSI_CMD_MODE_CTL); /* - * If we enable low-power mode here, with - * val |= DSI_CMD_MODE_CTL_IF1_LP_EN + * If we enable low-power mode here, * then display updates become really slow. */ + if (d->mdsi->mode_flags & MIPI_DSI_MODE_LPM) + val |= DSI_CMD_MODE_CTL_IF1_LP_EN; val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK; writel(val, d->regs + DSI_CMD_MODE_CTL); @@ -811,23 +852,11 @@ static void mcde_dsi_start(struct mcde_dsi *d) dev_info(d->dev, "DSI link enabled\n"); } - -static void mcde_dsi_bridge_enable(struct drm_bridge *bridge) -{ - struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); - u32 val; - - if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { - /* Enable video mode */ - val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); - val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN; - writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL); - } - - dev_info(d->dev, "enable DSI master\n"); -}; - -static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) +/* + * Notice that this is called from inside the display controller + * and not from the bridge callbacks. + */ +void mcde_dsi_enable(struct drm_bridge *bridge) { struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); unsigned long hs_freq, lp_freq; @@ -871,7 +900,25 @@ static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) dev_info(d->dev, "DSI HS clock rate %lu Hz\n", d->hs_freq); + /* Assert RESET through the PRCMU, active low */ + /* FIXME: which DSI block? */ + regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET, + PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0); + + usleep_range(100, 200); + + /* De-assert RESET again */ + regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET, + PRCM_DSI_SW_RESET_DSI0_SW_RESETN, + PRCM_DSI_SW_RESET_DSI0_SW_RESETN); + + /* Start up the hardware */ + mcde_dsi_start(d); + if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { + /* Set up the video mode from the DRM mode */ + mcde_dsi_setup_video_mode(d, d->mode); + /* Put IF1 into video mode */ val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE; @@ -887,17 +934,25 @@ static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC; val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA; writel(val, d->regs + DSI_VID_MODE_STS_CTL); + + /* Enable video mode */ + val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); + val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN; + writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL); } else { /* Command mode, clear IF1 ID */ val = readl(d->regs + DSI_CMD_MODE_CTL); /* - * If we enable low-power mode here with - * val |= DSI_CMD_MODE_CTL_IF1_LP_EN + * If we enable low-power mode here * the display updates become really slow. */ + if (d->mdsi->mode_flags & MIPI_DSI_MODE_LPM) + val |= DSI_CMD_MODE_CTL_IF1_LP_EN; val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK; writel(val, d->regs + DSI_CMD_MODE_CTL); } + + dev_info(d->dev, "enabled MCDE DSI master\n"); } static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge, @@ -911,13 +966,12 @@ static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge, return; } + d->mode = mode; + dev_info(d->dev, "set DSI master to %dx%d %u Hz %s mode\n", mode->hdisplay, mode->vdisplay, mode->clock * 1000, (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD" ); - - if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) - mcde_dsi_setup_video_mode(d, mode); } static void mcde_dsi_wait_for_command_mode_stop(struct mcde_dsi *d) @@ -961,14 +1015,15 @@ static void mcde_dsi_wait_for_video_mode_stop(struct mcde_dsi *d) } } -static void mcde_dsi_bridge_disable(struct drm_bridge *bridge) +/* + * Notice that this is called from inside the display controller + * and not from the bridge callbacks. + */ +void mcde_dsi_disable(struct drm_bridge *bridge) { struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); u32 val; - /* Disable all error interrupts */ - writel(0, d->regs + DSI_VID_MODE_STS_CTL); - if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { /* Stop video mode */ val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); @@ -980,7 +1035,14 @@ static void mcde_dsi_bridge_disable(struct drm_bridge *bridge) mcde_dsi_wait_for_command_mode_stop(d); } - /* Stop clocks */ + /* + * Stop clocks and terminate any DSI traffic here so the panel can + * send commands to shut down the display using DSI direct write until + * this point. + */ + + /* Disable all error interrupts */ + writel(0, d->regs + DSI_VID_MODE_STS_CTL); clk_disable_unprepare(d->hs_clk); clk_disable_unprepare(d->lp_clk); } @@ -1010,9 +1072,6 @@ static int mcde_dsi_bridge_attach(struct drm_bridge *bridge, static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = { .attach = mcde_dsi_bridge_attach, .mode_set = mcde_dsi_bridge_mode_set, - .disable = mcde_dsi_bridge_disable, - .enable = mcde_dsi_bridge_enable, - .pre_enable = mcde_dsi_bridge_pre_enable, }; static int mcde_dsi_bind(struct device *dev, struct device *master, @@ -1048,21 +1107,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master, return PTR_ERR(d->lp_clk); } - /* Assert RESET through the PRCMU, active low */ - /* FIXME: which DSI block? */ - regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET, - PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0); - - usleep_range(100, 200); - - /* De-assert RESET again */ - regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET, - PRCM_DSI_SW_RESET_DSI0_SW_RESETN, - PRCM_DSI_SW_RESET_DSI0_SW_RESETN); - - /* Start up the hardware */ - mcde_dsi_start(d); - /* Look for a panel as a child to this node */ for_each_available_child_of_node(dev->of_node, child) { panel = of_drm_find_panel(child); diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig index 93be766715c9..eec59658a938 100644 --- a/drivers/gpu/drm/mgag200/Kconfig +++ b/drivers/gpu/drm/mgag200/Kconfig @@ -1,13 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_MGAG200 - tristate "Kernel modesetting driver for MGA G200 server engines" + tristate "Matrox G200" depends on DRM && PCI && MMU select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER help - This is a KMS driver for the MGA G200 server chips, it - does not support the original MGA G200 or any of the desktop - chips. It requires 0.3.0 of the modesetting userspace driver, - and a version of mga driver that will fail on KMS enabled - devices. - + This is a KMS driver for Matrox G200 chips. It supports the original + MGA G200 desktop chips and the server variants. It requires 0.3.0 + of the modesetting userspace driver, and a version of mga driver + that will fail on KMS enabled devices. diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index e19660f4a637..771b26aeee19 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -9,6 +9,7 @@ #include <linux/console.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/vmalloc.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -36,6 +37,7 @@ static struct drm_driver mgag200_driver = { .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, + .gem_create_object = drm_gem_shmem_create_object_cached, DRM_GEM_SHMEM_DRIVER_OPS, }; @@ -43,18 +45,66 @@ static struct drm_driver mgag200_driver = { * DRM device */ -static int mgag200_device_init(struct mga_device *mdev, unsigned long flags) +static bool mgag200_has_sgram(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; - int ret, option; + u32 option; + int ret; - mdev->flags = mgag200_flags_from_driver_data(flags); - mdev->type = mgag200_type_from_driver_data(flags); + ret = pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option); + if (drm_WARN(dev, ret, "failed to read PCI config dword: %d\n", ret)) + return false; - pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option); - mdev->has_sdram = !(option & (1 << 14)); + return !!(option & PCI_MGA_OPTION_HARDPWMSK); +} - /* BAR 0 is the framebuffer, BAR 1 contains registers */ +static int mgag200_regs_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + u32 option, option2; + u8 crtcext3; + + switch (mdev->type) { + case G200_PCI: + case G200_AGP: + if (mgag200_has_sgram(mdev)) + option = 0x4049cd21; + else + option = 0x40499121; + option2 = 0x00008000; + break; + case G200_SE_A: + case G200_SE_B: + option = 0x40049120; + if (mgag200_has_sgram(mdev)) + option |= PCI_MGA_OPTION_HARDPWMSK; + option2 = 0x00008000; + break; + case G200_WB: + case G200_EW3: + option = 0x41049120; + option2 = 0x0000b000; + break; + case G200_EV: + option = 0x00000120; + option2 = 0x0000b000; + break; + case G200_EH: + case G200_EH3: + option = 0x00000120; + option2 = 0x0000b000; + break; + default: + option = 0; + option2 = 0; + } + + if (option) + pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); + if (option2) + pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2); + + /* BAR 1 contains registers */ mdev->rmmio_base = pci_resource_start(dev->pdev, 1); mdev->rmmio_size = pci_resource_len(dev->pdev, 1); @@ -68,12 +118,163 @@ static int mgag200_device_init(struct mga_device *mdev, unsigned long flags) if (mdev->rmmio == NULL) return -ENOMEM; - /* stash G200 SE model number for later use */ - if (IS_G200_SE(mdev)) { - mdev->unique_rev_id = RREG32(0x1e24); - drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", - mdev->unique_rev_id); + RREG_ECRT(0x03, crtcext3); + crtcext3 |= MGAREG_CRTCEXT3_MGAMODE; + WREG_ECRT(0x03, crtcext3); + + return 0; +} + +static void mgag200_g200_interpret_bios(struct mga_device *mdev, + const unsigned char *bios, + size_t size) +{ + static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'}; + static const unsigned int expected_length[6] = { + 0, 64, 64, 64, 128, 128 + }; + struct drm_device *dev = &mdev->base; + const unsigned char *pins; + unsigned int pins_len, version; + int offset; + int tmp; + + /* Test for MATROX string. */ + if (size < 45 + sizeof(matrox)) + return; + if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0) + return; + + /* Get the PInS offset. */ + if (size < MGA_BIOS_OFFSET + 2) + return; + offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET]; + + /* Get PInS data structure. */ + + if (size < offset + 6) + return; + pins = bios + offset; + if (pins[0] == 0x2e && pins[1] == 0x41) { + version = pins[5]; + pins_len = pins[2]; + } else { + version = 1; + pins_len = pins[0] + (pins[1] << 8); + } + + if (version < 1 || version > 5) { + drm_warn(dev, "Unknown BIOS PInS version: %d\n", version); + return; + } + if (pins_len != expected_length[version]) { + drm_warn(dev, "Unexpected BIOS PInS size: %d expected: %d\n", + pins_len, expected_length[version]); + return; } + if (size < offset + pins_len) + return; + + drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n", + version, pins_len); + + /* Extract the clock values */ + + switch (version) { + case 1: + tmp = pins[24] + (pins[25] << 8); + if (tmp) + mdev->model.g200.pclk_max = tmp * 10; + break; + case 2: + if (pins[41] != 0xff) + mdev->model.g200.pclk_max = (pins[41] + 100) * 1000; + break; + case 3: + if (pins[36] != 0xff) + mdev->model.g200.pclk_max = (pins[36] + 100) * 1000; + if (pins[52] & 0x20) + mdev->model.g200.ref_clk = 14318; + break; + case 4: + if (pins[39] != 0xff) + mdev->model.g200.pclk_max = pins[39] * 4 * 1000; + if (pins[92] & 0x01) + mdev->model.g200.ref_clk = 14318; + break; + case 5: + tmp = pins[4] ? 8000 : 6000; + if (pins[123] != 0xff) + mdev->model.g200.pclk_min = pins[123] * tmp; + if (pins[38] != 0xff) + mdev->model.g200.pclk_max = pins[38] * tmp; + if (pins[110] & 0x01) + mdev->model.g200.ref_clk = 14318; + break; + default: + break; + } +} + +static void mgag200_g200_init_refclk(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + unsigned char __iomem *rom; + unsigned char *bios; + size_t size; + + mdev->model.g200.pclk_min = 50000; + mdev->model.g200.pclk_max = 230000; + mdev->model.g200.ref_clk = 27050; + + rom = pci_map_rom(dev->pdev, &size); + if (!rom) + return; + + bios = vmalloc(size); + if (!bios) + goto out; + memcpy_fromio(bios, rom, size); + + if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa) + mgag200_g200_interpret_bios(mdev, bios, size); + + drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n", + mdev->model.g200.pclk_min, mdev->model.g200.pclk_max, + mdev->model.g200.ref_clk); + + vfree(bios); +out: + pci_unmap_rom(dev->pdev, rom); +} + +static void mgag200_g200se_init_unique_id(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + + /* stash G200 SE model number for later use */ + mdev->model.g200se.unique_rev_id = RREG32(0x1e24); + + drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", + mdev->model.g200se.unique_rev_id); +} + +static int mgag200_device_init(struct mga_device *mdev, unsigned long flags) +{ + struct drm_device *dev = &mdev->base; + int ret; + + mdev->flags = mgag200_flags_from_driver_data(flags); + mdev->type = mgag200_type_from_driver_data(flags); + + ret = mgag200_regs_init(mdev); + if (ret) + return ret; + + if (mdev->type == G200_PCI || mdev->type == G200_AGP) + mgag200_g200_init_refclk(mdev); + else if (IS_G200_SE(mdev)) + mgag200_g200se_init_unique_id(mdev); ret = mgag200_mm_init(mdev); if (ret) @@ -116,6 +317,8 @@ mgag200_device_create(struct pci_dev *pdev, unsigned long flags) */ static const struct pci_device_id mgag200_pciidlist[] = { + { PCI_VENDOR_ID_MATROX, 0x520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_PCI }, + { PCI_VENDOR_ID_MATROX, 0x521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_AGP }, { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD}, { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B }, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 3817520bfefc..749a075fe9e4 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -38,6 +38,8 @@ #define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg)) #define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg)) +#define MGA_BIOS_OFFSET 0x7ffc + #define ATTR_INDEX 0x1fc0 #define ATTR_DATA 0x1fc1 @@ -129,6 +131,8 @@ struct mga_mc { }; enum mga_type { + G200_PCI, + G200_AGP, G200_SE_A, G200_SE_B, G200_WB, @@ -161,14 +165,23 @@ struct mga_device { size_t vram_fb_available; enum mga_type type; - int has_sdram; int bpp_shifts[4]; int fb_mtrr; - /* SE model number stored in reg 0x1e24 */ - u32 unique_rev_id; + union { + struct { + long ref_clk; + long pclk_min; + long pclk_max; + } g200; + struct { + /* SE model number stored in reg 0x1e24 */ + u32 unique_rev_id; + } g200se; + } model; + struct mga_connector connector; struct drm_simple_display_pipe display_pipe; diff --git a/drivers/gpu/drm/mgag200/mgag200_mm.c b/drivers/gpu/drm/mgag200/mgag200_mm.c index 7b69392bcb89..641f1aa992be 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mm.c +++ b/drivers/gpu/drm/mgag200/mgag200_mm.c @@ -90,9 +90,17 @@ static void mgag200_mm_release(struct drm_device *dev, void *ptr) int mgag200_mm_init(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; + u8 misc; resource_size_t start, len; int ret; + WREG_ECRT(0x04, 0x00); + + misc = RREG8(MGA_MISC_IN); + misc |= MGAREG_MISC_RAMMAPEN | + MGAREG_MISC_HIGH_PG_SEL; + WREG8(MGA_MISC_OUT, misc); + /* BAR 0 is VRAM */ start = pci_resource_start(dev->pdev, 0); len = pci_resource_len(dev->pdev, 0); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index e0d037a7413c..38672f9e5c4f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -9,7 +9,6 @@ */ #include <linux/delay.h> -#include <linux/pci.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_state_helper.h> @@ -109,10 +108,82 @@ static inline void mga_wait_busy(struct mga_device *mdev) } while ((status & 0x01) && time_before(jiffies, timeout)); } +/* + * PLL setup + */ + +static int mgag200_g200_set_plls(struct mga_device *mdev, long clock) +{ + struct drm_device *dev = &mdev->base; + const int post_div_max = 7; + const int in_div_min = 1; + const int in_div_max = 6; + const int feed_div_min = 7; + const int feed_div_max = 127; + u8 testm, testn; + u8 n = 0, m = 0, p, s; + long f_vco; + long computed; + long delta, tmp_delta; + long ref_clk = mdev->model.g200.ref_clk; + long p_clk_min = mdev->model.g200.pclk_min; + long p_clk_max = mdev->model.g200.pclk_max; + + if (clock > p_clk_max) { + drm_err(dev, "Pixel Clock %ld too high\n", clock); + return 1; + } + + if (clock < p_clk_min >> 3) + clock = p_clk_min >> 3; + + f_vco = clock; + for (p = 0; + p <= post_div_max && f_vco < p_clk_min; + p = (p << 1) + 1, f_vco <<= 1) + ; + + delta = clock; + + for (testm = in_div_min; testm <= in_div_max; testm++) { + for (testn = feed_div_min; testn <= feed_div_max; testn++) { + computed = ref_clk * (testn + 1) / (testm + 1); + if (computed < f_vco) + tmp_delta = f_vco - computed; + else + tmp_delta = computed - f_vco; + if (tmp_delta < delta) { + delta = tmp_delta; + m = testm; + n = testn; + } + } + } + f_vco = ref_clk * (n + 1) / (m + 1); + if (f_vco < 100000) + s = 0; + else if (f_vco < 140000) + s = 1; + else if (f_vco < 180000) + s = 2; + else + s = 3; + + drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", + clock, f_vco, m, n, p, s); + + WREG_DAC(MGA1064_PIX_PLLC_M, m); + WREG_DAC(MGA1064_PIX_PLLC_N, n); + WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3))); + + return 0; +} + #define P_ARRAY_SIZE 9 static int mga_g200se_set_plls(struct mga_device *mdev, long clock) { + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta, permitteddelta; unsigned int testp, testm, testn; @@ -122,7 +193,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) unsigned int fvv; unsigned int i; - if (mdev->unique_rev_id <= 0x03) { + if (unique_rev_id <= 0x03) { m = n = p = 0; vcomax = 320000; @@ -220,7 +291,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) WREG_DAC(MGA1064_PIX_PLLC_N, n); WREG_DAC(MGA1064_PIX_PLLC_P, p); - if (mdev->unique_rev_id >= 0x04) { + if (unique_rev_id >= 0x04) { WREG_DAC(0x1a, 0x09); msleep(20); WREG_DAC(0x1a, 0x01); @@ -717,6 +788,9 @@ static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock) u8 misc; switch(mdev->type) { + case G200_PCI: + case G200_AGP: + return mgag200_g200_set_plls(mdev, clock); case G200_SE_A: case G200_SE_B: return mga_g200se_set_plls(mdev, clock); @@ -877,45 +951,6 @@ static void mgag200_set_startadd(struct mga_device *mdev, WREG_ECRT(0x00, crtcext0); } -static void mgag200_set_pci_regs(struct mga_device *mdev) -{ - uint32_t option = 0, option2 = 0; - struct drm_device *dev = &mdev->base; - - switch (mdev->type) { - case G200_SE_A: - case G200_SE_B: - if (mdev->has_sdram) - option = 0x40049120; - else - option = 0x4004d120; - option2 = 0x00008000; - break; - case G200_WB: - case G200_EW3: - option = 0x41049120; - option2 = 0x0000b000; - break; - case G200_EV: - option = 0x00000120; - option2 = 0x0000b000; - break; - case G200_EH: - case G200_EH3: - option = 0x00000120; - option2 = 0x0000b000; - break; - case G200_ER: - break; - } - - if (option) - pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); - - if (option2) - pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2); -} - static void mgag200_set_dac_regs(struct mga_device *mdev) { size_t i; @@ -933,6 +968,12 @@ static void mgag200_set_dac_regs(struct mga_device *mdev) }; switch (mdev->type) { + case G200_PCI: + case G200_AGP: + dacvalue[MGA1064_SYS_PLL_M] = 0x04; + dacvalue[MGA1064_SYS_PLL_N] = 0x2D; + dacvalue[MGA1064_SYS_PLL_P] = 0x19; + break; case G200_SE_A: case G200_SE_B: dacvalue[MGA1064_VREF_CTL] = 0x03; @@ -986,9 +1027,8 @@ static void mgag200_set_dac_regs(struct mga_device *mdev) static void mgag200_init_regs(struct mga_device *mdev) { - u8 crtc11, crtcext3, crtcext4, misc; + u8 crtc11, misc; - mgag200_set_pci_regs(mdev); mgag200_set_dac_regs(mdev); WREG_SEQ(2, 0x0f); @@ -1002,14 +1042,6 @@ static void mgag200_init_regs(struct mga_device *mdev) WREG_CRT(14, 0); WREG_CRT(15, 0); - RREG_ECRT(0x03, crtcext3); - - crtcext3 |= BIT(7); /* enable MGA mode */ - crtcext4 = 0x00; - - WREG_ECRT(0x03, crtcext3); - WREG_ECRT(0x04, crtcext4); - RREG_CRT(0x11, crtc11); crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT | MGAREG_CRTC11_VINTEN | @@ -1023,9 +1055,7 @@ static void mgag200_init_regs(struct mga_device *mdev) WREG_ECRT(0x34, 0x5); misc = RREG8(MGA_MISC_IN); - misc |= MGAREG_MISC_IOADSEL | - MGAREG_MISC_RAMMAPEN | - MGAREG_MISC_HIGH_PG_SEL; + misc |= MGAREG_MISC_IOADSEL; WREG8(MGA_MISC_OUT, misc); } @@ -1234,12 +1264,13 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, const struct drm_display_mode *mode, const struct drm_framebuffer *fb) { + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; unsigned int hiprilvl; u8 crtcext6; - if (mdev->unique_rev_id >= 0x04) { + if (unique_rev_id >= 0x04) { hiprilvl = 0; - } else if (mdev->unique_rev_id >= 0x02) { + } else if (unique_rev_id >= 0x02) { unsigned int bpp; unsigned long mb; @@ -1264,7 +1295,7 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, else hiprilvl = 5; - } else if (mdev->unique_rev_id >= 0x01) { + } else if (unique_rev_id >= 0x01) { hiprilvl = 3; } else { hiprilvl = 4; @@ -1388,7 +1419,9 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, int bpp = 32; if (IS_G200_SE(mdev)) { - if (mdev->unique_rev_id == 0x01) { + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + + if (unique_rev_id == 0x01) { if (mode->hdisplay > 1600) return MODE_VIRTUAL_X; if (mode->vdisplay > 1200) @@ -1396,7 +1429,7 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, if (mga_vga_calculate_mode_bandwidth(mode, bpp) > (24400 * 1024)) return MODE_BANDWIDTH; - } else if (mdev->unique_rev_id == 0x02) { + } else if (unique_rev_id == 0x02) { if (mode->hdisplay > 1920) return MODE_VIRTUAL_X; if (mode->vdisplay > 1200) diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h index c3b7bcad52ed..977be0565c06 100644 --- a/drivers/gpu/drm/mgag200/mgag200_reg.h +++ b/drivers/gpu/drm/mgag200/mgag200_reg.h @@ -256,6 +256,8 @@ #define MGAREG_CRTCEXT1_VSYNCOFF BIT(5) #define MGAREG_CRTCEXT1_HSYNCOFF BIT(4) +#define MGAREG_CRTCEXT3_MGAMODE BIT(7) + /* Cursor X and Y position */ #define MGA_CURPOSXL 0x3c0c #define MGA_CURPOSXH 0x3c0d @@ -282,6 +284,8 @@ #define PCI_MGA_OPTION2 0x50 #define PCI_MGA_OPTION3 0x54 +#define PCI_MGA_OPTION_HARDPWMSK BIT(14) + #define RAMDAC_OFFSET 0x3c00 /* TVP3026 direct registers */ diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c index c7df71e2fafc..7288041dd86a 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c @@ -50,14 +50,9 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector) struct drm_panel *panel = mdp4_lvds_connector->panel; int ret = 0; - if (panel) { - drm_panel_attach(panel, connector); - + if (panel) ret = drm_panel_get_modes(panel, connector); - drm_panel_detach(panel); - } - return ret; } diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 4b363bd7ddff..1d28dfba2c9b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -328,7 +328,6 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector) * In dual DSI mode, we have one connector that can be * attached to the drm_panel. */ - drm_panel_attach(panel, connector); num = drm_panel_get_modes(panel, connector); if (!num) return 0; diff --git a/drivers/gpu/drm/mxsfb/Kconfig b/drivers/gpu/drm/mxsfb/Kconfig index 0dca8f27169e..0143d539f8f8 100644 --- a/drivers/gpu/drm/mxsfb/Kconfig +++ b/drivers/gpu/drm/mxsfb/Kconfig @@ -5,7 +5,7 @@ config DRM_MXS Choose this option to select drivers for MXS FB devices config DRM_MXSFB - tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller" + tristate "i.MX (e)LCDIF LCD controller" depends on DRM && OF depends on COMMON_CLK select DRM_MXS @@ -13,8 +13,10 @@ config DRM_MXSFB select DRM_KMS_FB_HELPER select DRM_KMS_CMA_HELPER select DRM_PANEL + select DRM_PANEL_BRIDGE help - Choose this option if you have an i.MX23/i.MX28/i.MX6SX MXSFB - LCD controller. + Choose this option if you have an LCDIF or eLCDIF LCD controller. + Those devices are found in various i.MX SoC (including i.MX23, + i.MX28, i.MX6SX, i.MX7 and i.MX8M). If M is selected the module will be called mxsfb. diff --git a/drivers/gpu/drm/mxsfb/Makefile b/drivers/gpu/drm/mxsfb/Makefile index ff6e358088fa..26d153896d72 100644 --- a/drivers/gpu/drm/mxsfb/Makefile +++ b/drivers/gpu/drm/mxsfb/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -mxsfb-y := mxsfb_drv.o mxsfb_crtc.o mxsfb_out.o +mxsfb-y := mxsfb_drv.o mxsfb_kms.o obj-$(CONFIG_DRM_MXSFB) += mxsfb.o diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c deleted file mode 100644 index b69ace8bf526..000000000000 --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c +++ /dev/null @@ -1,343 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Marek Vasut <[email protected]> - * - * This code is based on drivers/video/fbdev/mxsfb.c : - * Copyright (C) 2010 Juergen Beisert, Pengutronix - * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved. - */ - -#include <linux/clk.h> -#include <linux/iopoll.h> -#include <linux/of_graph.h> -#include <linux/platform_data/simplefb.h> - -#include <video/videomode.h> - -#include <drm/drm_atomic_helper.h> -#include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> -#include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_of.h> -#include <drm/drm_plane_helper.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> -#include <drm/drm_vblank.h> - -#include "mxsfb_drv.h" -#include "mxsfb_regs.h" - -#define MXS_SET_ADDR 0x4 -#define MXS_CLR_ADDR 0x8 -#define MODULE_CLKGATE BIT(30) -#define MODULE_SFTRST BIT(31) -/* 1 second delay should be plenty of time for block reset */ -#define RESET_TIMEOUT 1000000 - -static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) -{ - return (val & mxsfb->devdata->hs_wdth_mask) << - mxsfb->devdata->hs_wdth_shift; -} - -/* Setup the MXSFB registers for decoding the pixels out of the framebuffer */ -static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb) -{ - struct drm_crtc *crtc = &mxsfb->pipe.crtc; - struct drm_device *drm = crtc->dev; - const u32 format = crtc->primary->state->fb->format->format; - u32 ctrl, ctrl1; - - ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER; - - /* - * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to - * match the selected mode here. This differs from the original - * MXSFB driver, which had the option to configure the bus width - * to arbitrary value. This limitation should not pose an issue. - */ - - /* CTRL1 contains IRQ config and status bits, preserve those. */ - ctrl1 = readl(mxsfb->base + LCDC_CTRL1); - ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ; - - switch (format) { - case DRM_FORMAT_RGB565: - dev_dbg(drm->dev, "Setting up RGB565 mode\n"); - ctrl |= CTRL_SET_WORD_LENGTH(0); - ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf); - break; - case DRM_FORMAT_XRGB8888: - dev_dbg(drm->dev, "Setting up XRGB8888 mode\n"); - ctrl |= CTRL_SET_WORD_LENGTH(3); - /* Do not use packed pixels = one pixel per word instead. */ - ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7); - break; - default: - dev_err(drm->dev, "Unhandled pixel format %08x\n", format); - return -EINVAL; - } - - writel(ctrl1, mxsfb->base + LCDC_CTRL1); - writel(ctrl, mxsfb->base + LCDC_CTRL); - - return 0; -} - -static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb) -{ - struct drm_crtc *crtc = &mxsfb->pipe.crtc; - struct drm_device *drm = crtc->dev; - u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; - u32 reg; - - reg = readl(mxsfb->base + LCDC_CTRL); - - if (mxsfb->connector->display_info.num_bus_formats) - bus_format = mxsfb->connector->display_info.bus_formats[0]; - - DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n", - bus_format); - - reg &= ~CTRL_BUS_WIDTH_MASK; - switch (bus_format) { - case MEDIA_BUS_FMT_RGB565_1X16: - reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT); - break; - case MEDIA_BUS_FMT_RGB666_1X18: - reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT); - break; - case MEDIA_BUS_FMT_RGB888_1X24: - reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT); - break; - default: - dev_err(drm->dev, "Unknown media bus format %d\n", bus_format); - break; - } - writel(reg, mxsfb->base + LCDC_CTRL); -} - -static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) -{ - u32 reg; - - if (mxsfb->clk_disp_axi) - clk_prepare_enable(mxsfb->clk_disp_axi); - clk_prepare_enable(mxsfb->clk); - - /* If it was disabled, re-enable the mode again */ - writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET); - - /* Enable the SYNC signals first, then the DMA engine */ - reg = readl(mxsfb->base + LCDC_VDCTRL4); - reg |= VDCTRL4_SYNC_SIGNALS_ON; - writel(reg, mxsfb->base + LCDC_VDCTRL4); - - writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET); -} - -static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb) -{ - u32 reg; - - /* - * Even if we disable the controller here, it will still continue - * until its FIFOs are running out of data - */ - writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR); - - readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN), - 0, 1000); - - reg = readl(mxsfb->base + LCDC_VDCTRL4); - reg &= ~VDCTRL4_SYNC_SIGNALS_ON; - writel(reg, mxsfb->base + LCDC_VDCTRL4); - - clk_disable_unprepare(mxsfb->clk); - if (mxsfb->clk_disp_axi) - clk_disable_unprepare(mxsfb->clk_disp_axi); -} - -/* - * Clear the bit and poll it cleared. This is usually called with - * a reset address and mask being either SFTRST(bit 31) or CLKGATE - * (bit 30). - */ -static int clear_poll_bit(void __iomem *addr, u32 mask) -{ - u32 reg; - - writel(mask, addr + MXS_CLR_ADDR); - return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT); -} - -static int mxsfb_reset_block(void __iomem *reset_addr) -{ - int ret; - - ret = clear_poll_bit(reset_addr, MODULE_SFTRST); - if (ret) - return ret; - - writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); - - ret = clear_poll_bit(reset_addr, MODULE_SFTRST); - if (ret) - return ret; - - return clear_poll_bit(reset_addr, MODULE_CLKGATE); -} - -static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb) -{ - struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb; - struct drm_gem_cma_object *gem; - - if (!fb) - return 0; - - gem = drm_fb_cma_get_gem_obj(fb, 0); - if (!gem) - return 0; - - return gem->paddr; -} - -static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) -{ - struct drm_device *drm = mxsfb->pipe.crtc.dev; - struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; - u32 bus_flags = mxsfb->connector->display_info.bus_flags; - u32 vdctrl0, vsync_pulse_len, hsync_pulse_len; - int err; - - /* - * It seems, you can't re-program the controller if it is still - * running. This may lead to shifted pictures (FIFO issue?), so - * first stop the controller and drain its FIFOs. - */ - - /* Mandatory eLCDIF reset as per the Reference Manual */ - err = mxsfb_reset_block(mxsfb->base); - if (err) - return; - - /* Clear the FIFOs */ - writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); - - err = mxsfb_set_pixel_fmt(mxsfb); - if (err) - return; - - clk_set_rate(mxsfb->clk, m->crtc_clock * 1000); - - if (mxsfb->bridge && mxsfb->bridge->timings) - bus_flags = mxsfb->bridge->timings->input_bus_flags; - - DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", - m->crtc_clock, - (int)(clk_get_rate(mxsfb->clk) / 1000)); - DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n", - bus_flags); - DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); - - writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) | - TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay), - mxsfb->base + mxsfb->devdata->transfer_count); - - vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start; - - vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */ - VDCTRL0_VSYNC_PERIOD_UNIT | - VDCTRL0_VSYNC_PULSE_WIDTH_UNIT | - VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len); - if (m->flags & DRM_MODE_FLAG_PHSYNC) - vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; - if (m->flags & DRM_MODE_FLAG_PVSYNC) - vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; - /* Make sure Data Enable is high active by default */ - if (!(bus_flags & DRM_BUS_FLAG_DE_LOW)) - vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; - /* - * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric, - * controllers VDCTRL0_DOTCLK is display centric. - * Drive on positive edge -> display samples on falling edge - * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING - */ - if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) - vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING; - - writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0); - - mxsfb_set_bus_fmt(mxsfb); - - /* Frame length in lines. */ - writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1); - - /* Line length in units of clocks or pixels. */ - hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start; - writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) | - VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal), - mxsfb->base + LCDC_VDCTRL2); - - writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) | - SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start), - mxsfb->base + LCDC_VDCTRL3); - - writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay), - mxsfb->base + LCDC_VDCTRL4); -} - -void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb) -{ - dma_addr_t paddr; - - mxsfb_enable_axi_clk(mxsfb); - mxsfb_crtc_mode_set_nofb(mxsfb); - - /* Write cur_buf as well to avoid an initial corrupt frame */ - paddr = mxsfb_get_fb_paddr(mxsfb); - if (paddr) { - writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf); - writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); - } - - mxsfb_enable_controller(mxsfb); -} - -void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb) -{ - mxsfb_disable_controller(mxsfb); - mxsfb_disable_axi_clk(mxsfb); -} - -void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, - struct drm_plane_state *state) -{ - struct drm_simple_display_pipe *pipe = &mxsfb->pipe; - struct drm_crtc *crtc = &pipe->crtc; - struct drm_pending_vblank_event *event; - dma_addr_t paddr; - - spin_lock_irq(&crtc->dev->event_lock); - event = crtc->state->event; - if (event) { - crtc->state->event = NULL; - - if (drm_crtc_vblank_get(crtc) == 0) { - drm_crtc_arm_vblank_event(crtc, event); - } else { - drm_crtc_send_vblank_event(crtc, event); - } - } - spin_unlock_irq(&crtc->dev->event_lock); - - paddr = mxsfb_get_fb_paddr(mxsfb); - if (paddr) { - mxsfb_enable_axi_clk(mxsfb); - writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); - mxsfb_disable_axi_clk(mxsfb); - } -} diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 508764fccd27..8c549c3931af 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -9,30 +9,24 @@ */ #include <linux/clk.h> -#include <linux/component.h> #include <linux/dma-mapping.h> -#include <linux/list.h> +#include <linux/io.h> #include <linux/module.h> #include <linux/of_device.h> -#include <linux/of_graph.h> -#include <linux/of_reserved_mem.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/dma-resv.h> -#include <linux/spinlock.h> -#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_crtc.h> +#include <drm/drm_bridge.h> +#include <drm/drm_connector.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_irq.h> +#include <drm/drm_mode_config.h> #include <drm/drm_of.h> -#include <drm/drm_panel.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> #include "mxsfb_drv.h" @@ -41,6 +35,11 @@ enum mxsfb_devtype { MXSFB_V3, MXSFB_V4, + /* + * Starting at i.MX6 the hardware version register is gone, use the + * i.MX family number as the version. + */ + MXSFB_V6, }; static const struct mxsfb_devdata mxsfb_devdata[] = { @@ -48,38 +47,28 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { .transfer_count = LCDC_V3_TRANSFER_COUNT, .cur_buf = LCDC_V3_CUR_BUF, .next_buf = LCDC_V3_NEXT_BUF, - .debug0 = LCDC_V3_DEBUG0, .hs_wdth_mask = 0xff, .hs_wdth_shift = 24, - .ipversion = 3, + .has_overlay = false, }, [MXSFB_V4] = { .transfer_count = LCDC_V4_TRANSFER_COUNT, .cur_buf = LCDC_V4_CUR_BUF, .next_buf = LCDC_V4_NEXT_BUF, - .debug0 = LCDC_V4_DEBUG0, .hs_wdth_mask = 0x3fff, .hs_wdth_shift = 18, - .ipversion = 4, + .has_overlay = false, + }, + [MXSFB_V6] = { + .transfer_count = LCDC_V4_TRANSFER_COUNT, + .cur_buf = LCDC_V4_CUR_BUF, + .next_buf = LCDC_V4_NEXT_BUF, + .hs_wdth_mask = 0x3fff, + .hs_wdth_shift = 18, + .has_overlay = true, }, }; -static const uint32_t mxsfb_formats[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_RGB565 -}; - -static const uint64_t mxsfb_modifiers[] = { - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - -static struct mxsfb_drm_private * -drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe) -{ - return container_of(pipe, struct mxsfb_drm_private, pipe); -} - void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb) { if (mxsfb->clk_axi) @@ -102,101 +91,51 @@ static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; -static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static int mxsfb_attach_bridge(struct mxsfb_drm_private *mxsfb) { - struct drm_connector *connector; - struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); - struct drm_device *drm = pipe->plane.dev; - - if (!mxsfb->connector) { - list_for_each_entry(connector, - &drm->mode_config.connector_list, - head) - if (connector->encoder == &mxsfb->pipe.encoder) { - mxsfb->connector = connector; - break; - } - } - - if (!mxsfb->connector) { - dev_warn(drm->dev, "No connector attached, using default\n"); - mxsfb->connector = &mxsfb->panel_connector; - } - - pm_runtime_get_sync(drm->dev); - drm_panel_prepare(mxsfb->panel); - mxsfb_crtc_enable(mxsfb); - drm_panel_enable(mxsfb->panel); -} + struct drm_device *drm = mxsfb->drm; + struct drm_connector_list_iter iter; + struct drm_panel *panel; + struct drm_bridge *bridge; + int ret; -static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) -{ - struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); - struct drm_device *drm = pipe->plane.dev; - struct drm_crtc *crtc = &pipe->crtc; - struct drm_pending_vblank_event *event; - - drm_panel_disable(mxsfb->panel); - mxsfb_crtc_disable(mxsfb); - drm_panel_unprepare(mxsfb->panel); - pm_runtime_put_sync(drm->dev); + ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, + &bridge); + if (ret) + return ret; - spin_lock_irq(&drm->event_lock); - event = crtc->state->event; - if (event) { - crtc->state->event = NULL; - drm_crtc_send_vblank_event(crtc, event); + if (panel) { + bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); } - spin_unlock_irq(&drm->event_lock); - if (mxsfb->connector != &mxsfb->panel_connector) - mxsfb->connector = NULL; -} - -static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state) -{ - struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); + if (!bridge) + return -ENODEV; - mxsfb_plane_atomic_update(mxsfb, plane_state); -} + ret = drm_bridge_attach(&mxsfb->encoder, bridge, NULL, 0); + if (ret) { + DRM_DEV_ERROR(drm->dev, + "failed to attach bridge: %d\n", ret); + return ret; + } -static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) -{ - struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); + mxsfb->bridge = bridge; - /* Clear and enable VBLANK IRQ */ - mxsfb_enable_axi_clk(mxsfb); - writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); - writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET); - mxsfb_disable_axi_clk(mxsfb); + /* + * Get hold of the connector. This is a bit of a hack, until the bridge + * API gives us bus flags and formats. + */ + drm_connector_list_iter_begin(drm, &iter); + mxsfb->connector = drm_connector_list_iter_next(&iter); + drm_connector_list_iter_end(&iter); return 0; } -static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) -{ - struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); - - /* Disable and clear VBLANK IRQ */ - mxsfb_enable_axi_clk(mxsfb); - writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR); - writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); - mxsfb_disable_axi_clk(mxsfb); -} - -static struct drm_simple_display_pipe_funcs mxsfb_funcs = { - .enable = mxsfb_pipe_enable, - .disable = mxsfb_pipe_disable, - .update = mxsfb_pipe_update, - .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, - .enable_vblank = mxsfb_pipe_enable_vblank, - .disable_vblank = mxsfb_pipe_disable_vblank, -}; - -static int mxsfb_load(struct drm_device *drm) +static int mxsfb_load(struct drm_device *drm, + const struct mxsfb_devdata *devdata) { struct platform_device *pdev = to_platform_device(drm->dev); struct mxsfb_drm_private *mxsfb; @@ -207,8 +146,9 @@ static int mxsfb_load(struct drm_device *drm) if (!mxsfb) return -ENOMEM; + mxsfb->drm = drm; drm->dev_private = mxsfb; - mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data]; + mxsfb->devdata = devdata; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mxsfb->base = devm_ioremap_resource(drm->dev, res); @@ -233,50 +173,28 @@ static int mxsfb_load(struct drm_device *drm) pm_runtime_enable(drm->dev); - ret = drm_vblank_init(drm, drm->mode_config.num_crtc); - if (ret < 0) { - dev_err(drm->dev, "Failed to initialise vblank\n"); - goto err_vblank; - } - /* Modeset init */ drm_mode_config_init(drm); - ret = mxsfb_create_output(drm); + ret = mxsfb_kms_init(mxsfb); if (ret < 0) { - dev_err(drm->dev, "Failed to create outputs\n"); + dev_err(drm->dev, "Failed to initialize KMS pipeline\n"); goto err_vblank; } - ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs, - mxsfb_formats, ARRAY_SIZE(mxsfb_formats), - mxsfb_modifiers, mxsfb->connector); + ret = drm_vblank_init(drm, drm->mode_config.num_crtc); if (ret < 0) { - dev_err(drm->dev, "Cannot setup simple display pipe\n"); + dev_err(drm->dev, "Failed to initialise vblank\n"); goto err_vblank; } - /* - * Attach panel only if there is one. - * If there is no panel attach, it must be a bridge. In this case, we - * need a reference to its connector for a proper initialization. - * We will do this check in pipe->enable(), since the connector won't - * be attached to an encoder until then. - */ + /* Start with vertical blanking interrupt reporting disabled. */ + drm_crtc_vblank_off(&mxsfb->crtc); - if (mxsfb->panel) { - ret = drm_panel_attach(mxsfb->panel, mxsfb->connector); - if (ret) { - dev_err(drm->dev, "Cannot connect panel: %d\n", ret); - goto err_vblank; - } - } else if (mxsfb->bridge) { - ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe, - mxsfb->bridge); - if (ret) { - dev_err(drm->dev, "Cannot connect bridge: %d\n", ret); - goto err_vblank; - } + ret = mxsfb_attach_bridge(mxsfb); + if (ret) { + dev_err(drm->dev, "Cannot connect bridge: %d\n", ret); + goto err_vblank; } drm->mode_config.min_width = MXSFB_MIN_XRES; @@ -294,7 +212,7 @@ static int mxsfb_load(struct drm_device *drm) if (ret < 0) { dev_err(drm->dev, "Failed to install IRQ handler\n"); - goto err_irq; + goto err_vblank; } drm_kms_helper_poll_init(drm); @@ -305,8 +223,6 @@ static int mxsfb_load(struct drm_device *drm) return 0; -err_irq: - drm_panel_detach(mxsfb->panel); err_vblank: pm_runtime_disable(drm->dev); @@ -327,11 +243,13 @@ static void mxsfb_unload(struct drm_device *drm) pm_runtime_disable(drm->dev); } -static void mxsfb_irq_preinstall(struct drm_device *drm) +static void mxsfb_irq_disable(struct drm_device *drm) { struct mxsfb_drm_private *mxsfb = drm->dev_private; - mxsfb_pipe_disable_vblank(&mxsfb->pipe); + mxsfb_enable_axi_clk(mxsfb); + mxsfb->crtc.funcs->disable_vblank(&mxsfb->crtc); + mxsfb_disable_axi_clk(mxsfb); } static irqreturn_t mxsfb_irq_handler(int irq, void *data) @@ -340,17 +258,13 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data) struct mxsfb_drm_private *mxsfb = drm->dev_private; u32 reg; - mxsfb_enable_axi_clk(mxsfb); - reg = readl(mxsfb->base + LCDC_CTRL1); if (reg & CTRL1_CUR_FRAME_DONE_IRQ) - drm_crtc_handle_vblank(&mxsfb->pipe.crtc); + drm_crtc_handle_vblank(&mxsfb->crtc); writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); - mxsfb_disable_axi_clk(mxsfb); - return IRQ_HANDLED; } @@ -359,8 +273,8 @@ DEFINE_DRM_GEM_CMA_FOPS(fops); static struct drm_driver mxsfb_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .irq_handler = mxsfb_irq_handler, - .irq_preinstall = mxsfb_irq_preinstall, - .irq_uninstall = mxsfb_irq_preinstall, + .irq_preinstall = mxsfb_irq_disable, + .irq_uninstall = mxsfb_irq_disable, DRM_GEM_CMA_DRIVER_OPS, .fops = &fops, .name = "mxsfb-drm", @@ -370,18 +284,10 @@ static struct drm_driver mxsfb_driver = { .minor = 0, }; -static const struct platform_device_id mxsfb_devtype[] = { - { .name = "imx23-fb", .driver_data = MXSFB_V3, }, - { .name = "imx28-fb", .driver_data = MXSFB_V4, }, - { .name = "imx6sx-fb", .driver_data = MXSFB_V4, }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, mxsfb_devtype); - static const struct of_device_id mxsfb_dt_ids[] = { - { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], }, - { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], }, - { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], }, + { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devdata[MXSFB_V3], }, + { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devdata[MXSFB_V4], }, + { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devdata[MXSFB_V6], }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mxsfb_dt_ids); @@ -396,14 +302,11 @@ static int mxsfb_probe(struct platform_device *pdev) if (!pdev->dev.of_node) return -ENODEV; - if (of_id) - pdev->id_entry = of_id->data; - drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev); if (IS_ERR(drm)) return PTR_ERR(drm); - ret = mxsfb_load(drm); + ret = mxsfb_load(drm, of_id->data); if (ret) goto err_free; @@ -457,7 +360,6 @@ static const struct dev_pm_ops mxsfb_pm_ops = { static struct platform_driver mxsfb_platform_driver = { .probe = mxsfb_probe, .remove = mxsfb_remove, - .id_table = mxsfb_devtype, .driver = { .name = "mxsfb", .of_match_table = mxsfb_dt_ids, diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h index 0b65b5194a9c..399d23e91ed1 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h @@ -8,14 +8,20 @@ #ifndef __MXSFB_DRV_H__ #define __MXSFB_DRV_H__ +#include <drm/drm_crtc.h> +#include <drm/drm_device.h> +#include <drm/drm_encoder.h> +#include <drm/drm_plane.h> + +struct clk; + struct mxsfb_devdata { - unsigned int transfer_count; - unsigned int cur_buf; - unsigned int next_buf; - unsigned int debug0; - unsigned int hs_wdth_mask; - unsigned int hs_wdth_shift; - unsigned int ipversion; + unsigned int transfer_count; + unsigned int cur_buf; + unsigned int next_buf; + unsigned int hs_wdth_mask; + unsigned int hs_wdth_shift; + bool has_overlay; }; struct mxsfb_drm_private { @@ -26,22 +32,26 @@ struct mxsfb_drm_private { struct clk *clk_axi; struct clk *clk_disp_axi; - struct drm_simple_display_pipe pipe; - struct drm_connector panel_connector; + struct drm_device *drm; + struct { + struct drm_plane primary; + struct drm_plane overlay; + } planes; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector *connector; - struct drm_panel *panel; struct drm_bridge *bridge; }; -int mxsfb_setup_crtc(struct drm_device *dev); -int mxsfb_create_output(struct drm_device *dev); +static inline struct mxsfb_drm_private * +to_mxsfb_drm_private(struct drm_device *drm) +{ + return drm->dev_private; +} void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb); void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb); -void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb); -void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb); -void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, - struct drm_plane_state *state); +int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb); #endif /* __MXSFB_DRV_H__ */ diff --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c new file mode 100644 index 000000000000..b721b8b262ce --- /dev/null +++ b/drivers/gpu/drm/mxsfb/mxsfb_kms.c @@ -0,0 +1,571 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2016 Marek Vasut <[email protected]> + * + * This code is based on drivers/video/fbdev/mxsfb.c : + * Copyright (C) 2010 Juergen Beisert, Pengutronix + * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/pm_runtime.h> +#include <linux/spinlock.h> + +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_crtc.h> +#include <drm/drm_encoder.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_plane.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_vblank.h> + +#include "mxsfb_drv.h" +#include "mxsfb_regs.h" + +/* 1 second delay should be plenty of time for block reset */ +#define RESET_TIMEOUT 1000000 + +/* ----------------------------------------------------------------------------- + * CRTC + */ + +static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) +{ + return (val & mxsfb->devdata->hs_wdth_mask) << + mxsfb->devdata->hs_wdth_shift; +} + +/* + * Setup the MXSFB registers for decoding the pixels out of the framebuffer and + * outputting them on the bus. + */ +static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb) +{ + struct drm_device *drm = mxsfb->drm; + const u32 format = mxsfb->crtc.primary->state->fb->format->format; + u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; + u32 ctrl, ctrl1; + + if (mxsfb->connector->display_info.num_bus_formats) + bus_format = mxsfb->connector->display_info.bus_formats[0]; + + DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n", + bus_format); + + ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER; + + /* CTRL1 contains IRQ config and status bits, preserve those. */ + ctrl1 = readl(mxsfb->base + LCDC_CTRL1); + ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ; + + switch (format) { + case DRM_FORMAT_RGB565: + dev_dbg(drm->dev, "Setting up RGB565 mode\n"); + ctrl |= CTRL_WORD_LENGTH_16; + ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf); + break; + case DRM_FORMAT_XRGB8888: + dev_dbg(drm->dev, "Setting up XRGB8888 mode\n"); + ctrl |= CTRL_WORD_LENGTH_24; + /* Do not use packed pixels = one pixel per word instead. */ + ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7); + break; + } + + switch (bus_format) { + case MEDIA_BUS_FMT_RGB565_1X16: + ctrl |= CTRL_BUS_WIDTH_16; + break; + case MEDIA_BUS_FMT_RGB666_1X18: + ctrl |= CTRL_BUS_WIDTH_18; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + ctrl |= CTRL_BUS_WIDTH_24; + break; + default: + dev_err(drm->dev, "Unknown media bus format %d\n", bus_format); + break; + } + + writel(ctrl1, mxsfb->base + LCDC_CTRL1); + writel(ctrl, mxsfb->base + LCDC_CTRL); +} + +static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) +{ + u32 reg; + + if (mxsfb->clk_disp_axi) + clk_prepare_enable(mxsfb->clk_disp_axi); + clk_prepare_enable(mxsfb->clk); + + /* If it was disabled, re-enable the mode again */ + writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET); + + /* Enable the SYNC signals first, then the DMA engine */ + reg = readl(mxsfb->base + LCDC_VDCTRL4); + reg |= VDCTRL4_SYNC_SIGNALS_ON; + writel(reg, mxsfb->base + LCDC_VDCTRL4); + + writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET); +} + +static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb) +{ + u32 reg; + + /* + * Even if we disable the controller here, it will still continue + * until its FIFOs are running out of data + */ + writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR); + + readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN), + 0, 1000); + + reg = readl(mxsfb->base + LCDC_VDCTRL4); + reg &= ~VDCTRL4_SYNC_SIGNALS_ON; + writel(reg, mxsfb->base + LCDC_VDCTRL4); + + clk_disable_unprepare(mxsfb->clk); + if (mxsfb->clk_disp_axi) + clk_disable_unprepare(mxsfb->clk_disp_axi); +} + +/* + * Clear the bit and poll it cleared. This is usually called with + * a reset address and mask being either SFTRST(bit 31) or CLKGATE + * (bit 30). + */ +static int clear_poll_bit(void __iomem *addr, u32 mask) +{ + u32 reg; + + writel(mask, addr + REG_CLR); + return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT); +} + +static int mxsfb_reset_block(struct mxsfb_drm_private *mxsfb) +{ + int ret; + + ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST); + if (ret) + return ret; + + writel(CTRL_CLKGATE, mxsfb->base + LCDC_CTRL + REG_CLR); + + ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST); + if (ret) + return ret; + + return clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_CLKGATE); +} + +static dma_addr_t mxsfb_get_fb_paddr(struct drm_plane *plane) +{ + struct drm_framebuffer *fb = plane->state->fb; + struct drm_gem_cma_object *gem; + + if (!fb) + return 0; + + gem = drm_fb_cma_get_gem_obj(fb, 0); + if (!gem) + return 0; + + return gem->paddr; +} + +static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) +{ + struct drm_device *drm = mxsfb->crtc.dev; + struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode; + u32 bus_flags = mxsfb->connector->display_info.bus_flags; + u32 vdctrl0, vsync_pulse_len, hsync_pulse_len; + int err; + + /* + * It seems, you can't re-program the controller if it is still + * running. This may lead to shifted pictures (FIFO issue?), so + * first stop the controller and drain its FIFOs. + */ + + /* Mandatory eLCDIF reset as per the Reference Manual */ + err = mxsfb_reset_block(mxsfb); + if (err) + return; + + /* Clear the FIFOs */ + writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); + + if (mxsfb->devdata->has_overlay) + writel(0, mxsfb->base + LCDC_AS_CTRL); + + mxsfb_set_formats(mxsfb); + + clk_set_rate(mxsfb->clk, m->crtc_clock * 1000); + + if (mxsfb->bridge && mxsfb->bridge->timings) + bus_flags = mxsfb->bridge->timings->input_bus_flags; + + DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", + m->crtc_clock, + (int)(clk_get_rate(mxsfb->clk) / 1000)); + DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n", + bus_flags); + DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); + + writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) | + TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay), + mxsfb->base + mxsfb->devdata->transfer_count); + + vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start; + + vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */ + VDCTRL0_VSYNC_PERIOD_UNIT | + VDCTRL0_VSYNC_PULSE_WIDTH_UNIT | + VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len); + if (m->flags & DRM_MODE_FLAG_PHSYNC) + vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; + if (m->flags & DRM_MODE_FLAG_PVSYNC) + vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; + /* Make sure Data Enable is high active by default */ + if (!(bus_flags & DRM_BUS_FLAG_DE_LOW)) + vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; + /* + * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric, + * controllers VDCTRL0_DOTCLK is display centric. + * Drive on positive edge -> display samples on falling edge + * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING + */ + if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) + vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING; + + writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0); + + /* Frame length in lines. */ + writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1); + + /* Line length in units of clocks or pixels. */ + hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start; + writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) | + VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal), + mxsfb->base + LCDC_VDCTRL2); + + writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) | + SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start), + mxsfb->base + LCDC_VDCTRL3); + + writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay), + mxsfb->base + LCDC_VDCTRL4); +} + +static int mxsfb_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + bool has_primary = state->plane_mask & + drm_plane_mask(crtc->primary); + + /* The primary plane has to be enabled when the CRTC is active. */ + if (state->active && !has_primary) + return -EINVAL; + + /* TODO: Is this needed ? */ + return drm_atomic_add_affected_planes(state->state, crtc); +} + +static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct drm_pending_vblank_event *event; + + event = crtc->state->event; + crtc->state->event = NULL; + + if (!event) + return; + + spin_lock_irq(&crtc->dev->event_lock); + if (drm_crtc_vblank_get(crtc) == 0) + drm_crtc_arm_vblank_event(crtc, event); + else + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); +} + +static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); + struct drm_device *drm = mxsfb->drm; + dma_addr_t paddr; + + pm_runtime_get_sync(drm->dev); + mxsfb_enable_axi_clk(mxsfb); + + drm_crtc_vblank_on(crtc); + + mxsfb_crtc_mode_set_nofb(mxsfb); + + /* Write cur_buf as well to avoid an initial corrupt frame */ + paddr = mxsfb_get_fb_paddr(crtc->primary); + if (paddr) { + writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf); + writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); + } + + mxsfb_enable_controller(mxsfb); +} + +static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); + struct drm_device *drm = mxsfb->drm; + struct drm_pending_vblank_event *event; + + mxsfb_disable_controller(mxsfb); + + spin_lock_irq(&drm->event_lock); + event = crtc->state->event; + if (event) { + crtc->state->event = NULL; + drm_crtc_send_vblank_event(crtc, event); + } + spin_unlock_irq(&drm->event_lock); + + drm_crtc_vblank_off(crtc); + + mxsfb_disable_axi_clk(mxsfb); + pm_runtime_put_sync(drm->dev); +} + +static int mxsfb_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); + + /* Clear and enable VBLANK IRQ */ + writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); + writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET); + + return 0; +} + +static void mxsfb_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); + + /* Disable and clear VBLANK IRQ */ + writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR); + writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); +} + +static const struct drm_crtc_helper_funcs mxsfb_crtc_helper_funcs = { + .atomic_check = mxsfb_crtc_atomic_check, + .atomic_flush = mxsfb_crtc_atomic_flush, + .atomic_enable = mxsfb_crtc_atomic_enable, + .atomic_disable = mxsfb_crtc_atomic_disable, +}; + +static const struct drm_crtc_funcs mxsfb_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = mxsfb_crtc_enable_vblank, + .disable_vblank = mxsfb_crtc_disable_vblank, +}; + +/* ----------------------------------------------------------------------------- + * Encoder + */ + +static const struct drm_encoder_funcs mxsfb_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +/* ----------------------------------------------------------------------------- + * Planes + */ + +static int mxsfb_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *plane_state) +{ + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev); + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_new_crtc_state(plane_state->state, + &mxsfb->crtc); + + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); +} + +static void mxsfb_plane_primary_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_pstate) +{ + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev); + dma_addr_t paddr; + + paddr = mxsfb_get_fb_paddr(plane); + if (paddr) + writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); +} + +static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_pstate) +{ + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev); + struct drm_plane_state *state = plane->state; + dma_addr_t paddr; + u32 ctrl; + + paddr = mxsfb_get_fb_paddr(plane); + if (!paddr) { + writel(0, mxsfb->base + LCDC_AS_CTRL); + return; + } + + /* + * HACK: The hardware seems to output 64 bytes of data of unknown + * origin, and then to proceed with the framebuffer. Until the reason + * is understood, live with the 16 initial invalid pixels on the first + * line and start 64 bytes within the framebuffer. + */ + paddr += 64; + + writel(paddr, mxsfb->base + LCDC_AS_NEXT_BUF); + + /* + * If the plane was previously disabled, write LCDC_AS_BUF as well to + * provide the first buffer. + */ + if (!old_pstate->fb) + writel(paddr, mxsfb->base + LCDC_AS_BUF); + + ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255); + + switch (state->fb->format->format) { + case DRM_FORMAT_XRGB4444: + ctrl |= AS_CTRL_FORMAT_RGB444 | AS_CTRL_ALPHA_CTRL_OVERRIDE; + break; + case DRM_FORMAT_ARGB4444: + ctrl |= AS_CTRL_FORMAT_ARGB4444 | AS_CTRL_ALPHA_CTRL_EMBEDDED; + break; + case DRM_FORMAT_XRGB1555: + ctrl |= AS_CTRL_FORMAT_RGB555 | AS_CTRL_ALPHA_CTRL_OVERRIDE; + break; + case DRM_FORMAT_ARGB1555: + ctrl |= AS_CTRL_FORMAT_ARGB1555 | AS_CTRL_ALPHA_CTRL_EMBEDDED; + break; + case DRM_FORMAT_RGB565: + ctrl |= AS_CTRL_FORMAT_RGB565 | AS_CTRL_ALPHA_CTRL_OVERRIDE; + break; + case DRM_FORMAT_XRGB8888: + ctrl |= AS_CTRL_FORMAT_RGB888 | AS_CTRL_ALPHA_CTRL_OVERRIDE; + break; + case DRM_FORMAT_ARGB8888: + ctrl |= AS_CTRL_FORMAT_ARGB8888 | AS_CTRL_ALPHA_CTRL_EMBEDDED; + break; + } + + writel(ctrl, mxsfb->base + LCDC_AS_CTRL); +} + +static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = { + .atomic_check = mxsfb_plane_atomic_check, + .atomic_update = mxsfb_plane_primary_atomic_update, +}; + +static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = { + .atomic_check = mxsfb_plane_atomic_check, + .atomic_update = mxsfb_plane_overlay_atomic_update, +}; + +static const struct drm_plane_funcs mxsfb_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static const uint32_t mxsfb_primary_plane_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, +}; + +static const uint32_t mxsfb_overlay_plane_formats[] = { + DRM_FORMAT_XRGB4444, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, +}; + +static const uint64_t mxsfb_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +/* ----------------------------------------------------------------------------- + * Initialization + */ + +int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb) +{ + struct drm_encoder *encoder = &mxsfb->encoder; + struct drm_crtc *crtc = &mxsfb->crtc; + int ret; + + drm_plane_helper_add(&mxsfb->planes.primary, + &mxsfb_plane_primary_helper_funcs); + ret = drm_universal_plane_init(mxsfb->drm, &mxsfb->planes.primary, 1, + &mxsfb_plane_funcs, + mxsfb_primary_plane_formats, + ARRAY_SIZE(mxsfb_primary_plane_formats), + mxsfb_modifiers, DRM_PLANE_TYPE_PRIMARY, + NULL); + if (ret) + return ret; + + if (mxsfb->devdata->has_overlay) { + drm_plane_helper_add(&mxsfb->planes.overlay, + &mxsfb_plane_overlay_helper_funcs); + ret = drm_universal_plane_init(mxsfb->drm, + &mxsfb->planes.overlay, 1, + &mxsfb_plane_funcs, + mxsfb_overlay_plane_formats, + ARRAY_SIZE(mxsfb_overlay_plane_formats), + mxsfb_modifiers, DRM_PLANE_TYPE_OVERLAY, + NULL); + if (ret) + return ret; + } + + drm_crtc_helper_add(crtc, &mxsfb_crtc_helper_funcs); + ret = drm_crtc_init_with_planes(mxsfb->drm, crtc, + &mxsfb->planes.primary, NULL, + &mxsfb_crtc_funcs, NULL); + if (ret) + return ret; + + encoder->possible_crtcs = drm_crtc_mask(crtc); + return drm_encoder_init(mxsfb->drm, encoder, &mxsfb_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); +} diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c deleted file mode 100644 index 9eca1605d11d..000000000000 --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Marek Vasut <[email protected]> - */ - -#include <linux/of_graph.h> - -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_of.h> -#include <drm/drm_panel.h> -#include <drm/drm_plane_helper.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> - -#include "mxsfb_drv.h" - -static struct mxsfb_drm_private * -drm_connector_to_mxsfb_drm_private(struct drm_connector *connector) -{ - return container_of(connector, struct mxsfb_drm_private, - panel_connector); -} - -static int mxsfb_panel_get_modes(struct drm_connector *connector) -{ - struct mxsfb_drm_private *mxsfb = - drm_connector_to_mxsfb_drm_private(connector); - - if (mxsfb->panel) - return drm_panel_get_modes(mxsfb->panel, connector); - - return 0; -} - -static const struct -drm_connector_helper_funcs mxsfb_panel_connector_helper_funcs = { - .get_modes = mxsfb_panel_get_modes, -}; - -static enum drm_connector_status -mxsfb_panel_connector_detect(struct drm_connector *connector, bool force) -{ - struct mxsfb_drm_private *mxsfb = - drm_connector_to_mxsfb_drm_private(connector); - - if (mxsfb->panel) - return connector_status_connected; - - return connector_status_disconnected; -} - -static void mxsfb_panel_connector_destroy(struct drm_connector *connector) -{ - struct mxsfb_drm_private *mxsfb = - drm_connector_to_mxsfb_drm_private(connector); - - if (mxsfb->panel) - drm_panel_detach(mxsfb->panel); - - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static const struct drm_connector_funcs mxsfb_panel_connector_funcs = { - .detect = mxsfb_panel_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = mxsfb_panel_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -int mxsfb_create_output(struct drm_device *drm) -{ - struct mxsfb_drm_private *mxsfb = drm->dev_private; - int ret; - - ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, - &mxsfb->panel, &mxsfb->bridge); - if (ret) - return ret; - - if (mxsfb->panel) { - mxsfb->connector = &mxsfb->panel_connector; - mxsfb->connector->dpms = DRM_MODE_DPMS_OFF; - mxsfb->connector->polled = 0; - drm_connector_helper_add(mxsfb->connector, - &mxsfb_panel_connector_helper_funcs); - ret = drm_connector_init(drm, mxsfb->connector, - &mxsfb_panel_connector_funcs, - DRM_MODE_CONNECTOR_Unknown); - } - - return ret; -} diff --git a/drivers/gpu/drm/mxsfb/mxsfb_regs.h b/drivers/gpu/drm/mxsfb/mxsfb_regs.h index 932d7ea08fd5..55d28a27f912 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_regs.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h @@ -27,52 +27,61 @@ #define LCDC_VDCTRL4 0xb0 #define LCDC_V4_DEBUG0 0x1d0 #define LCDC_V3_DEBUG0 0x1f0 - -#define CTRL_SFTRST (1 << 31) -#define CTRL_CLKGATE (1 << 30) -#define CTRL_BYPASS_COUNT (1 << 19) -#define CTRL_VSYNC_MODE (1 << 18) -#define CTRL_DOTCLK_MODE (1 << 17) -#define CTRL_DATA_SELECT (1 << 16) -#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10) -#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3) +#define LCDC_AS_CTRL 0x210 +#define LCDC_AS_BUF 0x220 +#define LCDC_AS_NEXT_BUF 0x230 +#define LCDC_AS_CLRKEYLOW 0x240 +#define LCDC_AS_CLRKEYHIGH 0x250 + +#define CTRL_SFTRST BIT(31) +#define CTRL_CLKGATE BIT(30) +#define CTRL_BYPASS_COUNT BIT(19) +#define CTRL_VSYNC_MODE BIT(18) +#define CTRL_DOTCLK_MODE BIT(17) +#define CTRL_DATA_SELECT BIT(16) +#define CTRL_BUS_WIDTH_16 (0 << 10) +#define CTRL_BUS_WIDTH_8 (1 << 10) +#define CTRL_BUS_WIDTH_18 (2 << 10) +#define CTRL_BUS_WIDTH_24 (3 << 10) #define CTRL_BUS_WIDTH_MASK (0x3 << 10) -#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8) -#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3) -#define CTRL_MASTER (1 << 5) -#define CTRL_DF16 (1 << 3) -#define CTRL_DF18 (1 << 2) -#define CTRL_DF24 (1 << 1) -#define CTRL_RUN (1 << 0) - -#define CTRL1_FIFO_CLEAR (1 << 21) +#define CTRL_WORD_LENGTH_16 (0 << 8) +#define CTRL_WORD_LENGTH_8 (1 << 8) +#define CTRL_WORD_LENGTH_18 (2 << 8) +#define CTRL_WORD_LENGTH_24 (3 << 8) +#define CTRL_MASTER BIT(5) +#define CTRL_DF16 BIT(3) +#define CTRL_DF18 BIT(2) +#define CTRL_DF24 BIT(1) +#define CTRL_RUN BIT(0) + +#define CTRL1_FIFO_CLEAR BIT(21) #define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16) #define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf) -#define CTRL1_CUR_FRAME_DONE_IRQ_EN (1 << 13) -#define CTRL1_CUR_FRAME_DONE_IRQ (1 << 9) +#define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13) +#define CTRL1_CUR_FRAME_DONE_IRQ BIT(9) #define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16) #define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff) #define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff) #define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff) -#define VDCTRL0_ENABLE_PRESENT (1 << 28) -#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27) -#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26) -#define VDCTRL0_DOTCLK_ACT_FALLING (1 << 25) -#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24) -#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21) -#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20) -#define VDCTRL0_HALF_LINE (1 << 19) -#define VDCTRL0_HALF_LINE_MODE (1 << 18) +#define VDCTRL0_ENABLE_PRESENT BIT(28) +#define VDCTRL0_VSYNC_ACT_HIGH BIT(27) +#define VDCTRL0_HSYNC_ACT_HIGH BIT(26) +#define VDCTRL0_DOTCLK_ACT_FALLING BIT(25) +#define VDCTRL0_ENABLE_ACT_HIGH BIT(24) +#define VDCTRL0_VSYNC_PERIOD_UNIT BIT(21) +#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT BIT(20) +#define VDCTRL0_HALF_LINE BIT(19) +#define VDCTRL0_HALF_LINE_MODE BIT(18) #define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) #define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) #define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff) #define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff) -#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29) -#define VDCTRL3_VSYNC_ONLY (1 << 28) +#define VDCTRL3_MUX_SYNC_SIGNALS BIT(29) +#define VDCTRL3_VSYNC_ONLY BIT(28) #define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16) #define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff) #define SET_VERT_WAIT_CNT(x) ((x) & 0xffff) @@ -80,28 +89,32 @@ #define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */ #define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */ -#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18) +#define VDCTRL4_SYNC_SIGNALS_ON BIT(18) #define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff) -#define DEBUG0_HSYNC (1 < 26) -#define DEBUG0_VSYNC (1 < 25) +#define DEBUG0_HSYNC BIT(26) +#define DEBUG0_VSYNC BIT(25) + +#define AS_CTRL_PS_DISABLE BIT(23) +#define AS_CTRL_ALPHA_INVERT BIT(20) +#define AS_CTRL_ALPHA(a) (((a) & 0xff) << 8) +#define AS_CTRL_FORMAT_RGB565 (0xe << 4) +#define AS_CTRL_FORMAT_RGB444 (0xd << 4) +#define AS_CTRL_FORMAT_RGB555 (0xc << 4) +#define AS_CTRL_FORMAT_ARGB4444 (0x9 << 4) +#define AS_CTRL_FORMAT_ARGB1555 (0x8 << 4) +#define AS_CTRL_FORMAT_RGB888 (0x4 << 4) +#define AS_CTRL_FORMAT_ARGB8888 (0x0 << 4) +#define AS_CTRL_ENABLE_COLORKEY BIT(3) +#define AS_CTRL_ALPHA_CTRL_ROP (3 << 1) +#define AS_CTRL_ALPHA_CTRL_MULTIPLY (2 << 1) +#define AS_CTRL_ALPHA_CTRL_OVERRIDE (1 << 1) +#define AS_CTRL_ALPHA_CTRL_EMBEDDED (0 << 1) +#define AS_CTRL_AS_ENABLE BIT(0) #define MXSFB_MIN_XRES 120 #define MXSFB_MIN_YRES 120 #define MXSFB_MAX_XRES 0xffff #define MXSFB_MAX_YRES 0xffff -#define RED 0 -#define GREEN 1 -#define BLUE 2 -#define TRANSP 3 - -#define STMLCDIF_8BIT 1 /* pixel data bus to the display is of 8 bit width */ -#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */ -#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */ -#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */ - -#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6) -#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negative edge sampling */ - #endif /* __MXSFB_REGS_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 7806278dce57..9140387f30dc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -646,66 +646,6 @@ nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags) return nouveau_sgdma_create_ttm(bo, page_flags); } -static int -nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, - struct ttm_mem_type_manager *man) -{ - struct nouveau_drm *drm = nouveau_bdev(bdev); - struct nvif_mmu *mmu = &drm->client.mmu; - - switch (type) { - case TTM_PL_SYSTEM: - man->flags = 0; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case TTM_PL_VRAM: - man->flags = TTM_MEMTYPE_FLAG_FIXED; - man->available_caching = TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; - - if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { - /* Some BARs do not support being ioremapped WC */ - const u8 type = mmu->type[drm->ttm.type_vram].type; - if (type & NVIF_MEM_UNCACHED) { - man->available_caching = TTM_PL_FLAG_UNCACHED; - man->default_caching = TTM_PL_FLAG_UNCACHED; - } - - man->func = &nouveau_vram_manager; - man->use_io_reserve_lru = true; - } else { - man->func = &ttm_bo_manager_func; - } - break; - case TTM_PL_TT: - if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) - man->func = &nouveau_gart_manager; - else - if (!drm->agp.bridge) - man->func = &nv04_gart_manager; - else - man->func = &ttm_bo_manager_func; - - if (drm->agp.bridge) { - man->flags = 0; - man->available_caching = TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; - } else { - man->flags = 0; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - } - - break; - default: - return -EINVAL; - } - return 0; -} - static void nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) { @@ -726,7 +666,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) static int nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo, - struct ttm_mem_reg *reg) + struct ttm_resource *reg) { struct nouveau_mem *old_mem = nouveau_mem(&bo->mem); struct nouveau_mem *new_mem = nouveau_mem(reg); @@ -758,7 +698,7 @@ done: static int nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, - bool no_wait_gpu, struct ttm_mem_reg *new_reg) + bool no_wait_gpu, struct ttm_resource *new_reg) { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_channel *chan = drm->ttm.chan; @@ -768,7 +708,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, /* create temporary vmas for the transfer and attach them to the * old nvkm_mem node, these will get cleaned up after ttm has - * destroyed the ttm_mem_reg + * destroyed the ttm_resource */ if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { ret = nouveau_bo_move_prep(drm, bo, new_reg); @@ -804,7 +744,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) s32 oclass; int (*exec)(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); int (*init)(struct nouveau_channel *, u32 handle); } _methods[] = { { "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init }, @@ -865,7 +805,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) static int nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, - bool no_wait_gpu, struct ttm_mem_reg *new_reg) + bool no_wait_gpu, struct ttm_resource *new_reg) { struct ttm_operation_ctx ctx = { intr, no_wait_gpu }; struct ttm_place placement_memtype = { @@ -874,7 +814,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING }; struct ttm_placement placement; - struct ttm_mem_reg tmp_reg; + struct ttm_resource tmp_reg; int ret; placement.num_placement = placement.num_busy_placement = 1; @@ -896,13 +836,13 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, ret = ttm_bo_move_ttm(bo, &ctx, new_reg); out: - ttm_bo_mem_put(bo, &tmp_reg); + ttm_resource_free(bo, &tmp_reg); return ret; } static int nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, - bool no_wait_gpu, struct ttm_mem_reg *new_reg) + bool no_wait_gpu, struct ttm_resource *new_reg) { struct ttm_operation_ctx ctx = { intr, no_wait_gpu }; struct ttm_place placement_memtype = { @@ -911,7 +851,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING }; struct ttm_placement placement; - struct ttm_mem_reg tmp_reg; + struct ttm_resource tmp_reg; int ret; placement.num_placement = placement.num_busy_placement = 1; @@ -932,13 +872,13 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, goto out; out: - ttm_bo_mem_put(bo, &tmp_reg); + ttm_resource_free(bo, &tmp_reg); return ret; } static void nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *new_reg) + struct ttm_resource *new_reg) { struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL; struct nouveau_bo *nvbo = nouveau_bo(bo); @@ -970,7 +910,7 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict, } static int -nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_reg, +nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_resource *new_reg, struct nouveau_drm_tile **new_tile) { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); @@ -1006,11 +946,11 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, static int nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_reg) + struct ttm_resource *new_reg) { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_bo *nvbo = nouveau_bo(bo); - struct ttm_mem_reg *old_reg = &bo->mem; + struct ttm_resource *old_reg = &bo->mem; struct nouveau_drm_tile *new_tile = NULL; int ret = 0; @@ -1079,18 +1019,12 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) } static int -nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg) +nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg) { struct nouveau_drm *drm = nouveau_bdev(bdev); struct nvkm_device *device = nvxx_device(&drm->client.device); struct nouveau_mem *mem = nouveau_mem(reg); - reg->bus.addr = NULL; - reg->bus.offset = 0; - reg->bus.size = reg->num_pages << PAGE_SHIFT; - reg->bus.base = 0; - reg->bus.is_iomem = false; - switch (reg->mem_type) { case TTM_PL_SYSTEM: /* System memory */ @@ -1159,7 +1093,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg) } static void -nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg) +nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_resource *reg) { struct nouveau_drm *drm = nouveau_bdev(bdev); struct nouveau_mem *mem = nouveau_mem(reg); @@ -1231,8 +1165,6 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) struct ttm_dma_tt *ttm_dma = (void *)ttm; struct nouveau_drm *drm; struct device *dev; - unsigned i; - int r; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); if (ttm->state != tt_unpopulated) @@ -1260,31 +1192,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) return ttm_dma_populate((void *)ttm, dev, ctx); } #endif - - r = ttm_pool_populate(ttm, ctx); - if (r) { - return r; - } - - for (i = 0; i < ttm->num_pages; i++) { - dma_addr_t addr; - - addr = dma_map_page(dev, ttm->pages[i], 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(dev, addr)) { - while (i--) { - dma_unmap_page(dev, ttm_dma->dma_address[i], - PAGE_SIZE, DMA_BIDIRECTIONAL); - ttm_dma->dma_address[i] = 0; - } - ttm_pool_unpopulate(ttm); - return -EFAULT; - } - - ttm_dma->dma_address[i] = addr; - } - return 0; + return ttm_populate_and_map_pages(dev, ttm_dma, ctx); } static void @@ -1293,7 +1201,6 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) struct ttm_dma_tt *ttm_dma = (void *)ttm; struct nouveau_drm *drm; struct device *dev; - unsigned i; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); if (slave) @@ -1316,14 +1223,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) } #endif - for (i = 0; i < ttm->num_pages; i++) { - if (ttm_dma->dma_address[i]) { - dma_unmap_page(dev, ttm_dma->dma_address[i], PAGE_SIZE, - DMA_BIDIRECTIONAL); - } - } - - ttm_pool_unpopulate(ttm); + ttm_unmap_and_unpopulate_pages(dev, ttm_dma); } void @@ -1341,7 +1241,6 @@ struct ttm_bo_driver nouveau_bo_driver = { .ttm_tt_create = &nouveau_ttm_tt_create, .ttm_tt_populate = &nouveau_ttm_tt_populate, .ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate, - .init_mem_type = nouveau_bo_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = nouveau_bo_evict_flags, .move_notify = nouveau_bo_move_ntfy, diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index 52489ce7d029..aecb7481df0d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -139,28 +139,28 @@ nouveau_bo_new_pin_map(struct nouveau_cli *cli, u64 size, int align, u32 flags, int nv04_bo_move_init(struct nouveau_channel *, u32); int nv04_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); int nv50_bo_move_init(struct nouveau_channel *, u32); int nv50_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); int nv84_bo_move_exec(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); int nva3_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); int nvc0_bo_move_init(struct nouveau_channel *, u32); int nvc0_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); int nvc0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); int nve0_bo_move_init(struct nouveau_channel *, u32); int nve0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); #define NVBO_WR32_(b,o,dr,f) nouveau_bo_wr32((b), (o)/4 + (dr), (f)) #define NVBO_RD32_(b,o,dr) nouveau_bo_rd32((b), (o)/4 + (dr)) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo0039.c b/drivers/gpu/drm/nouveau/nouveau_bo0039.c index bf7ae2cecaf6..7390132129fe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo0039.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo0039.c @@ -36,7 +36,7 @@ static inline uint32_t nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, - struct nouveau_channel *chan, struct ttm_mem_reg *reg) + struct nouveau_channel *chan, struct ttm_resource *reg) { if (reg->mem_type == TTM_PL_TT) return NvDmaTT; @@ -45,7 +45,7 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, int nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, - struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) + struct ttm_resource *old_reg, struct ttm_resource *new_reg) { struct nvif_push *push = chan->chan.push; u32 src_ctxdma = nouveau_bo_mem_ctxdma(bo, chan, old_reg); diff --git a/drivers/gpu/drm/nouveau/nouveau_bo5039.c b/drivers/gpu/drm/nouveau/nouveau_bo5039.c index f9b9b85abe44..4c75c7b3804c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo5039.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo5039.c @@ -37,7 +37,7 @@ int nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, - struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) + struct ttm_resource *old_reg, struct ttm_resource *new_reg) { struct nouveau_mem *mem = nouveau_mem(old_reg); struct nvif_push *push = chan->chan.push; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo74c1.c b/drivers/gpu/drm/nouveau/nouveau_bo74c1.c index 1b5fd78ddcba..ed6c09d67840 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo74c1.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo74c1.c @@ -34,7 +34,7 @@ int nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo, - struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) + struct ttm_resource *old_reg, struct ttm_resource *new_reg) { struct nouveau_mem *mem = nouveau_mem(old_reg); struct nvif_push *push = chan->chan.push; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo85b5.c b/drivers/gpu/drm/nouveau/nouveau_bo85b5.c index f0df172b029e..dec29b2d8bb2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo85b5.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo85b5.c @@ -38,7 +38,7 @@ int nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, - struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) + struct ttm_resource *old_reg, struct ttm_resource *new_reg) { struct nouveau_mem *mem = nouveau_mem(old_reg); struct nvif_push *push = chan->chan.push; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo9039.c b/drivers/gpu/drm/nouveau/nouveau_bo9039.c index 52fefb37064c..776b04976cdf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo9039.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo9039.c @@ -36,7 +36,7 @@ int nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, - struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) + struct ttm_resource *old_reg, struct ttm_resource *new_reg) { struct nvif_push *push = chan->chan.push; struct nouveau_mem *mem = nouveau_mem(old_reg); diff --git a/drivers/gpu/drm/nouveau/nouveau_bo90b5.c b/drivers/gpu/drm/nouveau/nouveau_bo90b5.c index 34b79d561c7f..8499f58213e3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo90b5.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo90b5.c @@ -31,7 +31,7 @@ int nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, - struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) + struct ttm_resource *old_reg, struct ttm_resource *new_reg) { struct nouveau_mem *mem = nouveau_mem(old_reg); struct nvif_push *push = chan->chan.push; diff --git a/drivers/gpu/drm/nouveau/nouveau_boa0b5.c b/drivers/gpu/drm/nouveau/nouveau_boa0b5.c index 394e29012e50..575212472e7a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_boa0b5.c +++ b/drivers/gpu/drm/nouveau/nouveau_boa0b5.c @@ -36,7 +36,7 @@ int nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, - struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) + struct ttm_resource *old_reg, struct ttm_resource *new_reg) { struct nouveau_mem *mem = nouveau_mem(old_reg); struct nvif_push *push = chan->chan.push; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index ae76a5865a5a..f63ac72aa556 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -157,7 +157,7 @@ struct nouveau_drm { atomic_t validate_sequence; int (*move)(struct nouveau_channel *, struct ttm_buffer_object *, - struct ttm_mem_reg *, struct ttm_mem_reg *); + struct ttm_resource *, struct ttm_resource *); struct nouveau_channel *chan; struct nvif_object copy; int mtrr; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index b1bb542d3115..269d8707acc3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -92,7 +92,7 @@ nouveau_mem_fini(struct nouveau_mem *mem) } int -nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt) +nouveau_mem_host(struct ttm_resource *reg, struct ttm_dma_tt *tt) { struct nouveau_mem *mem = nouveau_mem(reg); struct nouveau_cli *cli = mem->cli; @@ -130,7 +130,7 @@ nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt) } int -nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page) +nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page) { struct nouveau_mem *mem = nouveau_mem(reg); struct nouveau_cli *cli = mem->cli; @@ -173,7 +173,7 @@ nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page) } void -nouveau_mem_del(struct ttm_mem_reg *reg) +nouveau_mem_del(struct ttm_resource *reg) { struct nouveau_mem *mem = nouveau_mem(reg); nouveau_mem_fini(mem); @@ -183,7 +183,7 @@ nouveau_mem_del(struct ttm_mem_reg *reg) int nouveau_mem_new(struct nouveau_cli *cli, u8 kind, u8 comp, - struct ttm_mem_reg *reg) + struct ttm_resource *reg) { struct nouveau_mem *mem; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.h b/drivers/gpu/drm/nouveau/nouveau_mem.h index f6d039e73812..3fe1cfed57a1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.h +++ b/drivers/gpu/drm/nouveau/nouveau_mem.h @@ -7,7 +7,7 @@ struct ttm_dma_tt; #include <nvif/vmm.h> static inline struct nouveau_mem * -nouveau_mem(struct ttm_mem_reg *reg) +nouveau_mem(struct ttm_resource *reg) { return reg->mm_node; } @@ -21,10 +21,10 @@ struct nouveau_mem { }; int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp, - struct ttm_mem_reg *); -void nouveau_mem_del(struct ttm_mem_reg *); -int nouveau_mem_vram(struct ttm_mem_reg *, bool contig, u8 page); -int nouveau_mem_host(struct ttm_mem_reg *, struct ttm_dma_tt *); + struct ttm_resource *); +void nouveau_mem_del(struct ttm_resource *); +int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page); +int nouveau_mem_host(struct ttm_resource *, struct ttm_dma_tt *); void nouveau_mem_fini(struct nouveau_mem *); int nouveau_mem_map(struct nouveau_mem *, struct nvif_vmm *, struct nvif_vma *); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index c3ccf661b7a6..eef75c53a197 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -26,7 +26,7 @@ nouveau_sgdma_destroy(struct ttm_tt *ttm) } static int -nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg) +nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg) { struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; struct nouveau_mem *mem = nouveau_mem(reg); @@ -60,7 +60,7 @@ static struct ttm_backend_func nv04_sgdma_backend = { }; static int -nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg) +nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg) { struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; struct nouveau_mem *mem = nouveau_mem(reg); diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index e89ea052cf71..53c6f8827322 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -31,35 +31,17 @@ #include <core/tegra.h> -static int -nouveau_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) -{ - return 0; -} - -static int -nouveau_manager_fini(struct ttm_mem_type_manager *man) -{ - return 0; -} - static void -nouveau_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *reg) +nouveau_manager_del(struct ttm_resource_manager *man, struct ttm_resource *reg) { nouveau_mem_del(reg); } -static void -nouveau_manager_debug(struct ttm_mem_type_manager *man, - struct drm_printer *printer) -{ -} - static int -nouveau_vram_manager_new(struct ttm_mem_type_manager *man, +nouveau_vram_manager_new(struct ttm_resource_manager *man, struct ttm_buffer_object *bo, const struct ttm_place *place, - struct ttm_mem_reg *reg) + struct ttm_resource *reg) { struct nouveau_bo *nvbo = nouveau_bo(bo); struct nouveau_drm *drm = nouveau_bdev(bo->bdev); @@ -81,19 +63,16 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, return 0; } -const struct ttm_mem_type_manager_func nouveau_vram_manager = { - .init = nouveau_manager_init, - .takedown = nouveau_manager_fini, - .get_node = nouveau_vram_manager_new, - .put_node = nouveau_manager_del, - .debug = nouveau_manager_debug, +const struct ttm_resource_manager_func nouveau_vram_manager = { + .alloc = nouveau_vram_manager_new, + .free = nouveau_manager_del, }; static int -nouveau_gart_manager_new(struct ttm_mem_type_manager *man, +nouveau_gart_manager_new(struct ttm_resource_manager *man, struct ttm_buffer_object *bo, const struct ttm_place *place, - struct ttm_mem_reg *reg) + struct ttm_resource *reg) { struct nouveau_bo *nvbo = nouveau_bo(bo); struct nouveau_drm *drm = nouveau_bdev(bo->bdev); @@ -107,19 +86,16 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man, return 0; } -const struct ttm_mem_type_manager_func nouveau_gart_manager = { - .init = nouveau_manager_init, - .takedown = nouveau_manager_fini, - .get_node = nouveau_gart_manager_new, - .put_node = nouveau_manager_del, - .debug = nouveau_manager_debug +const struct ttm_resource_manager_func nouveau_gart_manager = { + .alloc = nouveau_gart_manager_new, + .free = nouveau_manager_del, }; static int -nv04_gart_manager_new(struct ttm_mem_type_manager *man, +nv04_gart_manager_new(struct ttm_resource_manager *man, struct ttm_buffer_object *bo, const struct ttm_place *place, - struct ttm_mem_reg *reg) + struct ttm_resource *reg) { struct nouveau_bo *nvbo = nouveau_bo(bo); struct nouveau_drm *drm = nouveau_bdev(bo->bdev); @@ -142,12 +118,9 @@ nv04_gart_manager_new(struct ttm_mem_type_manager *man, return 0; } -const struct ttm_mem_type_manager_func nv04_gart_manager = { - .init = nouveau_manager_init, - .takedown = nouveau_manager_fini, - .get_node = nv04_gart_manager_new, - .put_node = nouveau_manager_del, - .debug = nouveau_manager_debug +const struct ttm_resource_manager_func nv04_gart_manager = { + .alloc = nv04_gart_manager_new, + .free = nouveau_manager_del, }; int @@ -180,6 +153,113 @@ nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind) return 0; } +static int +nouveau_ttm_init_vram(struct nouveau_drm *drm) +{ + struct nvif_mmu *mmu = &drm->client.mmu; + if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + /* Some BARs do not support being ioremapped WC */ + const u8 type = mmu->type[drm->ttm.type_vram].type; + struct ttm_resource_manager *man = kzalloc(sizeof(*man), GFP_KERNEL); + if (!man) + return -ENOMEM; + + man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + + if (type & NVIF_MEM_UNCACHED) { + man->available_caching = TTM_PL_FLAG_UNCACHED; + man->default_caching = TTM_PL_FLAG_UNCACHED; + } + + man->func = &nouveau_vram_manager; + man->use_io_reserve_lru = true; + + ttm_resource_manager_init(man, + drm->gem.vram_available >> PAGE_SHIFT); + ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man); + ttm_resource_manager_set_used(man, true); + return 0; + } else { + return ttm_range_man_init(&drm->ttm.bdev, TTM_PL_VRAM, + TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC, + TTM_PL_FLAG_WC, false, + drm->gem.vram_available >> PAGE_SHIFT); + } +} + +static void +nouveau_ttm_fini_vram(struct nouveau_drm *drm) +{ + struct ttm_resource_manager *man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM); + + if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + ttm_resource_manager_set_used(man, false); + ttm_resource_manager_force_list_clean(&drm->ttm.bdev, man); + ttm_resource_manager_cleanup(man); + ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, NULL); + kfree(man); + } else + ttm_range_man_fini(&drm->ttm.bdev, TTM_PL_VRAM); +} + +static int +nouveau_ttm_init_gtt(struct nouveau_drm *drm) +{ + struct ttm_resource_manager *man; + unsigned long size_pages = drm->gem.gart_available >> PAGE_SHIFT; + unsigned available_caching, default_caching; + const struct ttm_resource_manager_func *func = NULL; + if (drm->agp.bridge) { + available_caching = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_WC; + default_caching = TTM_PL_FLAG_WC; + } else { + available_caching = TTM_PL_MASK_CACHING; + default_caching = TTM_PL_FLAG_CACHED; + } + + if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) + func = &nouveau_gart_manager; + else if (!drm->agp.bridge) + func = &nv04_gart_manager; + else + return ttm_range_man_init(&drm->ttm.bdev, TTM_PL_TT, + available_caching, default_caching, + true, + size_pages); + + man = kzalloc(sizeof(*man), GFP_KERNEL); + if (!man) + return -ENOMEM; + + man->func = func; + man->available_caching = available_caching; + man->default_caching = default_caching; + man->use_tt = true; + ttm_resource_manager_init(man, size_pages); + ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, man); + ttm_resource_manager_set_used(man, true); + return 0; +} + +static void +nouveau_ttm_fini_gtt(struct nouveau_drm *drm) +{ + struct ttm_resource_manager *man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_TT); + + if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA && + drm->agp.bridge) + ttm_range_man_fini(&drm->ttm.bdev, TTM_PL_TT); + else { + ttm_resource_manager_set_used(man, false); + ttm_resource_manager_force_list_clean(&drm->ttm.bdev, man); + ttm_resource_manager_cleanup(man); + ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, NULL); + kfree(man); + } +} + int nouveau_ttm_init(struct nouveau_drm *drm) { @@ -237,8 +317,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1), device->func->resource_size(device, 1)); - ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM, - drm->gem.vram_available >> PAGE_SHIFT); + ret = nouveau_ttm_init_vram(drm); if (ret) { NV_ERROR(drm, "VRAM mm init failed, %d\n", ret); return ret; @@ -254,8 +333,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) drm->gem.gart_available = drm->agp.size; } - ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_TT, - drm->gem.gart_available >> PAGE_SHIFT); + ret = nouveau_ttm_init_gtt(drm); if (ret) { NV_ERROR(drm, "GART mm init failed, %d\n", ret); return ret; @@ -271,8 +349,8 @@ nouveau_ttm_fini(struct nouveau_drm *drm) { struct nvkm_device *device = nvxx_device(&drm->client.device); - ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM); - ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT); + nouveau_ttm_fini_vram(drm); + nouveau_ttm_fini_gtt(drm); ttm_bo_device_release(&drm->ttm.bdev); diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.h b/drivers/gpu/drm/nouveau/nouveau_ttm.h index 085280754b3e..eaf25461cd91 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.h +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.h @@ -8,9 +8,9 @@ nouveau_bdev(struct ttm_bo_device *bd) return container_of(bd, struct nouveau_drm, ttm.bdev); } -extern const struct ttm_mem_type_manager_func nouveau_vram_manager; -extern const struct ttm_mem_type_manager_func nouveau_gart_manager; -extern const struct ttm_mem_type_manager_func nv04_gart_manager; +extern const struct ttm_resource_manager_func nouveau_vram_manager; +extern const struct ttm_resource_manager_func nouveau_gart_manager; +extern const struct ttm_resource_manager_func nv04_gart_manager; struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, u32 page_flags); diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c index cd1e87a528a4..6b697ee6bc0e 100644 --- a/drivers/gpu/drm/nouveau/nv17_fence.c +++ b/drivers/gpu/drm/nouveau/nv17_fence.c @@ -78,7 +78,7 @@ nv17_fence_context_new(struct nouveau_channel *chan) { struct nv10_fence_priv *priv = chan->drm->fence; struct nv10_fence_chan *fctx; - struct ttm_mem_reg *reg = &priv->bo->bo.mem; + struct ttm_resource *reg = &priv->bo->bo.mem; u32 start = reg->start * PAGE_SIZE; u32 limit = start + reg->size - 1; int ret = 0; diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index ebb740686b44..49b46f51073c 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c @@ -37,7 +37,7 @@ nv50_fence_context_new(struct nouveau_channel *chan) { struct nv10_fence_priv *priv = chan->drm->fence; struct nv10_fence_chan *fctx; - struct ttm_mem_reg *reg = &priv->bo->bo.mem; + struct ttm_resource *reg = &priv->bo->bo.mem; u32 start = reg->start * PAGE_SIZE; u32 limit = start + reg->size - 1; int ret; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 2578c95570f6..a14fbf06cb30 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -20,7 +20,6 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/clk.h> -#include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/component.h> #include <linux/of.h> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 4d4c1fabd0a1..b738d9750686 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -24,7 +24,6 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/clk.h> -#include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/component.h> #include <linux/of.h> diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index bd12eae0cb31..5c027c81760f 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -781,7 +781,7 @@ static int venc_probe_of(struct venc_device *venc) venc->type = OMAP_DSS_VENC_TYPE_SVIDEO; break; default: - dev_err(&venc->pdev->dev, "bad channel propert '%d'\n", + dev_err(&venc->pdev->dev, "bad channel property '%d'\n", channels); r = -EINVAL; goto err; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 4526967978b7..53d5e184ee77 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -349,13 +349,6 @@ static int omap_modeset_init(struct drm_device *dev) drm_connector_attach_encoder(pipe->connector, encoder); - if (pipe->output->panel) { - ret = drm_panel_attach(pipe->output->panel, - pipe->connector); - if (ret < 0) - return ret; - } - crtc = omap_crtc_init(dev, pipe, priv->planes[i]); if (IS_ERR(crtc)) return PTR_ERR(crtc); @@ -394,18 +387,8 @@ static int omap_modeset_init(struct drm_device *dev) static void omap_modeset_fini(struct drm_device *ddev) { - struct omap_drm_private *priv = ddev->dev_private; - unsigned int i; - omap_drm_irq_uninstall(ddev); - for (i = 0; i < priv->num_pipes; i++) { - struct omap_drm_pipeline *pipe = &priv->pipes[i]; - - if (pipe->output->panel) - drm_panel_detach(pipe->output->panel); - } - drm_mode_config_cleanup(ddev); } diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index de2f2a452be5..8d97d07c5871 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -217,6 +217,17 @@ 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 diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index e45ceac6286f..15a4e7752951 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.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 obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) += panel-osd-osd101t2587-53ts.o diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c index 47b37fef7ee8..abb0788843c6 100644 --- a/drivers/gpu/drm/panel/panel-arm-versatile.c +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -349,7 +349,9 @@ static int versatile_panel_probe(struct platform_device *pdev) drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs, DRM_MODE_CONNECTOR_DPI); - return drm_panel_add(&vpanel->panel); + drm_panel_add(&vpanel->panel); + + return 0; } static const struct of_device_id versatile_panel_match[] = { diff --git a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c index 9a5b7644d756..e95bc9f60b3f 100644 --- a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c +++ b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c @@ -315,11 +315,7 @@ static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi) return ret; } - ret = drm_panel_add(&ctx->panel); - if (ret < 0) { - dev_err(dev, "Failed to add panel: %d\n", ret); - return ret; - } + drm_panel_add(&ctx->panel); ret = mipi_dsi_attach(dsi); if (ret < 0) { diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c index 7c27bd5e3486..42854bd37fd5 100644 --- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c +++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c @@ -19,7 +19,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #include <video/mipi_display.h> @@ -93,8 +92,7 @@ static int boe_panel_disable(struct drm_panel *panel) err = mipi_dsi_dcs_set_display_off(pinfo->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - err); + dev_err(panel->dev, "failed to set display off: %d\n", err); return err; } @@ -113,13 +111,11 @@ static int boe_panel_unprepare(struct drm_panel *panel) err = mipi_dsi_dcs_set_display_off(pinfo->link); if (err < 0) - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - err); + dev_err(panel->dev, "failed to set display off: %d\n", err); err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link); if (err < 0) - DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", - err); + dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); /* sleep_mode_delay: 1ms - 2ms */ usleep_range(1000, 2000); @@ -163,15 +159,13 @@ static int boe_panel_prepare(struct drm_panel *panel) /* send init code */ err = send_mipi_cmds(panel, pinfo->desc->on_cmds); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to send DCS Init Code: %d\n", - err); + dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err); goto poweroff; } err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", - err); + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); goto poweroff; } @@ -180,8 +174,7 @@ static int boe_panel_prepare(struct drm_panel *panel) err = mipi_dsi_dcs_set_display_on(pinfo->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", - err); + dev_err(panel->dev, "failed to set display on: %d\n", err); goto poweroff; } @@ -209,8 +202,7 @@ static int boe_panel_enable(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_on(pinfo->link); if (ret < 0) { - DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", - ret); + dev_err(panel->dev, "failed to set display on: %d\n", ret); return ret; } @@ -228,8 +220,8 @@ static int boe_panel_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, m); if (!mode) { - DRM_DEV_ERROR(pinfo->base.dev, "failed to add mode %ux%u@%u\n", - m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); + dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n", + m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); return -ENOMEM; } @@ -865,8 +857,7 @@ static int panel_add(struct panel_info *pinfo) if (IS_ERR(pinfo->pp18_gpio)) { ret = PTR_ERR(pinfo->pp18_gpio); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, "failed to get pp18 gpio: %d\n", - ret); + dev_err(dev, "failed to get pp18 gpio: %d\n", ret); return ret; } @@ -874,8 +865,7 @@ static int panel_add(struct panel_info *pinfo) if (IS_ERR(pinfo->pp33_gpio)) { ret = PTR_ERR(pinfo->pp33_gpio); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, "failed to get pp33 gpio: %d\n", - ret); + dev_err(dev, "failed to get pp33 gpio: %d\n", ret); return ret; } @@ -883,8 +873,7 @@ static int panel_add(struct panel_info *pinfo) if (IS_ERR(pinfo->enable_gpio)) { ret = PTR_ERR(pinfo->enable_gpio); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, "failed to get enable gpio: %d\n", - ret); + dev_err(dev, "failed to get enable gpio: %d\n", ret); return ret; } @@ -895,7 +884,9 @@ static int panel_add(struct panel_info *pinfo) if (ret) return ret; - return drm_panel_add(&pinfo->base); + drm_panel_add(&pinfo->base); + + return 0; } static int panel_probe(struct mipi_dsi_device *dsi) @@ -935,18 +926,15 @@ static int panel_remove(struct mipi_dsi_device *dsi) err = boe_panel_disable(&pinfo->base); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", - err); + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); err = boe_panel_unprepare(&pinfo->base); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", - err); + dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); err = mipi_dsi_detach(dsi); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", - err); + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); drm_panel_remove(&pinfo->base); diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c index e320aa30b9ae..db9d0b86d542 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c @@ -11,6 +11,7 @@ #include <linux/of_device.h> #include <linux/regulator/consumer.h> +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> @@ -43,6 +44,7 @@ struct boe_panel { const struct panel_desc *desc; + enum drm_panel_orientation orientation; struct regulator *pp1800; struct regulator *avee; struct regulator *avdd; @@ -740,6 +742,7 @@ static int boe_panel_get_modes(struct drm_panel *panel, connector->display_info.width_mm = boe->desc->size.width_mm; connector->display_info.height_mm = boe->desc->size.height_mm; connector->display_info.bpc = boe->desc->bpc; + drm_connector_set_panel_orientation(connector, boe->orientation); return 1; } @@ -779,6 +782,11 @@ static int boe_panel_add(struct boe_panel *boe) drm_panel_init(&boe->base, dev, &boe_panel_funcs, DRM_MODE_CONNECTOR_DSI); + err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation); + if (err < 0) { + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); + return err; + } err = drm_panel_of_backlight(&boe->base); if (err) @@ -787,7 +795,9 @@ static int boe_panel_add(struct boe_panel *boe) boe->base.funcs = &boe_panel_funcs; boe->base.dev = &boe->dsi->dev; - return drm_panel_add(&boe->base); + drm_panel_add(&boe->base); + + return 0; } static int boe_panel_probe(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index e9675514d77b..bc36aa3c1123 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -22,7 +22,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> /* Manufacturer specific Commands send via DSI */ #define KD35T133_CMD_INTERFACEMODECTRL 0xb0 @@ -89,7 +88,7 @@ static int kd35t133_init_sequence(struct kd35t133 *ctx) 0xa9, 0x51, 0x2c, 0x82); mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0); - DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n"); + dev_dbg(dev, "Panel init sequence done\n"); return 0; } @@ -104,13 +103,11 @@ static int kd35t133_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) - DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", - ret); + dev_err(ctx->dev, "failed to set display off: %d\n", ret); ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", - ret); + dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); return ret; } @@ -131,18 +128,16 @@ static int kd35t133_prepare(struct drm_panel *panel) if (ctx->prepared) return 0; - DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); + dev_dbg(ctx->dev, "Resetting the panel\n"); ret = regulator_enable(ctx->vdd); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable vdd supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable vdd supply: %d\n", ret); return ret; } ret = regulator_enable(ctx->iovcc); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable iovcc supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); goto disable_vdd; } @@ -156,7 +151,7 @@ static int kd35t133_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); goto disable_iovcc; } @@ -164,14 +159,13 @@ static int kd35t133_prepare(struct drm_panel *panel) ret = kd35t133_init_sequence(ctx); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", - ret); + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); goto disable_iovcc; } ret = mipi_dsi_dcs_set_display_on(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret); + dev_err(ctx->dev, "Failed to set display on: %d\n", ret); goto disable_iovcc; } @@ -210,9 +204,9 @@ static int kd35t133_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); return -ENOMEM; } @@ -244,7 +238,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); + dev_err(dev, "cannot get reset gpio\n"); return PTR_ERR(ctx->reset_gpio); } @@ -252,9 +246,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->vdd)) { ret = PTR_ERR(ctx->vdd); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request vdd regulator: %d\n", - ret); + dev_err(dev, "Failed to request vdd regulator: %d\n", ret); return ret; } @@ -262,9 +254,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->iovcc)) { ret = PTR_ERR(ctx->iovcc); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request iovcc regulator: %d\n", - ret); + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); return ret; } @@ -288,7 +278,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) ret = mipi_dsi_attach(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); drm_panel_remove(&ctx->panel); return ret; } @@ -303,13 +293,11 @@ static void kd35t133_shutdown(struct mipi_dsi_device *dsi) ret = drm_panel_unprepare(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); ret = drm_panel_disable(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } static int kd35t133_remove(struct mipi_dsi_device *dsi) @@ -321,8 +309,7 @@ static int kd35t133_remove(struct mipi_dsi_device *dsi) ret = mipi_dsi_detach(dsi); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", - ret); + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c index 54610651ecdb..2a602aee61c3 100644 --- a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c +++ b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c @@ -13,7 +13,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define K101_IM2BA02_INIT_CMD_LEN 2 @@ -374,13 +373,11 @@ static int k101_im2ba02_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(ctx->dsi); if (ret < 0) - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - ret); + dev_err(panel->dev, "failed to set display off: %d\n", ret); ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); if (ret < 0) - DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", - ret); + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); msleep(200); @@ -416,10 +413,10 @@ static int k101_im2ba02_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &k101_im2ba02_default_mode); if (!mode) { - DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", - k101_im2ba02_default_mode.hdisplay, - k101_im2ba02_default_mode.vdisplay, - drm_mode_vrefresh(&k101_im2ba02_default_mode)); + dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n", + k101_im2ba02_default_mode.hdisplay, + k101_im2ba02_default_mode.vdisplay, + drm_mode_vrefresh(&k101_im2ba02_default_mode)); return -ENOMEM; } @@ -460,13 +457,13 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi) ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get regulators\n"); + dev_err(&dsi->dev, "Couldn't get regulators\n"); return ret; } ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n"); + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); return PTR_ERR(ctx->reset); } @@ -477,9 +474,7 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - ret = drm_panel_add(&ctx->panel); - if (ret < 0) - return ret; + drm_panel_add(&ctx->panel); dsi->mode_flags = MIPI_DSI_MODE_VIDEO; dsi->format = MIPI_DSI_FMT_RGB888; diff --git a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c index 19a6274b10f5..581661b506f8 100644 --- a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c +++ b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c @@ -7,7 +7,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #include <linux/gpio/consumer.h> #include <linux/delay.h> @@ -118,13 +117,11 @@ static int feiyang_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(ctx->dsi); if (ret < 0) - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - ret); + dev_err(panel->dev, "failed to set display off: %d\n", ret); ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); if (ret < 0) - DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", - ret); + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); /* T13 (backlight fall + video & logic signal fall) T13 >= 200ms */ msleep(200); @@ -165,10 +162,10 @@ static int feiyang_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &feiyang_default_mode); if (!mode) { - DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", - feiyang_default_mode.hdisplay, - feiyang_default_mode.vdisplay, - drm_mode_vrefresh(&feiyang_default_mode)); + dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n", + feiyang_default_mode.hdisplay, + feiyang_default_mode.vdisplay, + drm_mode_vrefresh(&feiyang_default_mode)); return -ENOMEM; } @@ -204,19 +201,19 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi) ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd"); if (IS_ERR(ctx->dvdd)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get dvdd regulator\n"); + dev_err(&dsi->dev, "Couldn't get dvdd regulator\n"); return PTR_ERR(ctx->dvdd); } ctx->avdd = devm_regulator_get(&dsi->dev, "avdd"); if (IS_ERR(ctx->avdd)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get avdd regulator\n"); + dev_err(&dsi->dev, "Couldn't get avdd regulator\n"); return PTR_ERR(ctx->avdd); } ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n"); + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); return PTR_ERR(ctx->reset); } @@ -224,9 +221,7 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - ret = drm_panel_add(&ctx->panel); - if (ret < 0) - return ret; + drm_panel_add(&ctx->panel); dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST; dsi->format = MIPI_DSI_FMT_RGB888; diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 67a64d1999f6..074e18559b9f 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -33,7 +33,6 @@ #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define ILI9322_CHIP_ID 0x00 #define ILI9322_CHIP_ID_MAGIC 0x96 @@ -683,7 +682,7 @@ static int ili9322_get_modes(struct drm_panel *panel, break; } if (!mode) { - DRM_ERROR("bad mode or failed to add mode\n"); + dev_err(panel->dev, "bad mode or failed to add mode\n"); return -EINVAL; } drm_mode_set_name(mode); @@ -892,7 +891,9 @@ static int ili9322_probe(struct spi_device *spi) drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs, DRM_MODE_CONNECTOR_DPI); - return drm_panel_add(&ili->panel); + drm_panel_add(&ili->panel); + + return 0; } static int ili9322_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 3ed8635a6fbd..0145129d7c66 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -10,6 +10,7 @@ #include <linux/fb.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> @@ -20,14 +21,6 @@ #include <video/mipi_display.h> -struct ili9881c { - struct drm_panel panel; - struct mipi_dsi_device *dsi; - - struct regulator *power; - struct gpio_desc *reset; -}; - enum ili9881c_op { ILI9881C_SWITCH_PAGE, ILI9881C_COMMAND, @@ -45,6 +38,21 @@ struct ili9881c_instr { } arg; }; +struct ili9881c_desc { + const struct ili9881c_instr *init; + const size_t init_length; + const struct drm_display_mode *mode; +}; + +struct ili9881c { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + const struct ili9881c_desc *desc; + + struct regulator *power; + struct gpio_desc *reset; +}; + #define ILI9881C_SWITCH_PAGE_INSTR(_page) \ { \ .op = ILI9881C_SWITCH_PAGE, \ @@ -64,7 +72,7 @@ struct ili9881c_instr { }, \ } -static const struct ili9881c_instr ili9881c_init[] = { +static const struct ili9881c_instr lhr050h41_init[] = { ILI9881C_SWITCH_PAGE_INSTR(3), ILI9881C_COMMAND_INSTR(0x01, 0x00), ILI9881C_COMMAND_INSTR(0x02, 0x00), @@ -252,6 +260,199 @@ static const struct ili9881c_instr ili9881c_init[] = { ILI9881C_COMMAND_INSTR(0xD3, 0x3F), }; +static const struct ili9881c_instr k101_im2byl02_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0x00), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x08), + ILI9881C_COMMAND_INSTR(0x07, 0x00), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x00), + ILI9881C_COMMAND_INSTR(0x0A, 0x01), + ILI9881C_COMMAND_INSTR(0x0B, 0x01), + ILI9881C_COMMAND_INSTR(0x0C, 0x00), + ILI9881C_COMMAND_INSTR(0x0D, 0x01), + ILI9881C_COMMAND_INSTR(0x0E, 0x01), + ILI9881C_COMMAND_INSTR(0x0F, 0x00), + ILI9881C_COMMAND_INSTR(0x10, 0x00), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1A, 0x00), + ILI9881C_COMMAND_INSTR(0x1B, 0x00), + ILI9881C_COMMAND_INSTR(0x1C, 0x00), + ILI9881C_COMMAND_INSTR(0x1D, 0x00), + ILI9881C_COMMAND_INSTR(0x1E, 0x40), + ILI9881C_COMMAND_INSTR(0x1F, 0xC0), + ILI9881C_COMMAND_INSTR(0x20, 0x06), + ILI9881C_COMMAND_INSTR(0x21, 0x01), + ILI9881C_COMMAND_INSTR(0x22, 0x06), + ILI9881C_COMMAND_INSTR(0x23, 0x01), + ILI9881C_COMMAND_INSTR(0x24, 0x88), + ILI9881C_COMMAND_INSTR(0x25, 0x88), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x3B), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2A, 0x00), + ILI9881C_COMMAND_INSTR(0x2B, 0x00), + ILI9881C_COMMAND_INSTR(0x2C, 0x00), + ILI9881C_COMMAND_INSTR(0x2D, 0x00), + ILI9881C_COMMAND_INSTR(0x2E, 0x00), + ILI9881C_COMMAND_INSTR(0x2F, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x00), /* GPWR1/2 non overlap time 2.62us */ + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x00), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3A, 0x00), + ILI9881C_COMMAND_INSTR(0x3B, 0x00), + ILI9881C_COMMAND_INSTR(0x3C, 0x00), + ILI9881C_COMMAND_INSTR(0x3D, 0x00), + ILI9881C_COMMAND_INSTR(0x3E, 0x00), + ILI9881C_COMMAND_INSTR(0x3F, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x50, 0x01), + ILI9881C_COMMAND_INSTR(0x51, 0x23), + ILI9881C_COMMAND_INSTR(0x52, 0x45), + ILI9881C_COMMAND_INSTR(0x53, 0x67), + ILI9881C_COMMAND_INSTR(0x54, 0x89), + ILI9881C_COMMAND_INSTR(0x55, 0xAB), + ILI9881C_COMMAND_INSTR(0x56, 0x01), + ILI9881C_COMMAND_INSTR(0x57, 0x23), + ILI9881C_COMMAND_INSTR(0x58, 0x45), + ILI9881C_COMMAND_INSTR(0x59, 0x67), + ILI9881C_COMMAND_INSTR(0x5A, 0x89), + ILI9881C_COMMAND_INSTR(0x5B, 0xAB), + ILI9881C_COMMAND_INSTR(0x5C, 0xCD), + ILI9881C_COMMAND_INSTR(0x5D, 0xEF), + ILI9881C_COMMAND_INSTR(0x5E, 0x00), + ILI9881C_COMMAND_INSTR(0x5F, 0x01), + ILI9881C_COMMAND_INSTR(0x60, 0x01), + ILI9881C_COMMAND_INSTR(0x61, 0x06), + ILI9881C_COMMAND_INSTR(0x62, 0x06), + ILI9881C_COMMAND_INSTR(0x63, 0x07), + ILI9881C_COMMAND_INSTR(0x64, 0x07), + ILI9881C_COMMAND_INSTR(0x65, 0x00), + ILI9881C_COMMAND_INSTR(0x66, 0x00), + ILI9881C_COMMAND_INSTR(0x67, 0x02), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x05), + ILI9881C_COMMAND_INSTR(0x6A, 0x05), + ILI9881C_COMMAND_INSTR(0x6B, 0x02), + ILI9881C_COMMAND_INSTR(0x6C, 0x0D), + ILI9881C_COMMAND_INSTR(0x6D, 0x0D), + ILI9881C_COMMAND_INSTR(0x6E, 0x0C), + ILI9881C_COMMAND_INSTR(0x6F, 0x0C), + ILI9881C_COMMAND_INSTR(0x70, 0x0F), + ILI9881C_COMMAND_INSTR(0x71, 0x0F), + ILI9881C_COMMAND_INSTR(0x72, 0x0E), + ILI9881C_COMMAND_INSTR(0x73, 0x0E), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x01), + ILI9881C_COMMAND_INSTR(0x76, 0x01), + ILI9881C_COMMAND_INSTR(0x77, 0x06), + ILI9881C_COMMAND_INSTR(0x78, 0x06), + ILI9881C_COMMAND_INSTR(0x79, 0x07), + ILI9881C_COMMAND_INSTR(0x7A, 0x07), + ILI9881C_COMMAND_INSTR(0x7B, 0x00), + ILI9881C_COMMAND_INSTR(0x7C, 0x00), + ILI9881C_COMMAND_INSTR(0x7D, 0x02), + ILI9881C_COMMAND_INSTR(0x7E, 0x02), + ILI9881C_COMMAND_INSTR(0x7F, 0x05), + ILI9881C_COMMAND_INSTR(0x80, 0x05), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x0D), + ILI9881C_COMMAND_INSTR(0x83, 0x0D), + ILI9881C_COMMAND_INSTR(0x84, 0x0C), + ILI9881C_COMMAND_INSTR(0x85, 0x0C), + ILI9881C_COMMAND_INSTR(0x86, 0x0F), + ILI9881C_COMMAND_INSTR(0x87, 0x0F), + ILI9881C_COMMAND_INSTR(0x88, 0x0E), + ILI9881C_COMMAND_INSTR(0x89, 0x0E), + ILI9881C_COMMAND_INSTR(0x8A, 0x02), + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x3B, 0xC0), /* ILI4003D sel */ + ILI9881C_COMMAND_INSTR(0x6C, 0x15), /* Set VCORE voltage = 1.5V */ + ILI9881C_COMMAND_INSTR(0x6E, 0x2A), /* di_pwr_reg=0 for power mode 2A, VGH clamp 18V */ + ILI9881C_COMMAND_INSTR(0x6F, 0x33), /* pumping ratio VGH=5x VGL=-3x */ + ILI9881C_COMMAND_INSTR(0x8D, 0x1B), /* VGL clamp -10V */ + ILI9881C_COMMAND_INSTR(0x87, 0xBA), /* ESD */ + ILI9881C_COMMAND_INSTR(0x3A, 0x24), /* POWER SAVING */ + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xB2, 0xD1), + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0A), /* BGR, SS */ + ILI9881C_COMMAND_INSTR(0x31, 0x00), /* Zigzag type3 inversion */ + ILI9881C_COMMAND_INSTR(0x40, 0x53), /* ILI4003D sel */ + ILI9881C_COMMAND_INSTR(0x43, 0x66), + ILI9881C_COMMAND_INSTR(0x53, 0x4C), + ILI9881C_COMMAND_INSTR(0x50, 0x87), + ILI9881C_COMMAND_INSTR(0x51, 0x82), + ILI9881C_COMMAND_INSTR(0x60, 0x15), + ILI9881C_COMMAND_INSTR(0x61, 0x01), + ILI9881C_COMMAND_INSTR(0x62, 0x0C), + ILI9881C_COMMAND_INSTR(0x63, 0x00), + ILI9881C_COMMAND_INSTR(0xA0, 0x00), + ILI9881C_COMMAND_INSTR(0xA1, 0x13), /* VP251 */ + ILI9881C_COMMAND_INSTR(0xA2, 0x23), /* VP247 */ + ILI9881C_COMMAND_INSTR(0xA3, 0x14), /* VP243 */ + ILI9881C_COMMAND_INSTR(0xA4, 0x16), /* VP239 */ + ILI9881C_COMMAND_INSTR(0xA5, 0x29), /* VP231 */ + ILI9881C_COMMAND_INSTR(0xA6, 0x1E), /* VP219 */ + ILI9881C_COMMAND_INSTR(0xA7, 0x1D), /* VP203 */ + ILI9881C_COMMAND_INSTR(0xA8, 0x86), /* VP175 */ + ILI9881C_COMMAND_INSTR(0xA9, 0x1E), /* VP144 */ + ILI9881C_COMMAND_INSTR(0xAA, 0x29), /* VP111 */ + ILI9881C_COMMAND_INSTR(0xAB, 0x74), /* VP80 */ + ILI9881C_COMMAND_INSTR(0xAC, 0x19), /* VP52 */ + ILI9881C_COMMAND_INSTR(0xAD, 0x17), /* VP36 */ + ILI9881C_COMMAND_INSTR(0xAE, 0x4B), /* VP24 */ + ILI9881C_COMMAND_INSTR(0xAF, 0x20), /* VP16 */ + ILI9881C_COMMAND_INSTR(0xB0, 0x26), /* VP12 */ + ILI9881C_COMMAND_INSTR(0xB1, 0x4C), /* VP8 */ + ILI9881C_COMMAND_INSTR(0xB2, 0x5D), /* VP4 */ + ILI9881C_COMMAND_INSTR(0xB3, 0x3F), /* VP0 */ + ILI9881C_COMMAND_INSTR(0xC0, 0x00), /* VN255 GAMMA N */ + ILI9881C_COMMAND_INSTR(0xC1, 0x13), /* VN251 */ + ILI9881C_COMMAND_INSTR(0xC2, 0x23), /* VN247 */ + ILI9881C_COMMAND_INSTR(0xC3, 0x14), /* VN243 */ + ILI9881C_COMMAND_INSTR(0xC4, 0x16), /* VN239 */ + ILI9881C_COMMAND_INSTR(0xC5, 0x29), /* VN231 */ + ILI9881C_COMMAND_INSTR(0xC6, 0x1E), /* VN219 */ + ILI9881C_COMMAND_INSTR(0xC7, 0x1D), /* VN203 */ + ILI9881C_COMMAND_INSTR(0xC8, 0x86), /* VN175 */ + ILI9881C_COMMAND_INSTR(0xC9, 0x1E), /* VN144 */ + ILI9881C_COMMAND_INSTR(0xCA, 0x29), /* VN111 */ + ILI9881C_COMMAND_INSTR(0xCB, 0x74), /* VN80 */ + ILI9881C_COMMAND_INSTR(0xCC, 0x19), /* VN52 */ + ILI9881C_COMMAND_INSTR(0xCD, 0x17), /* VN36 */ + ILI9881C_COMMAND_INSTR(0xCE, 0x4B), /* VN24 */ + ILI9881C_COMMAND_INSTR(0xCF, 0x20), /* VN16 */ + ILI9881C_COMMAND_INSTR(0xD0, 0x26), /* VN12 */ + ILI9881C_COMMAND_INSTR(0xD1, 0x4C), /* VN8 */ + ILI9881C_COMMAND_INSTR(0xD2, 0x5D), /* VN4 */ + ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ +}; + static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) { return container_of(panel, struct ili9881c, panel); @@ -311,8 +512,8 @@ static int ili9881c_prepare(struct drm_panel *panel) gpiod_set_value(ctx->reset, 0); msleep(20); - for (i = 0; i < ARRAY_SIZE(ili9881c_init); i++) { - const struct ili9881c_instr *instr = &ili9881c_init[i]; + for (i = 0; i < ctx->desc->init_length; i++) { + const struct ili9881c_instr *instr = &ctx->desc->init[i]; if (instr->op == ILI9881C_SWITCH_PAGE) ret = ili9881c_switch_page(ctx, instr->arg.page); @@ -368,7 +569,7 @@ static int ili9881c_unprepare(struct drm_panel *panel) return 0; } -static const struct drm_display_mode bananapi_default_mode = { +static const struct drm_display_mode lhr050h41_default_mode = { .clock = 62000, .hdisplay = 720, @@ -380,6 +581,26 @@ static const struct drm_display_mode bananapi_default_mode = { .vsync_start = 1280 + 10, .vsync_end = 1280 + 10 + 10, .vtotal = 1280 + 10 + 10 + 20, + + .width_mm = 62, + .height_mm = 110, +}; + +static const struct drm_display_mode k101_im2byl02_default_mode = { + .clock = 69700, + + .hdisplay = 800, + .hsync_start = 800 + 6, + .hsync_end = 800 + 6 + 15, + .htotal = 800 + 6 + 15 + 16, + + .vdisplay = 1280, + .vsync_start = 1280 + 8, + .vsync_end = 1280 + 8 + 48, + .vtotal = 1280 + 8 + 48 + 52, + + .width_mm = 135, + .height_mm = 217, }; static int ili9881c_get_modes(struct drm_panel *panel, @@ -388,12 +609,12 @@ static int ili9881c_get_modes(struct drm_panel *panel, struct ili9881c *ctx = panel_to_ili9881c(panel); struct drm_display_mode *mode; - mode = drm_mode_duplicate(connector->dev, &bananapi_default_mode); + mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); if (!mode) { dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", - bananapi_default_mode.hdisplay, - bananapi_default_mode.vdisplay, - drm_mode_vrefresh(&bananapi_default_mode)); + ctx->desc->mode->hdisplay, + ctx->desc->mode->vdisplay, + drm_mode_vrefresh(ctx->desc->mode)); return -ENOMEM; } @@ -402,8 +623,8 @@ static int ili9881c_get_modes(struct drm_panel *panel, mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode); - connector->display_info.width_mm = 62; - connector->display_info.height_mm = 110; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; return 1; } @@ -426,6 +647,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) return -ENOMEM; mipi_dsi_set_drvdata(dsi, ctx); ctx->dsi = dsi; + ctx->desc = of_device_get_match_data(&dsi->dev); drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs, DRM_MODE_CONNECTOR_DSI); @@ -446,9 +668,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - ret = drm_panel_add(&ctx->panel); - if (ret < 0) - return ret; + drm_panel_add(&ctx->panel); dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE; dsi->format = MIPI_DSI_FMT_RGB888; @@ -467,8 +687,21 @@ static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi) return 0; } +static const struct ili9881c_desc lhr050h41_desc = { + .init = lhr050h41_init, + .init_length = ARRAY_SIZE(lhr050h41_init), + .mode = &lhr050h41_default_mode, +}; + +static const struct ili9881c_desc k101_im2byl02_desc = { + .init = k101_im2byl02_init, + .init_length = ARRAY_SIZE(k101_im2byl02_init), + .mode = &k101_im2byl02_default_mode, +}; + static const struct of_device_id ili9881c_of_match[] = { - { .compatible = "bananapi,lhr050h41" }, + { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, + { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, { } }; MODULE_DEVICE_TABLE(of, ili9881c_of_match); diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index fdf030f4cf92..aea316225391 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -17,7 +17,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> struct panel_init_cmd { size_t len; @@ -85,13 +84,11 @@ static int innolux_panel_unprepare(struct drm_panel *panel) err = mipi_dsi_dcs_set_display_off(innolux->link); if (err < 0) - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - err); + dev_err(panel->dev, "failed to set display off: %d\n", err); err = mipi_dsi_dcs_enter_sleep_mode(innolux->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", - err); + dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); return err; } @@ -147,8 +144,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) err = mipi_dsi_generic_write(innolux->link, cmd->data, cmd->len); if (err < 0) { - dev_err(panel->dev, - "failed to write command %u\n", i); + dev_err(panel->dev, "failed to write command %u\n", i); goto poweroff; } @@ -159,8 +155,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) */ err = mipi_dsi_dcs_nop(innolux->link); if (err < 0) { - dev_err(panel->dev, - "failed to send DCS nop: %d\n", err); + dev_err(panel->dev, "failed to send DCS nop: %d\n", err); goto poweroff; } } @@ -168,8 +163,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) err = mipi_dsi_dcs_exit_sleep_mode(innolux->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", - err); + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); goto poweroff; } @@ -178,8 +172,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) err = mipi_dsi_dcs_set_display_on(innolux->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", - err); + dev_err(panel->dev, "failed to set display on: %d\n", err); goto poweroff; } @@ -398,8 +391,8 @@ static int innolux_panel_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, m); if (!mode) { - DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", - m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", + m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); return -ENOMEM; } @@ -475,9 +468,7 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi, if (err) return err; - err = drm_panel_add(&innolux->base); - if (err < 0) - return err; + drm_panel_add(&innolux->base); mipi_dsi_set_drvdata(dsi, innolux); innolux->link = dsi; @@ -514,17 +505,15 @@ static int innolux_panel_remove(struct mipi_dsi_device *dsi) err = drm_panel_unprepare(&innolux->base); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", - err); + dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); err = drm_panel_disable(&innolux->base); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err); + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); err = mipi_dsi_detach(dsi); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", - err); + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); innolux_panel_del(innolux); diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c index 1e3fd6633981..733010b5e4f5 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -440,9 +440,9 @@ static int jdi_panel_add(struct jdi_panel *jdi) drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_add(&jdi->base); + drm_panel_add(&jdi->base); - return ret; + return 0; } static void jdi_panel_del(struct jdi_panel *jdi) diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c index 0d397af23afe..86e4213e8bb1 100644 --- a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c @@ -16,7 +16,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> struct kingdisplay_panel { struct drm_panel base; @@ -191,8 +190,7 @@ static int kingdisplay_panel_disable(struct drm_panel *panel) err = mipi_dsi_dcs_set_display_off(kingdisplay->link); if (err < 0) - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - err); + dev_err(panel->dev, "failed to set display off: %d\n", err); kingdisplay->enabled = false; @@ -209,8 +207,7 @@ static int kingdisplay_panel_unprepare(struct drm_panel *panel) err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", - err); + dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); return err; } @@ -255,16 +252,14 @@ static int kingdisplay_panel_prepare(struct drm_panel *panel) err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i], sizeof(struct kingdisplay_panel_cmd)); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed write init cmds: %d\n", - err); + dev_err(panel->dev, "failed write init cmds: %d\n", err); goto poweroff; } } err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", - err); + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); goto poweroff; } @@ -273,8 +268,7 @@ static int kingdisplay_panel_prepare(struct drm_panel *panel) err = mipi_dsi_dcs_set_display_on(kingdisplay->link); if (err < 0) { - DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", - err); + dev_err(panel->dev, "failed to set display on: %d\n", err); goto poweroff; } @@ -290,8 +284,7 @@ poweroff: regulator_err = regulator_disable(kingdisplay->supply); if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); + dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err); return err; } @@ -327,9 +320,9 @@ static int kingdisplay_panel_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); return -ENOMEM; } @@ -382,7 +375,9 @@ static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay) if (err) return err; - return drm_panel_add(&kingdisplay->base); + drm_panel_add(&kingdisplay->base); + + return 0; } static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay) @@ -421,17 +416,15 @@ static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi) err = drm_panel_unprepare(&kingdisplay->base); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", - err); + dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); err = drm_panel_disable(&kingdisplay->base); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err); + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); err = mipi_dsi_detach(dsi); if (err < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", - err); + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); kingdisplay_panel_del(kingdisplay); diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index eaa9da3ebbea..ed0d5f959037 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -17,7 +17,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> struct ltk050h3146w_cmd { char cmd; @@ -314,8 +313,7 @@ static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) ret = mipi_dsi_dcs_set_tear_on(dsi, 1); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n", - ret); + dev_err(ctx->dev, "failed to set tear on: %d\n", ret); return ret; } @@ -360,8 +358,7 @@ static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page, ret = ltk050h3146w_a2_select_page(ctx, page); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "failed to select page %d: %d\n", - page, ret); + dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret); return ret; } @@ -369,9 +366,7 @@ static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page, ret = mipi_dsi_generic_write(dsi, &cmds[i], sizeof(struct ltk050h3146w_cmd)); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "failed to write page %d init cmds: %d\n", - page, ret); + dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret); return ret; } } @@ -405,15 +400,14 @@ static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx) ret = ltk050h3146w_a2_select_page(ctx, 0); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "failed to select page 0: %d\n", ret); + dev_err(ctx->dev, "failed to select page 0: %d\n", ret); return ret; } /* vendor code called this without param, where there should be one */ ret = mipi_dsi_dcs_set_tear_on(dsi, 0); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n", - ret); + dev_err(ctx->dev, "failed to set tear on: %d\n", ret); return ret; } @@ -452,15 +446,13 @@ static int ltk050h3146w_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", - ret); + dev_err(ctx->dev, "failed to set display off: %d\n", ret); return ret; } mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", - ret); + dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); return ret; } @@ -481,17 +473,15 @@ static int ltk050h3146w_prepare(struct drm_panel *panel) if (ctx->prepared) return 0; - DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); + dev_dbg(ctx->dev, "Resetting the panel\n"); ret = regulator_enable(ctx->vci); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable vci supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); return ret; } ret = regulator_enable(ctx->iovcc); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable iovcc supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); goto disable_vci; } @@ -502,14 +492,13 @@ static int ltk050h3146w_prepare(struct drm_panel *panel) ret = ctx->panel_desc->init(ctx); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", - ret); + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); goto disable_iovcc; } ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); goto disable_iovcc; } @@ -518,7 +507,7 @@ static int ltk050h3146w_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_on(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret); + dev_err(ctx->dev, "Failed to set display on: %d\n", ret); goto disable_iovcc; } @@ -577,7 +566,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); + dev_err(dev, "cannot get reset gpio\n"); return PTR_ERR(ctx->reset_gpio); } @@ -585,9 +574,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->vci)) { ret = PTR_ERR(ctx->vci); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request vci regulator: %d\n", - ret); + dev_err(dev, "Failed to request vci regulator: %d\n", ret); return ret; } @@ -595,9 +582,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->iovcc)) { ret = PTR_ERR(ctx->iovcc); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request iovcc regulator: %d\n", - ret); + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); return ret; } @@ -621,7 +606,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) ret = mipi_dsi_attach(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); drm_panel_remove(&ctx->panel); return ret; } @@ -636,13 +621,11 @@ static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi) ret = drm_panel_unprepare(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); ret = drm_panel_disable(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } static int ltk050h3146w_remove(struct mipi_dsi_device *dsi) @@ -654,8 +637,7 @@ static int ltk050h3146w_remove(struct mipi_dsi_device *dsi) ret = mipi_dsi_detach(dsi); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", - ret); + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c index 0f6a248c47a5..3c00e4f8f803 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c @@ -20,7 +20,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> struct ltk500hd1829 { struct device *dev; @@ -278,13 +277,11 @@ static int ltk500hd1829_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) - DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", - ret); + dev_err(panel->dev, "failed to set display off: %d\n", ret); ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", - ret); + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); } /* 120ms to enter sleep mode */ @@ -310,14 +307,12 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) ret = regulator_enable(ctx->vcc); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable vci supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); return ret; } ret = regulator_enable(ctx->iovcc); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable iovcc supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); goto disable_vcc; } @@ -333,16 +328,14 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) ret = mipi_dsi_generic_write(dsi, &init_code[i], sizeof(struct ltk500hd1829_cmd)); if (ret < 0) { - DRM_DEV_ERROR(panel->dev, - "failed to write init cmds: %d\n", ret); + dev_err(panel->dev, "failed to write init cmds: %d\n", ret); goto disable_iovcc; } } ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", - ret); + dev_err(panel->dev, "failed to exit sleep mode: %d\n", ret); goto disable_iovcc; } @@ -351,8 +344,7 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_on(dsi); if (ret < 0) { - DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", - ret); + dev_err(panel->dev, "failed to set display on: %d\n", ret); goto disable_iovcc; } @@ -389,9 +381,9 @@ static int ltk500hd1829_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_DEV_ERROR(ctx->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + dev_err(ctx->dev, "failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); return -ENOMEM; } @@ -423,7 +415,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); + dev_err(dev, "cannot get reset gpio\n"); return PTR_ERR(ctx->reset_gpio); } @@ -431,9 +423,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->vcc)) { ret = PTR_ERR(ctx->vcc); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request vcc regulator: %d\n", - ret); + dev_err(dev, "Failed to request vcc regulator: %d\n", ret); return ret; } @@ -441,9 +431,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->iovcc)) { ret = PTR_ERR(ctx->iovcc); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request iovcc regulator: %d\n", - ret); + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); return ret; } @@ -467,7 +455,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) ret = mipi_dsi_attach(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); drm_panel_remove(&ctx->panel); return ret; } @@ -482,13 +470,11 @@ static void ltk500hd1829_shutdown(struct mipi_dsi_device *dsi) ret = drm_panel_unprepare(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); ret = drm_panel_disable(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } static int ltk500hd1829_remove(struct mipi_dsi_device *dsi) @@ -500,8 +486,7 @@ static int ltk500hd1829_remove(struct mipi_dsi_device *dsi) ret = mipi_dsi_detach(dsi); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", - ret); + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-lg-lb035q02.c b/drivers/gpu/drm/panel/panel-lg-lb035q02.c index 14456b9cd5c0..f3183b68704f 100644 --- a/drivers/gpu/drm/panel/panel-lg-lb035q02.c +++ b/drivers/gpu/drm/panel/panel-lg-lb035q02.c @@ -198,7 +198,9 @@ static int lb035q02_probe(struct spi_device *spi) drm_panel_init(&lcd->panel, &lcd->spi->dev, &lb035q02_funcs, DRM_MODE_CONNECTOR_DPI); - return drm_panel_add(&lcd->panel); + drm_panel_add(&lcd->panel); + + return 0; } static int lb035q02_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c index aedc485d0727..8e5160af1de5 100644 --- a/drivers/gpu/drm/panel/panel-lg-lg4573.c +++ b/drivers/gpu/drm/panel/panel-lg-lg4573.c @@ -261,7 +261,9 @@ static int lg4573_probe(struct spi_device *spi) drm_panel_init(&ctx->panel, &spi->dev, &lg4573_drm_funcs, DRM_MODE_CONNECTOR_DPI); - return drm_panel_add(&ctx->panel); + drm_panel_add(&ctx->panel); + + return 0; } static int lg4573_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c index 5ce3f4a2b7a1..66c7d765b8f7 100644 --- a/drivers/gpu/drm/panel/panel-lvds.c +++ b/drivers/gpu/drm/panel/panel-lvds.c @@ -37,6 +37,8 @@ struct panel_lvds { struct gpio_desc *enable_gpio; struct gpio_desc *reset_gpio; + + enum drm_panel_orientation orientation; }; static inline struct panel_lvds *to_panel_lvds(struct drm_panel *panel) @@ -99,6 +101,7 @@ static int panel_lvds_get_modes(struct drm_panel *panel, connector->display_info.bus_flags = lvds->data_mirror ? DRM_BUS_FLAG_DATA_LSB_TO_MSB : DRM_BUS_FLAG_DATA_MSB_TO_LSB; + drm_connector_set_panel_orientation(connector, lvds->orientation); return 1; } @@ -116,6 +119,12 @@ static int panel_lvds_parse_dt(struct panel_lvds *lvds) const char *mapping; int ret; + ret = of_drm_get_panel_orientation(np, &lvds->orientation); + if (ret < 0) { + dev_err(lvds->dev, "%pOF: failed to get orientation %d\n", np, ret); + return ret; + } + ret = of_get_display_timing(np, "panel-timing", &timing); if (ret < 0) { dev_err(lvds->dev, "%pOF: problems parsing panel-timing (%d)\n", @@ -227,9 +236,7 @@ static int panel_lvds_probe(struct platform_device *pdev) if (ret) return ret; - ret = drm_panel_add(&lvds->panel); - if (ret < 0) - return ret; + drm_panel_add(&lvds->panel); dev_set_drvdata(lvds->dev, lvds); return 0; diff --git a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c new file mode 100644 index 000000000000..3482e28e30fc --- /dev/null +++ b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Mantix MLAF057WE51 5.7" MIPI-DSI panel driver + * + * Copyright (C) Purism SPC 2020 + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#define DRV_NAME "panel-mantix-mlaf057we51" + +/* Manufacturer specific Commands send via DSI */ +#define MANTIX_CMD_OTP_STOP_RELOAD_MIPI 0x41 +#define MANTIX_CMD_INT_CANCEL 0x4C + +struct mantix { + struct device *dev; + struct drm_panel panel; + struct gpio_desc *reset_gpio; + + struct regulator *avdd; + struct regulator *avee; + struct regulator *vddi; +}; + +static inline struct mantix *panel_to_mantix(struct drm_panel *panel) +{ + return container_of(panel, struct mantix, panel); +} + +#define dsi_generic_write_seq(dsi, seq...) do { \ + static const u8 d[] = { seq }; \ + int ret; \ + ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \ + if (ret < 0) \ + return ret; \ + } while (0) + +static int mantix_init_sequence(struct mantix *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + struct device *dev = ctx->dev; + + /* + * Init sequence was supplied by the panel vendor. + */ + dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A); + + dsi_generic_write_seq(dsi, MANTIX_CMD_INT_CANCEL, 0x03); + dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x03); + dsi_generic_write_seq(dsi, 0x80, 0xA9, 0x00); + + dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x09); + dsi_generic_write_seq(dsi, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00); + msleep(20); + + dev_dbg(dev, "Panel init sequence done\n"); + return 0; +} + +static int mantix_enable(struct drm_panel *panel) +{ + struct mantix *ctx = panel_to_mantix(panel); + struct device *dev = ctx->dev; + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + int ret; + + ret = mantix_init_sequence(ctx); + if (ret < 0) { + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); + return ret; + } + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode\n"); + return ret; + } + msleep(20); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret) + return ret; + usleep_range(10000, 12000); + + ret = mipi_dsi_turn_on_peripheral(dsi); + if (ret < 0) { + dev_err(dev, "Failed to turn on peripheral\n"); + return ret; + } + + return 0; +} + +static int mantix_disable(struct drm_panel *panel) +{ + struct mantix *ctx = panel_to_mantix(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) + dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) + dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret); + + + return 0; +} + +static int mantix_unprepare(struct drm_panel *panel) +{ + struct mantix *ctx = panel_to_mantix(panel); + + regulator_disable(ctx->avee); + regulator_disable(ctx->avdd); + /* T11 */ + usleep_range(5000, 6000); + regulator_disable(ctx->vddi); + /* T14 */ + msleep(50); + + return 0; +} + +static int mantix_prepare(struct drm_panel *panel) +{ + struct mantix *ctx = panel_to_mantix(panel); + int ret; + + /* Focaltech FT8006P, section 7.3.1 and 7.3.4 */ + dev_dbg(ctx->dev, "Resetting the panel\n"); + ret = regulator_enable(ctx->vddi); + if (ret < 0) { + dev_err(ctx->dev, "Failed to enable vddi supply: %d\n", ret); + return ret; + } + + /* T1 + T2 */ + usleep_range(8000, 10000); + + ret = regulator_enable(ctx->avdd); + if (ret < 0) { + dev_err(ctx->dev, "Failed to enable avdd supply: %d\n", ret); + return ret; + } + + /* T2d */ + usleep_range(3500, 4000); + ret = regulator_enable(ctx->avee); + if (ret < 0) { + dev_err(ctx->dev, "Failed to enable avee supply: %d\n", ret); + return ret; + } + + /* T3+T5 */ + usleep_range(10000, 12000); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5150, 7000); + + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + + /* T6 */ + msleep(50); + + return 0; +} + +static const struct drm_display_mode default_mode = { + .hdisplay = 720, + .hsync_start = 720 + 45, + .hsync_end = 720 + 45 + 14, + .htotal = 720 + 45 + 14 + 25, + .vdisplay = 1440, + .vsync_start = 1440 + 130, + .vsync_end = 1440 + 130 + 8, + .vtotal = 1440 + 130 + 8 + 106, + .clock = 85298, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 65, + .height_mm = 130, +}; + +static int mantix_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct mantix *ctx = panel_to_mantix(panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &default_mode); + if (!mode) { + dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(mode)); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs mantix_drm_funcs = { + .disable = mantix_disable, + .unprepare = mantix_unprepare, + .prepare = mantix_prepare, + .enable = mantix_enable, + .get_modes = mantix_get_modes, +}; + +static int mantix_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct mantix *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->reset_gpio = devm_gpiod_get(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); + } + + mipi_dsi_set_drvdata(dsi, ctx); + ctx->dev = dev; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + + ctx->avdd = devm_regulator_get(dev, "avdd"); + if (IS_ERR(ctx->avdd)) + return dev_err_probe(dev, PTR_ERR(ctx->avdd), "Failed to request avdd regulator\n"); + + ctx->avee = devm_regulator_get(dev, "avee"); + if (IS_ERR(ctx->avee)) + return dev_err_probe(dev, PTR_ERR(ctx->avee), "Failed to request avee regulator\n"); + + ctx->vddi = devm_regulator_get(dev, "vddi"); + if (IS_ERR(ctx->vddi)) + return dev_err_probe(dev, PTR_ERR(ctx->vddi), "Failed to request vddi regulator\n"); + + drm_panel_init(&ctx->panel, dev, &mantix_drm_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(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode), + mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); + + return 0; +} + +static void mantix_shutdown(struct mipi_dsi_device *dsi) +{ + struct mantix *ctx = mipi_dsi_get_drvdata(dsi); + + drm_panel_unprepare(&ctx->panel); + drm_panel_disable(&ctx->panel); +} + +static int mantix_remove(struct mipi_dsi_device *dsi) +{ + struct mantix *ctx = mipi_dsi_get_drvdata(dsi); + + mantix_shutdown(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); + + return 0; +} + +static const struct of_device_id mantix_of_match[] = { + { .compatible = "mantix,mlaf057we51-x" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mantix_of_match); + +static struct mipi_dsi_driver mantix_driver = { + .probe = mantix_probe, + .remove = mantix_remove, + .shutdown = mantix_shutdown, + .driver = { + .name = DRV_NAME, + .of_match_table = mantix_of_match, + }, +}; +module_mipi_dsi_driver(mantix_driver); + +MODULE_AUTHOR("Guido Günther <[email protected]>"); +MODULE_DESCRIPTION("DRM driver for Mantix MLAF057WE51-X MIPI DSI panel"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c index f894971c1c7c..6e5ab1debc8b 100644 --- a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c @@ -207,7 +207,9 @@ static int nl8048_probe(struct spi_device *spi) drm_panel_init(&lcd->panel, &lcd->spi->dev, &nl8048_funcs, DRM_MODE_CONNECTOR_DPI); - return drm_panel_add(&lcd->panel); + drm_panel_add(&lcd->panel); + + return 0; } static int nl8048_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index e98d54df00e7..b9a0e56f33e2 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c @@ -35,7 +35,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */ #define MCS_CMD_READ_ID1 0xDA @@ -376,6 +375,10 @@ struct nt35510 { }; /* Manufacturer command has strictly this byte sequence */ +static const u8 nt35510_mauc_mtp_read_param[] = { 0xAA, 0x55, 0x25, 0x01 }; +static const u8 nt35510_mauc_mtp_read_setting[] = { 0x01, 0x02, 0x00, 0x20, + 0x33, 0x13, 0x00, 0x40, + 0x00, 0x00, 0x23, 0x02 }; static const u8 nt35510_mauc_select_page_0[] = { 0x55, 0xAA, 0x52, 0x08, 0x00 }; static const u8 nt35510_mauc_select_page_1[] = { 0x55, 0xAA, 0x52, 0x08, 0x01 }; static const u8 nt35510_vgh_on[] = { 0x01 }; @@ -400,9 +403,7 @@ static int nt35510_send_long(struct nt35510 *nt, struct mipi_dsi_device *dsi, chunk = 15; ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk); if (ret < 0) { - DRM_DEV_ERROR(nt->dev, - "error sending DCS command seq cmd %02x\n", - cmd); + dev_err(nt->dev, "error sending DCS command seq cmd %02x\n", cmd); return ret; } cmdwritten += chunk; @@ -414,16 +415,13 @@ static int nt35510_send_long(struct nt35510 *nt, struct mipi_dsi_device *dsi, chunk = 15; ret = mipi_dsi_generic_write(dsi, seqp, chunk); if (ret < 0) { - DRM_DEV_ERROR(nt->dev, - "error sending generic write seq %02x\n", - cmd); + dev_err(nt->dev, "error sending generic write seq %02x\n", cmd); return ret; } cmdwritten += chunk; seqp += chunk; } - DRM_DEV_DEBUG(nt->dev, "sent command %02x %02x bytes\n", - cmd, cmdlen); + dev_dbg(nt->dev, "sent command %02x %02x bytes\n", cmd, cmdlen); return 0; } @@ -435,17 +433,17 @@ static int nt35510_read_id(struct nt35510 *nt) ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID1, &id1, 1); if (ret < 0) { - DRM_DEV_ERROR(nt->dev, "could not read MTP ID1\n"); + dev_err(nt->dev, "could not read MTP ID1\n"); return ret; } ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID2, &id2, 1); if (ret < 0) { - DRM_DEV_ERROR(nt->dev, "could not read MTP ID2\n"); + dev_err(nt->dev, "could not read MTP ID2\n"); return ret; } ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID3, &id3, 1); if (ret < 0) { - DRM_DEV_ERROR(nt->dev, "could not read MTP ID3\n"); + dev_err(nt->dev, "could not read MTP ID3\n"); return ret; } @@ -454,9 +452,7 @@ static int nt35510_read_id(struct nt35510 *nt) * ID (e.g. Hydis 0x55), driver ID (e.g. NT35510 0xc0) and * version. */ - DRM_DEV_INFO(nt->dev, - "MTP ID manufacturer: %02x version: %02x driver: %02x\n", - id1, id2, id3); + dev_info(nt->dev, "MTP ID manufacturer: %02x version: %02x driver: %02x\n", id1, id2, id3); return 0; } @@ -657,7 +653,7 @@ static int nt35510_set_brightness(struct backlight_device *bl) u8 brightness = bl->props.brightness; int ret; - DRM_DEV_DEBUG(nt->dev, "set brightness %d\n", brightness); + dev_dbg(nt->dev, "set brightness %d\n", brightness); ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, &brightness, sizeof(brightness)); @@ -698,6 +694,18 @@ static int nt35510_power_on(struct nt35510 *nt) usleep_range(120000, 140000); } + ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_PARAM, + ARRAY_SIZE(nt35510_mauc_mtp_read_param), + nt35510_mauc_mtp_read_param); + if (ret) + return ret; + + ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_SETTING, + ARRAY_SIZE(nt35510_mauc_mtp_read_setting), + nt35510_mauc_mtp_read_setting); + if (ret) + return ret; + ret = nt35510_read_id(nt); if (ret) return ret; @@ -780,8 +788,7 @@ static int nt35510_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret) { - DRM_DEV_ERROR(nt->dev, "failed to turn display off (%d)\n", - ret); + dev_err(nt->dev, "failed to turn display off (%d)\n", ret); return ret; } usleep_range(10000, 20000); @@ -789,8 +796,7 @@ static int nt35510_unprepare(struct drm_panel *panel) /* Enter sleep mode */ ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret) { - DRM_DEV_ERROR(nt->dev, "failed to enter sleep mode (%d)\n", - ret); + dev_err(nt->dev, "failed to enter sleep mode (%d)\n", ret); return ret; } @@ -817,8 +823,7 @@ static int nt35510_prepare(struct drm_panel *panel) /* Exit sleep mode */ ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret) { - DRM_DEV_ERROR(nt->dev, "failed to exit sleep mode (%d)\n", - ret); + dev_err(nt->dev, "failed to exit sleep mode (%d)\n", ret); return ret; } /* Up to 120 ms */ @@ -826,8 +831,7 @@ static int nt35510_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_on(dsi); if (ret) { - DRM_DEV_ERROR(nt->dev, "failed to turn display on (%d)\n", - ret); + dev_err(nt->dev, "failed to turn display on (%d)\n", ret); return ret; } /* Some 10 ms */ @@ -848,7 +852,7 @@ static int nt35510_get_modes(struct drm_panel *panel, info->height_mm = nt->conf->height_mm; mode = drm_mode_duplicate(connector->dev, &nt->conf->mode); if (!mode) { - DRM_ERROR("bad mode or failed to add mode\n"); + dev_err(panel->dev, "bad mode or failed to add mode\n"); return -EINVAL; } drm_mode_set_name(mode); @@ -947,7 +951,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) bl = devm_backlight_device_register(dev, "nt35510", dev, nt, &nt35510_bl_ops, NULL); if (IS_ERR(bl)) { - DRM_DEV_ERROR(dev, "failed to register backlight device\n"); + dev_err(dev, "failed to register backlight device\n"); return PTR_ERR(bl); } bl->props.max_brightness = 255; @@ -956,9 +960,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) nt->panel.backlight = bl; } - ret = drm_panel_add(&nt->panel); - if (ret < 0) - return ret; + drm_panel_add(&nt->panel); ret = mipi_dsi_attach(dsi); if (ret < 0) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt39016.c b/drivers/gpu/drm/panel/panel-novatek-nt39016.c index 91df050ba3f6..f8151fe3ac9a 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt39016.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt39016.c @@ -6,7 +6,6 @@ * Copyright (C) 2019, Paul Cercueil <[email protected]> */ -#include <linux/backlight.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/gpio/consumer.h> @@ -57,14 +56,11 @@ struct nt39016_panel_info { struct nt39016 { struct drm_panel drm_panel; - struct device *dev; struct regmap *map; struct regulator *supply; const struct nt39016_panel_info *panel_info; struct gpio_desc *reset_gpio; - - struct backlight_device *backlight; }; static inline struct nt39016 *to_nt39016(struct drm_panel *panel) @@ -127,7 +123,7 @@ static int nt39016_prepare(struct drm_panel *drm_panel) err = regulator_enable(panel->supply); if (err) { - dev_err(panel->dev, "Failed to enable power supply: %d", err); + dev_err(drm_panel->dev, "Failed to enable power supply: %d\n", err); return err; } @@ -146,7 +142,7 @@ static int nt39016_prepare(struct drm_panel *drm_panel) err = regmap_multi_reg_write(panel->map, nt39016_panel_regs, ARRAY_SIZE(nt39016_panel_regs)); if (err) { - dev_err(panel->dev, "Failed to init registers: %d", err); + dev_err(drm_panel->dev, "Failed to init registers: %d\n", err); goto err_disable_regulator; } @@ -176,18 +172,16 @@ static int nt39016_enable(struct drm_panel *drm_panel) ret = regmap_write(panel->map, NT39016_REG_SYSTEM, NT39016_SYSTEM_RESET_N | NT39016_SYSTEM_STANDBY); if (ret) { - dev_err(panel->dev, "Unable to enable panel: %d", ret); + dev_err(drm_panel->dev, "Unable to enable panel: %d\n", ret); return ret; } - if (panel->backlight) { + if (drm_panel->backlight) { /* Wait for the picture to be ready before enabling backlight */ msleep(150); - - ret = backlight_enable(panel->backlight); } - return ret; + return 0; } static int nt39016_disable(struct drm_panel *drm_panel) @@ -195,12 +189,10 @@ static int nt39016_disable(struct drm_panel *drm_panel) struct nt39016 *panel = to_nt39016(drm_panel); int err; - backlight_disable(panel->backlight); - err = regmap_write(panel->map, NT39016_REG_SYSTEM, NT39016_SYSTEM_RESET_N); if (err) { - dev_err(panel->dev, "Unable to disable panel: %d", err); + dev_err(drm_panel->dev, "Unable to disable panel: %d\n", err); return err; } @@ -259,7 +251,6 @@ static int nt39016_probe(struct spi_device *spi) if (!panel) return -ENOMEM; - panel->dev = dev; spi_set_drvdata(spi, panel); panel->panel_info = of_device_get_match_data(dev); @@ -268,13 +259,13 @@ static int nt39016_probe(struct spi_device *spi) panel->supply = devm_regulator_get(dev, "power"); if (IS_ERR(panel->supply)) { - dev_err(dev, "Failed to get power supply"); + dev_err(dev, "Failed to get power supply\n"); return PTR_ERR(panel->supply); } panel->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(panel->reset_gpio)) { - dev_err(dev, "Failed to get reset GPIO"); + dev_err(dev, "Failed to get reset GPIO\n"); return PTR_ERR(panel->reset_gpio); } @@ -282,33 +273,28 @@ static int nt39016_probe(struct spi_device *spi) spi->mode = SPI_MODE_3 | SPI_3WIRE; err = spi_setup(spi); if (err) { - dev_err(dev, "Failed to setup SPI"); + dev_err(dev, "Failed to setup SPI\n"); return err; } panel->map = devm_regmap_init_spi(spi, &nt39016_regmap_config); if (IS_ERR(panel->map)) { - dev_err(dev, "Failed to init regmap"); + dev_err(dev, "Failed to init regmap\n"); return PTR_ERR(panel->map); } - panel->backlight = devm_of_find_backlight(dev); - if (IS_ERR(panel->backlight)) { - err = PTR_ERR(panel->backlight); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get backlight handle"); - return err; - } - drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs, DRM_MODE_CONNECTOR_DPI); - err = drm_panel_add(&panel->drm_panel); - if (err < 0) { - dev_err(dev, "Failed to register panel"); + err = drm_panel_of_backlight(&panel->drm_panel); + if (err) { + if (err != -EPROBE_DEFER) + dev_err(dev, "Failed to get backlight handle\n"); return err; } + drm_panel_add(&panel->drm_panel); + return 0; } diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c index ecd76b5391d3..cb5cb27462df 100644 --- a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c +++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c @@ -283,7 +283,9 @@ static int lcd_olinuxino_probe(struct i2c_client *client, if (ret) return ret; - return drm_panel_add(&lcd->panel); + drm_panel_add(&lcd->panel); + + return 0; } static int lcd_olinuxino_remove(struct i2c_client *client) diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index d956522f32ee..b6e377aa1131 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -17,7 +17,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define OTM8009A_BACKLIGHT_DEFAULT 240 #define OTM8009A_BACKLIGHT_MAX 255 @@ -97,7 +96,7 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); if (mipi_dsi_dcs_write_buffer(dsi, data, len) < 0) - DRM_WARN("mipi dsi dcs write buffer failed\n"); + dev_warn(ctx->dev, "mipi dsi dcs write buffer failed\n"); } static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data, @@ -313,7 +312,7 @@ static int otm8009a_prepare(struct drm_panel *panel) ret = regulator_enable(ctx->supply); if (ret < 0) { - DRM_ERROR("failed to enable supply: %d\n", ret); + dev_err(panel->dev, "failed to enable supply: %d\n", ret); return ret; } @@ -355,9 +354,9 @@ static int otm8009a_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_ERROR("failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); return -ENOMEM; } @@ -390,7 +389,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) u8 data[2]; if (!ctx->prepared) { - DRM_DEBUG("lcd not ready yet for setting its backlight!\n"); + dev_dbg(&bd->dev, "lcd not ready yet for setting its backlight!\n"); return -ENXIO; } diff --git a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c index 83e5aa47f0d6..45b975dee587 100644 --- a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c +++ b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c @@ -164,7 +164,9 @@ static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587) if (ret) return ret; - return drm_panel_add(&osd101t2587->base); + drm_panel_add(&osd101t2587->base); + + return 0; } static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index 627dfcf8adb4..3c20beeb1781 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c @@ -206,7 +206,9 @@ static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt) if (ret) return ret; - return drm_panel_add(&wuxga_nt->base); + drm_panel_add(&wuxga_nt->base); + + return 0; } static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt) diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c index e50ee26474cf..5e9ccefb88f6 100644 --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c @@ -361,7 +361,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c, struct rpi_touchscreen *ts; struct device_node *endpoint, *dsi_host_node; struct mipi_dsi_host *host; - int ret, ver; + int ver; struct mipi_dsi_device_info info = { .type = RPI_DSI_DRIVER_NAME, .channel = 0, @@ -429,9 +429,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c, /* This appears last, as it's what will unblock the DSI host * driver's component bind function. */ - ret = drm_panel_add(&ts->base); - if (ret) - return ret; + drm_panel_add(&ts->base); return 0; diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67191.c b/drivers/gpu/drm/panel/panel-raydium-rm67191.c index 57ff2b1f6361..23b62081e951 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm67191.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm67191.c @@ -19,7 +19,6 @@ #include <drm/drm_crtc.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> /* Panel specific color-format bits */ #define COL_FMT_16BPP 0x55 @@ -329,7 +328,7 @@ static int rad_panel_enable(struct drm_panel *panel) ret = rad_panel_push_cmd_list(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to send MCS (%d)\n", ret); + dev_err(dev, "Failed to send MCS (%d)\n", ret); goto fail; } @@ -341,7 +340,7 @@ static int rad_panel_enable(struct drm_panel *panel) /* Software reset */ ret = mipi_dsi_dcs_soft_reset(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to do Software Reset (%d)\n", ret); + dev_err(dev, "Failed to do Software Reset (%d)\n", ret); goto fail; } @@ -350,33 +349,32 @@ static int rad_panel_enable(struct drm_panel *panel) /* Set DSI mode */ ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xC2, 0x0B }, 2); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to set DSI mode (%d)\n", ret); + dev_err(dev, "Failed to set DSI mode (%d)\n", ret); goto fail; } /* Set tear ON */ ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to set tear ON (%d)\n", ret); + dev_err(dev, "Failed to set tear ON (%d)\n", ret); goto fail; } /* Set tear scanline */ ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0x380); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to set tear scanline (%d)\n", ret); + dev_err(dev, "Failed to set tear scanline (%d)\n", ret); goto fail; } /* Set pixel format */ ret = mipi_dsi_dcs_set_pixel_format(dsi, color_format); - DRM_DEV_DEBUG_DRIVER(dev, "Interface color format set to 0x%x\n", - color_format); + dev_dbg(dev, "Interface color format set to 0x%x\n", color_format); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to set pixel format (%d)\n", ret); + dev_err(dev, "Failed to set pixel format (%d)\n", ret); goto fail; } /* Exit sleep mode */ ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to exit sleep mode (%d)\n", ret); + dev_err(dev, "Failed to exit sleep mode (%d)\n", ret); goto fail; } @@ -384,7 +382,7 @@ static int rad_panel_enable(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_on(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to set display ON (%d)\n", ret); + dev_err(dev, "Failed to set display ON (%d)\n", ret); goto fail; } @@ -418,7 +416,7 @@ static int rad_panel_disable(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to set display OFF (%d)\n", ret); + dev_err(dev, "Failed to set display OFF (%d)\n", ret); return ret; } @@ -426,7 +424,7 @@ static int rad_panel_disable(struct drm_panel *panel) ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to enter sleep mode (%d)\n", ret); + dev_err(dev, "Failed to enter sleep mode (%d)\n", ret); return ret; } @@ -442,9 +440,9 @@ static int rad_panel_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); return -ENOMEM; } @@ -609,9 +607,7 @@ static int rad_panel_probe(struct mipi_dsi_device *dsi) DRM_MODE_CONNECTOR_DSI); dev_set_drvdata(dev, panel); - ret = drm_panel_add(&panel->panel); - if (ret) - return ret; + drm_panel_add(&panel->panel); ret = mipi_dsi_attach(dsi); if (ret) @@ -628,8 +624,7 @@ static int rad_panel_remove(struct mipi_dsi_device *dsi) ret = mipi_dsi_detach(dsi); if (ret) - DRM_DEV_ERROR(dev, "Failed to detach from host (%d)\n", - ret); + dev_err(dev, "Failed to detach from host (%d)\n", ret); drm_panel_remove(&rad->panel); diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c index 81ae8be62d15..f908eeafb1af 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -17,7 +17,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> /*** Manufacturer Command Set ***/ #define MCS_CMD_MODE_SW 0xFE /* CMD Mode Switch */ @@ -110,8 +109,7 @@ static void rm68200_dcs_write_buf(struct rm68200 *ctx, const void *data, err = mipi_dsi_dcs_write_buffer(dsi, data, len); if (err < 0) - DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n", - err); + dev_err_ratelimited(ctx->dev, "MIPI DSI DCS write buffer failed: %d\n", err); } static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value) @@ -121,7 +119,7 @@ static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value) err = mipi_dsi_dcs_write(dsi, cmd, &value, 1); if (err < 0) - DRM_ERROR_RATELIMITED("MIPI DSI DCS write failed: %d\n", err); + dev_err_ratelimited(ctx->dev, "MIPI DSI DCS write failed: %d\n", err); } #define dcs_write_seq(ctx, seq...) \ @@ -256,11 +254,11 @@ static int rm68200_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret) - DRM_WARN("failed to set display off: %d\n", ret); + dev_warn(panel->dev, "failed to set display off: %d\n", ret); ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret) - DRM_WARN("failed to enter sleep mode: %d\n", ret); + dev_warn(panel->dev, "failed to enter sleep mode: %d\n", ret); msleep(120); @@ -287,7 +285,7 @@ static int rm68200_prepare(struct drm_panel *panel) ret = regulator_enable(ctx->supply); if (ret < 0) { - DRM_ERROR("failed to enable supply: %d\n", ret); + dev_err(ctx->dev, "failed to enable supply: %d\n", ret); return ret; } @@ -336,9 +334,9 @@ static int rm68200_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_ERROR("failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); return -ENOMEM; } diff --git a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c index a7b0b3e39e1a..535c8d1cca21 100644 --- a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c +++ b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c @@ -23,7 +23,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> struct rb070d30_panel { struct drm_panel panel; @@ -50,7 +49,7 @@ static int rb070d30_panel_prepare(struct drm_panel *panel) ret = regulator_enable(ctx->supply); if (ret < 0) { - DRM_DEV_ERROR(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret); + dev_err(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret); return ret; } @@ -117,9 +116,8 @@ static int rb070d30_panel_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_DEV_ERROR(&ctx->dsi->dev, - "Failed to add mode " DRM_MODE_FMT "\n", - DRM_MODE_ARG(&default_mode)); + dev_err(&ctx->dsi->dev, "Failed to add mode " DRM_MODE_FMT "\n", + DRM_MODE_ARG(&default_mode)); return -EINVAL; } @@ -166,13 +164,13 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->gpios.reset)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n"); + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); return PTR_ERR(ctx->gpios.reset); } ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW); if (IS_ERR(ctx->gpios.power)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get our power GPIO\n"); + dev_err(&dsi->dev, "Couldn't get our power GPIO\n"); return PTR_ERR(ctx->gpios.power); } @@ -182,7 +180,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) */ ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW); if (IS_ERR(ctx->gpios.updn)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get our updn GPIO\n"); + dev_err(&dsi->dev, "Couldn't get our updn GPIO\n"); return PTR_ERR(ctx->gpios.updn); } @@ -192,7 +190,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) */ ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW); if (IS_ERR(ctx->gpios.shlr)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get our shlr GPIO\n"); + dev_err(&dsi->dev, "Couldn't get our shlr GPIO\n"); return PTR_ERR(ctx->gpios.shlr); } @@ -200,9 +198,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - ret = drm_panel_add(&ctx->panel); - if (ret < 0) - return ret; + drm_panel_add(&ctx->panel); dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; dsi->format = MIPI_DSI_FMT_RGB888; diff --git a/drivers/gpu/drm/panel/panel-samsung-ld9040.c b/drivers/gpu/drm/panel/panel-samsung-ld9040.c index 9bb2e8c7934a..f484147fc3a6 100644 --- a/drivers/gpu/drm/panel/panel-samsung-ld9040.c +++ b/drivers/gpu/drm/panel/panel-samsung-ld9040.c @@ -21,7 +21,6 @@ #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> /* Manufacturer Command Set */ #define MCS_MANPWR 0xb0 @@ -269,7 +268,7 @@ static int ld9040_get_modes(struct drm_panel *panel, mode = drm_mode_create(connector->dev); if (!mode) { - DRM_ERROR("failed to create a new display mode\n"); + dev_err(panel->dev, "failed to create a new display mode\n"); return 0; } @@ -354,7 +353,9 @@ static int ld9040_probe(struct spi_device *spi) drm_panel_init(&ctx->panel, dev, &ld9040_drm_funcs, DRM_MODE_CONNECTOR_DPI); - return drm_panel_add(&ctx->panel); + drm_panel_add(&ctx->panel); + + return 0; } static int ld9040_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c index f02645d396ac..4aac0d1573dd 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -7,7 +7,6 @@ #include <drm/drm_modes.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> @@ -55,8 +54,7 @@ static int s6d16d0_unprepare(struct drm_panel *panel) /* Enter sleep mode */ ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret) { - DRM_DEV_ERROR(s6->dev, "failed to enter sleep mode (%d)\n", - ret); + dev_err(s6->dev, "failed to enter sleep mode (%d)\n", ret); return ret; } @@ -75,7 +73,7 @@ static int s6d16d0_prepare(struct drm_panel *panel) ret = regulator_enable(s6->supply); if (ret) { - DRM_DEV_ERROR(s6->dev, "failed to enable supply (%d)\n", ret); + dev_err(s6->dev, "failed to enable supply (%d)\n", ret); return ret; } @@ -90,15 +88,13 @@ static int s6d16d0_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); if (ret) { - DRM_DEV_ERROR(s6->dev, "failed to enable vblank TE (%d)\n", - ret); + dev_err(s6->dev, "failed to enable vblank TE (%d)\n", ret); return ret; } /* Exit sleep mode and power on */ ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret) { - DRM_DEV_ERROR(s6->dev, "failed to exit sleep mode (%d)\n", - ret); + dev_err(s6->dev, "failed to exit sleep mode (%d)\n", ret); return ret; } @@ -113,8 +109,7 @@ static int s6d16d0_enable(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_on(dsi); if (ret) { - DRM_DEV_ERROR(s6->dev, "failed to turn display on (%d)\n", - ret); + dev_err(s6->dev, "failed to turn display on (%d)\n", ret); return ret; } @@ -129,8 +124,7 @@ static int s6d16d0_disable(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret) { - DRM_DEV_ERROR(s6->dev, "failed to turn display off (%d)\n", - ret); + dev_err(s6->dev, "failed to turn display off (%d)\n", ret); return ret; } @@ -144,7 +138,7 @@ static int s6d16d0_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &samsung_s6d16d0_mode); if (!mode) { - DRM_ERROR("bad mode or failed to add mode\n"); + dev_err(panel->dev, "bad mode or failed to add mode\n"); return -EINVAL; } drm_mode_set_name(mode); @@ -204,17 +198,14 @@ static int s6d16d0_probe(struct mipi_dsi_device *dsi) if (IS_ERR(s6->reset_gpio)) { ret = PTR_ERR(s6->reset_gpio); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", - ret); + dev_err(dev, "failed to request GPIO (%d)\n", ret); return ret; } drm_panel_init(&s6->panel, dev, &s6d16d0_drm_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_add(&s6->panel); - if (ret < 0) - return ret; + drm_panel_add(&s6->panel); ret = mipi_dsi_attach(dsi); if (ret < 0) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c index 80ef122e7466..1d1c79a18613 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c @@ -18,7 +18,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define S6E3HA2_MIN_BRIGHTNESS 0 #define S6E3HA2_MAX_BRIGHTNESS 100 @@ -651,7 +650,7 @@ static int s6e3ha2_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); if (!mode) { - DRM_ERROR("failed to add mode %ux%ux@%u\n", + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, drm_mode_vrefresh(ctx->desc->mode)); return -ENOMEM; @@ -733,9 +732,7 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi) drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_add(&ctx->panel); - if (ret < 0) - goto unregister_backlight; + drm_panel_add(&ctx->panel); ret = mipi_dsi_attach(dsi); if (ret < 0) @@ -745,8 +742,6 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi) remove_panel: drm_panel_remove(&ctx->panel); - -unregister_backlight: backlight_device_unregister(ctx->bl_dev); return ret; diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c index 1247656d73bf..b962c817fb30 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c @@ -19,7 +19,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define MCS_LEVEL2_KEY 0xf0 #define MCS_MTP_KEY 0xf1 @@ -406,7 +405,7 @@ static int s6e63j0x03_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_ERROR("failed to add mode %ux%ux@%u\n", + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", default_mode.hdisplay, default_mode.vdisplay, drm_mode_vrefresh(&default_mode)); return -ENOMEM; @@ -479,9 +478,7 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS; ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; - ret = drm_panel_add(&ctx->panel); - if (ret < 0) - goto unregister_backlight; + drm_panel_add(&ctx->panel); ret = mipi_dsi_attach(dsi); if (ret < 0) @@ -491,8 +488,6 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) remove_panel: drm_panel_remove(&ctx->panel); - -unregister_backlight: backlight_device_unregister(ctx->bl_dev); return ret; diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c index 64421347bfd4..2cc772fdc456 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c @@ -10,7 +10,6 @@ #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #include <linux/backlight.h> #include <linux/delay.h> @@ -157,7 +156,7 @@ static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len) if (ctx->error < 0 || len == 0) return; - DRM_DEV_DEBUG(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data); + dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data); ret = s6e63m0_spi_write_word(ctx, *data); while (!ret && --len) { @@ -166,8 +165,7 @@ static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len) } if (ret) { - DRM_DEV_ERROR(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, - (int)len, data); + dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, (int)len, data); ctx->error = ret; } @@ -368,9 +366,9 @@ static int s6e63m0_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_ERROR("failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); return -ENOMEM; } @@ -425,8 +423,7 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx) &props); if (IS_ERR(ctx->bl_dev)) { ret = PTR_ERR(ctx->bl_dev); - DRM_DEV_ERROR(dev, "error registering backlight device (%d)\n", - ret); + dev_err(dev, "error registering backlight device (%d)\n", ret); } return ret; @@ -453,14 +450,13 @@ static int s6e63m0_probe(struct spi_device *spi) ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) { - DRM_DEV_ERROR(dev, "failed to get regulators: %d\n", ret); + dev_err(dev, "failed to get regulators: %d\n", ret); return ret; } ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset-gpios %ld\n", - PTR_ERR(ctx->reset_gpio)); + dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio)); return PTR_ERR(ctx->reset_gpio); } @@ -468,7 +464,7 @@ static int s6e63m0_probe(struct spi_device *spi) spi->mode = SPI_MODE_3; ret = spi_setup(spi); if (ret < 0) { - DRM_DEV_ERROR(dev, "spi setup failed.\n"); + dev_err(dev, "spi setup failed.\n"); return ret; } @@ -479,7 +475,9 @@ static int s6e63m0_probe(struct spi_device *spi) if (ret < 0) return ret; - return drm_panel_add(&ctx->panel); + drm_panel_add(&ctx->panel); + + return 0; } static int s6e63m0_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c index 485eabecfcc9..ea63799ff2a1 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c @@ -242,11 +242,7 @@ static int s6e88a0_ams452ef01_probe(struct mipi_dsi_device *dsi) drm_panel_init(&ctx->panel, dev, &s6e88a0_ams452ef01_panel_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_add(&ctx->panel); - if (ret < 0) { - dev_err(dev, "Failed to add panel: %d\n", ret); - return ret; - } + drm_panel_add(&ctx->panel); ret = mipi_dsi_attach(dsi); if (ret < 0) { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index 8a028d2bd0d6..527371120266 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -25,7 +25,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define LDI_MTP_LENGTH 24 #define GAMMA_LEVEL_NUM 25 @@ -928,7 +927,7 @@ static int s6e8aa0_get_modes(struct drm_panel *panel, mode = drm_mode_create(connector->dev); if (!mode) { - DRM_ERROR("failed to create a new display mode\n"); + dev_err(panel->dev, "failed to create a new display mode\n"); return 0; } @@ -1020,9 +1019,7 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs, DRM_MODE_CONNECTOR_DSI); - ret = drm_panel_add(&ctx->panel); - if (ret < 0) - return ret; + drm_panel_add(&ctx->panel); ret = mipi_dsi_attach(dsi); if (ret < 0) diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c index e417dc4921c2..0ee508576231 100644 --- a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c +++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c @@ -258,9 +258,7 @@ static int seiko_panel_probe(struct device *dev, if (err) return err; - err = drm_panel_add(&panel->base); - if (err < 0) - return err; + drm_panel_add(&panel->base); dev_set_drvdata(dev, panel); diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c index f07324b705b3..f8cd2a42ed13 100644 --- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c @@ -325,7 +325,9 @@ static int sharp_panel_add(struct sharp_panel *sharp) if (ret) return ret; - return drm_panel_add(&sharp->base); + drm_panel_add(&sharp->base); + + return 0; } static void sharp_panel_del(struct sharp_panel *sharp) diff --git a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c index d7bf13b9e1d6..94992f45113a 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c @@ -187,7 +187,9 @@ static int ls037v7dw01_probe(struct platform_device *pdev) drm_panel_init(&lcd->panel, &pdev->dev, &ls037v7dw01_funcs, DRM_MODE_CONNECTOR_DPI); - return drm_panel_add(&lcd->panel); + drm_panel_add(&lcd->panel); + + return 0; } static int ls037v7dw01_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index b2e58935529c..16dbf0f353ed 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -261,7 +261,9 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) if (ret) return ret; - return drm_panel_add(&sharp_nt->base); + drm_panel_add(&sharp_nt->base); + + return 0; } static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index cb6550d37e85..f499de71ab3d 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -112,6 +112,8 @@ struct panel_simple { struct gpio_desc *hpd_gpio; struct drm_display_mode override_mode; + + enum drm_panel_orientation orientation; }; static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) @@ -371,6 +373,9 @@ static int panel_simple_get_modes(struct drm_panel *panel, /* add hard-coded panel modes */ num += panel_simple_get_non_edid_modes(p, connector); + /* set up connector's "panel orientation" property */ + drm_connector_set_panel_orientation(connector, p->orientation); + return num; } @@ -500,6 +505,8 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) struct panel_simple *panel; struct display_timing dt; struct device_node *ddc; + int connector_type; + u32 bus_flags; int err; panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); @@ -530,6 +537,12 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) return err; } + err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation); + if (err) { + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); + return err; + } + ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); if (ddc) { panel->ddc = of_find_i2c_adapter_by_node(ddc); @@ -549,8 +562,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel_simple_parse_panel_timing_node(dev, panel, &dt); } - if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { - /* Catch common mistakes for LVDS panels. */ + connector_type = desc->connector_type; + /* Catch common mistakes for panels. */ + switch (connector_type) { + case 0: + dev_warn(dev, "Specify missing connector_type\n"); + connector_type = DRM_MODE_CONNECTOR_DPI; + break; + case DRM_MODE_CONNECTOR_LVDS: WARN_ON(desc->bus_flags & ~(DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_DE_HIGH | @@ -564,18 +583,48 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG || desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) && desc->bpc != 8); + break; + case DRM_MODE_CONNECTOR_eDP: + if (desc->bus_format == 0) + dev_warn(dev, "Specify missing bus_format\n"); + if (desc->bpc != 6 && desc->bpc != 8) + dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); + break; + case DRM_MODE_CONNECTOR_DSI: + if (desc->bpc != 6 && desc->bpc != 8) + dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); + break; + case DRM_MODE_CONNECTOR_DPI: + bus_flags = DRM_BUS_FLAG_DE_LOW | + DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | + DRM_BUS_FLAG_DATA_MSB_TO_LSB | + DRM_BUS_FLAG_DATA_LSB_TO_MSB | + DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE; + if (desc->bus_flags & ~bus_flags) + dev_warn(dev, "Unexpected bus_flags(%d)\n", desc->bus_flags & ~bus_flags); + if (!(desc->bus_flags & bus_flags)) + dev_warn(dev, "Specify missing bus_flags\n"); + if (desc->bus_format == 0) + dev_warn(dev, "Specify missing bus_format\n"); + if (desc->bpc != 6 && desc->bpc != 8) + dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); + break; + default: + dev_warn(dev, "Specify a valid connector_type: %d\n", desc->connector_type); + connector_type = DRM_MODE_CONNECTOR_DPI; + break; } - drm_panel_init(&panel->base, dev, &panel_simple_funcs, - desc->connector_type); + drm_panel_init(&panel->base, dev, &panel_simple_funcs, connector_type); err = drm_panel_of_backlight(&panel->base); if (err) goto free_ddc; - err = drm_panel_add(&panel->base); - if (err < 0) - goto free_ddc; + drm_panel_add(&panel->base); dev_set_drvdata(dev, panel); @@ -1191,10 +1240,14 @@ static const struct drm_display_mode boe_hv070wsa_mode = { static const struct panel_desc boe_hv070wsa = { .modes = &boe_hv070wsa_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 154, .height = 90, }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, }; static const struct drm_display_mode boe_nv101wxmn51_modes[] = { @@ -1414,6 +1467,36 @@ static const struct panel_desc cdtech_s070wv95_ct16 = { }, }; +static const struct display_timing chefree_ch101olhlwh_002_timing = { + .pixelclock = { 68900000, 71100000, 73400000 }, + .hactive = { 1280, 1280, 1280 }, + .hfront_porch = { 65, 80, 95 }, + .hback_porch = { 64, 79, 94 }, + .hsync_len = { 1, 1, 1 }, + .vactive = { 800, 800, 800 }, + .vfront_porch = { 7, 11, 14 }, + .vback_porch = { 7, 11, 14 }, + .vsync_len = { 1, 1, 1 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc chefree_ch101olhlwh_002 = { + .timings = &chefree_ch101olhlwh_002_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 217, + .height = 135, + }, + .delay = { + .enable = 200, + .disable = 200, + }, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct drm_display_mode chunghwa_claa070wp03xg_mode = { .clock = 66770, .hdisplay = 800, @@ -2258,6 +2341,34 @@ static const struct panel_desc ivo_m133nwf4_r0 = { .connector_type = DRM_MODE_CONNECTOR_eDP, }; +static const struct drm_display_mode kingdisplay_kd116n21_30nv_a010_mode = { + .clock = 81000, + .hdisplay = 1366, + .hsync_start = 1366 + 40, + .hsync_end = 1366 + 40 + 32, + .htotal = 1366 + 40 + 32 + 62, + .vdisplay = 768, + .vsync_start = 768 + 5, + .vsync_end = 768 + 5 + 5, + .vtotal = 768 + 5 + 5 + 122, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + +static const struct panel_desc kingdisplay_kd116n21_30nv_a010 = { + .modes = &kingdisplay_kd116n21_30nv_a010_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 256, + .height = 144, + }, + .delay = { + .hpd_absent_delay = 200, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, + .connector_type = DRM_MODE_CONNECTOR_eDP, +}; + static const struct display_timing koe_tx14d24vm1bpa_timing = { .pixelclock = { 5580000, 5850000, 6200000 }, .hactive = { 320, 320, 320 }, @@ -2946,7 +3057,7 @@ static const struct panel_desc ortustech_com43h4m85ulc = { .width = 56, .height = 93, }, - .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, .connector_type = DRM_MODE_CONNECTOR_DPI, }; @@ -3000,6 +3111,31 @@ static const struct panel_desc pda_91_00156_a0 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; +static const struct drm_display_mode powertip_ph800480t013_idf02_mode = { + .clock = 24750, + .hdisplay = 800, + .hsync_start = 800 + 54, + .hsync_end = 800 + 54 + 2, + .htotal = 800 + 54 + 2 + 44, + .vdisplay = 480, + .vsync_start = 480 + 49, + .vsync_end = 480 + 49 + 2, + .vtotal = 480 + 49 + 2 + 22, +}; + +static const struct panel_desc powertip_ph800480t013_idf02 = { + .modes = &powertip_ph800480t013_idf02_mode, + .num_modes = 1, + .size = { + .width = 152, + .height = 91, + }, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .connector_type = DRM_MODE_CONNECTOR_DPI, +}; static const struct drm_display_mode qd43003c0_40_mode = { .clock = 9000, @@ -3301,22 +3437,36 @@ static const struct panel_desc sharp_lq123p1jx31 = { }, }; -static const struct display_timing sharp_ls020b1dd01d_timing = { - .pixelclock = { 2000000, 4200000, 5000000 }, - .hactive = { 240, 240, 240 }, - .hfront_porch = { 66, 66, 66 }, - .hback_porch = { 1, 1, 1 }, - .hsync_len = { 1, 1, 1 }, - .vactive = { 160, 160, 160 }, - .vfront_porch = { 52, 52, 52 }, - .vback_porch = { 6, 6, 6 }, - .vsync_len = { 10, 10, 10 }, - .flags = DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW, +static const struct drm_display_mode sharp_ls020b1dd01d_modes[] = { + { /* 50 Hz */ + .clock = 3000, + .hdisplay = 240, + .hsync_start = 240 + 58, + .hsync_end = 240 + 58 + 1, + .htotal = 240 + 58 + 1 + 1, + .vdisplay = 160, + .vsync_start = 160 + 24, + .vsync_end = 160 + 24 + 10, + .vtotal = 160 + 24 + 10 + 6, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC, + }, + { /* 60 Hz */ + .clock = 3000, + .hdisplay = 240, + .hsync_start = 240 + 8, + .hsync_end = 240 + 8 + 1, + .htotal = 240 + 8 + 1 + 1, + .vdisplay = 160, + .vsync_start = 160 + 24, + .vsync_end = 160 + 24 + 10, + .vtotal = 160 + 24 + 10 + 6, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC, + }, }; static const struct panel_desc sharp_ls020b1dd01d = { - .timings = &sharp_ls020b1dd01d_timing, - .num_timings = 1, + .modes = sharp_ls020b1dd01d_modes, + .num_modes = ARRAY_SIZE(sharp_ls020b1dd01d_modes), .bpc = 6, .size = { .width = 42, @@ -3821,6 +3971,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "cdtech,s070wv95-ct16", .data = &cdtech_s070wv95_ct16, }, { + .compatible = "chefree,ch101olhlwh-002", + .data = &chefree_ch101olhlwh_002, + }, { .compatible = "chunghwa,claa070wp03xg", .data = &chunghwa_claa070wp03xg, }, { @@ -3923,6 +4076,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "ivo,m133nwf4-r0", .data = &ivo_m133nwf4_r0, }, { + .compatible = "kingdisplay,kd116n21-30nv-a010", + .data = &kingdisplay_kd116n21_30nv_a010, + }, { .compatible = "koe,tx14d24vm1bpa", .data = &koe_tx14d24vm1bpa, }, { @@ -4013,6 +4169,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "pda,91-00156-a0", .data = &pda_91_00156_a0, }, { + .compatible = "powertip,ph800480t013-idf02", + .data = &powertip_ph800480t013_idf02, + }, { .compatible = "qiaodian,qd43003c0-40", .data = &qd43003c0_40, }, { diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index 692041ae4eb6..4d2a149b202c 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -7,7 +7,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #include <linux/gpio/consumer.h> #include <linux/delay.h> @@ -269,10 +268,9 @@ static int st7701_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, desc_mode); if (!mode) { - DRM_DEV_ERROR(&st7701->dsi->dev, - "failed to add mode %ux%ux@%u\n", - desc_mode->hdisplay, desc_mode->vdisplay, - drm_mode_vrefresh(desc_mode)); + dev_err(&st7701->dsi->dev, "failed to add mode %ux%u@%u\n", + desc_mode->hdisplay, desc_mode->vdisplay, + drm_mode_vrefresh(desc_mode)); return -ENOMEM; } @@ -358,7 +356,7 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi) st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(st7701->reset)) { - DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n"); + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); return PTR_ERR(st7701->reset); } @@ -380,9 +378,7 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi) if (ret) return ret; - ret = drm_panel_add(&st7701->panel); - if (ret < 0) - return ret; + drm_panel_add(&st7701->panel); mipi_dsi_set_drvdata(dsi, st7701); st7701->dsi = dsi; diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c index 8996ced2b721..c22e7c49e077 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -22,7 +22,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define DRV_NAME "panel-sitronix-st7703" @@ -364,8 +363,7 @@ static int st7703_enable(struct drm_panel *panel) ret = ctx->desc->init_sequence(ctx); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", - ret); + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); return ret; } @@ -373,7 +371,7 @@ static int st7703_enable(struct drm_panel *panel) ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); return ret; } @@ -384,7 +382,7 @@ static int st7703_enable(struct drm_panel *panel) if (ret) return ret; - DRM_DEV_DEBUG_DRIVER(ctx->dev, "Panel init sequence done\n"); + dev_dbg(ctx->dev, "Panel init sequence done\n"); return 0; } @@ -397,13 +395,11 @@ static int st7703_disable(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) - DRM_DEV_ERROR(ctx->dev, - "Failed to turn off the display: %d\n", ret); + dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret); ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret < 0) - DRM_DEV_ERROR(ctx->dev, - "Failed to enter sleep mode: %d\n", ret); + dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret); return 0; } @@ -431,17 +427,15 @@ static int st7703_prepare(struct drm_panel *panel) if (ctx->prepared) return 0; - DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); + dev_dbg(ctx->dev, "Resetting the panel\n"); ret = regulator_enable(ctx->vcc); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable vcc supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); return ret; } ret = regulator_enable(ctx->iovcc); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable iovcc supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); goto disable_vcc; } @@ -467,9 +461,9 @@ static int st7703_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); if (!mode) { - DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", - ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, - drm_mode_vrefresh(ctx->desc->mode)); + dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", + ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, + drm_mode_vrefresh(ctx->desc->mode)); return -ENOMEM; } @@ -496,7 +490,7 @@ static int allpixelson_set(void *data, u64 val) struct st7703 *ctx = data; struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n"); + dev_dbg(ctx->dev, "Setting all pixels on\n"); dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); msleep(val * 1000); /* Reset the panel to get video back */ @@ -537,7 +531,7 @@ static int st7703_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); + dev_err(dev, "cannot get reset gpio\n"); return PTR_ERR(ctx->reset_gpio); } @@ -554,18 +548,14 @@ static int st7703_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->vcc)) { ret = PTR_ERR(ctx->vcc); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request vcc regulator: %d\n", - ret); + dev_err(dev, "Failed to request vcc regulator: %d\n", ret); return ret; } ctx->iovcc = devm_regulator_get(dev, "iovcc"); if (IS_ERR(ctx->iovcc)) { ret = PTR_ERR(ctx->iovcc); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request iovcc regulator: %d\n", - ret); + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); return ret; } @@ -580,17 +570,15 @@ static int st7703_probe(struct mipi_dsi_device *dsi) ret = mipi_dsi_attach(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, - "mipi_dsi_attach failed (%d). Is host ready?\n", - ret); + dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret); drm_panel_remove(&ctx->panel); return ret; } - DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", - ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, - drm_mode_vrefresh(ctx->desc->mode), - mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); + dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", + ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, + drm_mode_vrefresh(ctx->desc->mode), + mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); st7703_debugfs_init(ctx); return 0; @@ -603,13 +591,11 @@ static void st7703_shutdown(struct mipi_dsi_device *dsi) ret = drm_panel_unprepare(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); ret = drm_panel_disable(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } static int st7703_remove(struct mipi_dsi_device *dsi) @@ -621,8 +607,7 @@ static int st7703_remove(struct mipi_dsi_device *dsi) ret = mipi_dsi_detach(dsi); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", - ret); + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c index 3513ae40efa8..61e565524542 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c @@ -382,9 +382,7 @@ static int st7789v_probe(struct spi_device *spi) if (ret) return ret; - ret = drm_panel_add(&ctx->panel); - if (ret < 0) - return ret; + drm_panel_add(&ctx->panel); return 0; } diff --git a/drivers/gpu/drm/panel/panel-sony-acx424akp.c b/drivers/gpu/drm/panel/panel-sony-acx424akp.c index 97a1b4790d3c..065efae213f5 100644 --- a/drivers/gpu/drm/panel/panel-sony-acx424akp.c +++ b/drivers/gpu/drm/panel/panel-sony-acx424akp.c @@ -20,7 +20,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #define ACX424_DCS_READ_ID1 0xDA #define ACX424_DCS_READ_ID2 0xDB @@ -110,13 +109,11 @@ static int acx424akp_set_brightness(struct backlight_device *bl) SCALE_FACTOR_NS_DIV_MHZ); /* Set up PWM dutycycle ONE byte (differs from the standard) */ - DRM_DEV_DEBUG(acx->dev, "calculated duty cycle %02x\n", pwm_ratio); + dev_dbg(acx->dev, "calculated duty cycle %02x\n", pwm_ratio); ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, &pwm_ratio, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, - "failed to set display PWM ratio (%d)\n", - ret); + dev_err(acx->dev, "failed to set display PWM ratio (%d)\n", ret); return ret; } @@ -132,40 +129,30 @@ static int acx424akp_set_brightness(struct backlight_device *bl) par = 0xaa; ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, - "failed to unlock CMD 2 (%d)\n", - ret); + dev_err(acx->dev, "failed to unlock CMD 2 (%d)\n", ret); return ret; } par = 0x01; ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, - "failed to enter page 1 (%d)\n", - ret); + dev_err(acx->dev, "failed to enter page 1 (%d)\n", ret); return ret; } par = 0x01; ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, - "failed to disable MTP reload (%d)\n", - ret); + dev_err(acx->dev, "failed to disable MTP reload (%d)\n", ret); return ret; } ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, - "failed to set PWM divisor (%d)\n", - ret); + dev_err(acx->dev, "failed to set PWM divisor (%d)\n", ret); return ret; } par = 0xaa; ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, - "failed to lock CMD 2 (%d)\n", - ret); + dev_err(acx->dev, "failed to lock CMD 2 (%d)\n", ret); return ret; } @@ -174,9 +161,7 @@ static int acx424akp_set_brightness(struct backlight_device *bl) ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, &par, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, - "failed to enable display backlight (%d)\n", - ret); + dev_err(acx->dev, "failed to enable display backlight (%d)\n", ret); return ret; } @@ -196,22 +181,22 @@ static int acx424akp_read_id(struct acx424akp *acx) ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &vendor, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, "could not vendor ID byte\n"); + dev_err(acx->dev, "could not vendor ID byte\n"); return ret; } ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &version, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, "could not read device version byte\n"); + dev_err(acx->dev, "could not read device version byte\n"); return ret; } ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &panel, 1); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, "could not read panel ID byte\n"); + dev_err(acx->dev, "could not read panel ID byte\n"); return ret; } if (vendor == 0x00) { - DRM_DEV_ERROR(acx->dev, "device vendor ID is zero\n"); + dev_err(acx->dev, "device vendor ID is zero\n"); return -ENODEV; } @@ -220,14 +205,12 @@ static int acx424akp_read_id(struct acx424akp *acx) case DISPLAY_SONY_ACX424AKP_ID1: case DISPLAY_SONY_ACX424AKP_ID2: case DISPLAY_SONY_ACX424AKP_ID3: - DRM_DEV_INFO(acx->dev, - "MTP vendor: %02x, version: %02x, panel: %02x\n", - vendor, version, panel); + dev_info(acx->dev, "MTP vendor: %02x, version: %02x, panel: %02x\n", + vendor, version, panel); break; default: - DRM_DEV_INFO(acx->dev, - "unknown vendor: %02x, version: %02x, panel: %02x\n", - vendor, version, panel); + dev_info(acx->dev, "unknown vendor: %02x, version: %02x, panel: %02x\n", + vendor, version, panel); break; } @@ -240,7 +223,7 @@ static int acx424akp_power_on(struct acx424akp *acx) ret = regulator_enable(acx->supply); if (ret) { - DRM_DEV_ERROR(acx->dev, "failed to enable supply (%d)\n", ret); + dev_err(acx->dev, "failed to enable supply (%d)\n", ret); return ret; } @@ -276,7 +259,7 @@ static int acx424akp_prepare(struct drm_panel *panel) ret = acx424akp_read_id(acx); if (ret) { - DRM_DEV_ERROR(acx->dev, "failed to read panel ID (%d)\n", ret); + dev_err(acx->dev, "failed to read panel ID (%d)\n", ret); goto err_power_off; } @@ -284,8 +267,7 @@ static int acx424akp_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); if (ret) { - DRM_DEV_ERROR(acx->dev, "failed to enable vblank TE (%d)\n", - ret); + dev_err(acx->dev, "failed to enable vblank TE (%d)\n", ret); goto err_power_off; } @@ -302,23 +284,21 @@ static int acx424akp_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_write(dsi, ACX424_DCS_SET_MDDI, &mddi, sizeof(mddi)); if (ret < 0) { - DRM_DEV_ERROR(acx->dev, "failed to set MDDI (%d)\n", ret); + dev_err(acx->dev, "failed to set MDDI (%d)\n", ret); goto err_power_off; } /* Exit sleep mode */ ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret) { - DRM_DEV_ERROR(acx->dev, "failed to exit sleep mode (%d)\n", - ret); + dev_err(acx->dev, "failed to exit sleep mode (%d)\n", ret); goto err_power_off; } msleep(140); ret = mipi_dsi_dcs_set_display_on(dsi); if (ret) { - DRM_DEV_ERROR(acx->dev, "failed to turn display on (%d)\n", - ret); + dev_err(acx->dev, "failed to turn display on (%d)\n", ret); goto err_power_off; } if (acx->video_mode) { @@ -351,24 +331,20 @@ static int acx424akp_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, &par, 1); if (ret) { - DRM_DEV_ERROR(acx->dev, - "failed to disable display backlight (%d)\n", - ret); + dev_err(acx->dev, "failed to disable display backlight (%d)\n", ret); return ret; } ret = mipi_dsi_dcs_set_display_off(dsi); if (ret) { - DRM_DEV_ERROR(acx->dev, "failed to turn display off (%d)\n", - ret); + dev_err(acx->dev, "failed to turn display off (%d)\n", ret); return ret; } /* Enter sleep mode */ ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret) { - DRM_DEV_ERROR(acx->dev, "failed to enter sleep mode (%d)\n", - ret); + dev_err(acx->dev, "failed to enter sleep mode (%d)\n", ret); return ret; } msleep(85); @@ -418,7 +394,7 @@ static int acx424akp_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &sony_acx424akp_cmd_mode); if (!mode) { - DRM_ERROR("bad mode or failed to add mode\n"); + dev_err(panel->dev, "bad mode or failed to add mode\n"); return -EINVAL; } drm_mode_set_name(mode); @@ -486,8 +462,7 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi) if (IS_ERR(acx->reset_gpio)) { ret = PTR_ERR(acx->reset_gpio); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", - ret); + dev_err(dev, "failed to request GPIO (%d)\n", ret); return ret; } @@ -497,16 +472,14 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi) acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx, &acx424akp_bl_ops, NULL); if (IS_ERR(acx->bl)) { - DRM_DEV_ERROR(dev, "failed to register backlight device\n"); + dev_err(dev, "failed to register backlight device\n"); return PTR_ERR(acx->bl); } acx->bl->props.max_brightness = 1023; acx->bl->props.brightness = 512; acx->bl->props.power = FB_BLANK_POWERDOWN; - ret = drm_panel_add(&acx->panel); - if (ret < 0) - return ret; + drm_panel_add(&acx->panel); ret = mipi_dsi_attach(dsi); if (ret < 0) { diff --git a/drivers/gpu/drm/panel/panel-sony-acx565akm.c b/drivers/gpu/drm/panel/panel-sony-acx565akm.c index fc6a7e451abe..e95fdfb16b6c 100644 --- a/drivers/gpu/drm/panel/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/panel/panel-sony-acx565akm.c @@ -650,12 +650,7 @@ static int acx565akm_probe(struct spi_device *spi) drm_panel_init(&lcd->panel, &lcd->spi->dev, &acx565akm_funcs, DRM_MODE_CONNECTOR_DPI); - ret = drm_panel_add(&lcd->panel); - if (ret < 0) { - if (lcd->has_bc) - acx565akm_backlight_cleanup(lcd); - return ret; - } + drm_panel_add(&lcd->panel); return 0; } diff --git a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c index 58d683cc5215..037c14fd6bac 100644 --- a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c @@ -350,7 +350,9 @@ static int td028ttec1_probe(struct spi_device *spi) if (ret) return ret; - return drm_panel_add(&lcd->panel); + drm_panel_add(&lcd->panel); + + return 0; } static int td028ttec1_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c index 9b2a356c4d9a..49e6c9386258 100644 --- a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c @@ -460,11 +460,7 @@ static int td043mtea1_probe(struct spi_device *spi) drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs, DRM_MODE_CONNECTOR_DPI); - ret = drm_panel_add(&lcd->panel); - if (ret < 0) { - sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group); - return ret; - } + drm_panel_add(&lcd->panel); return 0; } diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c index c7a2f0ae5ba5..d57ed75a977c 100644 --- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c @@ -12,7 +12,6 @@ */ #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -238,7 +237,7 @@ static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write, spi_message_add_tail(&t[1], &m); ret = spi_sync(tpg->spi, &m); if (ret) { - DRM_DEV_ERROR(tpg->dev, "SPI message error %d\n", ret); + dev_err(tpg->dev, "SPI message error %d\n", ret); return ret; } if (write) @@ -265,18 +264,18 @@ static int tpg110_startup(struct tpg110 *tpg) /* De-assert the reset signal */ gpiod_set_value_cansleep(tpg->grestb, 0); usleep_range(1000, 2000); - DRM_DEV_DEBUG(tpg->dev, "de-asserted GRESTB\n"); + dev_dbg(tpg->dev, "de-asserted GRESTB\n"); /* Test display communication */ tpg110_write_reg(tpg, TPG110_TEST, 0x55); val = tpg110_read_reg(tpg, TPG110_TEST); if (val != 0x55) { - DRM_DEV_ERROR(tpg->dev, "failed communication test\n"); + dev_err(tpg->dev, "failed communication test\n"); return -ENODEV; } val = tpg110_read_reg(tpg, TPG110_CHIPID); - DRM_DEV_INFO(tpg->dev, "TPG110 chip ID: %d version: %d\n", + dev_info(tpg->dev, "TPG110 chip ID: %d version: %d\n", val >> 4, val & 0x0f); /* Show display resolution */ @@ -284,27 +283,25 @@ static int tpg110_startup(struct tpg110 *tpg) val &= TPG110_RES_MASK; switch (val) { case TPG110_RES_400X240_D: - DRM_DEV_INFO(tpg->dev, - "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n"); + dev_info(tpg->dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n"); break; case TPG110_RES_480X272_D: - DRM_DEV_INFO(tpg->dev, - "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n"); + dev_info(tpg->dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n"); break; case TPG110_RES_480X640: - DRM_DEV_INFO(tpg->dev, "480x640 RGB\n"); + dev_info(tpg->dev, "480x640 RGB\n"); break; case TPG110_RES_480X272: - DRM_DEV_INFO(tpg->dev, "480x272 RGB\n"); + dev_info(tpg->dev, "480x272 RGB\n"); break; case TPG110_RES_640X480: - DRM_DEV_INFO(tpg->dev, "640x480 RGB\n"); + dev_info(tpg->dev, "640x480 RGB\n"); break; case TPG110_RES_800X480: - DRM_DEV_INFO(tpg->dev, "800x480 RGB\n"); + dev_info(tpg->dev, "800x480 RGB\n"); break; default: - DRM_DEV_ERROR(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val); + dev_err(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val); break; } @@ -322,13 +319,12 @@ static int tpg110_startup(struct tpg110 *tpg) } } if (i == ARRAY_SIZE(tpg110_modes)) { - DRM_DEV_ERROR(tpg->dev, "unsupported mode (%02x) detected\n", - val); + dev_err(tpg->dev, "unsupported mode (%02x) detected\n", val); return -ENODEV; } val = tpg110_read_reg(tpg, TPG110_CTRL2); - DRM_DEV_INFO(tpg->dev, "resolution and standby is controlled by %s\n", + dev_info(tpg->dev, "resolution and standby is controlled by %s\n", (val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware"); /* Take control over resolution and standby */ val |= TPG110_CTRL2_RES_PM_CTRL; @@ -414,15 +410,15 @@ static int tpg110_probe(struct spi_device *spi) /* We get the physical display dimensions from the DT */ ret = of_property_read_u32(np, "width-mm", &tpg->width); if (ret) - DRM_DEV_ERROR(dev, "no panel width specified\n"); + dev_err(dev, "no panel width specified\n"); ret = of_property_read_u32(np, "height-mm", &tpg->height); if (ret) - DRM_DEV_ERROR(dev, "no panel height specified\n"); + dev_err(dev, "no panel height specified\n"); /* This asserts the GRESTB signal, putting the display into reset */ tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH); if (IS_ERR(tpg->grestb)) { - DRM_DEV_ERROR(dev, "no GRESTB GPIO\n"); + dev_err(dev, "no GRESTB GPIO\n"); return -ENODEV; } @@ -430,7 +426,7 @@ static int tpg110_probe(struct spi_device *spi) spi->mode |= SPI_3WIRE_HIZ; ret = spi_setup(spi); if (ret < 0) { - DRM_DEV_ERROR(dev, "spi setup failed.\n"); + dev_err(dev, "spi setup failed.\n"); return ret; } tpg->spi = spi; @@ -448,7 +444,9 @@ static int tpg110_probe(struct spi_device *spi) spi_set_drvdata(spi, tpg); - return drm_panel_add(&tpg->panel); + drm_panel_add(&tpg->panel); + + return 0; } static int tpg110_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c index 9b9c167b8dc8..b24b92d93ea5 100644 --- a/drivers/gpu/drm/panel/panel-truly-nt35597.c +++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c @@ -17,7 +17,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> static const char * const regulator_names[] = { "vdda", @@ -231,9 +230,7 @@ static int truly_dcs_write(struct drm_panel *panel, u32 command) for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { ret = mipi_dsi_dcs_write(ctx->dsi[i], command, NULL, 0); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "cmd 0x%x failed for dsi = %d\n", - command, i); + dev_err(ctx->dev, "cmd 0x%x failed for dsi = %d\n", command, i); } } @@ -250,8 +247,7 @@ static int truly_dcs_write_buf(struct drm_panel *panel, for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { ret = mipi_dsi_dcs_write_buffer(ctx->dsi[i], buf, size); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "failed to tx cmd [%d], err: %d\n", i, ret); + dev_err(ctx->dev, "failed to tx cmd [%d], err: %d\n", i, ret); return ret; } } @@ -300,16 +296,14 @@ static int truly_nt35597_power_off(struct truly_nt35597 *ctx) ret = regulator_set_load(ctx->supplies[i].consumer, regulator_disable_loads[i]); if (ret) { - DRM_DEV_ERROR(ctx->dev, - "regulator_set_load failed %d\n", ret); + dev_err(ctx->dev, "regulator_set_load failed %d\n", ret); return ret; } } ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret) { - DRM_DEV_ERROR(ctx->dev, - "regulator_bulk_disable failed %d\n", ret); + dev_err(ctx->dev, "regulator_bulk_disable failed %d\n", ret); } return ret; } @@ -325,8 +319,7 @@ static int truly_nt35597_disable(struct drm_panel *panel) if (ctx->backlight) { ret = backlight_disable(ctx->backlight); if (ret < 0) - DRM_DEV_ERROR(ctx->dev, "backlight disable failed %d\n", - ret); + dev_err(ctx->dev, "backlight disable failed %d\n", ret); } ctx->enabled = false; @@ -346,9 +339,7 @@ static int truly_nt35597_unprepare(struct drm_panel *panel) ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_OFF); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "set_display_off cmd failed ret = %d\n", - ret); + dev_err(ctx->dev, "set_display_off cmd failed ret = %d\n", ret); } /* 120ms delay required here as per DCS spec */ @@ -356,13 +347,12 @@ static int truly_nt35597_unprepare(struct drm_panel *panel) ret = truly_dcs_write(panel, MIPI_DCS_ENTER_SLEEP_MODE); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "enter_sleep cmd failed ret = %d\n", ret); + dev_err(ctx->dev, "enter_sleep cmd failed ret = %d\n", ret); } ret = truly_nt35597_power_off(ctx); if (ret < 0) - DRM_DEV_ERROR(ctx->dev, "power_off failed ret = %d\n", ret); + dev_err(ctx->dev, "power_off failed ret = %d\n", ret); ctx->prepared = false; return ret; @@ -396,18 +386,14 @@ static int truly_nt35597_prepare(struct drm_panel *panel) panel_on_cmds[i].size, panel_on_cmds[i].commands); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "cmd set tx failed i = %d ret = %d\n", - i, ret); + dev_err(ctx->dev, "cmd set tx failed i = %d ret = %d\n", i, ret); goto power_off; } } ret = truly_dcs_write(panel, MIPI_DCS_EXIT_SLEEP_MODE); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "exit_sleep_mode cmd failed ret = %d\n", - ret); + dev_err(ctx->dev, "exit_sleep_mode cmd failed ret = %d\n", ret); goto power_off; } @@ -416,8 +402,7 @@ static int truly_nt35597_prepare(struct drm_panel *panel) ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_ON); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "set_display_on cmd failed ret = %d\n", ret); + dev_err(ctx->dev, "set_display_on cmd failed ret = %d\n", ret); goto power_off; } @@ -430,7 +415,7 @@ static int truly_nt35597_prepare(struct drm_panel *panel) power_off: if (truly_nt35597_power_off(ctx)) - DRM_DEV_ERROR(ctx->dev, "power_off failed\n"); + dev_err(ctx->dev, "power_off failed\n"); return ret; } @@ -445,8 +430,7 @@ static int truly_nt35597_enable(struct drm_panel *panel) if (ctx->backlight) { ret = backlight_enable(ctx->backlight); if (ret < 0) - DRM_DEV_ERROR(ctx->dev, "backlight enable failed %d\n", - ret); + dev_err(ctx->dev, "backlight enable failed %d\n", ret); } ctx->enabled = true; @@ -464,8 +448,7 @@ static int truly_nt35597_get_modes(struct drm_panel *panel, config = ctx->config; mode = drm_mode_create(connector->dev); if (!mode) { - DRM_DEV_ERROR(ctx->dev, - "failed to create a new display mode\n"); + dev_err(ctx->dev, "failed to create a new display mode\n"); return 0; } @@ -501,15 +484,13 @@ static int truly_nt35597_panel_add(struct truly_nt35597 *ctx) ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n", - PTR_ERR(ctx->reset_gpio)); + dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio)); return PTR_ERR(ctx->reset_gpio); } ctx->mode_gpio = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW); if (IS_ERR(ctx->mode_gpio)) { - DRM_DEV_ERROR(dev, "cannot get mode gpio %ld\n", - PTR_ERR(ctx->mode_gpio)); + dev_err(dev, "cannot get mode gpio %ld\n", PTR_ERR(ctx->mode_gpio)); return PTR_ERR(ctx->mode_gpio); } @@ -584,22 +565,21 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi) dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); if (!dsi1) { - DRM_DEV_ERROR(dev, - "failed to get remote node for dsi1_device\n"); + dev_err(dev, "failed to get remote node for dsi1_device\n"); return -ENODEV; } dsi1_host = of_find_mipi_dsi_host_by_node(dsi1); of_node_put(dsi1); if (!dsi1_host) { - DRM_DEV_ERROR(dev, "failed to find dsi host\n"); + dev_err(dev, "failed to find dsi host\n"); return -EPROBE_DEFER; } /* register the second DSI device */ dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info); if (IS_ERR(dsi1_device)) { - DRM_DEV_ERROR(dev, "failed to create dsi device\n"); + dev_err(dev, "failed to create dsi device\n"); return PTR_ERR(dsi1_device); } @@ -611,7 +591,7 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi) ret = truly_nt35597_panel_add(ctx); if (ret) { - DRM_DEV_ERROR(dev, "failed to add panel\n"); + dev_err(dev, "failed to add panel\n"); goto err_panel_add; } @@ -623,8 +603,7 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi) MIPI_DSI_CLOCK_NON_CONTINUOUS; ret = mipi_dsi_attach(dsi_dev); if (ret < 0) { - DRM_DEV_ERROR(dev, - "dsi attach failed i = %d\n", i); + dev_err(dev, "dsi attach failed i = %d\n", i); goto err_dsi_attach; } } diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c index a12976b497ce..eb43503ec97b 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c @@ -14,7 +14,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> struct visionox_rm69299 { struct drm_panel panel; @@ -69,16 +68,14 @@ static int visionox_rm69299_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); if (ret < 0) - DRM_DEV_ERROR(ctx->panel.dev, - "set_display_off cmd failed ret = %d\n", ret); + dev_err(ctx->panel.dev, "set_display_off cmd failed ret = %d\n", ret); /* 120ms delay required here as per DCS spec */ msleep(120); ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); if (ret < 0) { - DRM_DEV_ERROR(ctx->panel.dev, - "enter_sleep cmd failed ret = %d\n", ret); + dev_err(ctx->panel.dev, "enter_sleep cmd failed ret = %d\n", ret); } ret = visionox_rm69299_power_off(ctx); @@ -103,36 +100,31 @@ static int visionox_rm69299_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2); if (ret < 0) { - DRM_DEV_ERROR(ctx->panel.dev, - "cmd set tx 0 failed, ret = %d\n", ret); + dev_err(ctx->panel.dev, "cmd set tx 0 failed, ret = %d\n", ret); goto power_off; } ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2); if (ret < 0) { - DRM_DEV_ERROR(ctx->panel.dev, - "cmd set tx 1 failed, ret = %d\n", ret); + dev_err(ctx->panel.dev, "cmd set tx 1 failed, ret = %d\n", ret); goto power_off; } ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2); if (ret < 0) { - DRM_DEV_ERROR(ctx->panel.dev, - "cmd set tx 2 failed, ret = %d\n", ret); + dev_err(ctx->panel.dev, "cmd set tx 2 failed, ret = %d\n", ret); goto power_off; } ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2); if (ret < 0) { - DRM_DEV_ERROR(ctx->panel.dev, - "cmd set tx 3 failed, ret = %d\n", ret); + dev_err(ctx->panel.dev, "cmd set tx 3 failed, ret = %d\n", ret); goto power_off; } ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); if (ret < 0) { - DRM_DEV_ERROR(ctx->panel.dev, - "exit_sleep_mode cmd failed ret = %d\n", ret); + dev_err(ctx->panel.dev, "exit_sleep_mode cmd failed ret = %d\n", ret); goto power_off; } @@ -141,8 +133,7 @@ static int visionox_rm69299_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); if (ret < 0) { - DRM_DEV_ERROR(ctx->panel.dev, - "set_display_on cmd failed ret = %d\n", ret); + dev_err(ctx->panel.dev, "set_display_on cmd failed ret = %d\n", ret); goto power_off; } @@ -179,8 +170,7 @@ static int visionox_rm69299_get_modes(struct drm_panel *panel, mode = drm_mode_create(connector->dev); if (!mode) { - DRM_DEV_ERROR(ctx->panel.dev, - "failed to create a new display mode\n"); + dev_err(ctx->panel.dev, "failed to create a new display mode\n"); return 0; } @@ -225,8 +215,7 @@ static int visionox_rm69299_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n", - PTR_ERR(ctx->reset_gpio)); + dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio)); return PTR_ERR(ctx->reset_gpio); } @@ -242,23 +231,19 @@ static int visionox_rm69299_probe(struct mipi_dsi_device *dsi) MIPI_DSI_CLOCK_NON_CONTINUOUS; ret = mipi_dsi_attach(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "dsi attach failed ret = %d\n", ret); + dev_err(dev, "dsi attach failed ret = %d\n", ret); goto err_dsi_attach; } ret = regulator_set_load(ctx->supplies[0].consumer, 32000); if (ret) { - DRM_DEV_ERROR(dev, - "regulator set load failed for vdda supply ret = %d\n", - ret); + dev_err(dev, "regulator set load failed for vdda supply ret = %d\n", ret); goto err_set_load; } ret = regulator_set_load(ctx->supplies[1].consumer, 13200); if (ret) { - DRM_DEV_ERROR(dev, - "regulator set load failed for vdd3p3 supply ret = %d\n", - ret); + dev_err(dev, "regulator set load failed for vdd3p3 supply ret = %d\n", ret); goto err_set_load; } diff --git a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c index 06341deb60ca..55172d63a922 100644 --- a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c +++ b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c @@ -12,7 +12,6 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> -#include <drm/drm_print.h> #include <video/display_timing.h> #include <video/mipi_display.h> @@ -135,7 +134,7 @@ static int xpp055c272_init_sequence(struct xpp055c272 *ctx) msleep(60); - DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n"); + dev_dbg(dev, "Panel init sequence done\n"); return 0; } @@ -150,13 +149,11 @@ static int xpp055c272_unprepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) - DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", - ret); + dev_err(ctx->dev, "failed to set display off: %d\n", ret); mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", - ret); + dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); return ret; } @@ -177,17 +174,15 @@ static int xpp055c272_prepare(struct drm_panel *panel) if (ctx->prepared) return 0; - DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); + dev_dbg(ctx->dev, "Resetting the panel\n"); ret = regulator_enable(ctx->vci); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable vci supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); return ret; } ret = regulator_enable(ctx->iovcc); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable iovcc supply: %d\n", ret); + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); goto disable_vci; } @@ -201,14 +196,13 @@ static int xpp055c272_prepare(struct drm_panel *panel) ret = xpp055c272_init_sequence(ctx); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", - ret); + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); goto disable_iovcc; } ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); goto disable_iovcc; } @@ -217,7 +211,7 @@ static int xpp055c272_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_display_on(dsi); if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret); + dev_err(ctx->dev, "Failed to set display on: %d\n", ret); goto disable_iovcc; } @@ -256,9 +250,9 @@ static int xpp055c272_get_modes(struct drm_panel *panel, mode = drm_mode_duplicate(connector->dev, &default_mode); if (!mode) { - DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); + dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", + default_mode.hdisplay, default_mode.vdisplay, + drm_mode_vrefresh(&default_mode)); return -ENOMEM; } @@ -290,7 +284,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); + dev_err(dev, "cannot get reset gpio\n"); return PTR_ERR(ctx->reset_gpio); } @@ -298,9 +292,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->vci)) { ret = PTR_ERR(ctx->vci); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request vci regulator: %d\n", - ret); + dev_err(dev, "Failed to request vci regulator: %d\n", ret); return ret; } @@ -308,9 +300,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) if (IS_ERR(ctx->iovcc)) { ret = PTR_ERR(ctx->iovcc); if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request iovcc regulator: %d\n", - ret); + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); return ret; } @@ -334,7 +324,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) ret = mipi_dsi_attach(dsi); if (ret < 0) { - DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); drm_panel_remove(&ctx->panel); return ret; } @@ -349,13 +339,11 @@ static void xpp055c272_shutdown(struct mipi_dsi_device *dsi) ret = drm_panel_unprepare(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); ret = drm_panel_disable(&ctx->panel); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", - ret); + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } static int xpp055c272_remove(struct mipi_dsi_device *dsi) @@ -367,8 +355,7 @@ static int xpp055c272_remove(struct mipi_dsi_device *dsi) ret = mipi_dsi_detach(dsi); if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", - ret); + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index 413987038fbf..8ab025d0035f 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -1,20 +1,29 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright 2019 Collabora ltd. */ + +#include <linux/clk.h> #include <linux/devfreq.h> #include <linux/devfreq_cooling.h> #include <linux/platform_device.h> #include <linux/pm_opp.h> -#include <linux/clk.h> -#include <linux/regulator/consumer.h> #include "panfrost_device.h" #include "panfrost_devfreq.h" -#include "panfrost_features.h" -#include "panfrost_issues.h" -#include "panfrost_gpu.h" -#include "panfrost_regs.h" -static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev); +static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq) +{ + ktime_t now, last; + + now = ktime_get(); + last = pfdevfreq->time_last_update; + + if (pfdevfreq->busy_count > 0) + pfdevfreq->busy_time += ktime_sub(now, last); + else + pfdevfreq->idle_time += ktime_sub(now, last); + + pfdevfreq->time_last_update = now; +} static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) @@ -34,30 +43,37 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, return 0; } -static void panfrost_devfreq_reset(struct panfrost_device *pfdev) +static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq) { - pfdev->devfreq.busy_time = 0; - pfdev->devfreq.idle_time = 0; - pfdev->devfreq.time_last_update = ktime_get(); + pfdevfreq->busy_time = 0; + pfdevfreq->idle_time = 0; + pfdevfreq->time_last_update = ktime_get(); } static int panfrost_devfreq_get_dev_status(struct device *dev, struct devfreq_dev_status *status) { struct panfrost_device *pfdev = dev_get_drvdata(dev); - - panfrost_devfreq_update_utilization(pfdev); + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + unsigned long irqflags; status->current_frequency = clk_get_rate(pfdev->clock); - status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time, - pfdev->devfreq.idle_time)); - status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time); + spin_lock_irqsave(&pfdevfreq->lock, irqflags); + + panfrost_devfreq_update_utilization(pfdevfreq); + + status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, + pfdevfreq->idle_time)); + + status->busy_time = ktime_to_ns(pfdevfreq->busy_time); + + panfrost_devfreq_reset(pfdevfreq); - panfrost_devfreq_reset(pfdev); + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); - dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time, - status->total_time, + dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", + status->busy_time, status->total_time, status->busy_time / (status->total_time / 100), status->current_frequency / 1000 / 1000); @@ -77,21 +93,43 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) unsigned long cur_freq; struct device *dev = &pfdev->pdev->dev; struct devfreq *devfreq; + struct opp_table *opp_table; struct thermal_cooling_device *cooling; + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names, + pfdev->comp->num_supplies); + if (IS_ERR(opp_table)) { + ret = PTR_ERR(opp_table); + /* Continue if the optional regulator is missing */ + if (ret != -ENODEV) { + DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); + goto err_fini; + } + } else { + pfdevfreq->regulators_opp_table = opp_table; + } ret = dev_pm_opp_of_add_table(dev); - if (ret == -ENODEV) /* Optional, continue without devfreq */ - return 0; - else if (ret) - return ret; + if (ret) { + /* Optional, continue without devfreq */ + if (ret == -ENODEV) + ret = 0; + goto err_fini; + } + pfdevfreq->opp_of_table_added = true; + + spin_lock_init(&pfdevfreq->lock); - panfrost_devfreq_reset(pfdev); + panfrost_devfreq_reset(pfdevfreq); cur_freq = clk_get_rate(pfdev->clock); opp = devfreq_recommended_opp(dev, &cur_freq, 0); - if (IS_ERR(opp)) - return PTR_ERR(opp); + if (IS_ERR(opp)) { + ret = PTR_ERR(opp); + goto err_fini; + } panfrost_devfreq_profile.initial_freq = cur_freq; dev_pm_opp_put(opp); @@ -100,75 +138,94 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); if (IS_ERR(devfreq)) { DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); - dev_pm_opp_of_remove_table(dev); - return PTR_ERR(devfreq); + ret = PTR_ERR(devfreq); + goto err_fini; } - pfdev->devfreq.devfreq = devfreq; + pfdevfreq->devfreq = devfreq; cooling = of_devfreq_cooling_register(dev->of_node, devfreq); if (IS_ERR(cooling)) DRM_DEV_INFO(dev, "Failed to register cooling device\n"); else - pfdev->devfreq.cooling = cooling; + pfdevfreq->cooling = cooling; return 0; + +err_fini: + panfrost_devfreq_fini(pfdev); + return ret; } void panfrost_devfreq_fini(struct panfrost_device *pfdev) { - if (pfdev->devfreq.cooling) - devfreq_cooling_unregister(pfdev->devfreq.cooling); - dev_pm_opp_of_remove_table(&pfdev->pdev->dev); + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + if (pfdevfreq->cooling) { + devfreq_cooling_unregister(pfdevfreq->cooling); + pfdevfreq->cooling = NULL; + } + + if (pfdevfreq->opp_of_table_added) { + dev_pm_opp_of_remove_table(&pfdev->pdev->dev); + pfdevfreq->opp_of_table_added = false; + } + + if (pfdevfreq->regulators_opp_table) { + dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table); + pfdevfreq->regulators_opp_table = NULL; + } } void panfrost_devfreq_resume(struct panfrost_device *pfdev) { - if (!pfdev->devfreq.devfreq) + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + if (!pfdevfreq->devfreq) return; - panfrost_devfreq_reset(pfdev); + panfrost_devfreq_reset(pfdevfreq); - devfreq_resume_device(pfdev->devfreq.devfreq); + devfreq_resume_device(pfdevfreq->devfreq); } void panfrost_devfreq_suspend(struct panfrost_device *pfdev) { - if (!pfdev->devfreq.devfreq) + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + if (!pfdevfreq->devfreq) return; - devfreq_suspend_device(pfdev->devfreq.devfreq); + devfreq_suspend_device(pfdevfreq->devfreq); } -static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) +void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq) { - ktime_t now; - ktime_t last; + unsigned long irqflags; - if (!pfdev->devfreq.devfreq) + if (!pfdevfreq->devfreq) return; - now = ktime_get(); - last = pfdev->devfreq.time_last_update; + spin_lock_irqsave(&pfdevfreq->lock, irqflags); - if (atomic_read(&pfdev->devfreq.busy_count) > 0) - pfdev->devfreq.busy_time += ktime_sub(now, last); - else - pfdev->devfreq.idle_time += ktime_sub(now, last); + panfrost_devfreq_update_utilization(pfdevfreq); - pfdev->devfreq.time_last_update = now; -} + pfdevfreq->busy_count++; -void panfrost_devfreq_record_busy(struct panfrost_device *pfdev) -{ - panfrost_devfreq_update_utilization(pfdev); - atomic_inc(&pfdev->devfreq.busy_count); + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); } -void panfrost_devfreq_record_idle(struct panfrost_device *pfdev) +void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq) { - int count; + unsigned long irqflags; + + if (!pfdevfreq->devfreq) + return; + + spin_lock_irqsave(&pfdevfreq->lock, irqflags); + + panfrost_devfreq_update_utilization(pfdevfreq); + + WARN_ON(--pfdevfreq->busy_count < 0); - panfrost_devfreq_update_utilization(pfdev); - count = atomic_dec_if_positive(&pfdev->devfreq.busy_count); - WARN_ON(count < 0); + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); } diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h index 0611beffc8d0..db6ea48e21f9 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h @@ -4,13 +4,39 @@ #ifndef __PANFROST_DEVFREQ_H__ #define __PANFROST_DEVFREQ_H__ +#include <linux/spinlock.h> +#include <linux/ktime.h> + +struct devfreq; +struct opp_table; +struct thermal_cooling_device; + +struct panfrost_device; + +struct panfrost_devfreq { + struct devfreq *devfreq; + struct opp_table *regulators_opp_table; + struct thermal_cooling_device *cooling; + bool opp_of_table_added; + + ktime_t busy_time; + ktime_t idle_time; + ktime_t time_last_update; + int busy_count; + /* + * Protect busy_time, idle_time, time_last_update and busy_count + * because these can be updated concurrently between multiple jobs. + */ + spinlock_t lock; +}; + int panfrost_devfreq_init(struct panfrost_device *pfdev); void panfrost_devfreq_fini(struct panfrost_device *pfdev); void panfrost_devfreq_resume(struct panfrost_device *pfdev); void panfrost_devfreq_suspend(struct panfrost_device *pfdev); -void panfrost_devfreq_record_busy(struct panfrost_device *pfdev); -void panfrost_devfreq_record_idle(struct panfrost_device *pfdev); +void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq); +void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq); #endif /* __PANFROST_DEVFREQ_H__ */ diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index b172087eee6a..e6896733838a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) { int ret, i; - if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators), - "Too many supplies in compatible structure.\n")) - return -EINVAL; + pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies, + sizeof(*pfdev->regulators), + GFP_KERNEL); + if (!pfdev->regulators) + return -ENOMEM; for (i = 0; i < pfdev->comp->num_supplies; i++) pfdev->regulators[i].supply = pfdev->comp->supply_names[i]; @@ -119,8 +121,10 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) static void panfrost_regulator_fini(struct panfrost_device *pfdev) { - regulator_bulk_disable(pfdev->comp->num_supplies, - pfdev->regulators); + if (!pfdev->regulators) + return; + + regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators); } static void panfrost_pm_domain_fini(struct panfrost_device *pfdev) @@ -214,58 +218,70 @@ int panfrost_device_init(struct panfrost_device *pfdev) return err; } - err = panfrost_regulator_init(pfdev); - if (err) - goto err_out0; + err = panfrost_devfreq_init(pfdev); + if (err) { + if (err != -EPROBE_DEFER) + dev_err(pfdev->dev, "devfreq init failed %d\n", err); + goto out_clk; + } + + /* OPP will handle regulators */ + if (!pfdev->pfdevfreq.opp_of_table_added) { + err = panfrost_regulator_init(pfdev); + if (err) + goto out_devfreq; + } err = panfrost_reset_init(pfdev); if (err) { dev_err(pfdev->dev, "reset init failed %d\n", err); - goto err_out1; + goto out_regulator; } err = panfrost_pm_domain_init(pfdev); if (err) - goto err_out2; + goto out_reset; res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); if (IS_ERR(pfdev->iomem)) { dev_err(pfdev->dev, "failed to ioremap iomem\n"); err = PTR_ERR(pfdev->iomem); - goto err_out3; + goto out_pm_domain; } err = panfrost_gpu_init(pfdev); if (err) - goto err_out3; + goto out_pm_domain; err = panfrost_mmu_init(pfdev); if (err) - goto err_out4; + goto out_gpu; err = panfrost_job_init(pfdev); if (err) - goto err_out5; + goto out_mmu; err = panfrost_perfcnt_init(pfdev); if (err) - goto err_out6; + goto out_job; return 0; -err_out6: +out_job: panfrost_job_fini(pfdev); -err_out5: +out_mmu: panfrost_mmu_fini(pfdev); -err_out4: +out_gpu: panfrost_gpu_fini(pfdev); -err_out3: +out_pm_domain: panfrost_pm_domain_fini(pfdev); -err_out2: +out_reset: panfrost_reset_fini(pfdev); -err_out1: +out_regulator: panfrost_regulator_fini(pfdev); -err_out0: +out_devfreq: + panfrost_devfreq_fini(pfdev); +out_clk: panfrost_clk_fini(pfdev); return err; } @@ -278,6 +294,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev) panfrost_gpu_fini(pfdev); panfrost_pm_domain_fini(pfdev); panfrost_reset_fini(pfdev); + panfrost_devfreq_fini(pfdev); panfrost_regulator_fini(pfdev); panfrost_clk_fini(pfdev); } diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index c30c719a8059..953f7536a773 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -13,6 +13,8 @@ #include <drm/drm_mm.h> #include <drm/gpu_scheduler.h> +#include "panfrost_devfreq.h" + struct panfrost_device; struct panfrost_mmu; struct panfrost_job_slot; @@ -20,7 +22,6 @@ struct panfrost_job; struct panfrost_perfcnt; #define NUM_JOB_SLOTS 3 -#define MAX_REGULATORS 2 #define MAX_PM_DOMAINS 3 struct panfrost_features { @@ -79,7 +80,7 @@ struct panfrost_device { void __iomem *iomem; struct clk *clock; struct clk *bus_clock; - struct regulator_bulk_data regulators[MAX_REGULATORS]; + struct regulator_bulk_data *regulators; struct reset_control *rstc; /* pm_domains for devices with more than one. */ struct device *pm_domain_devs[MAX_PM_DOMAINS]; @@ -107,14 +108,7 @@ struct panfrost_device { struct list_head shrinker_list; struct shrinker shrinker; - struct { - struct devfreq *devfreq; - struct thermal_cooling_device *cooling; - ktime_t busy_time; - ktime_t idle_time; - ktime_t time_last_update; - atomic_t busy_count; - } devfreq; + struct panfrost_devfreq pfdevfreq; }; struct panfrost_mmu { diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index ada51df9a7a3..36463c89e966 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -14,7 +14,6 @@ #include <drm/drm_utils.h> #include "panfrost_device.h" -#include "panfrost_devfreq.h" #include "panfrost_gem.h" #include "panfrost_mmu.h" #include "panfrost_job.h" @@ -606,13 +605,6 @@ static int panfrost_probe(struct platform_device *pdev) goto err_out0; } - err = panfrost_devfreq_init(pfdev); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Fatal error during devfreq init\n"); - goto err_out1; - } - pm_runtime_set_active(pfdev->dev); pm_runtime_mark_last_busy(pfdev->dev); pm_runtime_enable(pfdev->dev); @@ -625,16 +617,14 @@ static int panfrost_probe(struct platform_device *pdev) */ err = drm_dev_register(ddev, 0); if (err < 0) - goto err_out2; + goto err_out1; panfrost_gem_shrinker_init(ddev); return 0; -err_out2: - pm_runtime_disable(pfdev->dev); - panfrost_devfreq_fini(pfdev); err_out1: + pm_runtime_disable(pfdev->dev); panfrost_device_fini(pfdev); err_out0: drm_dev_put(ddev); @@ -650,7 +640,6 @@ static int panfrost_remove(struct platform_device *pdev) panfrost_gem_shrinker_cleanup(ddev); pm_runtime_get_sync(pfdev->dev); - panfrost_devfreq_fini(pfdev); panfrost_device_fini(pfdev); pm_runtime_put_sync_suspend(pfdev->dev); pm_runtime_disable(pfdev->dev); @@ -677,6 +666,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "arm,mali-t830", .data = &default_data, }, { .compatible = "arm,mali-t860", .data = &default_data, }, { .compatible = "arm,mali-t880", .data = &default_data, }, + { .compatible = "arm,mali-bifrost", .data = &default_data, }, {} }; MODULE_DEVICE_TABLE(of, dt_match); diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index f2c1ddc41a9b..e0f190e43813 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -10,6 +10,7 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include "panfrost_device.h" #include "panfrost_features.h" @@ -368,7 +369,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev) u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev) { - if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) - return gpu_read(pfdev, GPU_LATEST_FLUSH_ID); + u32 flush_id; + + if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) { + /* Flush reduction only makes sense when the GPU is kept powered on between jobs */ + if (pm_runtime_get_if_in_use(pfdev->dev)) { + flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID); + pm_runtime_put(pfdev->dev); + return flush_id; + } + } + return 0; } diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 360146f6f3d9..30e7b7196dab 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -145,7 +145,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) u64 jc_head = job->jc; int ret; - panfrost_devfreq_record_busy(pfdev); + panfrost_devfreq_record_busy(&pfdev->pfdevfreq); ret = pm_runtime_get_sync(pfdev->dev); if (ret < 0) @@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) for (i = 0; i < NUM_JOB_SLOTS; i++) { if (pfdev->jobs[i]) { pm_runtime_put_noidle(pfdev->dev); - panfrost_devfreq_record_idle(pfdev); + panfrost_devfreq_record_idle(&pfdev->pfdevfreq); pfdev->jobs[i] = NULL; } } @@ -478,7 +478,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data) pfdev->jobs[j] = NULL; panfrost_mmu_as_put(pfdev, &job->file_priv->mmu); - panfrost_devfreq_record_idle(pfdev); + panfrost_devfreq_record_idle(&pfdev->pfdevfreq); dma_fence_signal_locked(job->done_fence); pm_runtime_put_autosuspend(pfdev->dev); @@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev) struct panfrost_job_slot *js = pfdev->js; int i; - /* Check whether the hardware is idle */ - if (atomic_read(&pfdev->devfreq.busy_count)) - return false; - for (i = 0; i < NUM_JOB_SLOTS; i++) { /* If there are any jobs in the HW queue, we're not idle */ if (atomic_read(&js->queue[i].sched.hw_rq_count)) diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c index ec4695cf3caf..fdbc8d949135 100644 --- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c +++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c @@ -83,11 +83,13 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, ret = pm_runtime_get_sync(pfdev->dev); if (ret < 0) - return ret; + goto err_put_pm; bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize); - if (IS_ERR(bo)) - return PTR_ERR(bo); + if (IS_ERR(bo)) { + ret = PTR_ERR(bo); + goto err_put_pm; + } /* Map the perfcnt buf in the address space attached to file_priv. */ ret = panfrost_gem_open(&bo->base, file_priv); @@ -168,6 +170,8 @@ err_close_bo: panfrost_gem_close(&bo->base, file_priv); err_put_bo: drm_gem_object_put(&bo->base); +err_put_pm: + pm_runtime_put(pfdev->dev); return ret; } diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 96e58fda75d8..46b0d1c4a16c 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -10,18 +10,11 @@ */ /** - * DOC: ARM PrimeCell PL111 CLCD Driver + * DOC: ARM PrimeCell PL110 and PL111 CLCD Driver * - * The PL111 is a simple LCD controller that can support TFT and STN - * displays. This driver exposes a standard KMS interface for them. - * - * This driver uses the same Device Tree binding as the fbdev CLCD - * driver. While the fbdev driver supports panels that may be - * connected to the CLCD internally to the CLCD driver, in DRM the - * panels get split out to drivers/gpu/drm/panels/. This means that, - * in converting from using fbdev to using DRM, you also need to write - * a panel driver (which may be as simple as an entry in - * panel-simple.c). + * The PL110/PL111 is a simple LCD controller that can support TFT + * and STN displays. This driver exposes a standard KMS interface + * for them. * * The driver currently doesn't expose the cursor. The DRM API for * cursors requires support for 64x64 ARGB8888 cursor images, while @@ -29,16 +22,13 @@ * cursors. While one could imagine trying to hack something together * to look at the ARGB8888 and program reasonable in monochrome, we * just don't expose the cursor at all instead, and leave cursor - * support to the X11 software cursor layer. + * support to the application software cursor layer. * * TODO: * * - Fix race between setting plane base address and getting IRQ for * vsync firing the pageflip completion. * - * - Use the "max-memory-bandwidth" DT property to filter the - * supported formats. - * * - Read back hardware state at boot to skip reprogramming the * hardware when doing a no-op modeset. * diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index 798f9dd7ad75..54e3c3a97440 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -588,7 +588,7 @@ static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stal { int ret; - ret = qxl_bo_reserve(surf, false); + ret = qxl_bo_reserve(surf); if (ret) return ret; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 099dca48b0ff..6063f3a15329 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -26,6 +26,7 @@ #include <linux/crc32.h> #include <linux/delay.h> +#include <drm/drm_drv.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> @@ -162,7 +163,8 @@ static void qxl_update_offset_props(struct qxl_device *qdev) void qxl_display_read_client_monitors_config(struct qxl_device *qdev) { struct drm_device *dev = &qdev->ddev; - int status, retries; + struct drm_modeset_acquire_ctx ctx; + int status, retries, ret; for (retries = 0; retries < 10; retries++) { status = qxl_display_copy_rom_client_monitors_config(qdev); @@ -183,9 +185,9 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev) return; } - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); qxl_update_offset_props(qdev); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); if (!drm_helper_hpd_irq_event(dev)) { /* notify that the monitor configuration changed, to adjust at the arbitrary resolution */ @@ -403,18 +405,17 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, struct qxl_device *qdev = to_qxl(fb->dev); struct drm_clip_rect norect; struct qxl_bo *qobj; + struct drm_modeset_acquire_ctx ctx; bool is_primary; - int inc = 1; + int inc = 1, ret; - drm_modeset_lock_all(fb->dev); + DRM_MODESET_LOCK_ALL_BEGIN(fb->dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); qobj = gem_to_qxl_bo(fb->obj[0]); /* if we aren't primary surface ignore this */ is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary; - if (!is_primary) { - drm_modeset_unlock_all(fb->dev); - return 0; - } + if (!is_primary) + goto out_lock_end; if (!num_clips) { num_clips = 1; @@ -430,7 +431,8 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, qxl_draw_dirty_fb(qdev, fb, qobj, flags, color, clips, num_clips, inc, 0); - drm_modeset_unlock_all(fb->dev); +out_lock_end: + DRM_MODESET_LOCK_ALL_END(fb->dev, ctx, ret); return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 13872b882775..6e7f16f4cec7 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -96,7 +96,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto disable_pci; - if (is_vga(pdev)) { + if (is_vga(pdev) && pdev->revision < 5) { ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO); if (ret) { DRM_ERROR("can't get legacy vga ioports\n"); @@ -127,7 +127,7 @@ modeset_cleanup: unload: qxl_device_fini(qdev); put_vga: - if (is_vga(pdev)) + if (is_vga(pdev) && pdev->revision < 5) vga_put(pdev, VGA_RSRC_LEGACY_IO); disable_pci: pci_disable_device(pdev); @@ -155,7 +155,7 @@ qxl_pci_remove(struct pci_dev *pdev) drm_dev_unregister(dev); drm_atomic_helper_shutdown(dev); - if (is_vga(pdev)) + if (is_vga(pdev) && pdev->revision < 5) vga_put(pdev, VGA_RSRC_LEGACY_IO); } diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 9691449aefdb..aae90a9ee1db 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -350,7 +350,7 @@ int qxl_mode_dumb_mmap(struct drm_file *filp, int qxl_ttm_init(struct qxl_device *qdev); void qxl_ttm_fini(struct qxl_device *qdev); int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); /* qxl image */ diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index 8f605d5cc149..5cea6eea72ab 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -322,7 +322,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data, qobj = gem_to_qxl_bo(gobj); - ret = qxl_bo_reserve(qobj, false); + ret = qxl_bo_reserve(qobj); if (ret) goto out; diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index 80e7a17aaddd..f838b6d689aa 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -284,7 +284,7 @@ int qxl_bo_pin(struct qxl_bo *bo) { int r; - r = qxl_bo_reserve(bo, false); + r = qxl_bo_reserve(bo); if (r) return r; @@ -302,7 +302,7 @@ int qxl_bo_unpin(struct qxl_bo *bo) { int r; - r = qxl_bo_reserve(bo, false); + r = qxl_bo_reserve(bo); if (r) return r; diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h index 21fa81048f4f..6b434e5ef795 100644 --- a/drivers/gpu/drm/qxl/qxl_object.h +++ b/drivers/gpu/drm/qxl/qxl_object.h @@ -27,11 +27,11 @@ #include "qxl_drv.h" -static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait) +static inline int qxl_bo_reserve(struct qxl_bo *bo) { int r; - r = ttm_bo_reserve(&bo->tbo, true, no_wait, NULL); + r = ttm_bo_reserve(&bo->tbo, true, false, NULL); if (unlikely(r != 0)) { if (r != -ERESTARTSYS) { struct drm_device *ddev = bo->tbo.base.dev; diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index bf9dc451583a..7aae0a96f043 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -48,31 +48,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev) return qdev; } -static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, - struct ttm_mem_type_manager *man) -{ - switch (type) { - case TTM_PL_SYSTEM: - /* System memory */ - man->flags = 0; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case TTM_PL_VRAM: - case TTM_PL_PRIV: - /* "On-card" video ram */ - man->func = &ttm_bo_manager_func; - man->flags = TTM_MEMTYPE_FLAG_FIXED; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type); - return -EINVAL; - } - return 0; -} - static void qxl_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement) { @@ -96,16 +71,10 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo, } int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { struct qxl_device *qdev = qxl_get_qdev(bdev); - mem->bus.addr = NULL; - mem->bus.offset = 0; - mem->bus.size = mem->num_pages << PAGE_SHIFT; - mem->bus.base = 0; - mem->bus.is_iomem = false; - switch (mem->mem_type) { case TTM_PL_SYSTEM: /* system memory */ @@ -136,7 +105,7 @@ struct qxl_ttm_tt { }; static int qxl_ttm_backend_bind(struct ttm_tt *ttm, - struct ttm_mem_reg *bo_mem) + struct ttm_resource *bo_mem) { struct qxl_ttm_tt *gtt = (void *)ttm; @@ -188,9 +157,9 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo, } static void qxl_move_null(struct ttm_buffer_object *bo, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; BUG_ON(old_mem->mm_node != NULL); *old_mem = *new_mem; @@ -199,9 +168,9 @@ static void qxl_move_null(struct ttm_buffer_object *bo, static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; int ret; ret = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu); @@ -217,7 +186,7 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict, static void qxl_bo_move_notify(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct qxl_bo *qbo; struct qxl_device *qdev; @@ -233,7 +202,6 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo, static struct ttm_bo_driver qxl_bo_driver = { .ttm_tt_create = &qxl_ttm_tt_create, - .init_mem_type = &qxl_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = &qxl_evict_flags, .move = &qxl_bo_move, @@ -241,6 +209,14 @@ static struct ttm_bo_driver qxl_bo_driver = { .move_notify = &qxl_bo_move_notify, }; +static int qxl_ttm_init_mem_type(struct qxl_device *qdev, + unsigned int type, + uint64_t size) +{ + return ttm_range_man_init(&qdev->mman.bdev, type, TTM_PL_MASK_CACHING, + TTM_PL_FLAG_CACHED, false, size); +} + int qxl_ttm_init(struct qxl_device *qdev) { int r; @@ -258,14 +234,13 @@ int qxl_ttm_init(struct qxl_device *qdev) } /* NOTE: this includes the framebuffer (aka surface 0) */ num_io_pages = qdev->rom->ram_header_offset / PAGE_SIZE; - r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_VRAM, - num_io_pages); + r = qxl_ttm_init_mem_type(qdev, TTM_PL_VRAM, num_io_pages); if (r) { DRM_ERROR("Failed initializing VRAM heap.\n"); return r; } - r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_PRIV, - qdev->surfaceram_size / PAGE_SIZE); + r = qxl_ttm_init_mem_type(qdev, TTM_PL_PRIV, + qdev->surfaceram_size / PAGE_SIZE); if (r) { DRM_ERROR("Failed initializing Surfaces heap.\n"); return r; @@ -281,8 +256,8 @@ int qxl_ttm_init(struct qxl_device *qdev) void qxl_ttm_fini(struct qxl_device *qdev) { - ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM); - ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV); + ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_VRAM); + ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_PRIV); ttm_bo_device_release(&qdev->mman.bdev); DRM_INFO("qxl: ttm finalized\n"); } @@ -293,12 +268,10 @@ void qxl_ttm_fini(struct qxl_device *qdev) static int qxl_mm_dump_table(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; - struct drm_mm *mm = (struct drm_mm *)node->info_ent->data; + struct ttm_resource_manager *man = (struct ttm_resource_manager *)node->info_ent->data; struct drm_printer p = drm_seq_file_printer(m); - spin_lock(&ttm_bo_glob.lru_lock); - drm_mm_print(mm, &p); - spin_unlock(&ttm_bo_glob.lru_lock); + ttm_resource_manager_debug(man, &p); return 0; } #endif @@ -319,9 +292,9 @@ void qxl_ttm_debugfs_init(struct qxl_device *qdev) qxl_mem_types_list[i].show = &qxl_mm_dump_table; qxl_mem_types_list[i].driver_features = 0; if (i == 0) - qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_VRAM].priv; + qxl_mem_types_list[i].data = ttm_manager_type(&qdev->mman.bdev, TTM_PL_VRAM); else - qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_PRIV].priv; + qxl_mem_types_list[i].data = ttm_manager_type(&qdev->mman.bdev, TTM_PL_PRIV); } qxl_debugfs_add_files(qdev, qxl_mem_types_list, i); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b7c3fb2bfb54..cc4f58d16589 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2857,7 +2857,7 @@ int radeon_vm_clear_invalids(struct radeon_device *rdev, struct radeon_vm *vm); int radeon_vm_bo_update(struct radeon_device *rdev, struct radeon_bo_va *bo_va, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); void radeon_vm_bo_invalidate(struct radeon_device *rdev, struct radeon_bo *bo); struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index f178ba321715..3808a753127b 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -72,8 +72,8 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev) { void *ptr; - ptr = pci_alloc_consistent(rdev->pdev, rdev->gart.table_size, - &rdev->gart.table_addr); + ptr = dma_alloc_coherent(&rdev->pdev->dev, rdev->gart.table_size, + &rdev->gart.table_addr, GFP_KERNEL); if (ptr == NULL) { return -ENOMEM; } @@ -85,7 +85,6 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev) } #endif rdev->gart.ptr = ptr; - memset((void *)rdev->gart.ptr, 0, rdev->gart.table_size); return 0; } @@ -110,9 +109,8 @@ void radeon_gart_table_ram_free(struct radeon_device *rdev) rdev->gart.table_size >> PAGE_SHIFT); } #endif - pci_free_consistent(rdev->pdev, rdev->gart.table_size, - (void *)rdev->gart.ptr, - rdev->gart.table_addr); + dma_free_coherent(&rdev->pdev->dev, rdev->gart.table_size, + (void *)rdev->gart.ptr, rdev->gart.table_addr); rdev->gart.ptr = NULL; rdev->gart.table_addr = 0; } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 44157ada9b0e..7f5dfe04789e 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -224,9 +224,9 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, { struct radeon_device *rdev = dev->dev_private; struct drm_radeon_gem_info *args = data; - struct ttm_mem_type_manager *man; + struct ttm_resource_manager *man; - man = &rdev->mman.bdev.man[TTM_PL_VRAM]; + man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM); args->vram_size = (u64)man->size << PAGE_SHIFT; args->vram_visible = rdev->mc.visible_vram_size; diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index f3dee01250da..bb7582afd803 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -775,7 +775,7 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, void radeon_bo_move_notify(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct radeon_bo *rbo; diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 60275b822f79..44b47241ee42 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -165,7 +165,7 @@ extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, bool force_drop); extern void radeon_bo_move_notify(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *new_mem); + struct ttm_resource *new_mem); extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo); extern int radeon_bo_get_surface_reg(struct radeon_bo *bo); extern void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence, diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 004344dce140..3a4372ea74b9 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -66,53 +66,20 @@ struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev) return rdev; } -static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, - struct ttm_mem_type_manager *man) +static int radeon_ttm_init_vram(struct radeon_device *rdev) { - struct radeon_device *rdev; - - rdev = radeon_get_rdev(bdev); + return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_VRAM, + TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC, + TTM_PL_FLAG_WC, false, + rdev->mc.real_vram_size >> PAGE_SHIFT); +} - switch (type) { - case TTM_PL_SYSTEM: - /* System memory */ - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case TTM_PL_TT: - man->func = &ttm_bo_manager_func; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; -#if IS_ENABLED(CONFIG_AGP) - if (rdev->flags & RADEON_IS_AGP) { - if (!rdev->ddev->agp) { - DRM_ERROR("AGP is not enabled for memory type %u\n", - (unsigned)type); - return -EINVAL; - } - if (!rdev->ddev->agp->cant_use_aperture) - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; - } -#endif - break; - case TTM_PL_VRAM: - /* "On-card" video ram */ - man->func = &ttm_bo_manager_func; - man->flags = TTM_MEMTYPE_FLAG_FIXED | - TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; - break; - default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); - return -EINVAL; - } - return 0; +static int radeon_ttm_init_gtt(struct radeon_device *rdev) +{ + return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_TT, + TTM_PL_MASK_CACHING, + TTM_PL_FLAG_CACHED, true, + rdev->mc.gtt_size >> PAGE_SHIFT); } static void radeon_evict_flags(struct ttm_buffer_object *bo, @@ -182,9 +149,9 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp) } static void radeon_move_null(struct ttm_buffer_object *bo, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; BUG_ON(old_mem->mm_node != NULL); *old_mem = *new_mem; @@ -193,8 +160,8 @@ static void radeon_move_null(struct ttm_buffer_object *bo, static int radeon_move_blit(struct ttm_buffer_object *bo, bool evict, bool no_wait_gpu, - struct ttm_mem_reg *new_mem, - struct ttm_mem_reg *old_mem) + struct ttm_resource *new_mem, + struct ttm_resource *old_mem) { struct radeon_device *rdev; uint64_t old_start, new_start; @@ -249,11 +216,11 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, static int radeon_move_vram_ram(struct ttm_buffer_object *bo, bool evict, bool interruptible, bool no_wait_gpu, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu }; - struct ttm_mem_reg *old_mem = &bo->mem; - struct ttm_mem_reg tmp_mem; + struct ttm_resource *old_mem = &bo->mem; + struct ttm_resource tmp_mem; struct ttm_place placements; struct ttm_placement placement; int r; @@ -287,18 +254,18 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, } r = ttm_bo_move_ttm(bo, &ctx, new_mem); out_cleanup: - ttm_bo_mem_put(bo, &tmp_mem); + ttm_resource_free(bo, &tmp_mem); return r; } static int radeon_move_ram_vram(struct ttm_buffer_object *bo, bool evict, bool interruptible, bool no_wait_gpu, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu }; - struct ttm_mem_reg *old_mem = &bo->mem; - struct ttm_mem_reg tmp_mem; + struct ttm_resource *old_mem = &bo->mem; + struct ttm_resource tmp_mem; struct ttm_placement placement; struct ttm_place placements; int r; @@ -325,17 +292,17 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo, goto out_cleanup; } out_cleanup: - ttm_bo_mem_put(bo, &tmp_mem); + ttm_resource_free(bo, &tmp_mem); return r; } static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct radeon_device *rdev; struct radeon_bo *rbo; - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; int r; r = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu); @@ -392,18 +359,11 @@ memcpy: return 0; } -static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) +static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem) { - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; struct radeon_device *rdev = radeon_get_rdev(bdev); + size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; - mem->bus.addr = NULL; - mem->bus.offset = 0; - mem->bus.size = mem->num_pages << PAGE_SHIFT; - mem->bus.base = 0; - mem->bus.is_iomem = false; - if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) - return -EINVAL; switch (mem->mem_type) { case TTM_PL_SYSTEM: /* system memory */ @@ -421,7 +381,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; /* check if it's visible */ - if ((mem->bus.offset + mem->bus.size) > rdev->mc.visible_vram_size) + if ((mem->bus.offset + bus_size) > rdev->mc.visible_vram_size) return -EINVAL; mem->bus.base = rdev->mc.aper_base; mem->bus.is_iomem = true; @@ -433,11 +393,11 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ if (mem->placement & TTM_PL_FLAG_WC) mem->bus.addr = ioremap_wc(mem->bus.base + mem->bus.offset, - mem->bus.size); + bus_size); else mem->bus.addr = ioremap(mem->bus.base + mem->bus.offset, - mem->bus.size); + bus_size); if (!mem->bus.addr) return -ENOMEM; @@ -562,7 +522,7 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm) } static int radeon_ttm_backend_bind(struct ttm_tt *ttm, - struct ttm_mem_reg *bo_mem) + struct ttm_resource *bo_mem) { struct radeon_ttm_tt *gtt = (void*)ttm; uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ | @@ -760,7 +720,6 @@ static struct ttm_bo_driver radeon_bo_driver = { .ttm_tt_create = &radeon_ttm_tt_create, .ttm_tt_populate = &radeon_ttm_tt_populate, .ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate, - .init_mem_type = &radeon_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = &radeon_evict_flags, .move = &radeon_bo_move, @@ -785,8 +744,8 @@ int radeon_ttm_init(struct radeon_device *rdev) return r; } rdev->mman.initialized = true; - r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM, - rdev->mc.real_vram_size >> PAGE_SHIFT); + + r = radeon_ttm_init_vram(rdev); if (r) { DRM_ERROR("Failed initializing VRAM heap.\n"); return r; @@ -811,8 +770,8 @@ int radeon_ttm_init(struct radeon_device *rdev) } DRM_INFO("radeon: %uM of VRAM memory ready\n", (unsigned) (rdev->mc.real_vram_size / (1024 * 1024))); - r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, - rdev->mc.gtt_size >> PAGE_SHIFT); + + r = radeon_ttm_init_gtt(rdev); if (r) { DRM_ERROR("Failed initializing GTT heap.\n"); return r; @@ -843,8 +802,8 @@ void radeon_ttm_fini(struct radeon_device *rdev) } radeon_bo_unref(&rdev->stolen_vga_memory); } - ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_VRAM); - ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT); + ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_VRAM); + ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_TT); ttm_bo_device_release(&rdev->mman.bdev); radeon_gart_fini(rdev); rdev->mman.initialized = false; @@ -855,12 +814,12 @@ void radeon_ttm_fini(struct radeon_device *rdev) * isn't running */ void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size) { - struct ttm_mem_type_manager *man; + struct ttm_resource_manager *man; if (!rdev->mman.initialized) return; - man = &rdev->mman.bdev.man[TTM_PL_VRAM]; + man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM); /* this just adjusts TTM size idea, which sets lpfn to the correct value */ man->size = size >> PAGE_SHIFT; } @@ -914,7 +873,7 @@ static int radeon_mm_dump_table(struct seq_file *m, void *data) unsigned ttm_pl = *(int*)node->info_ent->data; struct drm_device *dev = node->minor->dev; struct radeon_device *rdev = dev->dev_private; - struct ttm_mem_type_manager *man = &rdev->mman.bdev.man[ttm_pl]; + struct ttm_resource_manager *man = ttm_manager_type(&rdev->mman.bdev, ttm_pl); struct drm_printer p = drm_seq_file_printer(m); man->func->debug(man, &p); diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index f60fae0aed11..71e2c3785ab9 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -911,7 +911,7 @@ static void radeon_vm_fence_pts(struct radeon_vm *vm, */ int radeon_vm_bo_update(struct radeon_device *rdev, struct radeon_bo_va *bo_va, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { struct radeon_vm *vm = bo_va->vm; struct radeon_ib ib; diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index ab0d49618cf9..bced729a96fe 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -677,15 +677,11 @@ static int rcar_lvds_attach(struct drm_bridge *bridge, if (ret < 0) return ret; - return drm_panel_attach(lvds->panel, connector); + return 0; } static void rcar_lvds_detach(struct drm_bridge *bridge) { - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - - if (lvds->panel) - drm_panel_detach(lvds->panel); } static const struct drm_bridge_funcs rcar_lvds_bridge_ops = { diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 63f967902c2d..f292c6a6e20f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -634,13 +634,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, "failed to attach encoder: %d\n", ret); goto err_free_connector; } - - ret = drm_panel_attach(lvds->panel, connector); - if (ret < 0) { - DRM_DEV_ERROR(drm_dev->dev, - "failed to attach panel: %d\n", ret); - goto err_free_connector; - } } else { ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0); if (ret) { @@ -676,8 +669,6 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master, encoder_funcs = lvds->soc_data->helper_funcs; encoder_funcs->disable(&lvds->encoder); - if (lvds->panel) - drm_panel_detach(lvds->panel); pm_runtime_disable(dev); drm_connector_cleanup(&lvds->connector); drm_encoder_cleanup(&lvds->encoder); diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 96f763d888af..9a0d77a68018 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -625,7 +625,7 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) return NULL; /* Kernel run queue has higher priority than normal run queue*/ - for (i = DRM_SCHED_PRIORITY_MAX - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { + for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { entity = drm_sched_rq_select_entity(&sched->sched_rq[i]); if (entity) break; @@ -852,7 +852,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, sched->name = name; sched->timeout = timeout; sched->hang_limit = hang_limit; - for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_MAX; i++) + for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_COUNT; i++) drm_sched_rq_init(sched, &sched->sched_rq[i]); init_waitqueue_head(&sched->wake_up_worker); diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index de4af7735c46..ddb4184f0726 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -389,8 +389,6 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force) dvo->panel = of_drm_find_panel(dvo->panel_node); if (IS_ERR(dvo->panel)) dvo->panel = NULL; - else - drm_panel_attach(dvo->panel, connector); } if (dvo->panel) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 072ea113e6be..f025534eb30c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -769,7 +769,7 @@ static const struct sunxi_engine_ops sun4i_backend_engine_ops = { .vblank_quirk = sun4i_backend_vblank_quirk, }; -static struct regmap_config sun4i_backend_regmap_config = { +static const struct regmap_config sun4i_backend_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c index 1568f68f9a9e..6825ef46f43f 100644 --- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c +++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c @@ -35,7 +35,7 @@ static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = { .fb_create = drm_gem_fb_create, }; -static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = { +static const struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c index ec2a032e07b9..b51cc685c13a 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.c +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c @@ -545,7 +545,7 @@ int sun4i_frontend_enable(struct sun4i_frontend *frontend) } EXPORT_SYMBOL(sun4i_frontend_enable); -static struct regmap_config sun4i_frontend_regmap_config = { +static const struct regmap_config sun4i_frontend_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c index ffda3184aa12..ac570437172e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c @@ -47,16 +47,13 @@ static int sun4i_lvds_get_modes(struct drm_connector *connector) return drm_panel_get_modes(lvds->panel, connector); } -static struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = { +static const struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = { .get_modes = sun4i_lvds_get_modes, }; static void sun4i_lvds_connector_destroy(struct drm_connector *connector) { - struct sun4i_lvds *lvds = drm_connector_to_sun4i_lvds(connector); - - drm_panel_detach(lvds->panel); drm_connector_cleanup(connector); } @@ -141,12 +138,6 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon) drm_connector_attach_encoder(&lvds->connector, &lvds->encoder); - - ret = drm_panel_attach(lvds->panel, &lvds->connector); - if (ret) { - dev_err(drm->dev, "Couldn't attach our panel\n"); - goto err_cleanup_connector; - } } if (bridge) { diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 5a7d43939ae6..e172426eb7e9 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -138,16 +138,13 @@ out: return MODE_OK; } -static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { +static const struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { .get_modes = sun4i_rgb_get_modes, }; static void sun4i_rgb_connector_destroy(struct drm_connector *connector) { - struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); - - drm_panel_detach(rgb->panel); drm_connector_cleanup(connector); } @@ -183,7 +180,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) } } -static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = { +static const struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = { .disable = sun4i_rgb_encoder_disable, .enable = sun4i_rgb_encoder_enable, .mode_valid = sun4i_rgb_mode_valid, @@ -233,12 +230,6 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon) drm_connector_attach_encoder(&rgb->connector, &rgb->encoder); - - ret = drm_panel_attach(rgb->panel, &rgb->connector); - if (ret) { - dev_err(drm->dev, "Couldn't attach our panel\n"); - goto err_cleanup_connector; - } } if (rgb->bridge) { diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index ced9a8287dd8..d12446cbcae0 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -825,7 +825,7 @@ static int sun4i_tcon_init_irq(struct device *dev, return 0; } -static struct regmap_config sun4i_tcon_regmap_config = { +static const struct regmap_config sun4i_tcon_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index 63f4428ac3bf..cb91bc11a0c7 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -468,7 +468,7 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder, regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0); } -static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = { +static const struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = { .disable = sun4i_tv_disable, .enable = sun4i_tv_enable, .mode_set = sun4i_tv_mode_set, @@ -504,7 +504,7 @@ static int sun4i_tv_comp_mode_valid(struct drm_connector *connector, return MODE_OK; } -static struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = { +static const struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = { .get_modes = sun4i_tv_comp_get_modes, .mode_valid = sun4i_tv_comp_mode_valid, }; @@ -523,7 +523,7 @@ static const struct drm_connector_funcs sun4i_tv_comp_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static struct regmap_config sun4i_tv_regmap_config = { +static const struct regmap_config sun4i_tv_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index 7f13f4d715bf..32af47197222 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -820,7 +820,7 @@ static int sun6i_dsi_get_modes(struct drm_connector *connector) return drm_panel_get_modes(dsi->panel, connector); } -static struct drm_connector_helper_funcs sun6i_dsi_connector_helper_funcs = { +static const struct drm_connector_helper_funcs sun6i_dsi_connector_helper_funcs = { .get_modes = sun6i_dsi_get_modes, }; @@ -973,7 +973,6 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host, dsi->panel = panel; dsi->device = device; - drm_panel_attach(dsi->panel, &dsi->connector); drm_kms_helper_hotplug_event(dsi->drm); dev_info(host->dev, "Attached device %s\n", device->name); @@ -985,12 +984,10 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct sun6i_dsi *dsi = host_to_sun6i_dsi(host); - struct drm_panel *panel = dsi->panel; dsi->panel = NULL; dsi->device = NULL; - drm_panel_detach(panel); drm_kms_helper_hotplug_event(dsi->drm); return 0; diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index 156d00e5165b..35c2133724e2 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -534,7 +534,7 @@ void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, } } -static struct regmap_config sun8i_hdmi_phy_regmap_config = { +static const struct regmap_config sun8i_hdmi_phy_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index cc4fb916318f..4b59806b30df 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -303,7 +303,7 @@ static const struct sunxi_engine_ops sun8i_engine_ops = { .layers_init = sun8i_layers_init, }; -static struct regmap_config sun8i_mixer_regmap_config = { +static const struct regmap_config sun8i_mixer_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index 54f937a7d5e7..816ad4ce8996 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -298,7 +298,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, true, zpos, old_zpos); } -static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { +static const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { .prepare_fb = drm_gem_fb_prepare_fb, .atomic_check = sun8i_ui_layer_atomic_check, .atomic_disable = sun8i_ui_layer_atomic_disable, diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 22c8c5375d0d..a360697a4a4a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -401,7 +401,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, true, zpos, old_zpos); } -static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { +static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { .prepare_fb = drm_gem_fb_prepare_fb, .atomic_check = sun8i_vi_layer_atomic_check, .atomic_disable = sun8i_vi_layer_atomic_disable, diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 3820e8dff14b..3387de79718b 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1498,10 +1498,8 @@ static int tegra_dsi_host_attach(struct mipi_dsi_host *host, if (IS_ERR(output->panel)) output->panel = NULL; - if (output->panel && output->connector.dev) { - drm_panel_attach(output->panel, &output->connector); + if (output->panel && output->connector.dev) drm_helper_hpd_irq_event(output->connector.dev); - } } return 0; diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index e36e5e7c2f69..a3adb9e4debf 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -179,13 +179,6 @@ void tegra_output_remove(struct tegra_output *output) int tegra_output_init(struct drm_device *drm, struct tegra_output *output) { int connector_type; - int err; - - if (output->panel) { - err = drm_panel_attach(output->panel, &output->connector); - if (err < 0) - return err; - } /* * The connector is now registered and ready to receive hotplug events @@ -220,9 +213,6 @@ void tegra_output_exit(struct tegra_output *output) */ if (output->hpd_gpio) disable_irq(output->hpd_irq); - - if (output->panel) - drm_panel_detach(output->panel); } void tegra_output_find_possible_crtcs(struct tegra_output *output, diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index c3ece2c9d1c8..b669168ae7cb 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -19,6 +19,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/sys_soc.h> #include <drm/drm_fourcc.h> #include <drm/drm_fb_cma_helper.h> @@ -302,6 +303,8 @@ struct dispc_device { u32 num_fourccs; u32 memory_bandwidth_limit; + + struct dispc_errata errata; }; static void dispc_write(struct dispc_device *dispc, u16 reg, u32 val) @@ -2641,6 +2644,19 @@ static int dispc_init_am65x_oldi_io_ctrl(struct device *dev, return 0; } +static void dispc_init_errata(struct dispc_device *dispc) +{ + static const struct soc_device_attribute am65x_sr10_soc_devices[] = { + { .family = "AM65X", .revision = "SR1.0" }, + { /* sentinel */ } + }; + + if (soc_device_match(am65x_sr10_soc_devices)) { + dispc->errata.i2000 = true; + dev_info(dispc->dev, "WA for erratum i2000: YUV formats disabled\n"); + } +} + int dispc_init(struct tidss_device *tidss) { struct device *dev = tidss->dev; @@ -2664,19 +2680,27 @@ int dispc_init(struct tidss_device *tidss) if (!dispc) return -ENOMEM; + dispc->tidss = tidss; + dispc->dev = dev; + dispc->feat = feat; + + dispc_init_errata(dispc); + dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats), sizeof(*dispc->fourccs), GFP_KERNEL); if (!dispc->fourccs) return -ENOMEM; num_fourccs = 0; - for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) + for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) { + if (dispc->errata.i2000 && + dispc_fourcc_is_yuv(dispc_color_formats[i].fourcc)) { + continue; + } dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc; + } dispc->num_fourccs = num_fourccs; - dispc->tidss = tidss; - dispc->dev = dev; - dispc->feat = feat; dispc_common_regmap = dispc->feat->common_regs; diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h index 5984e0de2cd9..e49432f0abf5 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.h +++ b/drivers/gpu/drm/tidss/tidss_dispc.h @@ -46,6 +46,10 @@ struct dispc_features_scaling { u32 xinc_max; }; +struct dispc_errata { + bool i2000; /* DSS Does Not Support YUV Pixel Data Formats */ +}; + enum dispc_vp_bus_type { DISPC_VP_DPI, /* DPI output */ DISPC_VP_OLDI, /* OLDI (LVDS) output */ diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile index caea2a099496..90c0da88cc98 100644 --- a/drivers/gpu/drm/ttm/Makefile +++ b/drivers/gpu/drm/ttm/Makefile @@ -4,7 +4,8 @@ ttm-y := ttm_memory.o ttm_tt.o ttm_bo.o \ ttm_bo_util.o ttm_bo_vm.o ttm_module.o \ - ttm_execbuf_util.o ttm_page_alloc.o ttm_bo_manager.o + ttm_execbuf_util.o ttm_page_alloc.o ttm_range_manager.o \ + ttm_resource.o ttm-$(CONFIG_AGP) += ttm_agp_backend.o ttm-$(CONFIG_DRM_TTM_DMA_PAGE_POOL) += ttm_page_alloc_dma.o diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c index 38f1351140e2..09fe80e215c5 100644 --- a/drivers/gpu/drm/ttm/ttm_agp_backend.c +++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c @@ -48,7 +48,7 @@ struct ttm_agp_backend { struct agp_bridge_data *bridge; }; -static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) +static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem) { struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm); struct page *dummy_read_page = ttm_bo_glob.dummy_read_page; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index cc6a4e7551e3..e3931e515906 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -77,26 +77,12 @@ static inline int ttm_mem_type_from_place(const struct ttm_place *place, return 0; } -static void ttm_mem_type_debug(struct ttm_bo_device *bdev, struct drm_printer *p, - int mem_type) -{ - struct ttm_mem_type_manager *man = &bdev->man[mem_type]; - - drm_printf(p, " has_type: %d\n", man->has_type); - drm_printf(p, " use_type: %d\n", man->use_type); - drm_printf(p, " flags: 0x%08X\n", man->flags); - drm_printf(p, " size: %llu\n", man->size); - drm_printf(p, " available_caching: 0x%08X\n", man->available_caching); - drm_printf(p, " default_caching: 0x%08X\n", man->default_caching); - if (mem_type != TTM_PL_SYSTEM) - (*man->func->debug)(man, p); -} - static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, struct ttm_placement *placement) { struct drm_printer p = drm_debug_printer(TTM_PFX); int i, ret, mem_type; + struct ttm_resource_manager *man; drm_printf(&p, "No space for %p (%lu pages, %luK, %luM)\n", bo, bo->mem.num_pages, bo->mem.size >> 10, @@ -108,7 +94,8 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, return; drm_printf(&p, " placement[%d]=0x%08X (%d)\n", i, placement->placement[i].flags, mem_type); - ttm_mem_type_debug(bo->bdev, &p, mem_type); + man = ttm_manager_type(bo->bdev, mem_type); + ttm_resource_manager_debug(man, &p); } } @@ -145,10 +132,10 @@ static inline uint32_t ttm_bo_type_flags(unsigned type) } static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_type_manager *man; + struct ttm_resource_manager *man; if (!list_empty(&bo->lru)) return; @@ -156,10 +143,10 @@ static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo, if (mem->placement & TTM_PL_FLAG_NO_EVICT) return; - man = &bdev->man[mem->mem_type]; + man = ttm_manager_type(bdev, mem->mem_type); list_add_tail(&bo->lru, &man->lru[bo->priority]); - if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED) && bo->ttm && + if (man->use_tt && bo->ttm && !(bo->ttm->page_flags & (TTM_PAGE_FLAG_SG | TTM_PAGE_FLAG_SWAPPED))) { list_add_tail(&bo->swap, &ttm_bo_glob.swap_lru[bo->priority]); @@ -223,7 +210,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { struct ttm_lru_bulk_move_pos *pos = &bulk->tt[i]; - struct ttm_mem_type_manager *man; + struct ttm_resource_manager *man; if (!pos->first) continue; @@ -231,14 +218,14 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) dma_resv_assert_held(pos->first->base.resv); dma_resv_assert_held(pos->last->base.resv); - man = &pos->first->bdev->man[TTM_PL_TT]; + man = ttm_manager_type(pos->first->bdev, TTM_PL_TT); list_bulk_move_tail(&man->lru[i], &pos->first->lru, &pos->last->lru); } for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { struct ttm_lru_bulk_move_pos *pos = &bulk->vram[i]; - struct ttm_mem_type_manager *man; + struct ttm_resource_manager *man; if (!pos->first) continue; @@ -246,7 +233,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) dma_resv_assert_held(pos->first->base.resv); dma_resv_assert_held(pos->last->base.resv); - man = &pos->first->bdev->man[TTM_PL_VRAM]; + man = ttm_manager_type(pos->first->bdev, TTM_PL_VRAM); list_bulk_move_tail(&man->lru[i], &pos->first->lru, &pos->last->lru); } @@ -268,12 +255,12 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) EXPORT_SYMBOL(ttm_bo_bulk_move_lru_tail); static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem, bool evict, + struct ttm_resource *mem, bool evict, struct ttm_operation_ctx *ctx) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_type_manager *old_man = &bdev->man[bo->mem.mem_type]; - struct ttm_mem_type_manager *new_man = &bdev->man[mem->mem_type]; + struct ttm_resource_manager *old_man = ttm_manager_type(bdev, bo->mem.mem_type); + struct ttm_resource_manager *new_man = ttm_manager_type(bdev, mem->mem_type); int ret; ret = ttm_mem_io_lock(old_man, true); @@ -286,13 +273,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, * Create and bind a ttm if required. */ - if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) { - if (bo->ttm == NULL) { - bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED); - ret = ttm_tt_create(bo, zero); - if (ret) - goto out_err; - } + if (new_man->use_tt) { + /* Zero init the new TTM structure if the old location should + * have used one as well. + */ + ret = ttm_tt_create(bo, old_man->use_tt); + if (ret) + goto out_err; ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement); if (ret) @@ -315,8 +302,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, if (bdev->driver->move_notify) bdev->driver->move_notify(bo, evict, mem); - if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) && - !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) + if (old_man->use_tt && new_man->use_tt) ret = ttm_bo_move_ttm(bo, ctx, mem); else if (bdev->driver->move) ret = bdev->driver->move(bo, evict, ctx, mem); @@ -340,8 +326,8 @@ moved: return 0; out_err: - new_man = &bdev->man[bo->mem.mem_type]; - if (new_man->flags & TTM_MEMTYPE_FLAG_FIXED) { + new_man = ttm_manager_type(bdev, bo->mem.mem_type); + if (!new_man->use_tt) { ttm_tt_destroy(bo->ttm); bo->ttm = NULL; } @@ -364,7 +350,7 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo) ttm_tt_destroy(bo->ttm); bo->ttm = NULL; - ttm_bo_mem_put(bo, &bo->mem); + ttm_resource_free(bo, &bo->mem); } static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo) @@ -552,7 +538,7 @@ static void ttm_bo_release(struct kref *kref) struct ttm_buffer_object *bo = container_of(kref, struct ttm_buffer_object, kref); struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; + struct ttm_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type); size_t acc_size = bo->acc_size; int ret; @@ -643,7 +629,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_reg evict_mem; + struct ttm_resource evict_mem; struct ttm_placement placement; int ret = 0; @@ -654,10 +640,9 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bdev->driver->evict_flags(bo, &placement); if (!placement.num_placement && !placement.num_busy_placement) { - ret = ttm_bo_pipeline_gutting(bo); - if (ret) - return ret; + ttm_bo_wait(bo, false, false); + ttm_bo_cleanup_memtype_use(bo); return ttm_tt_create(bo, false); } @@ -680,7 +665,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, if (unlikely(ret)) { if (ret != -ERESTARTSYS) pr_err("Buffer eviction failed\n"); - ttm_bo_mem_put(bo, &evict_mem); + ttm_resource_free(bo, &evict_mem); goto out; } bo->evicted = true; @@ -769,14 +754,13 @@ static int ttm_mem_evict_wait_busy(struct ttm_buffer_object *busy_bo, return r == -EDEADLK ? -EBUSY : r; } -static int ttm_mem_evict_first(struct ttm_bo_device *bdev, - uint32_t mem_type, - const struct ttm_place *place, - struct ttm_operation_ctx *ctx, - struct ww_acquire_ctx *ticket) +int ttm_mem_evict_first(struct ttm_bo_device *bdev, + struct ttm_resource_manager *man, + const struct ttm_place *place, + struct ttm_operation_ctx *ctx, + struct ww_acquire_ctx *ticket) { struct ttm_buffer_object *bo = NULL, *busy_bo = NULL; - struct ttm_mem_type_manager *man = &bdev->man[mem_type]; bool locked = false; unsigned i; int ret; @@ -842,38 +826,12 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, return ret; } -static int ttm_bo_mem_get(struct ttm_buffer_object *bo, - const struct ttm_place *place, - struct ttm_mem_reg *mem) -{ - struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type]; - - mem->mm_node = NULL; - if (!man->func || !man->func->get_node) - return 0; - - return man->func->get_node(man, bo, place, mem); -} - -void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) -{ - struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type]; - - if (!man->func || !man->func->put_node) - return; - - man->func->put_node(man, mem); - mem->mm_node = NULL; - mem->mem_type = TTM_PL_SYSTEM; -} -EXPORT_SYMBOL(ttm_bo_mem_put); - /** * Add the last move fence to the BO and reserve a new shared slot. */ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo, - struct ttm_mem_type_manager *man, - struct ttm_mem_reg *mem, + struct ttm_resource_manager *man, + struct ttm_resource *mem, bool no_wait_gpu) { struct dma_fence *fence; @@ -910,22 +868,22 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo, */ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, const struct ttm_place *place, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, struct ttm_operation_ctx *ctx) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type); struct ww_acquire_ctx *ticket; int ret; ticket = dma_resv_locking_ctx(bo->base.resv); do { - ret = ttm_bo_mem_get(bo, place, mem); + ret = ttm_resource_alloc(bo, place, mem); if (likely(!ret)) break; if (unlikely(ret != -ENOSPC)) return ret; - ret = ttm_mem_evict_first(bdev, mem->mem_type, place, ctx, + ret = ttm_mem_evict_first(bdev, man, place, ctx, ticket); if (unlikely(ret != 0)) return ret; @@ -934,7 +892,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, return ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu); } -static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man, +static uint32_t ttm_bo_select_caching(struct ttm_resource_manager *man, uint32_t cur_placement, uint32_t proposed_placement) { @@ -959,7 +917,7 @@ static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man, return result; } -static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man, +static bool ttm_bo_mt_compatible(struct ttm_resource_manager *man, uint32_t mem_type, const struct ttm_place *place, uint32_t *masked_placement) @@ -991,12 +949,12 @@ static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man, */ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, const struct ttm_place *place, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, struct ttm_operation_ctx *ctx) { struct ttm_bo_device *bdev = bo->bdev; uint32_t mem_type = TTM_PL_SYSTEM; - struct ttm_mem_type_manager *man; + struct ttm_resource_manager *man; uint32_t cur_flags = 0; int ret; @@ -1004,8 +962,8 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, if (ret) return ret; - man = &bdev->man[mem_type]; - if (!man->has_type || !man->use_type) + man = ttm_manager_type(bdev, mem_type); + if (!man || !ttm_resource_manager_used(man)) return -EBUSY; if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags)) @@ -1039,7 +997,7 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, */ int ttm_bo_mem_space(struct ttm_buffer_object *bo, struct ttm_placement *placement, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, struct ttm_operation_ctx *ctx) { struct ttm_bo_device *bdev = bo->bdev; @@ -1052,7 +1010,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, for (i = 0; i < placement->num_placement; ++i) { const struct ttm_place *place = &placement->placement[i]; - struct ttm_mem_type_manager *man; + struct ttm_resource_manager *man; ret = ttm_bo_mem_placement(bo, place, mem, ctx); if (ret == -EBUSY) @@ -1061,16 +1019,16 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, goto error; type_found = true; - ret = ttm_bo_mem_get(bo, place, mem); + ret = ttm_resource_alloc(bo, place, mem); if (ret == -ENOSPC) continue; if (unlikely(ret)) goto error; - man = &bdev->man[mem->mem_type]; + man = ttm_manager_type(bdev, mem->mem_type); ret = ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu); if (unlikely(ret)) { - ttm_bo_mem_put(bo, mem); + ttm_resource_free(bo, mem); if (ret == -EBUSY) continue; @@ -1105,9 +1063,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, error: if (bo->mem.mem_type == TTM_PL_SYSTEM && !list_empty(&bo->lru)) { - spin_lock(&ttm_bo_glob.lru_lock); - ttm_bo_move_to_lru_tail(bo, NULL); - spin_unlock(&ttm_bo_glob.lru_lock); + ttm_bo_move_to_lru_tail_unlocked(bo); } return ret; @@ -1119,7 +1075,7 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx) { int ret = 0; - struct ttm_mem_reg mem; + struct ttm_resource mem; dma_resv_assert_held(bo->base.resv); @@ -1139,13 +1095,13 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, ret = ttm_bo_handle_move_mem(bo, &mem, false, ctx); out_unlock: if (ret) - ttm_bo_mem_put(bo, &mem); + ttm_resource_free(bo, &mem); return ret; } static bool ttm_bo_places_compat(const struct ttm_place *places, unsigned num_placement, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, uint32_t *new_flags) { unsigned i; @@ -1168,7 +1124,7 @@ static bool ttm_bo_places_compat(const struct ttm_place *places, } bool ttm_bo_mem_compat(struct ttm_placement *placement, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, uint32_t *new_flags) { if (ttm_bo_places_compat(placement->placement, placement->num_placement, @@ -1224,7 +1180,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, /* * We might need to add a TTM. */ - if (bo->mem.mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { + if (bo->mem.mem_type == TTM_PL_SYSTEM) { ret = ttm_tt_create(bo, true); if (ret) return ret; @@ -1335,9 +1291,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, return ret; } - spin_lock(&ttm_bo_glob.lru_lock); - ttm_bo_move_to_lru_tail(bo, NULL); - spin_unlock(&ttm_bo_glob.lru_lock); + ttm_bo_move_to_lru_tail_unlocked(bo); return ret; } @@ -1426,144 +1380,24 @@ int ttm_bo_create(struct ttm_bo_device *bdev, } EXPORT_SYMBOL(ttm_bo_create); -static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev, - unsigned mem_type) -{ - struct ttm_operation_ctx ctx = { - .interruptible = false, - .no_wait_gpu = false, - .flags = TTM_OPT_FLAG_FORCE_ALLOC - }; - struct ttm_mem_type_manager *man = &bdev->man[mem_type]; - struct ttm_bo_global *glob = &ttm_bo_glob; - struct dma_fence *fence; - int ret; - unsigned i; - - /* - * Can't use standard list traversal since we're unlocking. - */ - - spin_lock(&glob->lru_lock); - for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { - while (!list_empty(&man->lru[i])) { - spin_unlock(&glob->lru_lock); - ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx, - NULL); - if (ret) - return ret; - spin_lock(&glob->lru_lock); - } - } - spin_unlock(&glob->lru_lock); - - spin_lock(&man->move_lock); - fence = dma_fence_get(man->move); - spin_unlock(&man->move_lock); - - if (fence) { - ret = dma_fence_wait(fence, false); - dma_fence_put(fence); - if (ret) - return ret; - } - - return 0; -} - -int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type) -{ - struct ttm_mem_type_manager *man; - int ret = -EINVAL; - - if (mem_type >= TTM_NUM_MEM_TYPES) { - pr_err("Illegal memory type %d\n", mem_type); - return ret; - } - man = &bdev->man[mem_type]; - - if (!man->has_type) { - pr_err("Trying to take down uninitialized memory manager type %u\n", - mem_type); - return ret; - } - - man->use_type = false; - man->has_type = false; - - ret = 0; - if (mem_type > 0) { - ret = ttm_bo_force_list_clean(bdev, mem_type); - if (ret) { - pr_err("Cleanup eviction failed\n"); - return ret; - } - - ret = (*man->func->takedown)(man); - } - - dma_fence_put(man->move); - man->move = NULL; - - return ret; -} -EXPORT_SYMBOL(ttm_bo_clean_mm); - int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type) { - struct ttm_mem_type_manager *man = &bdev->man[mem_type]; + struct ttm_resource_manager *man = ttm_manager_type(bdev, mem_type); if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) { pr_err("Illegal memory manager memory type %u\n", mem_type); return -EINVAL; } - if (!man->has_type) { + if (!man) { pr_err("Memory type %u has not been initialized\n", mem_type); return 0; } - return ttm_bo_force_list_clean(bdev, mem_type); + return ttm_resource_manager_force_list_clean(bdev, man); } EXPORT_SYMBOL(ttm_bo_evict_mm); -int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type, - unsigned long p_size) -{ - int ret; - struct ttm_mem_type_manager *man; - unsigned i; - - BUG_ON(type >= TTM_NUM_MEM_TYPES); - man = &bdev->man[type]; - BUG_ON(man->has_type); - man->use_io_reserve_lru = false; - mutex_init(&man->io_reserve_mutex); - spin_lock_init(&man->move_lock); - INIT_LIST_HEAD(&man->io_reserve_lru); - - ret = bdev->driver->init_mem_type(bdev, type, man); - if (ret) - return ret; - man->bdev = bdev; - - if (type != TTM_PL_SYSTEM) { - ret = (*man->func->init)(man, p_size); - if (ret) - return ret; - } - man->has_type = true; - man->use_type = true; - man->size = p_size; - - for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) - INIT_LIST_HEAD(&man->lru[i]); - man->move = NULL; - - return 0; -} -EXPORT_SYMBOL(ttm_bo_init_mm); - static void ttm_bo_global_kobj_release(struct kobject *kobj) { struct ttm_bo_global *glob = @@ -1628,21 +1462,12 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev) { struct ttm_bo_global *glob = &ttm_bo_glob; int ret = 0; - unsigned i = TTM_NUM_MEM_TYPES; - struct ttm_mem_type_manager *man; - - while (i--) { - man = &bdev->man[i]; - if (man->has_type) { - man->use_type = false; - if ((i != TTM_PL_SYSTEM) && ttm_bo_clean_mm(bdev, i)) { - ret = -EBUSY; - pr_err("DRM memory manager type %d is not clean\n", - i); - } - man->has_type = false; - } - } + unsigned i; + struct ttm_resource_manager *man; + + man = ttm_manager_type(bdev, TTM_PL_SYSTEM); + ttm_resource_manager_set_used(man, false); + ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, NULL); mutex_lock(&ttm_global_mutex); list_del(&bdev->device_list); @@ -1655,7 +1480,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev) spin_lock(&glob->lru_lock); for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) - if (list_empty(&bdev->man[0].lru[0])) + if (list_empty(&man->lru[0])) pr_debug("Swap list %d was clean\n", i); spin_unlock(&glob->lru_lock); @@ -1666,6 +1491,23 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev) } EXPORT_SYMBOL(ttm_bo_device_release); +static void ttm_bo_init_sysman(struct ttm_bo_device *bdev) +{ + struct ttm_resource_manager *man = &bdev->sysman; + + /* + * Initialize the system memory buffer type. + * Other types need to be driver / IOCTL initialized. + */ + man->use_tt = true; + man->available_caching = TTM_PL_MASK_CACHING; + man->default_caching = TTM_PL_FLAG_CACHED; + + ttm_resource_manager_init(man, 0); + ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man); + ttm_resource_manager_set_used(man, true); +} + int ttm_bo_device_init(struct ttm_bo_device *bdev, struct ttm_bo_driver *driver, struct address_space *mapping, @@ -1684,15 +1526,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, bdev->driver = driver; - memset(bdev->man, 0, sizeof(bdev->man)); - - /* - * Initialize the system memory buffer type. - * Other types need to be driver / IOCTL initialized. - */ - ret = ttm_bo_init_mm(bdev, TTM_PL_SYSTEM, 0); - if (unlikely(ret != 0)) - goto out_no_sys; + ttm_bo_init_sysman(bdev); bdev->vma_manager = vma_manager; INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue); @@ -1704,9 +1538,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, mutex_unlock(&ttm_global_mutex); return 0; -out_no_sys: - ttm_bo_global_release(); - return ret; } EXPORT_SYMBOL(ttm_bo_device_init); @@ -1725,7 +1556,7 @@ void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo) void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; + struct ttm_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type); ttm_mem_io_lock(man, false); ttm_bo_unmap_virtual_locked(bo); @@ -1812,7 +1643,7 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx) if (bo->mem.mem_type != TTM_PL_SYSTEM || bo->ttm->caching_state != tt_cached) { struct ttm_operation_ctx ctx = { false, false }; - struct ttm_mem_reg evict_mem; + struct ttm_resource evict_mem; evict_mem = bo->mem; evict_mem.mm_node = NULL; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index e6c8bd254055..ee04716b2603 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -47,15 +47,15 @@ struct ttm_transfer_obj { void ttm_bo_free_old_node(struct ttm_buffer_object *bo) { - ttm_bo_mem_put(bo, &bo->mem); + ttm_resource_free(bo, &bo->mem); } int ttm_bo_move_ttm(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct ttm_tt *ttm = bo->ttm; - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; int ret; if (old_mem->mem_type != TTM_PL_SYSTEM) { @@ -91,7 +91,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, } EXPORT_SYMBOL(ttm_bo_move_ttm); -int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) +int ttm_mem_io_lock(struct ttm_resource_manager *man, bool interruptible) { if (likely(!man->use_io_reserve_lru)) return 0; @@ -103,7 +103,7 @@ int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) return 0; } -void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) +void ttm_mem_io_unlock(struct ttm_resource_manager *man) { if (likely(!man->use_io_reserve_lru)) return; @@ -111,7 +111,7 @@ void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) mutex_unlock(&man->io_reserve_mutex); } -static int ttm_mem_io_evict(struct ttm_mem_type_manager *man) +static int ttm_mem_io_evict(struct ttm_resource_manager *man) { struct ttm_buffer_object *bo; @@ -127,9 +127,9 @@ static int ttm_mem_io_evict(struct ttm_mem_type_manager *man) } int ttm_mem_io_reserve(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type); int ret; if (mem->bus.io_reserved_count++) @@ -138,6 +138,10 @@ int ttm_mem_io_reserve(struct ttm_bo_device *bdev, if (!bdev->driver->io_mem_reserve) return 0; + mem->bus.addr = NULL; + mem->bus.offset = 0; + mem->bus.base = 0; + mem->bus.is_iomem = false; retry: ret = bdev->driver->io_mem_reserve(bdev, mem); if (ret == -ENOSPC) { @@ -149,7 +153,7 @@ retry: } void ttm_mem_io_free(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { if (--mem->bus.io_reserved_count) return; @@ -162,8 +166,8 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev, int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) { - struct ttm_mem_type_manager *man = &bo->bdev->man[bo->mem.mem_type]; - struct ttm_mem_reg *mem = &bo->mem; + struct ttm_resource_manager *man = ttm_manager_type(bo->bdev, bo->mem.mem_type); + struct ttm_resource *mem = &bo->mem; int ret; if (mem->bus.io_reserved_vm) @@ -181,7 +185,7 @@ int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) { - struct ttm_mem_reg *mem = &bo->mem; + struct ttm_resource *mem = &bo->mem; if (!mem->bus.io_reserved_vm) return; @@ -191,11 +195,11 @@ void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) ttm_mem_io_free(bo->bdev, mem); } -static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem, +static int ttm_resource_ioremap(struct ttm_bo_device *bdev, + struct ttm_resource *mem, void **virtual) { - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type); int ret; void *addr; @@ -209,12 +213,14 @@ static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, if (mem->bus.addr) { addr = mem->bus.addr; } else { + size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; + if (mem->placement & TTM_PL_FLAG_WC) addr = ioremap_wc(mem->bus.base + mem->bus.offset, - mem->bus.size); + bus_size); else addr = ioremap(mem->bus.base + mem->bus.offset, - mem->bus.size); + bus_size); if (!addr) { (void) ttm_mem_io_lock(man, false); ttm_mem_io_free(bdev, mem); @@ -226,13 +232,13 @@ static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, return 0; } -static void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem, +static void ttm_resource_iounmap(struct ttm_bo_device *bdev, + struct ttm_resource *mem, void *virtual) { - struct ttm_mem_type_manager *man; + struct ttm_resource_manager *man; - man = &bdev->man[mem->mem_type]; + man = ttm_manager_type(bdev, mem->mem_type); if (virtual && mem->bus.addr == NULL) iounmap(virtual); @@ -300,13 +306,13 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; + struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type); struct ttm_tt *ttm = bo->ttm; - struct ttm_mem_reg *old_mem = &bo->mem; - struct ttm_mem_reg old_copy = *old_mem; + struct ttm_resource *old_mem = &bo->mem; + struct ttm_resource old_copy = *old_mem; void *old_iomap; void *new_iomap; int ret; @@ -319,10 +325,10 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, if (ret) return ret; - ret = ttm_mem_reg_ioremap(bdev, old_mem, &old_iomap); + ret = ttm_resource_ioremap(bdev, old_mem, &old_iomap); if (ret) return ret; - ret = ttm_mem_reg_ioremap(bdev, new_mem, &new_iomap); + ret = ttm_resource_ioremap(bdev, new_mem, &new_iomap); if (ret) goto out; @@ -384,21 +390,21 @@ out2: *old_mem = *new_mem; new_mem->mm_node = NULL; - if (man->flags & TTM_MEMTYPE_FLAG_FIXED) { + if (!man->use_tt) { ttm_tt_destroy(ttm); bo->ttm = NULL; } out1: - ttm_mem_reg_iounmap(bdev, old_mem, new_iomap); + ttm_resource_iounmap(bdev, old_mem, new_iomap); out: - ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap); + ttm_resource_iounmap(bdev, &old_copy, old_iomap); /* * On error, keep the mm node! */ if (!ret) - ttm_bo_mem_put(bo, &old_copy); + ttm_resource_free(bo, &old_copy); return ret; } EXPORT_SYMBOL(ttm_bo_move_memcpy); @@ -502,7 +508,7 @@ static int ttm_bo_ioremap(struct ttm_buffer_object *bo, unsigned long size, struct ttm_bo_kmap_obj *map) { - struct ttm_mem_reg *mem = &bo->mem; + struct ttm_resource *mem = &bo->mem; if (bo->mem.bus.addr) { map->bo_kmap_type = ttm_bo_map_premapped; @@ -526,7 +532,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, unsigned long num_pages, struct ttm_bo_kmap_obj *map) { - struct ttm_mem_reg *mem = &bo->mem; + struct ttm_resource *mem = &bo->mem; struct ttm_operation_ctx ctx = { .interruptible = false, .no_wait_gpu = false @@ -567,8 +573,8 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page, unsigned long num_pages, struct ttm_bo_kmap_obj *map) { - struct ttm_mem_type_manager *man = - &bo->bdev->man[bo->mem.mem_type]; + struct ttm_resource_manager *man = + ttm_manager_type(bo->bdev, bo->mem.mem_type); unsigned long offset, size; int ret; @@ -597,8 +603,8 @@ EXPORT_SYMBOL(ttm_bo_kmap); void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) { struct ttm_buffer_object *bo = map->bo; - struct ttm_mem_type_manager *man = - &bo->bdev->man[bo->mem.mem_type]; + struct ttm_resource_manager *man = + ttm_manager_type(bo->bdev, bo->mem.mem_type); if (!map->virtual) return; @@ -628,11 +634,11 @@ EXPORT_SYMBOL(ttm_bo_kunmap); int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, struct dma_fence *fence, bool evict, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type); + struct ttm_resource *old_mem = &bo->mem; int ret; struct ttm_buffer_object *ghost_obj; @@ -642,7 +648,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, if (ret) return ret; - if (man->flags & TTM_MEMTYPE_FLAG_FIXED) { + if (!man->use_tt) { ttm_tt_destroy(bo->ttm); bo->ttm = NULL; } @@ -671,7 +677,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, * bo to be unbound and destroyed. */ - if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED)) + if (man->use_tt) ghost_obj->ttm = NULL; else bo->ttm = NULL; @@ -689,13 +695,13 @@ EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, struct dma_fence *fence, bool evict, - struct ttm_mem_reg *new_mem) + struct ttm_resource *new_mem) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_resource *old_mem = &bo->mem; - struct ttm_mem_type_manager *from = &bdev->man[old_mem->mem_type]; - struct ttm_mem_type_manager *to = &bdev->man[new_mem->mem_type]; + struct ttm_resource_manager *from = ttm_manager_type(bdev, old_mem->mem_type); + struct ttm_resource_manager *to = ttm_manager_type(bdev, new_mem->mem_type); int ret; @@ -727,7 +733,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, * bo to be unbound and destroyed. */ - if (!(to->flags & TTM_MEMTYPE_FLAG_FIXED)) + if (to->use_tt) ghost_obj->ttm = NULL; else bo->ttm = NULL; @@ -735,7 +741,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, dma_resv_unlock(&ghost_obj->base._resv); ttm_bo_put(ghost_obj); - } else if (from->flags & TTM_MEMTYPE_FLAG_FIXED) { + } else if (!from->use_tt) { /** * BO doesn't have a TTM we need to bind/unbind. Just remember @@ -765,7 +771,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, if (ret) return ret; - if (to->flags & TTM_MEMTYPE_FLAG_FIXED) { + if (!to->use_tt) { ttm_tt_destroy(bo->ttm); bo->ttm = NULL; } diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 4732dcc80e11..01693e8f24b7 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -281,8 +281,8 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, pgoff_t i; vm_fault_t ret = VM_FAULT_NOPAGE; unsigned long address = vmf->address; - struct ttm_mem_type_manager *man = - &bdev->man[bo->mem.mem_type]; + struct ttm_resource_manager *man = + ttm_manager_type(bdev, bo->mem.mem_type); /* * Refuse to fault imported pages. This should be handled @@ -308,9 +308,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, } if (bo->moving != moving) { - spin_lock(&ttm_bo_glob.lru_lock); - ttm_bo_move_to_lru_tail(bo, NULL); - spin_unlock(&ttm_bo_glob.lru_lock); + ttm_bo_move_to_lru_tail_unlocked(bo); } dma_fence_put(moving); } diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index 1797f04c0534..8a8f1a6a83a6 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -93,7 +93,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, list_for_each_entry(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; - ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), ticket); + ret = ttm_bo_reserve(bo, intr, (ticket == NULL), ticket); if (ret == -EALREADY && dups) { struct ttm_validate_buffer *safe = entry; entry = list_prev_entry(entry, head); @@ -119,13 +119,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, ttm_eu_backoff_reservation_reverse(list, entry); if (ret == -EDEADLK) { - if (intr) { - ret = dma_resv_lock_slow_interruptible(bo->base.resv, - ticket); - } else { - dma_resv_lock_slow(bo->base.resv, ticket); - ret = 0; - } + ret = ttm_bo_reserve_slowpath(bo, intr, ticket); } if (!ret && entry->num_shared) @@ -133,8 +127,6 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, entry->num_shared); if (unlikely(ret != 0)) { - if (ret == -EINTR) - ret = -ERESTARTSYS; if (ticket) { ww_acquire_done(ticket); ww_acquire_fini(ticket); diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c index facd3049c3aa..770c8988c139 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_manager.c +++ b/drivers/gpu/drm/ttm/ttm_range_manager.c @@ -44,16 +44,22 @@ */ struct ttm_range_manager { + struct ttm_resource_manager manager; struct drm_mm mm; spinlock_t lock; }; -static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, +static inline struct ttm_range_manager *to_range_manager(struct ttm_resource_manager *man) +{ + return container_of(man, struct ttm_range_manager, manager); +} + +static int ttm_range_man_alloc(struct ttm_resource_manager *man, struct ttm_buffer_object *bo, const struct ttm_place *place, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { - struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; + struct ttm_range_manager *rman = to_range_manager(man); struct drm_mm *mm = &rman->mm; struct drm_mm_node *node; enum drm_mm_insert_mode mode; @@ -89,10 +95,10 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, return ret; } -static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, - struct ttm_mem_reg *mem) +static void ttm_range_man_free(struct ttm_resource_manager *man, + struct ttm_resource *mem) { - struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; + struct ttm_range_manager *rman = to_range_manager(man); if (mem->mm_node) { spin_lock(&rman->lock); @@ -104,53 +110,78 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, } } -static int ttm_bo_man_init(struct ttm_mem_type_manager *man, - unsigned long p_size) +static const struct ttm_resource_manager_func ttm_range_manager_func; + +int ttm_range_man_init(struct ttm_bo_device *bdev, + unsigned type, + uint32_t available_caching, + uint32_t default_caching, + bool use_tt, + unsigned long p_size) { + struct ttm_resource_manager *man; struct ttm_range_manager *rman; rman = kzalloc(sizeof(*rman), GFP_KERNEL); if (!rman) return -ENOMEM; + man = &rman->manager; + man->available_caching = available_caching; + man->default_caching = default_caching; + man->use_tt = use_tt; + + man->func = &ttm_range_manager_func; + + ttm_resource_manager_init(man, p_size); + drm_mm_init(&rman->mm, 0, p_size); spin_lock_init(&rman->lock); - man->priv = rman; + + ttm_set_driver_manager(bdev, type, &rman->manager); + ttm_resource_manager_set_used(man, true); return 0; } +EXPORT_SYMBOL(ttm_range_man_init); -static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man) +int ttm_range_man_fini(struct ttm_bo_device *bdev, + unsigned type) { - struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; + struct ttm_resource_manager *man = ttm_manager_type(bdev, type); + struct ttm_range_manager *rman = to_range_manager(man); struct drm_mm *mm = &rman->mm; + int ret; + + ttm_resource_manager_set_used(man, false); + + ret = ttm_resource_manager_force_list_clean(bdev, man); + if (ret) + return ret; spin_lock(&rman->lock); - if (drm_mm_clean(mm)) { - drm_mm_takedown(mm); - spin_unlock(&rman->lock); - kfree(rman); - man->priv = NULL; - return 0; - } + drm_mm_clean(mm); + drm_mm_takedown(mm); spin_unlock(&rman->lock); - return -EBUSY; + + ttm_resource_manager_cleanup(man); + ttm_set_driver_manager(bdev, type, NULL); + kfree(rman); + return 0; } +EXPORT_SYMBOL(ttm_range_man_fini); -static void ttm_bo_man_debug(struct ttm_mem_type_manager *man, - struct drm_printer *printer) +static void ttm_range_man_debug(struct ttm_resource_manager *man, + struct drm_printer *printer) { - struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; + struct ttm_range_manager *rman = to_range_manager(man); spin_lock(&rman->lock); drm_mm_print(&rman->mm, printer); spin_unlock(&rman->lock); } -const struct ttm_mem_type_manager_func ttm_bo_manager_func = { - .init = ttm_bo_man_init, - .takedown = ttm_bo_man_takedown, - .get_node = ttm_bo_man_get_node, - .put_node = ttm_bo_man_put_node, - .debug = ttm_bo_man_debug +static const struct ttm_resource_manager_func ttm_range_manager_func = { + .alloc = ttm_range_man_alloc, + .free = ttm_range_man_free, + .debug = ttm_range_man_debug }; -EXPORT_SYMBOL(ttm_bo_manager_func); diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c new file mode 100644 index 000000000000..33b642532e5c --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -0,0 +1,151 @@ +/* + * Copyright 2020 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. + * + * Authors: Christian König + */ + +#include <drm/ttm/ttm_resource.h> +#include <drm/ttm/ttm_bo_driver.h> + +int ttm_resource_alloc(struct ttm_buffer_object *bo, + const struct ttm_place *place, + struct ttm_resource *res) +{ + struct ttm_resource_manager *man = + ttm_manager_type(bo->bdev, res->mem_type); + + res->mm_node = NULL; + if (!man->func || !man->func->alloc) + return 0; + + return man->func->alloc(man, bo, place, res); +} + +void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource *res) +{ + struct ttm_resource_manager *man = + ttm_manager_type(bo->bdev, res->mem_type); + + if (man->func && man->func->free) + man->func->free(man, res); + + res->mm_node = NULL; + res->mem_type = TTM_PL_SYSTEM; +} +EXPORT_SYMBOL(ttm_resource_free); + +/** + * ttm_resource_manager_init + * + * @man: memory manager object to init + * @p_size: size managed area in pages. + * + * Initialise core parts of a manager object. + */ +void ttm_resource_manager_init(struct ttm_resource_manager *man, + unsigned long p_size) +{ + unsigned i; + + man->use_io_reserve_lru = false; + mutex_init(&man->io_reserve_mutex); + spin_lock_init(&man->move_lock); + INIT_LIST_HEAD(&man->io_reserve_lru); + man->size = p_size; + + for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) + INIT_LIST_HEAD(&man->lru[i]); + man->move = NULL; +} +EXPORT_SYMBOL(ttm_resource_manager_init); + +/* + * ttm_resource_manager_force_list_clean + * + * @bdev - device to use + * @man - manager to use + * + * Force all the objects out of a memory manager until clean. + * Part of memory manager cleanup sequence. + */ +int ttm_resource_manager_force_list_clean(struct ttm_bo_device *bdev, + struct ttm_resource_manager *man) +{ + struct ttm_operation_ctx ctx = { + .interruptible = false, + .no_wait_gpu = false, + .flags = TTM_OPT_FLAG_FORCE_ALLOC + }; + struct ttm_bo_global *glob = &ttm_bo_glob; + struct dma_fence *fence; + int ret; + unsigned i; + + /* + * Can't use standard list traversal since we're unlocking. + */ + + spin_lock(&glob->lru_lock); + for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { + while (!list_empty(&man->lru[i])) { + spin_unlock(&glob->lru_lock); + ret = ttm_mem_evict_first(bdev, man, NULL, &ctx, + NULL); + if (ret) + return ret; + spin_lock(&glob->lru_lock); + } + } + spin_unlock(&glob->lru_lock); + + spin_lock(&man->move_lock); + fence = dma_fence_get(man->move); + spin_unlock(&man->move_lock); + + if (fence) { + ret = dma_fence_wait(fence, false); + dma_fence_put(fence); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL(ttm_resource_manager_force_list_clean); + +/** + * ttm_resource_manager_debug + * + * @man: manager type to dump. + * @p: printer to use for debug. + */ +void ttm_resource_manager_debug(struct ttm_resource_manager *man, + struct drm_printer *p) +{ + drm_printf(p, " use_type: %d\n", man->use_type); + drm_printf(p, " use_tt: %d\n", man->use_tt); + drm_printf(p, " size: %llu\n", man->size); + drm_printf(p, " available_caching: 0x%08X\n", man->available_caching); + drm_printf(p, " default_caching: 0x%08X\n", man->default_caching); + if (man->func && man->func->debug) + (*man->func->debug)(man, p); +} +EXPORT_SYMBOL(ttm_resource_manager_debug); diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 3437711ddb43..1ccf1ef050d6 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -50,6 +50,9 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) dma_resv_assert_held(bo->base.resv); + if (bo->ttm) + return 0; + if (bdev->need_dma32) page_flags |= TTM_PAGE_FLAG_DMA32; @@ -67,7 +70,6 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) page_flags |= TTM_PAGE_FLAG_SG; break; default: - bo->ttm = NULL; pr_err("Illegal buffer object type\n"); return -EINVAL; } @@ -314,7 +316,7 @@ void ttm_tt_unbind(struct ttm_tt *ttm) } } -int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem, +int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem, struct ttm_operation_ctx *ctx) { int ret = 0; diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 82a7dfdd14c2..9f7c26193831 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -358,18 +358,7 @@ static struct platform_driver v3d_platform_driver = { }, }; -static int __init v3d_drm_register(void) -{ - return platform_driver_register(&v3d_platform_driver); -} - -static void __exit v3d_drm_unregister(void) -{ - platform_driver_unregister(&v3d_platform_driver); -} - -module_init(v3d_drm_register); -module_exit(v3d_drm_unregister); +module_platform_driver(v3d_platform_driver); MODULE_ALIAS("platform:v3d-drm"); MODULE_DESCRIPTION("Broadcom V3D DRM Driver"); diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index a775feda1cc7..313339bbff90 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -471,8 +471,8 @@ static int __init vgem_init(void) out_put: drm_dev_put(&vgem_device->drm); + platform_device_unregister(vgem_device->platform); return ret; - out_unregister: platform_device_unregister(vgem_device->platform); out_free: diff --git a/drivers/gpu/drm/virtio/Kconfig b/drivers/gpu/drm/virtio/Kconfig index eff3047052d4..67624423013a 100644 --- a/drivers/gpu/drm/virtio/Kconfig +++ b/drivers/gpu/drm/virtio/Kconfig @@ -4,6 +4,7 @@ config DRM_VIRTIO_GPU depends on DRM && VIRTIO && MMU select DRM_KMS_HELPER select DRM_GEM_SHMEM_HELPER + select VIRTIO_DMA_SHARED_BUFFER help This is the virtual GPU driver for virtio. It can be used with QEMU based VMMs (like KVM or Xen). diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index af55b334be2f..2c2742b8d657 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -165,8 +165,6 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector) count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); if (width == 0 || height == 0) { - width = XRES_DEF; - height = YRES_DEF; drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); } else { DRM_DEBUG("add mode: %dx%d\n", width, height); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index ab4bed78e656..b039f493bda9 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -165,6 +165,7 @@ static unsigned int features[] = { VIRTIO_GPU_F_VIRGL, #endif VIRTIO_GPU_F_EDID, + VIRTIO_GPU_F_RESOURCE_UUID, }; static struct virtio_driver virtio_gpu_driver = { .feature_table = features, @@ -202,6 +203,8 @@ static struct drm_driver driver = { .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_mmap = drm_gem_prime_mmap, + .gem_prime_export = virtgpu_gem_prime_export, + .gem_prime_import = virtgpu_gem_prime_import, .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table, .gem_create_object = virtio_gpu_create_object, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 9ff9f4ac0522..9a8bfbf85412 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -49,6 +49,10 @@ #define DRIVER_MINOR 1 #define DRIVER_PATCHLEVEL 0 +#define UUID_INITIALIZING 0 +#define UUID_INITIALIZED 1 +#define UUID_INITIALIZATION_FAILED 2 + struct virtio_gpu_object_params { uint32_t format; uint32_t width; @@ -71,6 +75,9 @@ struct virtio_gpu_object { uint32_t hw_res_handle; bool dumb; bool created; + + int uuid_state; + uuid_t uuid; }; #define gem_to_virtio_gpu_obj(gobj) \ container_of((gobj), struct virtio_gpu_object, base.base) @@ -200,6 +207,7 @@ struct virtio_gpu_device { bool has_virgl_3d; bool has_edid; bool has_indirect; + bool has_resource_assign_uuid; struct work_struct config_changed_work; @@ -210,6 +218,9 @@ struct virtio_gpu_device { struct virtio_gpu_drv_capset *capsets; uint32_t num_capsets; struct list_head cap_cache; + + /* protects resource state when exporting */ + spinlock_t resource_export_lock; }; struct virtio_gpu_fpriv { @@ -336,6 +347,10 @@ void virtio_gpu_dequeue_fence_func(struct work_struct *work); void virtio_gpu_notify(struct virtio_gpu_device *vgdev); +int +virtio_gpu_cmd_resource_assign_uuid(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object_array *objs); + /* virtgpu_display.c */ void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); @@ -367,6 +382,12 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo); /* virtgpu_prime.c */ +struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj, + int flags); +struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev, + struct dma_buf *buf); +int virtgpu_gem_prime_get_uuid(struct drm_gem_object *obj, + uuid_t *uuid); struct drm_gem_object *virtgpu_gem_prime_import_sg_table( struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c index 24ffacac99e4..c30c75ee83fc 100644 --- a/drivers/gpu/drm/virtio/virtgpu_gem.c +++ b/drivers/gpu/drm/virtio/virtgpu_gem.c @@ -154,9 +154,8 @@ void virtio_gpu_gem_object_close(struct drm_gem_object *obj, struct virtio_gpu_object_array *virtio_gpu_array_alloc(u32 nents) { struct virtio_gpu_object_array *objs; - size_t size = sizeof(*objs) + sizeof(objs->objs[0]) * nents; - objs = kmalloc(size, GFP_KERNEL); + objs = kmalloc(struct_size(objs, objs, nents), GFP_KERNEL); if (!objs) return NULL; diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 4d944a0dff3e..75d0dc2f6d28 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -118,6 +118,7 @@ int virtio_gpu_init(struct drm_device *dev) vgdev->dev = dev->dev; spin_lock_init(&vgdev->display_info_lock); + spin_lock_init(&vgdev->resource_export_lock); ida_init(&vgdev->ctx_id_ida); ida_init(&vgdev->resource_ida); init_waitqueue_head(&vgdev->resp_wq); @@ -146,6 +147,9 @@ int virtio_gpu_init(struct drm_device *dev) if (virtio_has_feature(vgdev->vdev, VIRTIO_RING_F_INDIRECT_DESC)) { vgdev->has_indirect = true; } + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_UUID)) { + vgdev->has_resource_assign_uuid = true; + } DRM_INFO("features: %cvirgl %cedid\n", vgdev->has_virgl_3d ? '+' : '-', diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index e83651b7747d..842f8b61aa89 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -151,7 +151,13 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev, if (ret < 0) return -EINVAL; - shmem->pages = drm_gem_shmem_get_pages_sgt(&bo->base.base); + /* + * virtio_gpu uses drm_gem_shmem_get_sg_table instead of + * drm_gem_shmem_get_pages_sgt because virtio has it's own set of + * dma-ops. This is discouraged for other drivers, but should be fine + * since virtio_gpu doesn't support dma-buf import from other devices. + */ + shmem->pages = drm_gem_shmem_get_sg_table(&bo->base.base); if (!shmem->pages) { drm_gem_shmem_unpin(&bo->base.base); return -EINVAL; diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c index 050d24c39a8f..acd14ef73d56 100644 --- a/drivers/gpu/drm/virtio/virtgpu_prime.c +++ b/drivers/gpu/drm/virtio/virtgpu_prime.c @@ -23,12 +23,102 @@ */ #include <drm/drm_prime.h> +#include <linux/virtio_dma_buf.h> #include "virtgpu_drv.h" -/* Empty Implementations as there should not be any other driver for a virtual - * device that might share buffers with virtgpu - */ +static int virtgpu_virtio_get_uuid(struct dma_buf *buf, + uuid_t *uuid) +{ + struct drm_gem_object *obj = buf->priv; + struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); + struct virtio_gpu_device *vgdev = obj->dev->dev_private; + + wait_event(vgdev->resp_wq, bo->uuid_state != UUID_INITIALIZING); + if (bo->uuid_state != UUID_INITIALIZED) + return -ENODEV; + + uuid_copy(uuid, &bo->uuid); + + return 0; +} + +const struct virtio_dma_buf_ops virtgpu_dmabuf_ops = { + .ops = { + .cache_sgt_mapping = true, + .attach = virtio_dma_buf_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, + }, + .device_attach = drm_gem_map_attach, + .get_uuid = virtgpu_virtio_get_uuid, +}; + +struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj, + int flags) +{ + struct dma_buf *buf; + struct drm_device *dev = obj->dev; + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); + struct virtio_gpu_object_array *objs; + int ret = 0; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + if (vgdev->has_resource_assign_uuid) { + objs = virtio_gpu_array_alloc(1); + if (!objs) + return ERR_PTR(-ENOMEM); + virtio_gpu_array_add_obj(objs, &bo->base.base); + + ret = virtio_gpu_cmd_resource_assign_uuid(vgdev, objs); + if (ret) + return ERR_PTR(ret); + virtio_gpu_notify(vgdev); + } else { + bo->uuid_state = UUID_INITIALIZATION_FAILED; + } + + exp_info.ops = &virtgpu_dmabuf_ops.ops; + exp_info.size = obj->size; + exp_info.flags = flags; + exp_info.priv = obj; + exp_info.resv = obj->resv; + + buf = virtio_dma_buf_export(&exp_info); + if (IS_ERR(buf)) + return buf; + + drm_dev_get(dev); + drm_gem_object_get(obj); + + return buf; +} + +struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev, + struct dma_buf *buf) +{ + struct drm_gem_object *obj; + + if (buf->ops == &virtgpu_dmabuf_ops.ops) { + obj = buf->priv; + if (obj->dev == dev) { + /* + * Importing dmabuf exported from our own gem increases + * refcount on gem itself instead of f_count of dmabuf. + */ + drm_gem_object_get(obj); + return obj; + } + } + + return drm_gem_prime_import(dev, buf); +} struct drm_gem_object *virtgpu_gem_prime_import_sg_table( struct drm_device *dev, struct dma_buf_attachment *attach, diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 53af60d484a4..c93c2db35aaf 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -1107,3 +1107,58 @@ void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, memcpy(cur_p, &output->cursor, sizeof(output->cursor)); virtio_gpu_queue_cursor(vgdev, vbuf); } + +static void virtio_gpu_cmd_resource_uuid_cb(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf) +{ + struct virtio_gpu_object *obj = + gem_to_virtio_gpu_obj(vbuf->objs->objs[0]); + struct virtio_gpu_resp_resource_uuid *resp = + (struct virtio_gpu_resp_resource_uuid *)vbuf->resp_buf; + uint32_t resp_type = le32_to_cpu(resp->hdr.type); + + spin_lock(&vgdev->resource_export_lock); + WARN_ON(obj->uuid_state != UUID_INITIALIZING); + + if (resp_type == VIRTIO_GPU_RESP_OK_RESOURCE_UUID && + obj->uuid_state == UUID_INITIALIZING) { + memcpy(&obj->uuid.b, resp->uuid, sizeof(obj->uuid.b)); + obj->uuid_state = UUID_INITIALIZED; + } else { + obj->uuid_state = UUID_INITIALIZATION_FAILED; + } + spin_unlock(&vgdev->resource_export_lock); + + wake_up_all(&vgdev->resp_wq); +} + +int +virtio_gpu_cmd_resource_assign_uuid(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object_array *objs) +{ + struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(objs->objs[0]); + struct virtio_gpu_resource_assign_uuid *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + struct virtio_gpu_resp_resource_uuid *resp_buf; + + resp_buf = kzalloc(sizeof(*resp_buf), GFP_KERNEL); + if (!resp_buf) { + spin_lock(&vgdev->resource_export_lock); + bo->uuid_state = UUID_INITIALIZATION_FAILED; + spin_unlock(&vgdev->resource_export_lock); + virtio_gpu_array_put_free(objs); + return -ENOMEM; + } + + cmd_p = virtio_gpu_alloc_cmd_resp + (vgdev, virtio_gpu_cmd_resource_uuid_cb, &vbuf, sizeof(*cmd_p), + sizeof(struct virtio_gpu_resp_resource_uuid), resp_buf); + memset(cmd_p, 0, sizeof(*cmd_p)); + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID); + cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle); + + vbuf->objs = objs; + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); + return 0; +} diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 4af2f19480f4..4f3b07a32b60 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -33,7 +33,7 @@ static uint32_t compute_crc(void *vaddr_out, struct vkms_composer *composer) + (i * composer->pitch) + (j * composer->cpp); /* XRGB format ignores Alpha channel */ - memset(vaddr_out + src_offset + 24, 0, 8); + bitmap_clear(vaddr_out + src_offset, 24, 8); crc = crc32_le(crc, vaddr_out + src_offset, sizeof(u32)); } @@ -233,6 +233,22 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *src_name, return 0; } +static void vkms_set_composer(struct vkms_output *out, bool enabled) +{ + bool old_enabled; + + if (enabled) + drm_crtc_vblank_get(&out->crtc); + + spin_lock_irq(&out->lock); + old_enabled = out->composer_enabled; + out->composer_enabled = enabled; + spin_unlock_irq(&out->lock); + + if (old_enabled) + drm_crtc_vblank_put(&out->crtc); +} + int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name) { struct vkms_output *out = drm_crtc_to_vkms_output(crtc); @@ -241,9 +257,7 @@ int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name) ret = vkms_crc_parse_source(src_name, &enabled); - spin_lock_irq(&out->lock); - out->composer_enabled = enabled; - spin_unlock_irq(&out->lock); + vkms_set_composer(out, enabled); return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 57a8a397d5e8..83dd5567de8b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -190,8 +190,8 @@ static int __init vkms_init(void) out_put: drm_dev_put(&vkms_device->drm); + platform_device_unregister(vkms_device->platform); return ret; - out_unregister: platform_device_unregister(vkms_device->platform); out_free: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 1e59c019affa..3229451d0706 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -1135,14 +1135,14 @@ void vmw_bo_swap_notify(struct ttm_buffer_object *bo) * vmw_bo_move_notify - TTM move_notify_callback * * @bo: The TTM buffer object about to move. - * @mem: The struct ttm_mem_reg indicating to what memory + * @mem: The struct ttm_resource indicating to what memory * region the move is taking place. * * Detaches cached maps and device bindings that require that the * buffer doesn't move. */ void vmw_bo_move_notify(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { struct vmw_buffer_object *vbo; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index fb39826f72c1..e60012886065 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -620,6 +620,29 @@ static int vmw_dma_masks(struct vmw_private *dev_priv) return ret; } +static int vmw_vram_manager_init(struct vmw_private *dev_priv) +{ + int ret; +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + ret = vmw_thp_init(dev_priv); +#else + ret = ttm_range_man_init(&dev_priv->bdev, TTM_PL_VRAM, + TTM_PL_FLAG_CACHED, TTM_PL_FLAG_CACHED, + false, dev_priv->vram_size >> PAGE_SHIFT); +#endif + ttm_resource_manager_set_used(ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM), false); + return ret; +} + +static void vmw_vram_manager_fini(struct vmw_private *dev_priv) +{ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + vmw_thp_fini(dev_priv); +#else + ttm_range_man_fini(&dev_priv->bdev, TTM_PL_VRAM); +#endif +} + static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) { struct vmw_private *dev_priv; @@ -859,23 +882,30 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) DRM_ERROR("Failed initializing TTM buffer object driver.\n"); goto out_no_bdev; } + ttm_manager_type(&dev_priv->bdev, TTM_PL_SYSTEM)->available_caching = + TTM_PL_FLAG_CACHED; /* * Enable VRAM, but initially don't use it until SVGA is enabled and * unhidden. */ - ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM, - (dev_priv->vram_size >> PAGE_SHIFT)); + + ret = vmw_vram_manager_init(dev_priv); if (unlikely(ret != 0)) { DRM_ERROR("Failed initializing memory manager for VRAM.\n"); goto out_no_vram; } - dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; + /* + * "Guest Memory Regions" is an aperture like feature with + * one slot per bo. There is an upper limit of the number of + * slots as well as the bo size. + */ dev_priv->has_gmr = true; + /* TODO: This is most likely not correct */ if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || - refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR, - VMW_PL_GMR) != 0) { + refuse_dma || + vmw_gmrid_man_init(dev_priv, VMW_PL_GMR) != 0) { DRM_INFO("No GMR memory available. " "Graphics memory resources are very limited.\n"); dev_priv->has_gmr = false; @@ -883,8 +913,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS && !refuse_dma) { dev_priv->has_mob = true; - if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB, - VMW_PL_MOB) != 0) { + + if (vmw_gmrid_man_init(dev_priv, VMW_PL_MOB) != 0) { DRM_INFO("No MOB memory available. " "3D will be disabled.\n"); dev_priv->has_mob = false; @@ -961,10 +991,10 @@ out_no_fifo: vmw_kms_close(dev_priv); out_no_kms: if (dev_priv->has_mob) - (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); + vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB); if (dev_priv->has_gmr) - (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); - (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); + vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR); + vmw_vram_manager_fini(dev_priv); out_no_vram: (void)ttm_bo_device_release(&dev_priv->bdev); out_no_bdev: @@ -1012,12 +1042,12 @@ static void vmw_driver_unload(struct drm_device *dev) vmw_overlay_close(dev_priv); if (dev_priv->has_gmr) - (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); - (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); + vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR); vmw_release_device_early(dev_priv); if (dev_priv->has_mob) - (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); + vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB); + vmw_vram_manager_fini(dev_priv); (void) ttm_bo_device_release(&dev_priv->bdev); drm_vma_offset_manager_destroy(&dev_priv->vma_manager); vmw_release_device_late(dev_priv); @@ -1159,10 +1189,12 @@ static void vmw_master_drop(struct drm_device *dev, */ static void __vmw_svga_enable(struct vmw_private *dev_priv) { + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); + spin_lock(&dev_priv->svga_lock); - if (!dev_priv->bdev.man[TTM_PL_VRAM].use_type) { + if (!ttm_resource_manager_used(man)) { vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE); - dev_priv->bdev.man[TTM_PL_VRAM].use_type = true; + ttm_resource_manager_set_used(man, true); } spin_unlock(&dev_priv->svga_lock); } @@ -1188,9 +1220,11 @@ void vmw_svga_enable(struct vmw_private *dev_priv) */ static void __vmw_svga_disable(struct vmw_private *dev_priv) { + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); + spin_lock(&dev_priv->svga_lock); - if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { - dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; + if (ttm_resource_manager_used(man)) { + ttm_resource_manager_set_used(man, false); vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_HIDE | SVGA_REG_ENABLE_ENABLE); @@ -1207,6 +1241,7 @@ static void __vmw_svga_disable(struct vmw_private *dev_priv) */ void vmw_svga_disable(struct vmw_private *dev_priv) { + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); /* * Disabling SVGA will turn off device modesetting capabilities, so * notify KMS about that so that it doesn't cache atomic state that @@ -1222,8 +1257,8 @@ void vmw_svga_disable(struct vmw_private *dev_priv) vmw_kms_lost_device(dev_priv->dev); ttm_write_lock(&dev_priv->reservation_sem, false); spin_lock(&dev_priv->svga_lock); - if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { - dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; + if (ttm_resource_manager_used(man)) { + ttm_resource_manager_set_used(man, false); spin_unlock(&dev_priv->svga_lock); if (ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM)) DRM_ERROR("Failed evicting VRAM buffers.\n"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 3596f3923ea3..871ad738dadb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -793,7 +793,7 @@ extern void vmw_resource_unreserve(struct vmw_resource *res, struct vmw_buffer_object *new_backup, unsigned long new_backup_offset); extern void vmw_query_move_notify(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob); extern void vmw_resource_evict_all(struct vmw_private *dev_priv); extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo); @@ -878,7 +878,7 @@ extern void vmw_bo_fence_single(struct ttm_buffer_object *bo, extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo); extern void vmw_bo_unmap(struct vmw_buffer_object *vbo); extern void vmw_bo_move_notify(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo); extern struct vmw_buffer_object * vmw_user_bo_noref_lookup(struct ttm_object_file *tfile, u32 handle); @@ -1019,10 +1019,12 @@ extern struct ttm_placement vmw_mob_placement; extern struct ttm_placement vmw_mob_ne_placement; extern struct ttm_placement vmw_nonfixed_placement; extern struct ttm_bo_driver vmw_bo_driver; -extern int vmw_bo_map_dma(struct ttm_buffer_object *bo); -extern void vmw_bo_unmap_dma(struct ttm_buffer_object *bo); extern const struct vmw_sg_table * vmw_bo_sg_table(struct ttm_buffer_object *bo); +extern int vmw_bo_create_and_populate(struct vmw_private *dev_priv, + unsigned long bo_size, + struct ttm_buffer_object **bo_p); + extern void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt, unsigned long p_offs); @@ -1219,7 +1221,8 @@ int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv); * GMR Id manager */ -extern const struct ttm_mem_type_manager_func vmw_gmrid_manager_func; +int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type); +void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type); /** * Prime - vmwgfx_prime.c @@ -1518,9 +1521,8 @@ vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf, /* Transparent hugepage support - vmwgfx_thp.c */ #ifdef CONFIG_TRANSPARENT_HUGEPAGE -extern const struct ttm_mem_type_manager_func vmw_thp_func; -#else -#define vmw_thp_func ttm_bo_manager_func +extern int vmw_thp_init(struct vmw_private *dev_priv); +void vmw_thp_fini(struct vmw_private *dev_priv); #endif /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index 4a76fc7114ad..bb76acb5b0fc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -37,6 +37,7 @@ #include <linux/kernel.h> struct vmwgfx_gmrid_man { + struct ttm_resource_manager manager; spinlock_t lock; struct ida gmr_ida; uint32_t max_gmr_ids; @@ -44,13 +45,17 @@ struct vmwgfx_gmrid_man { uint32_t used_gmr_pages; }; -static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man, +static struct vmwgfx_gmrid_man *to_gmrid_manager(struct ttm_resource_manager *man) +{ + return container_of(man, struct vmwgfx_gmrid_man, manager); +} + +static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man, struct ttm_buffer_object *bo, const struct ttm_place *place, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { - struct vmwgfx_gmrid_man *gman = - (struct vmwgfx_gmrid_man *)man->priv; + struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); int id; id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); @@ -79,11 +84,10 @@ nospace: return -ENOSPC; } -static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, - struct ttm_mem_reg *mem) +static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man, + struct ttm_resource *mem) { - struct vmwgfx_gmrid_man *gman = - (struct vmwgfx_gmrid_man *)man->priv; + struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); if (mem->mm_node) { ida_free(&gman->gmr_ida, mem->start); @@ -94,22 +98,30 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, } } -static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man, - unsigned long p_size) +static const struct ttm_resource_manager_func vmw_gmrid_manager_func; + +int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type) { - struct vmw_private *dev_priv = - container_of(man->bdev, struct vmw_private, bdev); + struct ttm_resource_manager *man; struct vmwgfx_gmrid_man *gman = kzalloc(sizeof(*gman), GFP_KERNEL); if (unlikely(!gman)) return -ENOMEM; + man = &gman->manager; + + man->func = &vmw_gmrid_manager_func; + man->available_caching = TTM_PL_FLAG_CACHED; + man->default_caching = TTM_PL_FLAG_CACHED; + /* TODO: This is most likely not correct */ + man->use_tt = true; + ttm_resource_manager_init(man, 0); spin_lock_init(&gman->lock); gman->used_gmr_pages = 0; ida_init(&gman->gmr_ida); - switch (p_size) { + switch (type) { case VMW_PL_GMR: gman->max_gmr_ids = dev_priv->max_gmr_ids; gman->max_gmr_pages = dev_priv->max_gmr_pages; @@ -121,32 +133,29 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man, default: BUG(); } - man->priv = (void *) gman; + ttm_set_driver_manager(&dev_priv->bdev, type, &gman->manager); + ttm_resource_manager_set_used(man, true); return 0; } -static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man) +void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type) { - struct vmwgfx_gmrid_man *gman = - (struct vmwgfx_gmrid_man *)man->priv; + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, type); + struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); - if (gman) { - ida_destroy(&gman->gmr_ida); - kfree(gman); - } - return 0; -} + ttm_resource_manager_set_used(man, false); + + ttm_resource_manager_force_list_clean(&dev_priv->bdev, man); + + ttm_resource_manager_cleanup(man); + + ttm_set_driver_manager(&dev_priv->bdev, type, NULL); + ida_destroy(&gman->gmr_ida); + kfree(gman); -static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man, - struct drm_printer *printer) -{ - drm_printf(printer, "No debug info available for the GMR id manager\n"); } -const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = { - .init = vmw_gmrid_man_init, - .takedown = vmw_gmrid_man_takedown, - .get_node = vmw_gmrid_man_get_node, - .put_node = vmw_gmrid_man_put_node, - .debug = vmw_gmrid_man_debug +static const struct ttm_resource_manager_func vmw_gmrid_manager_func = { + .alloc = vmw_gmrid_man_get_node, + .free = vmw_gmrid_man_put_node, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index e8eb42933ca2..7f95ed6aa224 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -238,10 +238,6 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv, unsigned long offset; unsigned long bo_size; struct vmw_otable *otables = batch->otables; - struct ttm_operation_ctx ctx = { - .interruptible = false, - .no_wait_gpu = false - }; SVGAOTableType i; int ret; @@ -255,24 +251,9 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv, bo_size += otables[i].size; } - ret = ttm_bo_create(&dev_priv->bdev, bo_size, - ttm_bo_type_device, - &vmw_sys_ne_placement, - 0, false, &batch->otable_bo); - - if (unlikely(ret != 0)) - goto out_no_bo; - - ret = ttm_bo_reserve(batch->otable_bo, false, true, NULL); - BUG_ON(ret != 0); - ret = vmw_bo_driver.ttm_tt_populate(batch->otable_bo->ttm, &ctx); - if (unlikely(ret != 0)) - goto out_unreserve; - ret = vmw_bo_map_dma(batch->otable_bo); + ret = vmw_bo_create_and_populate(dev_priv, bo_size, &batch->otable_bo); if (unlikely(ret != 0)) - goto out_unreserve; - - ttm_bo_unreserve(batch->otable_bo); + return ret; offset = 0; for (i = 0; i < batch->num_otables; ++i) { @@ -289,8 +270,6 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv, return 0; -out_unreserve: - ttm_bo_unreserve(batch->otable_bo); out_no_setup: for (i = 0; i < batch->num_otables; ++i) { if (batch->otables[i].enabled) @@ -300,7 +279,6 @@ out_no_setup: ttm_bo_put(batch->otable_bo); batch->otable_bo = NULL; -out_no_bo: return ret; } @@ -432,41 +410,9 @@ struct vmw_mob *vmw_mob_create(unsigned long data_pages) static int vmw_mob_pt_populate(struct vmw_private *dev_priv, struct vmw_mob *mob) { - int ret; - struct ttm_operation_ctx ctx = { - .interruptible = false, - .no_wait_gpu = false - }; - BUG_ON(mob->pt_bo != NULL); - ret = ttm_bo_create(&dev_priv->bdev, mob->num_pages * PAGE_SIZE, - ttm_bo_type_device, - &vmw_sys_ne_placement, - 0, false, &mob->pt_bo); - if (unlikely(ret != 0)) - return ret; - - ret = ttm_bo_reserve(mob->pt_bo, false, true, NULL); - - BUG_ON(ret != 0); - ret = vmw_bo_driver.ttm_tt_populate(mob->pt_bo->ttm, &ctx); - if (unlikely(ret != 0)) - goto out_unreserve; - ret = vmw_bo_map_dma(mob->pt_bo); - if (unlikely(ret != 0)) - goto out_unreserve; - - ttm_bo_unreserve(mob->pt_bo); - - return 0; - -out_unreserve: - ttm_bo_unreserve(mob->pt_bo); - ttm_bo_put(mob->pt_bo); - mob->pt_bo = NULL; - - return ret; + return vmw_bo_create_and_populate(dev_priv, mob->num_pages * PAGE_SIZE, &mob->pt_bo); } /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index c8441030637a..c0f156078dda 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -855,7 +855,7 @@ int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob) * states from the device. */ void vmw_query_move_notify(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { struct vmw_buffer_object *dx_query_mob; struct ttm_bo_device *bdev = bo->bdev; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c index b7c816ba7166..3c00a9e7cfcc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c @@ -16,14 +16,20 @@ * @lock: Manager lock. */ struct vmw_thp_manager { + struct ttm_resource_manager manager; struct drm_mm mm; spinlock_t lock; }; +static struct vmw_thp_manager *to_thp_manager(struct ttm_resource_manager *man) +{ + return container_of(man, struct vmw_thp_manager, manager); +} + static int vmw_thp_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node, unsigned long align_pages, const struct ttm_place *place, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, unsigned long lpfn, enum drm_mm_insert_mode mode) { @@ -38,12 +44,12 @@ static int vmw_thp_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node, return -ENOSPC; } -static int vmw_thp_get_node(struct ttm_mem_type_manager *man, +static int vmw_thp_get_node(struct ttm_resource_manager *man, struct ttm_buffer_object *bo, const struct ttm_place *place, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { - struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv; + struct vmw_thp_manager *rman = to_thp_manager(man); struct drm_mm *mm = &rman->mm; struct drm_mm_node *node; unsigned long align_pages; @@ -100,10 +106,10 @@ found_unlock: -static void vmw_thp_put_node(struct ttm_mem_type_manager *man, - struct ttm_mem_reg *mem) +static void vmw_thp_put_node(struct ttm_resource_manager *man, + struct ttm_resource *mem) { - struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv; + struct vmw_thp_manager *rman = to_thp_manager(man); if (mem->mm_node) { spin_lock(&rman->lock); @@ -115,52 +121,63 @@ static void vmw_thp_put_node(struct ttm_mem_type_manager *man, } } -static int vmw_thp_init(struct ttm_mem_type_manager *man, - unsigned long p_size) +int vmw_thp_init(struct vmw_private *dev_priv) { + struct ttm_resource_manager *man; struct vmw_thp_manager *rman; rman = kzalloc(sizeof(*rman), GFP_KERNEL); if (!rman) return -ENOMEM; - drm_mm_init(&rman->mm, 0, p_size); + man = &rman->manager; + man->available_caching = TTM_PL_FLAG_CACHED; + man->default_caching = TTM_PL_FLAG_CACHED; + + ttm_resource_manager_init(man, + dev_priv->vram_size >> PAGE_SHIFT); + + drm_mm_init(&rman->mm, 0, man->size); spin_lock_init(&rman->lock); - man->priv = rman; + + ttm_set_driver_manager(&dev_priv->bdev, TTM_PL_VRAM, &rman->manager); + ttm_resource_manager_set_used(man, true); return 0; } -static int vmw_thp_takedown(struct ttm_mem_type_manager *man) +void vmw_thp_fini(struct vmw_private *dev_priv) { - struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv; + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); + struct vmw_thp_manager *rman = to_thp_manager(man); struct drm_mm *mm = &rman->mm; + int ret; + + ttm_resource_manager_set_used(man, false); + ret = ttm_resource_manager_force_list_clean(&dev_priv->bdev, man); + if (ret) + return; spin_lock(&rman->lock); - if (drm_mm_clean(mm)) { - drm_mm_takedown(mm); - spin_unlock(&rman->lock); - kfree(rman); - man->priv = NULL; - return 0; - } + drm_mm_clean(mm); + drm_mm_takedown(mm); spin_unlock(&rman->lock); - return -EBUSY; + ttm_resource_manager_cleanup(man); + ttm_set_driver_manager(&dev_priv->bdev, TTM_PL_VRAM, NULL); + kfree(rman); } -static void vmw_thp_debug(struct ttm_mem_type_manager *man, +static void vmw_thp_debug(struct ttm_resource_manager *man, struct drm_printer *printer) { - struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv; + struct vmw_thp_manager *rman = to_thp_manager(man); spin_lock(&rman->lock); drm_mm_print(&rman->mm, printer); spin_unlock(&rman->lock); } -const struct ttm_mem_type_manager_func vmw_thp_func = { - .init = vmw_thp_init, - .takedown = vmw_thp_takedown, - .get_node = vmw_thp_get_node, - .put_node = vmw_thp_put_node, +const struct ttm_resource_manager_func vmw_thp_func = { + .alloc = vmw_thp_get_node, + .free = vmw_thp_put_node, .debug = vmw_thp_debug }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index ab524ab3b0b4..c7f10b2c93d2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -519,43 +519,6 @@ static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt) vmw_tt->mapped = false; } - -/** - * vmw_bo_map_dma - Make sure buffer object pages are visible to the device - * - * @bo: Pointer to a struct ttm_buffer_object - * - * Wrapper around vmw_ttm_map_dma, that takes a TTM buffer object pointer - * instead of a pointer to a struct vmw_ttm_backend as argument. - * Note that the buffer object must be either pinned or reserved before - * calling this function. - */ -int vmw_bo_map_dma(struct ttm_buffer_object *bo) -{ - struct vmw_ttm_tt *vmw_tt = - container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm); - - return vmw_ttm_map_dma(vmw_tt); -} - - -/** - * vmw_bo_unmap_dma - Make sure buffer object pages are visible to the device - * - * @bo: Pointer to a struct ttm_buffer_object - * - * Wrapper around vmw_ttm_unmap_dma, that takes a TTM buffer object pointer - * instead of a pointer to a struct vmw_ttm_backend as argument. - */ -void vmw_bo_unmap_dma(struct ttm_buffer_object *bo) -{ - struct vmw_ttm_tt *vmw_tt = - container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm); - - vmw_ttm_unmap_dma(vmw_tt); -} - - /** * vmw_bo_sg_table - Return a struct vmw_sg_table object for a * TTM buffer object @@ -576,7 +539,7 @@ const struct vmw_sg_table *vmw_bo_sg_table(struct ttm_buffer_object *bo) } -static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) +static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem) { struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm); @@ -734,40 +697,6 @@ out_no_init: return NULL; } -static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, - struct ttm_mem_type_manager *man) -{ - switch (type) { - case TTM_PL_SYSTEM: - /* System memory */ - man->available_caching = TTM_PL_FLAG_CACHED; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case TTM_PL_VRAM: - /* "On-card" video ram */ - man->func = &vmw_thp_func; - man->flags = TTM_MEMTYPE_FLAG_FIXED; - man->available_caching = TTM_PL_FLAG_CACHED; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case VMW_PL_GMR: - case VMW_PL_MOB: - /* - * "Guest Memory Regions" is an aperture like feature with - * one slot per bo. There is an upper limit of the number of - * slots as well as the bo size. - */ - man->func = &vmw_gmrid_manager_func; - man->available_caching = TTM_PL_FLAG_CACHED; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); - return -EINVAL; - } - return 0; -} - static void vmw_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement) { @@ -782,16 +711,10 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp) return vmw_user_bo_verify_access(bo, tfile); } -static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) +static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem) { struct vmw_private *dev_priv = container_of(bdev, struct vmw_private, bdev); - mem->bus.addr = NULL; - mem->bus.is_iomem = false; - mem->bus.offset = 0; - mem->bus.size = mem->num_pages << PAGE_SHIFT; - mem->bus.base = 0; - switch (mem->mem_type) { case TTM_PL_SYSTEM: case VMW_PL_GMR: @@ -812,7 +735,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg * vmw_move_notify - TTM move_notify_callback * * @bo: The TTM buffer object about to move. - * @mem: The struct ttm_mem_reg indicating to what memory + * @mem: The struct ttm_resource indicating to what memory * region the move is taking place. * * Calls move_notify for all subsystems needing it. @@ -820,7 +743,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg */ static void vmw_move_notify(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *mem) + struct ttm_resource *mem) { vmw_bo_move_notify(bo, mem); vmw_query_move_notify(bo, mem); @@ -843,7 +766,6 @@ struct ttm_bo_driver vmw_bo_driver = { .ttm_tt_create = &vmw_ttm_tt_create, .ttm_tt_populate = &vmw_ttm_populate, .ttm_tt_unpopulate = &vmw_ttm_unpopulate, - .init_mem_type = vmw_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = vmw_evict_flags, .move = NULL, @@ -852,3 +774,38 @@ struct ttm_bo_driver vmw_bo_driver = { .swap_notify = vmw_swap_notify, .io_mem_reserve = &vmw_ttm_io_mem_reserve, }; + +int vmw_bo_create_and_populate(struct vmw_private *dev_priv, + unsigned long bo_size, + struct ttm_buffer_object **bo_p) +{ + struct ttm_operation_ctx ctx = { + .interruptible = false, + .no_wait_gpu = false + }; + struct ttm_buffer_object *bo; + int ret; + + ret = ttm_bo_create(&dev_priv->bdev, bo_size, + ttm_bo_type_device, + &vmw_sys_ne_placement, + 0, false, &bo); + + if (unlikely(ret != 0)) + return ret; + + ret = ttm_bo_reserve(bo, false, true, NULL); + BUG_ON(ret != 0); + ret = vmw_ttm_populate(bo->ttm, &ctx); + if (likely(ret == 0)) { + struct vmw_ttm_tt *vmw_tt = + container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm); + ret = vmw_ttm_map_dma(vmw_tt); + } + + ttm_bo_unreserve(bo); + + if (likely(ret == 0)) + *bo_p = bo; + return ret; +} diff --git a/drivers/video/fbdev/arcfb.c b/drivers/video/fbdev/arcfb.c index ae3d8e8b8d33..1447324ed0b6 100644 --- a/drivers/video/fbdev/arcfb.c +++ b/drivers/video/fbdev/arcfb.c @@ -419,7 +419,7 @@ static int arcfb_ioctl(struct fb_info *info, schedule(); finish_wait(&arcfb_waitq, &wait); } - fallthrough; + fallthrough; case FBIO_GETCONTROL2: { diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index bfd2f00b403b..8c1d47e52b1a 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -633,7 +633,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info) case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; - case 15: + case 15: fallthrough; case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 6815bfb7f572..cc69649dce95 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -777,7 +777,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (info->fbops->fb_read) return info->fbops->fb_read(info, buf, count, ppos); - + total_size = info->screen_size; if (total_size == 0) @@ -842,7 +842,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (info->fbops->fb_write) return info->fbops->fb_write(info, buf, count, ppos); - + total_size = info->screen_size; if (total_size == 0) @@ -1057,7 +1057,7 @@ EXPORT_SYMBOL(fb_set_var); int fb_blank(struct fb_info *info, int blank) -{ +{ struct fb_event event; int ret = -EINVAL; @@ -1433,7 +1433,7 @@ out: return res; } -static int +static int fb_release(struct inode *inode, struct file *file) __acquires(&info->lock) __releases(&info->lock) @@ -1623,7 +1623,7 @@ static int do_register_framebuffer(struct fb_info *fb_info) fb_info->pixmap.access_align = 32; fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; } - } + } fb_info->pixmap.offset = 0; if (!fb_info->pixmap.blit_x) diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c index 22f1d37a968a..496b43bdad21 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c @@ -19,7 +19,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/clk.h> -#include <linux/gpio.h> +#include <linux/of.h> #include <linux/regulator/consumer.h> #include <linux/component.h> #include <video/omapfb_dss.h> diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c index a06b6f1355bd..e3d441ade241 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c @@ -24,7 +24,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/clk.h> -#include <linux/gpio.h> +#include <linux/of.h> #include <linux/regulator/consumer.h> #include <linux/component.h> #include <video/omapfb_dss.h> diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index 2d9f69b93392..f4add36cb5f4 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -1028,6 +1028,8 @@ static int __init pvr2fb_setup(char *options) if (!options || !*options) return 0; + cable_arg[0] = output_arg[0] = 0; + while ((this_opt = strsep(&options, ","))) { if (!*this_opt) continue; diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c index a2442aae7e12..661398e40ff4 100644 --- a/drivers/video/fbdev/savage/savagefb_driver.c +++ b/drivers/video/fbdev/savage/savagefb_driver.c @@ -1859,7 +1859,6 @@ static int savage_init_hw(struct savagefb_par *par) vga_out8(0x3d4, 0x68, par); /* memory control 1 */ if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6)) RamSavage4[1] = 8; - fallthrough; case S3_SAVAGE2000: diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 5c92e4a50882..e76e9b9ba93c 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -126,4 +126,11 @@ config VIRTIO_MMIO_CMDLINE_DEVICES If unsure, say 'N'. +config VIRTIO_DMA_SHARED_BUFFER + tristate + depends on DMA_SHARED_BUFFER + help + This option adds a flavor of dma buffers that are backed by + virtio resources. + endif # VIRTIO_MENU diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 4d993791f2d7..591e6f72aa54 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o obj-$(CONFIG_VIRTIO_VDPA) += virtio_vdpa.o obj-$(CONFIG_VIRTIO_MEM) += virtio_mem.o +obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) += virtio_dma_buf.o diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index a977e32a88f2..5d46f0ded92d 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -357,6 +357,12 @@ out: } EXPORT_SYMBOL_GPL(register_virtio_device); +bool is_virtio_device(struct device *dev) +{ + return dev->bus == &virtio_bus; +} +EXPORT_SYMBOL_GPL(is_virtio_device); + void unregister_virtio_device(struct virtio_device *dev) { int index = dev->index; /* save for after device release */ diff --git a/drivers/virtio/virtio_dma_buf.c b/drivers/virtio/virtio_dma_buf.c new file mode 100644 index 000000000000..5127a2f0c986 --- /dev/null +++ b/drivers/virtio/virtio_dma_buf.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * dma-bufs for virtio exported objects + * + * Copyright (C) 2020 Google, Inc. + */ + +#include <linux/module.h> +#include <linux/virtio_dma_buf.h> + +/** + * virtio_dma_buf_export - Creates a new dma-buf for a virtio exported object + * @exp_info: [in] see dma_buf_export(). ops MUST refer to a dma_buf_ops + * struct embedded in a virtio_dma_buf_ops. + * + * This wraps dma_buf_export() to allow virtio drivers to create a dma-buf + * for an virtio exported object that can be queried by other virtio drivers + * for the object's UUID. + */ +struct dma_buf *virtio_dma_buf_export + (const struct dma_buf_export_info *exp_info) +{ + const struct virtio_dma_buf_ops *virtio_ops = + container_of(exp_info->ops, + const struct virtio_dma_buf_ops, ops); + + if (!exp_info->ops || + exp_info->ops->attach != &virtio_dma_buf_attach || + !virtio_ops->get_uuid) { + return ERR_PTR(-EINVAL); + } + + return dma_buf_export(exp_info); +} +EXPORT_SYMBOL(virtio_dma_buf_export); + +/** + * virtio_dma_buf_attach - mandatory attach callback for virtio dma-bufs + */ +int virtio_dma_buf_attach(struct dma_buf *dma_buf, + struct dma_buf_attachment *attach) +{ + int ret; + const struct virtio_dma_buf_ops *ops = + container_of(dma_buf->ops, + const struct virtio_dma_buf_ops, ops); + + if (ops->device_attach) { + ret = ops->device_attach(dma_buf, attach); + if (ret) + return ret; + } + return 0; +} +EXPORT_SYMBOL(virtio_dma_buf_attach); + +/** + * is_virtio_dma_buf - returns true if the given dma-buf is a virtio dma-buf + * @dma_buf: buffer to query + */ +bool is_virtio_dma_buf(struct dma_buf *dma_buf) +{ + return dma_buf->ops->attach == &virtio_dma_buf_attach; +} +EXPORT_SYMBOL(is_virtio_dma_buf); + +/** + * virtio_dma_buf_get_uuid - gets a virtio dma-buf's exported object's uuid + * @dma_buf: [in] buffer to query + * @uuid: [out] the uuid + * + * Returns: 0 on success, negative on failure. + */ +int virtio_dma_buf_get_uuid(struct dma_buf *dma_buf, + uuid_t *uuid) +{ + const struct virtio_dma_buf_ops *ops = + container_of(dma_buf->ops, + const struct virtio_dma_buf_ops, ops); + + if (!is_virtio_dma_buf(dma_buf)) + return -EINVAL; + + return ops->get_uuid(dma_buf, uuid); +} +EXPORT_SYMBOL(virtio_dma_buf_get_uuid); + +MODULE_LICENSE("GPL"); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index af145608b5ed..928136556174 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1604,10 +1604,13 @@ const char *drm_get_dvi_i_subconnector_name(int val); const char *drm_get_dvi_i_select_name(int val); const char *drm_get_tv_subconnector_name(int val); const char *drm_get_tv_select_name(int val); +const char *drm_get_dp_subconnector_name(int val); const char *drm_get_content_protection_name(int val); const char *drm_get_hdcp_content_type_name(int val); int drm_mode_create_dvi_i_properties(struct drm_device *dev); +void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector); + int drm_mode_create_tv_margin_properties(struct drm_device *dev); int drm_mode_create_tv_properties(struct drm_device *dev, unsigned int num_modes, diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index e47dc22ebf50..5c2819924862 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/types.h> +#include <drm/drm_connector.h> /* * Unless otherwise noted, all values are from the DP 1.1a spec. Note that @@ -1619,6 +1620,13 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]); void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], struct drm_dp_aux *aux); +enum drm_mode_subconnector +drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]); +void drm_dp_set_subconnector_property(struct drm_connector *connector, + enum drm_connector_status status, + const u8 *dpcd, + const u8 port_cap[4]); void drm_dp_remote_aux_init(struct drm_dp_aux *aux); void drm_dp_aux_init(struct drm_dp_aux *aux); diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index c2d3d71d133c..a18f73eb3cf6 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -681,6 +681,12 @@ struct drm_mode_config { struct drm_property *dvi_i_select_subconnector_property; /** + * @dp_subconnector_property: Optional DP property to differentiate + * between different DP downstream port types. + */ + struct drm_property *dp_subconnector_property; + + /** * @tv_subconnector_property: Optional TV property to differentiate * between different TV connector types. */ diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 6193cb555acc..33605c3f0eba 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -35,6 +35,8 @@ struct drm_device; struct drm_panel; struct display_timing; +enum drm_panel_orientation; + /** * struct drm_panel_funcs - perform operations on a given panel * @@ -175,12 +177,9 @@ void drm_panel_init(struct drm_panel *panel, struct device *dev, const struct drm_panel_funcs *funcs, int connector_type); -int drm_panel_add(struct drm_panel *panel); +void drm_panel_add(struct drm_panel *panel); void drm_panel_remove(struct drm_panel *panel); -int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector); -void drm_panel_detach(struct drm_panel *panel); - int drm_panel_prepare(struct drm_panel *panel); int drm_panel_unprepare(struct drm_panel *panel); @@ -191,11 +190,19 @@ int drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector #if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) struct drm_panel *of_drm_find_panel(const struct device_node *np); +int of_drm_get_panel_orientation(const struct device_node *np, + enum drm_panel_orientation *orientation); #else static inline struct drm_panel *of_drm_find_panel(const struct device_node *np) { return ERR_PTR(-ENODEV); } + +static inline int of_drm_get_panel_orientation(const struct device_node *np, + enum drm_panel_orientation *orientation) +{ + return -ENODEV; +} #endif #if IS_ENABLED(CONFIG_DRM_PANEL) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \ diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index b9780ae9dd26..92436553fd6a 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -33,15 +33,16 @@ struct drm_gpu_scheduler; struct drm_sched_rq; +/* These are often used as an (initial) index + * to an array, and as such should start at 0. + */ enum drm_sched_priority { DRM_SCHED_PRIORITY_MIN, - DRM_SCHED_PRIORITY_LOW = DRM_SCHED_PRIORITY_MIN, DRM_SCHED_PRIORITY_NORMAL, - DRM_SCHED_PRIORITY_HIGH_SW, - DRM_SCHED_PRIORITY_HIGH_HW, + DRM_SCHED_PRIORITY_HIGH, DRM_SCHED_PRIORITY_KERNEL, - DRM_SCHED_PRIORITY_MAX, - DRM_SCHED_PRIORITY_INVALID = -1, + + DRM_SCHED_PRIORITY_COUNT, DRM_SCHED_PRIORITY_UNSET = -2 }; @@ -274,7 +275,7 @@ struct drm_gpu_scheduler { uint32_t hw_submission_limit; long timeout; const char *name; - struct drm_sched_rq sched_rq[DRM_SCHED_PRIORITY_MAX]; + struct drm_sched_rq sched_rq[DRM_SCHED_PRIORITY_COUNT]; wait_queue_head_t wake_up_worker; wait_queue_head_t job_scheduled; atomic_t hw_rq_count; diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 96e408b4bdc9..8e7ae30ebcbb 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -258,9 +258,7 @@ INTEL_VGA_DEVICE(0x0f30, info), \ INTEL_VGA_DEVICE(0x0f31, info), \ INTEL_VGA_DEVICE(0x0f32, info), \ - INTEL_VGA_DEVICE(0x0f33, info), \ - INTEL_VGA_DEVICE(0x0157, info), \ - INTEL_VGA_DEVICE(0x0155, info) + INTEL_VGA_DEVICE(0x0f33, info) #define INTEL_BDW_ULT_GT1_IDS(info) \ INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \ diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index a9e13b252820..6c580987ba16 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -42,6 +42,8 @@ #include <linux/bitmap.h> #include <linux/dma-resv.h> +#include "ttm_resource.h" + struct ttm_bo_global; struct ttm_bo_device; @@ -55,55 +57,6 @@ struct ttm_place; struct ttm_lru_bulk_move; /** - * struct ttm_bus_placement - * - * @addr: mapped virtual address - * @base: bus base address - * @is_iomem: is this io memory ? - * @size: size in byte - * @offset: offset from the base address - * @io_reserved_vm: The VM system has a refcount in @io_reserved_count - * @io_reserved_count: Refcounting the numbers of callers to ttm_mem_io_reserve - * - * Structure indicating the bus placement of an object. - */ -struct ttm_bus_placement { - void *addr; - phys_addr_t base; - unsigned long size; - unsigned long offset; - bool is_iomem; - bool io_reserved_vm; - uint64_t io_reserved_count; -}; - - -/** - * struct ttm_mem_reg - * - * @mm_node: Memory manager node. - * @size: Requested size of memory region. - * @num_pages: Actual size of memory region in pages. - * @page_alignment: Page alignment. - * @placement: Placement flags. - * @bus: Placement on io bus accessible to the CPU - * - * Structure indicating the placement and space resources used by a - * buffer object. - */ - -struct ttm_mem_reg { - void *mm_node; - unsigned long start; - unsigned long size; - unsigned long num_pages; - uint32_t page_alignment; - uint32_t mem_type; - uint32_t placement; - struct ttm_bus_placement bus; -}; - -/** * enum ttm_bo_type * * @ttm_bo_type_device: These are 'normal' buffers that can @@ -185,7 +138,7 @@ struct ttm_buffer_object { * Members protected by the bo::resv::reserved lock. */ - struct ttm_mem_reg mem; + struct ttm_resource mem; struct file *persistent_swap_storage; struct ttm_tt *ttm; bool evicted; @@ -314,12 +267,12 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, bool interruptible, bool no_wait); * ttm_bo_mem_compat - Check if proposed placement is compatible with a bo * * @placement: Return immediately if buffer is busy. - * @mem: The struct ttm_mem_reg indicating the region where the bo resides + * @mem: The struct ttm_resource indicating the region where the bo resides * @new_flags: Describes compatible placement found * * Returns true if the placement is compatible */ -bool ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_mem_reg *mem, +bool ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_resource *mem, uint32_t *new_flags); /** @@ -532,52 +485,6 @@ int ttm_bo_create(struct ttm_bo_device *bdev, unsigned long size, struct ttm_buffer_object **p_bo); /** - * ttm_bo_init_mm - * - * @bdev: Pointer to a ttm_bo_device struct. - * @mem_type: The memory type. - * @p_size: size managed area in pages. - * - * Initialize a manager for a given memory type. - * Note: if part of driver firstopen, it must be protected from a - * potentially racing lastclose. - * Returns: - * -EINVAL: invalid size or memory type. - * -ENOMEM: Not enough memory. - * May also return driver-specified errors. - */ -int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type, - unsigned long p_size); - -/** - * ttm_bo_clean_mm - * - * @bdev: Pointer to a ttm_bo_device struct. - * @mem_type: The memory type. - * - * Take down a manager for a given memory type after first walking - * the LRU list to evict any buffers left alive. - * - * Normally, this function is part of lastclose() or unload(), and at that - * point there shouldn't be any buffers left created by user-space, since - * there should've been removed by the file descriptor release() method. - * However, before this function is run, make sure to signal all sync objects, - * and verify that the delayed delete queue is empty. The driver must also - * make sure that there are no NO_EVICT buffers present in this memory type - * when the call is made. - * - * If this function is part of a VT switch, the caller must make sure that - * there are no appications currently validating buffers before this - * function is called. The caller can do that by first taking the - * struct ttm_bo_device::ttm_lock in write mode. - * - * Returns: - * -EINVAL: invalid or uninitialized memory type. - * -EBUSY: There are still buffers left in this memory type. - */ -int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type); - -/** * ttm_bo_evict_mm * * @bdev: Pointer to a ttm_bo_device struct. @@ -713,6 +620,12 @@ static inline bool ttm_bo_uses_embedded_gem_object(struct ttm_buffer_object *bo) return bo->base.dev != NULL; } +int ttm_mem_evict_first(struct ttm_bo_device *bdev, + struct ttm_resource_manager *man, + const struct ttm_place *place, + struct ttm_operation_ctx *ctx, + struct ww_acquire_ctx *ticket); + /* Default number of pre-faulted pages in the TTM fault handler */ #define TTM_BO_VM_NUM_PREFAULT 16 diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 5a37f1cc057e..bc8d0ebb7568 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -43,171 +43,10 @@ #include "ttm_placement.h" #include "ttm_tt.h" -#define TTM_MAX_BO_PRIORITY 4U - -#define TTM_MEMTYPE_FLAG_FIXED (1 << 0) /* Fixed (on-card) PCI memory */ -#define TTM_MEMTYPE_FLAG_MAPPABLE (1 << 1) /* Memory mappable */ - -struct ttm_mem_type_manager; - -struct ttm_mem_type_manager_func { - /** - * struct ttm_mem_type_manager member init - * - * @man: Pointer to a memory type manager. - * @p_size: Implementation dependent, but typically the size of the - * range to be managed in pages. - * - * Called to initialize a private range manager. The function is - * expected to initialize the man::priv member. - * Returns 0 on success, negative error code on failure. - */ - int (*init)(struct ttm_mem_type_manager *man, unsigned long p_size); - - /** - * struct ttm_mem_type_manager member takedown - * - * @man: Pointer to a memory type manager. - * - * Called to undo the setup done in init. All allocated resources - * should be freed. - */ - int (*takedown)(struct ttm_mem_type_manager *man); - - /** - * struct ttm_mem_type_manager member get_node - * - * @man: Pointer to a memory type manager. - * @bo: Pointer to the buffer object we're allocating space for. - * @placement: Placement details. - * @flags: Additional placement flags. - * @mem: Pointer to a struct ttm_mem_reg to be filled in. - * - * This function should allocate space in the memory type managed - * by @man. Placement details if - * applicable are given by @placement. If successful, - * @mem::mm_node should be set to a non-null value, and - * @mem::start should be set to a value identifying the beginning - * of the range allocated, and the function should return zero. - * If the memory region accommodate the buffer object, @mem::mm_node - * should be set to NULL, and the function should return 0. - * If a system error occurred, preventing the request to be fulfilled, - * the function should return a negative error code. - * - * Note that @mem::mm_node will only be dereferenced by - * struct ttm_mem_type_manager functions and optionally by the driver, - * which has knowledge of the underlying type. - * - * This function may not be called from within atomic context, so - * an implementation can and must use either a mutex or a spinlock to - * protect any data structures managing the space. - */ - int (*get_node)(struct ttm_mem_type_manager *man, - struct ttm_buffer_object *bo, - const struct ttm_place *place, - struct ttm_mem_reg *mem); - - /** - * struct ttm_mem_type_manager member put_node - * - * @man: Pointer to a memory type manager. - * @mem: Pointer to a struct ttm_mem_reg to be filled in. - * - * This function frees memory type resources previously allocated - * and that are identified by @mem::mm_node and @mem::start. May not - * be called from within atomic context. - */ - void (*put_node)(struct ttm_mem_type_manager *man, - struct ttm_mem_reg *mem); - - /** - * struct ttm_mem_type_manager member debug - * - * @man: Pointer to a memory type manager. - * @printer: Prefix to be used in printout to identify the caller. - * - * This function is called to print out the state of the memory - * type manager to aid debugging of out-of-memory conditions. - * It may not be called from within atomic context. - */ - void (*debug)(struct ttm_mem_type_manager *man, - struct drm_printer *printer); -}; - -/** - * struct ttm_mem_type_manager - * - * @has_type: The memory type has been initialized. - * @use_type: The memory type is enabled. - * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory - * managed by this memory type. - * @gpu_offset: If used, the GPU offset of the first managed page of - * fixed memory or the first managed location in an aperture. - * @size: Size of the managed region. - * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, - * as defined in ttm_placement_common.h - * @default_caching: The default caching policy used for a buffer object - * placed in this memory type if the user doesn't provide one. - * @func: structure pointer implementing the range manager. See above - * @priv: Driver private closure for @func. - * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures - * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions - * reserved by the TTM vm system. - * @io_reserve_lru: Optional lru list for unreserving io mem regions. - * @move_lock: lock for move fence - * static information. bdev::driver::io_mem_free is never used. - * @lru: The lru list for this memory type. - * @move: The fence of the last pipelined move operation. - * - * This structure is used to identify and manage memory types for a device. - * It's set up by the ttm_bo_driver::init_mem_type method. - */ - - - -struct ttm_mem_type_manager { - struct ttm_bo_device *bdev; - - /* - * No protection. Constant from start. - */ - - bool has_type; - bool use_type; - uint32_t flags; - uint64_t size; - uint32_t available_caching; - uint32_t default_caching; - const struct ttm_mem_type_manager_func *func; - void *priv; - struct mutex io_reserve_mutex; - bool use_io_reserve_lru; - spinlock_t move_lock; - - /* - * Protected by @io_reserve_mutex: - */ - - struct list_head io_reserve_lru; - - /* - * Protected by the global->lru_lock. - */ - - struct list_head lru[TTM_MAX_BO_PRIORITY]; - - /* - * Protected by @move_lock. - */ - struct dma_fence *move; -}; - /** * struct ttm_bo_driver * * @create_ttm_backend_entry: Callback to create a struct ttm_backend. - * @init_mem_type: Callback to initialize a struct ttm_mem_type_manager - * structure. * @evict_flags: Callback to obtain placement flags when a buffer is evicted. * @move: Callback for a driver to hook in accelerated functions to * move a buffer. @@ -250,9 +89,6 @@ struct ttm_bo_driver { */ void (*ttm_tt_unpopulate)(struct ttm_tt *ttm); - int (*init_mem_type)(struct ttm_bo_device *bdev, uint32_t type, - struct ttm_mem_type_manager *man); - /** * struct ttm_bo_driver member eviction_valuable * @@ -290,7 +126,7 @@ struct ttm_bo_driver { */ int (*move)(struct ttm_buffer_object *bo, bool evict, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem); + struct ttm_resource *new_mem); /** * struct ttm_bo_driver_member verify_access @@ -316,7 +152,7 @@ struct ttm_bo_driver { */ void (*move_notify)(struct ttm_buffer_object *bo, bool evict, - struct ttm_mem_reg *new_mem); + struct ttm_resource *new_mem); /* notify the driver we are taking a fault on this BO * and have reserved it */ int (*fault_reserve_notify)(struct ttm_buffer_object *bo); @@ -333,9 +169,9 @@ struct ttm_bo_driver { * are balanced. */ int (*io_mem_reserve)(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); void (*io_mem_free)(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); /** * Return the pfn for a given page_offset inside the BO. @@ -429,7 +265,7 @@ extern struct ttm_bo_global { * struct ttm_bo_device - Buffer object driver device-specific data. * * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver. - * @man: An array of mem_type_managers. + * @man: An array of resource_managers. * @vma_manager: Address space manager (pointer) * lru_lock: Spinlock that protects the buffer+device lru lists and * ddestroy lists. @@ -447,8 +283,11 @@ struct ttm_bo_device { */ struct list_head device_list; struct ttm_bo_driver *driver; - struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; - + /* + * access via ttm_manager_type. + */ + struct ttm_resource_manager sysman; + struct ttm_resource_manager *man_drv[TTM_NUM_MEM_TYPES]; /* * Protected by internal locks. */ @@ -476,6 +315,19 @@ struct ttm_bo_device { bool no_retry; }; +static inline struct ttm_resource_manager *ttm_manager_type(struct ttm_bo_device *bdev, + int mem_type) +{ + return bdev->man_drv[mem_type]; +} + +static inline void ttm_set_driver_manager(struct ttm_bo_device *bdev, + int type, + struct ttm_resource_manager *manager) +{ + bdev->man_drv[type] = manager; +} + /** * struct ttm_lru_bulk_move_pos * @@ -531,7 +383,7 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask) * @bo: Pointer to a struct ttm_buffer_object. the data of which * we want to allocate space for. * @proposed_placement: Proposed new placement for the buffer object. - * @mem: A struct ttm_mem_reg. + * @mem: A struct ttm_resource. * @interruptible: Sleep interruptible when sliping. * @no_wait_gpu: Return immediately if the GPU is busy. * @@ -546,11 +398,9 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask) */ int ttm_bo_mem_space(struct ttm_buffer_object *bo, struct ttm_placement *placement, - struct ttm_mem_reg *mem, + struct ttm_resource *mem, struct ttm_operation_ctx *ctx); -void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); - int ttm_bo_device_release(struct ttm_bo_device *bdev); /** @@ -593,33 +443,34 @@ void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo); int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo); void ttm_mem_io_free_vm(struct ttm_buffer_object *bo); -int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible); -void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); +int ttm_mem_io_lock(struct ttm_resource_manager *man, bool interruptible); +void ttm_mem_io_unlock(struct ttm_resource_manager *man); /** - * __ttm_bo_reserve: + * ttm_bo_reserve: * * @bo: A pointer to a struct ttm_buffer_object. * @interruptible: Sleep interruptible if waiting. * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. * @ticket: ticket used to acquire the ww_mutex. * - * Will not remove reserved buffers from the lru lists. - * Otherwise identical to ttm_bo_reserve. + * Locks a buffer object for validation. (Or prevents other processes from + * locking it for validation), while taking a number of measures to prevent + * deadlocks. * * Returns: * -EDEADLK: The reservation may cause a deadlock. * Release all buffer reservations, wait for @bo to become unreserved and - * try again. (only if use_sequence == 1). + * try again. * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by * a signal. Release all buffer reservations and return to user-space. * -EBUSY: The function needed to sleep, but @no_wait was true * -EALREADY: Bo already reserved using @ticket. This error code will only * be returned if @use_ticket is set to true. */ -static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo, - bool interruptible, bool no_wait, - struct ww_acquire_ctx *ticket) +static inline int ttm_bo_reserve(struct ttm_buffer_object *bo, + bool interruptible, bool no_wait, + struct ww_acquire_ctx *ticket) { int ret = 0; @@ -642,59 +493,6 @@ static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo, } /** - * ttm_bo_reserve: - * - * @bo: A pointer to a struct ttm_buffer_object. - * @interruptible: Sleep interruptible if waiting. - * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. - * @ticket: ticket used to acquire the ww_mutex. - * - * Locks a buffer object for validation. (Or prevents other processes from - * locking it for validation) and removes it from lru lists, while taking - * a number of measures to prevent deadlocks. - * - * Deadlocks may occur when two processes try to reserve multiple buffers in - * different order, either by will or as a result of a buffer being evicted - * to make room for a buffer already reserved. (Buffers are reserved before - * they are evicted). The following algorithm prevents such deadlocks from - * occurring: - * Processes attempting to reserve multiple buffers other than for eviction, - * (typically execbuf), should first obtain a unique 32-bit - * validation sequence number, - * and call this function with @use_ticket == 1 and @ticket->stamp == the unique - * sequence number. If upon call of this function, the buffer object is already - * reserved, the validation sequence is checked against the validation - * sequence of the process currently reserving the buffer, - * and if the current validation sequence is greater than that of the process - * holding the reservation, the function returns -EDEADLK. Otherwise it sleeps - * waiting for the buffer to become unreserved, after which it retries - * reserving. - * The caller should, when receiving an -EDEADLK error - * release all its buffer reservations, wait for @bo to become unreserved, and - * then rerun the validation with the same validation sequence. This procedure - * will always guarantee that the process with the lowest validation sequence - * will eventually succeed, preventing both deadlocks and starvation. - * - * Returns: - * -EDEADLK: The reservation may cause a deadlock. - * Release all buffer reservations, wait for @bo to become unreserved and - * try again. (only if use_sequence == 1). - * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by - * a signal. Release all buffer reservations and return to user-space. - * -EBUSY: The function needed to sleep, but @no_wait was true - * -EALREADY: Bo already reserved using @ticket. This error code will only - * be returned if @use_ticket is set to true. - */ -static inline int ttm_bo_reserve(struct ttm_buffer_object *bo, - bool interruptible, bool no_wait, - struct ww_acquire_ctx *ticket) -{ - WARN_ON(!kref_read(&bo->kref)); - - return __ttm_bo_reserve(bo, interruptible, no_wait, ticket); -} - -/** * ttm_bo_reserve_slowpath: * @bo: A pointer to a struct ttm_buffer_object. * @interruptible: Sleep interruptible if waiting. @@ -708,20 +506,22 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, bool interruptible, struct ww_acquire_ctx *ticket) { - int ret = 0; - - WARN_ON(!kref_read(&bo->kref)); - - if (interruptible) - ret = dma_resv_lock_slow_interruptible(bo->base.resv, - ticket); - else - dma_resv_lock_slow(bo->base.resv, ticket); - - if (ret == -EINTR) - ret = -ERESTARTSYS; + if (interruptible) { + int ret = dma_resv_lock_slow_interruptible(bo->base.resv, + ticket); + if (ret == -EINTR) + ret = -ERESTARTSYS; + return ret; + } + dma_resv_lock_slow(bo->base.resv, ticket); + return 0; +} - return ret; +static inline void ttm_bo_move_to_lru_tail_unlocked(struct ttm_buffer_object *bo) +{ + spin_lock(&ttm_bo_glob.lru_lock); + ttm_bo_move_to_lru_tail(bo, NULL); + spin_unlock(&ttm_bo_glob.lru_lock); } /** @@ -733,9 +533,7 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, */ static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo) { - spin_lock(&ttm_bo_glob.lru_lock); - ttm_bo_move_to_lru_tail(bo, NULL); - spin_unlock(&ttm_bo_glob.lru_lock); + ttm_bo_move_to_lru_tail_unlocked(bo); dma_resv_unlock(bo->base.resv); } @@ -744,16 +542,16 @@ static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo) */ int ttm_mem_io_reserve(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); void ttm_mem_io_free(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem); + struct ttm_resource *mem); /** * ttm_bo_move_ttm * * @bo: A pointer to a struct ttm_buffer_object. * @interruptible: Sleep interruptible if waiting. * @no_wait_gpu: Return immediately if the GPU is busy. - * @new_mem: struct ttm_mem_reg indicating where to move. + * @new_mem: struct ttm_resource indicating where to move. * * Optimized move function for a buffer object with both old and * new placement backed by a TTM. The function will, if successful, @@ -767,7 +565,7 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev, int ttm_bo_move_ttm(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem); + struct ttm_resource *new_mem); /** * ttm_bo_move_memcpy @@ -775,7 +573,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, * @bo: A pointer to a struct ttm_buffer_object. * @interruptible: Sleep interruptible if waiting. * @no_wait_gpu: Return immediately if the GPU is busy. - * @new_mem: struct ttm_mem_reg indicating where to move. + * @new_mem: struct ttm_resource indicating where to move. * * Fallback move function for a mappable buffer object in mappable memory. * The function will, if successful, @@ -789,7 +587,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, - struct ttm_mem_reg *new_mem); + struct ttm_resource *new_mem); /** * ttm_bo_free_old_node @@ -806,7 +604,7 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo); * @bo: A pointer to a struct ttm_buffer_object. * @fence: A fence object that signals when moving is complete. * @evict: This is an evict move. Don't return until the buffer is idle. - * @new_mem: struct ttm_mem_reg indicating where to move. + * @new_mem: struct ttm_resource indicating where to move. * * Accelerated move function to be called when an accelerated move * has been scheduled. The function will create a new temporary buffer object @@ -817,7 +615,7 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo); */ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, struct dma_fence *fence, bool evict, - struct ttm_mem_reg *new_mem); + struct ttm_resource *new_mem); /** * ttm_bo_pipeline_move. @@ -825,14 +623,14 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, * @bo: A pointer to a struct ttm_buffer_object. * @fence: A fence object that signals when moving is complete. * @evict: This is an evict move. Don't return until the buffer is idle. - * @new_mem: struct ttm_mem_reg indicating where to move. + * @new_mem: struct ttm_resource indicating where to move. * * Function for pipelining accelerated moves. Either free the memory * immediately or hang it on a temporary buffer object. */ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, struct dma_fence *fence, bool evict, - struct ttm_mem_reg *new_mem); + struct ttm_resource *new_mem); /** * ttm_bo_pipeline_gutting. @@ -854,6 +652,35 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo); */ pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp); -extern const struct ttm_mem_type_manager_func ttm_bo_manager_func; +/** + * ttm_range_man_init + * + * @bdev: ttm device + * @type: memory manager type + * @available_caching: TTM_PL_FLAG_* for allowed caching modes + * @default_caching: default caching mode + * @use_tt: if the memory manager uses tt + * @p_size: size of area to be managed in pages. + * + * Initialise a generic range manager for the selected memory type. + * The range manager is installed for this device in the type slot. + */ +int ttm_range_man_init(struct ttm_bo_device *bdev, + unsigned type, + uint32_t available_caching, + uint32_t default_caching, + bool use_tt, + unsigned long p_size); + +/** + * ttm_range_man_fini + * + * @bdev: ttm device + * @type: memory manager type + * + * Remove the generic range manager from a slot and tear it down. + */ +int ttm_range_man_fini(struct ttm_bo_device *bdev, + unsigned type); #endif diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h new file mode 100644 index 000000000000..6d4226190480 --- /dev/null +++ b/include/drm/ttm/ttm_resource.h @@ -0,0 +1,261 @@ +/* + * Copyright 2020 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. + * + * Authors: Christian König + */ + +#ifndef _TTM_RESOURCE_H_ +#define _TTM_RESOURCE_H_ + +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/dma-fence.h> +#include <drm/drm_print.h> + +#define TTM_MAX_BO_PRIORITY 4U + +struct ttm_bo_device; +struct ttm_resource_manager; +struct ttm_resource; +struct ttm_place; +struct ttm_buffer_object; + +struct ttm_resource_manager_func { + /** + * struct ttm_resource_manager_func member alloc + * + * @man: Pointer to a memory type manager. + * @bo: Pointer to the buffer object we're allocating space for. + * @placement: Placement details. + * @flags: Additional placement flags. + * @mem: Pointer to a struct ttm_resource to be filled in. + * + * This function should allocate space in the memory type managed + * by @man. Placement details if + * applicable are given by @placement. If successful, + * @mem::mm_node should be set to a non-null value, and + * @mem::start should be set to a value identifying the beginning + * of the range allocated, and the function should return zero. + * If the memory region accommodate the buffer object, @mem::mm_node + * should be set to NULL, and the function should return 0. + * If a system error occurred, preventing the request to be fulfilled, + * the function should return a negative error code. + * + * Note that @mem::mm_node will only be dereferenced by + * struct ttm_resource_manager functions and optionally by the driver, + * which has knowledge of the underlying type. + * + * This function may not be called from within atomic context, so + * an implementation can and must use either a mutex or a spinlock to + * protect any data structures managing the space. + */ + int (*alloc)(struct ttm_resource_manager *man, + struct ttm_buffer_object *bo, + const struct ttm_place *place, + struct ttm_resource *mem); + + /** + * struct ttm_resource_manager_func member free + * + * @man: Pointer to a memory type manager. + * @mem: Pointer to a struct ttm_resource to be filled in. + * + * This function frees memory type resources previously allocated + * and that are identified by @mem::mm_node and @mem::start. May not + * be called from within atomic context. + */ + void (*free)(struct ttm_resource_manager *man, + struct ttm_resource *mem); + + /** + * struct ttm_resource_manager_func member debug + * + * @man: Pointer to a memory type manager. + * @printer: Prefix to be used in printout to identify the caller. + * + * This function is called to print out the state of the memory + * type manager to aid debugging of out-of-memory conditions. + * It may not be called from within atomic context. + */ + void (*debug)(struct ttm_resource_manager *man, + struct drm_printer *printer); +}; + +/** + * struct ttm_resource_manager + * + * @use_type: The memory type is enabled. + * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory + * managed by this memory type. + * @gpu_offset: If used, the GPU offset of the first managed page of + * fixed memory or the first managed location in an aperture. + * @size: Size of the managed region. + * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, + * as defined in ttm_placement_common.h + * @default_caching: The default caching policy used for a buffer object + * placed in this memory type if the user doesn't provide one. + * @func: structure pointer implementing the range manager. See above + * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures + * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions + * reserved by the TTM vm system. + * @io_reserve_lru: Optional lru list for unreserving io mem regions. + * @move_lock: lock for move fence + * static information. bdev::driver::io_mem_free is never used. + * @lru: The lru list for this memory type. + * @move: The fence of the last pipelined move operation. + * + * This structure is used to identify and manage memory types for a device. + */ +struct ttm_resource_manager { + /* + * No protection. Constant from start. + */ + bool use_type; + bool use_tt; + uint64_t size; + uint32_t available_caching; + uint32_t default_caching; + const struct ttm_resource_manager_func *func; + struct mutex io_reserve_mutex; + bool use_io_reserve_lru; + spinlock_t move_lock; + + /* + * Protected by @io_reserve_mutex: + */ + + struct list_head io_reserve_lru; + + /* + * Protected by the global->lru_lock. + */ + + struct list_head lru[TTM_MAX_BO_PRIORITY]; + + /* + * Protected by @move_lock. + */ + struct dma_fence *move; +}; + +/** + * struct ttm_bus_placement + * + * @addr: mapped virtual address + * @base: bus base address + * @is_iomem: is this io memory ? + * @offset: offset from the base address + * @io_reserved_vm: The VM system has a refcount in @io_reserved_count + * @io_reserved_count: Refcounting the numbers of callers to ttm_mem_io_reserve + * + * Structure indicating the bus placement of an object. + */ +struct ttm_bus_placement { + void *addr; + phys_addr_t base; + unsigned long offset; + bool is_iomem; + bool io_reserved_vm; + uint64_t io_reserved_count; +}; + +/** + * struct ttm_resource + * + * @mm_node: Memory manager node. + * @size: Requested size of memory region. + * @num_pages: Actual size of memory region in pages. + * @page_alignment: Page alignment. + * @placement: Placement flags. + * @bus: Placement on io bus accessible to the CPU + * + * Structure indicating the placement and space resources used by a + * buffer object. + */ +struct ttm_resource { + void *mm_node; + unsigned long start; + unsigned long size; + unsigned long num_pages; + uint32_t page_alignment; + uint32_t mem_type; + uint32_t placement; + struct ttm_bus_placement bus; +}; + +/** + * ttm_resource_manager_set_used + * + * @man: A memory manager object. + * @used: usage state to set. + * + * Set the manager in use flag. If disabled the manager is no longer + * used for object placement. + */ +static inline void +ttm_resource_manager_set_used(struct ttm_resource_manager *man, bool used) +{ + man->use_type = used; +} + +/** + * ttm_resource_manager_used + * + * @man: Manager to get used state for + * + * Get the in use flag for a manager. + * Returns: + * true is used, false if not. + */ +static inline bool ttm_resource_manager_used(struct ttm_resource_manager *man) +{ + return man->use_type; +} + +/** + * ttm_resource_manager_cleanup + * + * @man: A memory manager object. + * + * Cleanup the move fences from the memory manager object. + */ +static inline void +ttm_resource_manager_cleanup(struct ttm_resource_manager *man) +{ + dma_fence_put(man->move); + man->move = NULL; +} + +int ttm_resource_alloc(struct ttm_buffer_object *bo, + const struct ttm_place *place, + struct ttm_resource *res); +void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource *res); + +void ttm_resource_manager_init(struct ttm_resource_manager *man, + unsigned long p_size); + +int ttm_resource_manager_force_list_clean(struct ttm_bo_device *bdev, + struct ttm_resource_manager *man); + +void ttm_resource_manager_debug(struct ttm_resource_manager *man, + struct drm_printer *p); + +#endif diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index 5e2393fe42c6..241cc40839ed 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -30,7 +30,7 @@ #include <linux/types.h> struct ttm_tt; -struct ttm_mem_reg; +struct ttm_resource; struct ttm_buffer_object; struct ttm_operation_ctx; @@ -53,14 +53,14 @@ struct ttm_backend_func { * struct ttm_backend_func member bind * * @ttm: Pointer to a struct ttm_tt. - * @bo_mem: Pointer to a struct ttm_mem_reg describing the + * @bo_mem: Pointer to a struct ttm_resource describing the * memory type and location for binding. * * Bind the backend pages into the aperture in the location * indicated by @bo_mem. This function should be able to handle * differences between aperture and system page sizes. */ - int (*bind) (struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem); + int (*bind) (struct ttm_tt *ttm, struct ttm_resource *bo_mem); /** * struct ttm_backend_func member unbind @@ -179,11 +179,11 @@ void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma); * ttm_ttm_bind: * * @ttm: The struct ttm_tt containing backing pages. - * @bo_mem: The struct ttm_mem_reg identifying the binding location. + * @bo_mem: The struct ttm_resource identifying the binding location. * * Bind the pages of @ttm to an aperture location identified by @bo_mem */ -int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem, +int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem, struct ttm_operation_ctx *ctx); /** diff --git a/include/linux/fb.h b/include/linux/fb.h index 850f79e9a7cb..ecfbcc0553a5 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -124,7 +124,7 @@ struct fb_cursor_user { * Register/unregister for framebuffer events */ -/* The resolution of the passed in fb_info about to change */ +/* The resolution of the passed in fb_info about to change */ #define FB_EVENT_MODE_CHANGE 0x01 #ifdef CONFIG_GUMSTIX_AM200EPD @@ -457,12 +457,12 @@ struct fb_info { #if IS_ENABLED(CONFIG_FB_BACKLIGHT) /* assigned backlight device */ - /* set before framebuffer registration, + /* set before framebuffer registration, remove after unregister */ struct backlight_device *bl_dev; /* Backlight level curve */ - struct mutex bl_curve_mutex; + struct mutex bl_curve_mutex; u8 bl_curve[FB_BACKLIGHT_LEVELS]; #endif #ifdef CONFIG_FB_DEFERRED_IO @@ -481,8 +481,8 @@ struct fb_info { char __iomem *screen_base; /* Virtual address */ char *screen_buffer; }; - unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ - void *pseudo_palette; /* Fake palette of 16 colors */ + unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ + void *pseudo_palette; /* Fake palette of 16 colors */ #define FBINFO_STATE_RUNNING 0 #define FBINFO_STATE_SUSPENDED 1 u32 state; /* Hardware state i.e suspend */ @@ -585,11 +585,11 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { * `Generic' versions of the frame buffer device operations */ -extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var); -extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var); +extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var); +extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var); extern int fb_blank(struct fb_info *info, int blank); -extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); +extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image); /* * Drawing operations where framebuffer is in system RAM diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 1ad5aa3b86d9..47879fc7f75e 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -118,7 +118,7 @@ struct kparam_array * you can create your own by defining those variables. * * Standard types are: - * byte, short, ushort, int, uint, long, ulong + * byte, hexint, short, ushort, int, uint, long, ulong * charp: a character pointer * bool: a bool, values 0/1, y/n, Y/N. * invbool: the above, only sense-reversed (N = true). @@ -448,6 +448,11 @@ extern int param_set_ullong(const char *val, const struct kernel_param *kp); extern int param_get_ullong(char *buffer, const struct kernel_param *kp); #define param_check_ullong(name, p) __param_check(name, p, unsigned long long) +extern const struct kernel_param_ops param_ops_hexint; +extern int param_set_hexint(const char *val, const struct kernel_param *kp); +extern int param_get_hexint(char *buffer, const struct kernel_param *kp); +#define param_check_hexint(name, p) param_check_uint(name, p) + extern const struct kernel_param_ops param_ops_charp; extern int param_set_charp(const char *val, const struct kernel_param *kp); extern int param_get_charp(char *buffer, const struct kernel_param *kp); diff --git a/include/linux/virtio.h b/include/linux/virtio.h index a493eac08393..55ea329fe72a 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -127,6 +127,7 @@ static inline struct virtio_device *dev_to_virtio(struct device *_dev) void virtio_add_status(struct virtio_device *dev, unsigned int status); int register_virtio_device(struct virtio_device *dev); void unregister_virtio_device(struct virtio_device *dev); +bool is_virtio_device(struct device *dev); void virtio_break_device(struct virtio_device *dev); diff --git a/include/linux/virtio_dma_buf.h b/include/linux/virtio_dma_buf.h new file mode 100644 index 000000000000..a2fdf217ac62 --- /dev/null +++ b/include/linux/virtio_dma_buf.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * dma-bufs for virtio exported objects + * + * Copyright (C) 2020 Google, Inc. + */ + +#ifndef _LINUX_VIRTIO_DMA_BUF_H +#define _LINUX_VIRTIO_DMA_BUF_H + +#include <linux/dma-buf.h> +#include <linux/uuid.h> +#include <linux/virtio.h> + +/** + * struct virtio_dma_buf_ops - operations possible on exported object dma-buf + * @ops: the base dma_buf_ops. ops.attach MUST be virtio_dma_buf_attach. + * @device_attach: [optional] callback invoked by virtio_dma_buf_attach during + * all attach operations. + * @get_uid: [required] callback to get the uuid of the exported object. + */ +struct virtio_dma_buf_ops { + struct dma_buf_ops ops; + int (*device_attach)(struct dma_buf *dma_buf, + struct dma_buf_attachment *attach); + int (*get_uuid)(struct dma_buf *dma_buf, uuid_t *uuid); +}; + +int virtio_dma_buf_attach(struct dma_buf *dma_buf, + struct dma_buf_attachment *attach); + +struct dma_buf *virtio_dma_buf_export + (const struct dma_buf_export_info *exp_info); +bool is_virtio_dma_buf(struct dma_buf *dma_buf); +int virtio_dma_buf_get_uuid(struct dma_buf *dma_buf, uuid_t *uuid); + +#endif /* _LINUX_VIRTIO_DMA_BUF_H */ diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 3218576e109d..c5ff2b275fcd 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -673,6 +673,7 @@ struct drm_amdgpu_cs_chunk_data { */ #define AMDGPU_IDS_FLAGS_FUSION 0x1 #define AMDGPU_IDS_FLAGS_PREEMPTION 0x2 +#define AMDGPU_IDS_FLAGS_TMZ 0x4 /* indicate if acceleration can be working */ #define AMDGPU_INFO_ACCEL_WORKING 0x00 diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index deea447e5f22..863eda048265 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -332,14 +332,19 @@ struct drm_mode_get_encoder { /* This is for connectors with multiple signal types. */ /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ enum drm_mode_subconnector { - DRM_MODE_SUBCONNECTOR_Automatic = 0, - DRM_MODE_SUBCONNECTOR_Unknown = 0, - DRM_MODE_SUBCONNECTOR_DVID = 3, - DRM_MODE_SUBCONNECTOR_DVIA = 4, - DRM_MODE_SUBCONNECTOR_Composite = 5, - DRM_MODE_SUBCONNECTOR_SVIDEO = 6, - DRM_MODE_SUBCONNECTOR_Component = 8, - DRM_MODE_SUBCONNECTOR_SCART = 9, + DRM_MODE_SUBCONNECTOR_Automatic = 0, /* DVI-I, TV */ + DRM_MODE_SUBCONNECTOR_Unknown = 0, /* DVI-I, TV, DP */ + DRM_MODE_SUBCONNECTOR_VGA = 1, /* DP */ + DRM_MODE_SUBCONNECTOR_DVID = 3, /* DVI-I DP */ + DRM_MODE_SUBCONNECTOR_DVIA = 4, /* DVI-I */ + DRM_MODE_SUBCONNECTOR_Composite = 5, /* TV */ + DRM_MODE_SUBCONNECTOR_SVIDEO = 6, /* TV */ + DRM_MODE_SUBCONNECTOR_Component = 8, /* TV */ + DRM_MODE_SUBCONNECTOR_SCART = 9, /* TV */ + DRM_MODE_SUBCONNECTOR_DisplayPort = 10, /* DP */ + DRM_MODE_SUBCONNECTOR_HDMIA = 11, /* DP */ + DRM_MODE_SUBCONNECTOR_Native = 15, /* DP */ + DRM_MODE_SUBCONNECTOR_Wireless = 18, /* DP */ }; #define DRM_MODE_CONNECTOR_Unknown 0 diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 00546062e023..fa1f3d62f9a6 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -619,6 +619,12 @@ typedef struct drm_i915_irq_wait { */ #define I915_PARAM_PERF_REVISION 54 +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of + * timeline syncobj through drm_i915_gem_execbuffer_ext_timeline_fences. See + * I915_EXEC_USE_EXTENSIONS. + */ +#define I915_PARAM_HAS_EXEC_TIMELINE_FENCES 55 + /* Must be kept compact -- no holes and well documented */ typedef struct drm_i915_getparam { @@ -1046,6 +1052,38 @@ struct drm_i915_gem_exec_fence { __u32 flags; }; +/** + * See drm_i915_gem_execbuffer_ext_timeline_fences. + */ +#define DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES 0 + +/** + * This structure describes an array of drm_syncobj and associated points for + * timeline variants of drm_syncobj. It is invalid to append this structure to + * the execbuf if I915_EXEC_FENCE_ARRAY is set. + */ +struct drm_i915_gem_execbuffer_ext_timeline_fences { + struct i915_user_extension base; + + /** + * Number of element in the handles_ptr & value_ptr arrays. + */ + __u64 fence_count; + + /** + * Pointer to an array of struct drm_i915_gem_exec_fence of length + * fence_count. + */ + __u64 handles_ptr; + + /** + * Pointer to an array of u64 values of length fence_count. Values + * must be 0 for a binary drm_syncobj. A Value of 0 for a timeline + * drm_syncobj is invalid as it turns a drm_syncobj into a binary one. + */ + __u64 values_ptr; +}; + struct drm_i915_gem_execbuffer2 { /** * List of gem_exec_object2 structs @@ -1062,8 +1100,14 @@ struct drm_i915_gem_execbuffer2 { __u32 num_cliprects; /** * This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY - * is not set. If I915_EXEC_FENCE_ARRAY is set, then this is a - * struct drm_i915_gem_exec_fence *fences. + * & I915_EXEC_USE_EXTENSIONS are not set. + * + * If I915_EXEC_FENCE_ARRAY is set, then this is a pointer to an array + * of struct drm_i915_gem_exec_fence and num_cliprects is the length + * of the array. + * + * If I915_EXEC_USE_EXTENSIONS is set, then this is a pointer to a + * single struct i915_user_extension and num_cliprects is 0. */ __u64 cliprects_ptr; #define I915_EXEC_RING_MASK (0x3f) @@ -1181,7 +1225,16 @@ struct drm_i915_gem_execbuffer2 { */ #define I915_EXEC_FENCE_SUBMIT (1 << 20) -#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SUBMIT << 1)) +/* + * Setting I915_EXEC_USE_EXTENSIONS implies that + * drm_i915_gem_execbuffer2.cliprects_ptr is treated as a pointer to an linked + * list of i915_user_extension. Each i915_user_extension node is the base of a + * larger structure. The list of supported structures are listed in the + * drm_i915_gem_execbuffer_ext enum. + */ +#define I915_EXEC_USE_EXTENSIONS (1 << 21) + +#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_USE_EXTENSIONS << 1)) #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index f738c3b53f4e..695b606da4b1 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -449,8 +449,15 @@ struct kfd_ioctl_import_dmabuf_args { /* * KFD SMI(System Management Interface) events */ -/* Event type (defined by bitmask) */ -#define KFD_SMI_EVENT_VMFAULT 0x0000000000000001 +enum kfd_smi_event { + KFD_SMI_EVENT_NONE = 0, /* not used */ + KFD_SMI_EVENT_VMFAULT = 1, /* event start counting at 1 */ + KFD_SMI_EVENT_THERMAL_THROTTLE = 2, + KFD_SMI_EVENT_GPU_PRE_RESET = 3, + KFD_SMI_EVENT_GPU_POST_RESET = 4, +}; + +#define KFD_SMI_EVENT_MASK_FROM_INDEX(i) (1ULL << ((i) - 1)) struct kfd_ioctl_smi_events_args { __u32 gpuid; /* to KFD */ diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h index ccbd174ef321..747a5c5cc4e6 100644 --- a/include/uapi/linux/virtio_gpu.h +++ b/include/uapi/linux/virtio_gpu.h @@ -50,6 +50,10 @@ * VIRTIO_GPU_CMD_GET_EDID */ #define VIRTIO_GPU_F_EDID 1 +/* + * VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID + */ +#define VIRTIO_GPU_F_RESOURCE_UUID 2 enum virtio_gpu_ctrl_type { VIRTIO_GPU_UNDEFINED = 0, @@ -66,6 +70,7 @@ enum virtio_gpu_ctrl_type { VIRTIO_GPU_CMD_GET_CAPSET_INFO, VIRTIO_GPU_CMD_GET_CAPSET, VIRTIO_GPU_CMD_GET_EDID, + VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID, /* 3d commands */ VIRTIO_GPU_CMD_CTX_CREATE = 0x0200, @@ -87,6 +92,7 @@ enum virtio_gpu_ctrl_type { VIRTIO_GPU_RESP_OK_CAPSET_INFO, VIRTIO_GPU_RESP_OK_CAPSET, VIRTIO_GPU_RESP_OK_EDID, + VIRTIO_GPU_RESP_OK_RESOURCE_UUID, /* error responses */ VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, @@ -340,4 +346,17 @@ enum virtio_gpu_formats { VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, }; +/* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */ +struct virtio_gpu_resource_assign_uuid { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 padding; +}; + +/* VIRTIO_GPU_RESP_OK_RESOURCE_UUID */ +struct virtio_gpu_resp_resource_uuid { + struct virtio_gpu_ctrl_hdr hdr; + __u8 uuid[16]; +}; + #endif diff --git a/kernel/params.c b/kernel/params.c index 8e56f8b12d8f..3835fb82c64b 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -233,14 +233,15 @@ char *parse_args(const char *doing, EXPORT_SYMBOL(param_ops_##name) -STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", kstrtou8); -STANDARD_PARAM_DEF(short, short, "%hi", kstrtos16); -STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", kstrtou16); -STANDARD_PARAM_DEF(int, int, "%i", kstrtoint); -STANDARD_PARAM_DEF(uint, unsigned int, "%u", kstrtouint); -STANDARD_PARAM_DEF(long, long, "%li", kstrtol); -STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", kstrtoul); -STANDARD_PARAM_DEF(ullong, unsigned long long, "%llu", kstrtoull); +STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", kstrtou8); +STANDARD_PARAM_DEF(short, short, "%hi", kstrtos16); +STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", kstrtou16); +STANDARD_PARAM_DEF(int, int, "%i", kstrtoint); +STANDARD_PARAM_DEF(uint, unsigned int, "%u", kstrtouint); +STANDARD_PARAM_DEF(long, long, "%li", kstrtol); +STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", kstrtoul); +STANDARD_PARAM_DEF(ullong, unsigned long long, "%llu", kstrtoull); +STANDARD_PARAM_DEF(hexint, unsigned int, "%#08x", kstrtouint); int param_set_charp(const char *val, const struct kernel_param *kp) { |